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