DataMuseum.dk

Presents historical artifacts from the history of:

DKUUG/EUUG Conference tapes

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about DKUUG/EUUG Conference tapes

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - metrics - download
Index: T z

⟦1a7731619⟧ TextFile

    Length: 14115 (0x3723)
    Types: TextFile
    Names: »zfile.c«

Derivation

└─⟦a05ed705a⟧ Bits:30007078 DKUUG GNU 2/12/89
    └─⟦ff23ba0e6⟧ »./ghostscript-1.3.tar.Z« 
        └─⟦a24a58cd3⟧ 
            └─⟦this⟧ »zfile.c« 

TextFile

/* 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;
}