|
|
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.