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