stdio.c 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329
  1. /* Copyright (C) 2016 Jeremiah Orians
  2. * This file is part of M2-Planet.
  3. *
  4. * M2-Planet is free software: you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation, either version 3 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * M2-Planet is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with M2-Planet. If not, see <http://www.gnu.org/licenses/>.
  16. */
  17. #include <sys/types.h>
  18. #include <sys/stat.h>
  19. #include <fcntl.h>
  20. #include <unistd.h>
  21. #include <stdlib.h>
  22. /* Required constants */
  23. /* For file I/O*/
  24. #define EOF 0xFFFFFFFF
  25. #define BUFSIZ 0x140000 /* 20MB */
  26. /* For lseek */
  27. #define SEEK_SET 0
  28. #define SEEK_CUR 1
  29. #define SEEK_END 2
  30. /* Actual format of FILE */
  31. struct __IO_FILE
  32. {
  33. int fd;
  34. int bufmode; /* O_RDONLY = 0, O_WRONLY = 1 */
  35. int bufpos;
  36. int file_pos;
  37. int buflen;
  38. char* buffer;
  39. };
  40. /* Now give us the FILE we all love */
  41. typedef struct __IO_FILE FILE;
  42. /* Required variables */
  43. FILE* stdin;
  44. FILE* stdout;
  45. FILE* stderr;
  46. void __init_io()
  47. {
  48. stdin = calloc(1, sizeof(FILE));
  49. stdin->fd = STDIN_FILENO;
  50. stdin->bufmode = O_RDONLY;
  51. stdin->buflen = 1;
  52. stdin->buffer = calloc(2, sizeof(char));
  53. stdout = calloc(1, sizeof(FILE));
  54. stdout->fd = STDOUT_FILENO;
  55. stdout->bufmode = O_WRONLY;
  56. stdout->buflen = 1;
  57. stdout->buffer = calloc(2, sizeof(char));
  58. stderr = calloc(1, sizeof(FILE));
  59. stderr->fd = STDERR_FILENO;
  60. stderr->bufmode = O_WRONLY;
  61. stderr->buflen = 1;
  62. stderr->buffer = calloc(2, sizeof(char));
  63. }
  64. /* Standard C functions */
  65. /* Getting */
  66. int fgetc(FILE* f)
  67. {
  68. /* Only read on read buffers */
  69. if(O_WRONLY == f->bufmode) return EOF;
  70. /* Deal with stdin */
  71. if(STDIN_FILENO == f->fd)
  72. {
  73. f->bufpos = 0;
  74. int r = read(f->fd, f->buffer, 1);
  75. /* Catch special case of STDIN gets nothing (AN EOF) */
  76. if(0 == r) return EOF;
  77. }
  78. /* Catch EOF */
  79. if(f->buflen <= f->bufpos) return EOF;
  80. /* Deal with standard case */
  81. int ret = f->buffer[f->bufpos];
  82. f->bufpos = f->bufpos + 1;
  83. return ret;
  84. }
  85. int getchar()
  86. {
  87. return fgetc(stdin);
  88. }
  89. char* fgets(char* str, int count, FILE* stream)
  90. {
  91. int i = 0;
  92. int ch;
  93. while(i < count)
  94. {
  95. ch = fgetc(stream);
  96. if(EOF == ch) break;
  97. str[i] = ch;
  98. i = i + 1;
  99. if('\n' == ch) break;
  100. }
  101. return str;
  102. }
  103. /* Putting */
  104. int fflush(FILE* stream);
  105. void fputc(char s, FILE* f)
  106. {
  107. /* Only write on write buffers */
  108. if(O_RDONLY == f->bufmode) return;
  109. /* Add to buffer */
  110. f->buffer[f->bufpos] = s;
  111. f->bufpos = f->bufpos + 1;
  112. /* Flush if full or '\n' */
  113. if(f->bufpos == f->buflen) fflush(f);
  114. else if('\n' == s) fflush(f);
  115. }
  116. void putchar(char s)
  117. {
  118. fputc(s, stdout);
  119. }
  120. int fputs(char const* str, FILE* stream)
  121. {
  122. while(0 != str[0])
  123. {
  124. fputc(str[0], stream);
  125. str = str + 1;
  126. }
  127. return 0;
  128. }
  129. int puts(char const* str)
  130. {
  131. fputs(str, stdout);
  132. fputc('\n', stdout);
  133. return 0;
  134. }
  135. /* File management */
  136. FILE* fopen(char const* filename, char const* mode)
  137. {
  138. int f;
  139. FILE* fi = calloc(1, sizeof(FILE));
  140. int size;
  141. if('w' == mode[0]) f = open(filename, O_WRONLY|O_CREAT|O_TRUNC , 00600);
  142. else f = open(filename, 0, 0); /* Everything else is a read */
  143. /* Negative numbers are error codes */
  144. if(0 > f)
  145. {
  146. return 0;
  147. }
  148. if('w' == mode[0])
  149. {
  150. /* Buffer as much as possible */
  151. fi->buffer = calloc(BUFSIZ, sizeof(char));
  152. fi->buflen = BUFSIZ;
  153. fi->bufmode = O_WRONLY;
  154. }
  155. else
  156. {
  157. /* Get enough buffer to read it all */
  158. size = lseek(f, 0, SEEK_END);
  159. fi->buffer = calloc(size + 1, sizeof(char));
  160. fi->buflen = size;
  161. fi->bufmode = O_RDONLY;
  162. /* Now read it all */
  163. lseek(f, 0, SEEK_SET);
  164. read(f, fi->buffer, size);
  165. }
  166. fi->fd = f;
  167. return fi;
  168. }
  169. int fflush(FILE* stream)
  170. {
  171. /* We only need to flush on writes */
  172. if(O_RDONLY == stream->bufmode) return 0;
  173. /* If nothing to flush */
  174. if(0 ==stream->bufpos) return 0;
  175. /* The actual flushing */
  176. int error = write(stream->fd, stream->buffer, stream->bufpos);
  177. /* Keep track of position */
  178. stream->file_pos = stream->file_pos + stream->bufpos;
  179. stream->bufpos = 0;
  180. return error;
  181. }
  182. int fclose(FILE* stream)
  183. {
  184. /* Deal with STDIN, STDOUT and STDERR */
  185. /* No close for you */
  186. if(2 >= stream->fd) return 0;
  187. /* We only need to flush on writes */
  188. if(O_WRONLY == stream->bufmode)
  189. {
  190. fflush(stream);
  191. }
  192. /* Need to keep the File Descriptor for a moment */
  193. int fd = stream->fd;
  194. /* Free up the buffer and struct used for FILE */
  195. free(stream->buffer);
  196. free(stream);
  197. /* Do the actual closing */
  198. return close(fd);
  199. }
  200. /* File Positioning */
  201. int ungetc(int ch, FILE* stream)
  202. {
  203. /* Deal with STDIN, STDOUT and STDERR */
  204. /* No ungetc for you */
  205. if(2 >= stream->fd) return EOF;
  206. /* You can't unget on a write stream! */
  207. if(O_WRONLY == stream->bufmode) return EOF;
  208. /* Don't underflow */
  209. if(0 == stream->bufpos) return EOF;
  210. /* Don't let crap be shoved into read stream */
  211. if(stream->buffer[stream->bufpos - 1] != ch) return EOF;
  212. stream->bufpos = stream->bufpos - 1;
  213. return ch;
  214. }
  215. long ftell(FILE* stream)
  216. {
  217. /* Deal with STDIN, STDOUT and STDERR */
  218. /* No ftell for you */
  219. if(2 >= stream->fd) return 0;
  220. /* Deal with buffered output */
  221. if(O_WRONLY == stream->bufmode) return stream->file_pos + stream->bufpos;
  222. /* Deal with read */
  223. return stream->bufpos;
  224. }
  225. int fseek(FILE* f, long offset, int whence)
  226. {
  227. /* Deal with STDIN, STDOUT and STDERR */
  228. /* No seek and destroy missions */
  229. if(2 >= f->fd) return 0;
  230. /* Deal with ugly case */
  231. if(O_WRONLY == f->bufmode)
  232. {
  233. fflush(f);
  234. return lseek(f->fd, offset, whence);
  235. }
  236. /* Deal with read mode */
  237. int pos;
  238. if(SEEK_SET == whence)
  239. {
  240. pos = offset;
  241. }
  242. else if(SEEK_CUR == whence)
  243. {
  244. pos = f->bufpos + offset;
  245. }
  246. else if(SEEK_END == whence)
  247. {
  248. pos = f->buflen + offset;
  249. }
  250. else return -1;
  251. if(pos < 0) return -1;
  252. if(pos > f->buflen) return -1;
  253. f->bufpos = pos;
  254. return pos;
  255. }
  256. void rewind(FILE* f)
  257. {
  258. fseek(f, 0, SEEK_SET);
  259. }