Codebase list unrtf / bd13ae3a-94e6-40bf-b472-38179327dae8/main src / user.c
bd13ae3a-94e6-40bf-b472-38179327dae8/main

Tree @bd13ae3a-94e6-40bf-b472-38179327dae8/main (Download .tar.gz)

user.c @bd13ae3a-94e6-40bf-b472-38179327dae8/main

d5eaff9
 
 
 
 
 
 
 
 
 
4329b02
 
 
d5eaff9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
dff09ba
 
 
d5eaff9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4329b02
 
 
 
dff09ba
4329b02
d5eaff9
 
 
 
 
 
 
 
dff09ba
d5eaff9
dff09ba
d5eaff9
4329b02
d5eaff9
 
 
 
dff09ba
d5eaff9
dff09ba
d5eaff9
 
4329b02
d5eaff9
4329b02
d5eaff9
 
 
4329b02
d5eaff9
 
 
dff09ba
d5eaff9
 
 
 
 
 
 
 
 
 
dff09ba
4329b02
 
 
 
 
 
 
 
d5eaff9
dff09ba
 
 
 
 
 
 
 
 
d5eaff9
 
 
 
4329b02
d5eaff9
 
 
 
 
 
 
4329b02
d5eaff9
 
4329b02
 
d5eaff9
 
 
 
 
dff09ba
d5eaff9
dff09ba
d5eaff9
dff09ba
d5eaff9
dff09ba
d5eaff9
 
 
 
 
 
 
 
 
 
 
 
 
 
dff09ba
d5eaff9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
dff09ba
d5eaff9
dff09ba
d5eaff9
dff09ba
d5eaff9
dff09ba
d5eaff9
dff09ba
d5eaff9
 
 
 
dff09ba
 
 
 
d5eaff9
 
 
 
 
 
 
 
 
 
 
 
dff09ba
d5eaff9
dff09ba
d5eaff9
dff09ba
d5eaff9
 
dff09ba
d5eaff9
dff09ba
d5eaff9
 
 
 
dff09ba
d5eaff9
 
dff09ba
 
d5eaff9
dff09ba
 
 
 
 
 
 
 
 
d5eaff9
 
 
 
 
dff09ba
d5eaff9
 
 
dff09ba
d5eaff9
 
 
 
dff09ba
 
 
 
 
 
d5eaff9
dff09ba
d5eaff9
 
/*----------------------------------------------------------------------
 * Module name:  user
 * Author name:  Arkadiusz Firus
 * Create date:  01 Jul 08
 * Purpose:    User's defined output module
 *----------------------------------------------------------------------
 * Changes:
 * 21 Aug 10, daved@physiol.usyd.edu.au: test feof() rather than EOF for
 	AIX support
 * 23 Sep 11, daved - provision for escaping backslash in config files
 * 07 Oct 11, jf@dockes.org: major changes including adding GETC_OR_END
 *      macro and calling get_unicode_char instead of get_unicode_utf8
 *--------------------------------------------------------------------*/

#ifndef HAVE_STDIO_H
#include <stdio.h>
#define HAVE_STDIO_H
#endif

#ifndef HAVE_ERRNO_H
#include <errno.h>
#define HAVE_ERRNO_H
#endif

#ifndef HAVE_STDLIB_H
#include <stdlib.h>
#define HAVE_STDLIB_H
#endif


#include "error.h"
#include "malloc.h"
#include "output.h"
#include <string.h>
#include "user.h"


#include "unicode.h"
#include "util.h"

typedef struct my_F
{
	FILE *file;
	int line_nr;
	char *name;
} my_FILE;


/*========================================================================
 * Name		my_fclose
 * Purpose:	Opens file.
 * Args:	Path to file, mode in which file would be opened.
 * Returns:	Pointer to my_FILE
 *=======================================================================*/

my_FILE *
my_fopen(char *file_name, char *mode)
{
	my_FILE *f = (my_FILE *) malloc(sizeof(my_FILE));

	if ((f->file = fopen(file_name, "r")) == NULL || (f->name = my_malloc((strlen(file_name) + 1) * sizeof(char))) == NULL)
	{
		return NULL;
	}

	f->line_nr = 1;
	strcpy(f->name, file_name);

	return f;
}

/*========================================================================
 * Name		my_fclose
 * Purpose:	Closes file and frees memory.
 * Args:	File to close.
 * Returns:	Nothing
 *=======================================================================*/

void
my_fclose(my_FILE *f)
{
	fclose(f->file);
	my_free(f->name);
}

/*========================================================================
 * Name		give_definition
 * Purpose:	Reads definition value from a file.
 * Args:	File to read from.
 * Returns:	Definition or NULL on error.
 *=======================================================================*/

#define ADD_CHAR(char)\
	if (def_buffer_length == chars_nr)\
	{\
		if ((def = my_realloc(def, def_buffer_length, def_buffer_length * 2)) == NULL)\
		{\
			perror("Cannot allocate memory.");\
			return NULL;\
		}\
		def_buffer_length *= 2;\
	}\
	def[chars_nr] = char;\
	chars_nr++;

#define GETC_OR_END(F, C) {                     \
        C = fgetc(F);                           \
        if (feof(F) || ferror(F))               \
            goto inputend;                      \
    }

char *
give_definition(my_FILE *file)
{
	char c, c2 = 0, c3 = 0, c4 = 0, *def, *unicode_char;
	int i;
	unsigned long def_buffer_length = STANDARD_BUFFER_LENGTH, chars_nr = 0;

	if ((def = my_malloc(def_buffer_length)) == NULL)
	{
		return NULL;
	}

	GETC_OR_END(file->file, c);

	while (c == '\t' || c == '#')
	{
		if (c == '#')
		{
			leave_line(file->file);
		}
		else
		{
			GETC_OR_END(file->file, c);

			while (c != '\n')
			{
				if (c == 'U' && c2 == '<' && (c3 != '\\' || (c3 == '\\' && c4 == '\\')))
				{
					unicode_char = get_unicode_utf8(file->file);

					for (i = 0; unicode_char[i] != '\0'; i++)
						ADD_CHAR(unicode_char[i])
						GETC_OR_END(file->file, c);
					c2 = 0;
					c3 = 0;
					c4 = 0;
				}
				else
				{
					if (c2 == '<')
					{
						ADD_CHAR('<');
					}
					/* daved - 0.21.3 - allow escaping a backslash */
					if (c == '\\' && c2 == '\\')
					{
						ADD_CHAR('\\');
						c = 0;
						c2 = 0;
						c3 = 0;
					}
					else

						/* daved - support \n in definitions */
						if (c == 'n' && c2 == '\\')
						{
							ADD_CHAR('\n');
						}
						else if ((c != '<' && c != '\\') || (c == '\\' && c2 == '\\'))
						{
							ADD_CHAR(c)
						}

					c4 = c3;
					c3 = c2;
					c2 = c;
					GETC_OR_END(file->file, c);
				}
			}

			file->line_nr++;
			ADD_CHAR('\n');
		}

		GETC_OR_END(file->file, c);
	}

inputend:
	if (!feof(file->file) && !ferror(file->file))
	{
		ungetc(c, file->file);
	}

	if (chars_nr > 0)
	{
		def[chars_nr - 1] = '\0';
	}
	else
	{
		def[0] = '\0';
	}

	return def;
}

/*========================================================================
 * Name:	match_name
 * Purpose:	Tries to match known tag names with first argument
 * Args:	Tag name, Output Personality, file to read from
 * Returns:	-1 on error,
		0 on success,
		1 when tag name "name" is unknown
 *=======================================================================*/

int
match_name(char *name, OutputPersonality *op, my_FILE *file)
{
	struct definition
	{
		char *name;
		char **variable;
	} defs[] =  DEFS_ARRAY(op);

	char *endptr;
	int i;

#if 1 /* daved 0.21.0-rc2 */
	for (i = 0; defs[i].name && strcmp(defs[i].name, name); i++);

	if (!defs[i].name)
#else
	for (i = 0; defs[i].name[0] != '\0' && strcmp(defs[i].name, name); i++);

	if (defs[i].name[0] == '\0')
#endif
	{
		i = strtol(name, &endptr, 10);

		if (*endptr == '\0')
		{
			add_alias(op, i, give_definition(file));
		}
		else if (name[0] == '<' && name[1] == 'U')
		{
			add_alias(op, get_unicode(&name[2]), give_definition(file));
		}
		else
		{
			fprintf(stderr, "unrtf: unknown name \"%s\" in line %d of \"%s\"\n", name, file->line_nr, file->name);
			return 1;
		}
	}
	else if ((*defs[i].variable = give_definition(file)) == NULL)
	{
		return -1;
	}

	return 0;
}

/*========================================================================
 * Name:	user_init
 * Purpose:	Generates user's defined output personality.
 * Args:	Path to file with definitions.
 * Returns:	OutputPersonality or NULL on error.
 *=======================================================================*/

OutputPersonality *
user_init(OutputPersonality *op, char *definitions_file_path)
{
	my_FILE *f = NULL;
	char name_buffer[BUFFER_SIZE];
	int err = 1;

	if (op == NULL)
	{
		op = op_create();
	}

	if ((f = my_fopen(definitions_file_path, "r")) == NULL)
	{
		perror(definitions_file_path);
		goto out;
	}

	while (fgets(name_buffer, BUFFER_SIZE - 1, f->file) != NULL
	        && !feof(f->file) && !ferror(f->file))
	{
		int ll = strlen(name_buffer);
		if (ll <= 0 || name_buffer[ll - 1] != '\n')
		{
			/* Something is very wrong. There is no reason to continue
			   parsing a bad config file. Bail out */
			fprintf(stderr, "%s: bad line at %d\n", definitions_file_path,
					f->line_nr);
			goto out;
		}

		f->line_nr++;

		if (name_buffer[0] != '#' && name_buffer[0] != '\n')
		{
			name_buffer[ll - 1] = '\0';

			if (match_name(name_buffer, op, f) == -1)
			{
				goto out;
			}
		}
	}

	err = 0;
out:
	if (f) {
		my_fclose(f);
		free(f);
	}

	return err ? NULL : op;
}