upload tizen1.0 source
[framework/uifw/xorg/app/x11-apps.git] / xedit / lisp / io.c
1 /*
2  * Copyright (c) 2002 by The XFree86 Project, Inc.
3  *
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:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *  
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
20  * SOFTWARE.
21  *
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
25  * XFree86 Project.
26  *
27  * Author: Paulo César Pereira de Andrade
28  */
29
30 /* $XFree86: xc/programs/xedit/lisp/io.c,v 1.16tsi Exp $ */
31
32 #include "lisp/io.h"
33 #include <errno.h>
34 #include <fcntl.h>
35 #include <stdarg.h>
36 #include <sys/types.h>
37 #include <sys/stat.h>
38
39 /* Match the FILE_XXX flags */
40 #define READ_BIT        0x01
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
46
47 /*
48  * Prototypes
49  */
50 static int calculate_line(void*, int);
51 static int calculate_column(void*, int, int);
52
53 /*
54  * Initialization
55  */
56 extern int pagesize;
57
58 /*
59  * Implementation
60  */
61 int
62 LispGet(void)
63 {
64     int ch = EOF;
65     LispUngetInfo *unget = lisp__data.unget[lisp__data.iunget];
66
67     if (unget->offset)
68         ch = ((unsigned char*)unget->buffer)[--unget->offset];
69     else if (SINPUT->data.stream.readable) {
70         LispFile *file = NULL;
71
72         switch (SINPUT->data.stream.type) {
73             case LispStreamStandard:
74             case LispStreamFile:
75                 file = FSTREAMP(SINPUT);
76                 break;
77             case LispStreamPipe:
78                 file = IPSTREAMP(SINPUT);
79                 break;
80             case LispStreamString:
81                 ch = LispSgetc(SSTREAMP(SINPUT));
82                 break;
83             default:
84                 ch = EOF;
85                 break;
86         }
87         if (file != NULL) {
88             if (file->nonblock) {
89                 if (fcntl(file->descriptor, F_SETFL, 0) < 0)
90                     LispDestroy("fcntl: %s", strerror(errno));
91                 file->nonblock = 0;
92             }
93             ch = LispFgetc(file);
94         }
95     }
96     else
97         LispDestroy("cannot read from *STANDARD-INPUT*");
98
99     if (ch == EOF)
100         lisp__data.eof = 1;
101
102     return (ch);
103 }
104
105 int
106 LispUnget(int ch)
107 {
108     LispUngetInfo *unget = lisp__data.unget[lisp__data.iunget];
109
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;
114     }
115     else
116         unget->buffer[unget->offset++] = ch;
117
118     return (ch);
119 }
120
121 void
122 LispPushInput(LispObj *stream)
123 {
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);
127     SINPUT = stream;
128     if (lisp__data.iunget + 1 == lisp__data.nunget) {
129         LispUngetInfo **info =
130             realloc(lisp__data.unget,
131                     sizeof(LispUngetInfo) * (lisp__data.nunget + 1));
132
133         if (!info ||
134             (info[lisp__data.nunget] =
135              calloc(1, sizeof(LispUngetInfo))) == NULL)
136             LispDestroy("out of memory");
137         lisp__data.unget = info;
138         ++lisp__data.nunget;
139     }
140     ++lisp__data.iunget;
141     memset(lisp__data.unget[lisp__data.iunget], '\0', sizeof(LispUngetInfo));
142     lisp__data.eof = 0;
143 }
144
145 void
146 LispPopInput(LispObj *stream)
147 {
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;
153     --lisp__data.iunget;
154     lisp__data.eof = 0;
155 }
156
157 /*
158  * Low level functions
159  */
160 static int
161 calculate_line(void *data, int size)
162 {
163     int line = 0;
164     char *str, *ptr;
165
166     for (str = (char*)data, ptr = (char*)data + size; str < ptr; str++)
167         if (*ptr == '\n')
168             ++line;
169
170     return (line);
171 }
172
173 static int
174 calculate_column(void *data, int size, int column)
175 {
176     char *str, *ptr;
177
178     /* search for newline in data */
179     for (str = (char*)data, ptr = (char*)data + size - 1; ptr >= str; ptr--)
180         if (*ptr == '\n')
181             break;
182
183     /* newline found */
184     if (ptr >= str)
185         return (size - (ptr - str) - 1);
186
187     /* newline not found */
188     return (column + size);
189 }
190
191 LispFile *
192 LispFdopen(int descriptor, int mode)
193 {
194     LispFile *file = calloc(1, sizeof(LispFile));
195
196     if (file) {
197         struct stat st;
198
199         file->descriptor = descriptor;
200         file->readable = (mode & READ_BIT) != 0;
201         file->writable = (mode & WRITE_BIT) != 0;
202
203         if (fstat(descriptor, &st) == 0)
204             file->regular = S_ISREG(st.st_mode);
205         else
206             file->regular = 0;
207
208         file->buffered = (mode & BUFFERED_BIT) != 0;
209         if ((mode & UNBUFFERED_BIT) == 0)
210             file->buffered = file->regular;
211
212         if (file->buffered) {
213             file->buffer = malloc(pagesize);
214             if (file->buffer == NULL)
215                 file->buffered = 0;
216         }
217         file->line = 1;
218         file->binary = (mode & BINARY_BIT) != 0;
219         file->io_write = write;
220     }
221
222     return (file);
223 }
224
225 LispFile *
226 LispFopen(char *path, int mode)
227 {
228     LispFile *file;
229     int descriptor;
230     int flags = O_NOCTTY;
231
232     /* check read/write attributes */
233     if ((mode & (READ_BIT | WRITE_BIT)) == (READ_BIT | WRITE_BIT))
234         flags |= O_RDWR;
235     else if (mode & READ_BIT)
236         flags |= O_RDONLY;
237     else if (mode & WRITE_BIT)
238         flags |= O_WRONLY;
239
240     /* create if does not exist */
241     if (mode & WRITE_BIT) {
242         flags |= O_CREAT;
243
244         /* append if exists? */
245         if (mode & APPEND_BIT)
246             flags |= O_APPEND;
247         else
248             flags |= O_TRUNC;
249     }
250
251     /* open file */
252     descriptor = open(path, flags, 0666);
253     if (descriptor < 0)
254         return (NULL);
255
256     /* initialize LispFile structure */
257     file = LispFdopen(descriptor, mode);
258     if (file == NULL)
259         close(descriptor);
260
261     return (file);
262 }
263
264 void
265 LispFclose(LispFile *file)
266 {
267     /* flush any pending output */
268     LispFflush(file);
269     /* cleanup */
270     close(file->descriptor);
271     if (file->buffer)
272         free(file->buffer);
273     free(file);
274 }
275
276 io_write_fn
277 LispSetFileWrite(LispFile *file, io_write_fn new_write)
278 {
279     io_write_fn old_write = file->io_write;
280
281     file->io_write = new_write;
282
283     return (old_write);
284 }
285
286 int
287 LispFflush(LispFile *file)
288 {
289     if (file->writable && file->length) {
290         int length = (*file->io_write)(file->descriptor,
291                                        file->buffer, file->length);
292
293         if (length > 0) {
294             if (file->length > length)
295                 memmove(file->buffer, file->buffer + length,
296                         file->length - length);
297             file->length -= length;
298         }
299         return (length);
300     }
301
302     return (0);
303 }
304
305 int
306 LispFungetc(LispFile *file, int ch)
307 {
308     if (file->readable) {
309         file->available = 1;
310         file->unget = ch;
311         /* this should never happen */
312         if (ch == '\n' && !file->binary)
313             --file->line;
314     }
315
316     return (ch);
317 }
318
319 int
320 LispFgetc(LispFile *file)
321 {
322     int ch;
323
324     if (file->readable) {
325         unsigned char c;
326
327         if (file->available) {
328             ch = file->unget;
329             file->available = 0;
330         }
331         else if (file->buffered) {
332             if (file->writable) {
333                 LispFflush(file);
334                 if (read(file->descriptor, &c, 1) == 1)
335                     ch = c;
336                 else
337                     ch = EOF;
338             }
339             else {
340                 if (file->offset < file->length)
341                     ch = ((unsigned char*)file->buffer)[file->offset++];
342                 else {
343                     int length = read(file->descriptor,
344                                       file->buffer, pagesize);
345
346                     if (length >= 0)
347                         file->length = length;
348                     else
349                         file->length = 0;
350                     file->offset = 0;
351                     if (file->length)
352                         ch = ((unsigned char*)file->buffer)[file->offset++];
353                     else
354                         ch = EOF;
355                 }
356             }
357         }
358         else if (read(file->descriptor, &c, 1) == 1)
359             ch = c;
360         else
361             ch = EOF;
362     }
363     else
364         ch = EOF;
365
366     if (ch == '\n' && !file->binary)
367         ++file->line;
368
369     return (ch);
370 }
371
372 int
373 LispFputc(LispFile *file, int ch)
374 {
375     if (file->writable) {
376         unsigned char c = ch;
377
378         if (file->buffered) {
379             if (file->length + 1 >= pagesize)
380                 LispFflush(file);
381             file->buffer[file->length++] = c;
382         }
383         else if ((*file->io_write)(file->descriptor, &c, 1) != 1)
384             ch = EOF;
385
386         if (!file->binary) {
387             /* update column number */
388             if (ch == '\n')
389                 file->column = 0;
390             else
391                 ++file->column;
392         }
393     }
394
395     return (ch);
396 }
397
398 int
399 LispSgetc(LispString *string)
400 {
401     int ch;
402
403     if (string->input >= string->length)
404         return (EOF);                   /* EOF reading from string */
405
406     ch = ((unsigned char*)string->string)[string->input++];
407     if (ch == '\n' && !string->binary)
408         ++string->line;
409
410     return (ch);
411 }
412
413 int
414 LispSputc(LispString *string, int ch)
415 {
416     if (string->output + 1 >= string->space) {
417         if (string->fixed)
418             return (EOF);
419         else {
420             char *tmp = realloc(string->string, string->space + pagesize);
421
422             if (tmp == NULL)
423                 return (EOF);
424             string->string = tmp;
425             string->space += pagesize;
426         }
427     }
428
429     string->string[string->output++] = ch;
430     if (string->length < string->output)
431         string->length = string->output;
432
433     /* update column number */
434     if (!string->binary) {
435         if (ch == '\n')
436             string->column = 0;
437         else
438             ++string->column;
439     }
440
441     return (ch);
442 }
443
444 char *
445 LispFgets(LispFile *file, char *string, int size)
446 {
447     int ch, offset = 0;
448
449     if (size < 1)
450         return (string);
451
452     for (;;) {
453         if (offset + 1 >= size)
454             break;
455         if ((ch = LispFgetc(file)) == EOF)
456             break;
457         string[offset++] = ch;
458         /* line number is calculated in LispFgetc */
459         if (ch == '\n')
460             break;
461     }
462     string[offset] = '\0';
463
464     return (offset ? string : NULL);
465 }
466
467 int
468 LispFputs(LispFile *file, char *buffer)
469 {
470     return (LispFwrite(file, buffer, strlen(buffer)));
471 }
472
473 int
474 LispSputs(LispString *string, char *buffer)
475 {
476     return (LispSwrite(string, buffer, strlen(buffer)));
477 }
478
479 int
480 LispFread(LispFile *file, void *data, int size)
481 {
482     int bytes, length;
483     char *buffer;
484
485     if (!file->readable)
486         return (EOF);
487
488     if (size <= 0)
489         return (size);
490
491     length = 0;
492     buffer = (char*)data;
493
494     /* check if there is an unget character */
495     if (file->available) {
496         *buffer++ = file->unget;
497         file->available = 0;
498         if (--size == 0) {
499             if (file->unget == '\n' && !file->binary)
500                 ++file->line;
501
502             return (1);
503         }
504
505         length = 1;
506     }
507
508     if (file->buffered) {
509         void *base_data = (char*)data - length;
510
511         if (file->writable) {
512             LispFflush(file);
513             bytes = read(file->descriptor, buffer, size);
514             if (bytes < 0)
515                 bytes = 0;
516             if (!file->binary)
517                 file->line += calculate_line(base_data, length + bytes);
518
519             return (length + bytes);
520         }
521
522         /* read anything that is in the buffer */
523         if (file->offset < file->length) {
524             bytes = file->length - file->offset;
525             if (bytes > size)
526                 bytes = size;
527             memcpy(buffer, file->buffer + file->offset, bytes);
528             buffer += bytes;
529             file->offset += bytes;
530             size -= bytes;
531         }
532
533         /* if there is still something to read */
534         if (size) {
535             bytes = read(file->descriptor, buffer, size);
536             if (bytes < 0)
537                 bytes = 0;
538
539             length += bytes;
540         }
541
542         if (!file->binary)
543             file->line += calculate_line(base_data, length);
544
545         return (length);
546     }
547
548     bytes = read(file->descriptor, buffer, size);
549     if (bytes < 0)
550         bytes = 0;
551     if (!file->binary)
552         file->line += calculate_line(buffer - length, length + bytes);
553
554     return (length + bytes);
555 }
556
557 int
558 LispFwrite(LispFile *file, void *data, int size)
559 {
560     if (!file->writable || size < 0)
561         return (EOF);
562
563     if (!file->binary)
564         file->column = calculate_column(data, size, file->column);
565
566     if (file->buffered) {
567         int length, bytes;
568         char *buffer = (char*)data;
569
570         length = 0;
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;
576             LispFflush(file);
577
578             /* check if all data was written */
579             if (file->length)
580                 return (pagesize - file->length);
581
582             length = bytes;
583             buffer += bytes;
584             size -= bytes;
585         }
586
587         while (size > pagesize) {
588             /* write multiple of pagesize */
589             bytes = (*file->io_write)(file->descriptor, buffer,
590                                       size - (size % pagesize));
591             if (bytes <= 0)
592                 return (length);
593
594             length += bytes;
595             buffer += bytes;
596             size -= bytes;
597         }
598
599         if (size) {
600             /* keep remaining data in buffer */
601             switch (size) {
602                 case 8:
603                     file->buffer[file->length++] = *buffer++;
604                 case 7:
605                     file->buffer[file->length++] = *buffer++;
606                 case 6:
607                     file->buffer[file->length++] = *buffer++;
608                 case 5:
609                     file->buffer[file->length++] = *buffer++;
610                 case 4:
611                     file->buffer[file->length++] = *buffer++;
612                 case 3:
613                     file->buffer[file->length++] = *buffer++;
614                 case 2:
615                     file->buffer[file->length++] = *buffer++;
616                 case 1:
617                     file->buffer[file->length++] = *buffer++;
618                     break;
619                 default:
620                     memcpy(file->buffer + file->length, buffer, size);
621                     file->length += size;
622                     break;
623             }
624             length += size;
625         }
626
627         return (length);
628     }
629
630     return ((*file->io_write)(file->descriptor, data, size));
631 }
632
633 int
634 LispSwrite(LispString *string, void *data, int size)
635 {
636     int bytes;
637
638     if (size < 0)
639         return (EOF);
640
641     if (string->output + size >= string->space) {
642         if (string->fixed) {
643             /* leave space for a ending nul character */
644             bytes = string->space - string->output - 1;
645
646             if (bytes < size)
647                 size = bytes;
648
649             if (size <= 0)
650                 return (-1);
651         }
652         else {
653             char *tmp;
654
655             bytes = string->space + size;
656             bytes += pagesize - (bytes % pagesize);
657             tmp = realloc(string->string, bytes);
658
659             if (tmp == NULL)
660                 return (-1);
661
662             string->string = tmp;
663             string->space = bytes;
664         }
665     }
666     memcpy(string->string + string->output, data, size);
667     string->output += size;
668     if (string->length < string->output)
669         string->length = string->output;
670
671     if (!string->binary)
672         string->column = calculate_column(data, size, string->column);
673
674     return (size);
675 }
676
677 char *
678 LispGetSstring(LispString *string, int *length)
679 {
680     if (string->string == NULL || string->length <= 0) {
681         *length = 0;
682
683         return ("");
684     }
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';
691         else {
692             char *tmp = realloc(string->string, string->space + pagesize);
693
694             if (tmp == NULL)
695                 string->string[string->space - 1] = '\0';
696             else {
697                 string->string = tmp;
698                 string->space += pagesize;
699                 string->string[string->length] = '\0';
700             }
701         }
702     }
703
704     return (string->string);
705 }
706
707 int
708 LispRename(char *from, char *to)
709 {
710     return (rename(from, to));
711 }
712
713 int
714 LispUnlink(char *name)
715 {
716     return (unlink(name));
717 }