root/usr/src/cmd/dc/dc.c
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */
/*
 * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

/*      Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
/*        All Rights Reserved   */

#include <stdio.h>
#include <signal.h>
#include <errno.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <limits.h>
#include "dc.h"
#include <locale.h>
#include <stdlib.h>

#define LASTFUN 026
long longest = 0, maxsize = 0, active = 0;
int lall = 0, lrel = 0, lcopy = 0, lmore = 0, lbytes = 0;

/*
 * Routine to handle sign extension of characters on systems that do not
 * do automatic sign extension.  This should be portable to all 2's and 1's
 * complement systems that do or do not provide automatic sign
 * extension. If the system provides automatic sign extension or the
 * value of 'c' is positive, ctoint() will always return quickly,
 * otherwise ctoint() will search for the negative value by attempting
 * to wrap 'c' to 0.  The number of increments needed to get to 0 is the
 * negative value.
 *
 * Note: This assummes that the representation of values stored in chars
 * is sequential and allowed to wrap, and that values < 128 are
 * positive.  While this is true on 1's and 2's complement machines, it
 * may vary on less common architectures.
 */

#if __STDC__
int
ctoint(char c)
#else
int
ctoint(unsigned char c)
#endif
{
        int     i;

        if ((unsigned char)c <= SCHAR_MAX)
                return ((int)c);        /* Normal promotion will work */
        for (i = 0; c++; i--);          /* Scan for negative value */
        return (i);
}

#if !defined(TEXT_DOMAIN)               /* Should be defined by cc -D */
#define TEXT_DOMAIN "SYS_TEST"  /* Use this only if it weren't. */
#endif

void    commnds(void)   __NORETURN;

int
main(int argc, char **argv)
{
        (void) setlocale(LC_ALL, "");
        (void) textdomain(TEXT_DOMAIN);

        init(argc, argv);
        commnds();
        /* NOTREACHED */
}

void
commnds(void)
{
        int c;
        struct blk *p, *q;
        long l;
        int sign;
        struct blk **ptr, *s, *t;
        struct sym *sp;
        int sk, sk1, sk2;
        int n, d;
        int scalev;     /* scaling value for converting blks to integers */

        for (; ; ) {
                if (((c = readc()) >= '0' && c <= '9') ||
                    (c >= 'A' && c <= 'F') || c == '.') {
                        unreadc(c);
                        p = readin();
                        pushp(p);
                        continue;
                }
                switch (c) {
                case ' ':
                case '\n':
                case 0377:
                case EOF:
                        continue;
                case 'Y':
                        sdump("stk", *stkptr);
                        printf(gettext
                            ("all %ld rel %ld headmor %ld\n"), all, rel,
                            headmor);
                        printf(gettext("nbytes %ld\n"), nbytes);
                        printf(gettext
                            ("longest %ld active %ld maxsize %ld\n"), longest,
                            active, maxsize);
                        printf(gettext
                            ("new all %d rel %d copy %d more %d lbytes %d\n"),
                            lall, lrel, lcopy, lmore, lbytes);
                        lall = lrel = lcopy = lmore = lbytes = 0;
                        continue;
                case '_':
                        p = readin();
                        savk = sunputc(p);
                        chsign(p);
                        sputc(p, savk);
                        pushp(p);
                        continue;
                case '-':
                        subt();
                        continue;
                case '+':
                        if (eqk() != 0)
                                continue;
                        binop('+');
                        continue;
                case '*':
                        arg1 = pop();
                        EMPTY;
                        arg2 = pop();
                        EMPTYR(arg1);
                        sk1 = sunputc(arg1);
                        sk2 = sunputc(arg2);
                        binop('*');
                        p = pop();
                        sunputc(p);
                        savk = n = sk1 + sk2;
                        if (n > k && n > sk1 && n > sk2) {
                                sk = sk1;
                                if (sk < sk2)
                                        sk = sk2;
                                if (sk < k)
                                        sk = k;
                                p = removc(p, n - sk);
                                savk = sk;
                        }
                        sputc(p, savk);
                        pushp(p);
                        continue;
                case '/':
casediv:
                        if (dscale() != 0)
                                continue;
                        binop('/');
                        if (irem != 0)
                                release(irem);
                        release(rem);
                        continue;
                case '%':
                        if (dscale() != 0)
                                continue;
                        binop('/');
                        p = pop();
                        release(p);
                        if (irem == 0) {
                                sputc(rem, skr + k);
                                pushp(rem);
                                continue;
                        }
                        p = add0(rem, skd - (skr + k));
                        q = add(p, irem);
                        release(p);
                        release(irem);
                        sputc(q, skd);
                        pushp(q);
                        continue;
                case 'v':
                        p = pop();
                        EMPTY;
                        savk = sunputc(p);
                        if (length(p) == 0) {
                                sputc(p, savk);
                                pushp(p);
                                continue;
                        }
                        if ((c = sbackc(p)) < 0) {
                                error(gettext("sqrt of neg number\n"));
                        }
                        if (k < savk)
                                n = savk;
                        else {
                                n = k * 2 - savk;
                                savk = k;
                        }
                        arg1 = add0(p, n);
                        arg2 = sqrt(arg1);
                        sputc(arg2, savk);
                        pushp(arg2);
                        continue;
                case '^':
                        neg = 0;
                        arg1 = pop();
                        EMPTY;
                        if (sunputc(arg1) != 0)
                                error(gettext("exp not an integer\n"));
                        arg2 = pop();
                        EMPTYR(arg1);
                        if (sfbeg(arg1) == 0 && sbackc(arg1) < 0) {
                                neg++;
                                chsign(arg1);
                        }
                        if (length(arg1) >= 3)
                                error(gettext("exp too big\n"));
                        savk = sunputc(arg2);
                        p = exp(arg2, arg1);
                        release(arg2);
                        rewind(arg1);
                        c = sgetc(arg1);
                        if (c == EOF)
                                c = 0;
                        else if (sfeof(arg1) == 0)
                                c = sgetc(arg1) * 100 + c;
                        d = c * savk;
                        release(arg1);
                        if (k >= savk)
                                n = k;
                        else
                                n = savk;
                        if (n < d) {
                                q = removc(p, d - n);
                                sputc(q, n);
                                pushp(q);
                        } else {
                                sputc(p, d);
                                pushp(p);
                        }
                        if (neg == 0)
                                continue;
                        p = pop();
                        q = salloc(2);
                        sputc(q, 1);
                        sputc(q, 0);
                        pushp(q);
                        pushp(p);
                        goto casediv;
                case 'z':
                        p = salloc(2);
                        n = stkptr - stkbeg;
                        if (n >= 100) {
                                sputc(p, n / 100);
                                n %= 100;
                        }
                        sputc(p, n);
                        sputc(p, 0);
                        pushp(p);
                        continue;
                case 'Z':
                        p = pop();
                        EMPTY;
                        n = (length(p) - 1) << 1;
                        fsfile(p);
                        sbackc(p);
                        if (sfbeg(p) == 0) {
                                if ((c = sbackc(p)) < 0) {
                                        n -= 2;
                                        if (sfbeg(p) == 1)
                                                n += 1;
                                        else {
                                                if ((c = sbackc(p)) == 0)
                                                        n += 1;
                                                else if (c > 90)
                                                        n -= 1;
                                        }
                                } else
                                        if (c < 10)
                                                n -= 1;
                        }
                        release(p);
                        q = salloc(1);
                        if (n >= 100) {
                                sputc(q, n%100);
                                n /= 100;
                        }
                        sputc(q, n);
                        sputc(q, 0);
                        pushp(q);
                        continue;
                case 'i':
                        p = pop();
                        EMPTY;
                        p = scalint(p);

                        /*
                         * POSIX.2
                         * input base must be between 2 and 16
                         */
                        n = length(p);
                        q = copy(p, n);
                        fsfile(q);
                        c = sbackc(q);
                        if (sfbeg(q) == 0)
                                error(gettext("input base is too large\n"));
                        if (c < 2)
                                error(gettext("input base is too small\n"));
                        if (c > 16)
                                error(gettext("input base is too large\n"));
                        release(q);

                        release(inbas);
                        inbas = p;
                        continue;
                case 'I':
                        p = copy(inbas, length(inbas) + 1);
                        sputc(p, 0);
                        pushp(p);
                        continue;
                case 'o':
                        p = pop();
                        EMPTY;
                        p = scalint(p);
                        sign = 0;
                        n = length(p);
                        q = copy(p, n);
                        fsfile(q);
                        l = c = sbackc(q);
                        if (n != 1) {
                                if (c < 0) {
                                        sign = 1;
                                        chsign(q);
                                        n = length(q);
                                        fsfile(q);
                                        l = c = sbackc(q);
                                }
                                if (n != 1) {
                                        while (sfbeg(q) == 0)
                                                l = l * 100 + sbackc(q);
                                }
                        }

                        /*
                         * POSIX.2
                         * Check that output base is less than or equal
                         * BC_BASE_MAX.
                         */
                        if (l > BC_BASE_MAX)
                                error(gettext("output base is too large\n"));

                        logo = log2(l);
                        obase = l;
                        release(basptr);
                        if (sign == 1)
                                obase = -l;
                        basptr = p;
                        outdit = bigot;
                        if (n == 1 && sign == 0) {
                                if (c <= 16) {
                                        outdit = hexot;
                                        fw = 1;
                                        fw1 = 0;

                                        /*
                                         * POSIX.2
                                         * Line length is 70 characters,
                                         * including newline.
                                         */
                                        ll = 70;
                                        release(q);
                                        continue;
                                }
                        }
                        n = 0;
                        if (sign == 1)
                                n++;
                        p = salloc(1);
                        sputc(p, -1);
                        t = add(p, q);
                        n += length(t) * 2;
                        fsfile(t);
                        if ((c = sbackc(t)) > 9)
                                n++;
                        release(t);
                        release(q);
                        release(p);
                        fw = n;
                        fw1 = n-1;

                        /*
                         * POSIX.2
                         * Line length is 70 characters including newline
                         */
                        ll = 70;
                        if (fw >= ll)
                                continue;
                        ll = (70 / fw) * fw;
                        continue;
                case 'O':
                        p = copy(basptr, length(basptr) + 1);
                        sputc(p, 0);
                        pushp(p);
                        continue;
                case '[':
                        n = 0;
                        p = salloc(0);
                        for (; ; ) {
                                if ((c = readc()) == ']') {
                                        if (n == 0)
                                                break;
                                        n--;
                                }
                                sputc(p, c);
                                if (c == '[')
                                        n++;
                        }
                        pushp(p);
                        continue;
                case 'k':
                        p = pop();
                        EMPTY;
                        p = scalint(p);

                        /*
                         * POSIX.2
                         * Make sure scaling factor is between 0 and
                         * BC_SCALE_MAX.  Copy p to q and figure the
                         * scaling factor.
                         */
                        n = length(p);
                        q = copy(p, n);
                        fsfile(q);
                        c = 0;
                        if ((sfbeg(q) == 0) && ((c = sbackc(q)) < 0))
                                error(gettext("invalid scale factor\n"));

                        scalev = 1;
                        while (c < BC_SCALE_MAX && sfbeg(q) == 0)
                                c = (c * (scalev *= 100)) + sbackc(q);

                        if (c > BC_SCALE_MAX)
                                error(gettext("scale factor is too large\n"));
                        release(q);

                        rewind(p);
                        k = sfeof(p) ? 0 : sgetc(p);
                        release(scalptr);
                        scalptr = p;
                        continue;

                case 'K':
                        p = copy(scalptr, length(scalptr) + 1);
                        sputc(p, 0);
                        pushp(p);
                        continue;
                case 'X':
                        p = pop();
                        EMPTY;
                        fsfile(p);
                        n = sbackc(p);
                        release(p);
                        p = salloc(2);
                        sputc(p, n);
                        sputc(p, 0);
                        pushp(p);
                        continue;
                case 'Q':
                        p = pop();
                        EMPTY;
                        if (length(p) > 2) {
                                error("Q?\n");
                        }
                        rewind(p);
                        if ((c =  sgetc(p)) < 0) {
                                error(gettext("neg Q\n"));
                        }
                        release(p);
                        while (c-- > 0) {
                                if (readptr == &readstk[0]) {
                                        error("readstk?\n");
                                }
                                if (*readptr != 0)
                                        release(*readptr);
                                readptr--;
                        }
                        continue;
                case 'q':
                        if (readptr <= &readstk[1])
                                exit(0);
                        if (*readptr != 0)
                                release(*readptr);
                        readptr--;
                        if (*readptr != 0)
                                release(*readptr);
                        readptr--;
                        continue;
                case 'f':
                        if (stkptr == &stack[0])
                                printf(gettext("empty stack\n"));
                        else {
                                for (ptr = stkptr; ptr > &stack[0]; ) {
                                        print(*ptr--);
                                }
                        }
                        continue;
                case 'p':
                        if (stkptr == &stack[0])
                                printf(gettext("empty stack\n"));
                        else {
                                print(*stkptr);
                        }
                        continue;
                case 'P':
                        p = pop();
                        EMPTY;
                        sputc(p, 0);
                        printf("%s", p->beg);
                        release(p);
                        continue;
                case 'd':
                        if (stkptr == &stack[0]) {
                                printf(gettext("empty stack\n"));
                                continue;
                        }
                        q = *stkptr;
                        n = length(q);
                        p = copy(*stkptr, n);
                        pushp(p);
                        continue;
                case 'c':
                        while (stkerr == 0) {
                                p = pop();
                                if (stkerr == 0)
                                        release(p);
                        }
                        continue;
                case 'S':
                        if (stkptr == &stack[0]) {
                                error(gettext("save: args\n"));
                        }
                        c = readc() & 0377;
                        sptr = stable[c];
                        sp = stable[c] = sfree;
                        sfree = sfree->next;
                        if (sfree == 0)
                                goto sempty;
                        sp->next = sptr;
                        p = pop();
                        EMPTY;
                        if (c >= ARRAYST) {
                                q = copy(p, length(p) + PTRSZ);
                                for (n = 0; n < PTRSZ; n++) {
                                        sputc(q, 0);
                                }
                                release(p);
                                p = q;
                        }
                        sp->val = p;
                        continue;
sempty:
                        error(gettext("symbol table overflow\n"));
                case 's':
                        if (stkptr == &stack[0]) {
                                error(gettext("save:args\n"));
                        }
                        c = readc() & 0377;
                        sptr = stable[c];
                        if (sptr != 0) {
                                p = sptr->val;
                                if (c >= ARRAYST) {
                                        rewind(p);
                                        while (sfeof(p) == 0)
                                                release(getwd(p));
                                }
                                release(p);
                        } else {
                                sptr = stable[c] = sfree;
                                sfree = sfree->next;
                                if (sfree == 0)
                                        goto sempty;
                                sptr->next = 0;
                        }
                        p = pop();
                        sptr->val = p;
                        continue;
                case 'l':
                        load();
                        continue;
                case 'L':
                        c = readc() & 0377;
                        sptr = stable[c];
                        if (sptr == 0) {
                                error("L?\n");
                        }
                        stable[c] = sptr->next;
                        sptr->next = sfree;
                        sfree = sptr;
                        p = sptr->val;
                        if (c >= ARRAYST) {
                                rewind(p);
                                while (sfeof(p) == 0) {
                                        q = getwd(p);
                                        if (q != 0)
                                                release(q);
                                }
                        }
                        pushp(p);
                        continue;
                case ':':
                        p = pop();
                        EMPTY;
                        q = scalint(p);
                        fsfile(q);

                        /*
                         * POSIX.2
                         * Make sure index is between 0 and BC_DIM_MAX-1
                         */
                        c = 0;
                        if ((sfbeg(q) == 0) && ((c = sbackc(q)) < 0))
                                error(gettext("invalid index\n"));
                        scalev = 1;
                        while (c < BC_DIM_MAX && sfbeg(q) == 0)
                                c = (c * (scalev *= 100)) + sbackc(q);

                        if (c >= BC_DIM_MAX)
                                error(gettext("index is too large\n"));

                        release(q);
                        n = readc() & 0377;
                        sptr = stable[n];
                        if (sptr == 0) {
                                sptr = stable[n] = sfree;
                                sfree = sfree->next;
                                if (sfree == 0)
                                        goto sempty;
                                sptr->next = 0;
                                p = salloc((c + PTRSZ) * PTRSZ);
                                zero(p);
                        } else {
                                p = sptr->val;
                                if (length(p) - PTRSZ < c * PTRSZ) {
                                        q = copy(p, (c + PTRSZ) * PTRSZ);
                                        release(p);
                                        p = q;
                                }
                        }
                        seekc(p, c * PTRSZ);
                        q = lookwd(p);
                        if (q != NULL)
                                release(q);
                        s = pop();
                        EMPTY;
                        salterwd((struct wblk *)p, s);
                        sptr->val = p;
                        continue;

                case ';':
                        p = pop();
                        EMPTY;
                        q = scalint(p);
                        fsfile(q);

                        /*
                         * POSIX.2
                         * Make sure index is between 0 and BC_DIM_MAX-1
                         */
                        c = 0;
                        if ((sfbeg(q) == 0) && ((c = sbackc(q)) < 0))
                                error(gettext("invalid index\n"));
                        scalev = 1;
                        while (c < BC_DIM_MAX && sfbeg(q) == 0)
                                c = (c * (scalev *= 100)) + sbackc(q);

                        if (c >= BC_DIM_MAX)
                                error(gettext("index is too large\n"));

                        release(q);
                        n = readc() & 0377;
                        sptr = stable[n];
                        if (sptr != 0) {
                                p = sptr->val;
                                if (length(p) - PTRSZ >= c * PTRSZ) {
                                        seekc(p, c * PTRSZ);
                                        s = getwd(p);
                                        if (s != 0) {
                                                q = copy(s, length(s));
                                                pushp(q);
                                                continue;
                                        }
                                }
                        }
                        q = salloc(1);  /* uninitializd array elt prints as 0 */
                        sputc(q, 0);
                        pushp(q);
                        continue;
                case 'x':
execute:
                        p = pop();
                        EMPTY;
                        if ((readptr != &readstk[0]) && (*readptr != 0)) {
                                if ((*readptr)->rd == (*readptr)->wt)
                                        release(*readptr);
                                else {
                                        if (readptr++ == &readstk[RDSKSZ]) {
                                                error(gettext
                                                    ("nesting depth\n"));
                                        }
                                }
                        } else
                                readptr++;
                        *readptr = p;
                        if (p != 0)
                                rewind(p);
                        else {
                                if ((c = readc()) != '\n')
                                        unreadc(c);
                        }
                        continue;
                case '?':
                        if (++readptr == &readstk[RDSKSZ]) {
                                error(gettext("nesting depth\n"));
                        }
                        *readptr = 0;
                        fsave = curfile;
                        curfile = stdin;
                        while ((c = readc()) == '!')
                                command();
                        p = salloc(0);
                        sputc(p, c);
                        while ((c = readc()) != '\n') {
                                sputc(p, c);
                                if (c == '\\')
                                        sputc(p, readc());
                        }
                        curfile = fsave;
                        *readptr = p;
                        continue;
                case '!':
                        if (command() == 1)
                                goto execute;
                        continue;
                case '<':
                case '>':
                case '=':
                        if (cond(c) == 1)
                                goto execute;
                        continue;
                default:
                        printf(gettext("%o is unimplemented\n"), c);
                }
        }
}

struct blk *
dcdiv(struct blk *ddivd, struct blk *ddivr)
{
        int divsign, remsign, offset, divcarry;
        int carry, dig, magic, d, dd, under;
        long c, td, cc;
        struct blk *ps, *px;
        struct blk *p, *divd, *divr;

        rem = 0;
        p = salloc(0);
        if (length(ddivr) == 0) {
                pushp(ddivr);
                printf(gettext("divide by 0\n"));
                return (p);
        }
        divsign = remsign = 0;
        divr = ddivr;
        fsfile(divr);
        if (sbackc(divr) == -1) {
                divr = copy(ddivr, length(ddivr));
                chsign(divr);
                divsign = ~divsign;
        }
        divd = copy(ddivd, length(ddivd));
        fsfile(divd);
        if (sfbeg(divd) == 0 && sbackc(divd) == -1) {
                chsign(divd);
                divsign = ~divsign;
                remsign = ~remsign;
        }
        offset = length(divd) - length(divr);
        if (offset < 0)
                goto ddone;
        seekc(p, offset + 1);
        sputc(divd, 0);
        magic = 0;
        fsfile(divr);
        c = sbackc(divr);
        if (c < 10)
                magic++;
        c = c * 100 + (sfbeg(divr)?0:sbackc(divr));
        if (magic > 0) {
                c = (c * 100 +(sfbeg(divr)?0:sbackc(divr)))*2;
                c /= 25;
        }
        while (offset >= 0) {
                fsfile(divd);
                td = sbackc(divd) * 100;
                dd = sfbeg(divd)?0:sbackc(divd);
                td = (td + dd) * 100;
                dd = sfbeg(divd)?0:sbackc(divd);
                td = td + dd;
                cc = c;
                if (offset == 0)
                        td++;
                else
                        cc++;
                if (magic != 0)
                        td = td<<3;
                dig = td/cc;
                under = 0;
                if (td%cc < 8 && dig > 0 && magic) {
                        dig--;
                        under = 1;
                }
                rewind(divr);
                rewind(divxyz);
                carry = 0;
                while (sfeof(divr) == 0) {
                        d = sgetc(divr) * dig + carry;
                        carry = d / 100;
                        salterc(divxyz, d % 100);
                }
                salterc(divxyz, carry);
                rewind(divxyz);
                seekc(divd, offset);
                carry = 0;
                while (sfeof(divd) == 0) {
                        d = slookc(divd);
                        d = d - (sfeof(divxyz) ? 0 : sgetc(divxyz)) - carry;
                        carry = 0;
                        if (d < 0) {
                                d += 100;
                                carry = 1;
                        }
                        salterc(divd, d);
                }
                divcarry = carry;
                sbackc(p);
                salterc(p, dig);
                sbackc(p);
                fsfile(divd);
                d = sbackc(divd);
                if ((d != 0) && /* !divcarry */ (offset != 0)) {
                        d = sbackc(divd) + 100;
                        salterc(divd, d);
                }
                if (--offset >= 0) {
                        divd->wt--;
                }
        }
        if (under) {    /* undershot last - adjust */
                px = copy(divr, length(divr));  /* 11/88 don't corrupt ddivr */
                chsign(px);
                ps = add(px, divd);
                fsfile(ps);
                if (length(ps) > 0 && sbackc(ps) < 0) {
                        release(ps);    /* only adjust in really undershot */
                } else {
                        release(divd);
                        salterc(p, dig + 1);
                        divd = ps;
                }
        }
        if (divcarry != 0) {
                salterc(p, dig - 1);
                salterc(divd, -1);
                ps = add(divr, divd);
                release(divd);
                divd = ps;
        }

        rewind(p);
        divcarry = 0;
        while (sfeof(p) == 0) {
                d = slookc(p) + divcarry;
                divcarry = 0;
                if (d >= 100) {
                        d -= 100;
                        divcarry = 1;
                }
                salterc(p, d);
        }
        if (divcarry != 0)
                salterc(p, divcarry);
        fsfile(p);
        while (sfbeg(p) == 0) {
                if (sbackc(p) == 0)
                        truncate(p);
                else break;
        }
        if (divsign < 0)
                chsign(p);
        fsfile(divd);
        while (sfbeg(divd) == 0) {
                if (sbackc(divd) == 0)
                        truncate(divd);
                else break;
        }
ddone:
        if (remsign < 0)
                chsign(divd);
        if (divr != ddivr)
                release(divr);
        rem = divd;
        return (p);
}

int
dscale(void)
{
        struct blk *dd, *dr, *r;
        int c;

        dr = pop();
        EMPTYS;
        dd = pop();
        EMPTYSR(dr);
        fsfile(dd);
        skd = sunputc(dd);
        fsfile(dr);
        skr = sunputc(dr);
        if (sfbeg(dr) == 1 || (sfbeg(dr) == 0 && sbackc(dr) == 0)) {
                sputc(dr, skr);
                pushp(dr);
                printf(gettext("divide by 0\n"));
                return (1);
        }
        if (sfbeg(dd) == 1 || (sfbeg(dd) == 0 && sbackc(dd) == 0)) {
#ifdef XPG6
                sputc(dd, k);
#else
                sputc(dd, skd);
#endif
                pushp(dd);
                return (1);
        }
        c = k-skd+skr;
        if (c < 0)
                r = removr(dd, -c);
        else {
                r = add0(dd, c);
                irem = 0;
        }
        arg1 = r;
        arg2 = dr;
        savk = k;
        return (0);
}

struct blk *
removr(struct blk *p, int n)
{
        int nn, neg;
        struct blk *q, *s, *r;
        fsfile(p);
        neg = sbackc(p);
        if (neg < 0)
                chsign(p);
        rewind(p);
        nn = (n + 1) / 2;
        q = salloc(nn);
        while (n > 1) {
                sputc(q, sgetc(p));
                n -= 2;
        }
        r = salloc(2);
        while (sfeof(p) == 0)
                sputc(r, sgetc(p));
        release(p);
        if (n == 1) {
                s = dcdiv(r, tenptr);
                release(r);
                rewind(rem);
                if (sfeof(rem) == 0)
                        sputc(q, sgetc(rem));
                release(rem);
                if (neg < 0) {
                        chsign(s);
                        chsign(q);
                        irem = q;
                        return (s);
                }
                irem = q;
                return (s);
        }
        if (neg < 0) {
                chsign(r);
                chsign(q);
                irem = q;
                return (r);
        }
        irem = q;
        return (r);
}

struct blk *
sqrt(struct blk *p)
{
        struct blk *r, *q, *s, *t;
        int c, n, nn;

        n = length(p);
        fsfile(p);
        c = sbackc(p);
        if ((n & 1) != 1)
                c = c * 100 + (sfbeg(p) ? 0 : sbackc(p));
        n = (n + 1) >> 1;
        r = salloc(n);
        zero(r);
        seekc(r, n);
        nn = 1;
        while ((c -= nn) >= 0)
                nn += 2;
        c = (nn + 1) >> 1;
        fsfile(r);
        sbackc(r);
        if (c >= 100) {
                c -= 100;
                salterc(r, c);
                sputc(r, 1);
        } else
                salterc(r, c);
        for (; ; ) {
                q = dcdiv(p, r);
                s = add(q, r);
                release(q);
                release(rem);
                q = dcdiv(s, sqtemp);
                release(s);
                release(rem);
                s = copy(r, length(r));
                chsign(s);
                t = add(s, q);
                release(s);
                fsfile(t);
                nn = sfbeg(t) ? 0 : sbackc(t);
                if (nn >= 0)
                        break;
                release(r);
                release(t);
                r = q;
        }
        release(t);
        release(q);
        release(p);
        return (r);
}

struct blk *
exp(struct blk *base, struct blk *ex)
{
        struct blk *r, *e, *p, *e1, *t, *cp;
        int temp, c, n;
        r = salloc(1);
        sputc(r, 1);
        p = copy(base, length(base));
        e = copy(ex, length(ex));
        fsfile(e);
        if (sfbeg(e) != 0)
                goto edone;
        temp = 0;
        c = sbackc(e);
        if (c < 0) {
                temp++;
                chsign(e);
        }
        while (length(e) != 0) {
                e1 = dcdiv(e, sqtemp);
                release(e);
                e = e1;
                n = length(rem);
                release(rem);
                if (n != 0) {
                        e1 = mult(p, r);
                        release(r);
                        r = e1;
                }
                t = copy(p, length(p));
                cp = mult(p, t);
                release(p);
                release(t);
                p = cp;
        }
        if (temp != 0) {
                if ((c = length(base)) == 0) {
                        goto edone;
                }
                if (c > 1)
                        create(r);
                else {
                        rewind(base);
                        if ((c = sgetc(base)) <= 1) {
                                create(r);
                                sputc(r, c);
                        } else
                                create(r);
                }
        }
edone:
        release(p);
        release(e);
        return (r);
}

void
init(int argc, char **argv)
{
        struct sym *sp;
        char *dcmalloc();
        struct stat tsb;

        if (signal(SIGINT, SIG_IGN) != SIG_IGN)
                signal(SIGINT, onintr);
        setbuf(stdout, (char *)NULL);
        svargc = --argc;
        svargv = argv;
        while (svargc > 0 && svargv[1][0] == '-') {
                switch (svargv[1][1]) {
                default:
                        dbg = 1;
                }
                svargc--;
                svargv++;
        }

        ifile = 1;

        if (svargc <= 0)
                curfile = stdin;
        else {
                if (stat(svargv[1], &tsb) < 0) {
                        printf(gettext("Cannot stat %s: "), svargv[1]);
                        perror("");
                        exit(1);
                }

                if (S_ISREG(tsb.st_mode)) {
                        if ((curfile = fopen(svargv[1], "r")) == NULL) {
                                printf(gettext("can't open file %s\n"), \
                                    svargv[1]);
                                exit(1);
                        }
                } else {
                        printf(gettext("invalid file type: %s\n"), \
                            svargv[1]);
                        exit(1);
                }
        }

        dummy = dcmalloc(0);
        scalptr = salloc(1);
        sputc(scalptr, 0);
        basptr = salloc(1);
        sputc(basptr, 10);
        obase = 10;
        log10 = log2(10L);

        /*
         * POSIX.2
         * default line length is 70 characters including newline
         */
        ll = 70;
        fw = 1;
        fw1 = 0;
        tenptr = salloc(1);
        sputc(tenptr, 10);
        obase = 10;
        inbas = salloc(1);
        sputc(inbas, 10);
        sqtemp = salloc(1);
        sputc(sqtemp, 2);
        chptr = salloc(0);
        strptr = salloc(0);
        divxyz = salloc(0);
        stkbeg = stkptr = &stack[0];
        stkend = &stack[STKSZ];
        stkerr = 0;
        readptr = &readstk[0];
        k = 0;
        sp = sptr = &symlst[0];
        while (sptr < &symlst[TBLSZ]) {
                sptr->next = ++sp;
                sptr++;
        }
        sptr->next = 0;
        sfree = &symlst[0];
}

void
onintr(int sig)
{

        signal(sig, onintr);
        while (readptr != &readstk[0]) {
                if (*readptr != 0)
                        release(*readptr);
                readptr--;
        }
        curfile = stdin;
        commnds();
}

void
pushp(struct blk *p)
{
        if (stkptr == stkend)
                printf(gettext("out of stack space\n"));
        else {
                stkerr = 0;
                *++stkptr = p;
        }
}

struct blk *
pop(void)
{
        if (stkptr == stack) {
                stkerr = 1;
                return (0);
        }
        return (*stkptr--);
}

struct blk *
readin(void)
{
        struct blk *p, *q;
        int dp, dpct;
        int c;

        dp = dpct = 0;
        p = salloc(0);
        for (; ; ) {
                c = readc();
                switch (c) {
                case '.':
                        if (dp != 0)
                                goto gotnum;
                        dp++;
                        continue;
                case '\\':
                        readc();
                        continue;
                default:
                        if (c >= 'A' && c <= 'F')
                                c = c - 'A' + 10;
                        else
                                if (c >= '0' && c <= '9')
                                        c -= '0';
                                else
                                        goto gotnum;
                        if (dp != 0) {
                                if (dpct >= 99)
                                        continue;
                                dpct++;
                        }
                        create(chptr);
                        if (c != 0)
                                sputc(chptr, c);
                        q = mult(p, inbas);
                        release(p);
                        p = add(chptr, q);
                        release(q);
                }
        }
gotnum:
        unreadc(c);
        if (dp == 0) {
                sputc(p, 0);
                return (p);
        } else {
                /* if not base 10, then scale fractional input to precision */
                if (((int)*(inbas->beg)) != 10) {
                        while (dpct < k) {
                                create(chptr);
                                q = mult(p, inbas);
                                release(p);
                                p = add(chptr, q);
                                release(q);
                                dpct++;
                        }
                }
                q = scale(p, dpct);
                return (q);
        }
}

/*
 * returns pointer to struct with ct 0's & p
 */
struct blk *
add0(struct blk *p, int ct)
{
        struct blk *q, *t;

        q = salloc(length(p) + (ct + 1) / 2);
        while (ct > 1) {
                sputc(q, 0);
                ct -= 2;
        }
        rewind(p);
        while (sfeof(p) == 0) {
                sputc(q, sgetc(p));
        }
        release(p);
        if (ct == 1) {
                t = mult(tenptr, q);
                release(q);
                return (t);
        }
        return (q);
}

struct blk *
mult(struct blk *p, struct blk *q)
{
        struct blk *mp, *mq, *mr;
        int sign, offset, carry;
        int cq, cp, mt, mcr;

        offset = sign = 0;
        fsfile(p);
        mp = p;
        if (sfbeg(p) == 0) {
                if (sbackc(p) < 0) {
                        mp = copy(p, length(p));
                        chsign(mp);
                        sign = ~sign;
                }
        }
        fsfile(q);
        mq = q;
        if (sfbeg(q) == 0) {
                if (sbackc(q) < 0) {
                        mq = copy(q, length(q));
                        chsign(mq);
                        sign = ~sign;
                }
        }
        mr = salloc(length(mp) + length(mq));
        zero(mr);
        rewind(mq);
        while (sfeof(mq) == 0) {
                cq = sgetc(mq);
                rewind(mp);
                rewind(mr);
                mr->rd += offset;
                carry = 0;
                while (sfeof(mp) == 0) {
                        cp = sgetc(mp);
                        mcr = sfeof(mr) ? 0 : slookc(mr);
                        mt = cp*cq + carry + mcr;
                        carry = mt / 100;
                        salterc(mr, mt % 100);
                }
                offset++;
                if (carry != 0) {
                        mcr = sfeof(mr) ? 0 : slookc(mr);
                        salterc(mr, mcr + carry);
                }
        }
        if (sign < 0) {
                chsign(mr);
        }
        if (mp != p)
                release(mp);
        if (mq != q)
                release(mq);
        return (mr);
}

void
chsign(struct blk *p)
{
        int carry;
        char ct;

        carry = 0;
        rewind(p);
        while (sfeof(p) == 0) {
                ct = 100 - slookc(p) - carry;
                carry = 1;
                if (ct >= 100) {
                        ct -= 100;
                        carry = 0;
                }
                salterc(p, ct);
        }
        if (carry != 0) {
                sputc(p, -1);
                fsfile(p);
                sbackc(p);
                ct = sbackc(p);
                if (ct == 99) {
                        truncate(p);
                        sputc(p, -1);
                }
        } else {
                fsfile(p);
                ct = sbackc(p);
                if (ct == 0)
                        truncate(p);
        }
}

char
readc(void)
{
loop:
        if ((readptr != &readstk[0]) && (*readptr != 0)) {
                if (sfeof(*readptr) == 0)
                        return (lastchar = sgetc(*readptr));
                release(*readptr);
                readptr--;
                goto loop;
        }
        lastchar = getc(curfile);
        if (lastchar != EOF)
                return (lastchar);
        if (readptr != &readptr[0]) {
                readptr--;
                if (*readptr == 0)
                        curfile = stdin;
                goto loop;
        }
        if (curfile != stdin) {
                fclose(curfile);
                curfile = stdin;
                goto loop;
        }
        exit(0);
}

void
unreadc(char c)
{

        if ((readptr != &readstk[0]) && (*readptr != 0)) {
                sungetc(*readptr, c);
        } else
                ungetc(c, curfile);
}

void
binop(char c)
{
        struct blk *r;

        switch (c) {
        case '+':
                r = add(arg1, arg2);
                break;
        case '*':
                r = mult(arg1, arg2);
                break;
        case '/':
                r = dcdiv(arg1, arg2);
                break;
        }
        release(arg1);
        release(arg2);
        sputc(r, savk);
        pushp(r);
}

void
print(struct blk *hptr)
{
        struct blk *p, *q, *dec;
        int sc;                         /* scale */
        int dig, dout, ct;

        rewind(hptr);
        while (sfeof(hptr) == 0) {
                if (sgetc(hptr) > 99) {
                        rewind(hptr);
                        while (sfeof(hptr) == 0) {
                                printf("%c", sgetc(hptr));
                        }
                        printf("\n");
                        return;
                }
        }
        fsfile(hptr);
        sc = sbackc(hptr);              /* read scale off end of blk */
        if (sfbeg(hptr) != 0) {
                printf("0\n");
                return;
        }
        count = ll;
        p = copy(hptr, length(hptr));
        sunputc(p);
        fsfile(p);
        if (sbackc(p) < 0) {
                chsign(p);
                OUTC('-');
        }
        if ((obase == 0) || (obase == -1)) {
                oneot(p, sc, 'd');
                return;
        }
        if (obase == 1) {
                oneot(p, sc, '1');
                return;
        }
        if (obase == 10) {
                tenot(p, sc);
                return;
        }
        create(strptr);
        dig = log10 * sc;
        dout = ((dig / 10) + dig) / logo;
        dec = getdec(p, sc);
        p = removc(p, sc);
        while (length(p) != 0) {
                q = dcdiv(p, basptr);
                release(p);
                p = q;
                (*outdit)(rem, 0);
                if (obase > 16)
                        sputc(strptr, ' ');
        }
        release(p);
        fsfile(strptr);
        while (sfbeg(strptr) == 0)
                OUTC(sbackc(strptr));
        if (sc == 0) {
                release(dec);
                printf("\n");
                return;
        }
        create(strptr);
        OUTC('.');
        ct = 0;
        do {
                if (ct != 0 && obase > 16)
                        sputc(strptr, ' ');
                q = mult(basptr, dec);
                release(dec);
                dec = getdec(q, sc);
                p = removc(q, sc);
                (*outdit)(p, 1);
        } while (++ct < dout);
        release(dec);
        rewind(strptr);
        while (sfeof(strptr) == 0)
                OUTC(sgetc(strptr));
        printf("\n");
}

struct blk *
getdec(struct blk *p, int sc)
{
        int cc;
        struct blk *q, *t, *s;

        rewind(p);
        if (length(p) * 2 < sc) {
                q = copy(p, length(p));
                return (q);
        }
        q = salloc(length(p));
        while (sc >= 1) {
                sputc(q, sgetc(p));
                sc -= 2;
        }
        if (sc != 0) {
                t = mult(q, tenptr);
                s = salloc(cc = length(q));
                release(q);
                rewind(t);
                while (cc-- > 0)
                        sputc(s, sgetc(t));
                sputc(s, 0);
                release(t);
                t = dcdiv(s, tenptr);
                release(s);
                release(rem);
                return (t);
        }
        return (q);
}

void
tenot(struct blk *p, int sc)
{
        int c, f;

        fsfile(p);

        f = 0;

        /*
         * at this point, the number is stored as base 100 (two decimal
         * digits per char) stuck in a buf (character array) backwards.
         * sc indicates the scaling factor.
         */

        while ((sfbeg(p) == 0) && ((p->rd-p->beg-1)*2 >= sc)) {
                /*
                 * get numbers from the buf until we are the beginning of
                 * the buf (i.e., there are no more numbers) or the numbers
                 * remaining fall within the scaled (to the right of the
                 * decimal point) portion.
                 */
                c = sbackc(p);

                /*
                 * POSIX.2
                 * as we output digits, we have to watch the line length (ll)
                 * which should include a '\' and a newline.
                 */
                if (c < 10) {
                        /*
                         * if the number is less than 10, we need to output
                         * a space-holding '0' (unless this is the first time
                         * through).
                         */
                        if (f == 1) {
                                CHECKEND;
                                printf("0");
                                count--;
                        }

                        CHECKEND;
                        printf("%d", c);
                        count--;
                } else  {
                        CHECKEND;
                        printf("%d", c / 10);
                        count--;

                        CHECKEND;
                        printf("%d", c % 10);
                        count--;
                }
                f = 1;
        }

        if (sc == 0) {
                /*
                 * no scaling factor, so we must have exited loop because we
                 * ran out of numbers.
                 */
                printf("\n");
                release(p);
                return;
        }

        if ((p->rd - p->beg) * 2 > sc) {
                c = sbackc(p);

                CHECKEND;
                printf("%d", c / 10);
                count--;

                CHECKEND;
                printf(".");
                count--;

                CHECKEND;
                printf("%d", c % 10);
                count--;

                sc--;
        } else {
                CHECKEND;
                printf(".");
                count--;
        }

        if (sc > (p->rd - p->beg) * 2) {
                while (sc > (p->rd - p->beg) * 2) {
                        CHECKEND;
                        printf("0");
                        count--;

                        sc--;
                }
        }

        /* now go through the scaled portion of the number */
        while (sc > 1) {
                c = sbackc(p);
                if (c < 10) {
                        CHECKEND;
                        printf("0");
                        count--;

                        CHECKEND;
                        printf("%d", c);
                        count--;
                } else {
                        CHECKEND;
                        printf("%d", c / 10);
                        count--;

                        CHECKEND;
                        printf("%d", c % 10);
                        count--;
                }
                sc -= 2;
        }

        if (sc == 1) {          /* just in case the scaling factor was odd */
                CHECKEND;
                printf("%d", sbackc(p) / 10);
        }

        printf("\n");
        release(p);
}

void
oneot(struct blk *p, int sc, char ch)
{
        struct blk *q;

        q = removc(p, sc);
        create(strptr);
        sputc(strptr, -1);
        while (length(q) > 0) {
                p = add(strptr, q);
                release(q);
                q = p;
                OUTC(ch);
        }
        release(q);
        printf("\n");
}

void
hexot(struct blk *p, int flg)
{
        int c;

        rewind(p);
        if (sfeof(p) != 0) {
                sputc(strptr, '0');
                release(p);
                return;
        }
        c = sgetc(p);
        release(p);
        if (c >= 16) {
                printf(gettext("hex digit > 16"));
                return;
        }
        sputc(strptr, c < 10 ? c + '0' : c - 10 + 'A');
}

void
bigot(struct blk *p, int flg)
{
        struct blk *t, *q;
        int l;
        int neg;

        if (flg == 1)
                t = salloc(0);
        else {
                t = strptr;
                l = length(strptr) + fw - 1;
        }
        neg = 0;
        if (length(p) != 0) {
                fsfile(p);
                if (sbackc(p) < 0) {
                        neg = 1;
                        chsign(p);
                }
                while (length(p) != 0) {
                        q = dcdiv(p, tenptr);
                        release(p);
                        p = q;
                        rewind(rem);
                        sputc(t, sfeof(rem) ? '0' : sgetc(rem) + '0');
                        release(rem);
                }
        }
        release(p);
        if (flg == 1) {
                l = fw1 - length(t);
                if (neg != 0) {
                        l--;
                        sputc(strptr, '-');
                }
                fsfile(t);
                while (l-- > 0)
                        sputc(strptr, '0');
                while (sfbeg(t) == 0)
                        sputc(strptr, sbackc(t));
                release(t);
        } else {
                l -= length(strptr);
                while (l-- > 0)
                        sputc(strptr, '0');
                if (neg != 0) {
                        sunputc(strptr);
                        sputc(strptr, '-');
                }
        }
}

struct blk *
add(struct blk *a1, struct blk *a2)
{
        struct blk *p;
        int carry, n;
        int size;
        int c, n1, n2;

        size = length(a1) > length(a2) ? length(a1) : length(a2);
        p = salloc(size);
        rewind(a1);
        rewind(a2);
        carry = 0;
        while (--size >= 0) {
                n1 = sfeof(a1) ? 0 : sgetc(a1);
                n2 = sfeof(a2) ? 0 : sgetc(a2);
                n = n1 + n2 + carry;
                if (n >= 100) {
                        carry = 1;
                        n -= 100;
                } else
                        if (n < 0) {
                                carry = -1;
                                n += 100;
                        } else
                                carry = 0;
                sputc(p, n);
        }
        if (carry != 0)
                sputc(p, carry);
        fsfile(p);
        if (sfbeg(p) == 0) {
                while (sfbeg(p) == 0 && (c = sbackc(p)) == 0);
                if (c != 0)
                        salterc(p, c);
                truncate(p);
        }
        fsfile(p);
        if (sfbeg(p) == 0 && sbackc(p) == -1) {
                while ((c = sbackc(p)) == 99) {
                        if (c == EOF)
                                break;
                }
                sgetc(p);
                salterc(p, -1);
                truncate(p);
        }
        return (p);
}

int
eqk(void) {
        struct blk *p, *q;
        int skp, skq;

        p = pop();
        EMPTYS;
        q = pop();
        EMPTYSR(p);
        skp = sunputc(p);
        skq = sunputc(q);
        if (skp == skq) {
                arg1 = p;
                arg2 = q;
                savk = skp;
                return (0);
        } else
                if (skp < skq) {
                        savk = skq;
                        p = add0(p, skq - skp);
                } else {
                        savk = skp;
                        q = add0(q, skp - skq);
                }
        arg1 = p;
        arg2 = q;
        return (0);
}

struct blk *
removc(struct blk *p, int n)
{
        struct blk *q, *r;

        rewind(p);
        while (n > 1) {
                sgetc(p);
                n -= 2;
        }
        q = salloc(2);
        while (sfeof(p) == 0)
                sputc(q, sgetc(p));
        if (n == 1) {
                r = dcdiv(q, tenptr);
                release(q);
                release(rem);
                q = r;
        }
        release(p);
        return (q);
}

struct blk *
scalint(struct blk *p)
{
        int n;

        n = sunputc(p);
        p = removc(p, n);
        return (p);
}

struct blk *
scale(struct blk *p, int n)
{
        struct blk *q, *s, *t;

        t = add0(p, n);
        q = salloc(1);
        sputc(q, n);
        s = exp(inbas, q);
        release(q);
        q = dcdiv(t, s);
        release(t);
        release(s);
        release(rem);
        sputc(q, n);
        return (q);
}

int
subt(void)
{
        arg1 = pop();
        EMPTYS;
        savk = sunputc(arg1);
        chsign(arg1);
        sputc(arg1, savk);
        pushp(arg1);
        if (eqk() != 0)
                return (1);
        binop('+');
        return (0);
}

int
command(void)
{
        int c;
        char line[100], *sl;
        void (*savint)();
        pid_t pid, rpid;
        int retcode;

        switch (c = readc()) {
        case '<':
                return (cond(NL));
        case '>':
                return (cond(NG));
        case '=':
                return (cond(NE));
        default:
                sl = line;
                *sl++ = c;
                while ((c = readc()) != '\n')
                        *sl++ = c;
                *sl = 0;
                if ((pid = fork()) == (pid_t)0) {
                        execl("/usr/bin/sh", "sh", "-c", line, 0);
                        exit(0100);
                }
                savint = signal(SIGINT, SIG_IGN);
                while ((rpid = wait(&retcode)) != pid && rpid != (pid_t)-1);
                signal(SIGINT, savint);
                printf(gettext("!\n"));
                return (0);
        }
}

int
cond(char c)
{
        struct blk *p;
        int cc;

        if (subt() != 0)
                return (1);
        p = pop();
        sunputc(p);
        if (length(p) == 0) {
                release(p);
                if (c == '<' || c == '>' || c == NE) {
                        readc();
                        return (0);
                }
                load();
                return (1);
        } else {
                if (c == '=') {
                        release(p);
                        readc();
                        return (0);
                }
        }
        if (c == NE) {
                release(p);
                load();
                return (1);
        }
        fsfile(p);
        cc = sbackc(p);
        release(p);
        if ((cc < 0 && (c == '<' || c == NG)) ||
            (cc > 0) && (c == '>' || c == NL)) {
                readc();
                return (0);
        }
        load();
        return (1);
}

void
load(void)
{
        int c;
        struct blk *p, *q, *t, *s;

        c = readc() & 0377;
        sptr = stable[c];
        if (sptr != 0) {
                p = sptr->val;
                if (c >= ARRAYST) {
                        q = salloc(length(p));
                        rewind(p);
                        while (sfeof(p) == 0) {
                                s = getwd(p);
                                if (s == 0)
                                        putwd(q, (struct blk *)NULL);
                                else {
                                        t = copy(s, length(s));
                                        putwd(q, t);
                                }
                        }
                        pushp(q);
                } else {
                        q = copy(p, length(p));
                        pushp(q);
                }
        } else {
                q = salloc(1);
                if (c <= LASTFUN) {
                        printf(gettext
                            ("function %c undefined\n"), c + 'a' - 1);
                        sputc(q, 'c');
                        sputc(q, '0');
                        sputc(q, ' ');
                        sputc(q, '1');
                        sputc(q, 'Q');
                } else
                        sputc(q, 0);
                pushp(q);
        }
}

int
log2(long n)
{
        int i;

        if (n == 0)
                return (0);
        i = 31;
        if (n < 0)
                return (i);
        while ((n = n << 1) > 0)
                i--;
        return (--i);
}

struct blk *
salloc(int size)
{
        struct blk *hdr;
        char *ptr;
        char *dcmalloc();
        all++;
        lall++;
        if (all - rel > active)
                active = all - rel;
        nbytes += size;
        lbytes += size;
        if (nbytes > maxsize)
                maxsize = nbytes;
        if (size > longest)
                longest = size;
        ptr = dcmalloc((unsigned)size);
        if (ptr == 0) {
                garbage("salloc");
                if ((ptr = dcmalloc((unsigned)size)) == 0)
                        ospace("salloc");
        }
        if ((hdr = hfree) == 0)
                hdr = morehd();
        hfree = (struct blk *)hdr->rd;
        hdr->rd = hdr->wt = hdr->beg = ptr;
        hdr->last = ptr + size;
        return (hdr);
}

struct blk *
morehd(void)
{
        struct blk *h, *kk;
        char *dcmalloc();

        headmor++;
        nbytes += HEADSZ;
        hfree = h = (struct blk *)dcmalloc(HEADSZ);
        if (hfree == 0) {
                garbage("morehd");
                if ((hfree = h = (struct blk *)dcmalloc(HEADSZ)) == 0)
                        ospace("headers");
        }
        kk = h;
        while (h < hfree + (HEADSZ/BLK))
                (h++)->rd = (char *)++kk;
        (--h)->rd = 0;
        return (hfree);
}

struct blk *
copy(struct blk *hptr, int size)
{
        struct blk *hdr;
        unsigned sz;
        char *ptr;

        all++;
        lall++;
        lcopy++;
        nbytes += size;
        lbytes += size;
        if (size > longest)
                longest = size;
        if (size > maxsize)
                maxsize = size;
        sz = length(hptr);
        ptr = nalloc(hptr->beg, (unsigned)size);
        if (ptr == 0) {
                garbage("copy");
                if ((ptr = nalloc(hptr->beg, (unsigned)size)) == NULL) {
                        printf(gettext("copy size %d\n"), size);
                        ospace("copy");
                }
        }
        if ((hdr = hfree) == 0)
                hdr = morehd();
        hfree = (struct blk *)hdr->rd;
        hdr->rd = hdr->beg = ptr;
        hdr->last = ptr + size;
        hdr->wt = ptr + sz;
        ptr = hdr->wt;
        while (ptr < hdr->last)
                *ptr++ = '\0';
        return (hdr);
}

void
sdump(char *s1, struct blk *hptr)
{
        char *p;

        if (hptr) {
                printf("%s %o rd %o wt %o beg %o last %o\n", s1, hptr,
                    hptr->rd, hptr->wt, hptr->beg, hptr->last);
                p = hptr->beg;
                while (p < hptr->wt)
                        printf("%d ", *p++);
                printf("\n");
        } else
                printf("%s %o\n", s1, hptr);
}

void
seekc(struct blk *hptr, int n)
{
        char *nn, *p;

        nn = hptr->beg + n;
        if (nn > hptr->last) {
                nbytes += nn - hptr->last;
                if (nbytes > maxsize)
                        maxsize = nbytes;
                lbytes += nn - hptr->last;
                if (n > longest)
                        longest = n;
                p = realloc(hptr->beg, (unsigned)n);
                if (p == 0) {
                        hptr->beg = realloc(hptr->beg,
                            (unsigned)(hptr->last - hptr->beg));
                        garbage("seekc");
                        if ((p = realloc(hptr->beg, (unsigned)n)) == 0)
                                ospace("seekc");
                }
                hptr->beg = p;
                hptr->wt = hptr->last = hptr->rd = p + n;
                return;
        }
        hptr->rd = nn;
        if (nn > hptr->wt)
                hptr->wt = nn;
}

void
salterwd(struct wblk *hptr, struct blk *n)
{
        if (hptr->rdw == hptr->lastw)
                more((struct blk *)hptr);
        *hptr->rdw++ = n;
        if (hptr->rdw > hptr->wtw)
                hptr->wtw = hptr->rdw;
}

void
more(struct blk *hptr)
{
        unsigned size;
        char *p;

        if ((size = (hptr->last - hptr->beg) * 2) == 0)
                size = 1;
        nbytes += size / 2;
        if (nbytes > maxsize)
                maxsize = nbytes;
        if (size > longest)
                longest = size;
        lbytes += size / 2;
        lmore++;
        p = realloc(hptr->beg, (unsigned)size);
        if (p == 0) {
                hptr->beg = realloc(hptr->beg,
                    (unsigned)(hptr->last - hptr->beg));
                garbage("more");
                if ((p = realloc(hptr->beg, size)) == 0)
                        ospace("more");
        }
        hptr->rd = hptr->rd - hptr->beg + p;
        hptr->wt = hptr->wt - hptr->beg + p;
        hptr->beg = p;
        hptr->last = p + size;
}

void
ospace(char *s)
{
        printf(gettext("out of space: %s\n"), s);
        printf(gettext("all %ld rel %ld headmor %ld\n"), all, rel, headmor);
        printf(gettext("nbytes %ld\n"), nbytes);
        sdump("stk", *stkptr);
        abort();
}

#define G1      gettext("array %o elt %d odd\n")
#define G2      gettext("tmps %o p %o\n")
void
garbage(char *s)
{
        int i;
        struct blk *p, *q;
        struct sym *tmps;
        int ct;

        printf(gettext("got to garbage %s\n"), s);
        for (i = 0; i < TBLSZ; i++) {
                tmps = stable[i];
                if (tmps != 0) {
                        if (i < ARRAYST) {
                                do {
                                        p = tmps->val;
                                        if (((int)p->beg & 01) != 0) {
                                                printf(gettext(
                                                    "string %o\n"), i);
                                                sdump("odd beg", p);
                                        }
                                        redef(p);
                                        tmps = tmps->next;
                                } while (tmps != 0);
                                continue;
                        } else {
                                do {
                                        p = tmps->val;
                                        rewind(p);
                                        ct = 0;
                                        while ((q = getwd(p)) != NULL) {
                                                ct++;
                                                if (q != 0) {
                                                        if (((int)q->beg & 01)
                                                            != 0) {
                                                                printf(G1,
                                                                    i - ARRAYST,
                                                                    ct);
                                                                printf(G2,
                                                                    tmps, p);
                                                                sdump("elt", q);
                                                        }
                                                        redef(q);
                                                }
                                        }
                                        tmps = tmps->next;
                                } while (tmps != 0);
                        }
                }
        }
}

void
redef(struct blk *p)
{
        int offset;
        char *newp;
        char *dcmalloc();

        if ((int)p->beg & 01) {
                printf(gettext("odd ptr %o hdr %o\n"), p->beg, p);
                ospace("redef-bad");
        }
        free(dummy);
        dummy = dcmalloc(0);
        if (dummy == NULL)
                ospace("dummy");
        newp = realloc(p->beg, (unsigned)(p->last - p->beg));
        if (newp == NULL)
                ospace("redef");
        offset = newp - p->beg;
        p->beg = newp;
        p->rd += offset;
        p->wt += offset;
        p->last += offset;
}

void
release(struct blk *p)
{
        rel++;
        lrel++;
        nbytes -= p->last - p->beg;
        p->rd = (char *)hfree;
        hfree = p;
        free(p->beg);
        p->beg = NULL;
}

struct blk *
getwd(struct blk *p)
{
        struct wblk *wp;

        wp = (struct wblk *)p;
        if (wp->rdw == wp->wtw)
                return (NULL);
        return (*wp->rdw++);
}

void
putwd(struct blk *p, struct blk *c)
{
        struct wblk *wp;

        wp = (struct wblk *)p;
        if (wp->wtw == wp->lastw)
                more(p);
        *wp->wtw++ = c;
}

struct blk *
lookwd(struct blk *p)
{
        struct wblk *wp;

        wp = (struct wblk *)p;
        if (wp->rdw == wp->wtw)
                return (NULL);
        return (*wp->rdw);
}

char *
nalloc(char *p, unsigned int nbytes)
{
        char *dcmalloc();
        char *q, *r;
        q = r = dcmalloc(nbytes);
        if (q == 0)
                return (0);
        while (nbytes--)
                *q++ = *p++;
        return (r);
}

char *
dcmalloc(int size)
{
        return (malloc(size ? size : 1));
}