test/harness/testcaseinput.c
author ali <ali@juiblex.co.uk>
Sat Oct 05 21:37:31 2013 +0100 (2013-10-05)
changeset 99 783eff3047bc
parent 9 6a13fe0fc19e
child 101 f44c530f80da
permissions -rw-r--r--
Fix bug #21: False positive: Opening slanted double-quote, followed by single slanted quote, should be accepted by BL
ali@9
     1
#include <stdlib.h>
ali@9
     2
#include <stdio.h>
ali@9
     3
#include <string.h>
ali@9
     4
#include <unistd.h>
ali@9
     5
#include <errno.h>
ali@9
     6
#include <fcntl.h>
ali@9
     7
#ifdef WIN32
ali@9
     8
#include <io.h>
ali@9
     9
#endif
ali@9
    10
#include <glib.h>
ali@9
    11
#include <glib/gstdio.h>
ali@9
    12
#include <bl/bl.h>
ali@9
    13
#include "testcase.h"
ali@9
    14
#include "testcaseinput.h"
ali@9
    15
ali@9
    16
#ifndef O_BINARY
ali@9
    17
#define O_BINARY 0
ali@9
    18
#endif
ali@9
    19
ali@9
    20
/*
ali@9
    21
 * As write(), but with error handling.
ali@9
    22
 */
ali@9
    23
static size_t write_file(int fd,const char *buf,size_t count,GError **error)
ali@9
    24
{
ali@9
    25
    if (write(fd,buf,count)<count)
ali@9
    26
    {
ali@9
    27
	g_set_error(error,G_FILE_ERROR,g_file_error_from_errno(errno),
ali@9
    28
	  "Error writing bookloupe input file: %s",g_strerror(errno));
ali@9
    29
	return -1;
ali@9
    30
    }
ali@9
    31
    return count;
ali@9
    32
}
ali@9
    33
ali@9
    34
/*
ali@35
    35
 * Replace \n with \r\n, U+240A (visible symbol for LF) with \n
ali@35
    36
 * and U+240D (visible symbol for CR) with \r.
ali@9
    37
 */
ali@9
    38
static char *unix2dos(const char *text)
ali@9
    39
{
ali@9
    40
    gunichar c;
ali@9
    41
    const gunichar visible_lf=0x240A;
ali@35
    42
    const gunichar visible_cr=0x240D;
ali@9
    43
    GString *string;
ali@9
    44
    string=g_string_new(NULL);
ali@9
    45
    while(*text)
ali@9
    46
    {
ali@9
    47
	c=g_utf8_get_char(text);
ali@9
    48
	text=g_utf8_next_char(text);
ali@9
    49
	if (c=='\n')
ali@9
    50
	    g_string_append(string,"\r\n");
ali@9
    51
	else if (c==visible_lf)
ali@9
    52
	    g_string_append_c(string,'\n');
ali@35
    53
	else if (c==visible_cr)
ali@35
    54
	    g_string_append_c(string,'\r');
ali@9
    55
	else
ali@9
    56
	    g_string_append_unichar(string,c);
ali@9
    57
    }
ali@9
    58
    return g_string_free(string,FALSE);
ali@9
    59
}
ali@9
    60
ali@9
    61
/*
ali@9
    62
 * Create an input file needed for a testcase (as specified in <input>).
ali@9
    63
 * The file is written in the encoding specified for communicating with
ali@9
    64
 * bookloupe. The name_used field of <input> is filled in with the name
ali@9
    65
 * of the created file (which may be different than the name specified
ali@9
    66
 * if that contained "XXXXXX" to be replaced by a unique string).
ali@9
    67
 */
ali@9
    68
gboolean testcase_input_create(Testcase *testcase,TestcaseInput *input,
ali@9
    69
  GError **error)
ali@9
    70
{
ali@9
    71
    int fd;
ali@9
    72
    size_t n;
ali@9
    73
    char *filename,*s,*t;
ali@9
    74
    GError *tmp_err=NULL;
ali@9
    75
    if (input->contents)
ali@9
    76
    {
ali@9
    77
	if (testcase->encoding)
ali@9
    78
	{
ali@9
    79
	    t=unix2dos(input->contents);
ali@9
    80
	    s=g_convert(t,-1,testcase->encoding,"UTF-8",NULL,&n,&tmp_err);
ali@9
    81
	    g_free(t);
ali@9
    82
	    if (!s)
ali@9
    83
	    {
ali@9
    84
		g_propagate_prefixed_error(error,tmp_err,
ali@9
    85
		  "Conversion to %s failed: ",testcase->encoding);
ali@9
    86
		return FALSE;
ali@9
    87
	    }
ali@9
    88
	}
ali@9
    89
	else
ali@9
    90
	{
ali@9
    91
	    s=unix2dos(input->contents);
ali@9
    92
	    n=strlen(s);
ali@9
    93
	}
ali@9
    94
    }
ali@9
    95
    else
ali@9
    96
    {
ali@9
    97
	n=0;
ali@9
    98
	s=NULL;
ali@9
    99
    }
ali@9
   100
    g_free(input->name_used);
ali@9
   101
    input->name_used=NULL;
ali@9
   102
    if (testcase->tmpdir)
ali@9
   103
	filename=g_build_filename(testcase->tmpdir,input->name,NULL);
ali@9
   104
    else
ali@9
   105
	filename=g_strdup(input->name);
ali@9
   106
    if (strstr(input->name,"XXXXXX"))
ali@9
   107
	fd=g_mkstemp(filename);
ali@9
   108
    else
ali@9
   109
	fd=g_open(filename,O_WRONLY|O_CREAT|O_EXCL|O_BINARY,0600);
ali@9
   110
    if (fd<0)
ali@9
   111
    {
ali@9
   112
	g_set_error(error,G_FILE_ERROR,g_file_error_from_errno(errno),
ali@9
   113
	  "%s: %s",filename,g_strerror(errno));
ali@9
   114
	g_free(s);
ali@9
   115
	return FALSE;
ali@9
   116
    }
ali@9
   117
    input->name_used=g_strdup(filename+strlen(filename)-strlen(input->name));
ali@9
   118
    if (n && write_file(fd,s,n,error)!=n)
ali@9
   119
    {
ali@9
   120
	g_free(s);
ali@9
   121
	close(fd);
ali@9
   122
	(void)g_unlink(filename);
ali@9
   123
	g_free(filename);
ali@9
   124
	g_free(input->name_used);
ali@9
   125
	input->name_used=NULL;
ali@9
   126
	return FALSE;
ali@9
   127
    }
ali@9
   128
    g_free(s);
ali@9
   129
    if (close(fd)<0)
ali@9
   130
    {
ali@9
   131
	g_set_error(error,G_FILE_ERROR,g_file_error_from_errno(errno),
ali@9
   132
	  "%s: %s",filename,g_strerror(errno));
ali@9
   133
	(void)g_unlink(filename);
ali@9
   134
	g_free(filename);
ali@9
   135
	g_free(input->name_used);
ali@9
   136
	input->name_used=NULL;
ali@9
   137
	return FALSE;
ali@9
   138
    }
ali@9
   139
    g_free(filename);
ali@9
   140
    return TRUE;
ali@9
   141
}
ali@9
   142
ali@9
   143
/*
ali@9
   144
 * Remove an input file created with testcase_input_create()
ali@9
   145
 */
ali@9
   146
gboolean testcase_input_remove(Testcase *testcase,TestcaseInput *input,
ali@9
   147
  GError **error)
ali@9
   148
{
ali@9
   149
    char *filename;
ali@9
   150
    if (input->name_used)
ali@9
   151
    {
ali@9
   152
	if (testcase->tmpdir)
ali@9
   153
	    filename=g_build_filename(testcase->tmpdir,input->name_used,NULL);
ali@9
   154
	else
ali@9
   155
	    filename=g_strdup(input->name_used);
ali@9
   156
	if (g_unlink(filename)<0)
ali@9
   157
	{
ali@9
   158
	    g_set_error(error,G_FILE_ERROR,g_file_error_from_errno(errno),
ali@9
   159
	      "%s: %s",filename,g_strerror(errno));
ali@9
   160
	    return FALSE;
ali@9
   161
	}
ali@9
   162
	g_free(filename);
ali@9
   163
	g_free(input->name_used);
ali@9
   164
	input->name_used=NULL;
ali@9
   165
    }
ali@9
   166
    return TRUE;
ali@9
   167
}
ali@9
   168
ali@9
   169
/* Create a new description of an input file needed for a testcase */
ali@9
   170
TestcaseInput *testcase_input_new(const char *name,const char *contents)
ali@9
   171
{
ali@9
   172
    TestcaseInput *input;
ali@9
   173
    input=g_new0(TestcaseInput,1);
ali@9
   174
    input->name=g_strdup(name);
ali@9
   175
    input->contents=g_strdup(contents);
ali@9
   176
    return input;
ali@9
   177
}
ali@9
   178
ali@9
   179
/* Free the description of a testcase input file */
ali@9
   180
void testcase_input_free(TestcaseInput *input)
ali@9
   181
{
ali@9
   182
    g_free(input->name);
ali@9
   183
    g_free(input->name_used);
ali@9
   184
    g_free(input->contents);
ali@9
   185
    g_free(input);
ali@9
   186
}