static int stderr_open(gx_io_device * iodev, const char *access, stream ** ps, gs_memory_t * mem) { i_ctx_t *i_ctx_p = (i_ctx_t *)iodev->state; /* see above */ stream *s; if (!streq1(access, 'w')) return_error(e_invalidfileaccess); if (file_is_invalid(s, &ref_stderr)) { gs_memory_t *mem = imemory_system; byte *buf; s = file_alloc_stream(mem, "stderr_open(stream)"); buf = gs_alloc_bytes(mem, STDERR_BUF_SIZE, "stderr_open(buffer)"); if (s == 0 || buf == 0) return_error(e_VMerror); swrite_file(s, gs_stderr, buf, STDERR_BUF_SIZE); s->save_close = s->procs.flush; s->procs.close = file_close_file; make_file(&ref_stderr, a_write | avm_system, s->write_id, s); *ps = s; return 1; } *ps = s; return 0; }
static int stdin_open(gx_io_device * iodev, const char *access, stream ** ps, gs_memory_t * mem) { i_ctx_t *i_ctx_p = (i_ctx_t *)iodev->state; /* see above */ stream *s; if (!streq1(access, 'r')) return_error(e_invalidfileaccess); if (file_is_invalid(s, &ref_stdin)) { /****** stdin SHOULD NOT LINE-BUFFER ******/ gs_memory_t *mem = imemory_system; byte *buf; s = file_alloc_stream(mem, "stdin_open(stream)"); /* We want stdin to read only one character at a time, */ /* but it must have a substantial buffer, in case it is used */ /* by a stream that requires more than one input byte */ /* to make progress. */ buf = gs_alloc_bytes(mem, STDIN_BUF_SIZE, "stdin_open(buffer)"); if (s == 0 || buf == 0) return_error(e_VMerror); sread_file(s, gs_stdin, buf, STDIN_BUF_SIZE); s->procs.process = s_stdin_read_process; s->save_close = s_std_null; s->procs.close = file_close_file; make_file(&ref_stdin, a_readonly | avm_system, s->read_id, s); *ps = s; return 1; } *ps = s; return 0; }
/* If fname==0, set up stream, and buffer. */ int file_prepare_stream(const char *fname, uint len, const char *file_access, uint buffer_size, stream ** ps, char fmode[4], gs_memory_t *mem) { byte *buffer; register stream *s; /* Open the file, always in binary mode. */ strcpy(fmode, file_access); strcat(fmode, gp_fmode_binary_suffix); if (buffer_size == 0) buffer_size = file_default_buffer_size; if (len >= buffer_size) /* we copy the file name into the buffer */ return_error(gs_error_limitcheck); /* Allocate the stream first, since it persists */ /* even after the file has been closed. */ s = file_alloc_stream(mem, "file_prepare_stream"); if (s == 0) return_error(gs_error_VMerror); /* Allocate the buffer. */ buffer = gs_alloc_bytes(mem, buffer_size, "file_prepare_stream(buffer)"); if (buffer == 0) return_error(gs_error_VMerror); if (fname != 0) { memcpy(buffer, fname, len); buffer[len] = 0; /* terminate string */ } else buffer[0] = 0; /* safety */ s->cbuf = buffer; s->bsize = s->cbsize = buffer_size; *ps = s; return 0; }
/* The string must be allocated in non-garbage-collectable (foreign) space. */ int file_read_string(const byte *str, uint len, ref *pfile, gs_ref_memory_t *imem) { stream *s = file_alloc_stream((gs_memory_t *)imem, "file_read_string"); if (s == 0) return_error(e_VMerror); sread_string(s, str, len); s->foreign = 1; s->write_id = 0; make_file(pfile, a_readonly | imemory_space(imem), s->read_id, s); s->save_close = s->procs.close; s->procs.close = file_close_disable; return 0; }
/* Write a buffer to stdout, potentially writing to callback */ static int s_stdout_write_process(stream_state * st, stream_cursor_read * ignore_pr, stream_cursor_write * pw, bool last) { uint count = pr->limit - pr->ptr; int written; if (count == 0) return 0; written = outwrite(st->memory, pr->ptr + 1, count); if (written < count) { return ERRC; pr->ptr += written; return 0; } static int stdout_open(gx_io_device * iodev, const char *access, stream ** ps, gs_memory_t * mem) { i_ctx_t *i_ctx_p = (i_ctx_t *)iodev->state; /* see above */ stream *s; if (!streq1(access, 'w')) return_error(e_invalidfileaccess); if (file_is_invalid(s, &ref_stdout)) { gs_memory_t *mem = imemory_system; byte *buf; s = file_alloc_stream(mem, "stdout_open(stream)"); buf = gs_alloc_bytes(mem, STDOUT_BUF_SIZE, "stdout_open(buffer)"); if (s == 0 || buf == 0) return_error(e_VMerror); swrite_file(s, gs_stdout, buf, STDOUT_BUF_SIZE); s->save_close = s->procs.flush; s->procs.close = file_close_file; s->procs.process = s_stdout_write_process; make_file(&ref_stdout, a_write | avm_system, s->write_id, s); *ps = s; return 1; } *ps = s; return 0; }
/* Make a reusable string stream. */ int make_rss(i_ctx_t *i_ctx_p, os_ptr op, const byte * data, uint size, uint string_space, long offset, long length, bool is_bytestring) { uint save_space = icurrent_space; stream *s; long left = min(length, size - offset); ialloc_set_space(idmemory, string_space); s = file_alloc_stream(imemory, "make_rss"); ialloc_set_space(idmemory, save_space); if (s == 0) return_error(e_VMerror); sread_string_reusable(s, data + offset, max(left, 0)); if (is_bytestring) s->cbuf_string.data = 0; /* byte array, not string */ make_stream_file(op, s, "r"); return 0; }
/* <prefix|null> <access_string> .tempfile <name_string> <file> */ static int ztempfile(i_ctx_t *i_ctx_p) { os_ptr op = osp; const char *pstr; char fmode[4]; int code = parse_file_access_string(op, fmode); char prefix[gp_file_name_sizeof]; char fname[gp_file_name_sizeof]; uint fnlen; FILE *sfile; stream *s; byte *buf; if (code < 0) return code; strcat(fmode, gp_fmode_binary_suffix); if (r_has_type(op - 1, t_null)) pstr = gp_scratch_file_name_prefix; else { uint psize; check_read_type(op[-1], t_string); psize = r_size(op - 1); if (psize >= gp_file_name_sizeof) return_error(e_rangecheck); memcpy(prefix, op[-1].value.const_bytes, psize); prefix[psize] = 0; pstr = prefix; } if (gp_file_name_is_absolute(pstr, strlen(pstr))) { if (check_file_permissions(i_ctx_p, pstr, strlen(pstr), "PermitFileWriting") < 0) { return_error(e_invalidfileaccess); } } else if (!prefix_is_simple(pstr)) { return_error(e_invalidfileaccess); } s = file_alloc_stream(imemory, "ztempfile(stream)"); if (s == 0) return_error(e_VMerror); buf = gs_alloc_bytes(imemory, file_default_buffer_size, "ztempfile(buffer)"); if (buf == 0) return_error(e_VMerror); sfile = gp_open_scratch_file(pstr, fname, fmode); if (sfile == 0) { gs_free_object(imemory, buf, "ztempfile(buffer)"); return_error(e_invalidfileaccess); } fnlen = strlen(fname); file_init_stream(s, sfile, fmode, buf, file_default_buffer_size); code = ssetfilename(s, (const unsigned char*) fname, fnlen); if (code < 0) { sclose(s); iodev_default->procs.delete_file(iodev_default, fname); return_error(e_VMerror); } make_const_string(op - 1, a_readonly | icurrent_space, fnlen, s->file_name.data); make_stream_file(op, s, fmode); return code; }
/* This opens %statementedit% or %lineedit% and is also the * continuation proc for callouts. * Input: * string is the statement/line buffer, * int is the write index into string * bool is true if %statementedit% * file is stdin * Output: * file is a string based stream * We store the line being read in a PostScript string. * This limits the size to max_string_size (64k). * This could be increased by storing the input line in something * other than a PostScript string. */ int zfilelineedit(i_ctx_t *i_ctx_p) { uint count = 0; bool in_eol = false; int code; os_ptr op = osp; bool statement; stream *s; stream *ins; gs_string str; uint initial_buf_size; const char *filename; /* * buf exists only for stylistic parallelism: all occurrences of * buf-> could just as well be str. . */ gs_string *const buf = &str; check_type(*op, t_string); /* line assembled so far */ buf->data = op->value.bytes; buf->size = op->tas.rsize; check_type(*(op-1), t_integer); /* index */ count = (op-1)->value.intval; check_type(*(op-2), t_boolean); /* statementedit/lineedit */ statement = (op-2)->value.boolval; check_read_file(ins, op - 3); /* %stdin */ /* extend string */ initial_buf_size = statement ? STATEMENTEDIT_BUF_SIZE : LINEEDIT_BUF_SIZE; if (initial_buf_size > max_string_size) return_error(e_limitcheck); if (!buf->data || (buf->size < initial_buf_size)) { count = 0; buf->data = gs_alloc_string(imemory_system, initial_buf_size, "zfilelineedit(buffer)"); if (buf->data == 0) return_error(e_VMerror); op->value.bytes = buf->data; op->tas.rsize = buf->size = initial_buf_size; } rd: code = zreadline_from(ins, buf, imemory_system, &count, &in_eol); if (buf->size > max_string_size) { /* zreadline_from reallocated the buffer larger than * is valid for a PostScript string. * Return an error, but first realloc the buffer * back to a legal size. */ byte *nbuf = gs_resize_string(imemory_system, buf->data, buf->size, max_string_size, "zfilelineedit(shrink buffer)"); if (nbuf == 0) return_error(e_VMerror); op->value.bytes = buf->data = nbuf; op->tas.rsize = buf->size = max_string_size; return_error(e_limitcheck); } op->value.bytes = buf->data; /* zreadline_from sometimes resizes the buffer. */ op->tas.rsize = buf->size; switch (code) { case EOFC: code = gs_note_error(e_undefinedfilename); /* falls through */ case 0: break; default: code = gs_note_error(e_ioerror); break; case CALLC: { ref rfile; (op-1)->value.intval = count; /* callout is for stdin */ make_file(&rfile, a_readonly | avm_system, ins->read_id, ins); code = s_handle_read_exception(i_ctx_p, code, &rfile, NULL, 0, zfilelineedit); } break; case 1: /* filled buffer */ { uint nsize = buf->size; byte *nbuf; if (nsize >= max_string_size) { code = gs_note_error(e_limitcheck); break; } else if (nsize >= max_string_size / 2) nsize= max_string_size; else nsize = buf->size * 2; nbuf = gs_resize_string(imemory_system, buf->data, buf->size, nsize, "zfilelineedit(grow buffer)"); if (nbuf == 0) { code = gs_note_error(e_VMerror); break; } op->value.bytes = buf->data = nbuf; op->tas.rsize = buf->size = nsize; goto rd; } } if (code != 0) return code; if (statement) { /* If we don't have a complete token, keep going. */ stream st; stream *ts = &st; scanner_state state; ref ignore_value; uint depth = ref_stack_count(&o_stack); int code; /* Add a terminating EOL. */ if (count + 1 > buf->size) { uint nsize; byte *nbuf; nsize = buf->size + 1; if (nsize > max_string_size) { return_error(gs_note_error(e_limitcheck)); } else { nbuf = gs_resize_string(imemory_system, buf->data, buf->size, nsize, "zfilelineedit(grow buffer)"); if (nbuf == 0) { code = gs_note_error(e_VMerror); return_error(code); } op->value.bytes = buf->data = nbuf; op->tas.rsize = buf->size = nsize; } } buf->data[count++] = char_EOL; s_init(ts, NULL); sread_string(ts, buf->data, count); sc: scanner_init_stream_options(&state, ts, SCAN_CHECK_ONLY); code = scan_token(i_ctx_p, &ignore_value, &state); ref_stack_pop_to(&o_stack, depth); if (code < 0) code = scan_EOF; /* stop on scanner error */ switch (code) { case 0: /* read a token */ case scan_BOS: goto sc; /* keep going until we run out of data */ case scan_Refill: goto rd; case scan_EOF: break; default: /* error */ return code; } } buf->data = gs_resize_string(imemory_system, buf->data, buf->size, count, "zfilelineedit(resize buffer)"); if (buf->data == 0) return_error(e_VMerror); op->value.bytes = buf->data; op->tas.rsize = buf->size; s = file_alloc_stream(imemory_system, "zfilelineedit(stream)"); if (s == 0) return_error(e_VMerror); sread_string(s, buf->data, count); s->save_close = s->procs.close; s->procs.close = file_close_disable; filename = statement ? gs_iodev_statementedit.dname : gs_iodev_lineedit.dname; code = ssetfilename(s, (const byte *)filename, strlen(filename)+1); if (code < 0) { sclose(s); return_error(e_VMerror); } pop(3); make_stream_file(osp, s, "r"); return code; }