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