|
|
1.1 root 1: #include <stdio.h>
2: #include "ctype.h"
3: #include "typedef.h"
4: #include "basic.h"
5: #include "tokens.h"
6:
7: #define MAXUNIT 5
8: #define MAXSTR 255
9: #define MAXBUF 7
10: #define INUNIT 0
11: #define OUTUNIT 1
12:
13: static struct iotab {
14: int io_flag; /* if currently open etc. */
15: int io_col; /* current column */
16: FILE *io_ptr; /* input/output stdio table entry */
17: } units[MAXUNIT];
18:
19: static char buffers[MAXBUF][BUFSIZ];
20: static char bufflg[MAXBUF];
21: static char pflgs[_NFILE];
22:
23: char askdelims[] = { COMMA, ';', 0 };
24:
25: char *getsvar(), *strpop();
26: FILE *xopen(), *fopen(), *popen();
27: double popfloat();
28: struct iotab *getunit();
29:
30:
31: /*
32: * xopen --- open a file or a pipe; assign a buffer
33: */
34:
35: FILE *xopen(file, how)
36: char *file, *how;
37: {
38: register FILE *f;
39:
40: if (*file == '!') { /* open a pipe */
41: if (f = popen(&file[1], how))
42: pflgs[fileno(f)]++;
43: }
44: else
45: f = fopen(file, how);
46: if (f != (FILE *)NULL)
47: assbuf(f);
48: return(f);
49: }
50:
51:
52: /*
53: * xclose --- close a file previously opened by xopen
54: */
55:
56: xclose(file)
57: register FILE *file;
58: {
59: register char *b = file->_base;
60: register int i;
61:
62: i = fileno(file);
63: if (pflgs[i])
64: pclose(file);
65: else
66: fclose(file);
67: pflgs[i] = 0;
68: for (i = 0; i < MAXBUF; ++i)
69: if (b == buffers[i])
70: bufflg[i] = 0;
71: }
72:
73:
74: /*
75: * assbuf --- assign a buffer to a newly opened file
76: */
77:
78: assbuf(f)
79: register FILE *f;
80: {
81: register int i;
82:
83: for (i = 0; i < MAXBUF; ++i)
84: if (bufflg[i] == 0) {
85: setbuf(f, buffers[i]);
86: ++bufflg[i];
87: return;
88: }
89: err("no buffers available");
90: }
91:
92:
93: /*
94: * initio --- initialize i/o related structures
95: */
96:
97: initio()
98: {
99:
100: assbuf(stdin);
101: clrio();
102: }
103:
104:
105: /*
106: * clrio --- reinitialize i/o related structures
107: */
108:
109: clrio()
110: {
111: register struct iotab *i;
112:
113: for (i = units; i < &units[MAXUNIT]; ++i)
114: if (i->io_flag)
115: iocls(i);
116:
117: units[INUNIT].io_flag = INPUT;
118: units[INUNIT].io_ptr = stdin;
119: units[INUNIT].io_col = 1;
120: units[OUTUNIT].io_flag = OUTPUT;
121: units[OUTUNIT].io_ptr = stdout;
122: units[OUTUNIT].io_col = 1;
123: }
124:
125: iocls(i)
126: register struct iotab *i;
127: {
128: if (i->io_flag) {
129: if (i->io_ptr != stdin && i->io_ptr != stdout)
130: xclose(i->io_ptr);
131: i->io_flag = 0;
132: i->io_ptr = (FILE *)NULL;
133: i->io_col = 1;
134: }
135: }
136:
137:
138: /*
139: * getunit --- get and check unit number for OPEN statement
140: */
141:
142: struct iotab *getunit(flag, defunit)
143: {
144: register int n;
145: register struct iotab *i;
146:
147: if (*inptr != SHARP)
148: n = defunit;
149: else {
150: ++inptr;
151: n = fexpr();
152: if (!endtest()) {
153: while (*inptr == ' ' || *inptr == TAB)
154: ++inptr;
155: if (*inptr != THEN)
156: expectc(COMMA);
157: }
158: }
159: if (n < 0 || n >= MAXUNIT)
160: err("invalid unit %d", n);
161: i = &units[n];
162: if (flag && flag != i->io_flag)
163: err("unit not opened for %s",
164: ((flag == INPUT)? "input" : "output"));
165: return(i);
166: }
167:
168:
169: /*
170: * openstmt --- interpret an OPEN statement
171: */
172:
173: openstmt()
174: {
175: register struct iotab *i;
176: int len, how;
177: char *str, *code, *file;
178:
179: expr();
180: file = strpop();
181: expectc(FOR);
182: how = *inptr;
183: switch (how) {
184: case INPUT:
185: code = "r";
186: break;
187: case OUTPUT:
188: code = "w";
189: break;
190: case APPEND:
191: code = "a";
192: how = OUTPUT; /* same as OUTPUT mostly */
193: break;
194: default:
195: badsyn();
196: }
197: ++inptr;
198: i = getunit(0, ((how == INPUT)? INUNIT : OUTUNIT));
199: i->io_ptr = xopen(file, code);
200: if (i->io_ptr == (FILE *)NULL)
201: err("cannot open %s", file);
202: i->io_flag = how;
203: i->io_col = 1;
204: }
205:
206:
207: /*
208: * prtusing --- interpret a PRINT USING statement
209: */
210:
211: prtusing(fmtptr)
212: char *fmtptr;
213: {
214:
215: register struct iotab *i;
216:
217:
218: /* linefeed and carriage return and
219: * set column count to 1
220: */
221:
222: while (*inptr == ' ' || *inptr == COMMA || *inptr == TAB)
223: inptr++; /* skip spaces & first comma or tab */
224:
225: i = getunit(OUTPUT, OUTUNIT);
226: col = i->io_col;
227: if (col > 1) {
228: i->io_col = 1;
229: }
230:
231: getformat(fmtptr, i->io_ptr);
232: }
233:
234: /*
235: * getformat - get format field and variable for print-using
236: */
237:
238: getformat(fmtptr, file)
239: char *fmtptr;
240: FILE *file;
241: {
242:
243: register Stkptr s;
244: register int l;
245: int flag;
246: double f;
247: char *p, *fp, *tmp, *doformat(), *doformat(), *donumeric();
248:
249: fp = fmtptr;
250: while (!endtest()) {
251: while (*inptr == ' ' || *inptr == COMMA || *inptr == TAB)
252: inptr++; /* skip spaces & first comma or tab */
253: expr();
254: s = (Stkptr)stkptr;
255: switch(s->k_type) {
256: case FLOATEXPR:
257: f = popfloat();
258: fp = donumeric(fp, f, file);
259: break;
260: case STRINGEXPR:
261: pop(ANYTYPE);
262: fp = doformat(fp, s->k_un.k_str.s_ptr,
263: s->k_un.k_str.s_len, file);
264: break;
265: default:
266: badtype();
267: break;
268: }
269: switch(*inptr) {
270: case ' ':
271: case ';':
272: case COMMA:
273: ++inptr;
274: break;
275: case '\0':
276: case '\n':
277: case ELSE:
278: case COLON:
279: break;
280: default:
281: badsyn();
282: break;
283: }
284: }
285: while (*fp > 0) {
286: switch (*fp) {
287: case '\'': /* found a ' */
288: fp++;
289: switch (*fp) {
290: case 'l':
291: case 'L':
292: case 'r':
293: case 'R':
294: case 'c':
295: case 'C':
296: fprintf(file, " ");
297: for(tmp = fp+1;*fp && (*tmp == *fp); fp++,tmp++)
298: fprintf(file, " ");
299: fprintf(file, " ");
300: fp++;
301: break;
302: default:
303: fprintf(file, "'");
304: break;
305: }
306: break;
307: case '#':
308: fprintf(file, " ");
309: fp++;
310: break;
311: default:
312: putc(*fp++, file);
313: break;
314: }
315: }
316: if (*(inptr - 1) != ';')
317: putc('\n', file);
318: if (file == stdout)
319: fflush(file);
320:
321: }
322:
323: /*
324: * donumeric -- print numeric variable in print-using format
325: */
326:
327: char *donumeric(fmtptr, num, file)
328: char *fmtptr;
329: double num;
330: FILE *file;
331:
332: {
333: register int k,c,d,l;
334: register char *fp;
335: int negativeflag, dollarflag, periodflag;
336: int intsize, decsize;
337: long intpart, decpart;
338: double f;
339:
340:
341: /* the next line is for testing
342: printf("beginning donumeric routine");*/
343:
344: fp = fmtptr;
345: c = 0;
346: d = 0;
347: f = num;
348:
349: if (f > 999999999)
350: err("number too large ( > 999,999,999)");
351: /* check to see is number is too large to handle */
352:
353: if (f < 0) {
354: negativeflag = YES;
355: f = -f;
356: }
357: else
358: negativeflag = NO;
359:
360: dollarflag = NO; /* dollar in format field */
361: periodflag = NO; /* period in format field */
362: intsize = 1; /* 1 more than max integer part */
363: decsize = 1; /* 1 more than max decimal part */
364:
365: /* if character in the format line is not a $ or #, print it.
366: Or, if it is a $ or a . but is not followed by a #, print it. */
367:
368: while ((*fp > 0) && ((*fp != '$' && *fp != '#' && *fp != '.') ||
369: (*fp == '$' && *(fp + 1) != '#') ||
370: (*fp == '.' && *(fp + 1) != '#')))
371: fprintf(file, "%.1s", fp++);
372:
373:
374:
375:
376: /* at this point we have either a # or
377: a $ followed by a # */
378:
379:
380: if (*fp == '$') {
381: dollarflag = YES;
382: fp++;
383: }
384:
385: while (*fp == '#') {
386: c++;
387: intsize = intsize * 10;
388: fp++;
389: }
390:
391: if (*fp == '.') {
392: periodflag = YES;
393: fp++;
394: while (*fp == '#') {
395: d++;
396: decsize = decsize * 10;
397: fp++;
398: }
399: }
400:
401:
402: /* round-off number before checking for size */
403:
404: f = f + (5 / (10 * (float)decsize));
405:
406: intpart = f; /* integer part of passed float */
407:
408: /* check for number too large for field
409: if so, print *-filled format field */
410:
411: if (negativeflag == YES)
412: intsize = intsize/10; /* leave room for negative sign */
413:
414: if (intpart > (intsize -1)) {
415: if (dollarflag == YES)
416: fprintf(file, "$");
417: for (; c; c--)
418: fprintf(file, "*");
419: if (periodflag == YES)
420: fprintf(file, ".");
421: for (; d; d--)
422: fprintf(file, "*");
423: return(fp);
424: }
425:
426:
427: /* number fits in field, begin print */
428:
429: /* the following line is for testing only
430: printf("beginning print %d %d", intsize, c);
431: used to enclode previous line in a comment when not used */
432:
433: /* if number is zero, divide intsize by 10 to allow room
434: for the printing of the zero */
435:
436: if (intpart == 0)
437: intsize = intsize/10;
438:
439: for (; intsize > ( 1 + intpart * 10); intsize = intsize / 10)
440: fprintf(file, " ");
441:
442: if (negativeflag == YES)
443: fprintf(file, "-");
444:
445: if (dollarflag == YES)
446: fprintf(file, "$");
447:
448: if (intsize >= .01)
449: fprintf(file, "%u", intpart);
450:
451: if (periodflag == YES)
452: fprintf(file, ".");
453:
454:
455: if (decsize > 1) { /* if decsize is 1, no decimal part of # field */
456:
457: decpart = (f - intpart) * decsize;
458: if (decpart == 0)
459: while (d--)
460: fprintf(file, "0");
461: else {
462: while (decpart < (decsize / 10)){
463: fprintf(file, "0");
464: decsize = decsize / 10;
465: }
466: fprintf(file, "%u", decpart);
467: }
468: }
469:
470:
471: return(fp);
472:
473: }
474:
475: /*
476: * doformat - determine format and print string
477: */
478:
479: char *doformat(fmtptr, ptr, len, file)
480: char *fmtptr;
481: char *ptr;
482: int len;
483: FILE *file;
484: {
485: register int k, c, d, l;
486: register char *p;
487: register char *fp, *tmp;
488:
489: p = ptr;
490: fp = fmtptr;
491: l = len;
492: c = 1;
493: while (*fp > 0) {
494: if (*fp != '\'') {
495: fprintf(file, "%.1s", fp++);
496: continue;
497: }
498: fp++;
499: switch (*fp) {
500: case 'l':
501: case 'L':
502: tmp = fp + 1;
503: while (*fp == *tmp) {
504: c++;
505: fp++;
506: tmp++;
507: }
508: c = c + 1; /* count the last l or L */
509: fp++; /* move past last l or L */
510: while (c-- > 0 && l-- > 0)
511: fprintf(file, "%.1s", p++);
512: while (c-- >= 0)
513: fprintf(file, " ");
514: return (fp);
515: break;
516: case 'r':
517: case 'R':
518: tmp = fp + 1;
519: while (*fp == *tmp) {
520: c++;
521: fp++;
522: tmp++;
523: }
524: c = c + 1; /* count the last r or R */
525: fp++; /* move past last r or R */
526: if (l >= c) {
527: p = p + (l - c);
528: while (c-- > 0)
529: fprintf(file, "%.1s", p++);
530: }
531: else {
532: for (d = c - l; d > 0; d--)
533: fprintf(file, " ");
534: while (l-- > 0)
535: fprintf(file, "%.1s", p++);
536: }
537: return (fp);
538: break;
539: case 'c':
540: case 'C':
541: tmp = fp + 1;
542: while (*fp == *tmp) {
543: c++;
544: fp++;
545: tmp++;
546: }
547: c = c + 1; /* count the last c or C */
548: fp++; /* move past last c or C */
549: if (l < c) {
550: d = (c - l)/2;
551: k = (c - l) - d;
552:
553: /* this next line is for testing
554: printf( "d = %d c = %d k = %d l = %d, d, c, k, l);*/
555:
556: while (d--)
557: fprintf(file, " ");
558: while (l-- > 0)
559: fprintf(file, "%.1s", p++);
560: while (k-- > 0)
561: fprintf(file, " ");
562: }
563: else {
564: d = (l - c)/2;
565: p = p + d;
566: while (c-- > 0)
567: fprintf(file, "%.1s", p++);
568: }
569: return(fp);
570: break;
571: default:
572: fprintf(file, "'");
573: break;
574:
575: }
576: }
577: return(fp);
578: }
579:
580:
581: /*
582: * prtstmt --- interpret a PRINT statement
583: */
584:
585: prtstmt()
586: {
587: register struct iotab *i;
588:
589: i = getunit(OUTPUT, OUTUNIT);
590: col = i->io_col;
591: print(i->io_ptr);
592: i->io_col = col;
593: }
594:
595:
596: /*
597: * clsstmt --- interpret a CLOSE statement
598: */
599:
600: clsstmt()
601: {
602: register struct iotab *i;
603:
604: i = getunit(0, 0);
605: iocls(i);
606: }
607:
608:
609: /*
610: * flsstmt --- interpret a FLUSH statement
611: */
612:
613: flsstmt()
614: {
615: register struct iotab *i;
616:
617: i = getunit(OUTPUT, OUTUNIT);
618: if (i->io_flag == OUTPUT)
619: fflush(i->io_ptr);
620: }
621:
622:
623: /*
624: * print --- do the work for a PRINT statement
625: */
626:
627: print(file)
628: FILE *file;
629: {
630: register Stkptr s;
631: register int l;
632: int flag;
633: float f;
634:
635: flag = NO;
636: while (!endtest()) {
637: flag = NO;
638: if (*inptr == TAB) { /* tab(expr) */
639: ++inptr;
640: l = fexpr();
641: if (l < 0 || l > 80)
642: l = 1;
643: expectc(RPAR);
644: while (col < l - 8)
645: printstr("\t", 1, file);
646: if (col < l)
647: printstr(" ", l - col, file);
648: }
649: else {
650: expr();
651: s = (Stkptr)stkptr;
652: switch (s->k_type) {
653: case FLOATEXPR:
654: printstr(fprint(popfloat()), MAXSTR, file);
655: break;
656: case STRINGEXPR:
657: pop(ANYTYPE);
658: printstr(s->k_un.k_str.s_ptr,
659: s->k_un.k_str.s_len, file);
660: break;
661: default:
662: badtype();
663: }
664: }
665: switch(*inptr) {
666: case COMMA:
667: ++inptr;
668: printstr("\t", 1, file);
669: if ((col % 16) == 9)
670: printstr("\t", 1, file);
671: flag = YES; /* suppress the NL */
672: break;
673: case ';':
674: ++inptr;
675: flag = YES;
676: break;
677: case '\0':
678: case ELSE:
679: case COLON:
680: break;
681: default:
682: badsyn();
683: }
684: }
685: if (!flag)
686: printstr("\n", 1, file);
687: if (file == stdout)
688: fflush(file);
689: }
690:
691:
692: /*
693: * printstr --- print a string of specified length; update col
694: */
695:
696: printstr(ptr, len, file)
697: char *ptr;
698: FILE *file;
699: {
700: register int c, l;
701: register char *p;
702:
703: l = len;
704: if ((p = ptr) == NULL && l)
705: err("invalid string pointer");
706: while (--l >= 0 && (c = *p++)) {
707: switch (c) {
708: case '\n':
709: col = 1;
710: break;
711: case '\t':
712: col = ((col-1 + 8) & ~07) + 1;
713: break;
714: default:
715: col++;
716: break;
717: }
718: putc(c, file);
719: }
720: }
721:
722:
723: /*
724: * ask --- interpret an INPUT or ASK statement
725: */
726:
727: ask()
728: {
729: register char *v;
730: char *ptr;
731: int len, type;
732: FILE *f;
733:
734: f = getunit(INPUT, INUNIT)->io_ptr;
735: askptr = askline;
736: askline[0] = 0;
737: while (!endtest()) {
738: if (*inptr == QUOTE || *inptr == PRIME) {
739: strconst(*inptr++);
740: popstring(&ptr, &len);
741: printstr(ptr, len, stderr);
742: optional(askdelims);
743: }
744: v = getsvar(&type);
745: optional(askdelims);
746: while (*askptr == ' ')
747: ++askptr;
748: if (*askptr == 0) {
749: if (f == stdin)
750: fputs("? ", stderr);
751: if (readline(askline, f) < 0)
752: err("EOF on input");
753: askptr = askline;
754: }
755: cvtdata(v, type, &askptr);
756: }
757: }
758:
759:
760: /*
761: * morefiledata --- check to see if specified file is at end
762: */
763:
764: morefiledata()
765: {
766: int c;
767: FILE *f;
768:
769: f = getunit(INPUT, INUNIT)->io_ptr;
770: if ((c = getc(f)) != EOF) {
771:
772: /* not at end of file. put character back and return 1 */
773:
774: ungetc(c, f);
775: return(1);
776: }
777: else
778:
779: /* at end of file. return 0 */
780:
781: return(0);
782:
783: }
784: /*
785: * strpop --- pop string from stack; convert to null-terminated format
786: */
787:
788: char *strpop()
789: {
790: static char strtemp[MAXSTR];
791: char *str;
792: int len;
793:
794: popstring(&str, &len);
795: if (len >= MAXSTR - 1)
796: err("string too long");
797: move(len, str, strtemp);
798: strtemp[len] = 0;
799: return(strtemp);
800: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.