| 1 | #\f |
| 2 | # 35iosubs.s |
| 3 | # |
| 4 | # IO SUBROUTINES |
| 5 | # |
| 6 | .globl _getname #activate a file |
| 7 | .globl _unit #establish active file |
| 8 | .globl _iosync #syncronize a file window |
| 9 | .globl _unsync #push backed synced record for formatted read |
| 10 | .globl _pflush #flush all active files |
| 11 | .globl _pclose #close selected files |
| 12 | .globl _pmflush #flush pxp buffer |
| 13 | # |
| 14 | # system I/O routines |
| 15 | # |
| 16 | .globl _fclose |
| 17 | .globl _fflush |
| 18 | .globl _fopen |
| 19 | .globl _fprintf |
| 20 | .globl _fputc |
| 21 | .globl _fread |
| 22 | .globl _fscanf |
| 23 | .globl _fwrite |
| 24 | .globl _mktemp |
| 25 | .globl _rewind |
| 26 | .globl _sscanf |
| 27 | .globl _ungetc |
| 28 | .globl _unlink |
| 29 | # |
| 30 | # standard files |
| 31 | # |
| 32 | # file records |
| 33 | # |
| 34 | .set fnamesze,76 #maximum size of file name |
| 35 | .set recsze,30+fnamesze #file record size |
| 36 | .set FNAME,-recsze #name of associated UNIX file |
| 37 | .set LCOUNT,-30 #number of lines of output |
| 38 | .set LLIMIT,-26 #maximum number of text lines |
| 39 | .set FBUF,-22 #FILE pointer |
| 40 | .set FCHAIN,-18 #chain to next file |
| 41 | .set FLEV,-14 #ptr to associated file variable |
| 42 | .set PFNAME,-10 #ptr to name of error msg file |
| 43 | .set FUNIT,-6 #file status flags |
| 44 | .set FSIZE,-4 #size of elements in the file |
| 45 | .set WINDOW,0 #file window element |
| 46 | # |
| 47 | # unit flags |
| 48 | # |
| 49 | .set FDEF,0x8000 #1 => reserved file name |
| 50 | .set FTEXT,0x4000 #1 => text file, process EOLN |
| 51 | .set FWRITE,0x2000 #1 => open for writing |
| 52 | .set FREAD,0x1000 #1 => open for reading |
| 53 | .set TEMP,0x0800 #1 => temporary file |
| 54 | .set SYNC,0x0400 #1 => window is out of sync |
| 55 | .set EOLN,0x0200 #1 => at end of line |
| 56 | .set EOF,0x0100 #1 => at end of file |
| 57 | # |
| 58 | # bit positions of unit flags |
| 59 | # |
| 60 | .set fDEF,15 |
| 61 | .set fTEXT,14 |
| 62 | .set fWRITE,13 |
| 63 | .set fREAD,12 |
| 64 | .set fTEMP,11 |
| 65 | .set fSYNC,10 |
| 66 | .set fEOLN,9 |
| 67 | .set fEOF,8 |
| 68 | # |
| 69 | # standard file buffers |
| 70 | # |
| 71 | .set ioEOF,4 #bit position flagging EOF |
| 72 | .set ioERR,5 #bit position flagging I/O error |
| 73 | .set FLAG,12 #record offset of error flag |
| 74 | # |
| 75 | # standard input file |
| 76 | # |
| 77 | .data |
| 78 | .space fnamesze #name of associated UNIX file |
| 79 | .long 0 #line count |
| 80 | .long 0 #line limit |
| 81 | .long __iob #FILE pointer |
| 82 | .long stdout #chain to next file |
| 83 | .long 0 #ptr to associated file variable |
| 84 | .long sinnam #ptr to name of error msg file |
| 85 | .word FTEXT+FREAD+SYNC #file status flags |
| 86 | .long 1 #size of elements in the file |
| 87 | stdin: |
| 88 | .word 0 #file window element |
| 89 | # |
| 90 | # standard output file |
| 91 | # |
| 92 | .space fnamesze #name of associated UNIX file |
| 93 | .long 0 #line count |
| 94 | .long 0 #line limit |
| 95 | .long __iob+16 #FILE pointer |
| 96 | .long stderr #chain to next file |
| 97 | .long 0 #ptr to associated file variable |
| 98 | .long soutnam #ptr to name of error msg file |
| 99 | .word FTEXT+FWRITE+EOF #file status flags |
| 100 | .long 1 #size of elements in the file |
| 101 | stdout: |
| 102 | .word 0 #file window element |
| 103 | # |
| 104 | # standard error file |
| 105 | # |
| 106 | .space fnamesze #name of associated UNIX file |
| 107 | .long 0 #line count |
| 108 | .long 0 #line limit |
| 109 | .long __iob+32 #FILE pointer |
| 110 | .long 0 #chain to next file |
| 111 | .long 0 #ptr to associated file variable |
| 112 | .long msgnam #ptr to name of error msg file |
| 113 | .word FTEXT+FWRITE #file status flags |
| 114 | .long 1 #size of elements in the file |
| 115 | stderr: |
| 116 | .word 0 #file window element |
| 117 | |
| 118 | tmpname:.byte 't,'m,'p,'.,'X,'X,'X,'X,'X,'X, 0 |
| 119 | .text |
| 120 | sinnam: .byte 's,'t,'a,'n,'d,'a,'r,'d,' ,'i,'n,'p,'u,'t, 0 |
| 121 | soutnam:.byte 's,'t,'a,'n,'d,'a,'r,'d,' ,'o,'u,'t,'p,'u,'t, 0 |
| 122 | msgnam: .byte 'M,'e,'s,'s,'a,'g,'e,' ,'f,'i,'l,'e, 0 |
| 123 | monout: .byte 'p,'m,'o,'n,'.,'o,'u,'t, 0 |
| 124 | rdopen: .byte 'r, 0 |
| 125 | wtopen: .byte 'w, 0 |
| 126 | .set formfeed,12 |
| 127 | .set linefeed,10 |
| 128 | .set blank,' |
| 129 | # |
| 130 | # getname |
| 131 | # |
| 132 | # takes the width of a string in the subopcode and |
| 133 | # returns a pointer to a file structure in r0 |
| 134 | # |
| 135 | # there should be a string on the stack |
| 136 | # of length the contents of subopcode on top of |
| 137 | # a pointer to the file variable |
| 138 | # |
| 139 | # a new file structure is allocated if needed |
| 140 | # temporary names are generated, and given |
| 141 | # names are blank trimmed |
| 142 | # |
| 143 | # if a new file buffer is allocated, the address |
| 144 | # is stored in the file variable. |
| 145 | # |
| 146 | # |
| 147 | _getname: |
| 148 | .word R6|R7|R8|R9|R11 |
| 149 | cvtbl (r10)+, r8 # r8 has file name length |
| 150 | moval 4(ap), r9 # r9 will point to cleared stack |
| 151 | addl2 r8, r9 |
| 152 | blbc r9,l3501 |
| 153 | incl r9 |
| 154 | l3501: |
| 155 | movl ( r9)+, r11 # r11 pts to file variable |
| 156 | tstl ( r11) #check for existing file record |
| 157 | bneq gotone |
| 158 | # |
| 159 | # allocate and initialize a new file record |
| 160 | # |
| 161 | clrl r7 # r7 has status flags |
| 162 | cvtwl (r10)+,r6 #r6 has data size |
| 163 | bneq l3502 |
| 164 | movw $FTEXT, r7 #default to text file |
| 165 | movl $1,r6 #default size |
| 166 | l3502: |
| 167 | addl3 $recsze,r6,-(sp)#size of record |
| 168 | calls $1,_palloc #r0 points to allocated buffer |
| 169 | addl2 $recsze,r0 #adjust to base of record |
| 170 | l3503: |
| 171 | clrl LCOUNT(r0) #set default line limits |
| 172 | movl _llimit,LLIMIT(r0) |
| 173 | movw r7,FUNIT(r0) #set flags |
| 174 | movl r6,FSIZE(r0) #set size |
| 175 | movl r11,FLEV(r0) #set ptr to file variable |
| 176 | movl r0,( r11) #set file var ptr |
| 177 | # |
| 178 | # link the new record into the file chain |
| 179 | # |
| 180 | movl $_fchain-FCHAIN,r6 #r6 pts to "previous" record |
| 181 | movl _fchain,r1 #r1 pts to "next" record |
| 182 | brb l3505 |
| 183 | l3504: |
| 184 | movl r1,r6 #advance previous |
| 185 | movl FCHAIN(r1),r1 #get next |
| 186 | l3505: |
| 187 | cmpl FLEV(r1), r11 #check level |
| 188 | blssu l3504 #continue until greater |
| 189 | |
| 190 | movl r1,FCHAIN(r0) #link in new record |
| 191 | movl r0,FCHAIN(r6) |
| 192 | |
| 193 | movl r0, r11 # r11 points to file record |
| 194 | jbr setname |
| 195 | # |
| 196 | # have a previous buffer, dispose of associated file |
| 197 | # |
| 198 | gotone: |
| 199 | addl2 $2,r10 #discard data size |
| 200 | movl ( r11), r11 # r11 points to file record |
| 201 | bicw2 $~(FDEF+TEMP+FTEXT),FUNIT( r11) #clear status flags |
| 202 | bbc $fDEF,FUNIT( r11),l3506 #check for predefined file |
| 203 | bicw2 $FDEF,FUNIT( r11) #clear predefined flag |
| 204 | jbr setname |
| 205 | l3506: |
| 206 | pushl FBUF( r11) #flush and close previous file |
| 207 | calls $1,_fclose |
| 208 | movl FBUF( r11),r0 |
| 209 | bbs $ioERR,FLAG(r0),eclose |
| 210 | bbc $fTEMP,FUNIT( r11),setname #check for temp file |
| 211 | tstl r8 #remove renamed temp files |
| 212 | beql setname |
| 213 | pushl PFNAME( r11) |
| 214 | calls $1,_unlink |
| 215 | tstl r0 #check for remove error |
| 216 | beql setname |
| 217 | movl PFNAME( r11),_file |
| 218 | movw $EREMOVE,_perrno |
| 219 | moval error,PC(fp) #error return |
| 220 | ret |
| 221 | eclose: |
| 222 | movl PFNAME( r11),_file |
| 223 | movw $ECLOSE,_perrno |
| 224 | moval error,PC(fp) #error return |
| 225 | ret |
| 226 | # |
| 227 | # get the filename associated with the buffer |
| 228 | # |
| 229 | setname: |
| 230 | tstl r8 #check for a given name |
| 231 | bneq l3508 #br => has a name |
| 232 | tstb FNAME( r11) #check for no current name |
| 233 | bneq l3513 #br => had a previous name so use it |
| 234 | # |
| 235 | # no name given and no previous name, so generate |
| 236 | # a new one of the form tmp.xxxxxx |
| 237 | # |
| 238 | bisw2 $TEMP,FUNIT( r11)#set status to temporary |
| 239 | pushal tmpname #get a unique temp name |
| 240 | calls $1,_mktemp |
| 241 | movl $13, r8 #max length of temp name |
| 242 | brb l3511 |
| 243 | # |
| 244 | # name is given, strip trailing blanks |
| 245 | # |
| 246 | l3508: |
| 247 | bicw2 $TEMP,FUNIT( r11)#set permanent status |
| 248 | moval 4(ap),r0 #r0 pts to end of file name |
| 249 | addl3 r8,r0,r1 #r1 pts to end of name |
| 250 | l3509: |
| 251 | cmpb -(r1),$blank #delete trailing blanks |
| 252 | bneq l3511 #(note: could use "scanc" with source |
| 253 | clrb (r1) # and table reversed) |
| 254 | sobgtr r8,l3509 |
| 255 | # |
| 256 | # put the new name into the structure |
| 257 | # |
| 258 | l3511: |
| 259 | cmpl r8,$fnamesze #check for name too long |
| 260 | blss l3512 |
| 261 | movw $ENAMESIZE,_perrno |
| 262 | moval error,PC(fp) #error return |
| 263 | ret |
| 264 | l3512: |
| 265 | movc3 r8,(r0),FNAME( r11) #move name into record |
| 266 | clrb FNAME( r11)[ r8] #place null char after name |
| 267 | moval FNAME( r11),PFNAME( r11) #set pointer to name |
| 268 | l3513: |
| 269 | movl r9,r1 #return ptr to updated stack |
| 270 | movl r11,r0 #return ptr to file record |
| 271 | ret |
| 272 | # |
| 273 | # unit establishes a new active file |
| 274 | # |
| 275 | _unit: |
| 276 | .word 0 |
| 277 | movl 4(ap),r7 |
| 278 | beql erefinaf |
| 279 | bbs $fDEF,FUNIT(r7),erefinaf |
| 280 | movl PFNAME(r7),_file |
| 281 | cmpl r7,$stdin #flush stdout if activating stdin |
| 282 | bneq l3523 |
| 283 | cmpw _bufopt,$1 # and stdout is line buffered |
| 284 | bneq l3523 |
| 285 | pushl stdout+FBUF |
| 286 | calls $1,_fflush |
| 287 | l3523: |
| 288 | ret |
| 289 | erefinaf: |
| 290 | movw $EREFINAF,_perrno |
| 291 | moval error,PC(fp) #error return |
| 292 | ret |
| 293 | # |
| 294 | # iosync insures that a useable image is in the buffer window |
| 295 | # |
| 296 | _iosync: |
| 297 | .word R6 |
| 298 | cvtwl FUNIT(r7),r6 #r6 has FUNIT flags |
| 299 | bbc $fREAD,r6,eread #error if not open for reading |
| 300 | bbc $fSYNC,r6,l3515 #check for already synced |
| 301 | bbs $fEOF,r6,epeof #error if past EOF |
| 302 | bicw2 $SYNC,r6 #clear unsynced flag |
| 303 | pushl FBUF(r7) #stream |
| 304 | pushl $1 #number of items to read |
| 305 | pushl FSIZE(r7) #data size |
| 306 | pushl r7 #ptr to input window |
| 307 | calls $4,_fread |
| 308 | movl FBUF(r7),r0 #check for EOF |
| 309 | bbs $ioERR,FLAG(r0),epeof |
| 310 | bbs $ioEOF,FLAG(r0),eof |
| 311 | bbc $fTEXT,r6,l3514 #check for text processing |
| 312 | bicw2 $EOLN,r6 #check for EOLN |
| 313 | cmpb (r7),$linefeed |
| 314 | bneq l3514 |
| 315 | movb $blank,(r7) #blank out linefeed |
| 316 | bisw2 $EOLN,r6 |
| 317 | l3514: |
| 318 | movw r6,FUNIT(r7) #update status flags |
| 319 | l3515: |
| 320 | ret |
| 321 | eof: |
| 322 | bisw2 $EOF,r6 #set EOF |
| 323 | movw r6,FUNIT(r7) #update status flags |
| 324 | pushr $R2|R3|R4|R5 #save registers |
| 325 | movc5 $0,(r0),$0,FSIZE(r7),(r7) #clear buffer to undefined |
| 326 | popr $R2|R3|R4|R5 #restore registers |
| 327 | ret |
| 328 | eread: |
| 329 | movw $EREADIT,_perrno |
| 330 | moval error,PC(fp) #error return |
| 331 | ret |
| 332 | epeof: |
| 333 | movw $EPASTEOF,_perrno |
| 334 | moval error,PC(fp) #error return |
| 335 | ret |
| 336 | # |
| 337 | # push back last char read to prepare for formatted read |
| 338 | # |
| 339 | _unsync: |
| 340 | .word 0 |
| 341 | bbc $fREAD,FUNIT(r7),eread #error if not open for reading |
| 342 | bbs $fSYNC,FUNIT(r7),l3526 #push back window char |
| 343 | pushl FBUF(r7) |
| 344 | cvtbl (r7),-(sp) |
| 345 | calls $2,_ungetc |
| 346 | l3526: |
| 347 | ret |
| 348 | # |
| 349 | # flush all active output files |
| 350 | # |
| 351 | _pflush: |
| 352 | .word R6 |
| 353 | movl _fchain,r6 |
| 354 | beql l3518 |
| 355 | l3516: |
| 356 | bbc $fWRITE,FUNIT(r6),l3517 |
| 357 | pushl FBUF(r6) |
| 358 | calls $1,_fflush |
| 359 | l3517: |
| 360 | movl FCHAIN(r6),r6 |
| 361 | bneq l3516 |
| 362 | l3518: |
| 363 | ret |
| 364 | # |
| 365 | # close all active files down to the specified FLEV |
| 366 | # |
| 367 | _pclose: |
| 368 | .word R6|R7 |
| 369 | movl _fchain, r7 |
| 370 | beql l3520 |
| 371 | l3519: |
| 372 | cmpl FLEV( r7),4(ap) |
| 373 | bgtru l3520 |
| 374 | bbs $fDEF,FUNIT( r7),l3525 |
| 375 | movl FBUF( r7),r6 |
| 376 | pushl r6 |
| 377 | calls $1,_fclose |
| 378 | jbs $ioERR,FLAG(r6),eclose |
| 379 | l3525: |
| 380 | subl3 $recsze, r7,-(sp) |
| 381 | movl FCHAIN( r7), r7 |
| 382 | calls $1,_pfree |
| 383 | tstl r7 |
| 384 | bneq l3519 |
| 385 | l3520: |
| 386 | movl r7,_fchain |
| 387 | ret |
| 388 | # |
| 389 | # write out the pxp data |
| 390 | # |
| 391 | _pmflush: |
| 392 | .word R6 |
| 393 | tstl _pxpbuf |
| 394 | beql l3521 |
| 395 | pushal wtopen |
| 396 | pushal monout |
| 397 | calls $2,_fopen |
| 398 | tstl r0 |
| 399 | beql l3522 |
| 400 | movl r0,r6 |
| 401 | pushl r6 |
| 402 | pushl $1 |
| 403 | pushl _pxpsize |
| 404 | pushl _pxpbuf |
| 405 | calls $4,_fwrite |
| 406 | bbs $ioERR,FLAG(r6),l3522 |
| 407 | pushl r6 |
| 408 | calls $1,_fclose |
| 409 | bbs $ioERR,FLAG(r6),l3522 |
| 410 | l3521: |
| 411 | ret |
| 412 | l3522: |
| 413 | pushal monout |
| 414 | calls $1,_perror |
| 415 | ret |