/* 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 #include #include #include #include #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; itm_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