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, §ion_type, §ion_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 + -
显示快捷键?