Usermode/libc - open_memstream
[tpg/acess2.git] / Usermode / Libraries / libc.so_src / stdio.c
1 /*\r
2  * AcessOS Basic C Library\r
3  * stdio.c\r
4  */\r
5 #include "config.h"\r
6 #include <acess/sys.h>\r
7 #include <stdlib.h>\r
8 #include <stdio.h>\r
9 #include <string.h>\r
10 #include "lib.h"\r
11 #include "stdio_int.h"\r
12 #include <errno.h>\r
13 #include <assert.h>\r
14 \r
15 #define DEBUG_BUILD     0\r
16 \r
17 // === CONSTANTS ===\r
18 #define _stdin  0\r
19 #define _stdout 1\r
20 \r
21 #define FD_NOTOPEN      -1\r
22 #define FD_MEMFILE      -2\r
23 #define FD_MEMSTREAM    -3\r
24 \r
25 // === PROTOTYPES ===\r
26 struct sFILE    *get_file_struct();\r
27 \r
28 // === GLOBALS ===\r
29 struct sFILE    _iob[STDIO_MAX_STREAMS];        // IO Buffer\r
30 struct sFILE    *stdin; // Standard Input\r
31 struct sFILE    *stdout;        // Standard Output\r
32 struct sFILE    *stderr;        // Standard Error\r
33 ///\note Initialised in SoMain\r
34 static const int STDIN_BUFSIZ = 512;\r
35 static const int STDOUT_BUFSIZ = 512;\r
36 \r
37 // === CODE ===\r
38 void _stdio_init(void)\r
39 {\r
40         // Init FileIO Pointers\r
41         stdin = &_iob[0];\r
42         stdin->FD = 0;\r
43         stdin->Flags = FILE_FLAG_ALLOC|FILE_FLAG_MODE_READ|FILE_FLAG_LINEBUFFERED;\r
44         stdin->Buffer = malloc(STDIN_BUFSIZ);\r
45         stdin->BufferSpace = STDIN_BUFSIZ;\r
46 \r
47         stdout = &_iob[1];\r
48         stdout->FD = 1;\r
49         stdout->Flags = FILE_FLAG_ALLOC|FILE_FLAG_MODE_WRITE|FILE_FLAG_LINEBUFFERED;\r
50         stdout->Buffer = malloc(STDOUT_BUFSIZ);\r
51         stdout->BufferSpace = STDOUT_BUFSIZ;\r
52         \r
53         stderr = &_iob[2];\r
54         stderr->FD = 2;\r
55         stderr->Flags = FILE_FLAG_ALLOC|FILE_FLAG_MODE_WRITE;\r
56 }\r
57 \r
58 void _stdio_cleanup(void)\r
59 {\r
60          int    i;\r
61         for( i = 0; i < STDIO_MAX_STREAMS; i ++ )\r
62         {\r
63                 fclose( &_iob[i] );\r
64         }\r
65 }\r
66 \r
67 int _fopen_modetoflags(const char *mode)\r
68 {\r
69         int flags = 0;\r
70         \r
71         // Get main mode\r
72         switch(*mode)\r
73         {\r
74         case 'r':       flags = FILE_FLAG_MODE_READ;    break;\r
75         case 'w':       flags = FILE_FLAG_MODE_WRITE;   break;\r
76         case 'a':       flags = FILE_FLAG_MODE_APPEND;  break;\r
77         case 'x':       flags = FILE_FLAG_MODE_EXEC;    break;  // Acess addon\r
78         default:\r
79                 return -1;\r
80         }\r
81         mode ++;\r
82 \r
83         // Get Modifiers\r
84         for( ; *mode; mode ++ )\r
85         {\r
86                 switch(*mode)\r
87                 {\r
88                 case 'b':       flags |= FILE_FLAG_M_BINARY;    break;\r
89                 case '+':       flags |= FILE_FLAG_M_EXT;       break;\r
90                 default:\r
91                         return -1;\r
92                 }\r
93         }\r
94         \r
95         return flags;\r
96 }\r
97 \r
98 /**\r
99  * \fn FILE *freopen(char *file, char *mode, FILE *fp)\r
100  */\r
101 EXPORT FILE *freopen(const char *file, const char *mode, FILE *fp)\r
102 {\r
103          int    openFlags = 0;\r
104         \r
105         // Sanity Check Arguments\r
106         if(!fp || !file || !mode)       return NULL;\r
107         \r
108         if(fp->FD != FD_NOTOPEN) {\r
109                 fflush(fp);\r
110         }\r
111 \r
112         // Get stdio flags\r
113         fp->Flags = _fopen_modetoflags(mode);\r
114         if(fp->Flags == -1)\r
115                 return NULL;\r
116         \r
117         // Get Open Flags\r
118         switch(fp->Flags & FILE_FLAG_MODE_MASK)\r
119         {\r
120         // Read\r
121         case FILE_FLAG_MODE_READ:\r
122                 openFlags = OPENFLAG_READ;\r
123                 if(fp->Flags & FILE_FLAG_M_EXT)\r
124                         openFlags |= OPENFLAG_WRITE;\r
125                 break;\r
126         // Write\r
127         case FILE_FLAG_MODE_WRITE:\r
128                 openFlags = OPENFLAG_WRITE;\r
129                 if(fp->Flags & FILE_FLAG_M_EXT)\r
130                         openFlags |= OPENFLAG_READ;\r
131                 break;\r
132         // Execute\r
133         case FILE_FLAG_MODE_APPEND:\r
134                 openFlags = OPENFLAG_APPEND;\r
135                 if(fp->Flags & FILE_FLAG_M_EXT)\r
136                         openFlags |= OPENFLAG_READ;\r
137                 break;\r
138         // Execute\r
139         case FILE_FLAG_MODE_EXEC:\r
140                 openFlags = OPENFLAG_EXEC;\r
141                 break;\r
142         }\r
143 \r
144         //Open File\r
145         if(fp->FD != FD_NOTOPEN)\r
146                 fp->FD = _SysReopen(fp->FD, file, openFlags);\r
147         else\r
148                 fp->FD = _SysOpen(file, openFlags);\r
149         if(fp->FD == -1) {\r
150                 fp->Flags = 0;\r
151                 return NULL;\r
152         }\r
153         \r
154         if( (fp->Flags & FILE_FLAG_MODE_MASK) == FILE_FLAG_MODE_APPEND ) {\r
155                 _SysSeek(fp->FD, 0, SEEK_END);  //SEEK_END\r
156         }\r
157         \r
158         return fp;\r
159 }\r
160 /**\r
161  \fn FILE *fopen(const char *file, const char *mode)\r
162  \brief Opens a file and returns the pointer\r
163  \param file    String - Filename to open\r
164  \param mode    Mode to open in\r
165 */\r
166 EXPORT FILE *fopen(const char *file, const char *mode)\r
167 {\r
168         FILE    *retFile;\r
169         \r
170         // Sanity Check Arguments\r
171         if(!file || !mode)      return NULL;\r
172         \r
173         // Create Return Structure\r
174         retFile = get_file_struct();\r
175         \r
176         return freopen(file, mode, retFile);\r
177 }\r
178 \r
179 EXPORT FILE *fmemopen(void *buffer, size_t length, const char *mode)\r
180 {\r
181         FILE    *ret;\r
182         \r
183         if( !buffer || !mode )  return NULL;\r
184         \r
185         ret = get_file_struct();\r
186         \r
187         ret->FD = FD_MEMFILE;\r
188         ret->Flags = _fopen_modetoflags(mode);\r
189         if(ret->Flags == -1) {\r
190                 ret->Flags = 0;\r
191                 return NULL;\r
192         }\r
193         \r
194         ret->Buffer = buffer;\r
195         ret->BufferPos = 0;\r
196         ret->BufferSpace = length;\r
197         \r
198         return ret;\r
199 }\r
200 \r
201 EXPORT FILE *open_memstream(char **bufferptr, size_t *lengthptr)\r
202 {\r
203         FILE    *ret = get_file_struct();\r
204         ret->FD = FD_MEMSTREAM;\r
205         ret->Flags = FILE_FLAG_MODE_WRITE;\r
206         \r
207         ret->Buffer = NULL;\r
208         ret->BufferPos = 0;\r
209         ret->BufferSpace = 0;\r
210         ret->BufPtr = bufferptr;\r
211         ret->LenPtr = lengthptr;\r
212         \r
213         return ret;\r
214 }\r
215 \r
216 EXPORT int fclose(FILE *fp)\r
217 {\r
218         if( !(fp->Flags & FILE_FLAG_ALLOC) )\r
219                 return 0;\r
220         fflush(fp);\r
221         if( fp->FD >= 0 ) {\r
222                 _SysClose(fp->FD);\r
223         }\r
224         fp->Flags = 0;\r
225         fp->FD = FD_NOTOPEN;\r
226         return 0;\r
227 }\r
228 \r
229 EXPORT int setvbuf(FILE *fp, char *buffer, int mode, size_t size)\r
230 {\r
231         if( !fp ) {\r
232                 errno = EINVAL;\r
233                 return 1;\r
234         }\r
235 \r
236         // Check for memory files\r
237         if( fp->FD == FD_MEMFILE || fp->FD == FD_MEMSTREAM ) {\r
238                 errno = EINVAL;\r
239                 return 2;\r
240         }       \r
241 \r
242         // Not strictly needed, as this should only be called before any IO\r
243         fflush(fp);\r
244 \r
245         // Eliminate any pre-existing buffer\r
246         if( fp->Buffer ) {\r
247                 free( fp->Buffer );\r
248                 fp->Buffer = NULL;\r
249                 fp->BufferSpace = 0;\r
250                 fp->BufferPos = 0;\r
251         }\r
252 \r
253         if( mode == _IONBF ) {\r
254                 // Do nothing, buffering was disabled above\r
255         }\r
256         else\r
257         {\r
258                 // Sanity check buffering mode before allocating\r
259                 if( mode != _IOLBF && mode != _IOFBF ) {\r
260                         errno = EINVAL;\r
261                         return 1;\r
262                 }\r
263                 // Allocate a buffer if one was not provided\r
264                 if( !buffer ) {\r
265                         buffer = malloc(size);\r
266                         assert(buffer);\r
267                 }\r
268                 \r
269                 // Set buffer pointer and size\r
270                 fp->Buffer = buffer;\r
271                 fp->BufferSpace = size;\r
272                 \r
273                 // Set mode flag\r
274                 if( mode == _IOLBF )\r
275                         fp->Flags |= FILE_FLAG_LINEBUFFERED;\r
276                 else\r
277                         fp->Flags &= ~FILE_FLAG_LINEBUFFERED;\r
278         }\r
279         \r
280         return 0;\r
281 }\r
282 \r
283 int _fflush_int(FILE *fp)\r
284 {\r
285          int    ret = 0;\r
286         size_t  len;\r
287         \r
288         // Check the buffer contains data\r
289         if( fp->BufferPos == 0 )\r
290                 return 0;\r
291         \r
292         switch(fp->Flags & FILE_FLAG_MODE_MASK)\r
293         {\r
294         // Read - Flush input buffer\r
295         case FILE_FLAG_MODE_READ:\r
296                 fp->BufferPos = 0;\r
297                 break;\r
298         \r
299         // Append - Seek to end and write\r
300         case FILE_FLAG_MODE_APPEND:\r
301                 _SysSeek(fp->FD, fp->BufferOfs, SEEK_SET);\r
302                 len = _SysWrite(fp->FD, fp->Buffer, fp->BufferPos);\r
303                 if( len < fp->BufferPos )\r
304                         ret = 1;\r
305                 fp->BufferPos -= len;\r
306                 fp->BufferOfs = _SysTell(fp->FD);\r
307                 break;\r
308                 \r
309         // Write - Write buffer\r
310         case FILE_FLAG_MODE_WRITE:\r
311                 //_SysDebug("Flushing to %i '%.*s'", fp->FD, fp->BufferPos, fp->Buffer);\r
312                 len = _SysWrite(fp->FD, fp->Buffer, fp->BufferPos);\r
313                 if( len != fp->BufferPos )\r
314                         ret = 1;\r
315                 fp->BufferPos -= len;\r
316                 break;\r
317         default:\r
318                 break;\r
319         }\r
320         return ret;\r
321 }\r
322 \r
323 EXPORT void fflush(FILE *fp)\r
324 {\r
325         if( !fp || fp->FD == FD_NOTOPEN )\r
326                 return ;\r
327         \r
328         // Nothing to do for memory files\r
329         if( fp->FD == FD_MEMFILE )\r
330                 return ;\r
331         // Memory streams, update pointers\r
332         if( fp->FD == FD_MEMSTREAM ) {\r
333                 *fp->BufPtr = fp->Buffer;\r
334                 *fp->LenPtr = fp->BufferPos;\r
335                 return ;\r
336         }\r
337         \r
338         _fflush_int(fp);\r
339 }\r
340 \r
341 EXPORT void clearerr(FILE *fp)\r
342 {\r
343         if( !fp || fp->FD == FD_NOTOPEN )\r
344                 return ;\r
345         \r
346         // TODO: Impliment clearerr()\r
347 }\r
348 \r
349 EXPORT int feof(FILE *fp)\r
350 {\r
351         if( !fp || fp->FD == FD_NOTOPEN )\r
352                 return 0;\r
353         return !!(fp->Flags & FILE_FLAG_EOF);\r
354 }\r
355 \r
356 EXPORT int ferror(FILE *fp)\r
357 {\r
358         if( !fp || fp->FD == FD_NOTOPEN )\r
359                 return 0;\r
360         return 0;\r
361 }\r
362 EXPORT int fileno(FILE *stream)\r
363 {\r
364         return stream->FD;\r
365 }\r
366 \r
367 EXPORT off_t ftell(FILE *fp)\r
368 {\r
369         if(!fp || fp->FD == FD_NOTOPEN) {\r
370                 errno = EBADF;\r
371                 return -1;\r
372         }\r
373 \r
374         if( fp->FD == FD_MEMFILE || fp->FD == FD_MEMSTREAM )\r
375                 return fp->Pos; \r
376         else\r
377                 return _SysTell(fp->FD);\r
378 }\r
379 \r
380 int _fseek_memfile(FILE *fp, long int amt, int whence)\r
381 {\r
382         switch(whence)\r
383         {\r
384         case SEEK_CUR:\r
385                 fp->Pos += amt;\r
386                 break;\r
387         case SEEK_SET:\r
388                 fp->Pos = amt;\r
389                 break;\r
390         case SEEK_END:\r
391                 if( fp->BufferSpace < (size_t)amt )\r
392                         fp->Pos = 0;\r
393                 else\r
394                         fp->Pos = fp->BufferSpace - amt;\r
395                 break;\r
396         }\r
397         if(fp->Pos > (off_t)fp->BufferSpace) {\r
398                 fp->Pos = fp->BufferSpace;\r
399                 fp->Flags |= FILE_FLAG_EOF;\r
400         }\r
401         return 0;\r
402 }\r
403 \r
404 int _fseek_memstream(FILE *fp, long int amt, int whence)\r
405 {\r
406         switch(whence)\r
407         {\r
408         case SEEK_CUR:\r
409                 fp->Pos += amt;\r
410                 break;\r
411         case SEEK_SET:\r
412                 fp->Pos = amt;\r
413                 break;\r
414         case SEEK_END:\r
415                 if( fp->BufferSpace < (size_t)amt )\r
416                         fp->Pos = 0;\r
417                 else\r
418                         fp->Pos = fp->BufferSpace - amt;\r
419                 break;\r
420         }\r
421         if(fp->Pos > (off_t)fp->BufferSpace) {\r
422                 fp->Pos = fp->BufferSpace;\r
423                 fp->Flags |= FILE_FLAG_EOF;\r
424         }\r
425         return 0;\r
426 }\r
427 \r
428 EXPORT int fseek(FILE *fp, long int amt, int whence)\r
429 {\r
430         if(!fp || fp->FD == FD_NOTOPEN) {\r
431                 errno = EBADF;\r
432                 return -1;\r
433         }\r
434 \r
435         if( fp->FD == FD_MEMFILE ) {\r
436                 return _fseek_memfile(fp, amt, whence);\r
437         }\r
438         else if( fp->FD == FD_MEMSTREAM ) {\r
439                 return _fseek_memstream(fp, amt, whence);\r
440         }\r
441         else {\r
442                 fflush(fp);\r
443                 _SysSeek(fp->FD, amt, whence);\r
444                 fp->Pos = _SysTell(fp->FD);\r
445                 return 0;\r
446         }\r
447 }\r
448 \r
449 size_t _fwrite_unbuffered(FILE *fp, size_t size, size_t num, const void *data)\r
450 {\r
451         size_t  ret = 0, bytes;\r
452         while( num -- )\r
453         {\r
454                 bytes = _SysWrite(fp->FD, data, size);\r
455                 if( bytes == (size_t)-1 ) {\r
456                         // Oops.\r
457                         // TODO: Set error flag\r
458                         break;\r
459                 }\r
460                 if( bytes != size ) {\r
461                         _SysDebug("_fwrite_unbuffered: Oops, rollback %i/%i bytes!", bytes, size);\r
462                         _SysSeek(fp->FD, -bytes, SEEK_CUR);\r
463                         break;\r
464                 }\r
465                 data = (char*)data + size;\r
466         }\r
467         fp->Pos += ret * size;\r
468         return ret;\r
469 }\r
470 \r
471 size_t _fwrite_memfile(const void *ptr, size_t size, size_t num, FILE *fp)\r
472 {\r
473         size_t  avail = (fp->BufferSpace - fp->Pos) / size;\r
474         if( avail == 0 )\r
475                 fp->Flags |= FILE_FLAG_EOF;\r
476         if( num > avail )\r
477                 num = avail;\r
478         size_t  bytes = num * size;\r
479         memcpy(fp->Buffer + fp->Pos, ptr, bytes);\r
480         fp->Pos += bytes;\r
481         return num;\r
482 }\r
483 \r
484 size_t _fwrite_memstream(const void *ptr, size_t size, size_t num, FILE *fp)\r
485 {\r
486         size_t  bytes = size*num;\r
487         // #1. Check if we need to expand\r
488         if( fp->Pos + bytes > fp->BufferSpace )\r
489         {\r
490                 void *newbuf = realloc(fp->Buffer, fp->BufferSpace + bytes);\r
491                 if( !newbuf ) {\r
492                         errno = ENOMEM;\r
493                         return -1;\r
494                 }\r
495                 fp->Buffer = newbuf;\r
496                 fp->BufferSpace = fp->Pos + bytes;\r
497         }\r
498         // #2. Write (use the memfile code for that)\r
499         return _fwrite_memfile(ptr, size, num, fp);\r
500 }\r
501 \r
502 /**\r
503  * \fn EXPORT size_t fwrite(void *ptr, size_t size, size_t num, FILE *fp)\r
504  * \brief Write to a stream\r
505  */\r
506 EXPORT size_t fwrite(const void *ptr, size_t size, size_t num, FILE *fp)\r
507 {\r
508         size_t  ret;\r
509         \r
510         if(!fp || fp->FD == -1)\r
511                 return -1;\r
512         if( size == 0 || num == 0 )\r
513                 return 0;\r
514 \r
515         switch( _GetFileMode(fp) )\r
516         {\r
517         case FILE_FLAG_MODE_READ:\r
518         case FILE_FLAG_MODE_EXEC:\r
519                 errno = EBADF;\r
520                 return 0;\r
521         case FILE_FLAG_MODE_APPEND:\r
522                 fseek(fp, 0, SEEK_END);\r
523         case FILE_FLAG_MODE_WRITE:\r
524                 // Handle memory files first\r
525                 if( fp->FD == FD_MEMFILE ) {\r
526                         return _fwrite_memfile(ptr, size, num, fp);\r
527                 }\r
528                 else if( fp->FD == FD_MEMSTREAM ) {\r
529                         return _fwrite_memstream(ptr, size, num, fp);\r
530                 }\r
531                 else if( fp->BufferSpace )\r
532                 {\r
533                         // Buffering enabled\r
534                         if( fp->BufferSpace - fp->BufferPos < size*num )\r
535                         {\r
536                                 // If there's not enough space, flush and write-through\r
537                                 _fflush_int(fp);        // TODO: check ret\r
538                                 ret = _fwrite_unbuffered(fp, size, num, ptr);\r
539                         }\r
540                         else if( (fp->Flags & FILE_FLAG_LINEBUFFERED) && memchr(ptr,'\n',size*num) )\r
541                         {\r
542                                 // Newline present? Flush though\r
543                                 _fflush_int(fp);        // TODO: check ret\r
544                                 ret = _fwrite_unbuffered(fp, size, num, ptr);\r
545                         }\r
546                         else\r
547                         {\r
548                                 // Copy to buffer\r
549                                 memcpy( fp->Buffer + fp->BufferPos, ptr, size*num );\r
550                                 fp->BufferPos += size*num;\r
551                                 ret = num;\r
552                         }\r
553                 }\r
554                 else\r
555                 {\r
556                         // Bufering disabled, write-though\r
557                         ret = _fwrite_unbuffered(fp, size, num, ptr);\r
558                 }\r
559                 // errno should be set earlier\r
560                 break;\r
561         }\r
562         \r
563         return ret;\r
564 }\r
565 \r
566 size_t _fread_memfile(void *ptr, size_t size, size_t num, FILE *fp)\r
567 {\r
568         size_t  avail = (fp->BufferSpace - fp->Pos) / size;\r
569         if( avail == 0 )\r
570                 fp->Flags |= FILE_FLAG_EOF;\r
571         if( num > avail )       num = avail;\r
572         size_t  bytes = num * size;\r
573         memcpy(ptr, fp->Buffer + fp->Pos, bytes);\r
574         fp->Pos += bytes;\r
575         return num;\r
576 }\r
577 \r
578 #if 0\r
579 size_t _fread_memstream(void *ptr, size_t size, size_t num, FILE *fp)\r
580 {\r
581         errno = ENOTIMPL;\r
582         return -1;\r
583 }\r
584 #endif\r
585 \r
586 /**\r
587  * \fn EXPORT size_t fread(void *ptr, size_t size, size_t num, FILE *fp)\r
588  * \brief Read from a stream\r
589  */\r
590 EXPORT size_t fread(void *ptr, size_t size, size_t num, FILE *fp)\r
591 {\r
592         size_t  ret;\r
593         \r
594         if(!fp || fp->FD == -1)\r
595                 return -1;\r
596         if( size == 0 || num == 0 )\r
597                 return 0;\r
598         \r
599         if( _GetFileMode(fp) != FILE_FLAG_MODE_READ ) {\r
600                 errno = 0;\r
601                 return -1;\r
602         }\r
603 \r
604         if( fp->FD == FD_MEMFILE ) {\r
605                 return _fread_memfile(ptr, size, num, fp);\r
606         }\r
607         else if( fp->FD == FD_MEMSTREAM ) {\r
608                 //return _fread_memstream(ptr, size, num, fp);\r
609                 errno = EBADF;\r
610                 return 0;\r
611         }\r
612         \r
613         // Standard file\r
614         ret = _SysRead(fp->FD, ptr, size*num);\r
615         if( ret == (size_t)-1)\r
616                 return -1;\r
617         if( ret == 0 && size*num > 0 ) {\r
618                 fp->Flags |= FILE_FLAG_EOF;\r
619                 return 0;\r
620         }\r
621         ret /= size;\r
622         \r
623         return ret;\r
624 }\r
625 \r
626 /**\r
627  * \brief Write a string to a stream (without trailing \n)\r
628  */\r
629 EXPORT int fputs(const char *s, FILE *fp)\r
630 {\r
631         int len = strlen(s);\r
632         return fwrite(s, 1, len, fp);\r
633 }\r
634 \r
635 /**\r
636  * \brief Read a line (and possible trailing \n into a buffer)\r
637  */\r
638 EXPORT char *fgets(char *s, int size, FILE *fp)\r
639 {\r
640         int ofs = 0;\r
641         char    ch = '\0';\r
642         while( ofs < size && ch != '\n' )\r
643         {\r
644                 if( fread(&ch, 1, 1, fp) != 1 )\r
645                         break;\r
646                 s[ofs ++] = ch;\r
647         }\r
648         if( ofs < size )\r
649                 s[ofs] = '\0';\r
650         return s;\r
651 }\r
652 \r
653 /**\r
654  * \fn EXPORT int fputc(int c, FILE *fp)\r
655  * \brief Write a single character to the stream\r
656  */\r
657 EXPORT int fputc(int c, FILE *fp)\r
658 {\r
659         return fwrite(&c, 1, 1, fp);\r
660 }\r
661 \r
662 EXPORT int putchar(int c)\r
663 {\r
664         c &= 0xFF;\r
665         return _SysWrite(_stdout, &c, 1);\r
666 }\r
667 \r
668 /**\r
669  * \fn EXPORT int fgetc(FILE *fp)\r
670  * \brief Read a character from the stream\r
671  */\r
672 EXPORT int fgetc(FILE *fp)\r
673 {\r
674         char    ret = 0;\r
675         if( fread(&ret, 1, 1, fp) != 1 )\r
676                 return -1;\r
677         return ret;\r
678 }\r
679 \r
680 EXPORT int getchar(void)\r
681 {\r
682         char    ret = 0;\r
683         if(_SysRead(_stdin, &ret, 1) != 1)      return -1;\r
684         return ret;\r
685 }\r
686 \r
687 EXPORT int puts(const char *str)\r
688 {\r
689          int    len;\r
690         \r
691         if(!str)        return 0;\r
692         len = strlen(str);\r
693         \r
694         len = _SysWrite(_stdout, str, len);\r
695         _SysWrite(_stdout, "\n", 1);\r
696         return len;\r
697 }\r
698 \r
699 // --- INTERNAL ---\r
700 /**\r
701  * \fn FILE *get_file_struct()\r
702  * \brief Returns a file descriptor structure\r
703  */\r
704 FILE *get_file_struct()\r
705 {\r
706          int    i;\r
707         for(i=0;i<STDIO_MAX_STREAMS;i++)\r
708         {\r
709                 if(_iob[i].Flags & FILE_FLAG_ALLOC)\r
710                         continue ;\r
711                 _iob[i].Flags |= FILE_FLAG_ALLOC;\r
712                 _iob[i].FD = -1;\r
713                 _iob[i].Pos = 0;\r
714                 return &_iob[i];\r
715         }\r
716         return NULL;\r
717 }\r
718 \r

UCC git Repository :: git.ucc.asn.au