| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761 |
- (* FIO.mod provides a simple buffered file input/output library.
- Copyright (C) 2001-2025 Free Software Foundation, Inc.
- Contributed by Gaius Mulley <gaius.mulley@southwales.ac.uk>.
- This file is part of GNU Modula-2.
- GNU Modula-2 is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3, or (at your option)
- any later version.
- GNU Modula-2 is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
- Under Section 7 of GPL version 3, you are granted additional
- permissions described in the GCC Runtime Library Exception, version
- 3.1, as published by the Free Software Foundation.
- You should have received a copy of the GNU General Public License and
- a copy of the GCC Runtime Library Exception along with this program;
- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
- <http://www.gnu.org/licenses/>. *)
- IMPLEMENTATION MODULE FIO ;
- (*
- Title : FIO
- Author : Gaius Mulley
- System : UNIX (gm2)
- Date : Thu Sep 2 22:07:21 1999
- Last edit : Thu Sep 2 22:07:21 1999
- Description: a complete reimplememtation of FIO.mod
- provides a simple buffered file input/output library.
- *)
- IMPORT Strings;
- FROM SYSTEM IMPORT ADR, TSIZE, WORD, COFF_T ;
- FROM ASCII IMPORT nl, nul, tab ;
- FROM StrLib IMPORT StrLen, StrConCat, StrCopy ;
- FROM Storage IMPORT ALLOCATE, DEALLOCATE ;
- FROM NumberIO IMPORT CardToStr ;
- FROM Indexing IMPORT Index, InitIndex, InBounds, HighIndice, LowIndice, PutIndice, GetIndice ;
- FROM M2RTS IMPORT InstallTerminationProcedure ;
- FROM libc IMPORT exit, open, creat, read, write, close, lseek, strncpy, memcpy, unlink ;
- FROM wrapc IMPORT SeekSet, SeekEnd, ReadOnly, WriteOnly ;
- CONST
- MaxBufferLength = 1024*16 ;
- MaxErrorString = 1024* 8 ;
- CreatePermissions = 666B;
- TYPE
- FileUsage = (unused, openedforread, openedforwrite, openedforrandom) ;
- FileStatus = (successful, outofmemory, toomanyfilesopen, failed, connectionfailure, endofline, endoffile) ;
- NameInfo = RECORD
- address: ADDRESS ;
- size : CARDINAL ;
- END ;
- Buffer = POINTER TO buf ;
- buf = RECORD
- valid : BOOLEAN ; (* are the field valid? *)
- bufstart: LONGINT ; (* the position of buffer in file *)
- position: CARDINAL ; (* where are we through this buffer *)
- address : ADDRESS ; (* dynamic buffer address *)
- filled : CARDINAL ; (* length of the buffer filled *)
- size : CARDINAL ; (* maximum space in this buffer *)
- left : CARDINAL ; (* number of bytes left to read *)
- contents: POINTER TO ARRAY [0..MaxBufferLength] OF CHAR ;
- END ;
- FileDescriptor = POINTER TO fds ;
- fds = RECORD
- unixfd: INTEGER ;
- name : NameInfo ;
- state : FileStatus ;
- usage : FileUsage ;
- output: BOOLEAN ; (* is this file going to write data *)
- buffer: Buffer ;
- abspos: LONGINT ; (* absolute position into file. *)
- END ; (* reflects low level reads which *)
- (* means this value will normally *)
- (* be further through the file than *)
- (* bufstart above. *)
- PtrToChar = POINTER TO CHAR ;
- VAR
- FileInfo: Index ;
- Error : File ; (* not stderr, this is an unused file handle
- which only serves to hold status values
- when we cannot create a new file handle *)
- (*
- GetUnixFileDescriptor - returns the UNIX file descriptor of a file.
- *)
- PROCEDURE GetUnixFileDescriptor (f: File) : INTEGER ;
- VAR
- fd: FileDescriptor ;
- BEGIN
- IF f#Error
- THEN
- fd := GetIndice(FileInfo, f) ;
- IF fd#NIL
- THEN
- RETURN( fd^.unixfd )
- END
- END ;
- FormatError1('file %d has not been opened or is out of range\n', f) ;
- RETURN( -1 )
- END GetUnixFileDescriptor ;
- (*
- WriteString - writes a string to file, f.
- *)
- PROCEDURE WriteString (f: File; a: ARRAY OF CHAR) ;
- VAR
- l: CARDINAL ;
- BEGIN
- l := StrLen(a) ;
- IF WriteNBytes(f, l, ADR(a))#l
- THEN
- END
- END WriteString ;
- (*
- Max - returns the maximum of two values.
- *)
- PROCEDURE Max (a, b: CARDINAL) : CARDINAL ;
- BEGIN
- IF a>b
- THEN
- RETURN( a )
- ELSE
- RETURN( b )
- END
- END Max ;
- (*
- Min - returns the minimum of two values.
- *)
- PROCEDURE Min (a, b: CARDINAL) : CARDINAL ;
- BEGIN
- IF a<b
- THEN
- RETURN( a )
- ELSE
- RETURN( b )
- END
- END Min ;
- (*
- GetNextFreeDescriptor - returns the index to the FileInfo array indicating
- the next free slot.
- *)
- PROCEDURE GetNextFreeDescriptor () : File ;
- VAR
- f, h: File ;
- fd : FileDescriptor ;
- BEGIN
- f := Error+1 ;
- h := HighIndice(FileInfo) ;
- LOOP
- IF f<=h
- THEN
- fd := GetIndice(FileInfo, f) ;
- IF fd=NIL
- THEN
- RETURN( f )
- END
- END ;
- INC(f) ;
- IF f>h
- THEN
- PutIndice(FileInfo, f, NIL) ; (* create new slot *)
- RETURN( f )
- END
- END
- END GetNextFreeDescriptor ;
- (*
- IsNoError - returns a TRUE if no error has occured on file, f.
- *)
- PROCEDURE IsNoError (f: File) : BOOLEAN ;
- VAR
- fd: FileDescriptor ;
- BEGIN
- IF f=Error
- THEN
- RETURN( FALSE )
- ELSE
- fd := GetIndice(FileInfo, f) ;
- RETURN( (fd#NIL) AND ((fd^.state=successful) OR (fd^.state=endoffile) OR (fd^.state=endofline)) )
- END
- END IsNoError ;
- (*
- IsActive - returns TRUE if the file, f, is still active.
- *)
- PROCEDURE IsActive (f: File) : BOOLEAN ;
- BEGIN
- IF f=Error
- THEN
- RETURN( FALSE )
- ELSE
- RETURN( GetIndice(FileInfo, f)#NIL )
- END
- END IsActive ;
- (*
- openToRead - attempts to open a file, fname, for reading and
- it returns this file.
- The success of this operation can be checked by
- calling IsNoError.
- *)
- PROCEDURE openToRead (fname: ADDRESS; flength: CARDINAL) : File ;
- VAR
- f: File ;
- BEGIN
- f := GetNextFreeDescriptor() ;
- IF f=Error
- THEN
- SetState(f, toomanyfilesopen)
- ELSE
- f := InitializeFile(f, fname, flength, successful, openedforread, FALSE, MaxBufferLength) ;
- ConnectToUnix(f, FALSE, FALSE)
- END ;
- RETURN( f )
- END openToRead ;
- (*
- openToWrite - attempts to open a file, fname, for write and
- it returns this file.
- The success of this operation can be checked by
- calling IsNoError.
- *)
- PROCEDURE openToWrite (fname: ADDRESS; flength: CARDINAL) : File ;
- VAR
- f: File ;
- BEGIN
- f := GetNextFreeDescriptor() ;
- IF f=Error
- THEN
- SetState(f, toomanyfilesopen)
- ELSE
- f := InitializeFile(f, fname, flength, successful, openedforwrite, TRUE, MaxBufferLength) ;
- ConnectToUnix(f, TRUE, TRUE)
- END ;
- RETURN( f )
- END openToWrite ;
- (*
- openForRandom - attempts to open a file, fname, for random access
- read or write and it returns this file.
- The success of this operation can be checked by
- calling IsNoError.
- towrite, determines whether the file should be
- opened for writing or reading.
- *)
- PROCEDURE openForRandom (fname: ADDRESS; flength: CARDINAL;
- towrite, newfile: BOOLEAN) : File ;
- VAR
- f: File ;
- BEGIN
- f := GetNextFreeDescriptor() ;
- IF f=Error
- THEN
- SetState(f, toomanyfilesopen)
- ELSE
- f := InitializeFile(f, fname, flength, successful, openedforrandom, towrite, MaxBufferLength) ;
- ConnectToUnix(f, towrite, newfile)
- END ;
- RETURN( f )
- END openForRandom ;
- (*
- exists - returns TRUE if a file named, fname exists for reading.
- *)
- PROCEDURE exists (fname: ADDRESS; flength: CARDINAL) : BOOLEAN ;
- VAR
- f: File ;
- BEGIN
- f := openToRead(fname, flength) ;
- IF IsNoError(f)
- THEN
- Close(f) ;
- RETURN( TRUE )
- ELSE
- Close(f) ;
- RETURN( FALSE )
- END
- END exists ;
- (*
- SetState - sets the field, state, of file, f, to, s.
- *)
- PROCEDURE SetState (f: File; s: FileStatus) ;
- VAR
- fd: FileDescriptor ;
- BEGIN
- fd := GetIndice(FileInfo, f) ;
- fd^.state := s
- END SetState ;
- (*
- InitializeFile - initialize a file descriptor
- *)
- PROCEDURE InitializeFile (f: File; fname: ADDRESS;
- flength: CARDINAL; fstate: FileStatus;
- use: FileUsage;
- towrite: BOOLEAN; buflength: CARDINAL) : File ;
- VAR
- p : PtrToChar ;
- fd: FileDescriptor ;
- BEGIN
- NEW(fd) ;
- IF fd=NIL
- THEN
- SetState(Error, outofmemory) ;
- RETURN( Error )
- ELSE
- PutIndice(FileInfo, f, fd) ;
- WITH fd^ DO
- name.size := flength+1 ; (* need to guarantee the nul for C *)
- usage := use ;
- output := towrite ;
- ALLOCATE(name.address, name.size) ;
- IF name.address=NIL
- THEN
- state := outofmemory ;
- RETURN( f )
- END ;
- name.address := strncpy(name.address, fname, flength) ;
- (* and assign nul to the last byte *)
- p := name.address ;
- INC(p, flength) ;
- p^ := nul ;
- abspos := 0 ;
- (* now for the buffer *)
- NEW(buffer) ;
- IF buffer=NIL
- THEN
- SetState(Error, outofmemory) ;
- RETURN( Error )
- ELSE
- WITH buffer^ DO
- valid := FALSE ;
- bufstart := 0 ;
- size := buflength ;
- position := 0 ;
- filled := 0 ;
- IF size=0
- THEN
- address := NIL
- ELSE
- ALLOCATE(address, size) ;
- IF address=NIL
- THEN
- state := outofmemory ;
- RETURN( f )
- END
- END ;
- IF towrite
- THEN
- left := size
- ELSE
- left := 0
- END ;
- contents := address ; (* provides easy access for reading characters *)
- END ;
- state := fstate
- END
- END
- END ;
- RETURN( f )
- END InitializeFile ;
- (*
- ConnectToUnix - connects a FIO file to a UNIX file descriptor.
- *)
- PROCEDURE ConnectToUnix (f: File; towrite, newfile: BOOLEAN) ;
- VAR
- fd: FileDescriptor ;
- BEGIN
- IF f#Error
- THEN
- fd := GetIndice(FileInfo, f) ;
- IF fd#NIL
- THEN
- WITH fd^ DO
- IF towrite
- THEN
- IF newfile
- THEN
- unixfd := creat(name.address, CreatePermissions)
- ELSE
- unixfd := open(name.address, INTEGER (WriteOnly ()), 0)
- END
- ELSE
- unixfd := open(name.address, INTEGER (ReadOnly ()), 0)
- END ;
- IF unixfd<0
- THEN
- state := connectionfailure
- END
- END
- END
- END
- END ConnectToUnix ;
- (*
- The following functions are wrappers for the above.
- *)
- PROCEDURE Exists (fname: ARRAY OF CHAR) : BOOLEAN ;
- BEGIN
- RETURN( exists(ADR(fname), StrLen(fname)) )
- END Exists ;
- PROCEDURE OpenToRead (fname: ARRAY OF CHAR) : File ;
- BEGIN
- RETURN( openToRead(ADR(fname), StrLen(fname)) )
- END OpenToRead ;
- PROCEDURE OpenToWrite (fname: ARRAY OF CHAR) : File ;
- BEGIN
- RETURN( openToWrite(ADR(fname), StrLen(fname)) )
- END OpenToWrite ;
- PROCEDURE OpenForRandom (fname: ARRAY OF CHAR;
- towrite: BOOLEAN; newfile: BOOLEAN) : File ;
- BEGIN
- RETURN( openForRandom(ADR(fname), StrLen(fname), towrite, newfile) )
- END OpenForRandom ;
- (*
- Close - close a file which has been previously opened using:
- OpenToRead, OpenToWrite, OpenForRandom.
- It is correct to close a file which has an error status.
- *)
- PROCEDURE Close (f: File) ;
- VAR
- fd: FileDescriptor ;
- BEGIN
- IF f#Error
- THEN
- fd := GetIndice(FileInfo, f) ;
- (*
- we allow users to close files which have an error status
- *)
- IF fd#NIL
- THEN
- FlushBuffer(f) ;
- WITH fd^ DO
- IF unixfd>=0
- THEN
- IF close(unixfd)#0
- THEN
- FormatError1('failed to close file (%s)\n', name.address) ;
- state := failed (* --fixme-- too late to notify user (unless we return a BOOLEAN) *)
- END
- END ;
- IF name.address#NIL
- THEN
- DEALLOCATE(name.address, name.size)
- END ;
- IF buffer#NIL
- THEN
- WITH buffer^ DO
- IF address#NIL
- THEN
- DEALLOCATE(address, size)
- END
- END ;
- DISPOSE(buffer) ;
- buffer := NIL
- END
- END ;
- DISPOSE(fd) ;
- PutIndice(FileInfo, f, NIL)
- END
- END
- END Close ;
- (*
- Unlink - Delete a file which has been opened using
- OpenToRead, OpenToWrite, OpenForRandom.
- *)
- PROCEDURE Unlink ( f : File );
- VAR
- fname: ARRAY[0..256] OF CHAR ;
- BEGIN
- GetFileName(f,fname);
- fd := GetIndice(FileInfo, f) ;
- Close(f);
- unlink(ADR(fname));
- END Unlink;
- (*
- Delete - Delete a file which has been opened using
- OpenToRead, OpenToWrite, OpenForRandom.
- *)
- PROCEDURE Delete (fname: ARRAY OF CHAR ) ;
- VAR
- fd: FileDescriptor ;
-
- BEGIN
- fd := GetFDesc(fname);
- IF fd # NIL THEN
- Close(fd);
- (*Unlink(ADR(fname));*)
- END;
- END Delete;
- (*
- ReadFromBuffer - attempts to read, nBytes, from file, f.
- It firstly consumes the buffer and then performs
- direct unbuffered reads. This should only be used
- when wishing to read large files.
- The actual number of bytes read is returned.
- -1 is returned if EOF is reached.
- *)
- PROCEDURE ReadFromBuffer (f: File; a: ADDRESS; nBytes: CARDINAL) : INTEGER ;
- VAR
- t : ADDRESS ;
- result: INTEGER ;
- total,
- n : CARDINAL ;
- p : POINTER TO BYTE ;
- fd : FileDescriptor ;
- BEGIN
- IF f#Error
- THEN
- total := 0 ; (* how many bytes have we read *)
- fd := GetIndice(FileInfo, f) ;
- WITH fd^ DO
- (* extract from the buffer first *)
- IF (buffer#NIL) AND (buffer^.valid)
- THEN
- WITH buffer^ DO
- IF left>0
- THEN
- IF nBytes=1
- THEN
- (* too expensive to call memcpy for 1 character *)
- p := a ;
- p^ := contents^[position] ;
- DEC(left) ; (* remove consumed bytes *)
- INC(position) ; (* move onwards n bytes *)
- nBytes := 0 ; (* reduce the amount for future direct *)
- (* read *)
- RETURN( 1 )
- ELSE
- n := Min(left, nBytes) ;
- t := address ;
- INC(t, position) ;
- p := memcpy(a, t, n) ;
- DEC(left, n) ; (* remove consumed bytes *)
- INC(position, n) ; (* move onwards n bytes *)
- (* move onwards ready for direct reads *)
- INC(a, n) ;
- DEC(nBytes, n) ; (* reduce the amount for future direct *)
- (* read *)
- INC(total, n) ;
- RETURN( total ) (* much cleaner to return now, *)
- END (* difficult to record an error if *)
- END (* the read below returns -1 *)
- END
- END ;
- IF nBytes>0
- THEN
- (* still more to read *)
- result := read(unixfd, a, INTEGER(nBytes)) ;
- IF result>0
- THEN
- INC(total, result) ;
- INC(abspos, result) ;
- (* now disable the buffer as we read directly into, a. *)
- IF buffer#NIL
- THEN
- buffer^.valid := FALSE
- END ;
- ELSE
- IF result=0
- THEN
- (* eof reached *)
- state := endoffile
- ELSE
- state := failed
- END ;
- (* indicate buffer is empty *)
- IF buffer#NIL
- THEN
- WITH buffer^ DO
- valid := FALSE ;
- left := 0 ;
- position := 0 ;
- IF address#NIL
- THEN
- contents^[position] := nul
- END
- END
- END ;
- RETURN( -1 )
- END
- END
- END ;
- RETURN( total )
- ELSE
- RETURN( -1 )
- END
- END ReadFromBuffer ;
- (*
- ReadNBytes - reads nBytes of a file into memory area, dest, returning
- the number of bytes actually read.
- This function will consume from the buffer and then
- perform direct libc reads. It is ideal for large reads.
- *)
- PROCEDURE ReadNBytes (f: File; nBytes: CARDINAL; dest: ADDRESS) : CARDINAL ;
- VAR
- n: INTEGER ;
- p: POINTER TO CHAR ;
- BEGIN
- IF f # Error
- THEN
- CheckAccess (f, openedforread, FALSE) ;
- n := ReadFromBuffer (f, dest, nBytes) ;
- IF n <= 0
- THEN
- RETURN 0
- ELSE
- p := dest ;
- INC (p, n-1) ;
- SetEndOfLine (f, p^) ;
- RETURN n
- END
- ELSE
- RETURN 0
- END
- END ReadNBytes ;
- (*
- BufferedRead - will read, nBytes, through the buffer.
- Similar to ReadFromBuffer, but this function will always
- read into the buffer before copying into memory.
- Useful when performing small reads.
- *)
- PROCEDURE BufferedRead (f: File; nBytes: CARDINAL; dest: ADDRESS) : INTEGER ;
- VAR
- src : ADDRESS ;
- total,
- n : INTEGER ;
- p : POINTER TO BYTE ;
- fd : FileDescriptor ;
- BEGIN
- IF f#Error
- THEN
- fd := GetIndice (FileInfo, f) ;
- total := 0 ; (* how many bytes have we read *)
- IF fd#NIL
- THEN
- WITH fd^ DO
- (* extract from the buffer first *)
- IF buffer # NIL
- THEN
- WITH buffer^ DO
- WHILE nBytes > 0 DO
- IF (left > 0) AND valid
- THEN
- IF nBytes = 1
- THEN
- (* too expensive to call memcpy for 1 character *)
- p := dest ;
- p^ := contents^[position] ;
- DEC (left) ; (* remove consumed byte *)
- INC (position) ; (* move onwards n byte *)
- INC (total) ;
- RETURN( total )
- ELSE
- n := Min (left, nBytes) ;
- src := address ;
- INC (src, position) ;
- p := memcpy (dest, src, n) ;
- DEC (left, n) ; (* remove consumed bytes *)
- INC (position, n) ; (* move onwards n bytes *)
- (* move onwards ready for direct reads *)
- INC (dest, n) ;
- DEC (nBytes, n) ; (* reduce the amount for future direct *)
- (* read *)
- INC (total, n)
- END
- ELSE
- (* refill buffer *)
- n := read (unixfd, address, size) ;
- IF n >= 0
- THEN
- valid := TRUE ;
- position := 0 ;
- left := n ;
- filled := n ;
- bufstart := abspos ;
- INC (abspos, n) ;
- IF n = 0
- THEN
- (* eof reached *)
- state := endoffile ;
- RETURN( -1 )
- END
- ELSE
- valid := FALSE ;
- position := 0 ;
- left := 0 ;
- filled := 0 ;
- state := failed ;
- RETURN( total )
- END
- END
- END
- END ;
- RETURN( total )
- END
- END
- END
- END ;
- RETURN( -1 )
- END BufferedRead ;
- (*
- HandleEscape - translates \n and \t into their respective ascii codes.
- *)
- PROCEDURE HandleEscape (VAR dest: ARRAY OF CHAR; src: ARRAY OF CHAR;
- VAR i, j: CARDINAL; HighSrc, HighDest: CARDINAL) ;
- BEGIN
- IF (i+1<HighSrc) AND (src[i]='\') AND (j<HighDest)
- THEN
- IF src[i+1]='n'
- THEN
- (* requires a newline *)
- dest[j] := nl ;
- INC(j) ;
- INC(i, 2)
- ELSIF src[i+1]='t'
- THEN
- (* requires a tab (yuck) tempted to fake this but I better not.. *)
- dest[j] := tab ;
- INC(j) ;
- INC(i, 2)
- ELSE
- (* copy escaped character *)
- INC(i) ;
- dest[j] := src[i] ;
- INC(j) ;
- INC(i)
- END
- END
- END HandleEscape ;
- (*
- Cast - casts a := b
- *)
- PROCEDURE Cast (VAR a: ARRAY OF BYTE; b: ARRAY OF BYTE) ;
- VAR
- i: CARDINAL ;
- BEGIN
- IF HIGH(a)=HIGH(b)
- THEN
- FOR i := 0 TO HIGH(a) DO
- a[i] := b[i]
- END
- ELSE
- FormatError('cast failed')
- END
- END Cast ;
- (*
- StringFormat1 - converts string, src, into, dest, together with encapsulated
- entity, w. It only formats the first %s or %d with n.
- *)
- PROCEDURE StringFormat1 (VAR dest: ARRAY OF CHAR; src: ARRAY OF CHAR;
- w: ARRAY OF BYTE) ;
- VAR
- HighSrc,
- HighDest,
- c, i, j : CARDINAL ;
- str : ARRAY [0..MaxErrorString] OF CHAR ;
- p : POINTER TO CHAR ;
- BEGIN
- HighSrc := StrLen(src) ;
- HighDest := HIGH(dest) ;
- p := NIL ;
- c := 0 ;
- i := 0 ;
- j := 0 ;
- WHILE (i<HighSrc) AND (src[i]#nul) AND (j<HighDest) AND (src[i]#'%') DO
- IF src[i]='\'
- THEN
- HandleEscape(dest, src, i, j, HighSrc, HighDest)
- ELSE
- dest[j] := src[i] ;
- INC(i) ;
- INC(j)
- END
- END ;
- IF (i+1<HighSrc) AND (src[i]='%') AND (j<HighDest)
- THEN
- IF src[i+1]='s'
- THEN
- Cast(p, w) ;
- WHILE (j<HighDest) AND (p^#nul) DO
- dest[j] := p^ ;
- INC(j) ;
- INC(p)
- END ;
- IF j<HighDest
- THEN
- dest[j] := nul
- END ;
- j := StrLen(dest) ;
- INC(i, 2)
- ELSIF src[i+1]='d'
- THEN
- dest[j] := nul ;
- Cast(c, w) ;
- CardToStr(c, 0, str) ;
- StrConCat(dest, str, dest) ;
- j := StrLen(dest) ;
- INC(i, 2)
- ELSE
- dest[j] := src[i] ;
- INC(i) ;
- INC(j)
- END
- END ;
- (* and finish off copying src into dest *)
- WHILE (i<HighSrc) AND (src[i]#nul) AND (j<HighDest) DO
- IF src[i]='\'
- THEN
- HandleEscape(dest, src, i, j, HighSrc, HighDest)
- ELSE
- dest[j] := src[i] ;
- INC(i) ;
- INC(j)
- END
- END ;
- IF j<HighDest
- THEN
- dest[j] := nul
- END ;
- END StringFormat1 ;
- (*
- FormatError - provides a orthoganal counterpart to the procedure below.
- *)
- PROCEDURE FormatError (a: ARRAY OF CHAR) ;
- BEGIN
- WriteString (StdErr, a)
- END FormatError ;
- (*
- FormatError1 - generic error procedure taking standard format string
- and single parameter.
- *)
- PROCEDURE FormatError1 (a: ARRAY OF CHAR; w: ARRAY OF BYTE) ;
- VAR
- s: ARRAY [0..MaxErrorString] OF CHAR ;
- BEGIN
- StringFormat1 (s, a, w) ;
- FormatError (s)
- END FormatError1 ;
- (*
- FormatError2 - generic error procedure taking standard format string
- and two parameters.
- *)
- PROCEDURE FormatError2 (a: ARRAY OF CHAR;
- w1, w2: ARRAY OF BYTE) ;
- VAR
- s: ARRAY [0..MaxErrorString] OF CHAR ;
- BEGIN
- StringFormat1 (s, a, w1) ;
- FormatError1 (s, w2)
- END FormatError2 ;
- (*
- CheckAccess - checks to see whether a file f has been
- opened for read/write.
- *)
- PROCEDURE CheckAccess (f: File; use: FileUsage; towrite: BOOLEAN) ;
- VAR
- fd: FileDescriptor ;
- BEGIN
- IF f#Error
- THEN
- fd := GetIndice (FileInfo, f) ;
- IF fd=NIL
- THEN
- IF f#StdErr
- THEN
- FormatError ('this file has probably been closed and not reopened successfully or alternatively never opened\n')
- END ;
- HALT
- ELSE
- WITH fd^ DO
- IF (use=openedforwrite) AND (usage=openedforread)
- THEN
- FormatError1 ('this file (%s) has been opened for reading but is now being written\n',
- name.address) ;
- HALT
- ELSIF (use=openedforread) AND (usage=openedforwrite)
- THEN
- FormatError1('this file (%s) has been opened for writing but is now being read\n',
- name.address) ;
- HALT
- ELSIF state=connectionfailure
- THEN
- FormatError1('this file (%s) was not successfully opened\n',
- name.address) ;
- HALT
- ELSIF towrite#output
- THEN
- IF output
- THEN
- FormatError1('this file (%s) was opened for writing but is now being read\n',
- name.address) ;
- HALT
- ELSE
- FormatError1('this file (%s) was opened for reading but is now being written\n',
- name.address) ;
- HALT
- END
- END
- END
- END
- ELSE
- FormatError('this file has not been opened successfully\n') ;
- HALT
- END
- END CheckAccess ;
- (*
- ReadChar - returns a character read from file f.
- Sensible to check with IsNoError or EOF after calling
- this function.
- *)
- PROCEDURE ReadChar (f: File) : CHAR ;
- VAR
- ch: CHAR ;
- BEGIN
- CheckAccess (f, openedforread, FALSE) ;
- IF BufferedRead (f, SIZE (ch), ADR (ch)) = VAL (INTEGER, SIZE (ch))
- THEN
- SetEndOfLine (f, ch) ;
- RETURN ch
- ELSE
- RETURN nul
- END
- END ReadChar ;
- (*
- SetEndOfLine -
- *)
- PROCEDURE SetEndOfLine (f: File; ch: CHAR) ;
- VAR
- fd: FileDescriptor ;
- BEGIN
- CheckAccess(f, openedforread, FALSE) ;
- IF f#Error
- THEN
- fd := GetIndice(FileInfo, f) ;
- WITH fd^ DO
- IF ch=nl
- THEN
- state := endofline
- ELSE
- state := successful
- END
- END
- END
- END SetEndOfLine ;
- (*
- UnReadChar - replaces a character, ch, back into file f.
- This character must have been read by ReadChar
- and it does not allow successive calls. It may
- only be called if the previous read was successful
- or end of file was seen.
- If the state was previously endoffile then it
- is altered to successful.
- Otherwise it is left alone.
- *)
- PROCEDURE UnReadChar (f: File; ch: CHAR) ;
- VAR
- fd : FileDescriptor ;
- n : CARDINAL ;
- a, b: ADDRESS ;
- BEGIN
- CheckAccess(f, openedforread, FALSE) ;
- IF f#Error
- THEN
- fd := GetIndice(FileInfo, f) ;
- WITH fd^ DO
- IF (state=successful) OR (state=endoffile) OR (state=endofline)
- THEN
- IF (buffer#NIL) AND (buffer^.valid)
- THEN
- WITH buffer^ DO
- (* we assume that a ReadChar has occurred, we will check just in case. *)
- IF state=endoffile
- THEN
- position := MaxBufferLength ;
- left := 0 ;
- filled := 0 ;
- state := successful
- END ;
- IF position>0
- THEN
- DEC(position) ;
- INC(left) ;
- contents^[position] := ch ;
- ELSE
- (* position=0 *)
- (* if possible make room and store ch *)
- IF filled=size
- THEN
- FormatError1('performing too many UnReadChar calls on file (%d)\n', f)
- ELSE
- n := filled-position ;
- b := ADR(contents^[position]) ;
- a := ADR(contents^[position+1]) ;
- a := memcpy(a, b, n) ;
- INC(filled) ;
- contents^[position] := ch ;
- END
- END
- END
- END
- ELSE
- FormatError1('UnReadChar can only be called if the previous read was successful or end of file, error on file (%d)\n', f)
- END
- END
- END
- END UnReadChar ;
- (*
- ReadAny - reads HIGH (a) + 1 bytes into, a. All input
- is fully buffered, unlike ReadNBytes and thus is more
- suited to small reads.
- *)
- PROCEDURE ReadAny (f: File; VAR a: ARRAY OF BYTE) ;
- BEGIN
- CheckAccess(f, openedforread, FALSE) ;
- IF BufferedRead (f, HIGH (a) + 1, ADR (a)) = VAL (INTEGER, HIGH (a) + 1)
- THEN
- SetEndOfLine (f, a[HIGH(a)])
- END
- END ReadAny ;
- (*
- EOF - tests to see whether a file, f, has reached end of file.
- *)
- PROCEDURE EOF (f: File) : BOOLEAN ;
- VAR
- fd: FileDescriptor ;
- BEGIN
- CheckAccess(f, openedforread, FALSE) ;
- IF f#Error
- THEN
- fd := GetIndice(FileInfo, f) ;
- IF fd#NIL
- THEN
- RETURN( fd^.state=endoffile )
- END
- END ;
- RETURN( TRUE )
- END EOF ;
- (*
- EOLN - tests to see whether a file, f, is upon a newline.
- It does NOT consume the newline.
- *)
- PROCEDURE EOLN (f: File) : BOOLEAN ;
- VAR
- ch: CHAR ;
- fd: FileDescriptor ;
- BEGIN
- CheckAccess(f, openedforread, FALSE) ;
- (*
- we will read a character and then push it back onto the input stream,
- having noted the file status, we also reset the status.
- *)
- IF f#Error
- THEN
- fd := GetIndice(FileInfo, f) ;
- IF fd#NIL
- THEN
- IF (fd^.state=successful) OR (fd^.state=endofline)
- THEN
- ch := ReadChar(f) ;
- IF (fd^.state=successful) OR (fd^.state=endofline)
- THEN
- UnReadChar(f, ch)
- END ;
- RETURN( ch=nl )
- END
- END
- END ;
- RETURN( FALSE )
- END EOLN ;
- (*
- WasEOLN - tests to see whether a file, f, has just seen a newline.
- *)
- PROCEDURE WasEOLN (f: File) : BOOLEAN ;
- VAR
- fd: FileDescriptor ;
- BEGIN
- CheckAccess(f, openedforread, FALSE) ;
- IF f=Error
- THEN
- RETURN FALSE
- ELSE
- fd := GetIndice(FileInfo, f) ;
- RETURN( (fd#NIL) AND (fd^.state=endofline) )
- END
- END WasEOLN ;
- (*
- WriteLine - writes out a linefeed to file, f.
- *)
- PROCEDURE WriteLine (f: File) ;
- BEGIN
- WriteChar(f, nl)
- END WriteLine ;
- (*
- WriteNBytes - writes nBytes from memory area src to a file
- returning the number of bytes actually written.
- This function will flush the buffer and then
- write the nBytes using a direct write from libc.
- It is ideal for large writes.
- *)
- PROCEDURE WriteNBytes (f: File; nBytes: CARDINAL; src: ADDRESS) : CARDINAL ;
- VAR
- total: INTEGER ;
- fd : FileDescriptor ;
- BEGIN
- CheckAccess(f, openedforwrite, TRUE) ;
- FlushBuffer(f) ;
- IF f#Error
- THEN
- fd := GetIndice(FileInfo, f) ;
- IF fd#NIL
- THEN
- WITH fd^ DO
- total := write(unixfd, src, INTEGER(nBytes)) ;
- IF total<0
- THEN
- state := failed ;
- RETURN( 0 )
- ELSE
- INC(abspos, CARDINAL(total)) ;
- IF buffer#NIL
- THEN
- buffer^.bufstart := abspos
- END ;
- RETURN( CARDINAL(total) )
- END
- END
- END
- END ;
- RETURN( 0 )
- END WriteNBytes ;
- (*
- BufferedWrite - will write, nBytes, through the buffer.
- Similar to WriteNBytes, but this function will always
- write into the buffer before copying into memory.
- Useful when performing small writes.
- *)
- PROCEDURE BufferedWrite (f: File; nBytes: CARDINAL; src: ADDRESS) : INTEGER ;
- VAR
- dest : ADDRESS ;
- total,
- n : INTEGER ;
- p : POINTER TO BYTE ;
- fd : FileDescriptor ;
- BEGIN
- IF f # Error
- THEN
- fd := GetIndice (FileInfo, f) ;
- IF fd#NIL
- THEN
- total := 0 ; (* how many bytes have we read *)
- WITH fd^ DO
- IF buffer # NIL
- THEN
- WITH buffer^ DO
- WHILE nBytes > 0 DO
- (* place into the buffer first *)
- IF left > 0
- THEN
- IF nBytes = 1
- THEN
- (* too expensive to call memcpy for 1 character *)
- p := src ;
- contents^[position] := p^ ;
- DEC (left) ; (* reduce space *)
- INC (position) ; (* move onwards n byte *)
- INC (total) ;
- RETURN( total )
- ELSE
- n := Min (left, nBytes) ;
- dest := address ;
- INC (dest, position) ;
- p := memcpy (dest, src, CARDINAL (n)) ;
- DEC (left, n) ; (* remove consumed bytes *)
- INC (position, n) ; (* move onwards n bytes *)
- (* move ready for further writes *)
- INC (src, n) ;
- DEC (nBytes, n) ; (* reduce the amount for future writes *)
- INC (total, n)
- END
- ELSE
- FlushBuffer (f) ;
- IF (state#successful) AND (state#endofline)
- THEN
- nBytes := 0
- END
- END
- END
- END ;
- RETURN( total )
- END
- END
- END
- END ;
- RETURN( -1 )
- END BufferedWrite ;
- (*
- FlushBuffer - flush contents of file, f.
- *)
- PROCEDURE FlushBuffer (f: File) ;
- VAR
- fd: FileDescriptor ;
- BEGIN
- IF f#Error
- THEN
- fd := GetIndice(FileInfo, f) ;
- IF fd#NIL
- THEN
- WITH fd^ DO
- IF output AND (buffer#NIL)
- THEN
- WITH buffer^ DO
- IF (position=0) OR (write(unixfd, address, position)=VAL(INTEGER, position))
- THEN
- INC(abspos, position) ;
- bufstart := abspos ;
- position := 0 ;
- filled := 0 ;
- left := size
- ELSE
- state := failed
- END
- END
- END
- END
- END
- END
- END FlushBuffer ;
- (*
- WriteAny - writes HIGH (a) + 1 bytes onto, file, f. All output
- is fully buffered, unlike WriteNBytes and thus is more
- suited to small writes.
- *)
- PROCEDURE WriteAny (f: File; VAR a: ARRAY OF BYTE) ;
- BEGIN
- CheckAccess (f, openedforwrite, TRUE) ;
- IF BufferedWrite (f, HIGH (a) + 1, ADR (a)) = VAL (INTEGER, HIGH (a) + 1)
- THEN
- END
- END WriteAny ;
- (*
- WriteChar - writes a single character to file, f.
- *)
- PROCEDURE WriteChar (f: File; ch: CHAR) ;
- BEGIN
- CheckAccess (f, openedforwrite, TRUE) ;
- IF BufferedWrite (f, SIZE (ch), ADR (ch)) = VAL (INTEGER, SIZE (ch))
- THEN
- END
- END WriteChar ;
- (*
- WriteCardinal - writes a CARDINAL to file, f.
- It writes the binary image of the cardinal
- to file, f.
- *)
- PROCEDURE WriteCardinal (f: File; c: CARDINAL) ;
- BEGIN
- WriteAny(f, c)
- END WriteCardinal ;
- (*
- ReadCardinal - reads a CARDINAL from file, f.
- It reads a binary image of a CARDINAL
- from a file, f.
- *)
- PROCEDURE ReadCardinal (f: File) : CARDINAL ;
- VAR
- c: CARDINAL ;
- BEGIN
- ReadAny(f, c) ;
- RETURN( c )
- END ReadCardinal ;
- (*
- ReadString - reads a string from file, f, into string, a.
- It terminates the string if HIGH is reached or
- if a newline is seen or an error occurs.
- *)
- PROCEDURE ReadString (f: File; VAR a: ARRAY OF CHAR) ;
- VAR
- high,
- i : CARDINAL ;
- ch : CHAR ;
- BEGIN
- CheckAccess(f, openedforread, FALSE) ;
- high := HIGH(a) ;
- i := 0 ;
- REPEAT
- ch := ReadChar(f) ;
- IF i<=high
- THEN
- IF (ch=nl) OR (NOT IsNoError(f)) OR EOF(f)
- THEN
- a[i] := nul ;
- INC(i)
- ELSE
- a[i] := ch ;
- INC(i)
- END
- END
- UNTIL (ch=nl) OR (i>high) OR (NOT IsNoError(f)) OR EOF(f)
- END ReadString ;
- (*
- SetPositionFromBeginning - sets the position from the beginning of the file.
- *)
- PROCEDURE SetPositionFromBeginning (f: File; pos: LONGINT) ;
- VAR
- offset: LONGINT ;
- fd : FileDescriptor ;
- BEGIN
- IF f#Error
- THEN
- fd := GetIndice(FileInfo, f) ;
- IF fd#NIL
- THEN
- WITH fd^ DO
- (* always force the lseek, until we are confident that abspos is always correct,
- basically it needs some hard testing before we should remove the OR TRUE. *)
- IF (abspos#pos) OR TRUE
- THEN
- FlushBuffer(f) ;
- IF buffer#NIL
- THEN
- WITH buffer^ DO
- IF output
- THEN
- left := size
- ELSE
- left := 0
- END ;
- position := 0 ;
- filled := 0
- END
- END ;
- offset := lseek (unixfd, VAL (COFF_T, pos), SeekSet ()) ;
- IF (offset>=0) AND (pos=offset)
- THEN
- abspos := pos
- ELSE
- state := failed ;
- abspos := 0
- END ;
- IF buffer#NIL
- THEN
- buffer^.valid := FALSE ;
- buffer^.bufstart := abspos
- END
- END
- END
- END
- END
- END SetPositionFromBeginning ;
- (*
- SetPositionFromEnd - sets the position from the end of the file.
- *)
- PROCEDURE SetPositionFromEnd (f: File; pos: LONGINT) ;
- VAR
- offset: LONGINT ;
- fd : FileDescriptor ;
- BEGIN
- IF f#Error
- THEN
- fd := GetIndice(FileInfo, f) ;
- IF fd#NIL
- THEN
- WITH fd^ DO
- FlushBuffer(f) ;
- IF buffer#NIL
- THEN
- WITH buffer^ DO
- IF output
- THEN
- left := size
- ELSE
- left := 0
- END ;
- position := 0 ;
- filled := 0
- END
- END ;
- offset := lseek (unixfd, VAL (COFF_T, pos), SeekEnd ()) ;
- IF offset>=0
- THEN
- abspos := offset ;
- ELSE
- state := failed ;
- abspos := 0 ;
- offset := 0
- END ;
- IF buffer#NIL
- THEN
- buffer^.valid := FALSE ;
- buffer^.bufstart := offset
- END
- END
- END
- END
- END SetPositionFromEnd ;
- (*
- FindPosition - returns the current absolute position in file, f.
- *)
- PROCEDURE FindPosition (f: File) : LONGINT ;
- VAR
- fd: FileDescriptor ;
- BEGIN
- IF f#Error
- THEN
- fd := GetIndice(FileInfo, f) ;
- IF fd#NIL
- THEN
- WITH fd^ DO
- IF (buffer=NIL) OR (NOT buffer^.valid)
- THEN
- RETURN( abspos )
- ELSE
- WITH buffer^ DO
- RETURN( bufstart+VAL(LONGINT, position) )
- END
- END
- END
- END
- END ;
- RETURN( 0 )
- END FindPosition ;
- (*
- GetFDesc - return the file descriptor associated with File name, fname
- *)
- PROCEDURE GetFDesc (fname : ARRAY OF CHAR ) : File;
- VAR
- i : CARDINAL;
- fd : File;
- name : ARRAY[0..256] OF CHAR;
- BEGIN
- FOR i := LowIndice(FileInfo) TO HighIndice(FileInfo) DO
- fd := GetIndice (FileInfo, i);
- GetFileName(fd, name);
- IF Strings.Compare (fname,name) = equal THEN
- RETURN fd
- END;
- END;
- RETURN NIL
- END GetFDesc;
- (*
- GetFileName - assigns, a, with the filename associated with, f.
- *)
- PROCEDURE GetFileName (f: File; VAR a: ARRAY OF CHAR) ;
- VAR
- i : CARDINAL ;
- p : POINTER TO CHAR ;
- fd: FileDescriptor ;
- BEGIN
- IF f#Error
- THEN
- fd := GetIndice(FileInfo, f) ;
- IF fd=NIL
- THEN
- FormatError('this file has probably been closed and not reopened successfully or alternatively never opened\n') ;
- HALT
- ELSE
- WITH fd^.name DO
- IF address=NIL
- THEN
- StrCopy('', a)
- ELSE
- p := address ;
- i := 0 ;
- WHILE (p^#nul) AND (i<=HIGH(a)) DO
- a[i] := p^ ;
- INC(p) ;
- INC(i)
- END
- END
- END
- END
- END
- END GetFileName ;
- (*
- getFileName - returns the address of the filename associated with, f.
- *)
- PROCEDURE getFileName (f: File) : ADDRESS ;
- VAR
- fd: FileDescriptor ;
- BEGIN
- IF f#Error
- THEN
- fd := GetIndice(FileInfo, f) ;
- IF fd=NIL
- THEN
- FormatError('this file has probably been closed and not reopened successfully or alternatively never opened\n') ;
- HALT
- ELSE
- RETURN fd^.name.address
- END
- END ;
- RETURN NIL
- END getFileName ;
- (*
- getFileNameLength - returns the number of characters associated with filename, f.
- *)
- PROCEDURE getFileNameLength (f: File) : CARDINAL ;
- VAR
- fd: FileDescriptor ;
- BEGIN
- IF f#Error
- THEN
- fd := GetIndice(FileInfo, f) ;
- IF fd=NIL
- THEN
- FormatError('this file has probably been closed and not reopened successfully or alternatively never opened\n') ;
- HALT
- ELSE
- RETURN fd^.name.size
- END
- END ;
- RETURN 0
- END getFileNameLength ;
- (*
- PreInitialize - preinitialize the file descriptor.
- *)
- PROCEDURE PreInitialize (f: File; fname: ARRAY OF CHAR;
- state: FileStatus; use: FileUsage;
- towrite: BOOLEAN; osfd: INTEGER; bufsize: CARDINAL) ;
- VAR
- fd, fe: FileDescriptor ;
- BEGIN
- IF InitializeFile(f, ADR(fname), StrLen(fname), state, use, towrite, bufsize)=f
- THEN
- fd := GetIndice(FileInfo, f) ;
- IF f=Error
- THEN
- fe := GetIndice(FileInfo, StdErr) ;
- IF fe=NIL
- THEN
- HALT
- ELSE
- fd^.unixfd := fe^.unixfd (* the error channel *)
- END
- ELSE
- fd^.unixfd := osfd
- END
- ELSE
- HALT
- END
- END PreInitialize ;
- (*
- FlushOutErr - flushes, StdOut, and, StdErr.
- It is also called when the application calls M2RTS.Terminate.
- (which is automatically placed in program modules by the GM2
- scaffold).
- *)
- PROCEDURE FlushOutErr ;
- BEGIN
- IF IsNoError(StdOut)
- THEN
- FlushBuffer(StdOut)
- END ;
- IF IsNoError(StdErr)
- THEN
- FlushBuffer(StdErr)
- END
- END FlushOutErr ;
- (*
- Init - initialize the modules, global variables.
- *)
- PROCEDURE Init ;
- BEGIN
- FileInfo := InitIndex(0) ;
- Error := 0 ;
- PreInitialize(Error , 'error' , toomanyfilesopen, unused , FALSE, -1, 0) ;
- StdIn := 1 ;
- PreInitialize(StdIn , '<stdin>' , successful , openedforread , FALSE, 0, MaxBufferLength) ;
- StdOut := 2 ;
- PreInitialize(StdOut , '<stdout>', successful , openedforwrite, TRUE, 1, MaxBufferLength) ;
- StdErr := 3 ;
- PreInitialize(StdErr , '<stderr>', successful , openedforwrite, TRUE, 2, MaxBufferLength) ;
- IF NOT InstallTerminationProcedure(FlushOutErr)
- THEN
- HALT
- END
- END Init ;
- BEGIN
- Init
- FINALLY
- FlushOutErr
- END FIO.
|