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