Annotation of 43BSD/ucb/pascal/src/proc.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Copyright (c) 1980 Regents of the University of California.
                      3:  * All rights reserved.  The Berkeley software License Agreement
                      4:  * specifies the terms and conditions for redistribution.
                      5:  */
                      6: 
                      7: #ifndef lint
                      8: static char sccsid[] = "@(#)proc.c     5.1 (Berkeley) 6/5/85";
                      9: #endif not lint
                     10: 
                     11: #include "whoami.h"
                     12: #ifdef OBJ
                     13:     /*
                     14:      * and the rest of the file
                     15:      */
                     16: #include "0.h"
                     17: #include "tree.h"
                     18: #include "opcode.h"
                     19: #include "objfmt.h"
                     20: #include "tmps.h"
                     21: #include "tree_ty.h"
                     22: 
                     23: /*
                     24:  * The constant EXPOSIZE specifies the number of digits in the exponent
                     25:  * of real numbers.
                     26:  *
                     27:  * The constant REALSPC defines the amount of forced padding preceeding
                     28:  * real numbers when they are printed. If REALSPC == 0, then no padding
                     29:  * is added, REALSPC == 1 adds one extra blank irregardless of the width
                     30:  * specified by the user.
                     31:  *
                     32:  * N.B. - Values greater than one require program mods.
                     33:  */
                     34: #define EXPOSIZE       2
                     35: #define        REALSPC         0
                     36: 
                     37: /*
                     38:  * The following array is used to determine which classes may be read
                     39:  * from textfiles. It is indexed by the return value from classify.
                     40:  */
                     41: #define rdops(x) rdxxxx[(x)-(TFIRST)]
                     42: 
                     43: int rdxxxx[] = {
                     44:        0,              /* -7 file types */
                     45:        0,              /* -6 record types */
                     46:        0,              /* -5 array types */
                     47:        O_READE,        /* -4 scalar types */
                     48:        0,              /* -3 pointer types */
                     49:        0,              /* -2 set types */
                     50:        0,              /* -1 string types */
                     51:        0,              /*  0 nil, no type */
                     52:        O_READE,        /*  1 boolean */
                     53:        O_READC,        /*  2 character */
                     54:        O_READ4,        /*  3 integer */
                     55:        O_READ8         /*  4 real */
                     56: };
                     57: 
                     58: /*
                     59:  * Proc handles procedure calls.
                     60:  * Non-builtin procedures are "buck-passed" to func (with a flag
                     61:  * indicating that they are actually procedures.
                     62:  * builtin procedures are handled here.
                     63:  */
                     64: proc(r)
                     65:        struct tnode *r;
                     66: {
                     67:        register struct nl *p;
                     68:        register struct tnode *alv, *al;
                     69:        register int op;
                     70:        struct nl *filetype, *ap, *al1;
                     71:        int argc, typ, fmtspec, strfmt, stkcnt;
                     72:        struct tnode *argv; 
                     73:        char fmt, format[20], *strptr, *pu;
                     74:        int prec, field, strnglen, fmtlen, fmtstart;
                     75:        struct tnode *pua, *pui, *puz, *file;
                     76:        int i, j, k;
                     77:        int itemwidth;
                     78:        struct tmps soffset;
                     79:        struct nl       *tempnlp;
                     80: 
                     81: #define        CONPREC 4
                     82: #define        VARPREC 8
                     83: #define        CONWIDTH 1
                     84: #define        VARWIDTH 2
                     85: #define SKIP 16
                     86: 
                     87:        /*
                     88:         * Verify that the name is
                     89:         * defined and is that of a
                     90:         * procedure.
                     91:         */
                     92:        p = lookup(r->pcall_node.proc_id);
                     93:        if (p == NIL) {
                     94:                rvlist(r->pcall_node.arg);
                     95:                return;
                     96:        }
                     97:        if (p->class != PROC && p->class != FPROC) {
                     98:                error("Can't call %s, its %s not a procedure", p->symbol, classes[p->class]);
                     99:                rvlist(r->pcall_node.arg);
                    100:                return;
                    101:        }
                    102:        argv = r->pcall_node.arg;
                    103: 
                    104:        /*
                    105:         * Call handles user defined
                    106:         * procedures and functions.
                    107:         */
                    108:        if (bn != 0) {
                    109:                (void) call(p, argv, PROC, bn);
                    110:                return;
                    111:        }
                    112: 
                    113:        /*
                    114:         * Call to built-in procedure.
                    115:         * Count the arguments.
                    116:         */
                    117:        argc = 0;
                    118:        for (al = argv; al != TR_NIL; al = al->list_node.next)
                    119:                argc++;
                    120: 
                    121:        /*
                    122:         * Switch on the operator
                    123:         * associated with the built-in
                    124:         * procedure in the namelist
                    125:         */
                    126:        op = p->value[0] &~ NSTAND;
                    127:        if (opt('s') && (p->value[0] & NSTAND)) {
                    128:                standard();
                    129:                error("%s is a nonstandard procedure", p->symbol);
                    130:        }
                    131:        switch (op) {
                    132: 
                    133:        case O_ABORT:
                    134:                if (argc != 0)
                    135:                        error("null takes no arguments");
                    136:                return;
                    137: 
                    138:        case O_FLUSH:
                    139:                if (argc == 0) {
                    140:                        (void) put(1, O_MESSAGE);
                    141:                        return;
                    142:                }
                    143:                if (argc != 1) {
                    144:                        error("flush takes at most one argument");
                    145:                        return;
                    146:                }
                    147:                ap = stklval(argv->list_node.list, NIL );
                    148:                if (ap == NLNIL)
                    149:                        return;
                    150:                if (ap->class != FILET) {
                    151:                        error("flush's argument must be a file, not %s", nameof(ap));
                    152:                        return;
                    153:                }
                    154:                (void) put(1, op);
                    155:                return;
                    156: 
                    157:        case O_MESSAGE:
                    158:        case O_WRITEF:
                    159:        case O_WRITLN:
                    160:                /*
                    161:                 * Set up default file "output"'s type
                    162:                 */
                    163:                file = NIL;
                    164:                filetype = nl+T1CHAR;
                    165:                /*
                    166:                 * Determine the file implied
                    167:                 * for the write and generate
                    168:                 * code to make it the active file.
                    169:                 */
                    170:                if (op == O_MESSAGE) {
                    171:                        /*
                    172:                         * For message, all that matters
                    173:                         * is that the filetype is
                    174:                         * a character file.
                    175:                         * Thus "output" will suit us fine.
                    176:                         */
                    177:                        (void) put(1, O_MESSAGE);
                    178:                } else if (argv != TR_NIL && (al = argv->list_node.list)->tag !=
                    179:                                        T_WEXP) {
                    180:                        /*
                    181:                         * If there is a first argument which has
                    182:                         * no write widths, then it is potentially
                    183:                         * a file name.
                    184:                         */
                    185:                        codeoff();
                    186:                        ap = stkrval(argv->list_node.list, NLNIL, (long) RREQ );
                    187:                        codeon();
                    188:                        if (ap == NLNIL)
                    189:                                argv = argv->list_node.next;
                    190:                        if (ap != NLNIL && ap->class == FILET) {
                    191:                                /*
                    192:                                 * Got "write(f, ...", make
                    193:                                 * f the active file, and save
                    194:                                 * it and its type for use in
                    195:                                 * processing the rest of the
                    196:                                 * arguments to write.
                    197:                                 */
                    198:                                file = argv->list_node.list;
                    199:                                filetype = ap->type;
                    200:                                (void) stklval(argv->list_node.list, NIL );
                    201:                                (void) put(1, O_UNIT);
                    202:                                /*
                    203:                                 * Skip over the first argument
                    204:                                 */
                    205:                                argv = argv->list_node.next;
                    206:                                argc--;
                    207:                        } else {
                    208:                                /*
                    209:                                 * Set up for writing on 
                    210:                                 * standard output.
                    211:                                 */
                    212:                                (void) put(1, O_UNITOUT);
                    213:                                output->nl_flags |= NUSED;
                    214:                        }
                    215:                } else {
                    216:                        (void) put(1, O_UNITOUT);
                    217:                        output->nl_flags |= NUSED;
                    218:                }
                    219:                /*
                    220:                 * Loop and process each
                    221:                 * of the arguments.
                    222:                 */
                    223:                for (; argv != TR_NIL; argv = argv->list_node.next) {
                    224:                        /*
                    225:                         * fmtspec indicates the type (CONstant or VARiable)
                    226:                         *      and number (none, WIDTH, and/or PRECision)
                    227:                         *      of the fields in the printf format for this
                    228:                         *      output variable.
                    229:                         * stkcnt is the number of bytes pushed on the stack
                    230:                         * fmt is the format output indicator (D, E, F, O, X, S)
                    231:                         * fmtstart = 0 for leading blank; = 1 for no blank
                    232:                         */
                    233:                        fmtspec = NIL;
                    234:                        stkcnt = 0;
                    235:                        fmt = 'D';
                    236:                        fmtstart = 1;
                    237:                        al = argv->list_node.list;
                    238:                        if (al == TR_NIL)
                    239:                                continue;
                    240:                        if (al->tag == T_WEXP)
                    241:                                alv = al->wexpr_node.expr1;
                    242:                        else
                    243:                                alv = al;
                    244:                        if (alv == TR_NIL)
                    245:                                continue;
                    246:                        codeoff();
                    247:                        ap = stkrval(alv, NLNIL , (long) RREQ );
                    248:                        codeon();
                    249:                        if (ap == NLNIL)
                    250:                                continue;
                    251:                        typ = classify(ap);
                    252:                        if (al->tag == T_WEXP) {
                    253:                                /*
                    254:                                 * Handle width expressions.
                    255:                                 * The basic game here is that width
                    256:                                 * expressions get evaluated. If they
                    257:                                 * are constant, the value is placed
                    258:                                 * directly in the format string.
                    259:                                 * Otherwise the value is pushed onto
                    260:                                 * the stack and an indirection is
                    261:                                 * put into the format string.
                    262:                                 */
                    263:                                if (al->wexpr_node.expr3 == 
                    264:                                                (struct tnode *) OCT)
                    265:                                        fmt = 'O';
                    266:                                else if (al->wexpr_node.expr3 == 
                    267:                                                (struct tnode *) HEX)
                    268:                                        fmt = 'X';
                    269:                                else if (al->wexpr_node.expr3 != TR_NIL) {
                    270:                                        /*
                    271:                                         * Evaluate second format spec
                    272:                                         */
                    273:                                        if ( constval(al->wexpr_node.expr3)
                    274:                                            && isa( con.ctype , "i" ) ) {
                    275:                                                fmtspec += CONPREC;
                    276:                                                prec = con.crval;
                    277:                                        } else {
                    278:                                                fmtspec += VARPREC;
                    279:                                        }
                    280:                                        fmt = 'f';
                    281:                                        switch ( typ ) {
                    282:                                        case TINT:
                    283:                                                if ( opt( 's' ) ) {
                    284:                                                    standard();
                    285:                                                    error("Writing %ss with two write widths is non-standard", clnames[typ]);
                    286:                                                }
                    287:                                                /* and fall through */
                    288:                                        case TDOUBLE:
                    289:                                                break;
                    290:                                        default:
                    291:                                                error("Cannot write %ss with two write widths", clnames[typ]);
                    292:                                                continue;
                    293:                                        }
                    294:                                }
                    295:                                /*
                    296:                                 * Evaluate first format spec
                    297:                                 */
                    298:                                if (al->wexpr_node.expr2 != TR_NIL) {
                    299:                                        if ( constval(al->wexpr_node.expr2)
                    300:                                            && isa( con.ctype , "i" ) ) {
                    301:                                                fmtspec += CONWIDTH;
                    302:                                                field = con.crval;
                    303:                                        } else {
                    304:                                                fmtspec += VARWIDTH;
                    305:                                        }
                    306:                                }
                    307:                                if ((fmtspec & CONPREC) && prec < 0 ||
                    308:                                    (fmtspec & CONWIDTH) && field < 0) {
                    309:                                        error("Negative widths are not allowed");
                    310:                                        continue;
                    311:                                }
                    312:                                if ( opt('s') &&
                    313:                                    ((fmtspec & CONPREC) && prec == 0 ||
                    314:                                    (fmtspec & CONWIDTH) && field == 0)) {
                    315:                                        standard();
                    316:                                        error("Zero widths are non-standard");
                    317:                                }
                    318:                        }
                    319:                        if (filetype != nl+T1CHAR) {
                    320:                                if (fmt == 'O' || fmt == 'X') {
                    321:                                        error("Oct/hex allowed only on text files");
                    322:                                        continue;
                    323:                                }
                    324:                                if (fmtspec) {
                    325:                                        error("Write widths allowed only on text files");
                    326:                                        continue;
                    327:                                }
                    328:                                /*
                    329:                                 * Generalized write, i.e.
                    330:                                 * to a non-textfile.
                    331:                                 */
                    332:                                (void) stklval(file, NIL );
                    333:                                (void) put(1, O_FNIL);
                    334:                                /*
                    335:                                 * file^ := ...
                    336:                                 */
                    337:                                ap = rvalue(argv->list_node.list, NLNIL, LREQ);
                    338:                                if (ap == NLNIL)
                    339:                                        continue;
                    340:                                if (incompat(ap, filetype,
                    341:                                                argv->list_node.list)) {
                    342:                                        cerror("Type mismatch in write to non-text file");
                    343:                                        continue;
                    344:                                }
                    345:                                convert(ap, filetype);
                    346:                                (void) put(2, O_AS, width(filetype));
                    347:                                /*
                    348:                                 * put(file)
                    349:                                 */
                    350:                                (void) put(1, O_PUT);
                    351:                                continue;
                    352:                        }
                    353:                        /*
                    354:                         * Write to a textfile
                    355:                         *
                    356:                         * Evaluate the expression
                    357:                         * to be written.
                    358:                         */
                    359:                        if (fmt == 'O' || fmt == 'X') {
                    360:                                if (opt('s')) {
                    361:                                        standard();
                    362:                                        error("Oct and hex are non-standard");
                    363:                                }
                    364:                                if (typ == TSTR || typ == TDOUBLE) {
                    365:                                        error("Can't write %ss with oct/hex", clnames[typ]);
                    366:                                        continue;
                    367:                                }
                    368:                                if (typ == TCHAR || typ == TBOOL)
                    369:                                        typ = TINT;
                    370:                        }
                    371:                        /*
                    372:                         * Place the arguement on the stack. If there is
                    373:                         * no format specified by the programmer, implement
                    374:                         * the default.
                    375:                         */
                    376:                        switch (typ) {
                    377:                        case TPTR:
                    378:                                warning();
                    379:                                if (opt('s')) {
                    380:                                        standard();
                    381:                                }
                    382:                                error("Writing %ss to text files is non-standard",
                    383:                                    clnames[typ]);
                    384:                                /* and fall through */
                    385:                        case TINT:
                    386:                                if (fmt != 'f') {
                    387:                                        ap = stkrval(alv, NLNIL, (long) RREQ );
                    388:                                        stkcnt += sizeof(long);
                    389:                                } else {
                    390:                                        ap = stkrval(alv, NLNIL, (long) RREQ );
                    391:                                        (void) put(1, O_ITOD);
                    392:                                        stkcnt += sizeof(double);
                    393:                                        typ = TDOUBLE;
                    394:                                        goto tdouble;
                    395:                                }
                    396:                                if (fmtspec == NIL) {
                    397:                                        if (fmt == 'D')
                    398:                                                field = 10;
                    399:                                        else if (fmt == 'X')
                    400:                                                field = 8;
                    401:                                        else if (fmt == 'O')
                    402:                                                field = 11;
                    403:                                        else
                    404:                                                panic("fmt1");
                    405:                                        fmtspec = CONWIDTH;
                    406:                                }
                    407:                                break;
                    408:                        case TCHAR:
                    409:                             tchar:
                    410:                                if (fmtspec == NIL) {
                    411:                                        (void) put(1, O_FILE);
                    412:                                        ap = stkrval(alv, NLNIL, (long) RREQ );
                    413:                                        convert(nl + T4INT, INT_TYP);
                    414:                                        (void) put(2, O_WRITEC,
                    415:                                                sizeof(char *) + sizeof(int));
                    416:                                        fmtspec = SKIP;
                    417:                                        break;
                    418:                                }
                    419:                                ap = stkrval(alv, NLNIL , (long) RREQ );
                    420:                                convert(nl + T4INT, INT_TYP);
                    421:                                stkcnt += sizeof(int);
                    422:                                fmt = 'c';
                    423:                                break;
                    424:                        case TSCAL:
                    425:                                warning();
                    426:                                if (opt('s')) {
                    427:                                        standard();
                    428:                                }
                    429:                                error("Writing %ss to text files is non-standard",
                    430:                                    clnames[typ]);
                    431:                                /* and fall through */
                    432:                        case TBOOL:
                    433:                                (void) stkrval(alv, NLNIL , (long) RREQ );
                    434:                                (void) put(2, O_NAM, (long)listnames(ap));
                    435:                                stkcnt += sizeof(char *);
                    436:                                fmt = 's';
                    437:                                break;
                    438:                        case TDOUBLE:
                    439:                                ap = stkrval(alv, (struct nl *) TDOUBLE , (long) RREQ );
                    440:                                stkcnt += sizeof(double);
                    441:                             tdouble:
                    442:                                switch (fmtspec) {
                    443:                                case NIL:
                    444:                                        field = 14 + (5 + EXPOSIZE);
                    445:                                        prec = field - (5 + EXPOSIZE);
                    446:                                        fmt = 'e';
                    447:                                        fmtspec = CONWIDTH + CONPREC;
                    448:                                        break;
                    449:                                case CONWIDTH:
                    450:                                        field -= REALSPC;
                    451:                                        if (field < 1)
                    452:                                                field = 1;
                    453:                                        prec = field - (5 + EXPOSIZE);
                    454:                                        if (prec < 1)
                    455:                                                prec = 1;
                    456:                                        fmtspec += CONPREC;
                    457:                                        fmt = 'e';
                    458:                                        break;
                    459:                                case CONWIDTH + CONPREC:
                    460:                                case CONWIDTH + VARPREC:
                    461:                                        field -= REALSPC;
                    462:                                        if (field < 1)
                    463:                                                field = 1;
                    464:                                }
                    465:                                format[0] = ' ';
                    466:                                fmtstart = 1 - REALSPC;
                    467:                                break;
                    468:                        case TSTR:
                    469:                                (void) constval( alv );
                    470:                                switch ( classify( con.ctype ) ) {
                    471:                                    case TCHAR:
                    472:                                        typ = TCHAR;
                    473:                                        goto tchar;
                    474:                                    case TSTR:
                    475:                                        strptr = con.cpval;
                    476:                                        for (strnglen = 0;  *strptr++;  strnglen++) /* void */;
                    477:                                        strptr = con.cpval;
                    478:                                        break;
                    479:                                    default:
                    480:                                        strnglen = width(ap);
                    481:                                        break;
                    482:                                }
                    483:                                fmt = 's';
                    484:                                strfmt = fmtspec;
                    485:                                if (fmtspec == NIL) {
                    486:                                        fmtspec = SKIP;
                    487:                                        break;
                    488:                                }
                    489:                                if (fmtspec & CONWIDTH) {
                    490:                                        if (field <= strnglen) {
                    491:                                                fmtspec = SKIP;
                    492:                                                break;
                    493:                                        } else
                    494:                                                field -= strnglen;
                    495:                                }
                    496:                                /*
                    497:                                 * push string to implement leading blank padding
                    498:                                 */
                    499:                                (void) put(2, O_LVCON, 2);
                    500:                                putstr("", 0);
                    501:                                stkcnt += sizeof(char *);
                    502:                                break;
                    503:                        default:
                    504:                                error("Can't write %ss to a text file", clnames[typ]);
                    505:                                continue;
                    506:                        }
                    507:                        /*
                    508:                         * If there is a variable precision, evaluate it onto
                    509:                         * the stack
                    510:                         */
                    511:                        if (fmtspec & VARPREC) {
                    512:                                ap = stkrval(al->wexpr_node.expr3, NLNIL ,
                    513:                                                (long) RREQ );
                    514:                                if (ap == NIL)
                    515:                                        continue;
                    516:                                if (isnta(ap,"i")) {
                    517:                                        error("Second write width must be integer, not %s", nameof(ap));
                    518:                                        continue;
                    519:                                }
                    520:                                if ( opt( 't' ) ) {
                    521:                                    (void) put(3, O_MAX, 0, 0);
                    522:                                }
                    523:                                convert(nl+T4INT, INT_TYP);
                    524:                                stkcnt += sizeof(int);
                    525:                        }
                    526:                        /*
                    527:                         * If there is a variable width, evaluate it onto
                    528:                         * the stack
                    529:                         */
                    530:                        if (fmtspec & VARWIDTH) {
                    531:                                if ( ( typ == TDOUBLE && fmtspec == VARWIDTH )
                    532:                                    || typ == TSTR ) {
                    533:                                        soffset = sizes[cbn].curtmps;
                    534:                                        tempnlp = tmpalloc((long) (sizeof(long)),
                    535:                                                nl+T4INT, REGOK);
                    536:                                        (void) put(2, O_LV | cbn << 8 + INDX, 
                    537:                                            tempnlp -> value[ NL_OFFS ] );
                    538:                                }
                    539:                                ap = stkrval(al->wexpr_node.expr2, NLNIL, (long) RREQ );
                    540:                                if (ap == NIL)
                    541:                                        continue;
                    542:                                if (isnta(ap,"i")) {
                    543:                                        error("First write width must be integer, not %s", nameof(ap));
                    544:                                        continue;
                    545:                                }
                    546:                                /*
                    547:                                 * Perform special processing on widths based
                    548:                                 * on data type 
                    549:                                 */
                    550:                                switch (typ) {
                    551:                                case TDOUBLE:
                    552:                                        if (fmtspec == VARWIDTH) {
                    553:                                                fmt = 'e';
                    554:                                                (void) put(1, O_AS4);
                    555:                                                (void) put(2, O_RV4 | cbn << 8 + INDX,
                    556:                                                    tempnlp -> value[NL_OFFS] );
                    557:                                                (void) put(3, O_MAX,
                    558:                                                    5 + EXPOSIZE + REALSPC, 1);
                    559:                                                convert(nl+T4INT, INT_TYP);
                    560:                                                stkcnt += sizeof(int);
                    561:                                                (void) put(2, O_RV4 | cbn << 8 + INDX, 
                    562:                                                    tempnlp->value[NL_OFFS] );
                    563:                                                fmtspec += VARPREC;
                    564:                                                tmpfree(&soffset);
                    565:                                        }
                    566:                                        (void) put(3, O_MAX, REALSPC, 1);
                    567:                                        break;
                    568:                                case TSTR:
                    569:                                        (void) put(1, O_AS4);
                    570:                                        (void) put(2, O_RV4 | cbn << 8 + INDX, 
                    571:                                            tempnlp -> value[ NL_OFFS ] );
                    572:                                        (void) put(3, O_MAX, strnglen, 0);
                    573:                                        break;
                    574:                                default:
                    575:                                        if ( opt( 't' ) ) {
                    576:                                            (void) put(3, O_MAX, 0, 0);
                    577:                                        }
                    578:                                        break;
                    579:                                }
                    580:                                convert(nl+T4INT, INT_TYP);
                    581:                                stkcnt += sizeof(int);
                    582:                        }
                    583:                        /*
                    584:                         * Generate the format string
                    585:                         */
                    586:                        switch (fmtspec) {
                    587:                        default:
                    588:                                panic("fmt2");
                    589:                        case SKIP:
                    590:                                break;
                    591:                        case NIL:
                    592:                                sprintf(&format[1], "%%%c", fmt);
                    593:                                goto fmtgen;
                    594:                        case CONWIDTH:
                    595:                                sprintf(&format[1], "%%%d%c", field, fmt);
                    596:                                goto fmtgen;
                    597:                        case VARWIDTH:
                    598:                                sprintf(&format[1], "%%*%c", fmt);
                    599:                                goto fmtgen;
                    600:                        case CONWIDTH + CONPREC:
                    601:                                sprintf(&format[1], "%%%d.%d%c", field, prec, fmt);
                    602:                                goto fmtgen;
                    603:                        case CONWIDTH + VARPREC:
                    604:                                sprintf(&format[1], "%%%d.*%c", field, fmt);
                    605:                                goto fmtgen;
                    606:                        case VARWIDTH + CONPREC:
                    607:                                sprintf(&format[1], "%%*.%d%c", prec, fmt);
                    608:                                goto fmtgen;
                    609:                        case VARWIDTH + VARPREC:
                    610:                                sprintf(&format[1], "%%*.*%c", fmt);
                    611:                        fmtgen:
                    612:                                fmtlen = lenstr(&format[fmtstart], 0);
                    613:                                (void) put(2, O_LVCON, fmtlen);
                    614:                                putstr(&format[fmtstart], 0);
                    615:                                (void) put(1, O_FILE);
                    616:                                stkcnt += 2 * sizeof(char *);
                    617:                                (void) put(2, O_WRITEF, stkcnt);
                    618:                        }
                    619:                        /*
                    620:                         * Write the string after its blank padding
                    621:                         */
                    622:                        if (typ == TSTR) {
                    623:                                (void) put(1, O_FILE);
                    624:                                (void) put(2, CON_INT, 1);
                    625:                                if (strfmt & VARWIDTH) {
                    626:                                        (void) put(2, O_RV4 | cbn << 8 + INDX , 
                    627:                                            tempnlp -> value[ NL_OFFS ] );
                    628:                                        (void) put(2, O_MIN, strnglen);
                    629:                                        convert(nl+T4INT, INT_TYP);
                    630:                                        tmpfree(&soffset);
                    631:                                } else {
                    632:                                        if ((fmtspec & SKIP) &&
                    633:                                           (strfmt & CONWIDTH)) {
                    634:                                                strnglen = field;
                    635:                                        }
                    636:                                        (void) put(2, CON_INT, strnglen);
                    637:                                }
                    638:                                ap = stkrval(alv, NLNIL , (long) RREQ );
                    639:                                (void) put(2, O_WRITES,
                    640:                                        2 * sizeof(char *) + 2 * sizeof(int));
                    641:                        }
                    642:                }
                    643:                /*
                    644:                 * Done with arguments.
                    645:                 * Handle writeln and
                    646:                 * insufficent number of args.
                    647:                 */
                    648:                switch (p->value[0] &~ NSTAND) {
                    649:                        case O_WRITEF:
                    650:                                if (argc == 0)
                    651:                                        error("Write requires an argument");
                    652:                                break;
                    653:                        case O_MESSAGE:
                    654:                                if (argc == 0)
                    655:                                        error("Message requires an argument");
                    656:                        case O_WRITLN:
                    657:                                if (filetype != nl+T1CHAR)
                    658:                                        error("Can't 'writeln' a non text file");
                    659:                                (void) put(1, O_WRITLN);
                    660:                                break;
                    661:                }
                    662:                return;
                    663: 
                    664:        case O_READ4:
                    665:        case O_READLN:
                    666:                /*
                    667:                 * Set up default
                    668:                 * file "input".
                    669:                 */
                    670:                file = NIL;
                    671:                filetype = nl+T1CHAR;
                    672:                /*
                    673:                 * Determine the file implied
                    674:                 * for the read and generate
                    675:                 * code to make it the active file.
                    676:                 */
                    677:                if (argv != TR_NIL) {
                    678:                        codeoff();
                    679:                        ap = stkrval(argv->list_node.list, NLNIL, (long) RREQ );
                    680:                        codeon();
                    681:                        if (ap == NLNIL)
                    682:                                argv = argv->list_node.next;
                    683:                        if (ap != NLNIL && ap->class == FILET) {
                    684:                                /*
                    685:                                 * Got "read(f, ...", make
                    686:                                 * f the active file, and save
                    687:                                 * it and its type for use in
                    688:                                 * processing the rest of the
                    689:                                 * arguments to read.
                    690:                                 */
                    691:                                file = argv->list_node.list;
                    692:                                filetype = ap->type;
                    693:                                (void) stklval(argv->list_node.list, NIL );
                    694:                                (void) put(1, O_UNIT);
                    695:                                argv = argv->list_node.next;
                    696:                                argc--;
                    697:                        } else {
                    698:                                /*
                    699:                                 * Default is read from
                    700:                                 * standard input.
                    701:                                 */
                    702:                                (void) put(1, O_UNITINP);
                    703:                                input->nl_flags |= NUSED;
                    704:                        }
                    705:                } else {
                    706:                        (void) put(1, O_UNITINP);
                    707:                        input->nl_flags |= NUSED;
                    708:                }
                    709:                /*
                    710:                 * Loop and process each
                    711:                 * of the arguments.
                    712:                 */
                    713:                for (; argv != TR_NIL; argv = argv->list_node.next) {
                    714:                        /*
                    715:                         * Get the address of the target
                    716:                         * on the stack.
                    717:                         */
                    718:                        al = argv->list_node.list;
                    719:                        if (al == TR_NIL)
                    720:                                continue;
                    721:                        if (al->tag != T_VAR) {
                    722:                                error("Arguments to %s must be variables, not expressions", p->symbol);
                    723:                                continue;
                    724:                        }
                    725:                        ap = stklval(al, MOD|ASGN|NOUSE);
                    726:                        if (ap == NLNIL)
                    727:                                continue;
                    728:                        if (filetype != nl+T1CHAR) {
                    729:                                /*
                    730:                                 * Generalized read, i.e.
                    731:                                 * from a non-textfile.
                    732:                                 */
                    733:                                if (incompat(filetype, ap,
                    734:                                        argv->list_node.list )) {
                    735:                                        error("Type mismatch in read from non-text file");
                    736:                                        continue;
                    737:                                }
                    738:                                /*
                    739:                                 * var := file ^;
                    740:                                 */
                    741:                                if (file != NIL)
                    742:                                    (void) stklval(file, NIL);
                    743:                                else /* Magic */
                    744:                                    (void) put(2, PTR_RV, (int)input->value[0]);
                    745:                                (void) put(1, O_FNIL);
                    746:                                if (isa(filetype, "bcsi")) {
                    747:                                    int filewidth = width(filetype);
                    748: 
                    749:                                    switch (filewidth) {
                    750:                                        case 4:
                    751:                                            (void) put(1, O_IND4);
                    752:                                            break;
                    753:                                        case 2:
                    754:                                            (void) put(1, O_IND2);
                    755:                                            break;
                    756:                                        case 1:
                    757:                                            (void) put(1, O_IND1);
                    758:                                            break;
                    759:                                        default:
                    760:                                            (void) put(2, O_IND, filewidth);
                    761:                                    }
                    762:                                    convert(filetype, ap);
                    763:                                    rangechk(ap, ap);
                    764:                                    (void) gen(O_AS2, O_AS2,
                    765:                                            filewidth, width(ap));
                    766:                                } else {
                    767:                                    (void) put(2, O_IND, width(filetype));
                    768:                                    convert(filetype, ap);
                    769:                                    (void) put(2, O_AS, width(ap));
                    770:                                }
                    771:                                /*
                    772:                                 * get(file);
                    773:                                 */
                    774:                                (void) put(1, O_GET);
                    775:                                continue;
                    776:                        }
                    777:                        typ = classify(ap);
                    778:                        op = rdops(typ);
                    779:                        if (op == NIL) {
                    780:                                error("Can't read %ss from a text file", clnames[typ]);
                    781:                                continue;
                    782:                        }
                    783:                        if (op != O_READE)
                    784:                                (void) put(1, op);
                    785:                        else {
                    786:                                (void) put(2, op, (long)listnames(ap));
                    787:                                warning();
                    788:                                if (opt('s')) {
                    789:                                        standard();
                    790:                                }
                    791:                                error("Reading scalars from text files is non-standard");
                    792:                        }
                    793:                        /*
                    794:                         * Data read is on the stack.
                    795:                         * Assign it.
                    796:                         */
                    797:                        if (op != O_READ8 && op != O_READE)
                    798:                                rangechk(ap, op == O_READC ? ap : nl+T4INT);
                    799:                        (void) gen(O_AS2, O_AS2, width(ap),
                    800:                                op == O_READ8 ? 8 : op == O_READ4 ? 4 : 2);
                    801:                }
                    802:                /*
                    803:                 * Done with arguments.
                    804:                 * Handle readln and
                    805:                 * insufficient number of args.
                    806:                 */
                    807:                if (p->value[0] == O_READLN) {
                    808:                        if (filetype != nl+T1CHAR)
                    809:                                error("Can't 'readln' a non text file");
                    810:                        (void) put(1, O_READLN);
                    811:                }
                    812:                else if (argc == 0)
                    813:                        error("read requires an argument");
                    814:                return;
                    815: 
                    816:        case O_GET:
                    817:        case O_PUT:
                    818:                if (argc != 1) {
                    819:                        error("%s expects one argument", p->symbol);
                    820:                        return;
                    821:                }
                    822:                ap = stklval(argv->list_node.list, NIL );
                    823:                if (ap == NLNIL)
                    824:                        return;
                    825:                if (ap->class != FILET) {
                    826:                        error("Argument to %s must be a file, not %s", p->symbol, nameof(ap));
                    827:                        return;
                    828:                }
                    829:                (void) put(1, O_UNIT);
                    830:                (void) put(1, op);
                    831:                return;
                    832: 
                    833:        case O_RESET:
                    834:        case O_REWRITE:
                    835:                if (argc == 0 || argc > 2) {
                    836:                        error("%s expects one or two arguments", p->symbol);
                    837:                        return;
                    838:                }
                    839:                if (opt('s') && argc == 2) {
                    840:                        standard();
                    841:                        error("Two argument forms of reset and rewrite are non-standard");
                    842:                }
                    843:                codeoff();
                    844:                ap = stklval(argv->list_node.list, MOD|NOUSE);
                    845:                codeon();
                    846:                if (ap == NLNIL)
                    847:                        return;
                    848:                if (ap->class != FILET) {
                    849:                        error("First argument to %s must be a file, not %s", p->symbol, nameof(ap));
                    850:                        return;
                    851:                }
                    852:                (void) put(2, O_CON24, text(ap) ? 0: width(ap->type));
                    853:                if (argc == 2) {
                    854:                        /*
                    855:                         * Optional second argument
                    856:                         * is a string name of a
                    857:                         * UNIX (R) file to be associated.
                    858:                         */
                    859:                        al = argv->list_node.next;
                    860:                        codeoff();
                    861:                        al = (struct tnode *) stkrval(al->list_node.list,
                    862:                                        (struct nl *) NOFLAGS , (long) RREQ );
                    863:                        codeon();
                    864:                        if (al == TR_NIL)
                    865:                                return;
                    866:                        if (classify((struct nl *) al) != TSTR) {
                    867:                                error("Second argument to %s must be a string, not %s", p->symbol, nameof((struct nl *) al));
                    868:                                return;
                    869:                        }
                    870:                        (void) put(2, O_CON24, width((struct nl *) al));
                    871:                        al = argv->list_node.next;
                    872:                        al = (struct tnode *) stkrval(al->list_node.list,
                    873:                                        (struct nl *) NOFLAGS , (long) RREQ );
                    874:                } else {
                    875:                        (void) put(2, O_CON24, 0);
                    876:                        (void) put(2, PTR_CON, NIL);
                    877:                }
                    878:                ap = stklval(argv->list_node.list, MOD|NOUSE);
                    879:                (void) put(1, op);
                    880:                return;
                    881: 
                    882:        case O_NEW:
                    883:        case O_DISPOSE:
                    884:                if (argc == 0) {
                    885:                        error("%s expects at least one argument", p->symbol);
                    886:                        return;
                    887:                }
                    888:                ap = stklval(argv->list_node.list,
                    889:                                op == O_NEW ? ( MOD | NOUSE ) : MOD );
                    890:                if (ap == NLNIL)
                    891:                        return;
                    892:                if (ap->class != PTR) {
                    893:                        error("(First) argument to %s must be a pointer, not %s", p->symbol, nameof(ap));
                    894:                        return;
                    895:                }
                    896:                ap = ap->type;
                    897:                if (ap == NIL)
                    898:                        return;
                    899:                if ((ap->nl_flags & NFILES) && op == O_DISPOSE)
                    900:                        op = O_DFDISP;
                    901:                argv = argv->list_node.next;
                    902:                if (argv != TR_NIL) {
                    903:                        if (ap->class != RECORD) {
                    904:                                error("Record required when specifying variant tags");
                    905:                                return;
                    906:                        }
                    907:                        for (; argv != TR_NIL; argv = argv->list_node.next) {
                    908:                                if (ap->ptr[NL_VARNT] == NIL) {
                    909:                                        error("Too many tag fields");
                    910:                                        return;
                    911:                                }
                    912:                                if (!isconst(argv->list_node.list)) {
                    913:                                        error("Second and successive arguments to %s must be constants", p->symbol);
                    914:                                        return;
                    915:                                }
                    916:                                gconst(argv->list_node.list);
                    917:                                if (con.ctype == NIL)
                    918:                                        return;
                    919:                                if (incompat(con.ctype, (
                    920:                                        ap->ptr[NL_TAG])->type , TR_NIL )) {
                    921:                                        cerror("Specified tag constant type clashed with variant case selector type");
                    922:                                        return;
                    923:                                }
                    924:                                for (ap = ap->ptr[NL_VARNT]; ap != NIL; ap = ap->chain)
                    925:                                        if (ap->range[0] == con.crval)
                    926:                                                break;
                    927:                                if (ap == NIL) {
                    928:                                        error("No variant case label value equals specified constant value");
                    929:                                        return;
                    930:                                }
                    931:                                ap = ap->ptr[NL_VTOREC];
                    932:                        }
                    933:                }
                    934:                (void) put(2, op, width(ap));
                    935:                return;
                    936: 
                    937:        case O_DATE:
                    938:        case O_TIME:
                    939:                if (argc != 1) {
                    940:                        error("%s expects one argument", p->symbol);
                    941:                        return;
                    942:                }
                    943:                ap = stklval(argv->list_node.list, MOD|NOUSE);
                    944:                if (ap == NLNIL)
                    945:                        return;
                    946:                if (classify(ap) != TSTR || width(ap) != 10) {
                    947:                        error("Argument to %s must be a alfa, not %s", p->symbol, nameof(ap));
                    948:                        return;
                    949:                }
                    950:                (void) put(1, op);
                    951:                return;
                    952: 
                    953:        case O_HALT:
                    954:                if (argc != 0) {
                    955:                        error("halt takes no arguments");
                    956:                        return;
                    957:                }
                    958:                (void) put(1, op);
                    959:                noreach = TRUE; /* used to be 1 */
                    960:                return;
                    961: 
                    962:        case O_ARGV:
                    963:                if (argc != 2) {
                    964:                        error("argv takes two arguments");
                    965:                        return;
                    966:                }
                    967:                ap = stkrval(argv->list_node.list, NLNIL , (long) RREQ );
                    968:                if (ap == NLNIL)
                    969:                        return;
                    970:                if (isnta(ap, "i")) {
                    971:                        error("argv's first argument must be an integer, not %s", nameof(ap));
                    972:                        return;
                    973:                }
                    974:                al = argv->list_node.next;
                    975:                ap = stklval(al->list_node.list, MOD|NOUSE);
                    976:                if (ap == NLNIL)
                    977:                        return;
                    978:                if (classify(ap) != TSTR) {
                    979:                        error("argv's second argument must be a string, not %s", nameof(ap));
                    980:                        return;
                    981:                }
                    982:                (void) put(2, op, width(ap));
                    983:                return;
                    984: 
                    985:        case O_STLIM:
                    986:                if (argc != 1) {
                    987:                        error("stlimit requires one argument");
                    988:                        return;
                    989:                }
                    990:                ap = stkrval(argv->list_node.list, NLNIL , (long) RREQ );
                    991:                if (ap == NLNIL)
                    992:                        return;
                    993:                if (isnta(ap, "i")) {
                    994:                        error("stlimit's argument must be an integer, not %s", nameof(ap));
                    995:                        return;
                    996:                }
                    997:                if (width(ap) != 4)
                    998:                        (void) put(1, O_STOI);
                    999:                (void) put(1, op);
                   1000:                return;
                   1001: 
                   1002:        case O_REMOVE:
                   1003:                if (argc != 1) {
                   1004:                        error("remove expects one argument");
                   1005:                        return;
                   1006:                }
                   1007:                codeoff();
                   1008:                ap = stkrval(argv->list_node.list, (struct nl *) NOFLAGS,
                   1009:                                (long) RREQ );
                   1010:                codeon();
                   1011:                if (ap == NLNIL)
                   1012:                        return;
                   1013:                if (classify(ap) != TSTR) {
                   1014:                        error("remove's argument must be a string, not %s", nameof(ap));
                   1015:                        return;
                   1016:                }
                   1017:                (void) put(2, O_CON24, width(ap));
                   1018:                ap = stkrval(argv->list_node.list, (struct nl *) NOFLAGS,
                   1019:                                (long) RREQ );
                   1020:                (void) put(1, op);
                   1021:                return;
                   1022: 
                   1023:        case O_LLIMIT:
                   1024:                if (argc != 2) {
                   1025:                        error("linelimit expects two arguments");
                   1026:                        return;
                   1027:                }
                   1028:                al = argv->list_node.next;
                   1029:                ap = stkrval(al->list_node.list, NLNIL , (long) RREQ );
                   1030:                if (ap == NIL)
                   1031:                        return;
                   1032:                if (isnta(ap, "i")) {
                   1033:                        error("linelimit's second argument must be an integer, not %s", nameof(ap));
                   1034:                        return;
                   1035:                }
                   1036:                ap = stklval(argv->list_node.list, NOFLAGS|NOUSE);
                   1037:                if (ap == NLNIL)
                   1038:                        return;
                   1039:                if (!text(ap)) {
                   1040:                        error("linelimit's first argument must be a text file, not %s", nameof(ap));
                   1041:                        return;
                   1042:                }
                   1043:                (void) put(1, op);
                   1044:                return;
                   1045:        case O_PAGE:
                   1046:                if (argc != 1) {
                   1047:                        error("page expects one argument");
                   1048:                        return;
                   1049:                }
                   1050:                ap = stklval(argv->list_node.list, NIL );
                   1051:                if (ap == NLNIL)
                   1052:                        return;
                   1053:                if (!text(ap)) {
                   1054:                        error("Argument to page must be a text file, not %s", nameof(ap));
                   1055:                        return;
                   1056:                }
                   1057:                (void) put(1, O_UNIT);
                   1058:                (void) put(1, op);
                   1059:                return;
                   1060: 
                   1061:        case O_ASRT:
                   1062:                if (!opt('t'))
                   1063:                        return;
                   1064:                if (argc == 0 || argc > 2) {
                   1065:                        error("Assert expects one or two arguments");
                   1066:                        return;
                   1067:                }
                   1068:                if (argc == 2) {
                   1069:                        /*
                   1070:                         * Optional second argument is a string specifying
                   1071:                         * why the assertion failed.
                   1072:                         */
                   1073:                        al = argv->list_node.next;
                   1074:                        al1 =  stkrval(al->list_node.list, NLNIL , (long) RREQ );
                   1075:                        if (al1 == NIL)
                   1076:                                return;
                   1077:                        if (classify(al1) != TSTR) {
                   1078:                                error("Second argument to assert must be a string, not %s", nameof(al1));
                   1079:                                return;
                   1080:                        }
                   1081:                } else {
                   1082:                        (void) put(2, PTR_CON, NIL);
                   1083:                }
                   1084:                ap = stkrval(argv->list_node.list, NLNIL , (long) RREQ );
                   1085:                if (ap == NIL)
                   1086:                        return;
                   1087:                if (isnta(ap, "b"))
                   1088:                        error("Assert expression must be Boolean, not %ss", nameof(ap));
                   1089:                (void) put(1, O_ASRT);
                   1090:                return;
                   1091: 
                   1092:        case O_PACK:
                   1093:                if (argc != 3) {
                   1094:                        error("pack expects three arguments");
                   1095:                        return;
                   1096:                }
                   1097:                pu = "pack(a,i,z)";
                   1098:                pua = argv->list_node.list;
                   1099:                al = argv->list_node.next;
                   1100:                pui = al->list_node.list;
                   1101:                alv = al->list_node.next;
                   1102:                puz = alv->list_node.list;
                   1103:                goto packunp;
                   1104:        case O_UNPACK:
                   1105:                if (argc != 3) {
                   1106:                        error("unpack expects three arguments");
                   1107:                        return;
                   1108:                }
                   1109:                pu = "unpack(z,a,i)";
                   1110:                puz = argv->list_node.list;
                   1111:                al = argv->list_node.next;
                   1112:                pua = al->list_node.list;
                   1113:                alv = al->list_node.next;
                   1114:                pui = alv->list_node.list;
                   1115: packunp:
                   1116:                codeoff();
                   1117:                ap = stklval(pua, op == O_PACK ? NOFLAGS : MOD|NOUSE);
                   1118:                al1 = stklval(puz, op == O_UNPACK ? NOFLAGS : MOD|NOUSE);
                   1119:                codeon();
                   1120:                if (ap == NIL)
                   1121:                        return;
                   1122:                if (ap->class != ARRAY) {
                   1123:                        error("%s requires a to be an unpacked array, not %s", pu, nameof(ap));
                   1124:                        return;
                   1125:                }
                   1126:                if (al1->class != ARRAY) {
                   1127:                        error("%s requires z to be a packed array, not %s", pu, nameof(ap));
                   1128:                        return;
                   1129:                }
                   1130:                if (al1->type == NIL || ap->type == NIL)
                   1131:                        return;
                   1132:                if (al1->type != ap->type) {
                   1133:                        error("%s requires a and z to be arrays of the same type", pu, nameof(ap));
                   1134:                        return;
                   1135:                }
                   1136:                k = width(al1);
                   1137:                itemwidth = width(ap->type);
                   1138:                ap = ap->chain;
                   1139:                al1 = al1->chain;
                   1140:                if (ap->chain != NIL || al1->chain != NIL) {
                   1141:                        error("%s requires a and z to be single dimension arrays", pu);
                   1142:                        return;
                   1143:                }
                   1144:                if (ap == NIL || al1 == NIL)
                   1145:                        return;
                   1146:                /*
                   1147:                 * al1 is the range for z i.e. u..v
                   1148:                 * ap is the range for a i.e. m..n
                   1149:                 * i will be n-m+1
                   1150:                 * j will be v-u+1
                   1151:                 */
                   1152:                i = ap->range[1] - ap->range[0] + 1;
                   1153:                j = al1->range[1] - al1->range[0] + 1;
                   1154:                if (i < j) {
                   1155:                        error("%s cannot have more elements in a (%d) than in z (%d)", pu, (char *) j, (char *) i);
                   1156:                        return;
                   1157:                }
                   1158:                /*
                   1159:                 * get n-m-(v-u) and m for the interpreter
                   1160:                 */
                   1161:                i -= j;
                   1162:                j = ap->range[0];
                   1163:                (void) put(2, O_CON24, k);
                   1164:                (void) put(2, O_CON24, i);
                   1165:                (void) put(2, O_CON24, j);
                   1166:                (void) put(2, O_CON24, itemwidth);
                   1167:                al1 = stklval(puz, op == O_UNPACK ? NOFLAGS : MOD|NOUSE);
                   1168:                ap = stklval(pua, op == O_PACK ? NOFLAGS : MOD|NOUSE);
                   1169:                ap = stkrval(pui, NLNIL , (long) RREQ );
                   1170:                if (ap == NIL)
                   1171:                        return;
                   1172:                (void) put(1, op);
                   1173:                return;
                   1174:        case 0:
                   1175:                error("%s is an unimplemented extension", p->symbol);
                   1176:                return;
                   1177: 
                   1178:        default:
                   1179:                panic("proc case");
                   1180:        }
                   1181: }
                   1182: #endif OBJ

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.