home *** CD-ROM | disk | FTP | other *** search
- /* Copyright (C) 1989, 1990, 1991 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 */
- /* Non-I/O file operators for Ghostscript */
- #include "memory_.h"
- #include "string_.h"
- #include "ghost.h"
- #include "gp.h"
- #include "errors.h"
- #include "oper.h"
- #include "alloc.h"
- #include "estack.h" /* for filenameforall */
- #include "iutil.h"
- #include "save.h" /* for restore */
- #include "stream.h"
- #include "file.h" /* must come after stream.h */
- #include "store.h"
-
- /* Forward references */
- int lib_file_open(P3(byte *, uint, ref *));
- int file_open(P5(byte *, uint, char *, ref *, stream **));
- int file_close(P2(ref *, stream *));
- private int open_std_file(P3(os_ptr, char *, os_ptr));
- /* In zfileio.c */
- ref *zget_current_file(P0());
-
- /* Imported from gs.c */
- extern char **gs_lib_paths; /* search path list, */
- /* terminated by a null pointer */
-
- /* The chain of all open files. We need this only */
- /* so that we can do the right thing for restore (and GC someday). */
- private ref all_files; /* t_file */
- #define file_list all_files.value.pfile
-
- /* File buffer sizes. For real files, 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. */
- /* The buffer size for type 1 encrypted files is NOT arbitrary: */
- /* it must be at most 512. */
- #define buffer_size 512
-
- /* Standard file objects: */
- /* 0 is stdin, 1 is stdout, 2 is stderr, 3 is lineedit, 4 is statementedit */
- #define num_std_files 5
- stream invalid_file_entry;
- private byte
- #define stdin_buf_size 1
- stdin_buf[stdin_buf_size],
- #define stdout_buf_size 128
- stdout_buf[stdout_buf_size],
- #define stderr_buf_size 128
- stderr_buf[stderr_buf_size],
- #define lineedit_buf_size 160
- lineedit_buf[lineedit_buf_size];
- /* statementedit is equivalent to lineedit for now */
- stream std_files[num_std_files];
- private char *std_file_names[num_std_files] =
- { "%stdin",
- "%stdout",
- "%stderr",
- "%lineedit",
- "%statementedit"
- };
- private int std_file_attrs[num_std_files] =
- { a_read+a_execute,
- a_write+a_execute,
- a_write+a_execute,
- a_read+a_execute,
- a_read+a_execute
- };
-
- #ifdef ARC
- /* On the Archimedes, we often want to replace files with names like x.y.z by
- x.z.y. This function checks to see whether a file has one or a range of standard
- extensions (z), and makes the change. The result is placed in a given buffer.
-
- The typedef gives us a suitable temporary buffer.
- */
-
- #define ARC_MAX_FILE_NAME 4096 /* A likely value */
- typedef char arc_buf[ARC_MAX_FILE_NAME];
-
- private struct arc_ext
- {
- char *ext;
- int len;
- } arc_extension[] =
- { /* Shortest must be first */
- "ps", 2,
- "gsf", 3,
- "", 0
- };
-
-
- /* Change and copy name. To and from must not overlap. */
- private void arc_cvt_name(char *to, char *from, int len)
- {
- struct arc_ext *ext;
- int elen;
-
- to[len] = 0;
-
- for (ext = arc_extension ; (elen = ext->len) != 0 ; ext++)
- {
- if (from[len-elen-1] == '.' && memcmp(ext->ext, from+len-elen, elen) == 0)
- {
- /* Look back for earlier '.' */
- int i;
- for (i = len-elen-2 ; i >= 0 ; i--)
- {
- if (from[i] == '.')
- {
- /* Copy up to and including "." */
- memcpy(to, from, i+1);
- break;
- }
- }
-
- /* Add "ext." */
- i += 1;
- memcpy(to+i, ext->ext, elen);
- to[i+elen] = '.';
-
- /* Copy chunk to go after "ext." */
- elen += 1;
- memcpy(to+i+elen, from+i, len-i-elen);
-
- return;
- }
- }
-
- /* No extension matches - simple copy */
- memcpy(to, from, len);
-
- }
- #endif
-
- /* Initialize the file table */
- private void
- zfile_init()
- { /* Create files for stdin, stdout, and stderr. */
- /****** stdin IS NOT IMPLEMENTED PROPERLY ******/
- sread_file(&std_files[0], stdin, stdin_buf, stdin_buf_size);
- std_files[0].can_close = 0;
- swrite_file(&std_files[1], stdout, stdout_buf, stdout_buf_size);
- std_files[1].can_close = 0;
- swrite_file(&std_files[2], stderr, stderr_buf, stderr_buf_size);
- std_files[2].can_close = 0;
- make_tav(&all_files, t_file, 0, pfile, (stream *)0);
- s_disable(&invalid_file_entry);
- }
-
- /* file */
- int
- zfile(register os_ptr op)
- { char *file_access;
- ref fname;
- int code;
- stream *s;
- fname = op[-1];
- check_type(fname, t_string);
- check_type(*op, t_string);
- if ( r_size(op) != 1 ) return e_invalidfileaccess;
- switch ( *op->value.bytes )
- {
- case 'r': file_access = "r"; break;
- case 'w': file_access = "w"; break;
- default: return e_invalidfileaccess;
- }
- code = open_std_file(op - 1, file_access, op - 1);
- switch ( code )
- {
- case 0: /* successful open */
- pop(1);
- default: /* unsuccessful open */
- return code;
- case e_undefinedfilename: /* not a %file */
- ;
- }
- code = file_open(fname.value.bytes, r_size(&fname),
- file_access, op - 1, &s);
- if ( code >= 0 ) pop(1);
- return code;
- }
-
- /* closefile */
- int
- zclosefile(register os_ptr op)
- { stream *s;
- int code;
- check_file(s, op);
- if ( s->can_close == 0 )
- return e_invalidaccess; /* can't close std file */
- if ( (code = file_close(op, s)) >= 0 )
- { /* If we just closed the file from which the interpreter */
- /* is reading, zap it on the exec stack. */
- ref *fp = zget_current_file();
- if ( fp != 0 && fptr(fp) == fptr(op) )
- /* A null would confuse the estack parser.... */
- make_tasv(fp, t_array, a_executable+a_execute, 0, refs, (ref *)0);
- pop(1);
- }
- return code;
- }
-
- /* ------ Level 2 extensions ------ */
-
- /* deletefile */
- int
- zdeletefile(register os_ptr op)
- { char *str;
- int stat;
- check_read_type(*op, t_string);
- str = ref_to_string(op, "deletefile");
- if ( str == 0 ) return e_VMerror;
- #ifdef ARC
- {
- arc_buf temp_name;
- arc_cvt_name(temp_name, str, strlen(str));
- stat = remove(temp_name);
- }
- #else
- stat = unlink(str);
- #endif
- alloc_free(str, r_size(op) + 1, 1, "deletefile");
- if ( stat != 0 ) return e_ioerror;
- pop(1);
- return 0;
- }
-
- /* filenameforall */
- private int file_continue(P1(os_ptr));
- int
- zfilenameforall(register os_ptr op)
- { file_enum *pfen;
- check_write_type(*op, t_string);
- check_proc(op[-1]);
- check_read_type(op[-2], t_string);
- /* Push a mark, the pattern, the scratch string, the enumerator, */
- /* and the procedure, and invoke the continuation. */
- check_estack(7);
- pfen = gp_enumerate_files_init((char *)op[-2].value.bytes, r_size(op - 2), alloc, alloc_free);
- if ( pfen == 0 ) return e_VMerror;
- mark_estack(es_for);
- *++esp = op[-2];
- *++esp = *op;
- ++esp;
- make_tasv(esp, t_string, a_read+a_execute+a_executable, 0,
- bytes, (byte *)pfen);
- *++esp = op[-1];
- pop(3); op -= 3;
- return file_continue(op);
- }
- /* Continuation operator for enumerating files */
- private int
- file_continue(register os_ptr op)
- { es_ptr pscratch = esp - 2;
- file_enum *pfen = (file_enum *)esp[-1].value.bytes;
- uint len = r_size(pscratch);
- uint code = gp_enumerate_files_next(pfen, (char *)pscratch->value.bytes, len);
- if ( code == ~(uint)0 ) /* all done */
- { gp_enumerate_files_close(pfen);
- esp -= 4; /* pop mark, scatch, pfen, proc */
- }
- else if ( code > len ) /* overran string */
- { gp_enumerate_files_close(pfen);
- return e_rangecheck;
- }
- else if ( !string_match(pscratch->value.bytes, code,
- pscratch[-1].value.bytes, r_size(&pscratch[-1]))
- )
- { /* Enumerator was too liberal, ignore this one. */
- push_op_estack(file_continue); /* come again */
- }
- else
- { push(1);
- ref_assign(op, pscratch);
- r_set_subrange_size(op, code);
- push_op_estack(file_continue); /* come again */
- *++esp = pscratch[2]; /* proc */
- }
- return o_check_estack;
- }
-
- /* renamefile */
- int
- zrenamefile(register os_ptr op)
- { char *str1 = 0, *str2 = 0;
- check_read_type(*op, t_string);
- check_read_type(op[-1], t_string);
- str1 = ref_to_string(op - 1, "renamefile(from)");
- #ifdef ARC
- if ( str1 != 0 && str2 != 0 )
- {
- arc_buf temp1, temp2;
- arc_cvt_name(temp1, str1, strlen(str1));
- arc_cvt_name(temp2, str2, strlen(str2));
- if ( rename(temp1, temp2) )
- { pop(2);
- }
- }
- #else
- str2 = ref_to_string(op, "renamefile(to)");
- if ( str1 != 0 && str2 != 0 && rename(str1, str2) == 0 )
- { pop(2);
- }
- #endif
- if ( str1 != 0 )
- alloc_free(str1, r_size(op - 1) + 1, 1, "renamefile(from)");
- if ( str2 != 0 )
- alloc_free(str2, r_size(op) + 1, 1, "renamefile(to)");
- return 0;
- }
-
- /* ------ Ghostscript extensions ------ */
-
- /* findlibfile */
- int
- zfindlibfile(register os_ptr op)
- { int code;
- check_type(*op, t_string);
- code = open_std_file(op, "r", op - 1);
- switch ( code )
- {
- case 0: /* successful open */
- push(1);
- make_bool(op, 1);
- default: /* unsuccessful open */
- return code;
- case e_undefinedfilename: /* not a %file */
- ;
- }
- code = lib_file_open(op->value.bytes, r_size(op), op);
- push(1);
- make_bool(op, code >= 0);
- return 0;
- }
-
- /* type1decryptfile */
- int
- ztype1decryptfile(register os_ptr op)
- { stream *s;
- ushort state;
- ref dec_file;
- int code;
- stream *es;
- check_type(op[-1], t_integer);
- state = op[-1].value.intval;
- if ( op[-1].value.intval != state )
- return e_rangecheck; /* state value was truncated */
- check_read_file(s, op);
- code = file_open((byte *)0, 0, "r", &dec_file, &es);
- if ( code < 0 ) return code;
- sread_decrypt(es, fptr(op), es->cbuf, es->bsize, state);
- op[-1] = dec_file;
- pop(1);
- return 0;
- }
-
- /* ------ Initialization procedure ------ */
-
- op_def zfile_op_defs[] = {
- {"1closefile", zclosefile},
- {"1deletefile", zdeletefile},
- {"2file", zfile},
- {"3filenameforall", zfilenameforall},
- {"1findlibfile", zfindlibfile},
- {"2renamefile", zrenamefile},
- {"2type1decryptfile", ztype1decryptfile},
- op_def_end(zfile_init)
- };
-
- /* ------ Non-operator routines ------ */
-
- /* Open a file, using the search paths if necessary. */
- /* The startup code calls this to open the initialization file ghost.ps, */
- /* and any other files specified on the command line. */
- int
- lib_file_open(byte *fname, uint len, ref *pfile)
- { int code;
- char **ppath;
- #define max_len 200
- char cname[max_len];
- stream *s;
- code = file_open(fname, len, "r", pfile, &s);
- if ( code >= 0 ) return code;
- if ( gp_file_name_is_absolute((char *)fname, len) )
- return e_undefinedfilename;
- /* Go through the list of search paths */
- for ( ppath = gs_lib_paths; *ppath != 0; ppath++ )
- { char *path = *ppath;
- for ( ; ; )
- { /* Find the end of the next path */
- char *npath = path;
- uint plen;
- char *cstr;
- uint clen;
- while ( *npath != 0 && *npath != gp_file_name_list_separator )
- npath++;
- plen = npath - path;
- cstr = gp_file_name_concat_string(path, plen,
- (char *)fname, len);
- /* Concatenate the prefix, combiner, and file name. */
- clen = plen + strlen(cstr) + len;
- if ( clen <= max_len ) /* otherwise punt */
- { memcpy(cname, path, plen);
- strcpy(cname + plen, cstr);
- memcpy(cname + clen - len, fname, len);
- code = file_open((byte *)cname, clen, "r",
- pfile, &s);
- if ( code >= 0 ) return code;
- }
- /****** NYI ******/
- if ( !*npath ) break;
- path = npath + 1;
- }
- }
- return code;
- }
-
- /* Open a file and create a file object. */
- /* Return 0 if successful, error code if not. */
- /* If fname==0, set up the file entry, stream, and buffer, */
- /* but don't open an OS file or initialize the stream. */
- /* The filter routines also use this. */
- int
- file_open(byte *fname, uint len, char *file_access, ref *pfile, stream **ps)
- { byte *buffer;
- stream *s;
- int code;
- if ( len >= buffer_size )
- return e_limitcheck; /* we copy the file name into the buffer */
- /* Allocate the stream first, since it persists */
- /* even after the file has been closed. */
- s = (stream *)alloc(1, sizeof(stream), "file_open(stream)");
- if ( s == 0 ) return e_VMerror;
- /* Allocate the buffer. */
- buffer = (byte *)alloc(buffer_size, 1, "file_open(buffer)");
- if ( buffer == 0 )
- { alloc_free((char *)s, 1, sizeof(stream), "file_open(stream)");
- return e_VMerror;
- }
- if ( fname != 0 )
- { /* Copy the name (so we can terminate it with a zero byte.) */
- char *file_name = (char *)buffer;
- FILE *file;
- memcpy(file_name, fname, len);
- file_name[len] = 0; /* terminate string */
- /* Open the file. */
- #ifdef ARC
- {
- arc_buf temp_name;
- arc_cvt_name(temp_name, file_name, len);
- file = fopen(temp_name, file_access);
- }
- #else
- file = fopen(file_name, file_access);
- #endif
- code = e_undefinedfilename;
- if ( file == 0 )
- { alloc_free((char *)buffer, buffer_size, 1, "file_open(buffer)");
- alloc_free((char *)s, 1, sizeof(stream), "file_open(stream)");
- return code;
- }
- /* Set up the stream. */
- if ( *file_access == 'r' ) /* reading */
- sread_file(s, file, buffer, buffer_size);
- else
- swrite_file(s, file, buffer, buffer_size);
- }
- else /* save the buffer and size */
- { s->cbuf = buffer;
- s->bsize = buffer_size;
- }
- s->can_close = 1;
- if ( file_list != 0 )
- file_list->prev = s;
- s->next = file_list;
- s->prev = 0;
- file_list = s;
- make_file(pfile,
- (*file_access == 'r' ? a_read+a_execute : a_write+a_execute),
- s);
- *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)
- { byte *buffer = s->cbuf;
- switch ( s->can_close )
- {
- case 0: /* can't close std files, ignore */
- break;
- case -1: /* ignore on statement/lineedit */
- sclose(s);
- break;
- default: /* ordinary or filter file */
- 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 *)buffer, buffer_size, 1, "file_close(buffer)");
- alloc_free((char *)s, 1, sizeof(stream), "file_close(stream)");
- /* Unlink the file from the list of all files. */
- if ( s->prev != 0 ) s->prev->next = s->next;
- else file_list = s->next;
- if ( s->next != 0 ) s->next->prev = s->prev;
- }
- s_disable(s);
- return 0;
- }
-
- /* ------ Internal routines ------ */
-
- /* If a file name refers to one of the standard %files, */
- /* 'open' the file and return 0 or an error code, otherwise */
- /* return e_undefinedfilename. */
- private int
- open_std_file(os_ptr pfname, char *file_access, os_ptr pfile)
- { int i;
- for ( i = 0; i < num_std_files; i++ )
- if ( !bytes_compare(pfname->value.bytes, r_size(pfname),
- (byte *)std_file_names[i],
- strlen(std_file_names[i]))
- )
- { /* This is a standard file */
- int attrs = (*file_access == 'r' ? a_read+a_execute : a_write+a_execute);
- stream *s = &std_files[i];
- if ( attrs != std_file_attrs[i] )
- return e_invalidaccess;
- make_file(pfile, attrs, s);
- /* If this is %lineedit or %statementedit, */
- /* read a line now. */
- switch ( i )
- {
- case 3: case 4:
- { uint count;
- int code = zreadline_stdin(lineedit_buf,
- lineedit_buf_size, &count);
- if ( code < 0 ) return code;
- sread_string(s, lineedit_buf, count);
- s->can_close = -1;
- return 0;
- }
- }
- return 0;
- }
- return e_undefinedfilename;
- }
-
- /* Close inaccessible files just before a restore. */
- void
- file_restore(alloc_save *save)
- { while ( file_list != 0 &&
- alloc_is_since_save((char *)file_list, save)
- )
- { stream *s = file_list;
- if ( s->can_close > 0 ) /* ignore std & buffered files */
- { sclose(s);
- }
- file_list = s->next;
- if ( s->next != 0 ) s->next->prev = s->prev;
- s_disable(s);
- }
- }
-