test/harness/testcaseinput.c
author ali <ali@juiblex.co.uk>
Sun Oct 20 21:06:25 2013 +0100 (2013-10-20)
changeset 184 cd3068704d3a
parent 35 51a0beae92f6
permissions -rw-r--r--
Fix bug #24: Accept alternate form of newline
     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 	    if (testcase->flags&TESTCASE_UNIX_NEWLINES)
    80 		s=g_convert(input->contents,-1,testcase->encoding,"UTF-8",NULL,
    81 		  &n,&tmp_err);
    82 	    else
    83 	    {
    84 		t=unix2dos(input->contents);
    85 		s=g_convert(t,-1,testcase->encoding,"UTF-8",NULL,&n,&tmp_err);
    86 		g_free(t);
    87 	    }
    88 	    if (!s)
    89 	    {
    90 		g_propagate_prefixed_error(error,tmp_err,
    91 		  "Conversion to %s failed: ",testcase->encoding);
    92 		return FALSE;
    93 	    }
    94 	}
    95 	else if (testcase->flags&TESTCASE_UNIX_NEWLINES)
    96 	{
    97 	    s=g_strdup(input->contents);
    98 	    n=strlen(s);
    99 	}
   100 	else
   101 	{
   102 	    s=unix2dos(input->contents);
   103 	    n=strlen(s);
   104 	}
   105     }
   106     else
   107     {
   108 	n=0;
   109 	s=NULL;
   110     }
   111     g_free(input->name_used);
   112     input->name_used=NULL;
   113     if (testcase->tmpdir)
   114 	filename=g_build_filename(testcase->tmpdir,input->name,NULL);
   115     else
   116 	filename=g_strdup(input->name);
   117     if (strstr(input->name,"XXXXXX"))
   118 	fd=g_mkstemp(filename);
   119     else
   120 	fd=g_open(filename,O_WRONLY|O_CREAT|O_EXCL|O_BINARY,0600);
   121     if (fd<0)
   122     {
   123 	g_set_error(error,G_FILE_ERROR,g_file_error_from_errno(errno),
   124 	  "%s: %s",filename,g_strerror(errno));
   125 	g_free(s);
   126 	return FALSE;
   127     }
   128     input->name_used=g_strdup(filename+strlen(filename)-strlen(input->name));
   129     if (n && write_file(fd,s,n,error)!=n)
   130     {
   131 	g_free(s);
   132 	close(fd);
   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(s);
   140     if (close(fd)<0)
   141     {
   142 	g_set_error(error,G_FILE_ERROR,g_file_error_from_errno(errno),
   143 	  "%s: %s",filename,g_strerror(errno));
   144 	(void)g_unlink(filename);
   145 	g_free(filename);
   146 	g_free(input->name_used);
   147 	input->name_used=NULL;
   148 	return FALSE;
   149     }
   150     g_free(filename);
   151     return TRUE;
   152 }
   153 
   154 /*
   155  * Remove an input file created with testcase_input_create()
   156  */
   157 gboolean testcase_input_remove(Testcase *testcase,TestcaseInput *input,
   158   GError **error)
   159 {
   160     char *filename;
   161     if (input->name_used)
   162     {
   163 	if (testcase->tmpdir)
   164 	    filename=g_build_filename(testcase->tmpdir,input->name_used,NULL);
   165 	else
   166 	    filename=g_strdup(input->name_used);
   167 	if (g_unlink(filename)<0)
   168 	{
   169 	    g_set_error(error,G_FILE_ERROR,g_file_error_from_errno(errno),
   170 	      "%s: %s",filename,g_strerror(errno));
   171 	    return FALSE;
   172 	}
   173 	g_free(filename);
   174 	g_free(input->name_used);
   175 	input->name_used=NULL;
   176     }
   177     return TRUE;
   178 }
   179 
   180 /* Create a new description of an input file needed for a testcase */
   181 TestcaseInput *testcase_input_new(const char *name,const char *contents)
   182 {
   183     TestcaseInput *input;
   184     input=g_new0(TestcaseInput,1);
   185     input->name=g_strdup(name);
   186     input->contents=g_strdup(contents);
   187     return input;
   188 }
   189 
   190 /* Free the description of a testcase input file */
   191 void testcase_input_free(TestcaseInput *input)
   192 {
   193     g_free(input->name);
   194     g_free(input->name_used);
   195     g_free(input->contents);
   196     g_free(input);
   197 }