sectionfile.c

来自「kaffe Java 解释器语言,源码,Java的子集系统,开放源代码」· C语言 代码 · 共 1,220 行 · 第 1/2 页

C
1,220
字号
/* * sectionFile.c * Routines for reading/writing a formatted text file * * Copyright (c) 2000 University of Utah and the Flux Group. * All rights reserved. * * This file is licensed under the terms of the GNU Public License. * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * * Contributed by the Flux Research Group, Department of Computer Science, * University of Utah, http://www.cs.utah.edu/flux/ */#if defined(KAFFE_FEEDBACK)#include <stdio.h>#include <string.h>#include <stdarg.h>#include <unistd.h>#include <ctype.h>#include <stdlib.h>#include <sys/stat.h>#include "kaffe/jmalloc.h"#include "stringSupport.h"#include "debug.h"#include "sectionFile.h"/* Number of buckets for the file_section hash table */#define FILE_SECTION_TYPES_SIZE 31/* Hash table for file_section's */static struct file_section *file_section_types[FILE_SECTION_TYPES_SIZE];static void restoreLine(struct parse_state *ps);static int syncFile(struct parse_state *parent, struct section_file *sf,		    char *filename);/* * Internal state for the file parser */struct parse_state {	struct parse_state *ps_parent;		/* Keep track of nesting */	char *ps_filename;			/* Current file name */	struct section_file *ps_section_file;	/* Root section file */	FILE *ps_in_file;			/* Input File handle */	FILE *ps_out_file;			/* Output File handle */	struct section_file_data *ps_section;	/* Current section */	int ps_line;				/* Current line number */	int ps_column;				/* Current column number */	char *ps_data;				/* Current line string */	int ps_len;				/* Length of line */	char ps_save[2];			/* Storage for damage */};/* * Produce a hash value within table_size, for string `name' */static int hashName(const char *name, int table_size){	int h;	for( h = 0; *name; name++ )		h = (64 * h + tolower(*name)) % table_size;	return( h );}/* * Check for valid characters in a string from the file */static int validStringChar(int c){	int retval = 0;	if( isprint(c) &&	    (c != '#') &&	    (c != '%') &&	    (c != '\\') )		retval = 1;	return( retval );}/* * Write out a utf string with the proper escapes, if needed. */static int writeUtfString(struct parse_state *ps, char *ustr){	int ch, len, error = 0;	char *curr, *end;	len = strlen(ustr);	end = ustr + len;	curr = ustr;	while( (curr < end) && !error )	{		ch = UTF8_GET(curr, end);		if( ch < 0 )		{			error = 1;		}		else if( validStringChar(ch) )		{			/* Plain character, just write it out */			fprintf(ps->ps_out_file, "%c", (char)ch);		}		else		{			/* Write out a UTF8 character with escape sequence */			fprintf(ps->ps_out_file, "\\u%04x", ch);		}	}	return( !error );}enum {	SFS_INVALID,	SFS_PLAIN,	SFS_UTF8,};/* * Figure out what kind of string has come from a file.  If it has UTF8 * escapes we'll need to translate those. */static int stringType(char *str){	int retval = SFS_PLAIN, utf8char = 0;	while( *str && (retval != SFS_INVALID) )	{		if( *str == '\\' )		{			/* Do a thorough check of the escape */			if( (*(str + 1) == 'u') &&			    (sscanf(str + 2, "%x", &utf8char) == 1) )				retval = SFS_UTF8;			else				retval = SFS_INVALID;		}		str++;	}	return( retval );}/* * Convert a UTF8 escaped string from the file into an internal format. */static char *convertUtfString(struct parse_state *ps, char *pstr){	char *retval = 0;	int len;	len = strlen(pstr);	/* We're allocating more than is really needed... */	if( (retval = (char *)KMALLOC(len + 1)) )	{		int lpc, utf8char;		char *curr;		curr = retval;		for( lpc = 0; lpc < len; lpc++ )		{			switch( pstr[lpc] )			{			case '\\':				utf8char = 0;				lpc += 2; /* Skip the 'u' */				if( sscanf(&pstr[lpc],					   "%4x",					   &utf8char) == 1 )				{					char plain_char;					/*					 * XXX This isn't a proper check for a					 * UTF char.  We just check if its can					 * be held within 8 bits and write it					 * directly to the string, otherwise we					 * store it as 16 bits.					 */					plain_char = utf8char;					if( plain_char == utf8char )					{						*curr = plain_char;					}					else					{						*curr = utf8char >> 8;						curr++;						*curr = utf8char & 0xff;					}					curr++;				}				lpc += 3; /* Skip the value */				break;			default:				/* Plain character, just copy it over */				*curr = pstr[lpc];				curr++;				break;			}		}		*curr = 0;	}	return( retval );}/* * Do the actual removal of a section from a file, this is called after * write sync when a section was scheduled for removal. */static void reallyRemoveSectionFromFile(struct section_file *sf,					struct section_file_data *sfd){	struct section_file_data **prev, *curr;	int hash;	/* Remove it from the hash table */	hash = hashName(sfd->sfd_name, SECTION_FILE_HASH_SIZE);	curr = sf->sf_sections[hash];	prev = &sf->sf_sections[hash];	while( curr && (curr != sfd) )	{		prev = &curr->sfd_next;		curr = curr->sfd_next;	}	if( curr )		*prev = sfd->sfd_next;	/* Remove it from the ordered list */	curr = sf->sf_ordered_sections;	prev = &sf->sf_ordered_sections;	while( curr && (curr != sfd) )	{		prev = &curr->sfd_order;		curr = curr->sfd_order;	}	if( curr )		*prev = sfd->sfd_order;}/* Parse a directive line */static int parseDirective(struct parse_state *ps, int curr){	int retval = 1, lpc, directive_len, args_len, line_len;	char *directive, *args, *save, *line;	struct section_file *sf;	FILE *out_file;	sf = ps->ps_section_file;	out_file = ps->ps_out_file;	line_len = ps->ps_len;	line = ps->ps_data;	save = ps->ps_save;	/* The line passed in points to the beginning of the directive */	directive = &line[curr];	/* Move to the end of the directive */	for( lpc = curr; (lpc < line_len) && !isspace(line[lpc]); lpc++ );	directive_len = lpc - curr;	/* The arguments to the directive directly follow it */	args = &line[lpc + 1];	args_len = line_len - (lpc + 1);	if( !strncmp(directive, "%include", directive_len) )	{		int name_start, name_end;		/* Try and get a quoted filename from the args */		for( name_start = 0;		     (name_start < args_len) && (args[name_start] != '\"');		     name_start++ );		for( name_end = name_start + 1;		     (name_end < args_len) && (args[name_end] != '\"');		     name_end++ );		if( (name_start < args_len) && (name_end < args_len) )		{			args[name_end] = 0;			/* Try and sync the include file */			if( !syncFile(ps, ps->ps_section_file,				      args + name_start + 1) )			{				dprintf(					"Error:%s:%d:%d - Unable to process "					"file %s.\n",					ps->ps_filename,					ps->ps_line,					ps->ps_column,					args + name_start + 1);			}			args[name_end] = '\"';		}		else		{			dprintf(				"Error:%s:%d:%d - %%include directive needs "				"a quoted filename.\n",				ps->ps_filename,				ps->ps_line,				ps->ps_column);		}		if( out_file )		{			fwrite(line, 1, line_len, out_file);		}	}	else if( !strncmp(directive, "%begin", directive_len) )	{		char *section_type = 0, *section_name = 0;		struct file_section *type;		int stype;		/* This is the beginning of a section */		/* Parse the args into type and name */		ps->ps_data = args;		ps->ps_len = args_len;		parseSectionLine(ps, &section_type, &section_name, 0);		ps->ps_data = line;		ps->ps_len = line_len;		type = findSectionType(section_type);		switch( (stype = stringType(section_name)) )		{		case SFS_INVALID:			retval = 0;			dprintf(				"Error:%s:%d - Invalid characters in section "				"name\n",				ps->ps_filename,				ps->ps_line);			break;		case SFS_PLAIN:			break;		case SFS_UTF8:			if( !(section_name =			      convertUtfString(ps, section_name)) )				retval = 0;			break;		}		if( !retval )		{		}		else if( (ps->ps_section = findSectionInFile(sf,							     type,							     section_name)) )		{			/* The section already exists */			if( out_file )			{				/*				 * We'll be writing out the data in a bit				 * so clear the dirty bit.				 */				ps->ps_section->sfd_flags &= ~SFDF_DIRTY;			}		}		else if( out_file )		{			/*			 * If we're writing and there's no section then			 * something is screwy and we should probably cache			 * the unseen data...  or not			 */		}		else		{			/*			 * The section hasn't been seen before, make a new			 * one and add it to the structure.			 */			if( (ps->ps_section = createFileSection(section_type,								section_name,								NULL)) )			{				addSectionToFile(sf, ps->ps_section);			}			else			{				retval = 0;			}		}		if( stype == SFS_UTF8 )			KFREE(section_name);		/* Fix the damage parseSectionLine did */		restoreLine(ps);		if( out_file && ps->ps_section &&		    !(ps->ps_section->sfd_flags & SFDF_REMOVED) )		{			fwrite(line, 1, line_len, out_file);		}	}	else if( !strncmp(directive, "%end", directive_len) )	{		/* This is the end of a section */		if( out_file && ps->ps_section )		{			if( ps->ps_section->sfd_flags & SFDF_REMOVED )			{				/* The section was pending removal */				reallyRemoveSectionFromFile(sf,							    ps->ps_section);				deleteFileSection(ps->ps_section);			}			else			{				/* Ask the handler to write any new data out */				retval = ps->ps_section->sfd_type->					fs_handler(ps->ps_section->sfd_type,						   sf,						   SFM_FLUSH,						   ps->ps_section,						   ps,						   0,						   0,						   out_file);				fwrite(line, 1, line_len, out_file);			}		}		/* We're out of the section so clear the current section */		ps->ps_section = 0;	}	else	{		dprintf(			"Error:%s:%d - Directive `%s' is not valid\n",			ps->ps_filename,			ps->ps_line,			directive);	}	if( out_file && ferror(out_file) )		retval = 0;	return( retval );}/* XXX bleh */#define MAX_LINE_SIZE 1024/* * Parse the input file and send any output to `out_file' if there is one */static int parseFile(struct parse_state *ps){	char *line, buffer[MAX_LINE_SIZE];	int retval = 1, line_len;	FILE *in_file, *out_file;	struct section_file *sf;	sf = ps->ps_section_file;	in_file = ps->ps_in_file;	out_file = ps->ps_out_file;	ps->ps_data = buffer;	/* Walk over the input file line by line */	while( retval && (line = fgets(buffer, MAX_LINE_SIZE, in_file)) )	{		int curr;		ps->ps_line++;		ps->ps_column = 0;		ps->ps_len = line_len = strlen(line);		/* Skip white space */		for( curr = 0;		     (curr < line_len) && isspace(line[curr]);		     curr++ )			ps->ps_column++;		if( curr == line_len )		{			/* Empty line, dump to output */			if( out_file )				fwrite(line, 1, line_len, out_file);			continue;		}		/* Found something, parse it */		switch( line[curr] )		{		case '%':			/* Directive's start with %, handle it */			retval = parseDirective(ps, curr);			curr = line_len;			break;		case '#':			/* A comment, dump the rest of the line to output */			if( out_file )			{				fwrite(line, 1, line_len, out_file);			}			curr = line_len;			break;		default:			if( ps->ps_section )			{				if( ps->ps_section->sfd_flags & SFDF_REMOVED )					continue;				/*				 * We're in a section, ask the handler to				 * process it				 */				if( !line_len || (line[line_len - 1] != '\n') )				{					retval = 0;				}				else if( out_file )				{					/* Bring the file up to date */					retval = ps->ps_section->sfd_type->						fs_handler(ps->ps_section->							   sfd_type,							   sf,							   SFM_FLUSH,							   ps->ps_section,							   ps,							   line,							   line_len,							   out_file);				}				else				{					/* Read new data in */					retval = ps->ps_section->sfd_type->						fs_handler(ps->ps_section->							   sfd_type,							   sf,							   SFM_CACHE,							   ps->ps_section,							   ps,							   line,							   line_len);				}			}			else			{				dprintf(					"Error:%s:%d:%d - Text outside of "					"section\n",					ps->ps_filename,					ps->ps_line,					ps->ps_column);				if( out_file )				{					/*					 * Be nice and output it, but put it in					 * a comment					 */					fprintf(out_file, "# %s", line);				}			}			curr = line_len;			break;		}	}	/* Check for errors */	if( ferror(in_file) || (out_file && ferror(out_file)) )		retval = 0;	return( retval );}/* * Check for any new sections added to the section_file and output them to * the file. */static int writeNewSections(struct parse_state *ps){	struct section_file_data *sfd;	struct section_file *sf;	int retval = 1;	FILE *out_file;	sf = ps->ps_section_file;	out_file = ps->ps_out_file;	/* Walk over the hash table links */	sfd = sf->sf_ordered_sections;	while( sfd && retval )	{		if( sfd->sfd_flags & SFDF_DIRTY )		{			/*			 * This section wasn't touched while sync'ing			 * it must be new to the file.			 */			if( sfd->sfd_name[0] )			{				fprintf(out_file,					"\n%%begin %s ",					sfd->sfd_type->fs_name);				retval = writeUtfString(ps, sfd->sfd_name);				fprintf(out_file, "\n");			}			else			{				fprintf(out_file,					"\n%%begin %s\n",					sfd->sfd_type->fs_name);			}			retval = sfd->sfd_type->fs_handler(sfd->sfd_type,							   sf,							   SFM_FLUSH,							   sfd,							   ps,							   0,							   0,							   out_file);			fprintf(out_file, "%%end\n");			sfd->sfd_flags &= ~SFDF_DIRTY;		}		sfd = sfd->sfd_order;	}	if( ferror(out_file) )		retval = 0;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?