]>
Commit | Line | Data |
---|---|---|
1eee94d3 GM |
1 | /* do not edit automatically generated by mc from FIO. */ |
2 | /* FIO.mod provides a simple buffered file input/output library. | |
3 | ||
83ffe9cd | 4 | Copyright (C) 2001-2023 Free Software Foundation, Inc. |
1eee94d3 GM |
5 | Contributed by Gaius Mulley <gaius.mulley@southwales.ac.uk>. |
6 | ||
7 | This file is part of GNU Modula-2. | |
8 | ||
9 | GNU Modula-2 is free software; you can redistribute it and/or modify | |
10 | it under the terms of the GNU General Public License as published by | |
11 | the Free Software Foundation; either version 3, or (at your option) | |
12 | any later version. | |
13 | ||
14 | GNU Modula-2 is distributed in the hope that it will be useful, but | |
15 | WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
17 | General Public License for more details. | |
18 | ||
19 | Under Section 7 of GPL version 3, you are granted additional | |
20 | permissions described in the GCC Runtime Library Exception, version | |
21 | 3.1, as published by the Free Software Foundation. | |
22 | ||
23 | You should have received a copy of the GNU General Public License and | |
24 | a copy of the GCC Runtime Library Exception along with this program; | |
25 | see the files COPYING3 and COPYING.RUNTIME respectively. If not, see | |
26 | <http://www.gnu.org/licenses/>. */ | |
27 | ||
28 | # if !defined (PROC_D) | |
29 | # define PROC_D | |
30 | typedef void (*PROC_t) (void); | |
31 | typedef struct { PROC_t proc; } PROC; | |
32 | # endif | |
33 | ||
34 | # if !defined (TRUE) | |
35 | # define TRUE (1==1) | |
36 | # endif | |
37 | ||
38 | # if !defined (FALSE) | |
39 | # define FALSE (1==0) | |
40 | # endif | |
41 | ||
42 | #include <stddef.h> | |
43 | #include <string.h> | |
44 | #include <limits.h> | |
45 | #include <stdlib.h> | |
46 | # include "GStorage.h" | |
47 | # include "Gmcrts.h" | |
48 | #include <unistd.h> | |
49 | #if defined(__cplusplus) | |
50 | # undef NULL | |
51 | # define NULL 0 | |
52 | #endif | |
53 | #define _FIO_H | |
54 | #define _FIO_C | |
55 | ||
56 | # include "GSYSTEM.h" | |
57 | # include "GASCII.h" | |
58 | # include "GStrLib.h" | |
59 | # include "GStorage.h" | |
60 | # include "GNumberIO.h" | |
61 | # include "Glibc.h" | |
62 | # include "GIndexing.h" | |
63 | # include "GM2RTS.h" | |
64 | ||
65 | typedef unsigned int FIO_File; | |
66 | ||
67 | FIO_File FIO_StdErr; | |
68 | FIO_File FIO_StdOut; | |
69 | FIO_File FIO_StdIn; | |
70 | # define SEEK_SET 0 | |
71 | # define SEEK_END 2 | |
72 | # define UNIXREADONLY 0 | |
73 | # define UNIXWRITEONLY 1 | |
74 | # define CreatePermissions 0666 | |
75 | # define MaxBufferLength (1024*16) | |
76 | # define MaxErrorString (1024*8) | |
77 | typedef struct FIO_NameInfo_r FIO_NameInfo; | |
78 | ||
79 | typedef struct FIO_buf_r FIO_buf; | |
80 | ||
81 | typedef FIO_buf *FIO_Buffer; | |
82 | ||
83 | typedef struct FIO_fds_r FIO_fds; | |
84 | ||
85 | typedef FIO_fds *FIO_FileDescriptor; | |
86 | ||
87 | typedef struct FIO__T7_a FIO__T7; | |
88 | ||
89 | typedef char *FIO_PtrToChar; | |
90 | ||
91 | typedef enum {FIO_successful, FIO_outofmemory, FIO_toomanyfilesopen, FIO_failed, FIO_connectionfailure, FIO_endofline, FIO_endoffile} FIO_FileStatus; | |
92 | ||
93 | typedef enum {FIO_unused, FIO_openedforread, FIO_openedforwrite, FIO_openedforrandom} FIO_FileUsage; | |
94 | ||
95 | struct FIO_NameInfo_r { | |
96 | void *address; | |
97 | unsigned int size; | |
98 | }; | |
99 | ||
100 | struct FIO_buf_r { | |
101 | unsigned int valid; | |
102 | long int bufstart; | |
103 | unsigned int position; | |
104 | void *address; | |
105 | unsigned int filled; | |
106 | unsigned int size; | |
107 | unsigned int left; | |
108 | FIO__T7 *contents; | |
109 | }; | |
110 | ||
111 | struct FIO__T7_a { char array[MaxBufferLength+1]; }; | |
112 | struct FIO_fds_r { | |
113 | int unixfd; | |
114 | FIO_NameInfo name; | |
115 | FIO_FileStatus state; | |
116 | FIO_FileUsage usage; | |
117 | unsigned int output; | |
118 | FIO_Buffer buffer; | |
119 | long int abspos; | |
120 | }; | |
121 | ||
122 | static Indexing_Index FileInfo; | |
123 | static FIO_File Error; | |
124 | ||
125 | /* | |
126 | IsNoError - returns a TRUE if no error has occured on file, f. | |
127 | */ | |
128 | ||
129 | extern "C" unsigned int FIO_IsNoError (FIO_File f); | |
130 | ||
131 | /* | |
132 | IsActive - returns TRUE if the file, f, is still active. | |
133 | */ | |
134 | ||
135 | extern "C" unsigned int FIO_IsActive (FIO_File f); | |
136 | extern "C" unsigned int FIO_Exists (const char *fname_, unsigned int _fname_high); | |
137 | extern "C" FIO_File FIO_OpenToRead (const char *fname_, unsigned int _fname_high); | |
138 | extern "C" FIO_File FIO_OpenToWrite (const char *fname_, unsigned int _fname_high); | |
139 | extern "C" FIO_File FIO_OpenForRandom (const char *fname_, unsigned int _fname_high, unsigned int towrite, unsigned int newfile); | |
140 | ||
141 | /* | |
142 | Close - close a file which has been previously opened using: | |
143 | OpenToRead, OpenToWrite, OpenForRandom. | |
144 | It is correct to close a file which has an error status. | |
145 | */ | |
146 | ||
147 | extern "C" void FIO_Close (FIO_File f); | |
148 | ||
149 | /* | |
150 | exists - returns TRUE if a file named, fname exists for reading. | |
151 | */ | |
152 | ||
153 | extern "C" unsigned int FIO_exists (void * fname, unsigned int flength); | |
154 | ||
155 | /* | |
156 | openToRead - attempts to open a file, fname, for reading and | |
157 | it returns this file. | |
158 | The success of this operation can be checked by | |
159 | calling IsNoError. | |
160 | */ | |
161 | ||
162 | extern "C" FIO_File FIO_openToRead (void * fname, unsigned int flength); | |
163 | ||
164 | /* | |
165 | openToWrite - attempts to open a file, fname, for write and | |
166 | it returns this file. | |
167 | The success of this operation can be checked by | |
168 | calling IsNoError. | |
169 | */ | |
170 | ||
171 | extern "C" FIO_File FIO_openToWrite (void * fname, unsigned int flength); | |
172 | ||
173 | /* | |
174 | openForRandom - attempts to open a file, fname, for random access | |
175 | read or write and it returns this file. | |
176 | The success of this operation can be checked by | |
177 | calling IsNoError. | |
178 | towrite, determines whether the file should be | |
179 | opened for writing or reading. | |
180 | */ | |
181 | ||
182 | extern "C" FIO_File FIO_openForRandom (void * fname, unsigned int flength, unsigned int towrite, unsigned int newfile); | |
183 | ||
184 | /* | |
185 | FlushBuffer - flush contents of file, f. | |
186 | */ | |
187 | ||
188 | extern "C" void FIO_FlushBuffer (FIO_File f); | |
189 | ||
190 | /* | |
191 | ReadNBytes - reads nBytes of a file into memory area, dest, returning | |
192 | the number of bytes actually read. | |
193 | This function will consume from the buffer and then | |
194 | perform direct libc reads. It is ideal for large reads. | |
195 | */ | |
196 | ||
197 | extern "C" unsigned int FIO_ReadNBytes (FIO_File f, unsigned int nBytes, void * dest); | |
198 | ||
199 | /* | |
200 | ReadAny - reads HIGH(a) bytes into, a. All input | |
201 | is fully buffered, unlike ReadNBytes and thus is more | |
202 | suited to small reads. | |
203 | */ | |
204 | ||
205 | extern "C" void FIO_ReadAny (FIO_File f, unsigned char *a, unsigned int _a_high); | |
206 | ||
207 | /* | |
208 | WriteNBytes - writes nBytes from memory area src to a file | |
209 | returning the number of bytes actually written. | |
210 | This function will flush the buffer and then | |
211 | write the nBytes using a direct write from libc. | |
212 | It is ideal for large writes. | |
213 | */ | |
214 | ||
215 | extern "C" unsigned int FIO_WriteNBytes (FIO_File f, unsigned int nBytes, void * src); | |
216 | ||
217 | /* | |
218 | WriteAny - writes HIGH(a) bytes onto, file, f. All output | |
219 | is fully buffered, unlike WriteNBytes and thus is more | |
220 | suited to small writes. | |
221 | */ | |
222 | ||
223 | extern "C" void FIO_WriteAny (FIO_File f, unsigned char *a, unsigned int _a_high); | |
224 | ||
225 | /* | |
226 | WriteChar - writes a single character to file, f. | |
227 | */ | |
228 | ||
229 | extern "C" void FIO_WriteChar (FIO_File f, char ch); | |
230 | ||
231 | /* | |
232 | EOF - tests to see whether a file, f, has reached end of file. | |
233 | */ | |
234 | ||
235 | extern "C" unsigned int FIO_EOF (FIO_File f); | |
236 | ||
237 | /* | |
238 | EOLN - tests to see whether a file, f, is upon a newline. | |
239 | It does NOT consume the newline. | |
240 | */ | |
241 | ||
242 | extern "C" unsigned int FIO_EOLN (FIO_File f); | |
243 | ||
244 | /* | |
245 | WasEOLN - tests to see whether a file, f, has just seen a newline. | |
246 | */ | |
247 | ||
248 | extern "C" unsigned int FIO_WasEOLN (FIO_File f); | |
249 | ||
250 | /* | |
251 | ReadChar - returns a character read from file f. | |
252 | Sensible to check with IsNoError or EOF after calling | |
253 | this function. | |
254 | */ | |
255 | ||
256 | extern "C" char FIO_ReadChar (FIO_File f); | |
257 | ||
258 | /* | |
259 | UnReadChar - replaces a character, ch, back into file f. | |
260 | This character must have been read by ReadChar | |
261 | and it does not allow successive calls. It may | |
262 | only be called if the previous read was successful | |
263 | or end of file was seen. | |
264 | If the state was previously endoffile then it | |
265 | is altered to successful. | |
266 | Otherwise it is left alone. | |
267 | */ | |
268 | ||
269 | extern "C" void FIO_UnReadChar (FIO_File f, char ch); | |
270 | ||
271 | /* | |
272 | WriteLine - writes out a linefeed to file, f. | |
273 | */ | |
274 | ||
275 | extern "C" void FIO_WriteLine (FIO_File f); | |
276 | ||
277 | /* | |
278 | WriteString - writes a string to file, f. | |
279 | */ | |
280 | ||
281 | extern "C" void FIO_WriteString (FIO_File f, const char *a_, unsigned int _a_high); | |
282 | ||
283 | /* | |
284 | ReadString - reads a string from file, f, into string, a. | |
285 | It terminates the string if HIGH is reached or | |
286 | if a newline is seen or an error occurs. | |
287 | */ | |
288 | ||
289 | extern "C" void FIO_ReadString (FIO_File f, char *a, unsigned int _a_high); | |
290 | ||
291 | /* | |
292 | WriteCardinal - writes a CARDINAL to file, f. | |
293 | It writes the binary image of the cardinal | |
294 | to file, f. | |
295 | */ | |
296 | ||
297 | extern "C" void FIO_WriteCardinal (FIO_File f, unsigned int c); | |
298 | ||
299 | /* | |
300 | ReadCardinal - reads a CARDINAL from file, f. | |
301 | It reads a binary image of a CARDINAL | |
302 | from a file, f. | |
303 | */ | |
304 | ||
305 | extern "C" unsigned int FIO_ReadCardinal (FIO_File f); | |
306 | ||
307 | /* | |
308 | GetUnixFileDescriptor - returns the UNIX file descriptor of a file. | |
309 | */ | |
310 | ||
311 | extern "C" int FIO_GetUnixFileDescriptor (FIO_File f); | |
312 | ||
313 | /* | |
314 | SetPositionFromBeginning - sets the position from the beginning of the file. | |
315 | */ | |
316 | ||
317 | extern "C" void FIO_SetPositionFromBeginning (FIO_File f, long int pos); | |
318 | ||
319 | /* | |
320 | SetPositionFromEnd - sets the position from the end of the file. | |
321 | */ | |
322 | ||
323 | extern "C" void FIO_SetPositionFromEnd (FIO_File f, long int pos); | |
324 | ||
325 | /* | |
326 | FindPosition - returns the current absolute position in file, f. | |
327 | */ | |
328 | ||
329 | extern "C" long int FIO_FindPosition (FIO_File f); | |
330 | ||
331 | /* | |
332 | GetFileName - assigns, a, with the filename associated with, f. | |
333 | */ | |
334 | ||
335 | extern "C" void FIO_GetFileName (FIO_File f, char *a, unsigned int _a_high); | |
336 | ||
337 | /* | |
338 | getFileName - returns the address of the filename associated with, f. | |
339 | */ | |
340 | ||
341 | extern "C" void * FIO_getFileName (FIO_File f); | |
342 | ||
343 | /* | |
344 | getFileNameLength - returns the number of characters associated with filename, f. | |
345 | */ | |
346 | ||
347 | extern "C" unsigned int FIO_getFileNameLength (FIO_File f); | |
348 | ||
349 | /* | |
350 | FlushOutErr - flushes, StdOut, and, StdErr. | |
351 | It is also called when the application calls M2RTS.Terminate. | |
352 | (which is automatically placed in program modules by the GM2 | |
353 | scaffold). | |
354 | */ | |
355 | ||
356 | extern "C" void FIO_FlushOutErr (void); | |
357 | ||
358 | /* | |
359 | Max - returns the maximum of two values. | |
360 | */ | |
361 | ||
362 | static unsigned int Max (unsigned int a, unsigned int b); | |
363 | ||
364 | /* | |
365 | Min - returns the minimum of two values. | |
366 | */ | |
367 | ||
368 | static unsigned int Min (unsigned int a, unsigned int b); | |
369 | ||
370 | /* | |
371 | GetNextFreeDescriptor - returns the index to the FileInfo array indicating | |
372 | the next free slot. | |
373 | */ | |
374 | ||
375 | static FIO_File GetNextFreeDescriptor (void); | |
376 | ||
377 | /* | |
378 | SetState - sets the field, state, of file, f, to, s. | |
379 | */ | |
380 | ||
381 | static void SetState (FIO_File f, FIO_FileStatus s); | |
382 | ||
383 | /* | |
384 | InitializeFile - initialize a file descriptor | |
385 | */ | |
386 | ||
387 | static FIO_File InitializeFile (FIO_File f, void * fname, unsigned int flength, FIO_FileStatus fstate, FIO_FileUsage use, unsigned int towrite, unsigned int buflength); | |
388 | ||
389 | /* | |
390 | ConnectToUnix - connects a FIO file to a UNIX file descriptor. | |
391 | */ | |
392 | ||
393 | static void ConnectToUnix (FIO_File f, unsigned int towrite, unsigned int newfile); | |
394 | ||
395 | /* | |
396 | ReadFromBuffer - attempts to read, nBytes, from file, f. | |
397 | It firstly consumes the buffer and then performs | |
398 | direct unbuffered reads. This should only be used | |
399 | when wishing to read large files. | |
400 | ||
401 | The actual number of bytes read is returned. | |
402 | -1 is returned if EOF is reached. | |
403 | */ | |
404 | ||
405 | static int ReadFromBuffer (FIO_File f, void * a, unsigned int nBytes); | |
406 | ||
407 | /* | |
408 | BufferedRead - will read, nBytes, through the buffer. | |
409 | Similar to ReadFromBuffer, but this function will always | |
410 | read into the buffer before copying into memory. | |
411 | ||
412 | Useful when performing small reads. | |
413 | */ | |
414 | ||
415 | static int BufferedRead (FIO_File f, unsigned int nBytes, void * a); | |
416 | ||
417 | /* | |
418 | HandleEscape - translates | |
419 | and \t into their respective ascii codes. | |
420 | */ | |
421 | ||
422 | static void HandleEscape (char *dest, unsigned int _dest_high, const char *src_, unsigned int _src_high, unsigned int *i, unsigned int *j, unsigned int HighSrc, unsigned int HighDest); | |
423 | ||
424 | /* | |
425 | Cast - casts a := b | |
426 | */ | |
427 | ||
428 | static void Cast (unsigned char *a, unsigned int _a_high, const unsigned char *b_, unsigned int _b_high); | |
429 | ||
430 | /* | |
431 | StringFormat1 - converts string, src, into, dest, together with encapsulated | |
432 | entity, w. It only formats the first %s or %d with n. | |
433 | */ | |
434 | ||
435 | static void StringFormat1 (char *dest, unsigned int _dest_high, const char *src_, unsigned int _src_high, const unsigned char *w_, unsigned int _w_high); | |
436 | ||
437 | /* | |
438 | FormatError - provides a orthoganal counterpart to the procedure below. | |
439 | */ | |
440 | ||
441 | static void FormatError (const char *a_, unsigned int _a_high); | |
442 | ||
443 | /* | |
444 | FormatError1 - generic error procedure taking standard format string | |
445 | and single parameter. | |
446 | */ | |
447 | ||
448 | static void FormatError1 (const char *a_, unsigned int _a_high, const unsigned char *w_, unsigned int _w_high); | |
449 | ||
450 | /* | |
451 | FormatError2 - generic error procedure taking standard format string | |
452 | and two parameters. | |
453 | */ | |
454 | ||
455 | static void FormatError2 (const char *a_, unsigned int _a_high, const unsigned char *w1_, unsigned int _w1_high, const unsigned char *w2_, unsigned int _w2_high); | |
456 | ||
457 | /* | |
458 | CheckAccess - checks to see whether a file f has been | |
459 | opened for read/write. | |
460 | */ | |
461 | ||
462 | static void CheckAccess (FIO_File f, FIO_FileUsage use, unsigned int towrite); | |
463 | ||
464 | /* | |
465 | SetEndOfLine - | |
466 | */ | |
467 | ||
468 | static void SetEndOfLine (FIO_File f, char ch); | |
469 | ||
470 | /* | |
471 | BufferedWrite - will write, nBytes, through the buffer. | |
472 | Similar to WriteNBytes, but this function will always | |
473 | write into the buffer before copying into memory. | |
474 | ||
475 | Useful when performing small writes. | |
476 | */ | |
477 | ||
478 | static int BufferedWrite (FIO_File f, unsigned int nBytes, void * a); | |
479 | ||
480 | /* | |
481 | PreInitialize - preinitialize the file descriptor. | |
482 | */ | |
483 | ||
484 | static void PreInitialize (FIO_File f, const char *fname_, unsigned int _fname_high, FIO_FileStatus state, FIO_FileUsage use, unsigned int towrite, int osfd, unsigned int bufsize); | |
485 | ||
486 | /* | |
487 | Init - initialize the modules, global variables. | |
488 | */ | |
489 | ||
490 | static void Init (void); | |
491 | ||
492 | ||
493 | /* | |
494 | Max - returns the maximum of two values. | |
495 | */ | |
496 | ||
497 | static unsigned int Max (unsigned int a, unsigned int b) | |
498 | { | |
499 | if (a > b) | |
500 | { | |
501 | return a; | |
502 | } | |
503 | else | |
504 | { | |
505 | return b; | |
506 | } | |
507 | /* static analysis guarentees a RETURN statement will be used before here. */ | |
508 | __builtin_unreachable (); | |
509 | } | |
510 | ||
511 | ||
512 | /* | |
513 | Min - returns the minimum of two values. | |
514 | */ | |
515 | ||
516 | static unsigned int Min (unsigned int a, unsigned int b) | |
517 | { | |
518 | if (a < b) | |
519 | { | |
520 | return a; | |
521 | } | |
522 | else | |
523 | { | |
524 | return b; | |
525 | } | |
526 | /* static analysis guarentees a RETURN statement will be used before here. */ | |
527 | __builtin_unreachable (); | |
528 | } | |
529 | ||
530 | ||
531 | /* | |
532 | GetNextFreeDescriptor - returns the index to the FileInfo array indicating | |
533 | the next free slot. | |
534 | */ | |
535 | ||
536 | static FIO_File GetNextFreeDescriptor (void) | |
537 | { | |
538 | FIO_File f; | |
539 | FIO_File h; | |
540 | FIO_FileDescriptor fd; | |
541 | ||
542 | f = Error+1; | |
543 | h = Indexing_HighIndice (FileInfo); | |
544 | for (;;) | |
545 | { | |
546 | if (f <= h) | |
547 | { | |
548 | fd = static_cast<FIO_FileDescriptor> (Indexing_GetIndice (FileInfo, f)); | |
549 | if (fd == NULL) | |
550 | { | |
551 | return f; | |
552 | } | |
553 | } | |
554 | f += 1; | |
555 | if (f > h) | |
556 | { | |
557 | Indexing_PutIndice (FileInfo, f, NULL); /* create new slot */ | |
558 | return f; /* create new slot */ | |
559 | } | |
560 | } | |
561 | ReturnException ("../../gcc-git-devel-modula2/gcc/m2/gm2-libs/FIO.def", 25, 1); | |
562 | __builtin_unreachable (); | |
563 | } | |
564 | ||
565 | ||
566 | /* | |
567 | SetState - sets the field, state, of file, f, to, s. | |
568 | */ | |
569 | ||
570 | static void SetState (FIO_File f, FIO_FileStatus s) | |
571 | { | |
572 | FIO_FileDescriptor fd; | |
573 | ||
574 | fd = static_cast<FIO_FileDescriptor> (Indexing_GetIndice (FileInfo, f)); | |
575 | fd->state = s; | |
576 | } | |
577 | ||
578 | ||
579 | /* | |
580 | InitializeFile - initialize a file descriptor | |
581 | */ | |
582 | ||
583 | static FIO_File InitializeFile (FIO_File f, void * fname, unsigned int flength, FIO_FileStatus fstate, FIO_FileUsage use, unsigned int towrite, unsigned int buflength) | |
584 | { | |
585 | FIO_PtrToChar p; | |
586 | FIO_FileDescriptor fd; | |
587 | ||
588 | Storage_ALLOCATE ((void **) &fd, sizeof (FIO_fds)); | |
589 | if (fd == NULL) | |
590 | { | |
591 | SetState (Error, FIO_outofmemory); | |
592 | return Error; | |
593 | } | |
594 | else | |
595 | { | |
596 | Indexing_PutIndice (FileInfo, f, reinterpret_cast<void *> (fd)); | |
597 | fd->name.size = flength+1; /* need to guarantee the nul for C */ | |
598 | fd->usage = use; /* need to guarantee the nul for C */ | |
599 | fd->output = towrite; | |
600 | Storage_ALLOCATE (&fd->name.address, fd->name.size); | |
601 | if (fd->name.address == NULL) | |
602 | { | |
603 | fd->state = FIO_outofmemory; | |
604 | return f; | |
605 | } | |
606 | fd->name.address = libc_strncpy (fd->name.address, fname, flength); | |
607 | /* and assign nul to the last byte */ | |
608 | p = static_cast<FIO_PtrToChar> (fd->name.address); | |
609 | p += flength; | |
610 | (*p) = ASCII_nul; | |
611 | fd->abspos = 0; | |
612 | /* now for the buffer */ | |
613 | Storage_ALLOCATE ((void **) &fd->buffer, sizeof (FIO_buf)); | |
614 | if (fd->buffer == NULL) | |
615 | { | |
616 | SetState (Error, FIO_outofmemory); | |
617 | return Error; | |
618 | } | |
619 | else | |
620 | { | |
621 | fd->buffer->valid = FALSE; | |
622 | fd->buffer->bufstart = 0; | |
623 | fd->buffer->size = buflength; | |
624 | fd->buffer->position = 0; | |
625 | fd->buffer->filled = 0; | |
626 | if (fd->buffer->size == 0) | |
627 | { | |
628 | fd->buffer->address = NULL; | |
629 | } | |
630 | else | |
631 | { | |
632 | Storage_ALLOCATE (&fd->buffer->address, fd->buffer->size); | |
633 | if (fd->buffer->address == NULL) | |
634 | { | |
635 | fd->state = FIO_outofmemory; | |
636 | return f; | |
637 | } | |
638 | } | |
639 | if (towrite) | |
640 | { | |
641 | fd->buffer->left = fd->buffer->size; | |
642 | } | |
643 | else | |
644 | { | |
645 | fd->buffer->left = 0; | |
646 | } | |
647 | fd->buffer->contents = reinterpret_cast<FIO__T7 *> (fd->buffer->address); /* provides easy access for reading characters */ | |
648 | fd->state = fstate; /* provides easy access for reading characters */ | |
649 | } | |
650 | } | |
651 | return f; | |
652 | /* static analysis guarentees a RETURN statement will be used before here. */ | |
653 | __builtin_unreachable (); | |
654 | } | |
655 | ||
656 | ||
657 | /* | |
658 | ConnectToUnix - connects a FIO file to a UNIX file descriptor. | |
659 | */ | |
660 | ||
661 | static void ConnectToUnix (FIO_File f, unsigned int towrite, unsigned int newfile) | |
662 | { | |
663 | FIO_FileDescriptor fd; | |
664 | ||
665 | if (f != Error) | |
666 | { | |
667 | fd = static_cast<FIO_FileDescriptor> (Indexing_GetIndice (FileInfo, f)); | |
668 | if (fd != NULL) | |
669 | { | |
670 | if (towrite) | |
671 | { | |
672 | if (newfile) | |
673 | { | |
674 | fd->unixfd = libc_creat (fd->name.address, CreatePermissions); | |
675 | } | |
676 | else | |
677 | { | |
678 | fd->unixfd = libc_open (fd->name.address, UNIXWRITEONLY, 0); | |
679 | } | |
680 | } | |
681 | else | |
682 | { | |
683 | fd->unixfd = libc_open (fd->name.address, UNIXREADONLY, 0); | |
684 | } | |
685 | if (fd->unixfd < 0) | |
686 | { | |
687 | fd->state = FIO_connectionfailure; | |
688 | } | |
689 | } | |
690 | } | |
691 | } | |
692 | ||
693 | ||
694 | /* | |
695 | ReadFromBuffer - attempts to read, nBytes, from file, f. | |
696 | It firstly consumes the buffer and then performs | |
697 | direct unbuffered reads. This should only be used | |
698 | when wishing to read large files. | |
699 | ||
700 | The actual number of bytes read is returned. | |
701 | -1 is returned if EOF is reached. | |
702 | */ | |
703 | ||
704 | static int ReadFromBuffer (FIO_File f, void * a, unsigned int nBytes) | |
705 | { | |
706 | typedef unsigned char *ReadFromBuffer__T1; | |
707 | ||
708 | void * t; | |
709 | int result; | |
710 | unsigned int total; | |
711 | unsigned int n; | |
712 | ReadFromBuffer__T1 p; | |
713 | FIO_FileDescriptor fd; | |
714 | ||
715 | if (f != Error) | |
716 | { | |
717 | total = 0; /* how many bytes have we read */ | |
718 | fd = static_cast<FIO_FileDescriptor> (Indexing_GetIndice (FileInfo, f)); /* how many bytes have we read */ | |
719 | /* extract from the buffer first */ | |
720 | if ((fd->buffer != NULL) && fd->buffer->valid) | |
721 | { | |
722 | if (fd->buffer->left > 0) | |
723 | { | |
724 | /* avoid gcc warning by using compound statement even if not strictly necessary. */ | |
725 | if (nBytes == 1) | |
726 | { | |
727 | /* too expensive to call memcpy for 1 character */ | |
728 | p = static_cast<ReadFromBuffer__T1> (a); | |
729 | (*p) = static_cast<unsigned char> ((*fd->buffer->contents).array[fd->buffer->position]); | |
730 | fd->buffer->left -= 1; /* remove consumed bytes */ | |
731 | fd->buffer->position += 1; /* move onwards n bytes */ | |
732 | nBytes = 0; /* reduce the amount for future direct */ | |
733 | /* read */ | |
734 | return 1; | |
735 | } | |
736 | else | |
737 | { | |
738 | n = Min (fd->buffer->left, nBytes); | |
739 | t = fd->buffer->address; | |
740 | t = reinterpret_cast<void *> (reinterpret_cast<char *> (t)+fd->buffer->position); | |
741 | p = static_cast<ReadFromBuffer__T1> (libc_memcpy (a, t, static_cast<size_t> (n))); | |
742 | fd->buffer->left -= n; /* remove consumed bytes */ | |
743 | fd->buffer->position += n; /* move onwards n bytes */ | |
744 | /* move onwards ready for direct reads */ | |
745 | a = reinterpret_cast<void *> (reinterpret_cast<char *> (a)+n); | |
746 | nBytes -= n; /* reduce the amount for future direct */ | |
747 | /* read */ | |
748 | total += n; | |
749 | return total; /* much cleaner to return now, */ | |
750 | } | |
751 | /* difficult to record an error if */ | |
752 | } | |
753 | /* the read below returns -1 */ | |
754 | } | |
755 | if (nBytes > 0) | |
756 | { | |
757 | /* still more to read */ | |
758 | result = static_cast<int> (libc_read (fd->unixfd, a, static_cast<size_t> ((int ) (nBytes)))); | |
759 | if (result > 0) | |
760 | { | |
761 | /* avoid dangling else. */ | |
762 | total += result; | |
763 | fd->abspos += result; | |
764 | /* now disable the buffer as we read directly into, a. */ | |
765 | if (fd->buffer != NULL) | |
766 | { | |
767 | fd->buffer->valid = FALSE; | |
768 | } | |
769 | } | |
770 | else | |
771 | { | |
772 | if (result == 0) | |
773 | { | |
774 | /* eof reached */ | |
775 | fd->state = FIO_endoffile; | |
776 | } | |
777 | else | |
778 | { | |
779 | fd->state = FIO_failed; | |
780 | } | |
781 | /* indicate buffer is empty */ | |
782 | if (fd->buffer != NULL) | |
783 | { | |
784 | fd->buffer->valid = FALSE; | |
785 | fd->buffer->left = 0; | |
786 | fd->buffer->position = 0; | |
787 | if (fd->buffer->address != NULL) | |
788 | { | |
789 | (*fd->buffer->contents).array[fd->buffer->position] = ASCII_nul; | |
790 | } | |
791 | } | |
792 | return -1; | |
793 | } | |
794 | } | |
795 | return total; | |
796 | } | |
797 | else | |
798 | { | |
799 | return -1; | |
800 | } | |
801 | /* static analysis guarentees a RETURN statement will be used before here. */ | |
802 | __builtin_unreachable (); | |
803 | } | |
804 | ||
805 | ||
806 | /* | |
807 | BufferedRead - will read, nBytes, through the buffer. | |
808 | Similar to ReadFromBuffer, but this function will always | |
809 | read into the buffer before copying into memory. | |
810 | ||
811 | Useful when performing small reads. | |
812 | */ | |
813 | ||
814 | static int BufferedRead (FIO_File f, unsigned int nBytes, void * a) | |
815 | { | |
816 | typedef unsigned char *BufferedRead__T3; | |
817 | ||
818 | void * t; | |
819 | int result; | |
820 | int total; | |
821 | int n; | |
822 | BufferedRead__T3 p; | |
823 | FIO_FileDescriptor fd; | |
824 | ||
825 | if (f != Error) | |
826 | { | |
827 | /* avoid dangling else. */ | |
828 | fd = static_cast<FIO_FileDescriptor> (Indexing_GetIndice (FileInfo, f)); | |
829 | total = 0; /* how many bytes have we read */ | |
830 | if (fd != NULL) /* how many bytes have we read */ | |
831 | { | |
832 | /* extract from the buffer first */ | |
833 | if (fd->buffer != NULL) | |
834 | { | |
835 | while (nBytes > 0) | |
836 | { | |
837 | if ((fd->buffer->left > 0) && fd->buffer->valid) | |
838 | { | |
839 | if (nBytes == 1) | |
840 | { | |
841 | /* too expensive to call memcpy for 1 character */ | |
842 | p = static_cast<BufferedRead__T3> (a); | |
843 | (*p) = static_cast<unsigned char> ((*fd->buffer->contents).array[fd->buffer->position]); | |
844 | fd->buffer->left -= 1; /* remove consumed byte */ | |
845 | fd->buffer->position += 1; /* move onwards n byte */ | |
846 | total += 1; /* move onwards n byte */ | |
847 | return total; | |
848 | } | |
849 | else | |
850 | { | |
851 | n = Min (fd->buffer->left, nBytes); | |
852 | t = fd->buffer->address; | |
853 | t = reinterpret_cast<void *> (reinterpret_cast<char *> (t)+fd->buffer->position); | |
854 | p = static_cast<BufferedRead__T3> (libc_memcpy (a, t, static_cast<size_t> (n))); | |
855 | fd->buffer->left -= n; /* remove consumed bytes */ | |
856 | fd->buffer->position += n; /* move onwards n bytes */ | |
857 | /* move onwards ready for direct reads */ | |
858 | a = reinterpret_cast<void *> (reinterpret_cast<char *> (a)+n); | |
859 | nBytes -= n; /* reduce the amount for future direct */ | |
860 | /* read */ | |
861 | total += n; | |
862 | } | |
863 | } | |
864 | else | |
865 | { | |
866 | /* refill buffer */ | |
867 | n = static_cast<int> (libc_read (fd->unixfd, fd->buffer->address, static_cast<size_t> (fd->buffer->size))); | |
868 | if (n >= 0) | |
869 | { | |
870 | /* avoid dangling else. */ | |
871 | fd->buffer->valid = TRUE; | |
872 | fd->buffer->position = 0; | |
873 | fd->buffer->left = n; | |
874 | fd->buffer->filled = n; | |
875 | fd->buffer->bufstart = fd->abspos; | |
876 | fd->abspos += n; | |
877 | if (n == 0) | |
878 | { | |
879 | /* eof reached */ | |
880 | fd->state = FIO_endoffile; | |
881 | return -1; | |
882 | } | |
883 | } | |
884 | else | |
885 | { | |
886 | fd->buffer->valid = FALSE; | |
887 | fd->buffer->position = 0; | |
888 | fd->buffer->left = 0; | |
889 | fd->buffer->filled = 0; | |
890 | fd->state = FIO_failed; | |
891 | return total; | |
892 | } | |
893 | } | |
894 | } | |
895 | return total; | |
896 | } | |
897 | else | |
898 | { | |
899 | return -1; | |
900 | } | |
901 | } | |
902 | } | |
903 | else | |
904 | { | |
905 | return -1; | |
906 | } | |
907 | /* static analysis guarentees a RETURN statement will be used before here. */ | |
908 | __builtin_unreachable (); | |
909 | } | |
910 | ||
911 | ||
912 | /* | |
913 | HandleEscape - translates | |
914 | and \t into their respective ascii codes. | |
915 | */ | |
916 | ||
917 | static void HandleEscape (char *dest, unsigned int _dest_high, const char *src_, unsigned int _src_high, unsigned int *i, unsigned int *j, unsigned int HighSrc, unsigned int HighDest) | |
918 | { | |
919 | char src[_src_high+1]; | |
920 | ||
921 | /* make a local copy of each unbounded array. */ | |
922 | memcpy (src, src_, _src_high+1); | |
923 | ||
924 | if (((((*i)+1) < HighSrc) && (src[(*i)] == '\\')) && ((*j) < HighDest)) | |
925 | { | |
926 | /* avoid gcc warning by using compound statement even if not strictly necessary. */ | |
927 | if (src[(*i)+1] == 'n') | |
928 | { | |
929 | /* requires a newline */ | |
930 | dest[(*j)] = ASCII_nl; | |
931 | (*j) += 1; | |
932 | (*i) += 2; | |
933 | } | |
934 | else if (src[(*i)+1] == 't') | |
935 | { | |
936 | /* avoid dangling else. */ | |
937 | /* requires a tab (yuck) tempted to fake this but I better not.. */ | |
938 | dest[(*j)] = ASCII_tab; | |
939 | (*j) += 1; | |
940 | (*i) += 2; | |
941 | } | |
942 | else | |
943 | { | |
944 | /* avoid dangling else. */ | |
945 | /* copy escaped character */ | |
946 | (*i) += 1; | |
947 | dest[(*j)] = src[(*i)]; | |
948 | (*j) += 1; | |
949 | (*i) += 1; | |
950 | } | |
951 | } | |
952 | } | |
953 | ||
954 | ||
955 | /* | |
956 | Cast - casts a := b | |
957 | */ | |
958 | ||
959 | static void Cast (unsigned char *a, unsigned int _a_high, const unsigned char *b_, unsigned int _b_high) | |
960 | { | |
961 | unsigned int i; | |
962 | unsigned char b[_b_high+1]; | |
963 | ||
964 | /* make a local copy of each unbounded array. */ | |
965 | memcpy (b, b_, _b_high+1); | |
966 | ||
967 | if (_a_high == _b_high) | |
968 | { | |
969 | for (i=0; i<=_a_high; i++) | |
970 | { | |
971 | a[i] = b[i]; | |
972 | } | |
973 | } | |
974 | else | |
975 | { | |
976 | FormatError ((const char *) "cast failed", 11); | |
977 | } | |
978 | } | |
979 | ||
980 | ||
981 | /* | |
982 | StringFormat1 - converts string, src, into, dest, together with encapsulated | |
983 | entity, w. It only formats the first %s or %d with n. | |
984 | */ | |
985 | ||
986 | static void StringFormat1 (char *dest, unsigned int _dest_high, const char *src_, unsigned int _src_high, const unsigned char *w_, unsigned int _w_high) | |
987 | { | |
988 | typedef struct StringFormat1__T8_a StringFormat1__T8; | |
989 | ||
990 | typedef char *StringFormat1__T4; | |
991 | ||
992 | struct StringFormat1__T8_a { char array[MaxErrorString+1]; }; | |
993 | unsigned int HighSrc; | |
994 | unsigned int HighDest; | |
995 | unsigned int c; | |
996 | unsigned int i; | |
997 | unsigned int j; | |
998 | StringFormat1__T8 str; | |
999 | StringFormat1__T4 p; | |
1000 | char src[_src_high+1]; | |
1001 | unsigned char w[_w_high+1]; | |
1002 | ||
1003 | /* make a local copy of each unbounded array. */ | |
1004 | memcpy (src, src_, _src_high+1); | |
1005 | memcpy (w, w_, _w_high+1); | |
1006 | ||
1007 | HighSrc = StrLib_StrLen ((const char *) src, _src_high); | |
1008 | HighDest = _dest_high; | |
1009 | p = NULL; | |
1010 | c = 0; | |
1011 | i = 0; | |
1012 | j = 0; | |
1013 | while ((((i < HighSrc) && (src[i] != ASCII_nul)) && (j < HighDest)) && (src[i] != '%')) | |
1014 | { | |
1015 | if (src[i] == '\\') | |
1016 | { | |
1017 | HandleEscape ((char *) dest, _dest_high, (const char *) src, _src_high, &i, &j, HighSrc, HighDest); | |
1018 | } | |
1019 | else | |
1020 | { | |
1021 | dest[j] = src[i]; | |
1022 | i += 1; | |
1023 | j += 1; | |
1024 | } | |
1025 | } | |
1026 | if ((((i+1) < HighSrc) && (src[i] == '%')) && (j < HighDest)) | |
1027 | { | |
1028 | /* avoid gcc warning by using compound statement even if not strictly necessary. */ | |
1029 | if (src[i+1] == 's') | |
1030 | { | |
1031 | Cast ((unsigned char *) &p, (sizeof (p)-1), (const unsigned char *) w, _w_high); | |
1032 | while ((j < HighDest) && ((*p) != ASCII_nul)) | |
1033 | { | |
1034 | dest[j] = (*p); | |
1035 | j += 1; | |
1036 | p += 1; | |
1037 | } | |
1038 | if (j < HighDest) | |
1039 | { | |
1040 | dest[j] = ASCII_nul; | |
1041 | } | |
1042 | j = StrLib_StrLen ((const char *) dest, _dest_high); | |
1043 | i += 2; | |
1044 | } | |
1045 | else if (src[i+1] == 'd') | |
1046 | { | |
1047 | /* avoid dangling else. */ | |
1048 | dest[j] = ASCII_nul; | |
1049 | Cast ((unsigned char *) &c, (sizeof (c)-1), (const unsigned char *) w, _w_high); | |
1050 | NumberIO_CardToStr (c, 0, (char *) &str.array[0], MaxErrorString); | |
1051 | StrLib_StrConCat ((const char *) dest, _dest_high, (const char *) &str.array[0], MaxErrorString, (char *) dest, _dest_high); | |
1052 | j = StrLib_StrLen ((const char *) dest, _dest_high); | |
1053 | i += 2; | |
1054 | } | |
1055 | else | |
1056 | { | |
1057 | /* avoid dangling else. */ | |
1058 | dest[j] = src[i]; | |
1059 | i += 1; | |
1060 | j += 1; | |
1061 | } | |
1062 | } | |
1063 | /* and finish off copying src into dest */ | |
1064 | while (((i < HighSrc) && (src[i] != ASCII_nul)) && (j < HighDest)) | |
1065 | { | |
1066 | if (src[i] == '\\') | |
1067 | { | |
1068 | HandleEscape ((char *) dest, _dest_high, (const char *) src, _src_high, &i, &j, HighSrc, HighDest); | |
1069 | } | |
1070 | else | |
1071 | { | |
1072 | dest[j] = src[i]; | |
1073 | i += 1; | |
1074 | j += 1; | |
1075 | } | |
1076 | } | |
1077 | if (j < HighDest) | |
1078 | { | |
1079 | dest[j] = ASCII_nul; | |
1080 | } | |
1081 | } | |
1082 | ||
1083 | ||
1084 | /* | |
1085 | FormatError - provides a orthoganal counterpart to the procedure below. | |
1086 | */ | |
1087 | ||
1088 | static void FormatError (const char *a_, unsigned int _a_high) | |
1089 | { | |
1090 | char a[_a_high+1]; | |
1091 | ||
1092 | /* make a local copy of each unbounded array. */ | |
1093 | memcpy (a, a_, _a_high+1); | |
1094 | ||
1095 | FIO_WriteString (FIO_StdErr, (const char *) a, _a_high); | |
1096 | } | |
1097 | ||
1098 | ||
1099 | /* | |
1100 | FormatError1 - generic error procedure taking standard format string | |
1101 | and single parameter. | |
1102 | */ | |
1103 | ||
1104 | static void FormatError1 (const char *a_, unsigned int _a_high, const unsigned char *w_, unsigned int _w_high) | |
1105 | { | |
1106 | typedef struct FormatError1__T9_a FormatError1__T9; | |
1107 | ||
1108 | struct FormatError1__T9_a { char array[MaxErrorString+1]; }; | |
1109 | FormatError1__T9 s; | |
1110 | char a[_a_high+1]; | |
1111 | unsigned char w[_w_high+1]; | |
1112 | ||
1113 | /* make a local copy of each unbounded array. */ | |
1114 | memcpy (a, a_, _a_high+1); | |
1115 | memcpy (w, w_, _w_high+1); | |
1116 | ||
1117 | StringFormat1 ((char *) &s.array[0], MaxErrorString, (const char *) a, _a_high, (const unsigned char *) w, _w_high); | |
1118 | FormatError ((const char *) &s.array[0], MaxErrorString); | |
1119 | } | |
1120 | ||
1121 | ||
1122 | /* | |
1123 | FormatError2 - generic error procedure taking standard format string | |
1124 | and two parameters. | |
1125 | */ | |
1126 | ||
1127 | static void FormatError2 (const char *a_, unsigned int _a_high, const unsigned char *w1_, unsigned int _w1_high, const unsigned char *w2_, unsigned int _w2_high) | |
1128 | { | |
1129 | typedef struct FormatError2__T10_a FormatError2__T10; | |
1130 | ||
1131 | struct FormatError2__T10_a { char array[MaxErrorString+1]; }; | |
1132 | FormatError2__T10 s; | |
1133 | char a[_a_high+1]; | |
1134 | unsigned char w1[_w1_high+1]; | |
1135 | unsigned char w2[_w2_high+1]; | |
1136 | ||
1137 | /* make a local copy of each unbounded array. */ | |
1138 | memcpy (a, a_, _a_high+1); | |
1139 | memcpy (w1, w1_, _w1_high+1); | |
1140 | memcpy (w2, w2_, _w2_high+1); | |
1141 | ||
1142 | StringFormat1 ((char *) &s.array[0], MaxErrorString, (const char *) a, _a_high, (const unsigned char *) w1, _w1_high); | |
1143 | FormatError1 ((const char *) &s.array[0], MaxErrorString, (const unsigned char *) w2, _w2_high); | |
1144 | } | |
1145 | ||
1146 | ||
1147 | /* | |
1148 | CheckAccess - checks to see whether a file f has been | |
1149 | opened for read/write. | |
1150 | */ | |
1151 | ||
1152 | static void CheckAccess (FIO_File f, FIO_FileUsage use, unsigned int towrite) | |
1153 | { | |
1154 | FIO_FileDescriptor fd; | |
1155 | ||
1156 | if (f != Error) | |
1157 | { | |
1158 | /* avoid dangling else. */ | |
1159 | fd = static_cast<FIO_FileDescriptor> (Indexing_GetIndice (FileInfo, f)); | |
1160 | if (fd == NULL) | |
1161 | { | |
1162 | if (f != FIO_StdErr) | |
1163 | { | |
1164 | FormatError ((const char *) "this file has probably been closed and not reopened successfully or alternatively never opened\\n", 96); | |
1165 | } | |
1166 | M2RTS_HALT (-1); | |
1167 | __builtin_unreachable (); | |
1168 | } | |
1169 | else | |
1170 | { | |
1171 | if ((use == FIO_openedforwrite) && (fd->usage == FIO_openedforread)) | |
1172 | { | |
1173 | FormatError1 ((const char *) "this file (%s) has been opened for reading but is now being written\\n", 69, (const unsigned char *) &fd->name.address, (sizeof (fd->name.address)-1)); | |
1174 | M2RTS_HALT (-1); | |
1175 | __builtin_unreachable (); | |
1176 | } | |
1177 | else if ((use == FIO_openedforread) && (fd->usage == FIO_openedforwrite)) | |
1178 | { | |
1179 | /* avoid dangling else. */ | |
1180 | FormatError1 ((const char *) "this file (%s) has been opened for writing but is now being read\\n", 66, (const unsigned char *) &fd->name.address, (sizeof (fd->name.address)-1)); | |
1181 | M2RTS_HALT (-1); | |
1182 | __builtin_unreachable (); | |
1183 | } | |
1184 | else if (fd->state == FIO_connectionfailure) | |
1185 | { | |
1186 | /* avoid dangling else. */ | |
1187 | FormatError1 ((const char *) "this file (%s) was not successfully opened\\n", 44, (const unsigned char *) &fd->name.address, (sizeof (fd->name.address)-1)); | |
1188 | M2RTS_HALT (-1); | |
1189 | __builtin_unreachable (); | |
1190 | } | |
1191 | else if (towrite != fd->output) | |
1192 | { | |
1193 | /* avoid dangling else. */ | |
1194 | if (fd->output) | |
1195 | { | |
1196 | FormatError1 ((const char *) "this file (%s) was opened for writing but is now being read\\n", 61, (const unsigned char *) &fd->name.address, (sizeof (fd->name.address)-1)); | |
1197 | M2RTS_HALT (-1); | |
1198 | __builtin_unreachable (); | |
1199 | } | |
1200 | else | |
1201 | { | |
1202 | FormatError1 ((const char *) "this file (%s) was opened for reading but is now being written\\n", 64, (const unsigned char *) &fd->name.address, (sizeof (fd->name.address)-1)); | |
1203 | M2RTS_HALT (-1); | |
1204 | __builtin_unreachable (); | |
1205 | } | |
1206 | } | |
1207 | } | |
1208 | } | |
1209 | else | |
1210 | { | |
1211 | FormatError ((const char *) "this file has not been opened successfully\\n", 44); | |
1212 | M2RTS_HALT (-1); | |
1213 | __builtin_unreachable (); | |
1214 | } | |
1215 | } | |
1216 | ||
1217 | ||
1218 | /* | |
1219 | SetEndOfLine - | |
1220 | */ | |
1221 | ||
1222 | static void SetEndOfLine (FIO_File f, char ch) | |
1223 | { | |
1224 | FIO_FileDescriptor fd; | |
1225 | ||
1226 | CheckAccess (f, FIO_openedforread, FALSE); | |
1227 | if (f != Error) | |
1228 | { | |
1229 | fd = static_cast<FIO_FileDescriptor> (Indexing_GetIndice (FileInfo, f)); | |
1230 | if (ch == ASCII_nl) | |
1231 | { | |
1232 | fd->state = FIO_endofline; | |
1233 | } | |
1234 | else | |
1235 | { | |
1236 | fd->state = FIO_successful; | |
1237 | } | |
1238 | } | |
1239 | } | |
1240 | ||
1241 | ||
1242 | /* | |
1243 | BufferedWrite - will write, nBytes, through the buffer. | |
1244 | Similar to WriteNBytes, but this function will always | |
1245 | write into the buffer before copying into memory. | |
1246 | ||
1247 | Useful when performing small writes. | |
1248 | */ | |
1249 | ||
1250 | static int BufferedWrite (FIO_File f, unsigned int nBytes, void * a) | |
1251 | { | |
1252 | typedef unsigned char *BufferedWrite__T5; | |
1253 | ||
1254 | void * t; | |
1255 | int result; | |
1256 | int total; | |
1257 | int n; | |
1258 | BufferedWrite__T5 p; | |
1259 | FIO_FileDescriptor fd; | |
1260 | ||
1261 | if (f != Error) | |
1262 | { | |
1263 | fd = static_cast<FIO_FileDescriptor> (Indexing_GetIndice (FileInfo, f)); | |
1264 | if (fd != NULL) | |
1265 | { | |
1266 | total = 0; /* how many bytes have we read */ | |
1267 | if (fd->buffer != NULL) /* how many bytes have we read */ | |
1268 | { | |
1269 | /* place into the buffer first */ | |
1270 | while (nBytes > 0) | |
1271 | { | |
1272 | if (fd->buffer->left > 0) | |
1273 | { | |
1274 | if (nBytes == 1) | |
1275 | { | |
1276 | /* too expensive to call memcpy for 1 character */ | |
1277 | p = static_cast<BufferedWrite__T5> (a); | |
1278 | (*fd->buffer->contents).array[fd->buffer->position] = static_cast<char> ((*p)); | |
1279 | fd->buffer->left -= 1; /* reduce space */ | |
1280 | fd->buffer->position += 1; /* move onwards n byte */ | |
1281 | total += 1; /* move onwards n byte */ | |
1282 | return total; | |
1283 | } | |
1284 | else | |
1285 | { | |
1286 | n = Min (fd->buffer->left, nBytes); | |
1287 | t = fd->buffer->address; | |
1288 | t = reinterpret_cast<void *> (reinterpret_cast<char *> (t)+fd->buffer->position); | |
1289 | p = static_cast<BufferedWrite__T5> (libc_memcpy (a, t, static_cast<size_t> ((unsigned int ) (n)))); | |
1290 | fd->buffer->left -= n; /* remove consumed bytes */ | |
1291 | fd->buffer->position += n; /* move onwards n bytes */ | |
1292 | /* move ready for further writes */ | |
1293 | a = reinterpret_cast<void *> (reinterpret_cast<char *> (a)+n); | |
1294 | nBytes -= n; /* reduce the amount for future writes */ | |
1295 | total += n; /* reduce the amount for future writes */ | |
1296 | } | |
1297 | } | |
1298 | else | |
1299 | { | |
1300 | FIO_FlushBuffer (f); | |
1301 | if ((fd->state != FIO_successful) && (fd->state != FIO_endofline)) | |
1302 | { | |
1303 | nBytes = 0; | |
1304 | } | |
1305 | } | |
1306 | } | |
1307 | return total; | |
1308 | } | |
1309 | } | |
1310 | } | |
1311 | return -1; | |
1312 | /* static analysis guarentees a RETURN statement will be used before here. */ | |
1313 | __builtin_unreachable (); | |
1314 | } | |
1315 | ||
1316 | ||
1317 | /* | |
1318 | PreInitialize - preinitialize the file descriptor. | |
1319 | */ | |
1320 | ||
1321 | static void PreInitialize (FIO_File f, const char *fname_, unsigned int _fname_high, FIO_FileStatus state, FIO_FileUsage use, unsigned int towrite, int osfd, unsigned int bufsize) | |
1322 | { | |
1323 | FIO_FileDescriptor fd; | |
1324 | FIO_FileDescriptor fe; | |
1325 | char fname[_fname_high+1]; | |
1326 | ||
1327 | /* make a local copy of each unbounded array. */ | |
1328 | memcpy (fname, fname_, _fname_high+1); | |
1329 | ||
1330 | if ((InitializeFile (f, &fname, StrLib_StrLen ((const char *) fname, _fname_high), state, use, towrite, bufsize)) == f) | |
1331 | { | |
1332 | fd = static_cast<FIO_FileDescriptor> (Indexing_GetIndice (FileInfo, f)); | |
1333 | if (f == Error) | |
1334 | { | |
1335 | fe = static_cast<FIO_FileDescriptor> (Indexing_GetIndice (FileInfo, FIO_StdErr)); | |
1336 | if (fe == NULL) | |
1337 | { | |
1338 | M2RTS_HALT (-1); | |
1339 | __builtin_unreachable (); | |
1340 | } | |
1341 | else | |
1342 | { | |
1343 | fd->unixfd = fe->unixfd; /* the error channel */ | |
1344 | } | |
1345 | } | |
1346 | else | |
1347 | { | |
1348 | fd->unixfd = osfd; | |
1349 | } | |
1350 | } | |
1351 | else | |
1352 | { | |
1353 | M2RTS_HALT (-1); | |
1354 | __builtin_unreachable (); | |
1355 | } | |
1356 | } | |
1357 | ||
1358 | ||
1359 | /* | |
1360 | Init - initialize the modules, global variables. | |
1361 | */ | |
1362 | ||
1363 | static void Init (void) | |
1364 | { | |
1365 | FileInfo = Indexing_InitIndex (0); | |
1366 | Error = 0; | |
1367 | PreInitialize (Error, (const char *) "error", 5, FIO_toomanyfilesopen, FIO_unused, FALSE, -1, 0); | |
1368 | FIO_StdIn = 1; | |
1369 | PreInitialize (FIO_StdIn, (const char *) "<stdin>", 7, FIO_successful, FIO_openedforread, FALSE, 0, MaxBufferLength); | |
1370 | FIO_StdOut = 2; | |
1371 | PreInitialize (FIO_StdOut, (const char *) "<stdout>", 8, FIO_successful, FIO_openedforwrite, TRUE, 1, MaxBufferLength); | |
1372 | FIO_StdErr = 3; | |
1373 | PreInitialize (FIO_StdErr, (const char *) "<stderr>", 8, FIO_successful, FIO_openedforwrite, TRUE, 2, MaxBufferLength); | |
1374 | if (! (M2RTS_InstallTerminationProcedure ((PROC ) {(PROC_t) FIO_FlushOutErr}))) | |
1375 | { | |
1376 | M2RTS_HALT (-1); | |
1377 | __builtin_unreachable (); | |
1378 | } | |
1379 | } | |
1380 | ||
1381 | ||
1382 | /* | |
1383 | IsNoError - returns a TRUE if no error has occured on file, f. | |
1384 | */ | |
1385 | ||
1386 | extern "C" unsigned int FIO_IsNoError (FIO_File f) | |
1387 | { | |
1388 | FIO_FileDescriptor fd; | |
1389 | ||
1390 | if (f == Error) | |
1391 | { | |
1392 | return FALSE; | |
1393 | } | |
1394 | else | |
1395 | { | |
1396 | fd = static_cast<FIO_FileDescriptor> (Indexing_GetIndice (FileInfo, f)); | |
1397 | return (fd != NULL) && (((fd->state == FIO_successful) || (fd->state == FIO_endoffile)) || (fd->state == FIO_endofline)); | |
1398 | } | |
1399 | /* static analysis guarentees a RETURN statement will be used before here. */ | |
1400 | __builtin_unreachable (); | |
1401 | } | |
1402 | ||
1403 | ||
1404 | /* | |
1405 | IsActive - returns TRUE if the file, f, is still active. | |
1406 | */ | |
1407 | ||
1408 | extern "C" unsigned int FIO_IsActive (FIO_File f) | |
1409 | { | |
1410 | if (f == Error) | |
1411 | { | |
1412 | return FALSE; | |
1413 | } | |
1414 | else | |
1415 | { | |
1416 | return (Indexing_GetIndice (FileInfo, f)) != NULL; | |
1417 | } | |
1418 | /* static analysis guarentees a RETURN statement will be used before here. */ | |
1419 | __builtin_unreachable (); | |
1420 | } | |
1421 | ||
1422 | extern "C" unsigned int FIO_Exists (const char *fname_, unsigned int _fname_high) | |
1423 | { | |
1424 | char fname[_fname_high+1]; | |
1425 | ||
1426 | /* make a local copy of each unbounded array. */ | |
1427 | memcpy (fname, fname_, _fname_high+1); | |
1428 | ||
1429 | /* | |
1430 | The following functions are wrappers for the above. | |
1431 | */ | |
1432 | return FIO_exists (&fname, StrLib_StrLen ((const char *) fname, _fname_high)); | |
1433 | /* static analysis guarentees a RETURN statement will be used before here. */ | |
1434 | __builtin_unreachable (); | |
1435 | } | |
1436 | ||
1437 | extern "C" FIO_File FIO_OpenToRead (const char *fname_, unsigned int _fname_high) | |
1438 | { | |
1439 | char fname[_fname_high+1]; | |
1440 | ||
1441 | /* make a local copy of each unbounded array. */ | |
1442 | memcpy (fname, fname_, _fname_high+1); | |
1443 | ||
1444 | return FIO_openToRead (&fname, StrLib_StrLen ((const char *) fname, _fname_high)); | |
1445 | /* static analysis guarentees a RETURN statement will be used before here. */ | |
1446 | __builtin_unreachable (); | |
1447 | } | |
1448 | ||
1449 | extern "C" FIO_File FIO_OpenToWrite (const char *fname_, unsigned int _fname_high) | |
1450 | { | |
1451 | char fname[_fname_high+1]; | |
1452 | ||
1453 | /* make a local copy of each unbounded array. */ | |
1454 | memcpy (fname, fname_, _fname_high+1); | |
1455 | ||
1456 | return FIO_openToWrite (&fname, StrLib_StrLen ((const char *) fname, _fname_high)); | |
1457 | /* static analysis guarentees a RETURN statement will be used before here. */ | |
1458 | __builtin_unreachable (); | |
1459 | } | |
1460 | ||
1461 | extern "C" FIO_File FIO_OpenForRandom (const char *fname_, unsigned int _fname_high, unsigned int towrite, unsigned int newfile) | |
1462 | { | |
1463 | char fname[_fname_high+1]; | |
1464 | ||
1465 | /* make a local copy of each unbounded array. */ | |
1466 | memcpy (fname, fname_, _fname_high+1); | |
1467 | ||
1468 | return FIO_openForRandom (&fname, StrLib_StrLen ((const char *) fname, _fname_high), towrite, newfile); | |
1469 | /* static analysis guarentees a RETURN statement will be used before here. */ | |
1470 | __builtin_unreachable (); | |
1471 | } | |
1472 | ||
1473 | ||
1474 | /* | |
1475 | Close - close a file which has been previously opened using: | |
1476 | OpenToRead, OpenToWrite, OpenForRandom. | |
1477 | It is correct to close a file which has an error status. | |
1478 | */ | |
1479 | ||
1480 | extern "C" void FIO_Close (FIO_File f) | |
1481 | { | |
1482 | FIO_FileDescriptor fd; | |
1483 | ||
1484 | if (f != Error) | |
1485 | { | |
1486 | fd = static_cast<FIO_FileDescriptor> (Indexing_GetIndice (FileInfo, f)); | |
1487 | /* | |
1488 | we allow users to close files which have an error status | |
1489 | */ | |
1490 | if (fd != NULL) | |
1491 | { | |
1492 | FIO_FlushBuffer (f); | |
1493 | if (fd->unixfd >= 0) | |
1494 | { | |
1495 | if ((libc_close (fd->unixfd)) != 0) | |
1496 | { | |
1497 | FormatError1 ((const char *) "failed to close file (%s)\\n", 27, (const unsigned char *) &fd->name.address, (sizeof (fd->name.address)-1)); | |
1498 | fd->state = FIO_failed; /* --fixme-- too late to notify user (unless we return a BOOLEAN) */ | |
1499 | } | |
1500 | } | |
1501 | if (fd->name.address != NULL) | |
1502 | { | |
1503 | Storage_DEALLOCATE (&fd->name.address, fd->name.size); | |
1504 | } | |
1505 | if (fd->buffer != NULL) | |
1506 | { | |
1507 | if (fd->buffer->address != NULL) | |
1508 | { | |
1509 | Storage_DEALLOCATE (&fd->buffer->address, fd->buffer->size); | |
1510 | } | |
1511 | Storage_DEALLOCATE ((void **) &fd->buffer, sizeof (FIO_buf)); | |
1512 | fd->buffer = NULL; | |
1513 | } | |
1514 | Storage_DEALLOCATE ((void **) &fd, sizeof (FIO_fds)); | |
1515 | Indexing_PutIndice (FileInfo, f, NULL); | |
1516 | } | |
1517 | } | |
1518 | } | |
1519 | ||
1520 | ||
1521 | /* | |
1522 | exists - returns TRUE if a file named, fname exists for reading. | |
1523 | */ | |
1524 | ||
1525 | extern "C" unsigned int FIO_exists (void * fname, unsigned int flength) | |
1526 | { | |
1527 | FIO_File f; | |
1528 | ||
1529 | f = FIO_openToRead (fname, flength); | |
1530 | if (FIO_IsNoError (f)) | |
1531 | { | |
1532 | FIO_Close (f); | |
1533 | return TRUE; | |
1534 | } | |
1535 | else | |
1536 | { | |
1537 | FIO_Close (f); | |
1538 | return FALSE; | |
1539 | } | |
1540 | /* static analysis guarentees a RETURN statement will be used before here. */ | |
1541 | __builtin_unreachable (); | |
1542 | } | |
1543 | ||
1544 | ||
1545 | /* | |
1546 | openToRead - attempts to open a file, fname, for reading and | |
1547 | it returns this file. | |
1548 | The success of this operation can be checked by | |
1549 | calling IsNoError. | |
1550 | */ | |
1551 | ||
1552 | extern "C" FIO_File FIO_openToRead (void * fname, unsigned int flength) | |
1553 | { | |
1554 | FIO_File f; | |
1555 | ||
1556 | f = GetNextFreeDescriptor (); | |
1557 | if (f == Error) | |
1558 | { | |
1559 | SetState (f, FIO_toomanyfilesopen); | |
1560 | } | |
1561 | else | |
1562 | { | |
1563 | f = InitializeFile (f, fname, flength, FIO_successful, FIO_openedforread, FALSE, MaxBufferLength); | |
1564 | ConnectToUnix (f, FALSE, FALSE); | |
1565 | } | |
1566 | return f; | |
1567 | /* static analysis guarentees a RETURN statement will be used before here. */ | |
1568 | __builtin_unreachable (); | |
1569 | } | |
1570 | ||
1571 | ||
1572 | /* | |
1573 | openToWrite - attempts to open a file, fname, for write and | |
1574 | it returns this file. | |
1575 | The success of this operation can be checked by | |
1576 | calling IsNoError. | |
1577 | */ | |
1578 | ||
1579 | extern "C" FIO_File FIO_openToWrite (void * fname, unsigned int flength) | |
1580 | { | |
1581 | FIO_File f; | |
1582 | ||
1583 | f = GetNextFreeDescriptor (); | |
1584 | if (f == Error) | |
1585 | { | |
1586 | SetState (f, FIO_toomanyfilesopen); | |
1587 | } | |
1588 | else | |
1589 | { | |
1590 | f = InitializeFile (f, fname, flength, FIO_successful, FIO_openedforwrite, TRUE, MaxBufferLength); | |
1591 | ConnectToUnix (f, TRUE, TRUE); | |
1592 | } | |
1593 | return f; | |
1594 | /* static analysis guarentees a RETURN statement will be used before here. */ | |
1595 | __builtin_unreachable (); | |
1596 | } | |
1597 | ||
1598 | ||
1599 | /* | |
1600 | openForRandom - attempts to open a file, fname, for random access | |
1601 | read or write and it returns this file. | |
1602 | The success of this operation can be checked by | |
1603 | calling IsNoError. | |
1604 | towrite, determines whether the file should be | |
1605 | opened for writing or reading. | |
1606 | */ | |
1607 | ||
1608 | extern "C" FIO_File FIO_openForRandom (void * fname, unsigned int flength, unsigned int towrite, unsigned int newfile) | |
1609 | { | |
1610 | FIO_File f; | |
1611 | ||
1612 | f = GetNextFreeDescriptor (); | |
1613 | if (f == Error) | |
1614 | { | |
1615 | SetState (f, FIO_toomanyfilesopen); | |
1616 | } | |
1617 | else | |
1618 | { | |
1619 | f = InitializeFile (f, fname, flength, FIO_successful, FIO_openedforrandom, towrite, MaxBufferLength); | |
1620 | ConnectToUnix (f, towrite, newfile); | |
1621 | } | |
1622 | return f; | |
1623 | /* static analysis guarentees a RETURN statement will be used before here. */ | |
1624 | __builtin_unreachable (); | |
1625 | } | |
1626 | ||
1627 | ||
1628 | /* | |
1629 | FlushBuffer - flush contents of file, f. | |
1630 | */ | |
1631 | ||
1632 | extern "C" void FIO_FlushBuffer (FIO_File f) | |
1633 | { | |
1634 | FIO_FileDescriptor fd; | |
1635 | ||
1636 | if (f != Error) | |
1637 | { | |
1638 | fd = static_cast<FIO_FileDescriptor> (Indexing_GetIndice (FileInfo, f)); | |
1639 | if (fd != NULL) | |
1640 | { | |
1641 | if (fd->output && (fd->buffer != NULL)) | |
1642 | { | |
1643 | if ((fd->buffer->position == 0) || ((libc_write (fd->unixfd, fd->buffer->address, static_cast<size_t> (fd->buffer->position))) == ((int ) (fd->buffer->position)))) | |
1644 | { | |
1645 | fd->abspos += fd->buffer->position; | |
1646 | fd->buffer->bufstart = fd->abspos; | |
1647 | fd->buffer->position = 0; | |
1648 | fd->buffer->filled = 0; | |
1649 | fd->buffer->left = fd->buffer->size; | |
1650 | } | |
1651 | else | |
1652 | { | |
1653 | fd->state = FIO_failed; | |
1654 | } | |
1655 | } | |
1656 | } | |
1657 | } | |
1658 | } | |
1659 | ||
1660 | ||
1661 | /* | |
1662 | ReadNBytes - reads nBytes of a file into memory area, dest, returning | |
1663 | the number of bytes actually read. | |
1664 | This function will consume from the buffer and then | |
1665 | perform direct libc reads. It is ideal for large reads. | |
1666 | */ | |
1667 | ||
1668 | extern "C" unsigned int FIO_ReadNBytes (FIO_File f, unsigned int nBytes, void * dest) | |
1669 | { | |
1670 | typedef char *ReadNBytes__T2; | |
1671 | ||
1672 | int n; | |
1673 | ReadNBytes__T2 p; | |
1674 | ||
1675 | if (f != Error) | |
1676 | { | |
1677 | CheckAccess (f, FIO_openedforread, FALSE); | |
1678 | n = ReadFromBuffer (f, dest, nBytes); | |
1679 | if (n <= 0) | |
1680 | { | |
1681 | return 0; | |
1682 | } | |
1683 | else | |
1684 | { | |
1685 | p = static_cast<ReadNBytes__T2> (dest); | |
1686 | p += n-1; | |
1687 | SetEndOfLine (f, (*p)); | |
1688 | return n; | |
1689 | } | |
1690 | } | |
1691 | else | |
1692 | { | |
1693 | return 0; | |
1694 | } | |
1695 | /* static analysis guarentees a RETURN statement will be used before here. */ | |
1696 | __builtin_unreachable (); | |
1697 | } | |
1698 | ||
1699 | ||
1700 | /* | |
1701 | ReadAny - reads HIGH(a) bytes into, a. All input | |
1702 | is fully buffered, unlike ReadNBytes and thus is more | |
1703 | suited to small reads. | |
1704 | */ | |
1705 | ||
1706 | extern "C" void FIO_ReadAny (FIO_File f, unsigned char *a, unsigned int _a_high) | |
1707 | { | |
1708 | CheckAccess (f, FIO_openedforread, FALSE); | |
1709 | if ((BufferedRead (f, _a_high, a)) == ((int ) (_a_high))) | |
1710 | { | |
1711 | SetEndOfLine (f, static_cast<char> (a[_a_high])); | |
1712 | } | |
1713 | } | |
1714 | ||
1715 | ||
1716 | /* | |
1717 | WriteNBytes - writes nBytes from memory area src to a file | |
1718 | returning the number of bytes actually written. | |
1719 | This function will flush the buffer and then | |
1720 | write the nBytes using a direct write from libc. | |
1721 | It is ideal for large writes. | |
1722 | */ | |
1723 | ||
1724 | extern "C" unsigned int FIO_WriteNBytes (FIO_File f, unsigned int nBytes, void * src) | |
1725 | { | |
1726 | int total; | |
1727 | FIO_FileDescriptor fd; | |
1728 | ||
1729 | CheckAccess (f, FIO_openedforwrite, TRUE); | |
1730 | FIO_FlushBuffer (f); | |
1731 | if (f != Error) | |
1732 | { | |
1733 | fd = static_cast<FIO_FileDescriptor> (Indexing_GetIndice (FileInfo, f)); | |
1734 | if (fd != NULL) | |
1735 | { | |
1736 | total = static_cast<int> (libc_write (fd->unixfd, src, static_cast<size_t> ((int ) (nBytes)))); | |
1737 | if (total < 0) | |
1738 | { | |
1739 | fd->state = FIO_failed; | |
1740 | return 0; | |
1741 | } | |
1742 | else | |
1743 | { | |
1744 | fd->abspos += (unsigned int ) (total); | |
1745 | if (fd->buffer != NULL) | |
1746 | { | |
1747 | fd->buffer->bufstart = fd->abspos; | |
1748 | } | |
1749 | return (unsigned int ) (total); | |
1750 | } | |
1751 | } | |
1752 | } | |
1753 | return 0; | |
1754 | /* static analysis guarentees a RETURN statement will be used before here. */ | |
1755 | __builtin_unreachable (); | |
1756 | } | |
1757 | ||
1758 | ||
1759 | /* | |
1760 | WriteAny - writes HIGH(a) bytes onto, file, f. All output | |
1761 | is fully buffered, unlike WriteNBytes and thus is more | |
1762 | suited to small writes. | |
1763 | */ | |
1764 | ||
1765 | extern "C" void FIO_WriteAny (FIO_File f, unsigned char *a, unsigned int _a_high) | |
1766 | { | |
1767 | CheckAccess (f, FIO_openedforwrite, TRUE); | |
1768 | if ((BufferedWrite (f, _a_high, a)) == ((int ) (_a_high))) | |
1769 | {} /* empty. */ | |
1770 | } | |
1771 | ||
1772 | ||
1773 | /* | |
1774 | WriteChar - writes a single character to file, f. | |
1775 | */ | |
1776 | ||
1777 | extern "C" void FIO_WriteChar (FIO_File f, char ch) | |
1778 | { | |
1779 | CheckAccess (f, FIO_openedforwrite, TRUE); | |
1780 | if ((BufferedWrite (f, sizeof (ch), &ch)) == ((int ) (sizeof (ch)))) | |
1781 | {} /* empty. */ | |
1782 | } | |
1783 | ||
1784 | ||
1785 | /* | |
1786 | EOF - tests to see whether a file, f, has reached end of file. | |
1787 | */ | |
1788 | ||
1789 | extern "C" unsigned int FIO_EOF (FIO_File f) | |
1790 | { | |
1791 | FIO_FileDescriptor fd; | |
1792 | ||
1793 | CheckAccess (f, FIO_openedforread, FALSE); | |
1794 | if (f != Error) | |
1795 | { | |
1796 | fd = static_cast<FIO_FileDescriptor> (Indexing_GetIndice (FileInfo, f)); | |
1797 | if (fd != NULL) | |
1798 | { | |
1799 | return fd->state == FIO_endoffile; | |
1800 | } | |
1801 | } | |
1802 | return TRUE; | |
1803 | /* static analysis guarentees a RETURN statement will be used before here. */ | |
1804 | __builtin_unreachable (); | |
1805 | } | |
1806 | ||
1807 | ||
1808 | /* | |
1809 | EOLN - tests to see whether a file, f, is upon a newline. | |
1810 | It does NOT consume the newline. | |
1811 | */ | |
1812 | ||
1813 | extern "C" unsigned int FIO_EOLN (FIO_File f) | |
1814 | { | |
1815 | char ch; | |
1816 | FIO_FileDescriptor fd; | |
1817 | ||
1818 | CheckAccess (f, FIO_openedforread, FALSE); | |
1819 | /* | |
1820 | we will read a character and then push it back onto the input stream, | |
1821 | having noted the file status, we also reset the status. | |
1822 | */ | |
1823 | if (f != Error) | |
1824 | { | |
1825 | fd = static_cast<FIO_FileDescriptor> (Indexing_GetIndice (FileInfo, f)); | |
1826 | if (fd != NULL) | |
1827 | { | |
1828 | if ((fd->state == FIO_successful) || (fd->state == FIO_endofline)) | |
1829 | { | |
1830 | ch = FIO_ReadChar (f); | |
1831 | if ((fd->state == FIO_successful) || (fd->state == FIO_endofline)) | |
1832 | { | |
1833 | FIO_UnReadChar (f, ch); | |
1834 | } | |
1835 | return ch == ASCII_nl; | |
1836 | } | |
1837 | } | |
1838 | } | |
1839 | return FALSE; | |
1840 | /* static analysis guarentees a RETURN statement will be used before here. */ | |
1841 | __builtin_unreachable (); | |
1842 | } | |
1843 | ||
1844 | ||
1845 | /* | |
1846 | WasEOLN - tests to see whether a file, f, has just seen a newline. | |
1847 | */ | |
1848 | ||
1849 | extern "C" unsigned int FIO_WasEOLN (FIO_File f) | |
1850 | { | |
1851 | FIO_FileDescriptor fd; | |
1852 | ||
1853 | CheckAccess (f, FIO_openedforread, FALSE); | |
1854 | if (f == Error) | |
1855 | { | |
1856 | return FALSE; | |
1857 | } | |
1858 | else | |
1859 | { | |
1860 | fd = static_cast<FIO_FileDescriptor> (Indexing_GetIndice (FileInfo, f)); | |
1861 | return (fd != NULL) && (fd->state == FIO_endofline); | |
1862 | } | |
1863 | /* static analysis guarentees a RETURN statement will be used before here. */ | |
1864 | __builtin_unreachable (); | |
1865 | } | |
1866 | ||
1867 | ||
1868 | /* | |
1869 | ReadChar - returns a character read from file f. | |
1870 | Sensible to check with IsNoError or EOF after calling | |
1871 | this function. | |
1872 | */ | |
1873 | ||
1874 | extern "C" char FIO_ReadChar (FIO_File f) | |
1875 | { | |
1876 | char ch; | |
1877 | ||
1878 | CheckAccess (f, FIO_openedforread, FALSE); | |
1879 | if ((BufferedRead (f, sizeof (ch), &ch)) == ((int ) (sizeof (ch)))) | |
1880 | { | |
1881 | SetEndOfLine (f, ch); | |
1882 | return ch; | |
1883 | } | |
1884 | else | |
1885 | { | |
1886 | return ASCII_nul; | |
1887 | } | |
1888 | /* static analysis guarentees a RETURN statement will be used before here. */ | |
1889 | __builtin_unreachable (); | |
1890 | } | |
1891 | ||
1892 | ||
1893 | /* | |
1894 | UnReadChar - replaces a character, ch, back into file f. | |
1895 | This character must have been read by ReadChar | |
1896 | and it does not allow successive calls. It may | |
1897 | only be called if the previous read was successful | |
1898 | or end of file was seen. | |
1899 | If the state was previously endoffile then it | |
1900 | is altered to successful. | |
1901 | Otherwise it is left alone. | |
1902 | */ | |
1903 | ||
1904 | extern "C" void FIO_UnReadChar (FIO_File f, char ch) | |
1905 | { | |
1906 | FIO_FileDescriptor fd; | |
1907 | unsigned int n; | |
1908 | void * a; | |
1909 | void * b; | |
1910 | ||
1911 | CheckAccess (f, FIO_openedforread, FALSE); | |
1912 | if (f != Error) | |
1913 | { | |
1914 | fd = static_cast<FIO_FileDescriptor> (Indexing_GetIndice (FileInfo, f)); | |
1915 | if (((fd->state == FIO_successful) || (fd->state == FIO_endoffile)) || (fd->state == FIO_endofline)) | |
1916 | { | |
1917 | /* avoid dangling else. */ | |
1918 | if ((fd->buffer != NULL) && fd->buffer->valid) | |
1919 | { | |
1920 | /* we assume that a ReadChar has occurred, we will check just in case. */ | |
1921 | if (fd->state == FIO_endoffile) | |
1922 | { | |
1923 | fd->buffer->position = MaxBufferLength; | |
1924 | fd->buffer->left = 0; | |
1925 | fd->buffer->filled = 0; | |
1926 | fd->state = FIO_successful; | |
1927 | } | |
1928 | if (fd->buffer->position > 0) | |
1929 | { | |
1930 | fd->buffer->position -= 1; | |
1931 | fd->buffer->left += 1; | |
1932 | (*fd->buffer->contents).array[fd->buffer->position] = ch; | |
1933 | } | |
1934 | else | |
1935 | { | |
1936 | /* if possible make room and store ch */ | |
1937 | if (fd->buffer->filled == fd->buffer->size) | |
1938 | { | |
1939 | FormatError1 ((const char *) "performing too many UnReadChar calls on file (%d)\\n", 51, (const unsigned char *) &f, (sizeof (f)-1)); | |
1940 | } | |
1941 | else | |
1942 | { | |
1943 | n = fd->buffer->filled-fd->buffer->position; | |
1944 | b = &(*fd->buffer->contents).array[fd->buffer->position]; | |
1945 | a = &(*fd->buffer->contents).array[fd->buffer->position+1]; | |
1946 | a = libc_memcpy (a, b, static_cast<size_t> (n)); | |
1947 | fd->buffer->filled += 1; | |
1948 | (*fd->buffer->contents).array[fd->buffer->position] = ch; | |
1949 | } | |
1950 | } | |
1951 | } | |
1952 | } | |
1953 | else | |
1954 | { | |
1955 | FormatError1 ((const char *) "UnReadChar can only be called if the previous read was successful or end of file, error on file (%d)\\n", 102, (const unsigned char *) &f, (sizeof (f)-1)); | |
1956 | } | |
1957 | } | |
1958 | } | |
1959 | ||
1960 | ||
1961 | /* | |
1962 | WriteLine - writes out a linefeed to file, f. | |
1963 | */ | |
1964 | ||
1965 | extern "C" void FIO_WriteLine (FIO_File f) | |
1966 | { | |
1967 | FIO_WriteChar (f, ASCII_nl); | |
1968 | } | |
1969 | ||
1970 | ||
1971 | /* | |
1972 | WriteString - writes a string to file, f. | |
1973 | */ | |
1974 | ||
1975 | extern "C" void FIO_WriteString (FIO_File f, const char *a_, unsigned int _a_high) | |
1976 | { | |
1977 | unsigned int l; | |
1978 | char a[_a_high+1]; | |
1979 | ||
1980 | /* make a local copy of each unbounded array. */ | |
1981 | memcpy (a, a_, _a_high+1); | |
1982 | ||
1983 | l = StrLib_StrLen ((const char *) a, _a_high); | |
1984 | if ((FIO_WriteNBytes (f, l, &a)) != l) | |
1985 | {} /* empty. */ | |
1986 | } | |
1987 | ||
1988 | ||
1989 | /* | |
1990 | ReadString - reads a string from file, f, into string, a. | |
1991 | It terminates the string if HIGH is reached or | |
1992 | if a newline is seen or an error occurs. | |
1993 | */ | |
1994 | ||
1995 | extern "C" void FIO_ReadString (FIO_File f, char *a, unsigned int _a_high) | |
1996 | { | |
1997 | unsigned int high; | |
1998 | unsigned int i; | |
1999 | char ch; | |
2000 | ||
2001 | CheckAccess (f, FIO_openedforread, FALSE); | |
2002 | high = _a_high; | |
2003 | i = 0; | |
2004 | do { | |
2005 | ch = FIO_ReadChar (f); | |
2006 | if (i <= high) | |
2007 | { | |
2008 | /* avoid gcc warning by using compound statement even if not strictly necessary. */ | |
2009 | if (((ch == ASCII_nl) || (! (FIO_IsNoError (f)))) || (FIO_EOF (f))) | |
2010 | { | |
2011 | a[i] = ASCII_nul; | |
2012 | i += 1; | |
2013 | } | |
2014 | else | |
2015 | { | |
2016 | a[i] = ch; | |
2017 | i += 1; | |
2018 | } | |
2019 | } | |
2020 | } while (! ((((ch == ASCII_nl) || (i > high)) || (! (FIO_IsNoError (f)))) || (FIO_EOF (f)))); | |
2021 | } | |
2022 | ||
2023 | ||
2024 | /* | |
2025 | WriteCardinal - writes a CARDINAL to file, f. | |
2026 | It writes the binary image of the cardinal | |
2027 | to file, f. | |
2028 | */ | |
2029 | ||
2030 | extern "C" void FIO_WriteCardinal (FIO_File f, unsigned int c) | |
2031 | { | |
2032 | FIO_WriteAny (f, (unsigned char *) &c, (sizeof (c)-1)); | |
2033 | } | |
2034 | ||
2035 | ||
2036 | /* | |
2037 | ReadCardinal - reads a CARDINAL from file, f. | |
2038 | It reads a binary image of a CARDINAL | |
2039 | from a file, f. | |
2040 | */ | |
2041 | ||
2042 | extern "C" unsigned int FIO_ReadCardinal (FIO_File f) | |
2043 | { | |
2044 | unsigned int c; | |
2045 | ||
2046 | FIO_ReadAny (f, (unsigned char *) &c, (sizeof (c)-1)); | |
2047 | return c; | |
2048 | /* static analysis guarentees a RETURN statement will be used before here. */ | |
2049 | __builtin_unreachable (); | |
2050 | } | |
2051 | ||
2052 | ||
2053 | /* | |
2054 | GetUnixFileDescriptor - returns the UNIX file descriptor of a file. | |
2055 | */ | |
2056 | ||
2057 | extern "C" int FIO_GetUnixFileDescriptor (FIO_File f) | |
2058 | { | |
2059 | FIO_FileDescriptor fd; | |
2060 | ||
2061 | if (f != Error) | |
2062 | { | |
2063 | fd = static_cast<FIO_FileDescriptor> (Indexing_GetIndice (FileInfo, f)); | |
2064 | if (fd != NULL) | |
2065 | { | |
2066 | return fd->unixfd; | |
2067 | } | |
2068 | } | |
2069 | FormatError1 ((const char *) "file %d has not been opened or is out of range\\n", 48, (const unsigned char *) &f, (sizeof (f)-1)); | |
2070 | return -1; | |
2071 | /* static analysis guarentees a RETURN statement will be used before here. */ | |
2072 | __builtin_unreachable (); | |
2073 | } | |
2074 | ||
2075 | ||
2076 | /* | |
2077 | SetPositionFromBeginning - sets the position from the beginning of the file. | |
2078 | */ | |
2079 | ||
2080 | extern "C" void FIO_SetPositionFromBeginning (FIO_File f, long int pos) | |
2081 | { | |
2082 | long int offset; | |
2083 | FIO_FileDescriptor fd; | |
2084 | ||
2085 | if (f != Error) | |
2086 | { | |
2087 | fd = static_cast<FIO_FileDescriptor> (Indexing_GetIndice (FileInfo, f)); | |
2088 | if (fd != NULL) | |
2089 | { | |
2090 | /* always force the lseek, until we are confident that abspos is always correct, | |
2091 | basically it needs some hard testing before we should remove the OR TRUE. */ | |
2092 | if ((fd->abspos != pos) || TRUE) | |
2093 | { | |
2094 | FIO_FlushBuffer (f); | |
2095 | if (fd->buffer != NULL) | |
2096 | { | |
2097 | if (fd->output) | |
2098 | { | |
2099 | fd->buffer->left = fd->buffer->size; | |
2100 | } | |
2101 | else | |
2102 | { | |
2103 | fd->buffer->left = 0; | |
2104 | } | |
2105 | fd->buffer->position = 0; | |
2106 | fd->buffer->filled = 0; | |
2107 | } | |
2108 | offset = libc_lseek (fd->unixfd, pos, SEEK_SET); | |
2109 | if ((offset >= 0) && (pos == offset)) | |
2110 | { | |
2111 | fd->abspos = pos; | |
2112 | } | |
2113 | else | |
2114 | { | |
2115 | fd->state = FIO_failed; | |
2116 | fd->abspos = 0; | |
2117 | } | |
2118 | if (fd->buffer != NULL) | |
2119 | { | |
2120 | fd->buffer->valid = FALSE; | |
2121 | fd->buffer->bufstart = fd->abspos; | |
2122 | } | |
2123 | } | |
2124 | } | |
2125 | } | |
2126 | } | |
2127 | ||
2128 | ||
2129 | /* | |
2130 | SetPositionFromEnd - sets the position from the end of the file. | |
2131 | */ | |
2132 | ||
2133 | extern "C" void FIO_SetPositionFromEnd (FIO_File f, long int pos) | |
2134 | { | |
2135 | long int offset; | |
2136 | FIO_FileDescriptor fd; | |
2137 | ||
2138 | if (f != Error) | |
2139 | { | |
2140 | fd = static_cast<FIO_FileDescriptor> (Indexing_GetIndice (FileInfo, f)); | |
2141 | if (fd != NULL) | |
2142 | { | |
2143 | FIO_FlushBuffer (f); | |
2144 | if (fd->buffer != NULL) | |
2145 | { | |
2146 | if (fd->output) | |
2147 | { | |
2148 | fd->buffer->left = fd->buffer->size; | |
2149 | } | |
2150 | else | |
2151 | { | |
2152 | fd->buffer->left = 0; | |
2153 | } | |
2154 | fd->buffer->position = 0; | |
2155 | fd->buffer->filled = 0; | |
2156 | } | |
2157 | offset = libc_lseek (fd->unixfd, pos, SEEK_END); | |
2158 | if (offset >= 0) | |
2159 | { | |
2160 | fd->abspos = offset; | |
2161 | } | |
2162 | else | |
2163 | { | |
2164 | fd->state = FIO_failed; | |
2165 | fd->abspos = 0; | |
2166 | offset = 0; | |
2167 | } | |
2168 | if (fd->buffer != NULL) | |
2169 | { | |
2170 | fd->buffer->valid = FALSE; | |
2171 | fd->buffer->bufstart = offset; | |
2172 | } | |
2173 | } | |
2174 | } | |
2175 | } | |
2176 | ||
2177 | ||
2178 | /* | |
2179 | FindPosition - returns the current absolute position in file, f. | |
2180 | */ | |
2181 | ||
2182 | extern "C" long int FIO_FindPosition (FIO_File f) | |
2183 | { | |
2184 | FIO_FileDescriptor fd; | |
2185 | ||
2186 | if (f != Error) | |
2187 | { | |
2188 | fd = static_cast<FIO_FileDescriptor> (Indexing_GetIndice (FileInfo, f)); | |
2189 | if (fd != NULL) | |
2190 | { | |
2191 | if ((fd->buffer == NULL) || ! fd->buffer->valid) | |
2192 | { | |
2193 | return fd->abspos; | |
2194 | } | |
2195 | else | |
2196 | { | |
2197 | return fd->buffer->bufstart+((long int ) (fd->buffer->position)); | |
2198 | } | |
2199 | } | |
2200 | } | |
2201 | return 0; | |
2202 | /* static analysis guarentees a RETURN statement will be used before here. */ | |
2203 | __builtin_unreachable (); | |
2204 | } | |
2205 | ||
2206 | ||
2207 | /* | |
2208 | GetFileName - assigns, a, with the filename associated with, f. | |
2209 | */ | |
2210 | ||
2211 | extern "C" void FIO_GetFileName (FIO_File f, char *a, unsigned int _a_high) | |
2212 | { | |
2213 | typedef char *GetFileName__T6; | |
2214 | ||
2215 | unsigned int i; | |
2216 | GetFileName__T6 p; | |
2217 | FIO_FileDescriptor fd; | |
2218 | ||
2219 | if (f != Error) | |
2220 | { | |
2221 | fd = static_cast<FIO_FileDescriptor> (Indexing_GetIndice (FileInfo, f)); | |
2222 | if (fd == NULL) | |
2223 | { | |
2224 | FormatError ((const char *) "this file has probably been closed and not reopened successfully or alternatively never opened\\n", 96); | |
2225 | M2RTS_HALT (-1); | |
2226 | __builtin_unreachable (); | |
2227 | } | |
2228 | else | |
2229 | { | |
2230 | if (fd->name.address == NULL) | |
2231 | { | |
2232 | StrLib_StrCopy ((const char *) "", 0, (char *) a, _a_high); | |
2233 | } | |
2234 | else | |
2235 | { | |
2236 | p = static_cast<GetFileName__T6> (fd->name.address); | |
2237 | i = 0; | |
2238 | while (((*p) != ASCII_nul) && (i <= _a_high)) | |
2239 | { | |
2240 | a[i] = (*p); | |
2241 | p += 1; | |
2242 | i += 1; | |
2243 | } | |
2244 | } | |
2245 | } | |
2246 | } | |
2247 | } | |
2248 | ||
2249 | ||
2250 | /* | |
2251 | getFileName - returns the address of the filename associated with, f. | |
2252 | */ | |
2253 | ||
2254 | extern "C" void * FIO_getFileName (FIO_File f) | |
2255 | { | |
2256 | FIO_FileDescriptor fd; | |
2257 | ||
2258 | if (f != Error) | |
2259 | { | |
2260 | fd = static_cast<FIO_FileDescriptor> (Indexing_GetIndice (FileInfo, f)); | |
2261 | if (fd == NULL) | |
2262 | { | |
2263 | FormatError ((const char *) "this file has probably been closed and not reopened successfully or alternatively never opened\\n", 96); | |
2264 | M2RTS_HALT (-1); | |
2265 | __builtin_unreachable (); | |
2266 | } | |
2267 | else | |
2268 | { | |
2269 | return fd->name.address; | |
2270 | } | |
2271 | } | |
2272 | ReturnException ("../../gcc-git-devel-modula2/gcc/m2/gm2-libs/FIO.def", 25, 1); | |
2273 | __builtin_unreachable (); | |
2274 | } | |
2275 | ||
2276 | ||
2277 | /* | |
2278 | getFileNameLength - returns the number of characters associated with filename, f. | |
2279 | */ | |
2280 | ||
2281 | extern "C" unsigned int FIO_getFileNameLength (FIO_File f) | |
2282 | { | |
2283 | FIO_FileDescriptor fd; | |
2284 | ||
2285 | if (f != Error) | |
2286 | { | |
2287 | fd = static_cast<FIO_FileDescriptor> (Indexing_GetIndice (FileInfo, f)); | |
2288 | if (fd == NULL) | |
2289 | { | |
2290 | FormatError ((const char *) "this file has probably been closed and not reopened successfully or alternatively never opened\\n", 96); | |
2291 | M2RTS_HALT (-1); | |
2292 | __builtin_unreachable (); | |
2293 | } | |
2294 | else | |
2295 | { | |
2296 | return fd->name.size; | |
2297 | } | |
2298 | } | |
2299 | ReturnException ("../../gcc-git-devel-modula2/gcc/m2/gm2-libs/FIO.def", 25, 1); | |
2300 | __builtin_unreachable (); | |
2301 | } | |
2302 | ||
2303 | ||
2304 | /* | |
2305 | FlushOutErr - flushes, StdOut, and, StdErr. | |
2306 | It is also called when the application calls M2RTS.Terminate. | |
2307 | (which is automatically placed in program modules by the GM2 | |
2308 | scaffold). | |
2309 | */ | |
2310 | ||
2311 | extern "C" void FIO_FlushOutErr (void) | |
2312 | { | |
2313 | if (FIO_IsNoError (FIO_StdOut)) | |
2314 | { | |
2315 | FIO_FlushBuffer (FIO_StdOut); | |
2316 | } | |
2317 | if (FIO_IsNoError (FIO_StdErr)) | |
2318 | { | |
2319 | FIO_FlushBuffer (FIO_StdErr); | |
2320 | } | |
2321 | } | |
2322 | ||
2323 | extern "C" void _M2_FIO_init (__attribute__((unused)) int argc,__attribute__((unused)) char *argv[],__attribute__((unused)) char *envp[]) | |
2324 | { | |
2325 | Init (); | |
2326 | } | |
2327 | ||
2328 | extern "C" void _M2_FIO_finish (__attribute__((unused)) int argc,__attribute__((unused)) char *argv[],__attribute__((unused)) char *envp[]) | |
2329 | { | |
2330 | FIO_FlushOutErr (); | |
2331 | } |