|
|
1.1 root 1: #
2: # Operating System Interface to Berkeley VAX/UNIX
3: # for
4: # Macro SPITBOL V3.5
5: # -----------------------------------------------
6: #
7: # Copyright 1982
8: # Dewar Information Systems Corporation
9: # 221 West Lake Street
10: # Oak Park, Illinois 60302
11: #
12: # this operating system interface, commonly referred to as osint,
13: # provides the Macro SPITBOL compiler with a means to do all i/o
14: # and other OS dependent activities.
15: #
16: # osint is composed of one medium sized assembly module, with
17: # multiple entry points, and a collection of c functions. the
18: # entire interface is not in c due to the compiler's use of
19: # registers to pass parameters and other technicalities. all
20: # entries, except for sbchk, have five letter names starting
21: # with sys.
22: #
23: # when spitbol first starts execution, control passes to function
24: # main, just like in a normal c program. main processes any options
25: # and does other initialization chores. after completing
26: # initialization, main jumps to label sec04 to start
27: # the compiler itself. from that point, the compiler makes calls
28: # to sysxx routines to get service.
29: #
30: # the c functions are called from this module to do most of the
31: # hard and/or unix dependent work. an effort has been made to
32: # do all the system calls from c functions. this goal has not
33: # been entirely achieved.
34: #
35: #
36: # register masks
37: #
38: .set mr0,1
39: .set mr1,2
40: .set mr2,4
41: .set mr3,8
42: .set mr4,16
43: .set mr5,32
44: .set mr6,64
45: .set mr7,128
46: .set mr8,256
47: .set mr9,512
48: .set mr10,1024
49: .set mr11,2048
50: #
51: # c functions assume that r0 -> r5 are scratch. however, spitbol
52: # uses r2, r3, and r5. so, need to save these registers across
53: # function calls.
54: #
55: .set mr235,mr2+mr3+mr5
56: #
57: # mask for all registers used by compiler. necessary for dealing
58: # with load modules.
59: #
60: .set cmpreg,mr2+mr3+mr5+mr6+mr7+mr8+mr9+mr10
61: #
62: # miscellaneous equates
63: #
64: .set ch$lk,107 # upper case letter k
65: .set ch$mn,45 # dash (minus sign)
66: .set k,1024
67: .set kwords,k*4
68: #
69: # internal spitbol blocks
70: # -----------------------
71: #
72: # these equates describe compiler control blocks used by osint.
73: #
74: # chain of file control blocks
75: #
76: .set chtyp,0 # type word
77: .set chlen,4 # block length
78: .set chnxt,8 # -> next chblk
79: .set chfcb,12 # -> fcb
80: .set chsize,16 # size of chblk
81: #
82: # icblk - integer block
83: #
84: .set ictyp,0 # type word
85: .set icval,4 # integer value
86: #
87: # scblk - string block
88: #
89: .set sctyp,0 # type word
90: .set sclen,4 # string length
91: .set scstr,8 # start of string
92: #
93: # interface control blocks
94: # ------------------------
95: #
96: # these control blocks are built by the interface to handle i/o.
97: # for files other than standard input, standard output, and the
98: # terminal, these control blocks reside in the compiler's
99: # dynamic area. this requires appropriate setting of the type
100: # words to allow proper garbage collection.
101: #
102: # blocks with type b$xnt contain non-relocatable addresses - that
103: # is, no word may contain a pointer to another block in the
104: # dynamic area.
105: #
106: # blocks with type b$xrt contain relocatable addresses - that is
107: # words may contain a pointer to another block in the dynamic area.
108: #
109: # the basic structure is:
110: #
111: # for each input or output associated file there is:
112: #
113: # 1 ioblk containing all global information about
114: # the file: filename, buffer block pointer,
115: # file descriptor number, flags
116: #
117: # 1 bfblk containing the file buffer
118: #
119: # 1 or more fcblks containing the access mode (line or
120: # raw), the record length, and a pointer to
121: # the ioblk
122: #
123: # the first INPUT() or OUTPUT() call for a file creates one block
124: # of each type. subsequent calls to INPUT() or OUTPUT() for a
125: # previously associated file, may cause the creation of a new fcblk.
126: # allowing multiple fcblks provides the program with different
127: # ways of accessing the same file. for example, one type of access
128: # can be a character at a time and another entire records.
129: #
130: # the compiler keeps track of all active fcblks, and at times
131: # like end-of-job provides the inteface with a chain of all fcblks.
132: #
133: #
134: # bfblk - i/o buffer control block
135: #
136: .set bftyp,0 # type word - b$xnt
137: .set bflen,4 # block length
138: .set bfsiz,8 # buffer size in bytes
139: .set bfrem,12 # bytes remaining
140: .set bfoff,16 # offset to next remaining byte
141: .set bfsize,20 # end of fixed portion
142: #
143: # fcblk - file control block
144: #
145: .set fctyp,0 # type word - b$xrt
146: .set fclen,4 # block length
147: .set fcrsz,8 # record size ( >0 line mode / <0 raw mode)
148: .set fciob,12 # -> ioblk
149: .set fcsize,16 # size of fcblk
150: #
151: # ioblk - i/o control block
152: #
153: .set iotyp,0 # type word - b$xrt
154: .set iolen,4 # block length
155: .set iofnm,8 # -> filename scblk
156: .set iopid,12 # pid (if one end of pipe)
157: .set iobuf,16 # -> bfblk
158: .set iofdn,20 # file descriptor number
159: .set ioflg,24 # flags
160: .set iosize,28 # size of ioelt
161: #
162: # defines that match "spitio.h" for flags in ioflg
163: #
164: .set IO_INP,1 # input associated
165: .set IO_OUP,2 # output associated
166: .set IO_APP,4 # output open for append
167: .set IO_OPN,8 # file is open
168: .set IO_EOF,16 # eof on input file
169: .set IO_ERR,32 # i/o error
170: .set IO_SYS,64 # this is an osint file
171: .set IO_WRC,128 # don't do buffering
172: .set IO_PIP,256 # this is one end of a pipe
173: .set IO_DED,512 # other end of pipe died
174: .set IO_ILL,1024 # i/o illegal according to sysfc
175: #
176: # osint( argc,argv,environ ) is called just like the main
177: # function of a c program.
178: #
179: .globl _main
180: _main: .word 0
181: #
182: # normal start - process all command arguments.
183: #
184: movl 4(ap),r4 # get number of options
185: movl r4,argc # and save
186: movl 8(ap),r6 # -> option pointers
187: movl r6,argv # and save
188: #
189: # if this is a restart from an load module, go handle.
190: #
191: tstl lmodstk # if load module stack != 0 then
192: jnequ rstart # go handle
193: #
194: tstl (r6)+ # program name not interesting
195: brb gtcont # process other args
196: gtarg: movl (r6)+,r0 # -> option text
197: cmpb $ch$mn,(r0) # if no leading - then
198: bnequ gtinp # treat as input filename
199: incl r0 # bump over -
200: 1: movb (r0)+,curopt+1 # set option character in table
201: movl $opttbl,r1 # -> option table
202: 2: cmpl curopt,(r1) # if we have found it then
203: beqlu 3f # process it
204: addl2 $optsiz,r1 # -> next table entry
205: brb 2b # loop until found
206: 3: movl optrtn(r1),r11 # -> option routine
207: jsb (r11) # call option routine
208: 4: tstb (r0) # if char is binary zeros then
209: beqlu gtcont # done with this arg
210: cmpb $040,(r0) # if next char is blank then
211: bnequ 5f
212: incl r0 # ignore it
213: brb 4b # and check next char
214: 5: cmpb $ch$mn,(r0) # if next char is not - then
215: bnequ 1b # treat as option character
216: incl r0 # else skip over -
217: brb 1b # and treat next char as option
218: gtinp: jsb optinp # process input filename(s)
219: gtcont: sobgtr r4,gtarg # loop thru all options
220: #
221: # switch to proper input file
222: #
223: pushl inpptr
224: pushl inpcnt
225: calls $2,_swcinp
226: #
227: # call to do initial switch of output files.
228: #
229: pushl oupptr
230: calls $1,_swcoup
231: #
232: # see if standard output is tty or not.
233: #
234: pushl $1 # file descriptor 1
235: calls $1,_testty # call to check i/o chcaracteristics
236: tstl r0 # if r0 not 0 then
237: bnequ 0f # not a tty
238: clrl lnsppg # reset # lines per page
239: bisl2 $prtich,sptflg # else tell compiler
240: 0:
241: #
242: # set signals for execution
243: #
244: .globl _setsigs
245: calls $0,_setsigs # trap overflow signals
246: #
247: # allocate initial dynamic memory
248: #
249: mull3 meminc,$4,meminb# convert meminc to bytes
250: pushl meminb # memory request increment
251: calls $1,_sbrk # call to system call
252: movl r0,basmem # save base of memory
253: addl3 r0,meminb,topmem# computer top of memory
254: mull3 datwds,$4,r1 # convert max data words to bytes
255: addl3 r0,r1,maxmem # computer top of memory
256: 0: clrl (r0)+ # clear initial allocation
257: cmpl r0,topmem # loop until all cleared
258: blssu 0b
259: #
260: # set up lowest legal sp value, so that stack overflow can be detected,
261: #
262: mull3 $4,stksiz,r0 # convert words to bytes
263: subl3 r0,sp,lowsp # and compute lowest sp
264: movl sp,initsp # save initial sp
265: #
266: # clear registers, set dynamic area pointers, and jump off
267: # to compiler
268: #
269: clrl r2
270: clrl r3
271: clrl r4
272: clrl r5
273: clrl r6
274: clrl r7
275: clrl r8
276: movl basmem,r9
277: subl3 $4,topmem,r10
278: jmp sec04
279: #
280: # here to restart program after EXIT() call. this means we are now
281: # executing from an a.out file created by the interface.
282: #
283: rstart:
284: #
285: # before restoring stack, set up values for proper checking of
286: # stack overflow. (initial sp here will most probably differ
287: # from initial sp when compile was done.)
288: #
289: mull3 $4,stksiz,r0 # convert words to bytes
290: subl3 r0,sp,lowsp # and compute lowest sp
291: movl sp,initsp # save initial sp
292: jsb streloc # relocate pointers into stack
293: #
294: # restore stack from tscblk.
295: #
296: movl lmodstk,r0 # -> bottom word of stack
297: movab tscblk+scstr,r1 # -> top word of stack
298: 0: movl -(r0),-(sp) # relocate word of stack
299: cmpl r0,r1 # if not at end of relocation then
300: bgtru 0b # loop back
301: #
302: # if restarting, we can always access the command line arguments
303: #
304: movl $1,cmdcnt
305: #
306: # the system break will not be what it should, so reset it
307: #
308: pushl topmem
309: calls $1,_brk
310: #
311: # reset signals to what they should be.
312: #
313: calls $0,_setsigs
314: #
315: # forget about files open during compilation -
316: #
317: clrl inpptr # no input files
318: clrl inpcnt # so count is 0 too
319: clrl oupptr # no output file
320: clrl errfdn # no error file
321: #
322: # reset standard input buffer
323: #
324: clrl inpbf+bfrem # no remaining chars
325: clrl inpbf+bfoff # offset to next char
326: #
327: # restore compiler's registers and off we go.
328: #
329: popr $cmpreg # restore compiler's registers
330: addl2 $8,(sp)
331: rsb
332: #
333: # sbchk is called by the compiler to check for stack overflow.
334: #
335: .globl sbchk
336: sbchk: cmpl sp,lowsp # if sp is ok then
337: blssu 0f
338: rsb # return
339: 0: tstl (sp)+ # else pop stack
340: jmp sec05 # and go to stack overflow section
341: #
342: # unsupported entries that simply return.
343: #
344: .globl sysdc
345: sysdc:
346: .globl sysdm
347: sysdm:
348: .globl systt
349: systt:
350: .globl sysul
351: sysul:
352: rsb
353: #
354: # unsupported that take error returns
355: #
356: .globl sysex
357: sysex:
358: .globl sysld
359: sysld:
360: pushr $mr235 # save ye registers
361: jbr erxit1
362: #
363: # sysax - after execution call
364: #
365: # sysax is called immediately after execution, so that the interface
366: # can do any cleanup. here, the standard output file is switched, if
367: # necessary back to the listing file.
368: #
369: .globl sysax
370: sysax:
371: pushr $mr235
372: pushl oupptr
373: calls $1,_swcoup
374: popr $mr235
375: rsb
376: #
377: # sysbx - before execution call
378: #
379: # sysbx is called after compilation and before execution begins.
380: # sysbx allows the inteface to do any cleanup. here, the standard
381: # listing file is switched to the standard output file.
382: #
383: .globl sysbx
384: sysbx:
385: pushr $mr235
386: pushl oupptr
387: calls $1,_swcoup
388: popr $mr235
389: rsb
390: #
391: # sysdt - get current date
392: #
393: # return both date and time
394: #
395: # jsb sysdt # call to get date
396: # (r10) # -> scblk
397: #
398: .globl sysdt
399: sysdt:
400: pushr $mr235
401: movl $tscblk,r10
402: movl $17,sclen(r10) # dd/mm/yy hh.mm.ss
403: pushl $tscblk+scstr
404: calls $1,_getdate
405: popr $mr235
406: rsb
407: #
408: # sysef - eject file
409: #
410: .globl sysef
411: sysef:
412: pushr $mr235
413: pushl fciob(r6) # -> ioblk
414: calls $1,_osopen # call to do open
415: tstl r0 # if open error then
416: jnequ erxit1 # take error exit
417: pushl $ffscb # -> ff scblk
418: pushl fciob(r6) # -> ioblk
419: pushl ffscb+sclen # record length
420: mnegl fcrsz(r6),-(sp) # i/o mode - raw or line
421: calls $4,_oswrite # call to do write
422: tstl r0 # if output error then
423: jneq erxit3 # signal failure
424: popr $mr235
425: addl2 $12,(sp)
426: rsb
427: #
428: # sysej - end of job
429: #
430: .globl sysej
431: sysej:
432: movl r10,_rzfcb # copy head of fcb chain
433: beqlu 1f # if empty then nothing to close
434: 0: movl chfcb(r10),r1 # -> fcb
435: pushl fciob(r1) # -> ioblk
436: calls $1,_osclose # call to do close
437: movl chnxt(r10),r10 # -> next on chain
438: bnequ 0b # and loop back for more
439: 1: pushl r7 # return &code
440: calls $1,__exit
441: #
442: # sysem - get error message text
443: #
444: .globl sysem
445: sysem:
446: pushr $mr235
447: movl $tscblk,r9 # -> temp scblk
448: clrl sclen(r9) # default error text is null string
449: tstl errfdn # if error fd exists then
450: bnequ 0f # skip open
451: calls $0,_openerr # else open error text file
452: movl r0,errfdn # and save fd
453: 0: tstl errfdn # if no error text file then
454: blss emxit # return null string
455: decl r6 # errors start at 1
456: blss emxit # but don't have error 0
457: mull2 $49,r6 # compute byte offset of error text
458: pushl $0 # whence
459: pushl r6 # offset
460: pushl errfdn # file descriptor number
461: calls $3,_lseek # call to do seek
462: tstl r0 # if lseek fails then
463: blss emxit # return null string
464: pushl $48 # error text length w/out nl
465: pushl $tscblk+8 # buffer address
466: pushl errfdn # file descriptor number
467: calls $3,_read # call to do read
468: tstl r0 # if read failed then
469: blss emxit # return null string
470: 1: cmpb $' ,tscblk+7(r0)# if last character is
471: bneq 2f # nonblank, return length
472: sobgeq r0,1b # otherwise discard the blank, try again
473: 2: movl r0,sclen(r9) # set actual length
474: emxit:
475: popr $mr235
476: rsb # return
477: #
478: # sysen - endfile
479: #
480: .globl sysen
481: sysen:
482: pushr $mr235
483: movl r$fcb,_rzfcb # copy fcb chain head
484: pushl fciob(r6) # -> ioblk
485: calls $1,_osclose # call to do close
486: popr $mr235
487: addl2 $12,(sp)
488: rsb
489: #
490: # sysej - eject standard output
491: #
492: .globl sysep
493: sysep:
494: pushr $mr235
495: pushl $1 # 1 character
496: pushl $ffstr # -> ff
497: pushl $1 # fd 1
498: calls $3,_write # call to do write
499: popr $mr235
500: rsb
501: #
502: # sysfc
503: #
504: .globl sysfc
505: sysfc:
506: movl (sp)+,(sp) # remove stacked scblk
507: pushr $mr235
508: tstl sclen(r10) # if null filearg1 then
509: jeqlu erxit1 # error
510: #
511: # get length of filename and scan off options.
512: #
513: movl r9,-(sp) # -> filename scblk
514: calls $1,_lenfnm # call to get filename length
515: movl r0,lenfname # save length for later use
516: jlss erxit1 # length must not be negative
517: movl r9,-(sp) # -> filename scblk
518: movl $tioblk,-(sp) # -> temporary ioblk
519: movl r7,-(sp) # input/output association flag
520: calls $3,_sioarg # call to scan i/o args
521: tstl r0 # if error in args then
522: jlss erxit1 # take error return
523: #
524: # check for consistency of calls. cannot have both input
525: # and output to same channel. if this happens, though,
526: # set flag and let sysio take proper error exit.
527: #
528: tstl r6 # if no previous fcblk then
529: beqlu 0f # skip
530: movl fciob(r6),r0 # -> ioblk
531: movl ioflg(r0),r0 # get previous flags
532: mcoml $IO_INP+IO_OUP,r1 # get mask for bicl
533: bicl2 r1,r0 # remove all bits but INP&OUP
534: bitl tioblk+ioflg,r0 # if bits are not same then
535: bnequ 0f
536: bisl2 $IO_ILL,tioblk+ioflg # then set error flag
537: 0:
538: #
539: # handle null filenames here - must either have a previous
540: # fcblk or specify -f arg.
541: #
542: tstl lenfname # if non-null filename then
543: bgtr fcfnam # go handle below
544: bitl $IO_OPN,tioblk+ioflg
545: bnequ fcfarf # if -f specified then merge w/non-null
546: tstl r6 # if no previous fcblk then
547: jeqlu erxit1 # error
548: clrl r6 # assume that no new fcblk needed
549: clrl ioblkptr # no ioblk ptr to stuff
550: tstl tioblk # if however i/o args indicate one
551: jeqlu fcxit
552: movl fciob(r6),ioblkptr
553: movl $fcsize,r6 # allocate one
554: jbr fcxit
555: #
556: # handle real filenames and null filenames with -f arg here.
557: # note that they're mutually exclusive.
558: #
559: fcfnam: bitl $IO_OPN,tioblk+ioflg
560: jnequ erxit1 # can't have -f arg too
561: fcfarf: tstl r6 # if previous fcblk passed then
562: jnequ erxit1 # error
563: clrl ioblkptr
564: addl3 $bfsize+3,tioblk+iopid,r6
565: bicl2 $3,r6
566: movl r6,bfblksiz
567: addl2 $fcsize+iosize,r6
568: movl $1,tioblk # set newfcb flag
569: #
570: fcxit: clrl r10 # no private fcblk
571: clrl r8 # xrblk please
572: popr $mr235
573: addl2 $4,(sp)
574: rsb
575: #
576: # syshs
577: #
578: .globl syshs
579: syshs:
580: pushr $mr235
581: cmpl $b$icl,(r6) # if arg1 not integer then
582: jnequ 9f # return host string
583: casel icval(r6),$0,$5
584: 0:
585: .word 1f-0b # 0: return -u argument
586: .word 2f-0b # 1: do system call
587: .word 3f-0b # 2: return command arg
588: .word 4f-0b # 3: return number of first #! arg
589: .word 5f-0b # 4: get environment variable
590: .word 6f-0b # 5: manipulate signals
591: jbr erxit1 # else arg error
592: #
593: 1: tstl uarg # if uarg is 0 then
594: jeqlu erxit4 # return null string
595: pushl tscblk # push scblk string length
596: pushl $tscblk # -> temp scblk
597: clrl -(sp) # ending character is 0
598: pushl uarg # -> -u argument
599: calls $4,_cpys2sc # copy string to scblk
600: movab tscblk,r10 # -> temp scblk
601: jbr erxit3 # return
602: #
603: 2: cmpl $b$scl,(r10) # if 2nd arg not string then
604: jnequ erxit1 # return error
605: tstl sclen(r10) # if null string then
606: jeqlu erxit4 # return null string
607: pushl r10 # -> command string
608: calls $1,_dosys # call to do system call
609: jbr erxit4 # return null string
610: #
611: 3: cmpl $b$icl,(r10) # if 2nd arg not integer then
612: jnequ erxit1 # return error
613: movl tscblk,tscblk+sclen # set max length of scblk
614: pushab tscblk # push -> tscblk
615: pushl argv # push -> pointers
616: pushl argc # push number of args
617: pushl icval(r10) # arg requested
618: calls $4,_arg2scb # call to do real move
619: tstl r0 # if out of range then
620: jlss erxit6 # fail
621: jeqlu erxit4 # (if 0) return null string
622: movab tscblk,r10 # -> tscblk
623: jbr erxit3 # return
624: #
625: 4: tstl cmdcnt # if not invoked by #! then
626: jeqlu erxit6 # fail
627: movab temp1,r9 # -> temp icblk
628: movl $b$icl,(r9) # set integer block
629: movl cmdcnt,icval(r9)# set value
630: jbr erxit5 # return result
631: #
632: 5: cmpl $b$scl,(r10) # if 2nd arg not string then
633: jnequ erxit1 # return error
634: tstl sclen(r10) # if null string then
635: jeqlu erxit1 # return error
636: movl tscblk,tscblk+sclen # set max length of scblk
637: pushab tscblk # push -> tscblk
638: pushl r10 # -> environment variable requested
639: calls $2,_rdenv # fetch the environment variable
640: tstl r0 # if it couldn't be found
641: jlss erxit6 # fail
642: movab tscblk,r10 # else return tscblk
643: jbr erxit3
644: 6: cmpl $b$icl,(r10) # if second arg not integer then
645: jnequ erxit1 # return error
646: pushl icval(r10) # get the value
647: calls $1,_sigtrap # call the routine
648: movab temp1,r9 # -> temp icblk
649: movl $b$icl,(r9) # set integer block
650: movl r0,icval(r9) # set value
651: jbr erxit5 # return result
652: #
653: #
654: 9: pushl hststr # push length of host string
655: pushab hststr # push -> host string scblk
656: calls $2,_gethost # call to get host string
657: tstl hststr+sclen # if null host string then
658: jeqlu erxit4 # return null string
659: movl $hststr,r10 # -> host string
660: jbr erxit3 # return
661: #
662: # sysid - return system id
663: #
664: .globl sysid
665: sysid:
666: movl $id1,r9
667: movl $id2,r10
668: rsb
669: #
670: # sysil - get input record length
671: #
672: .globl sysil
673: sysil:
674: movl fcrsz(r6),r6
675: bgtr 0f
676: mnegl r6,r6
677: 0:
678: rsb
679: #
680: # sysin - read input record
681: #
682: .globl sysin
683: sysin:
684: pushr $mr235
685: pushl fciob(r6) # -> ioblk
686: calls $1,_osopen # call to open file
687: tstl r0 # if open unsuccessful then
688: jnequ erxit3 # take error exit
689: pushl r9 # -> scblk
690: pushl fciob(r6) # -> ioblk
691: pushl fcrsz(r6) # push record length
692: bgtr 0f
693: mnegl (sp),(sp) # if negative then make it positive
694: 0: pushl fcrsz(r6) # i/o mode - raw or line
695: calls $4,_osread # call to do read
696: cmpl r0,$-1 # check for eof or input error
697: jeql erxit1 # take eof exit
698: jlss erxit2 # take error exit
699: movl r0,sclen(r9) # set record length
700: popr $mr235
701: addl2 $12,(sp)
702: rsb
703: #
704: # sysio
705: #
706: .globl sysio
707: sysio:
708: pushr $mr235
709: bitl $IO_ILL,tioblk+ioflg
710: jnequ erxit2 # if illegal then take error exit
711: movl r6,fcblkptr # copy fcblk pointer for exit
712: #
713: # fill in fcblk.
714: #
715: tstl tioblk+iotyp # if no new fcb to build then
716: jeqlu iodon # done
717: movl $fcsize,fclen(r6)
718: movl tioblk+iolen,fcrsz(r6)
719: movl ioblkptr,fciob(r6)
720: jnequ iodon
721: movab fcsize(r6),fciob(r6)
722: #
723: # fill in ioblk.
724: #
725: movab fcsize(r6),r6 # -> ioblk
726: movl $b$xrt,(r6)
727: movl $iosize,iolen(r6)
728: movl r9,iofnm(r6)
729: clrl iopid(r6)
730: movab iosize(r6),iobuf(r6)
731: movl tioblk+iofdn,iofdn(r6)
732: movl tioblk+ioflg,ioflg(r6)
733: #
734: # if -f0 or -f1 specified then
735: #
736: # for -f0 ensure that buffer is same as osint's
737: #
738: # for -f1 no buffering should be done
739: #
740: bitl $IO_SYS,ioflg(r6)
741: beqlu 9f
742: cmpl $1,iofdn(r6)
743: blssu 9f
744: beqlu 1f
745: movl $inpbf,iobuf(r6)
746: jbr 9f
747: 1: clrl iobuf(r6)
748: bisl2 $IO_WRC,ioflg(r6)
749: 9:
750: #
751: # fill in bfblk
752: #
753: movab iosize(r6),r6 # -> bfblk
754: movl $b$xnt,(r6)
755: movl bfblksiz,bflen(r6)
756: movl tioblk+iopid,bfsiz(r6)
757: clrl bfrem(r6)
758: clrl bfoff(r6)
759: #
760: # try to open the file
761: #
762: movl fcblkptr,r0
763: pushl fciob(r0)
764: calls $1,_osopen
765: tstl r0
766: jneq erxit2 # if open failed, indicate error
767: #
768: iodon: movl fcblkptr,r10
769: clrl r8
770: popr $mr235
771: addl2 $8,(sp)
772: rsb
773: #
774: # sysmm - get more memory
775: #
776: .globl sysmm
777: sysmm:
778: cmpl topmem,maxmem # if already at top of memory then
779: blssu 0f
780: clrl r9 # no more to be had
781: rsb
782: 0: # else {alloc some more}
783: pushr $mr235
784: pushl meminb # size in bytes of memory request
785: calls $1,_sbrk # call to get memory
786: popr $mr235
787: tstl r0 # if memory obtained then
788: blss 1f
789: addl2 meminb,topmem # adjust current top
790: movl meminc,r9 # set number of words in block
791: rsb # return
792: 1: clrl r9 # else nothing to get
793: rsb
794: #
795: # sysmx - get maximum size of created objects
796: #
797: .globl sysmx
798: sysmx:
799: mull3 $4,maxsiz,r6
800: rsb
801: #
802: # sysou - output record
803: #
804: .globl sysou
805: sysou:
806: pushr $mr235
807: pushl fciob(r6) # -> ioblk
808: calls $1,_osopen # call to do open
809: tstl r0 # if open error then
810: jnequ erxit1 # take error exit
811: pushl r9 # -> scblk
812: pushl fciob(r6) # -> ioblk
813: pushl sclen(r9) # record length
814: pushl fcrsz(r6) # i/o mode - raw or line
815: calls $4,_oswrite # call to do write
816: tstl r0 # if output error,
817: jneq erxit2 # take error exit
818: popr $mr235
819: addl2 $8,(sp)
820: rsb
821: #
822: # syspi - print on interactive channel (terminal)
823: #
824: .globl syspi
825: syspi:
826: movl $ttyiob,r11
827: jbr piprt
828: #
829: # syspp - return print parameters
830: #
831: .globl syspp
832: syspp:
833: movl pagwid,r6
834: movl lnsppg,r7
835: movl sptflg,r8
836: movl defcas,kvcas
837: rsb
838: #
839: # syspr - print on standard output
840: #
841: .globl syspr
842: syspr:
843: movl $oupiob,r11
844: #
845: # handle both syspi and syspr here.
846: #
847: piprt:
848: pushr $mr235
849: bisl2 $IO_WRC,ioflg(r11) # briefly set no buffering
850: pushl r9 # -> scblk
851: pushl r11 # -> ioblk
852: pushl r6 # number characters
853: pushl $1 # line mode
854: calls $4,_oswrite # call to do write
855: bicl2 $IO_WRC,ioflg(r11) # back to buffering
856: tstl r0 # if output error then
857: jneq erxit1 # indicate error return
858: popr $mr235
859: addl2 $4,(sp)
860: rsb
861: #
862: # sysrd - read from standard input
863: #
864: .globl sysrd
865: sysrd:
866: pushr $mr235
867: movl $inpiob,ioblkptr
868: #
869: # handle both sysrd and sysri here.
870: #
871: rdmrg:
872: pushl r9 # -> scblk
873: pushl ioblkptr # -> ioblk
874: pushl r8 # read length
875: pushl r8 # line mode
876: calls $4,_osread # call to do read
877: cmpl r0,$-1 # check for eof or input error
878: jeql rdeof # take eof exit
879: jlss erxit1 # take error exit
880: movl r0,sclen(r9) # set read length
881: #
882: # check for 1st record of standard input coming from a file specified
883: # on the command line. if all of these conditions are true, allow
884: # the program to access any arguments following the file name.
885: #
886: tstl rdrec1 # if already ready record 1 then
887: bnequ rdskp # skip
888: cmpl $inpiob,ioblkptr
889: bnequ rdskp # if sysri entry then skip
890: incl rdrec1 # indicate read 1st record from std input
891: tstl inpptr # if not file from command line then
892: beqlu rdskp # skip
893: cmpb $'#,scstr(r9) # if 1st char not # then
894: bnequ rdskp # skip
895: cmpb $'!,scstr+1(r9) # if 2nd char not ! then
896: bnequ rdskp # skip
897: subl3 inpcnt,argc,cmdcnt
898: incl cmdcnt # compute # args after filename
899: movl $1,inpcnt # reset input count
900: brb rdmrg # ignore 1st record and try again
901: rdskp:
902: popr $mr235
903: addl2 $4,(sp)
904: rsb
905: #
906: # come here to handle eof for both sysrd and sysri. if eof
907: # is for sysrd, standard input, switch to next input file
908: # if one exists.
909: #
910: rdeof: movl ioblkptr,r4 # -> ioblk
911: tstl iofdn(r4) # if not file descriptor 0 then
912: jnequ erxit1 # real eof
913: pushl inpptr # push -> array of pointers
914: pushl inpcnt # push size of areray
915: calls $2,_swcinp # call to switch input files
916: tstl r0 # if more to read then
917: jeqlu rdmrg # read it
918: jmp erxit1 # else signal eof
919: #
920: # sysri - read from interactive channel (terminal)
921: #
922: .globl sysri
923: sysri:
924: pushr $mr235
925: movl $ttyiob,ioblkptr
926: jbr rdmrg
927: #
928: # sysrw - rewind file
929: #
930: .globl sysrw
931: sysrw:
932: pushr $mr235
933: pushl fciob(r6) # -> ioblk
934: calls $1,_osopen # call to do open
935: tstl r0 # if open error then
936: jnequ erxit1 # take error exit
937: movl fciob(r6),r1 # -> ioblk
938: bitl $IO_PIP,ioflg(r1)
939: jnequ erxit2 # if pipe then rewind not allowed
940: cmpl iofdn(r1),$2 # if fd < 2 then
941: jlssu erxit2 # rewind not allowed
942: pushl $0 # whence
943: pushl $0 # offset
944: pushl fciob(r6) # -> ioblk
945: calls $3,_doset # call to do set
946: popr $mr235
947: addl2 $12,(sp)
948: rsb
949: #
950: # sysst - set file pointer
951: #
952: .globl sysst
953: sysst:
954: pushr $mr235
955: pushl fciob(r6) # -> ioblk
956: calls $1,_osopen # call to do open
957: tstl r0 # if file open error then
958: jnequ erxit3 # return error
959: #
960: movl fciob(r6),r1 # -> ioblk
961: bitl $IO_PIP,ioflg(r1)
962: jnequ erxit4 # if pipe then set not allowed
963: cmpl iofdn(r1),$2 # if fd < 2 then
964: jlssu erxit4 # set not allowed
965: #
966: cmpl $b$icl,(r7) # if already integer then
967: bnequ 0f
968: movl icval(r7),temp1 # grab value
969: brb 1f
970: 0: cmpl $b$scl,(r7) # else if not a string then
971: jnequ erxit1 # error
972: clrl temp3 # clear scnint character count
973: pushl $temp3 # -> temp3
974: pushl sclen(r7) # string length
975: pushab scstr(r7) # -> string
976: calls $3,_scnint # call to scan integer
977: movl r0,temp1 # and save
978: 1:
979: #
980: cmpl $b$icl,(r8) # if already integer then
981: bnequ 0f
982: movl icval(r8),temp2 # grab value
983: brb 1f
984: 0: cmpl $b$scl,(r8) # else if not a string then
985: jnequ erxit1 # error
986: clrl temp3 # clear scnint character count
987: pushl $temp3 # -> temp3
988: pushl sclen(r8) # string length
989: pushab scstr(r8) # -> string
990: calls $3,_scnint # call to scan integer
991: movl r0,temp2 # and save
992: 1:
993: #
994: pushl temp2 # whence
995: pushl temp1 # offset
996: pushl fciob(r6) # -> ioblk
997: calls $3,_doset # call to do set
998: popr $mr235
999: addl2 $20,(sp)
1000: rsb
1001: #
1002: # systm - get execution time so far
1003: #
1004: .globl systm
1005: systm:
1006: pushr $mr2+mr3
1007: movl $tscblk+8,-(sp) # -> times buffer
1008: calls $1,_times # call to do times
1009: movl tscblk+8,r5 # get user time in 60ths
1010: mull2 $100,r5 # mulitply by 100 to get 6000ths
1011: divl2 $6,r5 # divide by 6 to get 1000ths
1012: popr $mr2+mr3
1013: rsb
1014: #
1015: # sysxi - exit from executing program
1016: #
1017: .globl sysxi
1018: sysxi:
1019: tstl r10 # if 0 instead of scblk then
1020: jeqlu xilmod # try to write load module
1021: pushr $mr235
1022: cmpl $b$scl,(r10) # if not scblk then
1023: jnequ erxit1 # error
1024: pushl r10 # push scblk pointer
1025: calls $1,_doexec # go do exit
1026: jmp erxit2 # should never return
1027: #
1028: # write load module
1029: #
1030: xilmod: tstl r5 # if r5 <= 0 then
1031: bgtr 0f
1032: pushr $mr235 # save regs for error exits
1033: jbr erxit1 # and take error exit
1034: 0: pushr $cmpreg # else save all compiler regs
1035: #
1036: # need to save stack contents, so that when load module is
1037: # invoked, stack can be recreated.
1038: #
1039: subl3 sp,initsp,r0 # compute depth of stack
1040: cmpl r0,tscblk # if stack won't fit in tscblk then
1041: jgtru xi2big # big trouble
1042: movl sp,r0 # -> into real stack
1043: movab tscblk+scstr,r1 # -> save stack area
1044: 1: movl (r0)+,(r1)+ # copy word of stack ...
1045: cmpl r0,initsp # until hit top word
1046: blssu 1b
1047: movl r1,lmodstk # set top of saved stack
1048: #
1049: # before creating the load module, we must relativize the
1050: # compiler cells that point into the stack. We do this by
1051: # temporarily negating initsp, calling streloc, and then
1052: # restoring initsp. After the load module has been written,
1053: # another call to streloc will restore the stack pointers.
1054: #
1055: mnegl initsp,initsp # negate initsp so streloc will subtract
1056: jsb streloc # relativize the compiler cells
1057: mnegl initsp,initsp # restore initsp to its previous value
1058: #
1059: # create a.out header in hststr scblk.
1060: #
1061: addl3 $1023,dnamp,r1 # round current memory in use
1062: bicl3 $0x3ff,r1,-(sp) # to a multiple of the page size
1063: movab hststr+scstr,r0 # -> a.out header block
1064: pushl r0 # which will be the other argument
1065: movl $0413,(r0)+ # set magic number
1066: bicl3 $0x3ff,$_etext,r1 # get text size, rounded down
1067: movl r1,(r0)+ # and place it in a.out header
1068: subl3 r1,4(sp),(r0)+ # data size = total - text size
1069: clrl (r0)+ # we will use no bss
1070: clrl (r0)+
1071: clrl (r0)+ # set starting address
1072: clrl (r0)+
1073: clrl (r0)+
1074: #
1075: # call a workhorse c routine to actually write a.out file.
1076: # the amount of memory to write has already been pushed.
1077: #
1078: calls $2,_wrtaout # call to write a.out
1079: #
1080: # restore compiler cells to their previous values
1081: #
1082: jsb streloc # unrelativize stack pointers
1083: #
1084: tstl r0 # if error creating a.out then
1085: blss xi2big # return error
1086: #
1087: # pop registers and set up call to sysej
1088: #
1089: popr $cmpreg # restore all registers
1090: movl r7,r10 # -> chain of fcbs
1091: clrl r7 # set &CODE = 0
1092: jsb sysej # call to end run
1093: #
1094: # if stack too big
1095: #
1096: xi2big: popr $cmpreg # restore all regs
1097: pushr $mr235 # push correct regs
1098: jbr erxit2 # take error exit
1099: #
1100: # error/ppm exits - pick up n-th word following jsb and return
1101: # to address contained in that word.
1102: #
1103: erxit1:
1104: popr $mr235
1105: movl (sp)+,r11
1106: jmp *(r11)+
1107: #
1108: erxit2:
1109: popr $mr235
1110: addl3 $4,(sp)+,r11
1111: jmp *(r11)+
1112: #
1113: erxit3:
1114: popr $mr235
1115: addl3 $8,(sp)+,r11
1116: jmp *(r11)+
1117: #
1118: erxit4:
1119: popr $mr235
1120: addl3 $12,(sp)+,r11
1121: jmp *(r11)+
1122: #
1123: erxit5:
1124: popr $mr235
1125: addl3 $16,(sp)+,r11
1126: jmp *(r11)+
1127: #
1128: erxit6:
1129: popr $mr235
1130: addl3 $20,(sp)+,r11
1131: jmp *(r11)+
1132: #
1133: # streloc - relocate stack pointers. this routine adds
1134: # initsp to every cell whose address appears in strellst.
1135: #
1136: streloc:
1137: pushr $mr0+mr1
1138: moval strellst,r1 # start of list of thing to relocate
1139: jbr strel1 # jump into the loop
1140: strel0: addl2 initsp,(r0) # relocate a pointer
1141: strel1: movl (r1)+,r0 # fetch a pointer to a cell
1142: jneq strel0 # if zero, we're done
1143: popr $mr0+mr1
1144: rsb
1145: #
1146: # option routines
1147: #
1148: # optclr clears a flag
1149: # opterr signals an error
1150: # optfld sets defcas to 0 for no folding
1151: # optnum get numeric value
1152: # optset set option value
1153: #
1154: # optclr
1155: #
1156: optclr: bicl2 optflg(r1),sptflg
1157: rsb
1158: #
1159: # opterr
1160: #
1161: opterr: pushr $mr0+mr1+mr2+mr3+mr4+mr5
1162: pushl $6
1163: pushl $curopt
1164: pushl $2
1165: calls $3,_write
1166: popr $mr0+mr1+mr2+mr3+mr4+mr5
1167: rsb
1168: #
1169: # optinp
1170: #
1171: optinp: tstl inpptr # if already processed input filenames then
1172: bnequ opterr # error
1173: subl3 $4,r6,inpptr # -> first input filename
1174: movl r4,inpcnt # set number of filenames
1175: movl $1,r4 # done scanning options
1176: rsb # return
1177: #
1178: # optfld
1179: #
1180: optfld: clrl defcas
1181: rsb
1182: #
1183: # optnum
1184: #
1185: optnum: pushl r0 # -> number
1186: jsb getnum # get number
1187: movl (sp)+,r0 # -> byte past last digit
1188: movzbl (r0),r2 # get byte past last digit
1189: bisb2 $040,r2 # fold to lower case
1190: cmpb $ch$lk,r2 # if number followed by k then
1191: bnequ 0f
1192: mull2 $1024,r5 # mulitply by 1024
1193: incl r0 # skip over k
1194: 0: tstl r5 # if number zero or negative
1195: bleq opterr # treat as error
1196: movl r5,*optflg(r1) # store option
1197: rsb # return
1198: #
1199: # optoup
1200: #
1201: optoup: cmpl $2,r4 # if no option after -o then
1202: bgtru opterr # error
1203: movl (r6),r1 # -> output filename
1204: cmpb $ch$mn,(r1) # if filename starts with - then
1205: beqlu opterr # error
1206: movl (r6)+,oupptr # save pointer to output filename
1207: decl r4 # one less option to process
1208: rsb # return
1209: #
1210: # optset
1211: #
1212: optset: bisl2 optflg(r1),sptflg
1213: rsb
1214: #
1215: # optusr
1216: #
1217: optusr: cmpl $2,r4 # if fewer than 2 options then
1218: jgtru opterr # can't have argument
1219: movl (r6)+,uarg # save -> argument
1220: decl r4 # dec number of remaining options
1221: rsb
1222: #
1223: # getnum
1224: #
1225: # (sp) -> string to convert
1226: # jsb getnum
1227: # (sp) -> char after last digit
1228: # (r5) converted number
1229: #
1230: getnum:
1231: movl 4(sp),r7 # -> string
1232: clrl r5 # clear accumulator
1233: 0: cmpb $060,(r7) # if not a decimal digit then
1234: bgtru 1f # done with conversion
1235: cmpb $071,(r7) #
1236: blssu 1f
1237: movzbl (r7)+,r8 # load digit
1238: subl2 $060,r8 # remove unnecessary bits
1239: mull2 $10,r5 # accum * 10
1240: addl2 r8,r5 # add in this digit
1241: brb 0b
1242: 1: movl r7,4(sp) # return address of next byte
1243: rsb # return
1244: #
1245: # interface data area
1246: # -------------------
1247: #
1248: .data 1
1249: #
1250: # flags for compiler
1251: #
1252: .set errors,1 # send errors to terminal
1253: .set prtich,2 # standard printer is terminal
1254: .set nolist,4 # suppress compilation listing
1255: .set nocmps,8 # suppress compilation statistics
1256: .set noexcs,16 # suppress execution statistics
1257: .set lnglst,32 # generate page ejects
1258: .set noexec,64 # suppress program execution
1259: .set trmnal,128 # terminal i/o association
1260: .set stdlst,256 # standard listing (intermediate)
1261: .set nohedr,512 # suppress sysid header
1262: #
1263: .set deflag,errors+nolist+nocmps+noexcs+trmnal+nohedr
1264: #
1265: # option table
1266: #
1267: .set opttxt,0 # option characters
1268: .set optflg,4 # option flag - flags or address
1269: .set optrtn,8 # -> option processing routine
1270: .set optsiz,12 # size in bytes of entry
1271: #
1272: opttbl:
1273: .ascii "-f "
1274: .long 0,optfld
1275: #
1276: .ascii "-e "
1277: .long errors,optclr
1278: #
1279: .ascii "-l "
1280: .long nolist,optclr
1281: #
1282: .ascii "-c "
1283: .long nocmps,optclr
1284: #
1285: .ascii "-x "
1286: .long noexcs,optclr
1287: #
1288: .ascii "-a "
1289: .long nolist+nocmps+noexcs,optclr
1290: #
1291: .ascii "-p "
1292: .long lnglst,optset
1293: #
1294: .ascii "-z "
1295: .long stdlst,optset
1296: #
1297: .ascii "-h "
1298: .long nohedr,optclr
1299: #
1300: .ascii "-n "
1301: .long noexec,optset
1302: #
1303: .ascii "-m "
1304: .long maxsiz,optnum
1305: #
1306: .ascii "-s "
1307: .long stksiz,optnum
1308: #
1309: .ascii "-d "
1310: .long datwds,optnum
1311: #
1312: .ascii "-i "
1313: .long meminc,optnum
1314: #
1315: .ascii "-o "
1316: .long 0,optoup
1317: #
1318: .ascii "-u "
1319: .long 0,optusr
1320: #
1321: curopt: .ascii "- "
1322: .ascii "?\n "
1323: .long opterr
1324: .align 2
1325: #
1326: # standard input/output pointers
1327: #
1328: inpcnt: .long 0
1329: inpptr: .long 0
1330: oupptr: .long 0
1331: #
1332: # pointer to -u arg
1333: #
1334: uarg: .long 0
1335: #
1336: # save argc and argv from initial call
1337: #
1338: argc: .long 0
1339: argv: .long 0
1340: #
1341: # #! data areas
1342: #
1343: cmdcnt: .long 0 # number of command args
1344: rdrec1: .long 0 # read record 1 from std in flag
1345: #
1346: # standard ioblks
1347: #
1348: inpiob: .space iobuf
1349: .long inpbf # -> input bfblk
1350: .long 0 # file descriptor
1351: .long IO_INP|IO_OPN|IO_SYS
1352: #
1353: inpbf: .space bfsiz
1354: .long 4096 # buffer size
1355: .long 0 # remaining chars to read
1356: .long 0 # offset to next character to read
1357: .space 4096 # buffer
1358: #
1359: #
1360: oupiob: .space iobuf
1361: .long 0 # no buffer
1362: .long 1 # file descriptor number
1363: .long IO_OUP|IO_OPN|IO_SYS
1364: #
1365: #
1366: ttyiob: .space iobuf
1367: .long ttybf # -> tty buffer input
1368: .long 2 # file descriptor number
1369: .long IO_INP|IO_OUP|IO_OPN|IO_SYS
1370: #
1371: ttybf: .space bfsiz
1372: .long 258 # buffer size
1373: .long 0 # remaining chars to read
1374: .long 0 # offset to next char to read
1375: .space 258 # buffer
1376: .align 2
1377: #
1378: .globl _rzfcb
1379: _rzfcb: .long 0
1380: #
1381: fildes: .long 0
1382: pr_len: .long 0
1383: rd_len: .long 0
1384: lenfname: .long 0
1385: ioblkptr: .long 0
1386: bfblkptr: .long 0
1387: bfblksiz: .long 0
1388: fcblkptr: .long 0
1389: tioblk: .space iosize
1390: #
1391: # memory allocation variables
1392: #
1393: meminc: .long 4*k # increment in words for sbrk
1394: meminb: .long 0 # meminc * 4 (to get bytes)
1395: datwds: .long 256*k # max size in words of dynamic area
1396: basmem: .long 0 # base of dynamic memory
1397: topmem: .long 0 # current top of dynamic memory
1398: maxmem: .long 0 # maximum top of dynamic memory
1399: maxsiz: .long 8*k # maximum object size in words
1400: stksiz: .long 2*k # stack size in words
1401: initsp: .long 0 # initial value of sp on entry to sec04
1402: lowsp: .long 0 # lowest legal sp value
1403: #
1404: # default value for &case
1405: #
1406: defcas: .long 1
1407: #
1408: # values given to syspp for print parameters
1409: #
1410: lnsppg: .long 60 # lines per page
1411: pagwid: .long 120 # page width
1412: sptflg: .long deflag # flags
1413: #
1414: # flag that indicates that this is a load module. also, serves
1415: # the dual purpose of indicating size of saved stack.
1416: #
1417: lmodstk: .long 0
1418: #
1419: temp1: .long 0
1420: temp2: .long 0
1421: temp3: .long 0
1422: #
1423: nulstr: .long 0,0
1424: #
1425: tscblk: .long 512,0
1426: .space 512
1427: #
1428: hststr: .long 128,0
1429: .space 128
1430: #
1431: id1: .long 0,id1l
1432: .ascii "(0.0)"
1433: id1e:
1434: .set id1l,id1e-id1-8
1435: .align 2
1436: #
1437: id2: .long 0,id2l
1438: .ascii "VAX/UNIX Version"
1439: id2e:
1440: .set id2l,id2e-id2-8
1441: .align 2
1442: #
1443: ffscb: .long 0,1
1444: ffstr: .byte 12
1445: #
1446: nlstr: .ascii "\n"
1447: .align 2
1448: #
1449: errfdn: .long 0
1450: #
1451: # The following pointers address those cells in the compiler
1452: # that point into the stack when a load module might be written,
1453: # and which must therefore be relocated.
1454: strellst:
1455: .long flptr
1456: .long stbas
1457: .long gtcef
1458: .long 0 # end of list marker
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.