test/harness/testcaseinput.c
author ali <ali@juiblex.co.uk>
Sat Oct 26 18:47:33 2013 +0100 (2013-10-26)
changeset 101 f44c530f80da
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 requested newline, U+240A (visible symbol for LF)
    36  * with \n and U+240D (visible symbol for CR) with \r.
    37  */
    38 static char *convert_newlines(const char *text,int flags)
    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' && !(flags&TESTCASE_UNIX_NEWLINES))
    50 	{
    51 	    if (flags&TESTCASE_OS9_NEWLINES)
    52 		g_string_append_c(string,'\r');
    53 	    else
    54 		g_string_append(string,"\r\n");
    55 	}
    56 	else if (c==visible_lf)
    57 	    g_string_append_c(string,'\n');
    58 	else if (c==visible_cr)
    59 	    g_string_append_c(string,'\r');
    60 	else
    61 	    g_string_append_unichar(string,c);
    62     }
    63     return g_string_free(string,FALSE);
    64 }
    65 
    66 /*
    67  * Create an input file needed for a testcase (as specified in <input>).
    68  * The file is written in the encoding specified for communicating with
    69  * bookloupe. The name_used field of <input> is filled in with the name
    70  * of the created file (which may be different than the name specified
    71  * if that contained "XXXXXX" to be replaced by a unique string).
    72  */
    73 gboolean testcase_input_create(Testcase *testcase,TestcaseInput *input,
    74   GError **error)
    75 {
    76     int fd;
    77     size_t n;
    78     char *filename,*s,*t;
    79     GError *tmp_err=NULL;
    80     if (input->contents)
    81     {
    82 	if (testcase->encoding)
    83 	{
    84 	    t=convert_newlines(input->contents,testcase->flags);
    85 	    s=g_convert(t,-1,testcase->encoding,"UTF-8",NULL,&n,&tmp_err);
    86 	    g_free(t);
    87 	    if (!s)
    88 	    {
    89 		g_propagate_prefixed_error(error,tmp_err,
    90 		  "Conversion to %s failed: ",testcase->encoding);
    91 		return FALSE;
    92 	    }
    93 	}
    94 	else
    95 	{
    96 	    s=convert_newlines(input->contents,testcase->flags);
    97 	    n=strlen(s);
    98 	}
    99     }
   100     else
   101     {
   102 	n=0;
   103 	s=NULL;
   104     }
   105     g_free(input->name_used);
   106     input->name_used=NULL;
   107     if (testcase->tmpdir)
   108 	filename=g_build_filename(testcase->tmpdir,input->name,NULL);
   109     else
   110 	filename=g_strdup(input->name);
   111     if (strstr(input->name,"XXXXXX"))
   112 	fd=g_mkstemp(filename);
   113     else
   114 	fd=g_open(filename,O_WRONLY|O_CREAT|O_EXCL|O_BINARY,0600);
   115     if (fd<0)
   116     {
   117 	g_set_error(error,G_FILE_ERROR,g_file_error_from_errno(errno),
   118 	  "%s: %s",filename,g_strerror(errno));
   119 	g_free(s);
   120 	return FALSE;
   121     }
   122     input->name_used=g_strdup(filename+strlen(filename)-strlen(input->name));
   123     if (n && write_file(fd,s,n,error)!=n)
   124     {
   125 	g_free(s);
   126 	close(fd);
   127 	(void)g_unlink(filename);
   128 	g_free(filename);
   129 	g_free(input->name_used);
   130 	input->name_used=NULL;
   131 	return FALSE;
   132     }
   133     g_free(s);
   134     if (close(fd)<0)
   135     {
   136 	g_set_error(error,G_FILE_ERROR,g_file_error_from_errno(errno),
   137 	  "%s: %s",filename,g_strerror(errno));
   138 	(void)g_unlink(filename);
   139 	g_free(filename);
   140 	g_free(input->name_used);
   141 	input->name_used=NULL;
   142 	return FALSE;
   143     }
   144     g_free(filename);
   145     return TRUE;
   146 }
   147 
   148 /*
   149  * Remove an input file created with testcase_input_create()
   150  */
   151 gboolean testcase_input_remove(Testcase *testcase,TestcaseInput *input,
   152   GError **error)
   153 {
   154     char *filename;
   155     if (input->name_used)
   156     {
   157 	if (testcase->tmpdir)
   158 	    filename=g_build_filename(testcase->tmpdir,input->name_used,NULL);
   159 	else
   160 	    filename=g_strdup(input->name_used);
   161 	if (g_unlink(filename)<0)
   162 	{
   163 	    g_set_error(error,G_FILE_ERROR,g_file_error_from_errno(errno),
   164 	      "%s: %s",filename,g_strerror(errno));
   165 	    return FALSE;
   166 	}
   167 	g_free(filename);
   168 	g_free(input->name_used);
   169 	input->name_used=NULL;
   170     }
   171     return TRUE;
   172 }
   173 
   174 /* Create a new description of an input file needed for a testcase */
   175 TestcaseInput *testcase_input_new(const char *name,const char *contents)
   176 {
   177     TestcaseInput *input;
   178     input=g_new0(TestcaseInput,1);
   179     input->name=g_strdup(name);
   180     input->contents=g_strdup(contents);
   181     return input;
   182 }
   183 
   184 /* Free the description of a testcase input file */
   185 void testcase_input_free(TestcaseInput *input)
   186 {
   187     g_free(input->name);
   188     g_free(input->name_used);
   189     g_free(input->contents);
   190     g_free(input);
   191 }