2 * Copyright (c) 2002 by The XFree86 Project, Inc.
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE XFREE86 PROJECT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
18 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
19 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 * Except as contained in this notice, the name of the XFree86 Project shall
23 * not be used in advertising or otherwise to promote the sale, use or other
24 * dealings in this Software without prior written authorization from the
27 * Author: Paulo César Pereira de Andrade
30 /* $XFree86: xc/programs/xedit/lisp/io.c,v 1.16tsi Exp $ */
36 #include <sys/types.h>
39 /* Match the FILE_XXX flags */
41 #define WRITE_BIT 0x02
42 #define APPEND_BIT 0x04
43 #define BUFFERED_BIT 0x08
44 #define UNBUFFERED_BIT 0x10
45 #define BINARY_BIT 0x20
50 static int calculate_line(void*, int);
51 static int calculate_column(void*, int, int);
65 LispUngetInfo *unget = lisp__data.unget[lisp__data.iunget];
68 ch = ((unsigned char*)unget->buffer)[--unget->offset];
69 else if (SINPUT->data.stream.readable) {
70 LispFile *file = NULL;
72 switch (SINPUT->data.stream.type) {
73 case LispStreamStandard:
75 file = FSTREAMP(SINPUT);
78 file = IPSTREAMP(SINPUT);
80 case LispStreamString:
81 ch = LispSgetc(SSTREAMP(SINPUT));
89 if (fcntl(file->descriptor, F_SETFL, 0) < 0)
90 LispDestroy("fcntl: %s", strerror(errno));
97 LispDestroy("cannot read from *STANDARD-INPUT*");
108 LispUngetInfo *unget = lisp__data.unget[lisp__data.iunget];
110 if (unget->offset == sizeof(unget->buffer)) {
111 LispWarning("character %c lost at LispUnget()", unget->buffer[0]);
112 memmove(unget->buffer, unget->buffer + 1, unget->offset - 1);
113 unget->buffer[unget->offset - 1] = ch;
116 unget->buffer[unget->offset++] = ch;
122 LispPushInput(LispObj *stream)
124 if (!STREAMP(stream) || !stream->data.stream.readable)
125 LispDestroy("bad stream at PUSH-INPUT");
126 lisp__data.input_list = CONS(stream, lisp__data.input_list);
128 if (lisp__data.iunget + 1 == lisp__data.nunget) {
129 LispUngetInfo **info =
130 realloc(lisp__data.unget,
131 sizeof(LispUngetInfo) * (lisp__data.nunget + 1));
134 (info[lisp__data.nunget] =
135 calloc(1, sizeof(LispUngetInfo))) == NULL)
136 LispDestroy("out of memory");
137 lisp__data.unget = info;
141 memset(lisp__data.unget[lisp__data.iunget], '\0', sizeof(LispUngetInfo));
146 LispPopInput(LispObj *stream)
148 if (!CONSP(lisp__data.input_list) || stream != CAR(lisp__data.input_list))
149 LispDestroy("bad stream at POP-INPUT");
150 lisp__data.input_list = CDR(lisp__data.input_list);
151 SINPUT = CONSP(lisp__data.input_list) ?
152 CAR(lisp__data.input_list) : lisp__data.input_list;
158 * Low level functions
161 calculate_line(void *data, int size)
166 for (str = (char*)data, ptr = (char*)data + size; str < ptr; str++)
174 calculate_column(void *data, int size, int column)
178 /* search for newline in data */
179 for (str = (char*)data, ptr = (char*)data + size - 1; ptr >= str; ptr--)
185 return (size - (ptr - str) - 1);
187 /* newline not found */
188 return (column + size);
192 LispFdopen(int descriptor, int mode)
194 LispFile *file = calloc(1, sizeof(LispFile));
199 file->descriptor = descriptor;
200 file->readable = (mode & READ_BIT) != 0;
201 file->writable = (mode & WRITE_BIT) != 0;
203 if (fstat(descriptor, &st) == 0)
204 file->regular = S_ISREG(st.st_mode);
208 file->buffered = (mode & BUFFERED_BIT) != 0;
209 if ((mode & UNBUFFERED_BIT) == 0)
210 file->buffered = file->regular;
212 if (file->buffered) {
213 file->buffer = malloc(pagesize);
214 if (file->buffer == NULL)
218 file->binary = (mode & BINARY_BIT) != 0;
219 file->io_write = write;
226 LispFopen(char *path, int mode)
230 int flags = O_NOCTTY;
232 /* check read/write attributes */
233 if ((mode & (READ_BIT | WRITE_BIT)) == (READ_BIT | WRITE_BIT))
235 else if (mode & READ_BIT)
237 else if (mode & WRITE_BIT)
240 /* create if does not exist */
241 if (mode & WRITE_BIT) {
244 /* append if exists? */
245 if (mode & APPEND_BIT)
252 descriptor = open(path, flags, 0666);
256 /* initialize LispFile structure */
257 file = LispFdopen(descriptor, mode);
265 LispFclose(LispFile *file)
267 /* flush any pending output */
270 close(file->descriptor);
277 LispSetFileWrite(LispFile *file, io_write_fn new_write)
279 io_write_fn old_write = file->io_write;
281 file->io_write = new_write;
287 LispFflush(LispFile *file)
289 if (file->writable && file->length) {
290 int length = (*file->io_write)(file->descriptor,
291 file->buffer, file->length);
294 if (file->length > length)
295 memmove(file->buffer, file->buffer + length,
296 file->length - length);
297 file->length -= length;
306 LispFungetc(LispFile *file, int ch)
308 if (file->readable) {
311 /* this should never happen */
312 if (ch == '\n' && !file->binary)
320 LispFgetc(LispFile *file)
324 if (file->readable) {
327 if (file->available) {
331 else if (file->buffered) {
332 if (file->writable) {
334 if (read(file->descriptor, &c, 1) == 1)
340 if (file->offset < file->length)
341 ch = ((unsigned char*)file->buffer)[file->offset++];
343 int length = read(file->descriptor,
344 file->buffer, pagesize);
347 file->length = length;
352 ch = ((unsigned char*)file->buffer)[file->offset++];
358 else if (read(file->descriptor, &c, 1) == 1)
366 if (ch == '\n' && !file->binary)
373 LispFputc(LispFile *file, int ch)
375 if (file->writable) {
376 unsigned char c = ch;
378 if (file->buffered) {
379 if (file->length + 1 >= pagesize)
381 file->buffer[file->length++] = c;
383 else if ((*file->io_write)(file->descriptor, &c, 1) != 1)
387 /* update column number */
399 LispSgetc(LispString *string)
403 if (string->input >= string->length)
404 return (EOF); /* EOF reading from string */
406 ch = ((unsigned char*)string->string)[string->input++];
407 if (ch == '\n' && !string->binary)
414 LispSputc(LispString *string, int ch)
416 if (string->output + 1 >= string->space) {
420 char *tmp = realloc(string->string, string->space + pagesize);
424 string->string = tmp;
425 string->space += pagesize;
429 string->string[string->output++] = ch;
430 if (string->length < string->output)
431 string->length = string->output;
433 /* update column number */
434 if (!string->binary) {
445 LispFgets(LispFile *file, char *string, int size)
453 if (offset + 1 >= size)
455 if ((ch = LispFgetc(file)) == EOF)
457 string[offset++] = ch;
458 /* line number is calculated in LispFgetc */
462 string[offset] = '\0';
464 return (offset ? string : NULL);
468 LispFputs(LispFile *file, char *buffer)
470 return (LispFwrite(file, buffer, strlen(buffer)));
474 LispSputs(LispString *string, char *buffer)
476 return (LispSwrite(string, buffer, strlen(buffer)));
480 LispFread(LispFile *file, void *data, int size)
492 buffer = (char*)data;
494 /* check if there is an unget character */
495 if (file->available) {
496 *buffer++ = file->unget;
499 if (file->unget == '\n' && !file->binary)
508 if (file->buffered) {
509 void *base_data = (char*)data - length;
511 if (file->writable) {
513 bytes = read(file->descriptor, buffer, size);
517 file->line += calculate_line(base_data, length + bytes);
519 return (length + bytes);
522 /* read anything that is in the buffer */
523 if (file->offset < file->length) {
524 bytes = file->length - file->offset;
527 memcpy(buffer, file->buffer + file->offset, bytes);
529 file->offset += bytes;
533 /* if there is still something to read */
535 bytes = read(file->descriptor, buffer, size);
543 file->line += calculate_line(base_data, length);
548 bytes = read(file->descriptor, buffer, size);
552 file->line += calculate_line(buffer - length, length + bytes);
554 return (length + bytes);
558 LispFwrite(LispFile *file, void *data, int size)
560 if (!file->writable || size < 0)
564 file->column = calculate_column(data, size, file->column);
566 if (file->buffered) {
568 char *buffer = (char*)data;
571 if (size + file->length > pagesize) {
572 /* fill remaining space in buffer and flush */
573 bytes = pagesize - file->length;
574 memcpy(file->buffer + file->length, buffer, bytes);
575 file->length += bytes;
578 /* check if all data was written */
580 return (pagesize - file->length);
587 while (size > pagesize) {
588 /* write multiple of pagesize */
589 bytes = (*file->io_write)(file->descriptor, buffer,
590 size - (size % pagesize));
600 /* keep remaining data in buffer */
603 file->buffer[file->length++] = *buffer++;
605 file->buffer[file->length++] = *buffer++;
607 file->buffer[file->length++] = *buffer++;
609 file->buffer[file->length++] = *buffer++;
611 file->buffer[file->length++] = *buffer++;
613 file->buffer[file->length++] = *buffer++;
615 file->buffer[file->length++] = *buffer++;
617 file->buffer[file->length++] = *buffer++;
620 memcpy(file->buffer + file->length, buffer, size);
621 file->length += size;
630 return ((*file->io_write)(file->descriptor, data, size));
634 LispSwrite(LispString *string, void *data, int size)
641 if (string->output + size >= string->space) {
643 /* leave space for a ending nul character */
644 bytes = string->space - string->output - 1;
655 bytes = string->space + size;
656 bytes += pagesize - (bytes % pagesize);
657 tmp = realloc(string->string, bytes);
662 string->string = tmp;
663 string->space = bytes;
666 memcpy(string->string + string->output, data, size);
667 string->output += size;
668 if (string->length < string->output)
669 string->length = string->output;
672 string->column = calculate_column(data, size, string->column);
678 LispGetSstring(LispString *string, int *length)
680 if (string->string == NULL || string->length <= 0) {
685 *length = string->length;
686 if (string->string[string->length -1] != '\0') {
687 if (string->length < string->space)
688 string->string[string->length] = '\0';
689 else if (string->fixed && string->space)
690 string->string[string->space - 1] = '\0';
692 char *tmp = realloc(string->string, string->space + pagesize);
695 string->string[string->space - 1] = '\0';
697 string->string = tmp;
698 string->space += pagesize;
699 string->string[string->length] = '\0';
704 return (string->string);
708 LispRename(char *from, char *to)
710 return (rename(from, to));
714 LispUnlink(char *name)
716 return (unlink(name));