archie/prospero/lib/psrv/wais_gw/irfileio.c
2024-05-27 16:13:40 +02:00

773 lines
15 KiB
C

/* WIDE AREA INFORMATION SERVER SOFTWARE:
Developed by Thinking Machines Corporation and put into the public
domain with no guarantees or restrictions.
*/
/*---------------------------------------------------------------------------*/
/********************************************************
* Writing and reading structures to files. *
* *
* These use the Lisp printer format with the *
* lisp naming conventions. You ask: "Why would *
* you want to use that?". Well, we need an *
* easily readable data syntax that can handle *
* a large number of different data types. *
* Further, we need it to be tagged so that *
* run time tagged languages can read it and *
* it is flexible. We need one that supports *
* optional fields so that the format can *
* grow backcompatibly. And (the kicker), *
* it must be read from many languages since *
* user interfaces may be written in anything *
* from smalltalk to hypercard. *
* *
* -brewster 5/10/90 *
********************************************************/
#include <string.h>
#include <ctype.h>
#include <time.h>
#include <pfs.h>
#include <perrno.h>
#include "irfileio.h"
#include "cutil.h"
#define INDENT_SPACES (2L)
#define MAX_INDENT (40L)
#ifdef NOTUSEDANDNOTTHREADSAFE
static long indent_level;
#endif /*NOTUSEDANDNOTTHREADSAFE
#define RETURN(val) {retval = val; goto cleanup; }
/**********************/
/**********************/
#ifdef NOTUSEDANDNOTTHREADSAFE
static void indent(FILE* file);
static void indent(file)
FILE* file;
{
long i;
for(i = 0; i <= MIN(MAX_INDENT, MAX(0L, indent_level * INDENT_SPACES)); i++){
putc(' ', file);
}
}
long WriteStartOfList(file)
FILE* file;
{
indent_level++;
return(fprintf(file, " ( "));
}
long WriteEndOfList(file)
FILE* file;
{
indent_level--;
return(fprintf(file, " ) "));
}
long WriteStartOfStruct(name,file)
char* name;
FILE* file;
{
indent_level++;
return(fprintf(file, " (:%s ", name));
}
long WriteEndOfStruct(file)
FILE* file;
{
indent_level--;
return(fprintf(file, " ) "));
}
long WriteSymbol(name,file)
char* name;
FILE* file;
{
return(fprintf(file, " %s ", name));
}
long WriteNewline(file)
FILE* file;
{
long return_value = fprintf(file, "\n");
indent(file);
return(return_value);
}
long WriteLong(number,file)
long number;
FILE* file;
{
return(fprintf(file, " %ld ", number));
}
long WriteDouble(number,file)
double number;
FILE* file;
{
return(fprintf(file, " %f ", number));
}
long WriteString(string,file)
char* string;
FILE* file;
{
long i;
putc('\"', file);
for(i = 0; i < strlen(string); i++){
if(string[i] == '\\' || string[i] == '\"')
putc('\\', file);
putc(string[i], file);
}
putc('\"', file);
return(1);
}
long WriteAny(value,file)
any* value;
FILE* file;
{
WriteStartOfStruct("any", file);
WriteSymbol(":size", file); WriteLong(value->size, file);
WriteSymbol(":bytes", file);
Write8BitArray(value->size, value->bytes, file);
return(WriteEndOfStruct(file));
}
long Write8BitArray(length,array,file)
long length;
char* array;
FILE* file;
{
long i;
fprintf(file, " #( ");
for(i=0; i<length; i++){
WriteLong((long)array[i], file);
}
return(fprintf(file, " ) "));
}
long WriteTM(atime,file)
struct tm* atime;
FILE* file;
{
WriteStartOfStruct("tm", file);
WriteSymbol(":tm-sec", file); WriteLong(atime->tm_sec, file);
WriteSymbol(":tm-min", file); WriteLong(atime->tm_min, file);
WriteSymbol(":tm-hour", file); WriteLong(atime->tm_hour, file);
WriteSymbol(":tm-mday", file); WriteLong(atime->tm_mday, file);
WriteSymbol(":tm-mon", file); WriteLong(atime->tm_mon, file);
WriteNewline(file);
WriteSymbol(":tm-year", file); WriteLong(atime->tm_year, file);
WriteSymbol(":tm-wday", file); WriteLong(atime->tm_wday, file);
WriteNewline(file);
WriteSymbol(":tm-yday", file); WriteLong(atime->tm_yday, file);
WriteSymbol(":tm-isdst", file); WriteLong(atime->tm_isdst, file);
WriteEndOfStruct(file);
return(WriteNewline(file));
}
boolean
writeAbsoluteTime(atime,file)
struct tm* atime;
FILE* file;
{
WriteStartOfStruct("absolute-time",file);
WriteNewline(file);
WriteSymbol(":year",file); WriteLong((long)atime->tm_year,file);
WriteNewline(file);
WriteSymbol(":month",file); WriteLong((long)atime->tm_mon,file);
WriteNewline(file);
WriteSymbol(":mday",file); WriteLong((long)atime->tm_mday,file);
WriteNewline(file);
WriteSymbol(":hour",file); WriteLong((long)atime->tm_hour,file);
WriteNewline(file);
WriteSymbol(":minute",file); WriteLong((long)atime->tm_min,file);
WriteNewline(file);
WriteSymbol(":second",file); WriteLong((long)atime->tm_sec,file);
WriteNewline(file);
return(WriteEndOfStruct(file));
}
#endif /*NOTUSEDANDNOTTHREADSAFE*/
/************************/
/************************/
#define BEFORE (1L)
#define DURING (2L)
#define HASH (3L)
#define S (4L)
#define QUOTE (5L)
#if !defined(IN_RMG)
boolean ReadStartOfList(file)
FILE* file;
{
long ch;
while(TRUE){
ch = getc(file);
if(ch == '(')
return(TRUE);
if(!isspace(ch)){
if(ch == 'N' || ch == 'n'){
ch = getc(file);
if(ch == 'I' || ch == 'i'){
ch = getc(file);
if(ch == 'L' || ch == 'l'){
ungetc(')', file);
return(TRUE);
}
}
}
return(FALSE);
}
}
}
boolean ReadEndOfList(file)
FILE* file;
{
long ch;
while(TRUE){
ch = getc(file);
if(ch == ')')
return(TRUE);
if(!isspace(ch))
return(FALSE);
}
}
#endif /*!IN_RMG*/
#define STRING_ESC '\\'
long
SkipObject(file)
FILE* file;
{
long ch;
while (true)
{ ch = getc(file);
if (ch == EOF)
return (EOF);
else
{ if (isspace(ch))
continue;
else if (ch == '"')
{ long escapeCount = 0;
while (true)
{ ch = getc(file);
if (ch == EOF)
return (EOF);
else
{ if (ch == STRING_ESC)
{ escapeCount++;
escapeCount = escapeCount % 2;
}
if (ch == '"' && escapeCount == 0)
break;
}
}
break;
}
else if ((isdigit(ch) || ch == '-' || ch == '.') ||
(ch == ':'))
{ while (!isspace(ch))
{ ch = getc(file);
if (ch == EOF)
return(EOF);
}
break;
}
else if ((ch == '#') ||
(ch == '('))
{ long parenCount = 1;
if (ch == '#')
ch = getc(file);
while (parenCount > 0)
{ ch = getc(file);
if (ch == EOF)
return(EOF);
else if (ch == '"')
{
ungetc(ch,file);
SkipObject(file);
}
else if (ch == '(')
parenCount++;
else if (ch == ')')
parenCount--;
}
break;
}
}
}
return(true);
}
long ReadLong(file,answer)
FILE* file;
long* answer;
{
long ch;
long state = BEFORE;
boolean isNegative = false;
long count = 0;
*answer = 0;
while(TRUE){
ch = getc(file);
if (ch == EOF){
break;
}
else if (isdigit(ch)){
if(state == BEFORE){
state = DURING;
}
count++;
if(count == 12){
return(false);
}
*answer = *answer * 10 + (ch - '0');
}
else if (ch == '-') {
if (isNegative)
return(false);
if (state == BEFORE) {
isNegative = true;
state = DURING;
}
else {
ungetc(ch,file);
break;
}
}
else if(ch == ')' && (state == DURING)){
ungetc(ch, file);
return(true);
}
else if(!isspace(ch)){
return(false);
}
else if(state == DURING){
ungetc(ch, file);
break;
}
}
if (isNegative)
*answer *= -1;
return(true);
}
long ReadDouble(file,answer)
FILE* file;
double* answer;
{
long ch;
long state = BEFORE;
long count = 0;
long decimal_count = 0;
*answer = 0.0;
while(TRUE){
ch = getc(file);
if (ch == EOF){
return(true);
}
else if (ch == '.'){
decimal_count ++;
}
else if (isdigit(ch)){
if(state == BEFORE){
state = DURING;
}
count++;
if(count == 12){
return(false);
}
if (decimal_count == 0){
*answer = *answer * 10 + (ch - '0');
}
else{
double fraction = (ch - '0');
long internal_count;
for(internal_count = 0; internal_count < decimal_count;
internal_count++){
fraction = fraction / 10.0;
}
*answer = *answer + fraction;
decimal_count++;
}
}
else if(!isspace(ch)){
return(false);
}
else if(state == DURING){
ungetc(ch, file);
return(true);
}
}
}
static boolean issymbolchar(long ch);
static
boolean issymbolchar(ch)
long ch;
{
return(!( isspace(ch) || ch == ')' || ch == '(' || ch == EOF));
}
long ReadSymbol(string,file,string_size)
char* string;
FILE* file;
long string_size;
{
long ch;
long state = BEFORE;
long position = 0;
while(TRUE){
ch = getc(file);
if((state == BEFORE) && (ch == ')'))
return(END_OF_STRUCT_OR_LIST);
if(issymbolchar((long)ch)){
if(state == BEFORE)
state = DURING;
string[position] = ch;
position++;
if(position >= string_size){
string[string_size - 1] = '\0';
return(FALSE);
}
}
else if((state == DURING) || ch == EOF){
if(ch != EOF) ungetc(ch, file);
string[position] = '\0';
return(TRUE);
}
}
}
#if !defined(IN_RMG)
long ReadEndOfListOrStruct(file)
FILE* file;
{
long ch;
while(TRUE){
ch = getc(file);
if (EOF == ch)
return(FALSE);
else if(')' == ch)
return(TRUE);
else if(!isspace(ch))
return(FALSE);
}
}
#endif
long ReadString(string,file,string_size)
char* string;
FILE* file;
long string_size;
{
long ch;
long state = BEFORE;
long position = 0;
string[0] = '\0';
while(TRUE){
ch = getc(file);
if((state == BEFORE) && (ch == '\"'))
state = DURING;
else if (EOF == ch){
string[position] = '\0';
return(FALSE);
}
else if ((state == BEFORE) && (ch == ')'))
return(END_OF_STRUCT_OR_LIST);
else if ((state == DURING) && (ch == '\\'))
state = QUOTE;
else if ((state == DURING) && (ch == '"')){
string[position] = '\0';
return(TRUE);
}
else if ((state == QUOTE) || (state == DURING)){
if(state == QUOTE)
state = DURING;
string[position] = ch;
position++;
if(position >= string_size){
string[string_size - 1] = '\0';
return(FALSE);
}
}
}
}
long ReadStartOfStruct(name,file)
char* name;
FILE* file;
{
int ch;
long state = BEFORE;
name[0] = '\0';
while(TRUE){
ch = getc(file);
if((state == BEFORE) && (ch == '#'))
state = HASH;
if((state == BEFORE) && (ch == '('))
state = DURING;
else if((state == BEFORE) && (ch == ')'))
return(END_OF_STRUCT_OR_LIST);
else if((state == BEFORE) && !isspace(ch))
return(FALSE);
else if(state == HASH){
if (ch == 's')
state = S;
else{
fprintf(stderr,"Expected an 's' but got an %c\n", ch);
return(FALSE);
}
}
else if(state == S){
if (ch == '(')
state = DURING;
else{
fprintf(stderr,"Expected an '(' but got an an %c\n",ch);
return(FALSE);
}
}
else if(state == DURING){
return(ReadSymbol(name, file, MAX_SYMBOL_SIZE));
}
}
}
long CheckStartOfStruct(name,file)
char* name;
FILE* file;
{
char temp_string[MAX_SYMBOL_SIZE];
long result = ReadStartOfStruct(temp_string, file);
if(result == END_OF_STRUCT_OR_LIST)
return(END_OF_STRUCT_OR_LIST);
else if(result == FALSE)
return(FALSE);
else if(0 == strcmp(temp_string, name))
return(TRUE);
else
return(FALSE);
}
#if !defined(IN_RMG)
long ReadAny(destination,file)
any* destination;
FILE* file;
{
char temp_string[MAX_SYMBOL_SIZE];
long retval;
destination->size = 0;
if(FALSE == CheckStartOfStruct("any", file)){
fprintf(stderr,"An 'any' structure was not read from the disk");
return(FALSE);
}
while(TRUE){
long check_result;
check_result = ReadSymbol(temp_string, file, MAX_SYMBOL_SIZE);
if(FALSE == check_result)
return(FALSE);
if(END_OF_STRUCT_OR_LIST == check_result)
RETURN(TRUE);
if(0 == strcmp(temp_string, ":size")) {
long size;
ReadLong(file,&size);
destination->size = (unsigned long)size;
}
else if(0 == strcmp(temp_string, ":bytes")){
long result;
destination->bytes = (char*)s_malloc(destination->size);
if(NULL == destination->bytes){
/* May never get here, s_malloc may abort if no space */
p_err_string = qsprintf_stcopyr(p_err_string,
"Error on reading file. Malloc couldnt allocate %d bytes",
destination->size );
RETURN(FALSE);
}
result = Read8BitArray(destination->bytes, file, destination->size);
if(FALSE == result)
RETURN(FALSE);
}
else{
p_err_string = qsprintf_stcopyr(p_err_string,
"Unknown keyword for ANY %s\n", temp_string);
RETURN(FALSE);
}
} /*while*/
cleanup:
/* For now, not freeing destination->bytes on error, let caller do it*/
return(retval);
}
long
Read8BitArray(char *destination, FILE *file,long len)
{
int ch; /* don't use a long, because %c conversion
isn't defined for longs. */
long state = BEFORE;
while(TRUE){
ch = getc(file);
if((state == BEFORE) && ((ch == '#') || (ch == '('))) {
if (ch == '(') state = DURING;
else state = HASH;
}
else if((state == BEFORE) && !isspace(ch)){
fprintf(stderr,"error in reading array. Expected # and got %c", ch);
return(FALSE);
}
else if(state == HASH){
if (ch == '(')
state = DURING;
else{
fprintf(stderr,"Expected an '(' but got an %c\n", ch);
return(FALSE);
}
}
else if(state == DURING){
long i;
ungetc(ch, file);
for(i = 0; i < len; i++){
long value;
if(ReadLong(file,&value) == false){
fprintf(stderr,"Error in reading a number from the file.");
return(FALSE);
}
if(value > 255){
fprintf(stderr,"Error in reading file. Expected a byte in an ANY, but got %ld", value);
return(FALSE);
}
destination[i] = (char)value;
}
if(FALSE == ReadEndOfListOrStruct(file)){
fprintf(stderr,"array was wrong length");
return(FALSE);
}
return(TRUE);
}
}
}
boolean
readAbsoluteTime(atime,file)
struct tm* atime;
FILE* file;
{
if (CheckStartOfStruct("absolute-time",file) == FALSE)
return(false);
while (true)
{ long result;
long val;
char temp_string[MAX_SYMBOL_SIZE + 1];
result = ReadSymbol(temp_string,file,MAX_SYMBOL_SIZE);
if (result == END_OF_STRUCT_OR_LIST)
break;
else if (result == false)
return(false);
if (strcmp(temp_string,":second") == 0)
{ if (ReadLong(file,&val) == false)
return(false);
atime->tm_sec = val;
}
else if (strcmp(temp_string,":minute") == 0)
{ if (ReadLong(file,&val) == false)
return(false);
atime->tm_min = val;
}
else if (strcmp(temp_string,":hour") == 0)
{ if (ReadLong(file,&val) == false)
return(false);
atime->tm_hour = val;
}
else if (strcmp(temp_string,":mday") == 0)
{ if (ReadLong(file,&val) == false)
return(false);
atime->tm_mday = val;
}
else if (strcmp(temp_string,":month") == 0)
{ if (ReadLong(file,&val) == false)
return(false);
atime->tm_mon = val;
}
else if (strcmp(temp_string,":year") == 0)
{ if (ReadLong(file,&val) == false)
return(false);
atime->tm_year = val;
}
else
SkipObject(file);
}
return(true);
}
#endif