summaryrefslogtreecommitdiff
path: root/lisp/io.c
diff options
context:
space:
mode:
Diffstat (limited to 'lisp/io.c')
-rw-r--r--lisp/io.c709
1 files changed, 709 insertions, 0 deletions
diff --git a/lisp/io.c b/lisp/io.c
new file mode 100644
index 0000000..ea59575
--- /dev/null
+++ b/lisp/io.c
@@ -0,0 +1,709 @@
+/*
+ * Copyright (c) 2002 by The XFree86 Project, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE XFREE86 PROJECT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Except as contained in this notice, the name of the XFree86 Project shall
+ * not be used in advertising or otherwise to promote the sale, use or other
+ * dealings in this Software without prior written authorization from the
+ * XFree86 Project.
+ *
+ * Author: Paulo César Pereira de Andrade
+ */
+
+/* $XFree86: xc/programs/xedit/lisp/io.c,v 1.16 2002/12/16 03:59:27 paulo Exp $ */
+
+#include "io.h"
+#include <errno.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+/* Match the FILE_XXX flags */
+#define READ_BIT 0x01
+#define WRITE_BIT 0x02
+#define APPEND_BIT 0x04
+#define BUFFERED_BIT 0x08
+#define UNBUFFERED_BIT 0x10
+#define BINARY_BIT 0x20
+
+/*
+ * Prototypes
+ */
+static int calculate_line(void*, int);
+static int calculate_column(void*, int, int);
+
+/*
+ * Initialization
+ */
+extern int pagesize;
+
+/*
+ * Implementation
+ */
+int
+LispGet(void)
+{
+ int ch = EOF;
+ LispUngetInfo *unget = lisp__data.unget[lisp__data.iunget];
+
+ if (unget->offset)
+ ch = ((unsigned char*)unget->buffer)[--unget->offset];
+ else if (SINPUT->data.stream.readable) {
+ LispFile *file = NULL;
+
+ switch (SINPUT->data.stream.type) {
+ case LispStreamStandard:
+ case LispStreamFile:
+ file = FSTREAMP(SINPUT);
+ break;
+ case LispStreamPipe:
+ file = IPSTREAMP(SINPUT);
+ break;
+ case LispStreamString:
+ ch = LispSgetc(SSTREAMP(SINPUT));
+ break;
+ default:
+ ch = EOF;
+ break;
+ }
+ if (file != NULL) {
+ if (file->nonblock) {
+ if (fcntl(file->descriptor, F_SETFL, 0) < 0)
+ LispDestroy("fcntl: %s", strerror(errno));
+ file->nonblock = 0;
+ }
+ ch = LispFgetc(file);
+ }
+ }
+ else
+ LispDestroy("cannot read from *STANDARD-INPUT*");
+
+ if (ch == EOF)
+ lisp__data.eof = 1;
+
+ return (ch);
+}
+
+int
+LispUnget(int ch)
+{
+ LispUngetInfo *unget = lisp__data.unget[lisp__data.iunget];
+
+ if (unget->offset == sizeof(unget->buffer)) {
+ LispWarning("character %c lost at LispUnget()", unget->buffer[0]);
+ memmove(unget->buffer, unget->buffer + 1, unget->offset - 1);
+ unget->buffer[unget->offset - 1] = ch;
+ }
+ else
+ unget->buffer[unget->offset++] = ch;
+
+ return (ch);
+}
+
+void
+LispPushInput(LispObj *stream)
+{
+ if (!STREAMP(stream) || !stream->data.stream.readable)
+ LispDestroy("bad stream at PUSH-INPUT");
+ lisp__data.input_list = CONS(stream, lisp__data.input_list);
+ SINPUT = stream;
+ if (lisp__data.iunget + 1 == lisp__data.nunget) {
+ LispUngetInfo **info =
+ realloc(lisp__data.unget,
+ sizeof(LispUngetInfo) * (lisp__data.nunget + 1));
+
+ if (!info ||
+ (info[lisp__data.nunget] =
+ calloc(1, sizeof(LispUngetInfo))) == NULL)
+ LispDestroy("out of memory");
+ lisp__data.unget = info;
+ ++lisp__data.nunget;
+ }
+ ++lisp__data.iunget;
+ memset(lisp__data.unget[lisp__data.iunget], '\0', sizeof(LispUngetInfo));
+ lisp__data.eof = 0;
+}
+
+void
+LispPopInput(LispObj *stream)
+{
+ if (!CONSP(lisp__data.input_list) || stream != CAR(lisp__data.input_list))
+ LispDestroy("bad stream at POP-INPUT");
+ lisp__data.input_list = CDR(lisp__data.input_list);
+ SINPUT = CONSP(lisp__data.input_list) ?
+ CAR(lisp__data.input_list) : lisp__data.input_list;
+ --lisp__data.iunget;
+ lisp__data.eof = 0;
+}
+
+/*
+ * Low level functions
+ */
+static int
+calculate_line(void *data, int size)
+{
+ int line = 0;
+ char *str, *ptr;
+
+ for (str = (char*)data, ptr = (char*)data + size; str < ptr; str++)
+ if (*ptr == '\n')
+ ++line;
+
+ return (line);
+}
+
+static int
+calculate_column(void *data, int size, int column)
+{
+ char *str, *ptr;
+
+ /* search for newline in data */
+ for (str = (char*)data, ptr = (char*)data + size - 1; ptr >= str; ptr--)
+ if (*ptr == '\n')
+ break;
+
+ /* newline found */
+ if (ptr >= str)
+ return (size - (ptr - str) - 1);
+
+ /* newline not found */
+ return (column + size);
+}
+
+LispFile *
+LispFdopen(int descriptor, int mode)
+{
+ LispFile *file = calloc(1, sizeof(LispFile));
+
+ if (file) {
+ struct stat st;
+
+ file->descriptor = descriptor;
+ file->readable = (mode & READ_BIT) != 0;
+ file->writable = (mode & WRITE_BIT) != 0;
+
+ if (fstat(descriptor, &st) == 0)
+ file->regular = S_ISREG(st.st_mode);
+ else
+ file->regular = 0;
+
+ file->buffered = (mode & BUFFERED_BIT) != 0;
+ if ((mode & UNBUFFERED_BIT) == 0)
+ file->buffered = file->regular;
+
+ if (file->buffered) {
+ file->buffer = malloc(pagesize);
+ if (file->buffer == NULL)
+ file->buffered = 0;
+ }
+ file->line = 1;
+ file->binary = (mode & BINARY_BIT) != 0;
+ file->io_write = write;
+ }
+
+ return (file);
+}
+
+LispFile *
+LispFopen(char *path, int mode)
+{
+ LispFile *file;
+ int descriptor;
+ int flags = O_NOCTTY;
+
+ /* check read/write attributes */
+ if ((mode & (READ_BIT | WRITE_BIT)) == (READ_BIT | WRITE_BIT))
+ flags |= O_RDWR;
+ else if (mode & READ_BIT)
+ flags |= O_RDONLY;
+ else if (mode & WRITE_BIT)
+ flags |= O_WRONLY;
+
+ /* create if does not exist */
+ if (mode & WRITE_BIT) {
+ flags |= O_CREAT;
+
+ /* append if exists? */
+ if (mode & APPEND_BIT)
+ flags |= O_APPEND;
+ else
+ flags |= O_TRUNC;
+ }
+
+ /* open file */
+ descriptor = open(path, flags, 0666);
+ if (descriptor < 0)
+ return (NULL);
+
+ /* initialize LispFile structure */
+ file = LispFdopen(descriptor, mode);
+ if (file == NULL)
+ close(descriptor);
+
+ return (file);
+}
+
+void
+LispFclose(LispFile *file)
+{
+ /* flush any pending output */
+ LispFflush(file);
+ /* cleanup */
+ close(file->descriptor);
+ if (file->buffer)
+ free(file->buffer);
+ free(file);
+}
+
+io_write_fn
+LispSetFileWrite(LispFile *file, io_write_fn new_write)
+{
+ io_write_fn old_write = file->io_write;
+
+ file->io_write = new_write;
+
+ return (old_write);
+}
+
+int
+LispFflush(LispFile *file)
+{
+ if (file->writable && file->length) {
+ int length = (*file->io_write)(file->descriptor,
+ file->buffer, file->length);
+
+ if (length > 0) {
+ if (file->length > length)
+ memmove(file->buffer, file->buffer + length,
+ file->length - length);
+ file->length -= length;
+ }
+ return (length);
+ }
+
+ return (0);
+}
+
+int
+LispFungetc(LispFile *file, int ch)
+{
+ if (file->readable) {
+ file->available = 1;
+ file->unget = ch;
+ /* this should never happen */
+ if (ch == '\n' && !file->binary)
+ --file->line;
+ }
+
+ return (ch);
+}
+
+int
+LispFgetc(LispFile *file)
+{
+ int ch;
+
+ if (file->readable) {
+ unsigned char c;
+
+ if (file->available) {
+ ch = file->unget;
+ file->available = 0;
+ }
+ else if (file->buffered) {
+ if (file->writable) {
+ LispFflush(file);
+ if (read(file->descriptor, &c, 1) == 1)
+ ch = c;
+ else
+ ch = EOF;
+ }
+ else {
+ if (file->offset < file->length)
+ ch = ((unsigned char*)file->buffer)[file->offset++];
+ else {
+ int length = read(file->descriptor,
+ file->buffer, pagesize);
+
+ if (length >= 0)
+ file->length = length;
+ else
+ file->length = 0;
+ file->offset = 0;
+ if (file->length)
+ ch = ((unsigned char*)file->buffer)[file->offset++];
+ else
+ ch = EOF;
+ }
+ }
+ }
+ else if (read(file->descriptor, &c, 1) == 1)
+ ch = c;
+ else
+ ch = EOF;
+ }
+ else
+ ch = EOF;
+
+ if (ch == '\n' && !file->binary)
+ ++file->line;
+
+ return (ch);
+}
+
+int
+LispFputc(LispFile *file, int ch)
+{
+ if (file->writable) {
+ unsigned char c = ch;
+
+ if (file->buffered) {
+ if (file->length + 1 >= pagesize)
+ LispFflush(file);
+ file->buffer[file->length++] = c;
+ }
+ else if ((*file->io_write)(file->descriptor, &c, 1) != 1)
+ ch = EOF;
+
+ if (!file->binary) {
+ /* update column number */
+ if (ch == '\n')
+ file->column = 0;
+ else
+ ++file->column;
+ }
+ }
+
+ return (ch);
+}
+
+int
+LispSgetc(LispString *string)
+{
+ int ch;
+
+ if (string->input >= string->length)
+ return (EOF); /* EOF reading from string */
+
+ ch = ((unsigned char*)string->string)[string->input++];
+ if (ch == '\n' && !string->binary)
+ ++string->line;
+
+ return (ch);
+}
+
+int
+LispSputc(LispString *string, int ch)
+{
+ if (string->output + 1 >= string->space) {
+ if (string->fixed)
+ return (EOF);
+ else {
+ char *tmp = realloc(string->string, string->space + pagesize);
+
+ if (tmp == NULL)
+ return (EOF);
+ string->string = tmp;
+ string->space += pagesize;
+ }
+ }
+
+ string->string[string->output++] = ch;
+ if (string->length < string->output)
+ string->length = string->output;
+
+ /* update column number */
+ if (!string->binary) {
+ if (ch == '\n')
+ string->column = 0;
+ else
+ ++string->column;
+ }
+
+ return (ch);
+}
+
+char *
+LispFgets(LispFile *file, char *string, int size)
+{
+ int ch, offset = 0;
+
+ if (size < 1)
+ return (string);
+
+ for (;;) {
+ if (offset + 1 >= size)
+ break;
+ if ((ch = LispFgetc(file)) == EOF)
+ break;
+ string[offset++] = ch;
+ /* line number is calculated in LispFgetc */
+ if (ch == '\n')
+ break;
+ }
+ string[offset] = '\0';
+
+ return (offset ? string : NULL);
+}
+
+int
+LispFputs(LispFile *file, char *buffer)
+{
+ return (LispFwrite(file, buffer, strlen(buffer)));
+}
+
+int
+LispSputs(LispString *string, char *buffer)
+{
+ return (LispSwrite(string, buffer, strlen(buffer)));
+}
+
+int
+LispFread(LispFile *file, void *data, int size)
+{
+ int bytes, length;
+ char *buffer;
+
+ if (!file->readable)
+ return (EOF);
+
+ if (size <= 0)
+ return (size);
+
+ length = 0;
+ buffer = (char*)data;
+
+ /* check if there is an unget character */
+ if (file->available) {
+ *buffer++ = file->unget;
+ file->available = 0;
+ if (--size == 0) {
+ if (file->unget == '\n' && !file->binary)
+ ++file->line;
+
+ return (1);
+ }
+
+ length = 1;
+ }
+
+ if (file->buffered) {
+ void *base_data = (char*)data - length;
+
+ if (file->writable) {
+ LispFflush(file);
+ bytes = read(file->descriptor, buffer, size);
+ if (bytes < 0)
+ bytes = 0;
+ if (!file->binary)
+ file->line += calculate_line(base_data, length + bytes);
+
+ return (length + bytes);
+ }
+
+ /* read anything that is in the buffer */
+ if (file->offset < file->length) {
+ bytes = file->length - file->offset;
+ if (bytes > size)
+ bytes = size;
+ memcpy(buffer, file->buffer + file->offset, bytes);
+ buffer += bytes;
+ file->offset += bytes;
+ size -= bytes;
+ }
+
+ /* if there is still something to read */
+ if (size) {
+ bytes = read(file->descriptor, buffer, size);
+ if (bytes < 0)
+ bytes = 0;
+
+ length += bytes;
+ }
+
+ if (!file->binary)
+ file->line += calculate_line(base_data, length);
+
+ return (length);
+ }
+
+ bytes = read(file->descriptor, buffer, size);
+ if (bytes < 0)
+ bytes = 0;
+ if (!file->binary)
+ file->line += calculate_line(buffer - length, length + bytes);
+
+ return (length + bytes);
+}
+
+int
+LispFwrite(LispFile *file, void *data, int size)
+{
+ if (!file->writable || size < 0)
+ return (EOF);
+
+ if (!file->binary)
+ file->column = calculate_column(data, size, file->column);
+
+ if (file->buffered) {
+ int length, bytes;
+ char *buffer = (char*)data;
+
+ length = 0;
+ if (size + file->length > pagesize) {
+ /* fill remaining space in buffer and flush */
+ bytes = pagesize - file->length;
+ memcpy(file->buffer + file->length, buffer, bytes);
+ file->length += bytes;
+ LispFflush(file);
+
+ /* check if all data was written */
+ if (file->length)
+ return (pagesize - file->length);
+
+ length = bytes;
+ buffer += bytes;
+ size -= bytes;
+ }
+
+ while (size > pagesize) {
+ /* write multiple of pagesize */
+ bytes = (*file->io_write)(file->descriptor, buffer,
+ size - (size % pagesize));
+ if (bytes <= 0)
+ return (length);
+
+ length += bytes;
+ buffer += bytes;
+ size -= bytes;
+ }
+
+ if (size) {
+ /* keep remaining data in buffer */
+ switch (size) {
+ case 8:
+ file->buffer[file->length++] = *buffer++;
+ case 7:
+ file->buffer[file->length++] = *buffer++;
+ case 6:
+ file->buffer[file->length++] = *buffer++;
+ case 5:
+ file->buffer[file->length++] = *buffer++;
+ case 4:
+ file->buffer[file->length++] = *buffer++;
+ case 3:
+ file->buffer[file->length++] = *buffer++;
+ case 2:
+ file->buffer[file->length++] = *buffer++;
+ case 1:
+ file->buffer[file->length++] = *buffer++;
+ break;
+ default:
+ memcpy(file->buffer + file->length, buffer, size);
+ file->length += size;
+ break;
+ }
+ length += size;
+ }
+
+ return (length);
+ }
+
+ return ((*file->io_write)(file->descriptor, data, size));
+}
+
+int
+LispSwrite(LispString *string, void *data, int size)
+{
+ if (size < 0)
+ return (EOF);
+
+ if (string->output + size >= string->space) {
+ if (string->fixed) {
+ /* leave space for a ending nul character */
+ size = string->space - string->output - 1;
+
+ if (size <= 0)
+ return (-1);
+ }
+ else {
+ char *tmp = realloc(string->string, string->space +
+ (size / pagesize) * pagesize + pagesize);
+
+ if (tmp == NULL)
+ return (-1);
+
+ string->string = tmp;
+ string->space += pagesize;
+ }
+ }
+ memcpy(string->string + string->output, data, size);
+ string->output += size;
+ if (string->length < string->output)
+ string->length = string->output;
+
+ if (!string->binary)
+ string->column = calculate_column(data, size, string->column);
+
+ return (size);
+}
+
+char *
+LispGetSstring(LispString *string, int *length)
+{
+ if (string->string == NULL || string->length <= 0) {
+ *length = 0;
+
+ return ("");
+ }
+ *length = string->length;
+ if (string->string[string->length -1] != '\0') {
+ if (string->length < string->space)
+ string->string[string->length] = '\0';
+ else if (string->fixed && string->space)
+ string->string[string->space - 1] = '\0';
+ else {
+ char *tmp = realloc(string->string, string->space + pagesize);
+
+ if (tmp == NULL)
+ string->string[string->space - 1] = '\0';
+ else {
+ string->string = tmp;
+ string->space += pagesize;
+ string->string[string->length] = '\0';
+ }
+ }
+ }
+
+ return (string->string);
+}
+
+int
+LispRename(char *from, char *to)
+{
+ return (rename(from, to));
+}
+
+int
+LispUnlink(char *name)
+{
+ return (unlink(name));
+}