Annotation of researchv10no/cmd/picasso/misc.c, revision 1.1.1.1

1.1       root        1: /*     Copyright (c) 1988 AT&T */
                      2: /*       All Rights Reserved   */
                      3: 
                      4: /*     THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T     */
                      5: /*     The copyright notice above does not evidence any        */
                      6: /*     actual or intended publication of such source code.     */
                      7: 
                      8: /*     @(#)picasso:misc.c      1.0     */
                      9: #include       "picasso.h"
                     10: #include       "y.tab.h"
                     11: 
                     12: extern int     pic_compat;
                     13: extern int     batch;
                     14: 
                     15: double getcomp(p, t)   /* return component of a position; these must now be */
                     16:        obj *p;         /* transformed as there is no later chance to do so. */
                     17:        int t;
                     18: {
                     19:        float   bnd[4];
                     20: 
                     21:        switch (t) {
                     22:        case DOTX:      return Xformx(p, 1, p->o_x, p->o_y);
                     23:        case DOTY:      return Xformy(p, 1, p->o_x, p->o_y);
                     24:        case DOTRAD:
                     25:                switch (p->o_type) {
                     26:                case SECTOR:
                     27:                case ARC:
                     28:                case BOX:
                     29:                case ARROW:
                     30:                case LINE:      return p->o_val[N_VAL].f;
                     31:                case CIRCLE:
                     32:                case ELLIPSE:   break;  /* fall through to DOTWID case */
                     33:                }
                     34:        case DOTHT:
                     35:        case DOTWID:    if (p->o_type <= TEXT) {
                     36:                                get_bounds(p, bnd, 1);
                     37:                                if (t == DOTHT)
                     38:                                        return (bnd[3] - bnd[1]);
                     39:                                else
                     40:                                        return (bnd[2] - bnd[0]);
                     41:                        }
                     42:        }
                     43:        yyerror("can't happen getcomp");
                     44: }
                     45: 
                     46: exprsave(f)
                     47:        double f;
                     48: {
                     49:        if (nexpr >= nexprlist)
                     50:                exprlist = (float *) grow((char *)exprlist, "exprlist",
                     51:                                        nexprlist += 256, sizeof(float));
                     52:        exprlist[nexpr] = f;
                     53:        return ++nexpr;
                     54: }
                     55: 
                     56: char *sprintgen(fmt)
                     57:        char *fmt;
                     58: {
                     59:        char buf[1000];
                     60: 
                     61:        sprintf (buf, fmt,  exprlist[0], exprlist[1], exprlist[2],
                     62:                                         exprlist[3], exprlist[4]);
                     63:        nexpr = 0;
                     64:        free(fmt);
                     65:        return tostring(buf);
                     66: }
                     67: 
                     68: printexpr(f)   /* print expression for debugging */
                     69:        double f;
                     70: {
                     71:        fprintf(stderr, "%g\n", f);
                     72: }
                     73: 
                     74: printpos(p)    /* print position for debugging */
                     75:        obj *p;
                     76: {
                     77:        double  x, y;
                     78: 
                     79:        x = Xformx(p, 1, p->o_x, p->o_y);
                     80:        y = Xformy(p, 0, p->o_x, p->o_y);
                     81:        fprintf(stderr, "%g, %g\n", x, y);
                     82: }
                     83: 
                     84: char *tostring(s)
                     85:        register char *s;
                     86: {
                     87:        register char *p;
                     88: 
                     89:        p = malloc(strlen(s)+1);
                     90:        if (p == NULL) {
                     91:                yyerror("out of space in tostring on %s", s);
                     92:                exit(1);
                     93:        }
                     94:        strcpy(p, s);
                     95:        return(p);
                     96: }
                     97: 
                     98: obj *makepos(x, y, corner, q)  /* make a position cell */
                     99:        double  x, y;
                    100:        int     corner;
                    101:        obj     *q;
                    102: {
                    103:        obj *p;
                    104: 
                    105:        p = makenode(PLACE, 1, 0);
                    106:        if (q)
                    107:                p->o_parent = q;
                    108:        p->o_x = x;
                    109:        p->o_y = y;
                    110:        p->o_val[0].f = corner;
                    111:        return(p);
                    112: }
                    113: 
                    114: obj *makebetween(f, p1, p2)    /* make position between p1 and p2   */
                    115:        double  f;              /* again, transforms must be applied */
                    116:        obj     *p1, *p2;
                    117: {
                    118:        obj     *p;
                    119:        double  x1, y1, x2, y2;
                    120: 
                    121:        p = makenode(PLACE, 3, 0);
                    122:        x1 = Xformx(p1, 1, p1->o_x, p1->o_y);
                    123:        y1 = Xformy(p1, 0, p1->o_x, p1->o_y);
                    124:        x2 = Xformx(p2, 1, p2->o_x, p2->o_y);
                    125:        y2 = Xformy(p2, 0, p2->o_x, p2->o_y);
                    126:        p->o_x = x1 + f * (x2 - x1);
                    127:        p->o_y = y1 + f * (y2 - y1);
                    128:        p->o_val[0].f = f;
                    129:        p->o_val[1].o = p1;
                    130:        p->o_val[2].o = p2;
                    131:        return(p);
                    132: }
                    133: 
                    134: int    xdelta[8] = {1,1,1,0,-1,-1,-1,0},
                    135:        ydelta[8] = {-1,0,1,1,1,0,-1,-1};
                    136: 
                    137: obj *getnth(p, nth)    /* find nth point of an object */
                    138:        obj     *p;
                    139:        int     nth;
                    140: {
                    141:        float   x, y;
                    142:        int     n = nth;
                    143: 
                    144:        switch (p->o_type) {
                    145:        default:        if (n != 1)
                    146:                                yyerror("object has only 1 point defined");
                    147:                        return p;
                    148:        case ARC:       if (n > 2) {
                    149:                                yyerror("arcs have only 2 points defined");
                    150:                                return p;
                    151:                        }
                    152:                        /* else fall through to SECTOR case */
                    153:        case SECTOR:    if ((n %= 3) == 0)
                    154:                                return p;
                    155:                        else if (n == 1) {
                    156:                                x = p->o_val[N_VAL+2].f;
                    157:                                y = p->o_val[N_VAL+3].f;
                    158:                        }
                    159:                        else {
                    160:                                x = p->o_val[N_VAL+4].f;
                    161:                                y = p->o_val[N_VAL+5].f;
                    162:                        }
                    163:                        break;
                    164:        case BLOCK:     while (n--) {
                    165:                                p = p->o_next;
                    166:                                if (p->o_type <= TEXT)
                    167:                                        continue;
                    168:                                else if (p->o_type == BLOCKEND) {
                    169:                                        yyerror("[] has less than %d objects",
                    170:                                                        nth);
                    171:                                        p = p->o_parent;
                    172:                                }
                    173:                        }
                    174:                        return p;       
                    175:        case BOX:       n %= 8;
                    176:                        x = p->o_x + xdelta[n] * p->o_wid / 2;
                    177:                        y = p->o_y + ydelta[n] * p->o_ht  / 2;
                    178:                        break;
                    179:        case ARROW:
                    180:        case LINE:
                    181:        case SPLINE:    if (--n > p->o_val[N_VAL+3].f) {
                    182:                                yyerror("line has less than %d points", nth);
                    183:                                return p;
                    184:                        }
                    185:                        x = p->o_val[N_VAL + 4 + 2 * n].f;
                    186:                        y = p->o_val[N_VAL + 5 + 2 * n].f;
                    187:                        break;
                    188:        case CIRCLE:
                    189:        case ELLIPSE:   n %= 8;
                    190:                        x = xdelta[n] * p->o_wid / 2;
                    191:                        y = ydelta[n] * p->o_ht  / 2;
                    192:                        if (n % 2 == 0) {
                    193:                                x *= M_SQRT1_2;
                    194:                                y *= M_SQRT1_2;
                    195:                        }
                    196:                        x += p->o_x;
                    197:                        y += p->o_y;
                    198:                        break;
                    199:        }
                    200:        /*  DBK--Here also there is a question of whether x and y should
                    201:            be transformed */
                    202:        return makepos(x, y, nth, p);
                    203: }
                    204: 
                    205: obj *getpos(p, corner) /* find position of point */
                    206:        obj     *p;
                    207:        int     corner;
                    208: {
                    209:        float   x, y;
                    210: 
                    211:        if (pic_compat && (p->o_type == CIRCLE || p->o_type == ELLIPSE) &&
                    212:                (corner == NE || corner == NW || corner == SW || corner == SE))
                    213:                        return getnth(p, corner == NE ? 2 : corner == NW ? 4 :
                    214:                                                        corner == SW ? 6 : 8);
                    215:        if (corner == -1 )
                    216:                if (pic_compat && (p->o_type == LINE || p->o_type == ARROW ||
                    217:                                                        p->o_type == SPLINE))
                    218:                        corner = START;
                    219:                else
                    220:                        return p;
                    221:        whatpos(p, corner, &x, &y);
                    222:        return makepos(x,y,corner,(corner < EAST || corner > SW)? p: (obj *)0);
                    223: }
                    224: 
                    225: whatpos(p, corner, px, py)     /* what is the position (no side effect) */
                    226:        obj     *p;
                    227:        int     corner;
                    228:        float   *px, *py;
                    229: {
                    230:        float   x, y, bnd[4];
                    231: 
                    232:        if (corner >= EAST && corner <= SW) {
                    233:                get_bounds(p, bnd, 1);
                    234:                switch (corner) {
                    235:        case NE:        x = bnd[2];             y = bnd[3];     break;
                    236:        case SW:        x = bnd[0];             y = bnd[1];     break;
                    237:        case SE:        x = bnd[2];             y = bnd[1];     break;
                    238:        case NW:        x = bnd[0];             y = bnd[3];     break;
                    239:        case NORTH:     x = (bnd[0]+bnd[2])/2;  y = bnd[3];     break;
                    240:        case SOUTH:     x = (bnd[0]+bnd[2])/2;  y = bnd[1];     break;
                    241:        case EAST:      x = bnd[2];     y = (bnd[1]+bnd[3])/2;  break;
                    242:        case WEST:      x = bnd[0];     y = (bnd[1]+bnd[3])/2;  break;
                    243:                }
                    244:        }
                    245:        else {  /* DBK--note that get_bounds returns the transformed position,
                    246:                   but the following calculations do not!! */
                    247:                x = p->o_x;
                    248:                y = p->o_y;
                    249: 
                    250: /* futz around for special cases: */
                    251: 
                    252:                switch (p->o_type) {
                    253:        case BLOCK:     if (corner == START)
                    254:                                whatpos(p->o_next, START, &x, &y);
                    255:                        else if (corner == END)
                    256:                                whatpos(p->o_val[N_VAL+1].o->o_prev,END,&x,&y);
                    257:                        break;
                    258:        case ARC:       if (corner == START) {
                    259:                                x = p->o_val[N_VAL+2].f;
                    260:                                y = p->o_val[N_VAL+3].f;
                    261:                        }
                    262:                        else if (corner == END) {
                    263:                                x = p->o_val[N_VAL+4].f;
                    264:                                y = p->o_val[N_VAL+5].f;
                    265:                        }
                    266:                        break;
                    267:        case LINE:
                    268:        case SPLINE:
                    269:        case ARROW:     switch (corner) {
                    270:                                int     n;
                    271:                case START:     x = p->o_val[N_VAL+4].f;
                    272:                                y = p->o_val[N_VAL+5].f;
                    273:                                break;
                    274:                case END:       n = N_VAL + 4 + 2*p->o_val[N_VAL+3].f;
                    275:                                x = p->o_val[n].f;
                    276:                                y = p->o_val[n+1].f;
                    277:                                break;
                    278:                        }
                    279:                        break;
                    280:                }
                    281:        }
                    282:        *px = x;
                    283:        *py = y;
                    284:        return 1;
                    285: }
                    286: 
                    287: obj *gethere() /* make a place for curx,cury */
                    288: {
                    289:        return(makepos(curx, cury, 0, (obj *)0));
                    290: }
                    291: 
                    292: obj *getlast(n, t)     /* find n-th previous occurrence of type t */
                    293:        int n, t;
                    294: {
                    295:        int k;
                    296:        obj *p;
                    297: 
                    298:        k = n;
                    299:        if (t == TEXTOBJ)       /* for purely syntactical reasons */
                    300:                t = TEXT;
                    301:        for (p = objtail->o_prev; p != objhead; p = p->o_prev) {
                    302:                if (p->o_type == BLOCKEND) {
                    303:                        p = p->o_parent;
                    304:                        if (t != BLOCK && t != OBJECT)
                    305:                                continue;
                    306:                }
                    307:                if (t == OBJECT && p->o_type > TEXT)
                    308:                        continue;
                    309:                if (t != OBJECT && p->o_type != t)
                    310:                        continue;
                    311:                if (--k > 0)
                    312:                        continue;       /* not there yet */
                    313:                return(p);
                    314:        }
                    315:        yyerror("there is no %dth last", n);
                    316:        return(NULL);
                    317: }
                    318: 
                    319: obj *getfirst(n, t)    /* find n-th occurrence of type t */
                    320:        int n, t;
                    321: {
                    322:        int k;
                    323:        obj *p;
                    324: 
                    325:        k = n;
                    326:        if (t == TEXTOBJ)
                    327:                t = TEXT;
                    328:        for (p = objhead->o_next; p != objtail; p = p->o_next) {
                    329:                if (p->o_type == BLOCK
                    330:                && t != BLOCK && t != OBJECT) {         /* skip block,  */
                    331:                        if (p->o_val[N_VAL].o != NULL)  /* unless it's  */
                    332:                                p = p->o_val[N_VAL].o;  /* still active */
                    333:                        continue;
                    334:                }
                    335:                if (t == OBJECT && p->o_type > TEXT)
                    336:                        continue;
                    337:                if (t != OBJECT && p->o_type != t)
                    338:                        continue;
                    339:                if (--k > 0)
                    340:                        continue;       /* not there yet */
                    341:                return(p);
                    342:        }
                    343:        yyerror("there is no %dth", n);
                    344:        return(NULL);
                    345: }
                    346: 
                    347: double getblkvar(p, s) /* find variable s2 in block p */
                    348:        obj *p;
                    349:        char *s;
                    350: {
                    351:        YYSTYPE y, getblk();
                    352: 
                    353:        y = getblk(p, s);
                    354:        free(s);
                    355:        return y.f;
                    356: }
                    357: 
                    358: obj *getblock(p, s)    /* find variable s in block p */
                    359:        obj *p;
                    360:        char *s;
                    361: {
                    362:        YYSTYPE y, getblk();
                    363: 
                    364:        y = getblk(p, s);
                    365:        free(s);
                    366:        return y.o;
                    367: }
                    368: 
                    369: YYSTYPE getblk(p, s)   /* find union type for s in p */
                    370:        obj *p;
                    371:        char *s;
                    372: {
                    373:        static YYSTYPE bug;
                    374:        struct symtab *stp;
                    375: 
                    376:        if (p->o_type != BLOCK) {
                    377:                yyerror(".%s is not in that block", s);
                    378:                return(bug);
                    379:        }
                    380:        for (stp = p->o_val[N_VAL+1].s; stp != NULL; stp = stp->s_next)
                    381:                if (strcmp(s, stp->s_name) == 0)
                    382:                        return(stp->s_val);
                    383:        yyerror("there is no .%s in that []", s);
                    384:        return(bug);
                    385: }
                    386: 
                    387: obj *fixpos(p, x, y)   /* this, addpos & subpos SHOULD be altered to give   */
                    388:        obj *p;         /* o_x,o_y as offset from position of p, with p as   */
                    389:        double x, y;    /* o_parent, but I haven't yet worked out the xform. */
                    390: {
                    391: #if 1
                    392: /* DBK: 3/21/90 -- comment out the following if clause.  It has the effect
                    393:    of changing A in the expression A + x,y !!!
                    394:        if (p->o_type == PLACE) {
                    395:                p->o_x += x;
                    396:                p->o_y += y;
                    397:                return p;
                    398:        }
                    399:    end of commented out code *************/
                    400:        x += Xformx(p, 1, p->o_x, p->o_y);
                    401:        y += Xformy(p, 0, p->o_x, p->o_y);
                    402: #else
                    403:        if (p->o_type == PLACE) {
                    404:                x += p->o_x;
                    405:                y += p->o_y;
                    406:        }
                    407:        else {
                    408:                x += Xformx(p, 1, p->o_x, p->o_y);
                    409:                y += Xformy(p, 0, p->o_x, p->o_y);
                    410:        }
                    411: #endif
                    412:        return makepos(x, y, 0, (obj *)0);
                    413: }
                    414: 
                    415: obj *addpos(p, q)
                    416:        obj *p, *q;
                    417: {
                    418:        double  x, y;
                    419: 
                    420:        x = Xformx(q, 1, q->o_x, q->o_y);
                    421:        y = Xformy(q, 0, q->o_x, q->o_y);
                    422: /* DBK:  see above
                    423:        if (p->o_type == PLACE) {
                    424:                p->o_x += x;
                    425:                p->o_y += y;
                    426:                return p;
                    427:        }
                    428:  */
                    429:        x += Xformx(p, 1, p->o_x, p->o_y);
                    430:        y += Xformy(p, 0, p->o_x, p->o_y);
                    431:        return makepos(x, y, 0, (obj *)0);
                    432: }
                    433: 
                    434: obj *subpos(p, q)
                    435:        obj *p, *q;
                    436: {
                    437:        double  x, y;
                    438: 
                    439:        x = Xformx(q, 1, q->o_x, q->o_y);
                    440:        y = Xformy(q, 0, q->o_x, q->o_y);
                    441: /* DBK:  see above
                    442:        if (p->o_type == PLACE) {
                    443:                p->o_x -= x;
                    444:                p->o_y -= y;
                    445:                return p;
                    446:        }
                    447:  */
                    448:        x -= Xformx(p, 1, p->o_x, p->o_y);
                    449:        y -= Xformy(p, 0, p->o_x, p->o_y);
                    450:        return makepos(x, y, 0, (obj *)0);
                    451: }
                    452: 
                    453: obj *makenode(type, n, layer)
                    454:        int     type, n, layer;
                    455: {
                    456:        obj     *p;
                    457: 
                    458:        if (objbuf && batch)
                    459:                print_buf();
                    460:        p = (obj *) calloc(1, sizeof(obj) + (n-1)*sizeof(YYSTYPE));
                    461:        if (p == NULL) {
                    462:                yyerror("out of space in makenode");
                    463:                exit(1);
                    464:        }
                    465:        if (n > 65535)
                    466:                yyerror("making excessively large object");
                    467:        p->o_next = objtail;
                    468:        p->o_prev = objtail->o_prev;
                    469:        p->o_prev->o_next = objtail->o_prev = p;        
                    470:        p->o_parent = cur_block;
                    471:        p->o_x = curx;
                    472:        p->o_y = cury;
                    473:        p->o_nt1 = ntext1;
                    474:        p->o_nt2 = ntext;
                    475:        p->o_text = -1;
                    476: #if 1
                    477:        /* force all strings in object to have same justification */
                    478:        {
                    479:        int     jflags, lastf;
                    480:        jflags = RJUST|LJUST|CENTER|ABOVE|BELOW;
                    481:        lastf = text[ntext-1].t_type & jflags;
                    482:        for ( ; ntext1 < ntext; ntext1++)
                    483:                text[ntext1].t_type = text[ntext1].t_type & ~ jflags | lastf;
                    484:        }
                    485: #endif
                    486:        ntext1 = ntext; /* ready for next caller */
                    487:        if (layer < -128)
                    488:                layer = -128;
                    489:        else if (layer > 127)
                    490:                layer = 127;
                    491:        if ((p->o_layer = layer) > 0 && layer > top_layer)
                    492:                top_layer = layer;
                    493:        if ((p->o_type = type) <= TEXT) {
                    494:                p->o_mxx = p->o_myy = 1.0;      /* initialize xform matrix */
                    495:                p->o_size = n;                  /* keep count, for copies  */
                    496:        }
                    497:        return(p);
                    498: }
                    499: 
                    500: freenode (p)           /* free space occupied by object p */
                    501:        obj     *p;
                    502: {
                    503:        obj     *q, *q1;
                    504: 
                    505:        if (p->o_type == BLOCK) {                       /* I think there's */
                    506:                freesymtab(p->o_val[N_VAL+1].s);        /* a bug here, for */
                    507:                q = p->o_val[N_VAL].o;                  /* nested blocks.  */
                    508:                p->o_prev->o_next = q->o_next;
                    509:                q->o_next->o_prev = p->o_prev;
                    510:                q->o_next = (obj *)NULL;
                    511:                for (q = p->o_next; q != NULL; ) {
                    512:                        if (q->o_type == BLOCK)
                    513:                                freesymtab(q->o_val[N_VAL+1].s);
                    514:                        q1 = q;
                    515:                        q = q->o_next;
                    516:                        free(q1); 
                    517:                }
                    518:        }
                    519:        else {
                    520:                p->o_prev->o_next = p->o_next;
                    521:                p->o_next->o_prev = p->o_prev;
                    522:        }
                    523:        free (p);
                    524:        if (!objbuf) redo_gbox = 1;     /* page boundaries are now suspect */
                    525: }
                    526: 
                    527: extreme(x, y, bbox)    /* record max and min x and y values */
                    528:        double  x, y;
                    529:        float   *bbox;
                    530: {
                    531:        if ((float)x < bbox[0]) bbox[0] = x;
                    532:        if ((float)y < bbox[1]) bbox[1] = y;
                    533:        if ((float)x > bbox[2]) bbox[2] = x;
                    534:        if ((float)y > bbox[3]) bbox[3] = y;
                    535: }
                    536: 
                    537: track_bounds(x0, y0, x1, y1)   /* insert a bounding box into the global box */
                    538:        double  x0, y0, x1, y1;
                    539: {
                    540:        if (x0 < Gbox[0])       Gbox[0] = x0;
                    541:        if (y0 < Gbox[1])       Gbox[1] = y0;
                    542:        if (x1 > Gbox[2])       Gbox[2] = x1;
                    543:        if (y1 > Gbox[3])       Gbox[3] = y1;
                    544: }
                    545: 
                    546: get_bounds(p, bbox, flag) /* reconstruct bounding box from center/basis/xform */
                    547:        obj     *p;
                    548:        float   *bbox;
                    549:        int     flag;
                    550: {
                    551: static obj     *lastp = (obj *)0;
                    552: static double  x0, y0, x1, y1;
                    553:        double  w, h, wm, hm, x, y;
                    554:        double  owid, oht;
                    555: 
                    556:        if (flag && p == lastp)
                    557:                goto done;
                    558:        x = Xformx(p, 1, p->o_x, p->o_y);
                    559:        y = Xformy(p, 0, p->o_x, p->o_y);
                    560:        if (p->o_type > TEXT) {
                    561:                x0 = x1 = x;
                    562:                y0 = y1 = y;
                    563:        }
                    564:        else {
                    565:                if (p->o_type == TEXT) {
                    566:                        x += Linx(p,0,p->o_val[N_VAL-2].f,p->o_val[N_VAL-1].f);
                    567:                        y += Liny(p,0,p->o_val[N_VAL-2].f,p->o_val[N_VAL-1].f);
                    568:                }
                    569:                else if (p->o_type == ARC || p->o_type == SECTOR) {
                    570:                        x -= Linx(p,0,p->o_val[N_VAL+6].f,p->o_val[N_VAL+7].f);
                    571:                        y -= Liny(p,0,p->o_val[N_VAL+6].f,p->o_val[N_VAL+7].f);
                    572:                }
                    573:                owid = p->o_wid + p->o_weight;
                    574:                oht =  p->o_ht + p->o_weight;
                    575:                if (     ( p->o_type == ARROW || p->o_type == LINE
                    576:                        || p->o_type == SPLINE || p->o_type == ARC)
                    577:                                                && (p->o_attr & HEAD12)) {
                    578:                    w = p->o_val[N_VAL+(p->o_type == ARC ? 8 : 1)].f;
                    579:                    owid += w;          /* account for width of arrowheads */
                    580:                    oht  += w;
                    581:                }
                    582:                w = Linx(p, 0, owid, oht) / 2;  /* transform main diagonal */
                    583:                h = Liny(p, 0, owid, oht) / 2;
                    584:                wm = Linx(p, 0, -owid, oht) / 2; /* transform other diagonal */
                    585:                hm = Liny(p, 0, -owid, oht) / 2;
                    586:                if (w < 0)      w = -w;
                    587:                if (h < 0)      h = -h;
                    588:                if (wm < 0)     wm = -wm;
                    589:                if (hm < 0)     hm = -hm;
                    590:                if (w < wm)     w = wm;
                    591:                if (h < hm)     h = hm;
                    592:                x0 = x - w;
                    593:                x1 = x + w;
                    594:                y0 = y - h;
                    595:                y1 = y + h;
                    596:        }
                    597:        lastp = p;
                    598: done:  bbox[0] = x0;   bbox[1] = y0;   bbox[2] = x1; bbox[3] = y1;
                    599: }

unix.superglobalmegacorp.com

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