stdio.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399
  1. /*
  2. * Stdio replacement library
  3. * Contains a subset of functions to use as drop-in replacement
  4. * Specifically made for porting the BCC compiler
  5. * Getc has a memory buffer, and puts is put entirely into memory
  6. */
  7. // maximum number of files to open at the same time (+1 because we skip index 0)
  8. #define FOPEN_MAX_FILES 16
  9. #define FOPEN_FILENAME_LIMIT 32
  10. #define EOF -1
  11. #define FOPEN_OUTFILE_ADDR 0x500000
  12. char fopenList[FOPEN_MAX_FILES][FOPEN_FILENAME_LIMIT]; // filenames for each opened file
  13. word fopenCurrentlyOpen[FOPEN_MAX_FILES]; // which indexes are currently opened
  14. word fopenCursors[FOPEN_MAX_FILES]; // cursors of currently opened files
  15. word CH376CurrentlyOpened = 0; // index in fopenList which is currently opened on CH376
  16. // Buffers for reading/writing
  17. // Length of buffer always should be less than 65536, since this is the maximum FS_readFile can do in a single call
  18. #define STDIO_FBUF_LEN 4096
  19. char *inputBuffer = (char*) INPUTBUFFER_ADDR; //[STDIO_FBUF_LEN];
  20. word inbufStartPos = 0; // where in the file the buffer starts
  21. word inbufCursor = 0; // where in the buffer we currently are working
  22. word outbufCursor = 0;
  23. word outFileIndex = 0;
  24. word includeDepth = 0; // keeping track how many levels we are deep compiling, for progress bar
  25. // fopen replacement
  26. // requires full paths
  27. // returns 0 on error
  28. // otherwise returns the index to the fopenList buffer
  29. // creates new file if write is 1
  30. // append is not an option for now
  31. word fopen(const char* fname, const word write)
  32. {
  33. if (strlen(fname) >= FOPEN_FILENAME_LIMIT)
  34. {
  35. BDOS_PrintConsole("E: Path too large\n");
  36. return 0;
  37. }
  38. if (fname[0] != '/')
  39. {
  40. BDOS_PrintConsole("E: Filename should be a full path\n");
  41. return 0;
  42. }
  43. // conver to uppercase
  44. strToUpper(fname);
  45. // if write, create the file
  46. if (write)
  47. {
  48. outbufCursor = 0; // where in the buffer we currently are working
  49. FS_close(); // to be sure
  50. CH376CurrentlyOpened = 0;
  51. // if current path is correct (can be file or directory)
  52. if (FS_sendFullPath(fname) == FS_ANSW_USB_INT_SUCCESS)
  53. {
  54. // create the file
  55. if (FS_createFile() == FS_ANSW_USB_INT_SUCCESS)
  56. {
  57. //BDOS_PrintConsole("File created\n");
  58. }
  59. else
  60. {
  61. BDOS_PrintConsole("E: Could not create file\n");
  62. return 0;
  63. }
  64. }
  65. else
  66. {
  67. BDOS_PrintConsole("E: Invalid path\n");
  68. return 0;
  69. }
  70. }
  71. else // read
  72. {
  73. FS_close();
  74. CH376CurrentlyOpened = 0;
  75. // init read buffer
  76. inbufStartPos = 0; // start at 0
  77. inbufCursor = 0; // start at 0
  78. }
  79. word i = 1; // skip index 0
  80. while (i < FOPEN_MAX_FILES)
  81. {
  82. if (fopenCurrentlyOpen[i] == 0)
  83. {
  84. // found a free spot
  85. fopenCurrentlyOpen[i] = 1;
  86. fopenCursors[i] = 0;
  87. // write filename
  88. strcpy(fopenList[i], fname);
  89. // so we know which file is the output file
  90. if (write)
  91. {
  92. outFileIndex = i;
  93. }
  94. else
  95. {
  96. word x;
  97. for (x = 0; x < includeDepth; x++)
  98. {
  99. BDOS_PrintConsole("-");
  100. }
  101. BDOS_PrintlnConsole(fname);
  102. includeDepth++;
  103. }
  104. return i; // return index
  105. }
  106. i++;
  107. }
  108. BDOS_PrintConsole("E: The maximum number of files are already opened. Forgot to close some files?\n");
  109. return 0;
  110. }
  111. // returns EOF if file cannot be opened
  112. word fcanopen(word i)
  113. {
  114. if (CH376CurrentlyOpened == i)
  115. {
  116. return 0;
  117. }
  118. FS_close();
  119. CH376CurrentlyOpened = 0;
  120. // if the resulting path is correct (can be file or directory)
  121. if (FS_sendFullPath(fopenList[i]) == FS_ANSW_USB_INT_SUCCESS)
  122. {
  123. // if we can successfully open the file (not directory)
  124. if (FS_open() == FS_ANSW_USB_INT_SUCCESS)
  125. {
  126. FS_close();
  127. return 0;
  128. }
  129. else
  130. {
  131. return EOF;
  132. }
  133. }
  134. else
  135. {
  136. return EOF;
  137. }
  138. return EOF;
  139. }
  140. // closes file at index
  141. // also closes the file on CH376 if it is currently open there as well
  142. void fclose(word i)
  143. {
  144. if (CH376CurrentlyOpened == i)
  145. {
  146. FS_close(); // to be sure
  147. CH376CurrentlyOpened = 0;
  148. }
  149. // if output file, write entire buffer to the file
  150. if (outFileIndex == i && i > 0)
  151. {
  152. BDOS_PrintConsole("\nWriting to output file:\n");
  153. // close other file if open
  154. FS_close();
  155. CH376CurrentlyOpened = 0;
  156. // if the resulting path is correct (can be file or directory)
  157. if (FS_sendFullPath(fopenList[i]) == FS_ANSW_USB_INT_SUCCESS)
  158. {
  159. // if we can successfully open the file (not directory)
  160. if (FS_open() == FS_ANSW_USB_INT_SUCCESS)
  161. {
  162. FS_setCursor(0); // set cursor to start
  163. word bytesWritten = 0;
  164. word* outbufAddr = (word*) FOPEN_OUTFILE_ADDR;
  165. // loop until all bytes are sent
  166. while (bytesWritten != outbufCursor)
  167. {
  168. word partToSend = outbufCursor - bytesWritten;
  169. // send in parts of 0xFFFF
  170. if (partToSend > 0xFFFF)
  171. partToSend = 0xFFFF;
  172. // write away
  173. if (FS_writeFile((outbufAddr +bytesWritten), partToSend) != FS_ANSW_USB_INT_SUCCESS)
  174. BDOS_PrintConsole("write error\n");
  175. // Update the amount of bytes sent
  176. bytesWritten += partToSend;
  177. BDOS_PrintConsole(".");
  178. }
  179. BDOS_PrintConsole("\nDone!\n");
  180. FS_close();
  181. }
  182. else
  183. {
  184. BDOS_PrintConsole("E: could not open outfile\n");
  185. return;
  186. }
  187. }
  188. else
  189. {
  190. BDOS_PrintConsole("E: could not open outfile\n");
  191. return;
  192. }
  193. outFileIndex = 0;
  194. }
  195. else
  196. {
  197. includeDepth--;
  198. word x;
  199. for (x = 0; x < includeDepth; x++)
  200. {
  201. BDOS_PrintConsole("-");
  202. }
  203. BDOS_PrintlnConsole("Done");
  204. }
  205. fopenCurrentlyOpen[i] = 0;
  206. fopenList[i][0] = 0; // to be sure
  207. }
  208. // returns the current char at cursor (EOF is end of file)
  209. // increments the cursor
  210. word fgetc(word i)
  211. {
  212. // check if file is open
  213. if (fopenCurrentlyOpen[i] == 0)
  214. {
  215. BDOS_PrintConsole("fgetc: File is not open\n");
  216. return EOF;
  217. }
  218. // open on CH376 if not open already
  219. if (CH376CurrentlyOpened != i)
  220. {
  221. // close last one first, unless there is no last
  222. if (CH376CurrentlyOpened != 0)
  223. {
  224. //BDOS_PrintConsole("fgetc: Closed previous file\n");
  225. FS_close();
  226. }
  227. // if the resulting path is correct (can be file or directory)
  228. if (FS_sendFullPath(fopenList[i]) == FS_ANSW_USB_INT_SUCCESS)
  229. {
  230. // if we can successfully open the file (not directory)
  231. if (FS_open() == FS_ANSW_USB_INT_SUCCESS)
  232. {
  233. CH376CurrentlyOpened = i;
  234. // set cursor to last position
  235. FS_setCursor(fopenCursors[i]);
  236. // reset the buffer
  237. inbufStartPos = fopenCursors[i];
  238. inbufCursor = 0;
  239. //BDOS_PrintConsole("fgetc: File opened on CH376\n");
  240. }
  241. else
  242. {
  243. BDOS_PrintConsole("E: Could not open file\n");
  244. return EOF;
  245. }
  246. }
  247. else
  248. {
  249. BDOS_PrintConsole("E: Invalid path\n");
  250. return EOF;
  251. }
  252. }
  253. // workaround for missing compiler check for ALU constants > 11 bit
  254. word stdioBufLen = STDIO_FBUF_LEN;
  255. if (inbufCursor >= STDIO_FBUF_LEN || inbufCursor == 0) // we are at the end of the buffer (or it is not initialized yet)
  256. {
  257. // get filesize
  258. word sizeOfFile = FS_getFileSize();
  259. // if we cannot completely fill the buffer:
  260. if (inbufStartPos + stdioBufLen > sizeOfFile)
  261. {
  262. // fill the buffer, and append with EOF token
  263. FS_readFile(inputBuffer, sizeOfFile - inbufStartPos, 0);
  264. inputBuffer[sizeOfFile - inbufStartPos] = EOF;
  265. }
  266. else
  267. {
  268. // Fill buffer again
  269. FS_readFile(inputBuffer, STDIO_FBUF_LEN, 0);
  270. }
  271. inbufStartPos += stdioBufLen; // for the next fill
  272. inbufCursor = 0; // start at the beginning of the buffer again
  273. }
  274. // return from the buffer, and increment
  275. char gotchar = inputBuffer[inbufCursor];
  276. inbufCursor++;
  277. fopenCursors[i]++;
  278. // BDOS_PrintcConsole(gotchar); // useful for debugging
  279. return gotchar;
  280. }
  281. // write to memory buffer
  282. word fputs(word i, char* s)
  283. {
  284. if (i != outFileIndex)
  285. {
  286. BDOS_PrintConsole("W: Writing to something else than outfile!\n");
  287. }
  288. word* outbufAddr = (word*) FOPEN_OUTFILE_ADDR;
  289. word slen = strlen(s);
  290. memcpy((outbufAddr +outbufCursor), s, slen);
  291. outbufCursor += slen;
  292. return 1;
  293. }
  294. // write to memory buffer
  295. word fputc(word i, char c)
  296. {
  297. if (i != outFileIndex)
  298. {
  299. BDOS_PrintConsole("W: Writing to something else than outfile!\n");
  300. }
  301. word* outbufAddr = (word*) FOPEN_OUTFILE_ADDR;
  302. *(outbufAddr +outbufCursor) = c;
  303. outbufCursor++;
  304. return 1;
  305. }
  306. int fgetpos(word i)
  307. {
  308. if (i != outFileIndex)
  309. {
  310. BDOS_PrintConsole("W: Getting cursor for something else than outfile!\n");
  311. }
  312. return outbufCursor;
  313. }
  314. int fsetpos(word i, word c)
  315. {
  316. if (i != outFileIndex)
  317. {
  318. BDOS_PrintConsole("W: Setting cursor for something else than outfile!\n");
  319. }
  320. outbufCursor = c;
  321. return 1;
  322. }
  323. word printf(char* s)
  324. {
  325. BDOS_PrintConsole(s);
  326. }
  327. word printd(word d)
  328. {
  329. if (d < 0)
  330. {
  331. BDOS_PrintcConsole('-');
  332. BDOS_PrintDecConsole(-d);
  333. }
  334. else
  335. {
  336. BDOS_PrintDecConsole(d);
  337. }
  338. }
  339. void exit(word i)
  340. {
  341. asm("jump Return_BDOS\n");
  342. }