|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T z
Length: 14115 (0x3723) Types: TextFile Names: »zfile.c«
└─⟦a05ed705a⟧ Bits:30007078 DKUUG GNU 2/12/89 └─⟦ff23ba0e6⟧ »./ghostscript-1.3.tar.Z« └─⟦a24a58cd3⟧ └─⟦this⟧ »zfile.c«
/* Copyright (C) 1989 Aladdin Enterprises. All rights reserved. Distributed by Free Software Foundation, Inc. This file is part of Ghostscript. Ghostscript is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY. No author or distributor accepts responsibility to anyone for the consequences of using it or for whether it serves any particular purpose or works at all, unless he says so in writing. Refer to the Ghostscript General Public License for full details. Everyone is granted permission to copy, modify and redistribute Ghostscript, but only under the conditions described in the Ghostscript General Public License. A copy of this license is supposed to have been given to you along with Ghostscript so you can know your rights and responsibilities. It should be in a file named COPYING. Among other things, the copyright notice and this notice must be preserved on all copies. */ /* zfile.c */ /* File operators for GhostScript */ #include <stdio.h> #include "ghost.h" #include "errors.h" #include "oper.h" #include "alloc.h" #include "stream.h" #include "store.h" /* Forward references */ private int write_string(P2(ref *, stream *)); /* Imported from scanner.c */ extern char *scan_char_decoder; /* Import the execution stack for currentfile */ extern ref estack[]; extern ref *esp; /* File objects store a file table index in the size field, */ /* and a sequence number (for checking validity) in value.intval. */ /* Open file table. This is bigger than any OS supports. */ /* The s field of each entry either points to a stream */ /* (if the entry is in use), or is zero if the entry is free. */ /* A file object is legal iff the sequence number */ /* in the files table matches the sequence number in the file object. */ #define max_files 40 typedef struct { stream *s; ushort seq_num; } file_entry; private file_entry files[max_files]; /* Standard file objects: */ /* 0 is stdin, 1 is stdout, 2 is stderr, 3 is linedit, 4 is statementedit */ #define max_std_file 4 private int next_file; /* next index for assigning files */ private char *std_file_names[max_std_file + 1] = { "%stdin", "%stdout", "%stderr", "%linedit", "%statementedit" }; /* File buffer size. This is arbitrary, since the C library does its own */ /* buffering in addition. stdout and stderr use smaller buffers, */ /* on the assumption that they are usually not real files. */ #define buffer_size 512 #define buffer_size_std 128 /* Macros for checking file validity */ #define check_file_access(svar,op,acc)\ { file_entry *fe = &files[(op)->size];\ svar = fe->s; /* do first for access check */\ if ( fe->seq_num != (op)->value.index || !(acc) )\ return e_invalidaccess;\ } #define check_file_ref(svar,op,acc)\ { if ( r_type(op) != t_file ) return e_typecheck;\ check_file_access(svar,op,acc);\ } #define check_file(svar,op) check_file_ref(svar,op,1) #define check_read_file(svar,op) check_file_ref(svar,op,!svar->writing) #define check_write_file(svar,op) check_file_ref(svar,op,svar->writing) /* Initialize the file table */ void zfile_init() { int i; for ( i = 0; i < max_files; i++ ) files[i].s = 0, files[i].seq_num = 0; next_file = max_std_file + 1; /* Create files for stdin, stdout, and stderr. */ /****** stdin IS NOT IMPLEMENTED PROPERLY ******/ files[0].s = (stream *)alloc(sizeof(stream), "zfile_init"); sread_file(files[0].s, stdin, (byte *)alloc(1, "zfile_init"), 1); files[1].s = (stream *)alloc(sizeof(stream), "zfile_init"); swrite_file(files[1].s, stdout, (byte *)alloc(buffer_size_std, "zfile_init"), buffer_size_std); files[2].s = (stream *)alloc(sizeof(stream), "zfile_init"); swrite_file(files[2].s, stderr, (byte *)alloc(buffer_size_std, "zfile_init"), buffer_size_std); } /* file */ int zfile(register ref *op) { char *file_access; ref fname, file; int i; int code; fname = op[-1]; check_type(fname, t_string); check_type(*op, t_string); if ( op->size != 1 ) return e_invalidfileaccess; switch ( *op->value.bytes ) { case 'r': file_access = "r"; break; case 'w': file_access = "w"; break; default: return e_invalidfileaccess; } for ( i = 0; i <= max_std_file; i++ ) if ( !bytes_compare(fname.value.bytes, fname.size, std_file_names[i], strlen(std_file_names[i])) ) { /* This is a standard file */ stream *s; int attrs = (*file_access == 'r' ? a_read+a_execute : a_write+a_execute); make_tasv(&file, t_file, attrs, i, index, 0); code = file_check(&file, (attrs & a_write) != 0, &s); if ( code >= 0 ) op[-1] = file, pop(1); return code; } code = file_open(fname.value.bytes, fname.size, file_access, op - 1); if ( code >= 0 ) pop(1); return code; } /* closefile */ int zclosefile(register ref *op) { stream *s; int code; check_file(s, op); if ( (code = file_close(op, s)) >= 0 ) pop(1); return code; } /* read */ int zread(register ref *op) { stream *s; int ch; check_read_file(s, op); ch = sgetc(s); if ( ch == EOFC ) make_bool(op, 0); else { make_int(op, ch); push(1); make_bool(op, 1); } return 0; } /* write */ int zwrite(register ref *op) { stream *s; ulong ch; check_write_file(s, op - 1); check_type(*op, t_integer); ch = op->value.intval; if ( ch > 0xff ) return e_rangecheck; sputc((byte)ch, s); pop(2); return 0; } /* readhexstring */ int zreadhexstring(register ref *op) { stream st; register stream *s; byte *ptr; byte *limit; int ch, val1, val2; int filled; ref *op1 = op - 1; switch ( r_type(op1) ) { default: return e_typecheck; case t_file: check_read_file(s, op1); break; case t_string: s = &st; sread_string(s, op1->value.bytes, op1->size); } check_type(*op, t_string); ptr = op->value.bytes; limit = ptr + op->size; while ( ptr != limit ) { while ( (val1 = scan_char_decoder[ch = sgetc(s)]) >= 0x10 ) { if ( ch == EOFC ) goto ended; } while ( (val2 = scan_char_decoder[ch = sgetc(s)]) >= 0x10 ) { if ( ch == EOFC ) goto ended; } *ptr++ = (val1 << 4) + val2; } if ( ch == '\r' ) /* check for \r\n */ { ch = sgetc(s); if ( ch != '\n' && ch != EOFC ) sputback(s); } filled = 1; goto out; /* Reached end-of-file before filling the string. */ /* Return an appropriate substring. */ ended: op->size = ptr - op->value.bytes; r_set_attrs(op, a_subrange); filled = 0; out: if ( s == &st ) { /* Reading from a string, return remainder */ uint pos = stell(&st); push(1); op1->size -= pos, op1->value.bytes += pos; r_set_attrs(op1, a_subrange); } else { /* Reading from a file */ op[-1] = *op; } make_bool(op, filled); return 0; } /* writehexstring */ int zwritehexstring(register ref *op) { stream *s; byte *p; uint len; static char *hex_digits = "0123456789abcdef"; check_write_file(s, op - 1); check_type(*op, t_string); p = op->value.bytes; len = op->size; while ( len-- ) { byte ch = *p++; sputc(hex_digits[ch >> 4], s); sputc(hex_digits[ch & 0xf], s); } pop(2); return 0; } /* readstring */ int zreadstring(register ref *op) { stream *s; uint len, rlen; check_read_file(s, op - 1); check_type(*op, t_string); len = op->size; rlen = sgets(op->value.bytes, len, s); op->size = rlen; r_set_attrs(op, a_subrange); op[-1] = *op; make_bool(op, (rlen == len ? 1 : 0)); return 0; } /* writestring */ int zwritestring(register ref *op) { stream *s; int code; check_write_file(s, op - 1); code = write_string(op, s); if ( code >= 0 ) pop(2); return code; } /* readline */ int zreadline(register ref *op) { stream *s; byte *ptr; uint size; int ch; check_read_file(s, op - 1); check_type(*op, t_string); ptr = op->value.bytes; size = op->size; while ( size ) { switch ( ch = sgetc(s) ) { case '\r': ch = sgetc(s); if ( ch != '\n' && ch != EOFC ) sputback(s); /* falls through */ case '\n': op->size -= size; r_set_attrs(op, a_subrange); op[-1] = *op; make_bool(op, 1); return 0; case EOFC: op->size -= size; r_set_attrs(op, a_subrange); op[-1] = *op; make_bool(op, 0); return 0; } *ptr++ = ch; size--; } return e_rangecheck; /* filled the string */ } /* token - this is called from zstring.c */ int ztoken_file(register ref *op) { stream *s; ref token; int code; check_read_file(s, op); switch ( code = scan_token(s, 0, &token) ) { case 0: /* read a token */ *op = token; push(1); make_bool(op, 1); return 0; case 1: /* no tokens */ make_bool(op, 0); return 0; default: /* error */ return code; } } /* bytesavailable */ int zbytesavailable(register ref *op) { stream *s; long pos, end; check_read_file(s, op); pos = ftell(s->file); if ( fseek(s->file, 0L, 2) ) return e_ioerror; end = ftell(s->file); if ( fseek(s->file, pos, 0) ) return e_ioerror; make_int(op, end - pos); return 0; } /* flush */ int zflush(register ref *op) { sflush(files[1].s); return 0; } /* flushfile */ int zflushfile(register ref *op) { stream *s; check_file(s, op); sflush(s); if ( !s->writing ) fseek(s->file, 0L, 2); /* set to end */ return 0; } /* resetfile */ int zresetfile(register ref *op) { NYI("resetfile"); pop(1); return 0; } /* status */ int zstatus(register ref *op) { check_type(*op, t_file); make_bool(op, (files[op->size].seq_num == op->value.index ? 1 : 0)); return 0; } /* run */ int zrun(register ref *op) { NYI("run"); pop(1); return 0; } /* currentfile */ int zcurrentfile(register ref *op) { ref *ep = esp; push(1); while ( ep >= estack ) { if ( r_type(ep) == t_file ) { *op = *ep; return 0; } ep--; } /* Return an invalid file object. */ /* This doesn't make a lot of sense to me, */ /* but it's what the PostScript manual specifies. */ make_tasv(op, t_file, 0, 0, index, -1); return 0; } /* print */ int zprint(register ref *op) { int code = write_string(op, files[1].s); if ( code >= 0 ) pop(1); return code; } /* echo */ int zecho(register ref *op) { check_type(*op, t_boolean); /****** NOT IMPLEMENTED YET ******/ pop(1); return 0; } /* setfileposition */ int zsetfileposition(register ref *op) { stream *s; check_file(s, op - 1); check_type(*op, t_integer); if ( sseek(s, op->value.intval) < 0 ) return e_ioerror; pop(2); return 0; } /* currentfileposition */ int zcurrentfileposition(register ref *op) { stream *s; check_file(s, op); if ( !sseekable(s) ) return e_ioerror; make_int(op, stell(s)); return 0; } /* ------ Initialization procedure ------ */ void zfile_op_init() { static op_def my_defs[] = { {"1bytesavailable", zbytesavailable}, {"1closefile", zclosefile}, {"0currentfile", zcurrentfile}, {"0currentfileposition", zcurrentfileposition}, {"1echo", zecho}, {"2file", zfile}, {"0flush", zflush}, {"1flushfile", zflushfile}, {"1print", zprint}, {"1read", zread}, {"2readhexstring", zreadhexstring}, {"2readline", zreadline}, {"2readstring", zreadstring}, {"1resetfile", zresetfile}, {"1run", zrun}, {"2setfileposition", zsetfileposition}, {"1status", zstatus}, {"2write", zwrite}, {"2writehexstring", zwritehexstring}, {"2writestring", zwritestring}, op_def_end }; z_op_init(my_defs); } /* ------ Non-operator routines ------ */ /* Open a file and create a file object. */ /* Return 0 if successful, error code if not. */ /* The startup code calls this to open the initialization file ghost.ps. */ file_open(byte *fname, uint len, char *file_access, ref *pfile) { byte *buffer; stream *s; char *file_name; FILE *file; /* Allocate the buffer and stream first. */ if ( len >= buffer_size ) return e_limitcheck; /* we copy the file name into the buffer */ buffer = (byte *)alloc(buffer_size, "file_open(buffer)"); if ( buffer == 0 ) return e_VMerror; s = (stream *)alloc(sizeof(stream), "file_open(stream)"); if ( s == 0 ) { alloc_free((char *)buffer, buffer_size, "file_open(buffer)"); return e_VMerror; } /* Copy the name (so we can terminate it with a zero byte.) */ file_name = (char *)buffer; memcpy(file_name, fname, len); file_name[len] = 0; /* terminate string */ /* Open the file. */ file = fopen(file_name, file_access); if ( file == 0 ) { alloc_free((char *)s, sizeof(stream), "file_open(stream)"); alloc_free((char *)buffer, buffer_size, "file_open(buffer)"); return e_undefinedfilename; } /* Assign the next available file index. */ /* There will surely be one, because there are more */ /* file indices than any OS allows open files. */ while ( files[next_file].s != 0 ) if ( ++next_file == max_files ) next_file = max_std_file + 1; if ( *file_access == 'r' ) /* reading */ sread_file(s, file, buffer, buffer_size); else swrite_file(s, file, buffer, buffer_size); files[next_file].s = s; make_tasv(pfile, t_file, (*file_access == 'r' ? a_read+a_execute : a_write+a_execute), next_file, index, files[next_file].seq_num); return 0; } /* Check a file for validity. */ /* The interpreter calls this to check an executable file. */ int file_check(ref *op, int for_writing, stream **ps) { stream *s; check_file_access(s, op, (for_writing ? s->writing : !s->writing) ); *ps = s; return 0; } /* Close a file. The interpreter calls this when */ /* it reaches the end of an executable file. */ int file_close(ref *fp /* t_file */, stream *s) { int idx = fp->size; byte *buffer = s->buf; if ( idx <= max_std_file ) /* can't close std files */ return e_invalidaccess; if ( sclose(s) ) return e_ioerror; /* Free the stream and buffer in the reverse of the order */ /* in which they were created, and hope for LIFO storage behavior. */ alloc_free((char *)s, sizeof(stream), "file_close(stream)"); alloc_free((char *)buffer, buffer_size, "file_close(buffer)"); files[idx].s = 0; files[idx].seq_num++; /* prevent use of closed files */ return 0; } /* ------ Internal routines ------ */ /* Write a string on a file. The file has been checked for validity, */ /* but not the string. */ private int write_string(ref *op, stream *s) { uint len; check_type(*op, t_string); len = op->size; if ( sputs(op->value.bytes, len, s) != len ) return e_ioerror; return 0; }