Annotation of lucent/sys/src/9/port/devbit.c, revision 1.1

1.1     ! root        1: #include       "u.h"
        !             2: #include       "../port/lib.h"
        !             3: #include       <libg.h>
        !             4: #include       <gnot.h>
        !             5: #include       "mem.h"
        !             6: #include       "dat.h"
        !             7: #include       "fns.h"
        !             8: #include       "../port/error.h"
        !             9: 
        !            10: #include       "devtab.h"
        !            11: 
        !            12: #include       "screen.h"
        !            13: 
        !            14: /*
        !            15:  * Some monochrome screens are reversed from what we like:
        !            16:  * We want 0's bright and 1's dark.
        !            17:  * Indexed by an Fcode, these compensate for the source bitmap being wrong
        !            18:  * (exchange S rows) and destination (exchange D columns and invert result)
        !            19:  */
        !            20: int flipS[] = {
        !            21:        0x0, 0x4, 0x8, 0xC, 0x1, 0x5, 0x9, 0xD,
        !            22:        0x2, 0x6, 0xA, 0xE, 0x3, 0x7, 0xB, 0xF
        !            23: };
        !            24: 
        !            25: int flipD[] = {
        !            26:        0xF, 0xD, 0xE, 0xC, 0x7, 0x5, 0x6, 0x4,
        !            27:        0xB, 0x9, 0xA, 0x8, 0x3, 0x1, 0x2, 0x0, 
        !            28: };
        !            29: 
        !            30: int flipping;  /* are flip tables being used to transform Fcodes? */
        !            31: 
        !            32: /*
        !            33:  * Device (#b/bitblt) is exclusive use on open, so no locks are necessary
        !            34:  * for i/o
        !            35:  */
        !            36: 
        !            37: /*
        !            38:  * Arena is a word containing N, followed by a pointer to the Arena,
        !            39:  * followed by a pointer to the Bitmap, followed by N words.
        !            40:  * The bitmap pointer is zero if block is free.
        !            41:  * bit.map is an array of pointers to GBitmaps.  The GBitmaps are
        !            42:  * freed individually and their corresponding entries in bit.map are zeroed.
        !            43:  * The index into bit.map is the Bitmap id as seen in libg.  Subfonts and
        !            44:  * fonts are handled similarly.
        !            45:  */
        !            46: 
        !            47: typedef struct Arena   Arena;
        !            48: struct Arena
        !            49: {
        !            50:        ulong   *words;         /* storage */
        !            51:        ulong   *wfree;         /* pointer to next free word */
        !            52:        ulong   nwords;         /* total in arena */
        !            53:        int     nbusy;          /* number of busy blocks */
        !            54: };
        !            55: 
        !            56: typedef struct BSubfont BSubfont;
        !            57: struct BSubfont
        !            58: {
        !            59:        GSubfont;
        !            60:        int     ref;            /* number of times this subfont is open */
        !            61:        ulong   qid[2];         /* unique id used as a cache tag */
        !            62: };
        !            63: 
        !            64: extern GSubfont        *defont;
        !            65:        BSubfont        *bdefont;
        !            66:        BSubfont bdefont0;
        !            67: 
        !            68: 
        !            69: struct
        !            70: {
        !            71:        Ref;
        !            72:        QLock;
        !            73:        GBitmap **map;          /* indexed array */
        !            74:        int     nmap;           /* number allocated */
        !            75:        GFont   **font;         /* indexed array */
        !            76:        int     nfont;          /* number allocated */
        !            77:        BSubfont**subfont;      /* indexed array */
        !            78:        int     nsubfont;       /* number allocated */
        !            79:        Arena   *arena;         /* array */
        !            80:        int     narena;         /* number allocated */
        !            81:        int     mouseopen;      /* flag: mouse open */
        !            82:        int     bitbltopen;     /* flag: bitblt open */
        !            83:        int     bid;            /* last allocated bitmap id */
        !            84:        int     subfid;         /* last allocated subfont id */
        !            85:        int     cacheid;        /* last cached subfont id */
        !            86:        int     fid;            /* last allocated font id */
        !            87:        int     init;           /* freshly opened; init message pending */
        !            88:        int     rid;            /* read bitmap id */
        !            89:        int     rminy;          /* read miny */
        !            90:        int     rmaxy;          /* read maxy */
        !            91:        int     mid;            /* colormap read bitmap id */
        !            92: }bit;
        !            93: 
        !            94: #define        DMAP    16              /* delta increase in size of arrays */
        !            95: #define        FREE    0x80000000
        !            96: 
        !            97: void   bitcompact(void);
        !            98: int    bitalloc(Rectangle, int);
        !            99: void   bitfree(GBitmap*);
        !           100: void   fontfree(GFont*);
        !           101: void   subfontfree(BSubfont*, int);
        !           102: void   arenafree(Arena*);
        !           103: void   bitstring(GBitmap*, Point, GFont*, uchar*, long, Fcode);
        !           104: void   bitloadchar(GFont*, int, GSubfont*, int);
        !           105: extern GBitmap gscreen;
        !           106: 
        !           107: typedef struct Mouseinfo       Mouseinfo;
        !           108: typedef struct Cursorinfo      Cursorinfo;
        !           109: 
        !           110: struct Mouseinfo{
        !           111:        /*
        !           112:         * First three fields are known in some l.s's
        !           113:         */
        !           114:        int     dx;
        !           115:        int     dy;
        !           116:        int     track;          /* l.s has updated dx & dy */
        !           117:        Mouse;
        !           118:        int     redraw;         /* update cursor on screen */
        !           119:        ulong   counter;        /* increments every update */
        !           120:        ulong   lastcounter;    /* value when /dev/mouse read */
        !           121:        Rendez  r;
        !           122: };
        !           123: 
        !           124: struct Cursorinfo{
        !           125:        Cursor;
        !           126:        Lock;
        !           127:        int     visible;        /* on screen */
        !           128:        Rectangle r;            /* location */
        !           129: };
        !           130: 
        !           131: Mouseinfo      mouse;
        !           132: Cursorinfo     cursor;
        !           133: Cursor         curs;
        !           134: int            mouseshifted;
        !           135: int            mousetype;
        !           136: int            mouseswap;
        !           137: int            islittle;
        !           138: int            hwcurs;
        !           139: 
        !           140: Cursor arrow =
        !           141: {
        !           142:        {-1, -1},
        !           143:        {0xFF, 0xE0, 0xFF, 0xE0, 0xFF, 0xC0, 0xFF, 0x00,
        !           144:         0xFF, 0x00, 0xFF, 0x80, 0xFF, 0xC0, 0xFF, 0xE0,
        !           145:         0xE7, 0xF0, 0xE3, 0xF8, 0xC1, 0xFC, 0x00, 0xFE,
        !           146:         0x00, 0x7F, 0x00, 0x3E, 0x00, 0x1C, 0x00, 0x08,
        !           147:        },
        !           148:        {0x00, 0x00, 0x7F, 0xC0, 0x7F, 0x00, 0x7C, 0x00,
        !           149:         0x7E, 0x00, 0x7F, 0x00, 0x6F, 0x80, 0x67, 0xC0,
        !           150:         0x43, 0xE0, 0x41, 0xF0, 0x00, 0xF8, 0x00, 0x7C,
        !           151:         0x00, 0x3E, 0x00, 0x1C, 0x00, 0x08, 0x00, 0x00,
        !           152:        }
        !           153: };
        !           154: 
        !           155: ulong setbits[16];
        !           156: GBitmap        set =
        !           157: {
        !           158:        setbits,
        !           159:        0,
        !           160:        1,
        !           161:        0,
        !           162:        {0, 0, 16, 16},
        !           163:        {0, 0, 16, 16}
        !           164: };
        !           165: 
        !           166: ulong clrbits[16];
        !           167: GBitmap        clr =
        !           168: {
        !           169:        clrbits,
        !           170:        0,
        !           171:        1,
        !           172:        0,
        !           173:        {0, 0, 16, 16},
        !           174:        {0, 0, 16, 16}
        !           175: };
        !           176: 
        !           177: ulong cursorbackbits[16*4];
        !           178: GBitmap cursorback =
        !           179: {
        !           180:        cursorbackbits,
        !           181:        0,
        !           182:        1,
        !           183:        0,
        !           184:        {0, 0, 16, 16},
        !           185:        {0, 0, 16, 16}
        !           186: };
        !           187: 
        !           188: void   Cursortocursor(Cursor*);
        !           189: int    mousechanged(void*);
        !           190: 
        !           191: enum{
        !           192:        Qdir,
        !           193:        Qbitblt,
        !           194:        Qmouse,
        !           195:        Qmousectl,
        !           196:        Qscreen,
        !           197: };
        !           198: 
        !           199: Dirtab bitdir[]={
        !           200:        "bitblt",       {Qbitblt},      0,                      0666,
        !           201:        "mouse",        {Qmouse},       0,                      0666,
        !           202:        "mousectl",     {Qmousectl},    0,                      0220,
        !           203:        "screen",       {Qscreen},      0,                      0444,
        !           204: };
        !           205: 
        !           206: #define        NBIT    (sizeof bitdir/sizeof(Dirtab))
        !           207: #define        NINFO   8192    /* max chars per subfont; sanity check only */
        !           208: #define        HDR     3
        !           209: 
        !           210: void
        !           211: lockedupdate(void)
        !           212: {
        !           213:        qlock(&bit);
        !           214:        if(waserror()){
        !           215:                qunlock(&bit);
        !           216:                return;
        !           217:        }
        !           218:        screenupdate();
        !           219:        qunlock(&bit);
        !           220:        poperror();
        !           221: }
        !           222: 
        !           223: void
        !           224: bitfreeup(void)
        !           225: {
        !           226:        int i;
        !           227:        BSubfont *s;
        !           228: 
        !           229:        /* free unused subfonts and compact */
        !           230:        for(i=0; i<bit.nsubfont; i++){
        !           231:                s = bit.subfont[i];
        !           232:                if(s && s!=bdefont && s->ref==0){
        !           233:                        s->ref = 1;
        !           234:                        s->qid[0] = ~0; /* force cleanup */
        !           235:                        subfontfree(s, i);
        !           236:                }
        !           237:        }
        !           238:        bitcompact();
        !           239: }
        !           240: 
        !           241: void*
        !           242: bitmalloc(ulong n)
        !           243: {
        !           244:        void *p;
        !           245: 
        !           246:        p = malloc(n);
        !           247:        if(p)
        !           248:                return p;
        !           249:        bitfreeup();
        !           250:        return malloc(n);
        !           251: }
        !           252: 
        !           253: void
        !           254: bitdebug(void)
        !           255: {
        !           256:        int i;
        !           257:        long l;
        !           258:        Arena *a;
        !           259: 
        !           260:        l = 0;
        !           261:        for(i=0; i<bit.narena; i++){
        !           262:                a = &bit.arena[i];
        !           263:                if(a->words){
        !           264:                        l += a->nwords;
        !           265:                        print("%d: %ld bytes used; %ld total\n", i,
        !           266:                                (a->wfree-a->words)*sizeof(ulong),
        !           267:                                a->nwords*sizeof(ulong));
        !           268:                }
        !           269:        }
        !           270:        print("arena: %ld bytes\n", l*sizeof(ulong));
        !           271:        l = 0;
        !           272:        for(i=0; i<bit.nmap; i++)
        !           273:                if(bit.map[i])
        !           274:                        l++;
        !           275:        print("%d bitmaps ", l);
        !           276:        l = 0;
        !           277:        for(i=0; i<bit.nfont; i++)
        !           278:                if(bit.font[i])
        !           279:                        l++;
        !           280:        print("%d fonts ", l);
        !           281:        l = 0;
        !           282:        for(i=0; i<bit.nsubfont; i++)
        !           283:                if(bit.subfont[i]){
        !           284:                        print("%d: %lux %lux ", i, bit.subfont[i]->qid[0], bit.subfont[i]->qid[1]);
        !           285:                        l++;
        !           286:                }
        !           287:        print("%d subfonts\n", l);
        !           288: }
        !           289: 
        !           290: void
        !           291: bitreset(void)
        !           292: {
        !           293:        int ws;
        !           294:        ulong r;
        !           295:        Arena *a;
        !           296: 
        !           297:        if(!conf.monitor)
        !           298:                return;
        !           299: 
        !           300:        memmove(&bdefont0, defont, sizeof(*defont));
        !           301:        bdefont = &bdefont0;
        !           302:        bit.map = smalloc(DMAP*sizeof(GBitmap*));
        !           303:        bit.nmap = DMAP;
        !           304:        getcolor(0, &r, &r, &r);
        !           305:        if(r == 0)
        !           306:                flipping = 1;
        !           307:        bit.bid = -1;
        !           308:        bit.subfid = -1;
        !           309:        bit.fid = -1;
        !           310:        bit.cacheid = -1;
        !           311:        bit.font = smalloc(DMAP*sizeof(GFont*));
        !           312:        bit.nfont = DMAP;
        !           313:        bit.subfont = smalloc(DMAP*sizeof(BSubfont*));
        !           314:        bit.nsubfont = DMAP;
        !           315:        bit.arena = smalloc(DMAP*sizeof(Arena));
        !           316:        bit.narena = DMAP;
        !           317:        a = &bit.arena[0];
        !           318:        /*
        !           319:         * Somewhat of a heuristic: start with three screensful and
        !           320:         * allocate single screensful dynamically if needed.
        !           321:         */
        !           322: 
        !           323:        ws = BI2WD>>gscreen.ldepth;     /* pixels per word */
        !           324:        a->nwords = 3*(HDR + gscreen.r.max.y*gscreen.r.max.x/ws);
        !           325:        a->words = xalloc(a->nwords*sizeof(ulong));
        !           326:        if(a->words == 0){
        !           327:                /* try again */
        !           328:                print("bitreset: allocating only 1 screenful\n");
        !           329:                a->nwords /= 3;
        !           330:                a->words = a->words = xalloc(a->nwords*sizeof(ulong));
        !           331:                if(a->words == 0)
        !           332:                        panic("bitreset");
        !           333:        }
        !           334:        a->wfree = a->words;
        !           335:        a->nbusy = 1;   /* keep 0th arena from being freed */
        !           336:        Cursortocursor(&arrow);
        !           337: }
        !           338: 
        !           339: /*
        !           340:  *  screen bit depth changed, reset backup map for cursor
        !           341:  */
        !           342: void
        !           343: bitdepth(void)
        !           344: {
        !           345:        cursoroff(1);
        !           346:        if(gscreen.ldepth > 3)
        !           347:                cursorback.ldepth = 0;
        !           348:        else{
        !           349:                cursorback.ldepth = gscreen.ldepth;
        !           350:                cursorback.width = ((16 << gscreen.ldepth) + 31) >> 5;
        !           351:        }
        !           352:        cursoron(1);
        !           353: }
        !           354: 
        !           355: void
        !           356: bitinit(void)
        !           357: {
        !           358:        if(!conf.monitor)
        !           359:                return;
        !           360:        if(gscreen.ldepth > 3)
        !           361:                cursorback.ldepth = 0;
        !           362:        else{
        !           363:                cursorback.ldepth = gscreen.ldepth;
        !           364:                cursorback.width = ((16 << gscreen.ldepth) + 31) >> 5;
        !           365:        }
        !           366:        cursoron(1);
        !           367: }
        !           368: 
        !           369: Chan*
        !           370: bitattach(char *spec)
        !           371: {
        !           372:        if(!conf.monitor)
        !           373:                error(Egreg);
        !           374:        return devattach('b', spec);
        !           375: }
        !           376: 
        !           377: Chan*
        !           378: bitclone(Chan *c, Chan *nc)
        !           379: {
        !           380:        if(!conf.monitor)
        !           381:                error(Egreg);
        !           382:        nc = devclone(c, nc);
        !           383:        if(c->qid.path != CHDIR)
        !           384:                incref(&bit);
        !           385:        return nc;
        !           386: }
        !           387: 
        !           388: int
        !           389: bitwalk(Chan *c, char *name)
        !           390: {
        !           391:        if(!conf.monitor)
        !           392:                error(Egreg);
        !           393:        return devwalk(c, name, bitdir, NBIT, devgen);
        !           394: }
        !           395: 
        !           396: void
        !           397: bitstat(Chan *c, char *db)
        !           398: {
        !           399:        if(!conf.monitor)
        !           400:                error(Egreg);
        !           401:        devstat(c, db, bitdir, NBIT, devgen);
        !           402: }
        !           403: 
        !           404: Chan*
        !           405: bitopen(Chan *c, int omode)
        !           406: {
        !           407:        GBitmap *b;
        !           408: 
        !           409:        if(!conf.monitor)
        !           410:                error(Egreg);
        !           411:        switch(c->qid.path){
        !           412:        case CHDIR:
        !           413:                if(omode != OREAD)
        !           414:                        error(Eperm);
        !           415:                break;
        !           416:        case Qmouse:
        !           417:                lock(&bit);
        !           418:                if(bit.mouseopen){
        !           419:                        unlock(&bit);
        !           420:                        error(Einuse);
        !           421:                }
        !           422:                bit.mouseopen = 1;
        !           423:                bit.ref++;
        !           424:                unlock(&bit);
        !           425:                break;
        !           426:        case Qbitblt:
        !           427:                lock(&bit);
        !           428:                if(bit.bitbltopen || bit.mouseopen){
        !           429:                        unlock(&bit);
        !           430:                        error(Einuse);
        !           431:                }
        !           432:                b = smalloc(sizeof(GBitmap));
        !           433:                *b = gscreen;
        !           434:                bit.map[0] = b;                 /* bitmap 0 is screen */
        !           435:                bit.subfont[0] = bdefont;       /* subfont 0 is default */
        !           436:                bit.subfont[0]->ref = 1;
        !           437:                bit.subfont[0]->qid[0] = 0;
        !           438:                bit.subfont[0]->qid[1] = 0;
        !           439:                bit.bid = -1;
        !           440:                bit.fid = -1;
        !           441:                bit.subfid = -1;
        !           442:                bit.cacheid = -1;
        !           443:                bit.rid = -1;
        !           444:                bit.mid = -1;
        !           445:                bit.init = 0;
        !           446:                bit.bitbltopen = 1;
        !           447:                Cursortocursor(&arrow);
        !           448:                unlock(&bit);
        !           449:                break;
        !           450:        default:
        !           451:                incref(&bit);
        !           452:        }
        !           453:        c->mode = openmode(omode);
        !           454:        c->flag |= COPEN;
        !           455:        c->offset = 0;
        !           456:        return c;
        !           457: }
        !           458: 
        !           459: void
        !           460: bitcreate(Chan *c, char *name, int omode, ulong perm)
        !           461: {
        !           462:        if(!conf.monitor)
        !           463:                error(Egreg);
        !           464:        USED(c, name, omode, perm);
        !           465:        error(Eperm);
        !           466: }
        !           467: 
        !           468: void
        !           469: bitremove(Chan *c)
        !           470: {
        !           471:        if(!conf.monitor)
        !           472:                error(Egreg);
        !           473:        USED(c);
        !           474:        error(Eperm);
        !           475: }
        !           476: 
        !           477: void
        !           478: bitwstat(Chan *c, char *db)
        !           479: {
        !           480:        if(!conf.monitor)
        !           481:                error(Egreg);
        !           482:        USED(c, db);
        !           483:        error(Eperm);
        !           484: }
        !           485: 
        !           486: void
        !           487: bitclose(Chan *c)
        !           488: {
        !           489:        GBitmap *b, **bp, **ebp;
        !           490:        BSubfont *s, **sp, **esp;
        !           491:        GFont *f, **fp, **efp;
        !           492: 
        !           493:        if(!conf.monitor)
        !           494:                error(Egreg);
        !           495:        if(c->qid.path!=CHDIR && (c->flag&COPEN)){
        !           496:                lock(&bit);
        !           497:                if(c->qid.path == Qmouse)
        !           498:                        bit.mouseopen = 0;
        !           499:                if(c->qid.path == Qbitblt)
        !           500:                        bit.bitbltopen = 0;
        !           501:                if(--bit.ref == 0){
        !           502:                        ebp = &bit.map[bit.nmap];
        !           503:                        for(bp = bit.map; bp<ebp; bp++){
        !           504:                                b = *bp;
        !           505:                                if(b){
        !           506:                                        bitfree(b);
        !           507:                                        *bp = 0;
        !           508:                                }
        !           509:                        }
        !           510:                        esp = &bit.subfont[bit.nsubfont];
        !           511:                        for(sp=bit.subfont; sp<esp; sp++){
        !           512:                                s = *sp;
        !           513:                                if(s)
        !           514:                                        subfontfree(s, sp-bit.subfont);
        !           515:                                /* don't clear *sp: cached */
        !           516:                        }
        !           517:                        efp = &bit.font[bit.nfont];
        !           518:                        for(fp=bit.font; fp<efp; fp++){
        !           519:                                f = *fp;
        !           520:                                if(f){
        !           521:                                        fontfree(f);
        !           522:                                        *fp = 0;
        !           523:                                }
        !           524:                        }
        !           525:                }
        !           526:                unlock(&bit);
        !           527:        }
        !           528: }
        !           529: 
        !           530: long
        !           531: bitread(Chan *c, void *va, long n, ulong offset)
        !           532: {
        !           533:        uchar *p, *q;
        !           534:        long miny, maxy, t, x, y;
        !           535:        ulong l, nw, ws, rv, gv, bv;
        !           536:        int off, j;
        !           537:        Fontchar *i;
        !           538:        GBitmap *src;
        !           539:        BSubfont *s;
        !           540:        static int map[8] = {0, 4, 2, 6, 1, 5, 3, 7 };
        !           541: 
        !           542:        if(!conf.monitor)
        !           543:                error(Egreg);
        !           544:        if(c->qid.path & CHDIR)
        !           545:                return devdirread(c, va, n, bitdir, NBIT, devgen);
        !           546: 
        !           547:        if(c->qid.path == Qmouse){
        !           548:                /*
        !           549:                 * mouse:
        !           550:                 *      'm'             1
        !           551:                 *      buttons         1
        !           552:                 *      point           8
        !           553:                 *      msec            4
        !           554:                 */
        !           555:                if(n < 14)
        !           556:                        error(Ebadblt);
        !           557:                while(mousechanged(0) == 0)
        !           558:                        sleep(&mouse.r, mousechanged, 0);
        !           559:                lock(&cursor);
        !           560:                p = va;
        !           561:                p[0] = 'm';
        !           562:                p[1] = mouseswap ? map[mouse.buttons&7] : mouse.buttons;
        !           563:                BPLONG(p+2, mouse.xy.x);
        !           564:                BPLONG(p+6, mouse.xy.y);
        !           565:                BPLONG(p+10, TK2MS(MACHP(0)->ticks));
        !           566:                mouse.lastcounter = mouse.counter;
        !           567:                unlock(&cursor);
        !           568:                return 14;
        !           569:        }
        !           570:        if(c->qid.path == Qscreen){
        !           571:                if(offset==0){
        !           572:                        if(n < 5*12)
        !           573:                                error(Eio);
        !           574:                        sprint(va, "%11d %11d %11d %11d %11d ",
        !           575:                                gscreen.ldepth, gscreen.r.min.x,
        !           576:                                gscreen.r.min.y, gscreen.r.max.x,
        !           577:                                gscreen.r.max.y);
        !           578:                        return 5*12;
        !           579:                }
        !           580:                ws = 1<<(3-gscreen.ldepth);     /* pixels per byte */
        !           581:                l = (gscreen.r.max.x+ws-1)/ws - gscreen.r.min.x/ws;
        !           582:                if(l == 0)
        !           583:                        error(Ebadblt);
        !           584:                t = offset-5*12;
        !           585:                miny = t/l;     /* unsigned computation */
        !           586:                maxy = (t+n)/l;
        !           587:                if(miny >= gscreen.r.max.y)
        !           588:                        return 0;
        !           589:                if(maxy >= gscreen.r.max.y)
        !           590:                        maxy = gscreen.r.max.y;
        !           591:                n = 0;
        !           592:                p = va;
        !           593:                for(y=miny; y<maxy; y++){
        !           594:                        q = (uchar*)gaddr(&gscreen, Pt(0, y));
        !           595:                        memmove(p, q, l);
        !           596:                        if(flipping)
        !           597:                                /* is screen, so must be word aligned */
        !           598:                                for(x=0; x<l; x+=sizeof(ulong),p+=sizeof(ulong))
        !           599:                                        *(ulong*)p ^= ~0;
        !           600:                        else
        !           601:                                p += l;
        !           602:                        n += l;
        !           603:                }
        !           604:                return n;
        !           605:        }
        !           606:        if(c->qid.path != Qbitblt)
        !           607:                error(Egreg);
        !           608: 
        !           609:        qlock(&bit);
        !           610:        if(waserror()){
        !           611:                qunlock(&bit);
        !           612:                nexterror();
        !           613:        }
        !           614:        p = va;
        !           615:        /*
        !           616:         * Fuss about and figure out what to say.
        !           617:         */
        !           618:        if(bit.init){
        !           619:                /*
        !           620:                 * init:
        !           621:                 *      'I'             1
        !           622:                 *      ldepth          1
        !           623:                 *      rectangle       16
        !           624:                 *      clip rectangle  16
        !           625:                 *      font info       3*12
        !           626:                 *      fontchars       6*(bdefont->n+1)
        !           627:                 */
        !           628:                if(n < 34)
        !           629:                        error(Ebadblt);
        !           630:                p[0] = 'I';
        !           631:                p[1] = gscreen.ldepth;
        !           632:                BPLONG(p+2, gscreen.r.min.x);
        !           633:                BPLONG(p+6, gscreen.r.min.y);
        !           634:                BPLONG(p+10, gscreen.r.max.x);
        !           635:                BPLONG(p+14, gscreen.r.max.y);
        !           636:                BPLONG(p+18, gscreen.clipr.min.x);
        !           637:                BPLONG(p+22, gscreen.clipr.min.y);
        !           638:                BPLONG(p+26, gscreen.clipr.max.x);
        !           639:                BPLONG(p+30, gscreen.clipr.max.y);
        !           640:                if(n >= 34+3*12+6*(bdefont->n+1)){
        !           641:                        p += 34;
        !           642:                        sprint((char*)p, "%11d %11d %11d ", bdefont->n,
        !           643:                                bdefont->height, bdefont->ascent);
        !           644:                        p += 3*12;
        !           645:                        for(i=bdefont->info,j=0; j<=bdefont->n; j++,i++,p+=6){
        !           646:                                BPSHORT(p, i->x);
        !           647:                                p[2] = i->top;
        !           648:                                p[3] = i->bottom;
        !           649:                                p[4] = i->left;
        !           650:                                p[5] = i->width;
        !           651:                        }
        !           652:                        n = 34+3*12+6*(bdefont->n+1);
        !           653:                }else
        !           654:                        n = 34;
        !           655:                bit.init = 0;
        !           656:        }else if(bit.bid > 0){
        !           657:                /*
        !           658:                 * allocate:
        !           659:                 *      'A'             1
        !           660:                 *      bitmap id       2
        !           661:                 */
        !           662:                if(n < 3)
        !           663:                        error(Ebadblt);
        !           664:                if(bit.bid<0 || bit.map[bit.bid]==0)
        !           665:                        error(Ebadbitmap);
        !           666:                p[0] = 'A';
        !           667:                BPSHORT(p+1, bit.bid);
        !           668:                bit.bid = -1;
        !           669:                n = 3;
        !           670:        }else if(bit.subfid > 0){
        !           671:                /*
        !           672:                 * allocate subfont:
        !           673:                 *      'K'             1
        !           674:                 *      subfont id      2
        !           675:                 */
        !           676:                if(n<3 || bit.subfid<0)
        !           677:                        error(Ebadblt);
        !           678:                s = bit.subfont[bit.subfid];
        !           679:                if(s==0 || s->ref==0)
        !           680:                        error(Ebadfont);
        !           681:                p[0] = 'K';
        !           682:                BPSHORT(p+1, bit.subfid);
        !           683:                bit.subfid = -1;
        !           684:                n = 3;
        !           685:        }else if(bit.cacheid >= 0){
        !           686:                /*
        !           687:                 * check cache for subfont:
        !           688:                 *      'J'             1
        !           689:                 *      subfont id      2
        !           690:                 *      font info       3*12
        !           691:                 *      fontchars       6*(subfont->n+1)
        !           692:                 */
        !           693:                p[0] = 'J';
        !           694:                if(bit.cacheid < 0)
        !           695:                        error(Ebadfont);
        !           696:                s = bit.subfont[bit.cacheid];
        !           697:                if(s==0 || s->ref==0)
        !           698:                        error(Ebadfont);
        !           699:                if(n < 3+3*12+6*(s->n+1))
        !           700:                        error(Ebadblt);
        !           701:                BPSHORT(p+1, bit.cacheid);
        !           702:                p += 3;
        !           703:                sprint((char*)p, "%11d %11d %11d ", s->n, s->height, s->ascent);
        !           704:                p += 3*12;
        !           705:                for(i=s->info,j=0; j<=s->n; j++,i++,p+=6){
        !           706:                        BPSHORT(p, i->x);
        !           707:                        p[2] = i->top;
        !           708:                        p[3] = i->bottom;
        !           709:                        p[4] = i->left;
        !           710:                        p[5] = i->width;
        !           711:                }
        !           712:                n = 3+3*12+6*(s->n+1);
        !           713:                bit.cacheid = -1;
        !           714:        }else if(bit.fid >= 0){
        !           715:                /*
        !           716:                 * allocate font:
        !           717:                 *      'N'             1
        !           718:                 *      font id         2
        !           719:                 */
        !           720:                if(n < 3)
        !           721:                        error(Ebadblt);
        !           722:                if(bit.fid<0 || bit.font[bit.fid]==0)
        !           723:                        error(Ebadfont);
        !           724:                p[0] = 'N';
        !           725:                BPSHORT(p+1, bit.fid);
        !           726:                bit.fid = -1;
        !           727:                n = 3;
        !           728:        }else if(bit.mid >= 0){
        !           729:                /*
        !           730:                 * read colormap:
        !           731:                 *      data            12*(2**bitmapdepth)
        !           732:                 */
        !           733:                src = bit.map[bit.mid];
        !           734:                if(src == 0)
        !           735:                        error(Ebadbitmap);
        !           736:                l = (1<<src->ldepth);
        !           737:                nw = 1 << l;
        !           738:                if(n < 12*nw)
        !           739:                        error(Ebadblt);
        !           740:                for(j = 0; j < nw; j++){
        !           741:                        if(bit.mid == 0){
        !           742:                                getcolor(flipping? nw-j-1 : j, &rv, &gv, &bv);
        !           743:                        }else{
        !           744:                                rv = j;
        !           745:                                for(off = 32-l; off > 0; off -= l)
        !           746:                                        rv = (rv << l) | j;
        !           747:                                gv = bv = rv;
        !           748:                        }
        !           749:                        BPLONG(p, rv);
        !           750:                        BPLONG(p+4, gv);
        !           751:                        BPLONG(p+8, bv);
        !           752:                        p += 12;
        !           753:                }
        !           754:                bit.mid = -1;
        !           755:                n = 12*nw;
        !           756:        }else if(bit.rid >= 0){
        !           757:                /*
        !           758:                 * read bitmap:
        !           759:                 *      data            bytewidth*(maxy-miny)
        !           760:                 */
        !           761:                src = bit.map[bit.rid];
        !           762:                if(src == 0)
        !           763:                        error(Ebadbitmap);
        !           764:                off = 0;
        !           765:                if(bit.rid == 0)
        !           766:                        off = 1;
        !           767:                miny = bit.rminy;
        !           768:                maxy = bit.rmaxy;
        !           769:                if(miny>maxy || miny<src->r.min.y || maxy>src->r.max.y)
        !           770:                        error(Ebadblt);
        !           771:                ws = 1<<(3-src->ldepth);        /* pixels per byte */
        !           772:                /* set l to number of bytes of incoming data per scan line */
        !           773:                if(src->r.min.x >= 0)
        !           774:                        l = (src->r.max.x+ws-1)/ws - src->r.min.x/ws;
        !           775:                else{   /* make positive before divide */
        !           776:                        t = (-src->r.min.x)+ws-1;
        !           777:                        t = (t/ws)*ws;
        !           778:                        l = (t+src->r.max.x+ws-1)/ws;
        !           779:                }
        !           780:                if(n < l*(maxy-miny))
        !           781:                        error(Ebadblt);
        !           782:                if(off)
        !           783:                        cursoroff(1);
        !           784:                n = 0;
        !           785:                p = va;
        !           786:                for(y=miny; y<maxy; y++){
        !           787:                        q = (uchar*)gaddr(src, Pt(src->r.min.x, y));
        !           788:                        q += (src->r.min.x&((sizeof(ulong))*ws-1))/ws;
        !           789:                        memmove(p, q, l);
        !           790:                        if(islittle)
        !           791:                                pixreverse(p, l, src->ldepth);
        !           792:                        if(bit.rid==0 && flipping)
        !           793:                                /* is screen, so must be word aligned */
        !           794:                                for(x=0; x<l; x+=sizeof(ulong),p+=sizeof(ulong))
        !           795:                                        *(ulong*)p ^= ~0;
        !           796:                        else
        !           797:                                p += l;
        !           798:                        n += l;
        !           799:                }
        !           800:                if(off)
        !           801:                        cursoron(1);
        !           802:                bit.rid = -1;
        !           803:        }
        !           804: 
        !           805:        poperror();
        !           806:        qunlock(&bit);
        !           807:        return n;
        !           808: }
        !           809: 
        !           810: Point
        !           811: bitstrsize(GFont *f, uchar *p, int l)
        !           812: {
        !           813:        ushort r;
        !           814:        Point s = {0,0};
        !           815:        GCacheinfo *c;
        !           816: 
        !           817:        while(l > 0){
        !           818:                r = BGSHORT(p);
        !           819:                p += 2;
        !           820:                l -= 2;
        !           821:                if(r >= f->ncache)
        !           822:                        continue;
        !           823:                c = &f->cache[r];
        !           824:                if(c->bottom > s.y)
        !           825:                        s.y = c->bottom;
        !           826:                s.x += c->width;
        !           827:        }
        !           828:        return s;
        !           829: }
        !           830: 
        !           831: long
        !           832: bitwrite(Chan *c, void *va, long n, ulong offset)
        !           833: {
        !           834:        uchar *p, *q, *oq;
        !           835:        long m, v, miny, maxy, t, x, y;
        !           836:        ulong l, nw, ws, rv, q0, q1;
        !           837:        ulong *lp;
        !           838:        int off, isoff, i, j, ok;
        !           839:        ulong *endscreen = gaddr(&gscreen, Pt(0, gscreen.r.max.y));
        !           840:        Point pt, pt1, pt2;
        !           841:        Rectangle rect;
        !           842:        Fcode fc;
        !           843:        Fontchar *fcp;
        !           844:        GBitmap *src, *dst;
        !           845:        BSubfont *f, *tf, **fp;
        !           846:        GFont *ff, **ffp;
        !           847:        GCacheinfo *gc;
        !           848:        char buf[64];
        !           849: 
        !           850:        if(!conf.monitor)
        !           851:                error(Egreg);
        !           852:        USED(offset);
        !           853: 
        !           854:        if(c->qid.path == CHDIR)
        !           855:                error(Eisdir);
        !           856: 
        !           857:        if(c->qid.path == Qmousectl){
        !           858:                if(n >= sizeof(buf))
        !           859:                        n = sizeof(buf)-1;
        !           860:                strncpy(buf, va, n);
        !           861:                buf[n] = 0;
        !           862:                mousectl(buf);
        !           863:                return n;
        !           864:        }
        !           865: 
        !           866:        if(c->qid.path != Qbitblt)
        !           867:                error(Egreg);
        !           868: 
        !           869:        isoff = 0;
        !           870:        qlock(&bit);
        !           871:        if(waserror()){
        !           872:                qunlock(&bit);
        !           873:                if(isoff)
        !           874:                        cursoron(1);
        !           875:                nexterror();
        !           876:        }
        !           877:        p = va;
        !           878:        m = n;
        !           879:        SET(src, dst, f, ff);
        !           880:        while(m > 0)
        !           881:                switch(*p){
        !           882:                default:
        !           883:                        pprint("bitblt request 0x%x\n", *p);
        !           884:                        error(Ebadblt);
        !           885: 
        !           886:                case 'a':
        !           887:                        /*
        !           888:                         * allocate:
        !           889:                         *      'a'             1
        !           890:                         *      ldepth          1
        !           891:                         *      Rectangle       16
        !           892:                         * next read returns allocated bitmap id
        !           893:                         */
        !           894:                        if(m < 18)
        !           895:                                error(Ebadblt);
        !           896:                        v = *(p+1);
        !           897:                        if(v > 3)       /* BUG */
        !           898:                                error(Ebadblt);
        !           899:                        rect.min.x = BGLONG(p+2);
        !           900:                        rect.min.y = BGLONG(p+6);
        !           901:                        rect.max.x = BGLONG(p+10);
        !           902:                        rect.max.y = BGLONG(p+14);
        !           903:                        if(Dx(rect) < 0 || Dy(rect) < 0)
        !           904:                                error(Ebadblt);
        !           905:                        bit.bid = bitalloc(rect, v);
        !           906:                        m -= 18;
        !           907:                        p += 18;
        !           908:                        break;
        !           909: 
        !           910:                case 'b':
        !           911:                        /*
        !           912:                         * bitblt
        !           913:                         *      'b'             1
        !           914:                         *      dst id          2
        !           915:                         *      dst Point       8
        !           916:                         *      src id          2
        !           917:                         *      src Rectangle   16
        !           918:                         *      code            2
        !           919:                         */
        !           920:                        if(m < 31)
        !           921:                                error(Ebadblt);
        !           922:                        fc = BGSHORT(p+29) & 0xF;
        !           923:                        v = BGSHORT(p+11);
        !           924:                        if(v<0 || v>=bit.nmap || (src=bit.map[v])==0)
        !           925:                                error(Ebadbitmap);
        !           926:                        off = 0;
        !           927:                        if(v == 0){
        !           928:                                if(flipping)
        !           929:                                        fc = flipS[fc];
        !           930:                                off = 1;
        !           931:                        }
        !           932:                        v = BGSHORT(p+1);
        !           933:                        if(v<0 || v>=bit.nmap || (dst=bit.map[v])==0)
        !           934:                                error(Ebadbitmap);
        !           935:                        if(v == 0){
        !           936:                                if(flipping)
        !           937:                                        fc = flipD[fc];
        !           938:                                off = 1;
        !           939:                        }
        !           940:                        pt.x = BGLONG(p+3);
        !           941:                        pt.y = BGLONG(p+7);
        !           942:                        rect.min.x = BGLONG(p+13);
        !           943:                        rect.min.y = BGLONG(p+17);
        !           944:                        rect.max.x = BGLONG(p+21);
        !           945:                        rect.max.y = BGLONG(p+25);
        !           946:                        if(off && !isoff){
        !           947:                                cursoroff(1);
        !           948:                                isoff = 1;
        !           949:                        }
        !           950:                        gbitblt(dst, pt, src, rect, fc);
        !           951:                        if(dst->base < endscreen)
        !           952:                                mbbrect(Rpt(pt, add(pt, sub(rect.max, rect.min))));
        !           953:                        m -= 31;
        !           954:                        p += 31;
        !           955:                        break;
        !           956: 
        !           957:                case 'c':
        !           958:                        /*
        !           959:                         * cursorswitch
        !           960:                         *      'c'             1
        !           961:                         * if nothing more: return to arrow; else
        !           962:                         *      Point           8
        !           963:                         *      clr             32
        !           964:                         *      set             32
        !           965:                         */
        !           966:                        if(m == 1){
        !           967:                                if(!isoff){
        !           968:                                        cursoroff(1);
        !           969:                                        isoff = 1;
        !           970:                                }
        !           971:                                Cursortocursor(&arrow);
        !           972:                                m -= 1;
        !           973:                                p += 1;
        !           974:                                break;
        !           975:                        }
        !           976:                        if(m < 73)
        !           977:                                error(Ebadblt);
        !           978:                        curs.offset.x = BGLONG(p+1);
        !           979:                        curs.offset.y = BGLONG(p+5);
        !           980:                        memmove(curs.clr, p+9, 2*16);
        !           981:                        memmove(curs.set, p+41, 2*16);
        !           982:                        if(islittle){
        !           983:                                pixreverse(curs.clr, 2*16, 0);
        !           984:                                pixreverse(curs.set, 2*16, 0);
        !           985:                        }
        !           986:                        if(!isoff){
        !           987:                                cursoroff(1);
        !           988:                                isoff = 1;
        !           989:                        }
        !           990:                        Cursortocursor(&curs);
        !           991:                        m -= 73;
        !           992:                        p += 73;
        !           993:                        break;
        !           994: 
        !           995:                case 'e':
        !           996:                        /*
        !           997:                         * polysegment
        !           998:                         *
        !           999:                         *      'e'             1
        !          1000:                         *      id              2
        !          1001:                         *      pt              8
        !          1002:                         *      value           1
        !          1003:                         *      code            2
        !          1004:                         *      n               2
        !          1005:                         *      pts             2*n
        !          1006:                         */
        !          1007:                        if(m < 16)
        !          1008:                                error(Ebadblt);
        !          1009:                        l = BGSHORT(p+14);
        !          1010:                        if(m < 16+2*l)
        !          1011:                                error(Ebadblt);
        !          1012:                        v = BGSHORT(p+1);
        !          1013:                        if(v<0 || v>=bit.nmap || (dst=bit.map[v])==0)
        !          1014:                                error(Ebadbitmap);
        !          1015:                        off = 0;
        !          1016:                        fc = BGSHORT(p+12) & 0xF;
        !          1017:                        if(v == 0){
        !          1018:                                if(flipping)
        !          1019:                                        fc = flipD[fc];
        !          1020:                                off = 1;
        !          1021:                        }
        !          1022:                        pt1.x = BGLONG(p+3);
        !          1023:                        pt1.y = BGLONG(p+7);
        !          1024:                        t = p[11];
        !          1025:                        if(off && !isoff){
        !          1026:                                cursoroff(1);
        !          1027:                                isoff = 1;
        !          1028:                        }
        !          1029:                        p += 16;
        !          1030:                        m -= 16;
        !          1031:                        while(l > 0){
        !          1032:                                pt2.x = pt1.x + (schar)p[0];
        !          1033:                                pt2.y = pt1.y + (schar)p[1];
        !          1034:                                gsegment(dst, pt1, pt2, t, fc);
        !          1035:                                if(dst->base < endscreen){
        !          1036:                                        mbbpt(pt1);
        !          1037:                                        mbbpt(pt2);
        !          1038:                                }
        !          1039:                                pt1 = pt2;
        !          1040:                                p += 2;
        !          1041:                                m -= 2;
        !          1042:                                l--;
        !          1043:                        }
        !          1044:                        break;
        !          1045: 
        !          1046:                case 'f':
        !          1047:                        /*
        !          1048:                         * free
        !          1049:                         *      'f'             1
        !          1050:                         *      id              2
        !          1051:                         */
        !          1052:                        if(m < 3)
        !          1053:                                error(Ebadblt);
        !          1054:                        v = BGSHORT(p+1);
        !          1055:                        if(v<0 || v>=bit.nmap || (dst=bit.map[v])==0)
        !          1056:                                error(Ebadbitmap);
        !          1057:                        bitfree(dst);
        !          1058:                        bit.map[v] = 0;
        !          1059:                        m -= 3;
        !          1060:                        p += 3;
        !          1061:                        break;
        !          1062: 
        !          1063:                case 'g':
        !          1064:                        /*
        !          1065:                         * free subfont
        !          1066:                         *      'g'             1
        !          1067:                         *      id              2
        !          1068:                         */
        !          1069:                        if(m < 3)
        !          1070:                                error(Ebadblt);
        !          1071:                        v = BGSHORT(p+1);
        !          1072:                        if(v<0 || v>=bit.nsubfont || (f=bit.subfont[v])==0 || f->ref==0)
        !          1073:                                error(Ebadfont);
        !          1074:                        subfontfree(f, v);
        !          1075:                        m -= 3;
        !          1076:                        p += 3;
        !          1077:                        break;
        !          1078: 
        !          1079:                case 'h':
        !          1080:                        /*
        !          1081:                         * free font
        !          1082:                         *      'h'             1
        !          1083:                         *      id              2
        !          1084:                         */
        !          1085:                        if(m < 3)
        !          1086:                                error(Ebadblt);
        !          1087:                        v = BGSHORT(p+1);
        !          1088:                        if(v<0 || v>=bit.nfont || (ff=bit.font[v])==0)
        !          1089:                                error(Ebadfont);
        !          1090:                        fontfree(ff);
        !          1091:                        bit.font[v] = 0;
        !          1092:                        m -= 3;
        !          1093:                        p += 3;
        !          1094:                        break;
        !          1095: 
        !          1096:                case 'i':
        !          1097:                        /*
        !          1098:                         * init
        !          1099:                         *
        !          1100:                         *      'i'             1
        !          1101:                         */
        !          1102:                        bit.init = 1;
        !          1103:                        m -= 1;
        !          1104:                        p += 1;
        !          1105:                        break;
        !          1106: 
        !          1107:                case 'j':
        !          1108:                        /*
        !          1109:                         * subfont cache check
        !          1110:                         *
        !          1111:                         *      'j'             1
        !          1112:                         *      qid             8
        !          1113:                         */
        !          1114:                        if(m < 9)
        !          1115:                                error(Ebadblt);
        !          1116:                        q0 = BGLONG(p+1);
        !          1117:                        q1 = BGLONG(p+5);
        !          1118:                        i = 0;
        !          1119:                        if(q0 != ~0)
        !          1120:                                for(; i<bit.nsubfont; i++){
        !          1121:                                        f = bit.subfont[i];
        !          1122:                                        if(f && f->qid[0]==q0 && f->qid[1]==q1)
        !          1123:                                                goto sfcachefound;
        !          1124:                                }
        !          1125:                        error(Esfnotcached);
        !          1126: 
        !          1127:                sfcachefound:
        !          1128:                        f->ref++;
        !          1129:                        bit.cacheid = i;
        !          1130:                        m -= 9;
        !          1131:                        p += 9;
        !          1132:                        break;
        !          1133: 
        !          1134:                case 'k':
        !          1135:                        /*
        !          1136:                         * allocate subfont
        !          1137:                         *      'k'             1
        !          1138:                         *      n               2
        !          1139:                         *      height          1
        !          1140:                         *      ascent          1
        !          1141:                         *      bitmap id       2
        !          1142:                         *      qid             8
        !          1143:                         *      fontchars       6*(n+1)
        !          1144:                         * next read returns allocated font id
        !          1145:                         */
        !          1146:                        if(m < 15)
        !          1147:                                error(Ebadblt);
        !          1148:                        v = BGSHORT(p+1);
        !          1149:                        if(v<0 || v>NINFO || m<15+6*(v+1))
        !          1150:                                error(Ebadblt);
        !          1151:                        for(i=1; i<bit.nsubfont; i++)
        !          1152:                                if(bit.subfont[i] == 0)
        !          1153:                                        goto subfontfound;
        !          1154:                        fp = bitmalloc((bit.nsubfont+DMAP)*sizeof(BSubfont*));
        !          1155:                        if(fp == 0)
        !          1156:                                error(Enomem);
        !          1157:                        memmove(fp, bit.subfont, bit.nsubfont*sizeof(BSubfont*));
        !          1158:                        free(bit.subfont);
        !          1159:                        bit.subfont = fp;
        !          1160:                        bit.nsubfont += DMAP;
        !          1161:                subfontfound:
        !          1162:                        f = bitmalloc(sizeof(BSubfont));
        !          1163:                        if(f == 0)
        !          1164:                                error(Enomem);
        !          1165:                        f->info = bitmalloc((v+1)*sizeof(Fontchar));
        !          1166:                        if(f->info == 0){
        !          1167:                                free(f);
        !          1168:                                error(Enomem);
        !          1169:                        }
        !          1170:                        bit.subfont[i] = f;
        !          1171:                        f->n = v;
        !          1172:                        f->height = p[3];
        !          1173:                        f->ascent = p[4];
        !          1174:                        f->qid[0] = BGLONG(p+7);
        !          1175:                        f->qid[1] = BGLONG(p+11);
        !          1176:                        /* check to see if already there, uncache if so */
        !          1177:                        for(j=0; j<bit.nsubfont; j++){
        !          1178:                                if(j == i)
        !          1179:                                        continue;
        !          1180:                                tf = bit.subfont[j];
        !          1181:                                if(tf && tf->qid[0]==f->qid[0] && tf->qid[1]==f->qid[1]){
        !          1182:                                        f->qid[0] = ~0; /* uncached */
        !          1183:                                        break;
        !          1184:                                }
        !          1185:                        }
        !          1186:                        f->ref = 1;
        !          1187:                        v = BGSHORT(p+5);
        !          1188:                        if(v<0 || v>=bit.nmap || (dst=bit.map[v])==0)
        !          1189:                                error(Ebadbitmap);
        !          1190:                        f->bits = dst;
        !          1191:                        bit.map[v] = 0; /* subfont now owns bitmap */
        !          1192:                        m -= 15;
        !          1193:                        p += 15;
        !          1194:                        fcp = f->info;
        !          1195:                        for(j=0; j<=f->n; j++,fcp++){
        !          1196:                                fcp->x = BGSHORT(p);
        !          1197:                                fcp->top = p[2];
        !          1198:                                fcp->bottom = p[3];
        !          1199:                                fcp->left = p[4];
        !          1200:                                fcp->width = p[5];
        !          1201:                                fcp->top = p[2];
        !          1202:                                p += 6;
        !          1203:                                m -= 6;
        !          1204:                        }
        !          1205:                        bit.subfid = i;
        !          1206:                        break;
        !          1207: 
        !          1208:                case 'l':
        !          1209:                        /*
        !          1210:                         * line segment
        !          1211:                         *
        !          1212:                         *      'l'             1
        !          1213:                         *      id              2
        !          1214:                         *      pt1             8
        !          1215:                         *      pt2             8
        !          1216:                         *      value           1
        !          1217:                         *      code            2
        !          1218:                         */
        !          1219:                        if(m < 22)
        !          1220:                                error(Ebadblt);
        !          1221:                        v = BGSHORT(p+1);
        !          1222:                        if(v<0 || v>=bit.nmap || (dst=bit.map[v])==0)
        !          1223:                                error(Ebadbitmap);
        !          1224:                        off = 0;
        !          1225:                        fc = BGSHORT(p+20) & 0xF;
        !          1226:                        if(v == 0){
        !          1227:                                if(flipping)
        !          1228:                                        fc = flipD[fc];
        !          1229:                                off = 1;
        !          1230:                        }
        !          1231:                        pt1.x = BGLONG(p+3);
        !          1232:                        pt1.y = BGLONG(p+7);
        !          1233:                        pt2.x = BGLONG(p+11);
        !          1234:                        pt2.y = BGLONG(p+15);
        !          1235:                        t = p[19];
        !          1236:                        if(off && !isoff){
        !          1237:                                cursoroff(1);
        !          1238:                                isoff = 1;
        !          1239:                        }
        !          1240:                        gsegment(dst, pt1, pt2, t, fc);
        !          1241:                        if(dst->base < endscreen){
        !          1242:                                mbbpt(pt1);
        !          1243:                                mbbpt(pt2);
        !          1244:                        }
        !          1245:                        m -= 22;
        !          1246:                        p += 22;
        !          1247:                        break;
        !          1248: 
        !          1249:                case 'm':
        !          1250:                        /*
        !          1251:                         * read colormap
        !          1252:                         *
        !          1253:                         *      'm'             1
        !          1254:                         *      id              2
        !          1255:                         */
        !          1256:                        if(m < 3)
        !          1257:                                error(Ebadblt);
        !          1258:                        v = BGSHORT(p+1);
        !          1259:                        if(v<0 || v>=bit.nmap || (dst=bit.map[v])==0)
        !          1260:                                error(Ebadbitmap);
        !          1261:                        bit.mid = v;
        !          1262:                        m -= 3;
        !          1263:                        p += 3;
        !          1264:                        break;
        !          1265: 
        !          1266:                case 'n':
        !          1267:                        /*
        !          1268:                         * allocate font
        !          1269:                         *      'n'             1
        !          1270:                         *      height          1
        !          1271:                         *      ascent          1
        !          1272:                         *      ldepth          2
        !          1273:                         *      ncache          2
        !          1274:                         * next read returns allocated font id
        !          1275:                         */
        !          1276:                        if(m < 7)
        !          1277:                                error(Ebadblt);
        !          1278:                        v = BGSHORT(p+3);
        !          1279:                        t = BGSHORT(p+5);
        !          1280:                        if(v<0 || t<0)
        !          1281:                                error(Ebadblt);
        !          1282:                        for(i=0; i<bit.nfont; i++)
        !          1283:                                if(bit.font[i] == 0)
        !          1284:                                        goto fontfound;
        !          1285:                        ffp = bitmalloc((bit.nfont+DMAP)*sizeof(GFont*));
        !          1286:                        if(ffp == 0)
        !          1287:                                error(Enomem);
        !          1288:                        memmove(ffp, bit.font, bit.nfont*sizeof(GFont*));
        !          1289:                        free(bit.font);
        !          1290:                        bit.font = ffp;
        !          1291:                        bit.nfont += DMAP;
        !          1292:                fontfound:
        !          1293:                        ff = bitmalloc(sizeof(GFont));
        !          1294:                        if(ff == 0)
        !          1295:                                error(Enomem);
        !          1296:                        ff->ncache = t;
        !          1297:                        ff->cache = bitmalloc(t*sizeof(GCacheinfo));
        !          1298:                        if(ff->cache == 0){
        !          1299:                                free(ff);
        !          1300:                                error(Enomem);
        !          1301:                        }
        !          1302:                        bit.font[i] = ff;
        !          1303:                        ff = bit.font[i];
        !          1304:                        ff->height = p[1];
        !          1305:                        ff->ascent = p[2];
        !          1306:                        ff->ldepth = v;
        !          1307:                        ff->width = 0;
        !          1308:                        ff->b = 0;
        !          1309:                        m -= 7;
        !          1310:                        p += 7;
        !          1311:                        bit.fid = i;
        !          1312:                        break;
        !          1313: 
        !          1314:                case 'p':
        !          1315:                        /*
        !          1316:                         * point
        !          1317:                         *
        !          1318:                         *      'p'             1
        !          1319:                         *      id              2
        !          1320:                         *      pt              8
        !          1321:                         *      value           1
        !          1322:                         *      code            2
        !          1323:                         */
        !          1324:                        if(m < 14)
        !          1325:                                error(Ebadblt);
        !          1326:                        v = BGSHORT(p+1);
        !          1327:                        if(v<0 || v>=bit.nmap || (dst=bit.map[v])==0)
        !          1328:                                error(Ebadbitmap);
        !          1329:                        off = 0;
        !          1330:                        fc = BGSHORT(p+12) & 0xF;
        !          1331:                        if(v == 0){
        !          1332:                                if(flipping)
        !          1333:                                        fc = flipD[fc];
        !          1334:                                off = 1;
        !          1335:                        }
        !          1336:                        pt1.x = BGLONG(p+3);
        !          1337:                        pt1.y = BGLONG(p+7);
        !          1338:                        t = p[11];
        !          1339:                        if(off && !isoff){
        !          1340:                                cursoroff(1);
        !          1341:                                isoff = 1;
        !          1342:                        }
        !          1343:                        gpoint(dst, pt1, t, fc);
        !          1344:                        if(dst->base < endscreen)
        !          1345:                                mbbpt(pt1);
        !          1346:                        m -= 14;
        !          1347:                        p += 14;
        !          1348:                        break;
        !          1349: 
        !          1350:                case 'q':
        !          1351:                        /*
        !          1352:                         * clip rectangle
        !          1353:                         *      'q'             1
        !          1354:                         *      id              2
        !          1355:                         *      rect            16
        !          1356:                         */
        !          1357:                        if(m < 19)
        !          1358:                                error(Ebadblt);
        !          1359:                        v = BGSHORT(p+1);
        !          1360:                        if(v<0 || v>=bit.nmap || (dst=bit.map[v])==0)
        !          1361:                                error(Ebadbitmap);
        !          1362:                        rect.min.x = BGLONG(p+3);
        !          1363:                        rect.min.y = BGLONG(p+7);
        !          1364:                        rect.max.x = BGLONG(p+11);
        !          1365:                        rect.max.y = BGLONG(p+15);
        !          1366:                        if(rectclip(&rect, dst->r))
        !          1367:                                dst->clipr = rect;
        !          1368:                        m -= 19;
        !          1369:                        p += 19;
        !          1370:                        break;
        !          1371: 
        !          1372:                case 'r':
        !          1373:                        /*
        !          1374:                         * read
        !          1375:                         *      'r'             1
        !          1376:                         *      src id          2
        !          1377:                         *      miny            4
        !          1378:                         *      maxy            4
        !          1379:                         */
        !          1380:                        if(m < 11)
        !          1381:                                error(Ebadblt);
        !          1382:                        v = BGSHORT(p+1);
        !          1383:                        if(v<0 || v>=bit.nmap || (src=bit.map[v])==0)
        !          1384:                                error(Ebadbitmap);
        !          1385:                        miny = BGLONG(p+3);
        !          1386:                        maxy = BGLONG(p+7);
        !          1387:                        if(miny>maxy || miny<src->r.min.y || maxy>src->r.max.y)
        !          1388:                                error(Ebadblt);
        !          1389:                        bit.rid = v;
        !          1390:                        bit.rminy = miny;
        !          1391:                        bit.rmaxy = maxy;
        !          1392:                        p += 11;
        !          1393:                        m -= 11;
        !          1394:                        break;
        !          1395: 
        !          1396:                case 's':
        !          1397:                        /*
        !          1398:                         * string
        !          1399:                         *      's'             1
        !          1400:                         *      id              2
        !          1401:                         *      pt              8
        !          1402:                         *      font id         2
        !          1403:                         *      code            2
        !          1404:                         *      n               2
        !          1405:                         *      cache indices   2*n (not null terminated)
        !          1406:                         */
        !          1407:                        if(m < 17)
        !          1408:                                error(Ebadblt);
        !          1409:                        v = BGSHORT(p+1);
        !          1410:                        if(v<0 || v>=bit.nmap || (dst=bit.map[v])==0)
        !          1411:                                error(Ebadbitmap);
        !          1412:                        off = 0;
        !          1413:                        fc = BGSHORT(p+13) & 0xF;
        !          1414:                        if(v == 0){
        !          1415:                                if(flipping)
        !          1416:                                        fc = flipD[fc];
        !          1417:                                off = 1;
        !          1418:                        }
        !          1419:                        pt.x = BGLONG(p+3);
        !          1420:                        pt.y = BGLONG(p+7);
        !          1421:                        v = BGSHORT(p+11);
        !          1422:                        if(v<0 || v>=bit.nfont || (ff=bit.font[v])==0)
        !          1423:                                error(Ebadfont);
        !          1424:                        l = BGSHORT(p+15)*2;
        !          1425:                        p += 17;
        !          1426:                        m -= 17;
        !          1427:                        if(l > m)
        !          1428:                                error(Ebadblt);
        !          1429:                        if(off && !isoff){
        !          1430:                                cursoroff(1);
        !          1431:                                isoff = 1;
        !          1432:                        }
        !          1433:                        bitstring(dst, pt, ff, p, l, fc);
        !          1434:                        if(dst->base < endscreen)
        !          1435:                                mbbrect(Rpt(pt, add(pt, bitstrsize(ff, p, l))));
        !          1436:                        m -= l;
        !          1437:                        p += l;
        !          1438:                        break;
        !          1439: 
        !          1440:                case 't':
        !          1441:                        /*
        !          1442:                         * texture
        !          1443:                         *      't'             1
        !          1444:                         *      dst id          2
        !          1445:                         *      rect            16
        !          1446:                         *      src id          2
        !          1447:                         *      fcode           2
        !          1448:                         */
        !          1449:                        if(m < 23)
        !          1450:                                error(Ebadblt);
        !          1451:                        v = BGSHORT(p+1);
        !          1452:                        if(v<0 || v>=bit.nmap || (dst=bit.map[v])==0)
        !          1453:                                error(Ebadbitmap);
        !          1454:                        off = 0;
        !          1455:                        fc = BGSHORT(p+21) & 0xF;
        !          1456:                        if(v == 0){
        !          1457:                                if(flipping)
        !          1458:                                        fc = flipD[fc];
        !          1459:                                off = 1;
        !          1460:                        }
        !          1461:                        rect.min.x = BGLONG(p+3);
        !          1462:                        rect.min.y = BGLONG(p+7);
        !          1463:                        rect.max.x = BGLONG(p+11);
        !          1464:                        rect.max.y = BGLONG(p+15);
        !          1465:                        v = BGSHORT(p+19);
        !          1466:                        if(v<0 || v>=bit.nmap || (src=bit.map[v])==0)
        !          1467:                                error(Ebadbitmap);
        !          1468:                        if(off && !isoff){
        !          1469:                                cursoroff(1);
        !          1470:                                isoff = 1;
        !          1471:                        }
        !          1472:                        gtexture(dst, rect, src, fc);
        !          1473:                        if(dst->base < endscreen)
        !          1474:                                mbbrect(rect);
        !          1475:                        m -= 23;
        !          1476:                        p += 23;
        !          1477:                        break;
        !          1478: 
        !          1479:                case 'v':
        !          1480:                        /*
        !          1481:                         * clear font cache and bitmap.
        !          1482:                         * if error, font is unchanged.
        !          1483:                         *      'v'             1
        !          1484:                         *      id              2
        !          1485:                         *      ncache          2
        !          1486:                         *      width           2
        !          1487:                         */
        !          1488:                        if(m < 7)
        !          1489:                                error(Ebadblt);
        !          1490:                        v = BGSHORT(p+1);
        !          1491:                        t = BGSHORT(p+3);
        !          1492:                        if(t<0 || v<0 || v>=bit.nfont || (ff=bit.font[v])==0)
        !          1493:                                error(Ebadblt);
        !          1494:                        x = BGSHORT(p+5);
        !          1495:                        i = bitalloc(Rect(0, 0, t*x, ff->height), ff->ldepth);
        !          1496:                        if(t != ff->ncache){
        !          1497:                                gc = bitmalloc(t*sizeof(ff->cache[0]));
        !          1498:                                if(gc == 0){
        !          1499:                                        bitfree(bit.map[i]);
        !          1500:                                        bit.map[i] = 0;
        !          1501:                                        error(Enomem);
        !          1502:                                }
        !          1503:                                free(ff->cache);
        !          1504:                                ff->cache = gc;
        !          1505:                                ff->ncache = t;
        !          1506:                        }else{
        !          1507:                                /*
        !          1508:                                 * memset not necessary but helps avoid
        !          1509:                                 * confusion if the cache is mishandled by the
        !          1510:                                 * user.
        !          1511:                                 */
        !          1512:                                memset(ff->cache, 0, t*sizeof(ff->cache[0]));
        !          1513:                        }
        !          1514:                        if(ff->b)
        !          1515:                                bitfree(ff->b);
        !          1516:                        ff->b = bit.map[i];
        !          1517:                        bit.map[i] = 0; /* disconnect it from GBitmap space */
        !          1518:                        ff->width = x;
        !          1519:                        p += 7;
        !          1520:                        m -= 7;
        !          1521:                        break;
        !          1522: 
        !          1523:                case 'w':
        !          1524:                        /*
        !          1525:                         * write
        !          1526:                         *      'w'             1
        !          1527:                         *      dst id          2
        !          1528:                         *      miny            4
        !          1529:                         *      maxy            4
        !          1530:                         *      data            bytewidth*(maxy-miny)
        !          1531:                         */
        !          1532:                        if(m < 11)
        !          1533:                                error(Ebadblt);
        !          1534:                        v = BGSHORT(p+1);
        !          1535:                        if(v<0 || v>=bit.nmap || (dst=bit.map[v])==0)
        !          1536:                                error(Ebadbitmap);
        !          1537:                        off = 0;
        !          1538:                        if(v == 0)
        !          1539:                                off = 1;
        !          1540:                        miny = BGLONG(p+3);
        !          1541:                        maxy = BGLONG(p+7);
        !          1542:                        if(miny>maxy || miny<dst->r.min.y || maxy>dst->r.max.y)
        !          1543:                                error(Ebadblt);
        !          1544:                        ws = 1<<(3-dst->ldepth);        /* pixels per byte */
        !          1545:                        /* set l to number of bytes of incoming data per scan line */
        !          1546:                        if(dst->r.min.x >= 0)
        !          1547:                                l = (dst->r.max.x+ws-1)/ws - dst->r.min.x/ws;
        !          1548:                        else{   /* make positive before divide */
        !          1549:                                t = (-dst->r.min.x)+ws-1;
        !          1550:                                t = (t/ws)*ws;
        !          1551:                                l = (t+dst->r.max.x+ws-1)/ws;
        !          1552:                        }
        !          1553:                        if(dst->base < endscreen)
        !          1554:                                mbbrect(Rect(dst->r.min.x, miny, dst->r.max.x, maxy));
        !          1555:                        p += 11;
        !          1556:                        m -= 11;
        !          1557:                        if(m < l*(maxy-miny))
        !          1558:                                error(Ebadblt);
        !          1559:                        if(off && !isoff){
        !          1560:                                cursoroff(1);
        !          1561:                                isoff = 1;
        !          1562:                        }
        !          1563:                        for(y=miny; y<maxy; y++){
        !          1564:                                oq = (uchar*)gaddr(dst, Pt(dst->r.min.x, y));
        !          1565:                                q = oq + (dst->r.min.x&((sizeof(ulong))*ws-1))/ws;
        !          1566:                                memmove(q, p, l);
        !          1567:                                if(islittle)
        !          1568:                                        pixreverse(q, l, dst->ldepth);
        !          1569:                                if(v==0 && flipping){   /* flip bits */
        !          1570:                                        /* we know it's all word aligned */
        !          1571:                                        lp = (ulong*)oq;
        !          1572:                                        for(x=0; x<l; x+=sizeof(ulong))
        !          1573:                                                *lp++ ^= ~0;
        !          1574:                                }
        !          1575:                                p += l;
        !          1576:                                m -= l;
        !          1577:                        }
        !          1578:                        if(v == 0)
        !          1579:                                hwscreenwrite(miny, maxy);
        !          1580:                        break;
        !          1581: 
        !          1582:                case 'x':
        !          1583:                        /*
        !          1584:                         * cursorset
        !          1585:                         *
        !          1586:                         *      'x'             1
        !          1587:                         *      pt              8
        !          1588:                         */
        !          1589:                        if(m < 9)
        !          1590:                                error(Ebadblt);
        !          1591:                        pt1.x = BGLONG(p+1);
        !          1592:                        pt1.y = BGLONG(p+5);
        !          1593:                        if(ptinrect(pt1, gscreen.r)){
        !          1594:                                mouse.xy = pt1;
        !          1595:                                mouse.redraw = 1;
        !          1596:                                mouse.track = 1;
        !          1597:                                mouseclock();
        !          1598:                        }
        !          1599:                        m -= 9;
        !          1600:                        p += 9;
        !          1601:                        break;
        !          1602: 
        !          1603:                case 'y':
        !          1604:                        /*
        !          1605:                         * load font from subfont
        !          1606:                         *      'y'             1
        !          1607:                         *      id              2
        !          1608:                         *      cache index     2
        !          1609:                         *      subfont id      2
        !          1610:                         *      subfont index   2
        !          1611:                         */
        !          1612:                        if(m < 9)
        !          1613:                                error(Ebadblt);
        !          1614:                        v = BGSHORT(p+1);
        !          1615:                        if(v<0 || v>=bit.nfont || (ff=bit.font[v])==0)
        !          1616:                                error(Ebadblt);
        !          1617:                        if(ff->b == 0)
        !          1618:                                error(Ebadbitmap);
        !          1619:                        l = BGSHORT(p+3);
        !          1620:                        if(l >= ff->ncache)
        !          1621:                                error(Ebadblt);
        !          1622:                        v = BGSHORT(p+5);
        !          1623:                        if(v<0 || v>=bit.nsubfont || (f=bit.subfont[v])==0 || f->ref==0)
        !          1624:                                error(Ebadfont);
        !          1625:                        nw = BGSHORT(p+7);
        !          1626:                        if(nw >= f->n)
        !          1627:                                error(Ebadblt);
        !          1628:                        bitloadchar(ff, l, f, nw);
        !          1629:                        p += 9;
        !          1630:                        m -= 9;
        !          1631:                        break;
        !          1632: 
        !          1633:                case 'z':
        !          1634:                        /*
        !          1635:                         * write the colormap
        !          1636:                         *
        !          1637:                         *      'z'             1
        !          1638:                         *      id              2
        !          1639:                         *      map             12*(2**bitmapdepth)
        !          1640:                         */
        !          1641:                        if(m < 3)
        !          1642:                                error(Ebadblt);
        !          1643:                        v = BGSHORT(p+1);
        !          1644:                        if(v != 0)
        !          1645:                                error(Ebadbitmap);
        !          1646:                        m -= 3;
        !          1647:                        p += 3;
        !          1648:                        nw = 1 << (1 << gscreen.ldepth);
        !          1649:                        if(m < 12*nw)
        !          1650:                                error(Ebadblt);
        !          1651:                        ok = 1;
        !          1652:                        for(i = 0; i < nw; i++){
        !          1653:                                ok &= setcolor(flipping ? ~i : i, BGLONG(p), BGLONG(p+4), BGLONG(p+8));
        !          1654:                                p += 12;
        !          1655:                                m -= 12;
        !          1656:                        }
        !          1657:                        if(!ok){
        !          1658:                                /* assume monochrome: possibly change flipping */
        !          1659:                                l = BGLONG(p-12);
        !          1660:                                getcolor(nw-1, &rv, &rv, &rv);
        !          1661:                                flipping = (l != rv);
        !          1662:                        }
        !          1663:                        break;
        !          1664:                }
        !          1665: 
        !          1666:        poperror();
        !          1667:        if(isoff)
        !          1668:                cursoron(1);
        !          1669:        screenupdate();
        !          1670:        qunlock(&bit);
        !          1671:        return n;
        !          1672: }
        !          1673: 
        !          1674: int
        !          1675: bitalloc(Rectangle rect, int ld)
        !          1676: {
        !          1677:        Arena *a, *ea, *aa;
        !          1678:        GBitmap *b, **bp, **ep;
        !          1679:        ulong l, ws, nw;
        !          1680:        long t;
        !          1681: 
        !          1682:        ws = BI2WD>>ld; /* pixels per word */
        !          1683:        if(rect.min.x >= 0){
        !          1684:                l = (rect.max.x+ws-1)/ws;
        !          1685:                l -= rect.min.x/ws;
        !          1686:        }else{  /* make positive before divide */
        !          1687:                t = (-rect.min.x)+ws-1;
        !          1688:                t = (t/ws)*ws;
        !          1689:                l = (t+rect.max.x+ws-1)/ws;
        !          1690:        }
        !          1691:        nw = l*Dy(rect);
        !          1692:        ea = &bit.arena[bit.narena];
        !          1693: 
        !          1694:        /* first try easy fit */
        !          1695:        for(a=bit.arena; a<ea; a++){
        !          1696:                if(a->words == 0)
        !          1697:                        continue;
        !          1698:                if(a->wfree+HDR+nw <= a->words+a->nwords)
        !          1699:                        goto found;
        !          1700:        }
        !          1701: 
        !          1702:        /* compact and try again */
        !          1703:        bitcompact();
        !          1704:        aa = 0;
        !          1705:        for(a=bit.arena; a<ea; a++){
        !          1706:                if(a->words == 0){
        !          1707:                        if(aa == 0)
        !          1708:                                aa = a;
        !          1709:                        continue;
        !          1710:                }
        !          1711:                if(a->wfree+HDR+nw <= a->words+a->nwords)
        !          1712:                        goto found;
        !          1713:        }
        !          1714: 
        !          1715:        /* need new arena */
        !          1716:        if(aa){
        !          1717:                a = aa;
        !          1718:                a->nwords = HDR + (gscreen.r.max.y*gscreen.r.max.x)/ws;
        !          1719:                if(a->nwords < HDR+nw)
        !          1720:                        a->nwords = HDR+nw;
        !          1721:                a->words = xalloc(a->nwords*sizeof(ulong));
        !          1722:                if(a->words){
        !          1723:                        a->wfree = a->words;
        !          1724:                        a->nbusy = 0;
        !          1725:                        goto found;
        !          1726:                }
        !          1727:        }
        !          1728:        /* else can't grow list: bitmaps have backpointers */
        !          1729: 
        !          1730:        bitfreeup();
        !          1731: 
        !          1732:        for(a=bit.arena; a<ea; a++){
        !          1733:                if(a->words == 0)
        !          1734:                        continue;
        !          1735:                if(a->wfree+HDR+nw <= a->words+a->nwords)
        !          1736:                        goto found;
        !          1737:        }
        !          1738:        if(a == ea)
        !          1739:                error(Enobitstore);
        !          1740:        
        !          1741:     found:
        !          1742:        b = bitmalloc(sizeof(GBitmap));
        !          1743:        if(b == 0)
        !          1744:                error(Enomem);
        !          1745:        *a->wfree++ = nw;
        !          1746:        *a->wfree++ = (ulong)a;
        !          1747:        *a->wfree++ = (ulong)b;
        !          1748:        memset(a->wfree, 0, nw*sizeof(ulong));
        !          1749:        b->base = a->wfree;
        !          1750:        a->wfree += nw;
        !          1751:        a->nbusy++;
        !          1752:        b->zero = l*rect.min.y;
        !          1753:        if(rect.min.x >= 0)
        !          1754:                b->zero += rect.min.x/ws;
        !          1755:        else
        !          1756:                b->zero -= (-rect.min.x+ws-1)/ws;
        !          1757:        b->zero = -b->zero;
        !          1758:        b->width = l;
        !          1759:        b->ldepth = ld;
        !          1760:        b->r = rect;
        !          1761:        b->clipr = rect;
        !          1762:        b->cache = 0;
        !          1763:        /* worth doing better than linear lookup? */
        !          1764:        ep = bit.map+bit.nmap;
        !          1765:        for(bp=bit.map; bp<ep; bp++)
        !          1766:                if(*bp == 0)
        !          1767:                        break;
        !          1768:        if(bp == ep){
        !          1769:                bp = bitmalloc((bit.nmap+DMAP)*sizeof(GBitmap*));
        !          1770:                if(bp == 0){
        !          1771:                        bitfree(b);
        !          1772:                        error(Enomem);
        !          1773:                }
        !          1774:                memmove(bp, bit.map, bit.nmap*sizeof(GBitmap*));
        !          1775:                free(bit.map);
        !          1776:                bit.map = bp;
        !          1777:                bp += bit.nmap;
        !          1778:                bit.nmap += DMAP;
        !          1779:        }
        !          1780:        *bp = b;
        !          1781:        return bp-bit.map;
        !          1782: }
        !          1783: 
        !          1784: void
        !          1785: bitfree(GBitmap *b)
        !          1786: {
        !          1787:        Arena *a;
        !          1788: 
        !          1789:        if(b->base != gscreen.base){    /* can't free screen memory */
        !          1790:                a = (Arena*)(b->base[-2]);
        !          1791:                a->nbusy--;
        !          1792:                if(a->nbusy == 0)
        !          1793:                        arenafree(a);
        !          1794:                b->base[-1] = 0;
        !          1795:        }
        !          1796:        free(b);
        !          1797: }
        !          1798: 
        !          1799: void
        !          1800: fontfree(GFont *f)
        !          1801: {
        !          1802:        if(f->b)
        !          1803:                bitfree(f->b);
        !          1804:        free(f->cache);
        !          1805:        free(f);
        !          1806: }
        !          1807: 
        !          1808: void
        !          1809: subfontfree(BSubfont *s, int i)
        !          1810: {
        !          1811:        if(s!=bdefont && s->ref>0){     /* don't free subfont 0, bdefont */
        !          1812:                s->ref--;
        !          1813:                if(s->ref==0 && s->qid[0]==~0){ /* uncached */
        !          1814:                        bitfree(s->bits);
        !          1815:                        free(s->info);
        !          1816:                        free(s);
        !          1817:                        bit.subfont[i] = 0;
        !          1818:                }
        !          1819:        }
        !          1820:        return;
        !          1821: }
        !          1822: 
        !          1823: void
        !          1824: arenafree(Arena *a)
        !          1825: {
        !          1826:        xfree(a->words);
        !          1827:        a->words = 0;
        !          1828: }
        !          1829: 
        !          1830: void
        !          1831: bitstring(GBitmap *bp, Point pt, GFont *f, uchar *p, long l, Fcode fc)
        !          1832: {
        !          1833:        int full;
        !          1834:        Rectangle rect;
        !          1835:        ushort r;
        !          1836:        GCacheinfo *c;
        !          1837:        int x;
        !          1838:        Fcode clr;
        !          1839: 
        !          1840:        clr = 0;
        !          1841:        full = (fc&~S)^(D&~S);  /* result involves source */
        !          1842:        if(full){
        !          1843:                rect.min.y = 0;
        !          1844:                rect.max.y = f->height;
        !          1845:                /* set clr to result under fc if source pixel is zero */
        !          1846:                /* hard to do without knowing layout of bits, so we cheat */
        !          1847:                clr = (fc&3);   /* fc&3 is result if source is zero */
        !          1848:                clr |= clr<<2;  /* fc&(3<<2) is result if source is one */
        !          1849:        }
        !          1850: 
        !          1851:        while(l > 0){
        !          1852:                r = BGSHORT(p);
        !          1853:                p += 2;
        !          1854:                l -= 2;
        !          1855:                if(r >= f->ncache)
        !          1856:                        continue;
        !          1857:                c = &f->cache[r];
        !          1858:                if(!full){
        !          1859:                        rect.min.y = c->top;
        !          1860:                        rect.max.y = c->bottom;
        !          1861:                }else{
        !          1862:                        if(c->left > 0)
        !          1863:                                gbitblt(bp, pt, bp,
        !          1864:                                        Rect(pt.x, pt.y, pt.x+c->left, pt.y+f->height),
        !          1865:                                        clr);
        !          1866:                        x = c->left+(c->xright-c->x);
        !          1867:                        if(x < c->width)
        !          1868:                                gbitblt(bp, Pt(pt.x+x, pt.y), bp,
        !          1869:                                        Rect(pt.x+x, pt.y, pt.x+c->width, pt.y+f->height),
        !          1870:                                        clr);
        !          1871:                }
        !          1872:                rect.min.x = c->x;
        !          1873:                rect.max.x = c->xright;
        !          1874:                gbitblt(bp, Pt(pt.x+c->left, pt.y+rect.min.y), f->b, rect, fc);
        !          1875:                pt.x += c->width;
        !          1876:        }
        !          1877: }
        !          1878: 
        !          1879: void
        !          1880: bitloadchar(GFont *f, int ci, GSubfont *subf, int si)
        !          1881: {
        !          1882:        GCacheinfo *c;
        !          1883:        Rectangle rect;
        !          1884:        Fontchar *fi;
        !          1885:        int y;
        !          1886: 
        !          1887:        c = &f->cache[ci];
        !          1888:        fi = &subf->info[si];
        !          1889:        /* careful about sign extension: top and bottom are uchars */
        !          1890:        y = fi->top + (f->ascent-subf->ascent);
        !          1891:        if(y < 0)
        !          1892:                y = 0;
        !          1893:        c->top = y;
        !          1894:        y = fi->bottom + (f->ascent-subf->ascent);
        !          1895:        if(y < 0)
        !          1896:                y = 0;
        !          1897:        c->bottom = y;
        !          1898:        c->width = fi->width;
        !          1899:        c->left = fi->left;
        !          1900:        c->x = ci*f->width;
        !          1901:        c->xright = c->x + ((fi+1)->x - fi->x);
        !          1902:        rect.min.y = 0;
        !          1903:        rect.max.y = f->height;
        !          1904:        rect.min.x = c->x;
        !          1905:        rect.max.x = c->x+f->width;
        !          1906:        gbitblt(f->b, rect.min, f->b, rect, 0);
        !          1907:        rect.min.x = fi->x;
        !          1908:        rect.max.x = (fi+1)->x;
        !          1909:        rect.max.y = subf->height;
        !          1910:        gbitblt(f->b, Pt(c->x, f->ascent-subf->ascent), subf->bits, rect, S);
        !          1911: }
        !          1912: 
        !          1913: QLock  bitlock;
        !          1914: 
        !          1915: GBitmap*
        !          1916: id2bit(int v)
        !          1917: {
        !          1918:        GBitmap *bp=0;
        !          1919: 
        !          1920:        if(v<0 || v>=bit.nmap || (bp=bit.map[v])==0)
        !          1921:                error(Ebadbitmap);
        !          1922:        return bp;
        !          1923: }
        !          1924: 
        !          1925: void
        !          1926: bitcompact(void)
        !          1927: {
        !          1928:        Arena *a, *ea, *na;
        !          1929:        ulong *p1, *p2, n;
        !          1930: 
        !          1931:        qlock(&bitlock);
        !          1932:        ea = &bit.arena[bit.narena];
        !          1933:        for(a=bit.arena; a<ea; a++){
        !          1934:                if(a->words == 0)
        !          1935:                        continue;
        !          1936:                /* first compact what's here */
        !          1937:                p1 = p2 = a->words;
        !          1938:                while(p2 < a->wfree){
        !          1939:                        n = HDR+p2[0];
        !          1940:                        if(p2[2] == 0){
        !          1941:                                p2 += n;
        !          1942:                                continue;
        !          1943:                        }
        !          1944:                        if(p1 != p2){
        !          1945:                                memmove(p1, p2, n*sizeof(ulong));
        !          1946:                                ((GBitmap*)p1[2])->base = p1+HDR;
        !          1947:                        }
        !          1948:                        p2 += n;
        !          1949:                        p1 += n;
        !          1950:                }
        !          1951:                /* now pull stuff from later arena to fill this one */
        !          1952:                na = a+1;
        !          1953:                while(na<ea && p1<a->words+a->nwords){
        !          1954:                        p2 = na->words;
        !          1955:                        if(p2 == 0){
        !          1956:                                na++;
        !          1957:                                continue;
        !          1958:                        }
        !          1959:                        while(p2 < na->wfree){
        !          1960:                                n = HDR+p2[0];
        !          1961:                                if(p2[2] == 0){
        !          1962:                                        p2 += n;
        !          1963:                                        continue;
        !          1964:                                }
        !          1965:                                if(p1+n < a->words+a->nwords){
        !          1966:                                        memmove(p1, p2, n*sizeof(ulong));
        !          1967:                                        ((GBitmap*)p1[2])->base = p1+HDR;
        !          1968:                                        /* block now in new arena... */
        !          1969:                                        p1[1] = (ulong)a;
        !          1970:                                        a->nbusy++;
        !          1971:                                        /* ... not in old arena */
        !          1972:                                        na->nbusy--;
        !          1973:                                        p2[2] = 0;
        !          1974:                                        p1 += n;
        !          1975:                                }
        !          1976:                                p2 += n;
        !          1977:                        }
        !          1978:                        na++;
        !          1979:                }
        !          1980:                a->wfree = p1;
        !          1981:        }
        !          1982:        for(a=bit.arena; a<ea; a++)
        !          1983:                if(a->words && a->nbusy==0)
        !          1984:                        arenafree(a);
        !          1985:        qunlock(&bitlock);
        !          1986: }
        !          1987: 
        !          1988: void
        !          1989: Cursortocursor(Cursor *c)
        !          1990: {
        !          1991:        lock(&cursor);
        !          1992:        memmove(&cursor, c, sizeof(Cursor));
        !          1993:        setcursor(c);
        !          1994:        unlock(&cursor);
        !          1995: }
        !          1996: 
        !          1997: int
        !          1998: cursoron(int dolock)
        !          1999: {
        !          2000:        int ret;
        !          2001: 
        !          2002:        if(dolock)
        !          2003:                lock(&cursor);
        !          2004:        ret = 0;
        !          2005:        if(hwcurs)
        !          2006:                ret = hwgcmove(mouse.xy);
        !          2007:        else if(cursor.visible++ == 0){
        !          2008:                cursor.r.min = mouse.xy;
        !          2009:                cursor.r.max = add(mouse.xy, Pt(16, 16));
        !          2010:                cursor.r = raddp(cursor.r, cursor.offset);
        !          2011:                gbitblt(&cursorback, Pt(0, 0), &gscreen, cursor.r, S);
        !          2012:                gbitblt(&gscreen, cursor.r.min,
        !          2013:                        &clr, Rect(0, 0, 16, 16), flipping? flipD[D&~S] : D&~S);
        !          2014:                gbitblt(&gscreen, cursor.r.min,
        !          2015:                        &set, Rect(0, 0, 16, 16), flipping? flipD[S|D] : S|D);
        !          2016:                mbbrect(cursor.r);
        !          2017:        }
        !          2018:        if(dolock)
        !          2019:                unlock(&cursor);
        !          2020: 
        !          2021:        return ret;
        !          2022: }
        !          2023: 
        !          2024: void
        !          2025: cursoroff(int dolock)
        !          2026: {
        !          2027:        if(hwcurs)
        !          2028:                return;
        !          2029:        if(dolock)
        !          2030:                lock(&cursor);
        !          2031:        if(--cursor.visible == 0) {
        !          2032:                gbitblt(&gscreen, cursor.r.min, &cursorback, Rect(0, 0, 16, 16), S);
        !          2033:                mbbrect(cursor.r);
        !          2034:                mousescreenupdate();
        !          2035:        }
        !          2036:        if(dolock)
        !          2037:                unlock(&cursor);
        !          2038: }
        !          2039: 
        !          2040: /*
        !          2041:  *  called by the clock routine to redraw the cursor
        !          2042:  */
        !          2043: void
        !          2044: mouseclock(void)
        !          2045: {
        !          2046:        if(mouse.track){
        !          2047:                mousetrack(mouse.buttons, mouse.dx, mouse.dy);
        !          2048:                mouse.track = 0;
        !          2049:                mouse.dx = 0;
        !          2050:                mouse.dy = 0;
        !          2051:        }
        !          2052:        if(mouse.redraw && canlock(&cursor)){
        !          2053:                mouse.redraw = 0;
        !          2054:                cursoroff(0);
        !          2055:                mouse.redraw = cursoron(0);
        !          2056:                mousescreenupdate();
        !          2057:                unlock(&cursor);
        !          2058:        }
        !          2059: }
        !          2060: 
        !          2061: /*
        !          2062:  *  called at interrupt level to update the structure and
        !          2063:  *  awaken any waiting procs.
        !          2064:  */
        !          2065: void
        !          2066: mousetrack(int b, int dx, int dy)
        !          2067: {
        !          2068:        int x, y;
        !          2069: 
        !          2070:        x = mouse.xy.x + dx;
        !          2071:        if(x < gscreen.r.min.x)
        !          2072:                x = gscreen.r.min.x;
        !          2073:        if(x >= gscreen.r.max.x)
        !          2074:                x = gscreen.r.max.x;
        !          2075:        y = mouse.xy.y + dy;
        !          2076:        if(y < gscreen.r.min.y)
        !          2077:                y = gscreen.r.min.y;
        !          2078:        if(y >= gscreen.r.max.y)
        !          2079:                y = gscreen.r.max.y;
        !          2080:        mouse.counter++;
        !          2081:        mouse.xy = Pt(x, y);
        !          2082:        mouse.buttons = b;
        !          2083:        mouse.redraw = 1;
        !          2084:        wakeup(&mouse.r);
        !          2085: }
        !          2086: 
        !          2087: /*
        !          2088:  *  microsoft 3 button, 7 bit bytes
        !          2089:  *
        !          2090:  *     byte 0 -        1  L  R Y7 Y6 X7 X6
        !          2091:  *     byte 1 -        0 X5 X4 X3 X2 X1 X0
        !          2092:  *     byte 2 -        0 Y5 Y4 Y3 Y2 Y1 Y0
        !          2093:  *     byte 3 -        0  M  x  x  x  x  x     (optional)
        !          2094:  *
        !          2095:  *  shift & right button is the same as middle button (for 2 button mice)
        !          2096:  */
        !          2097: int
        !          2098: m3mouseputc(IOQ *q, int c)
        !          2099: {
        !          2100:        static uchar msg[3];
        !          2101:        static int nb;
        !          2102:        static int middle;
        !          2103:        static uchar b[] = { 0, 4, 1, 5, 0, 2, 1, 5 };
        !          2104:        short x;
        !          2105:        int dx, dy, newbuttons;
        !          2106: 
        !          2107:        USED(q);
        !          2108:        /* 
        !          2109:         *  check bit 6 for consistency
        !          2110:         */
        !          2111:        if(nb==0){
        !          2112:                if((c&0x40) == 0){
        !          2113:                        /* an extra byte gets sent for the middle button */
        !          2114:                        middle = (c&0x20) ? 2 : 0;
        !          2115:                        newbuttons = (mouse.buttons & ~2) | middle;
        !          2116:                        mousetrack(newbuttons, 0, 0);
        !          2117:                        return 0;
        !          2118:                }
        !          2119:        }
        !          2120:        msg[nb] = c;
        !          2121:        if(++nb == 3){
        !          2122:                nb = 0;
        !          2123:                newbuttons = middle | b[(msg[0]>>4)&3 | (mouseshifted ? 4 : 0)];
        !          2124:                x = (msg[0]&0x3)<<14;
        !          2125:                dx = (x>>8) | msg[1];
        !          2126:                x = (msg[0]&0xc)<<12;
        !          2127:                dy = (x>>8) | msg[2];
        !          2128:                mousetrack(newbuttons, dx, dy);
        !          2129:        }
        !          2130:        return 0;
        !          2131: }
        !          2132: 
        !          2133: /*
        !          2134:  *  Logitech 5 byte packed binary mouse format, 8 bit bytes
        !          2135:  *
        !          2136:  *  shift & right button is the same as middle button (for 2 button mice)
        !          2137:  */
        !          2138: int
        !          2139: mouseputc(IOQ *q, int c)
        !          2140: {
        !          2141:        static short msg[5];
        !          2142:        static int nb;
        !          2143:        static uchar b[] = {0, 4, 2, 6, 1, 5, 3, 7, 0, 2, 2, 6, 1, 5, 3, 7};
        !          2144:        int dx, dy, newbuttons;
        !          2145: 
        !          2146:        USED(q);
        !          2147:        if((c&0xF0) == 0x80)
        !          2148:                nb=0;
        !          2149:        msg[nb] = c;
        !          2150:        if(c & 0x80)
        !          2151:                msg[nb] |= ~0xFF;       /* sign extend */
        !          2152:        if(++nb == 5){
        !          2153:                newbuttons = b[((msg[0]&7)^7) | (mouseshifted ? 8 : 0)];
        !          2154:                dx = msg[1]+msg[3];
        !          2155:                dy = -(msg[2]+msg[4]);
        !          2156:                mousetrack(newbuttons, dx, dy);
        !          2157:                nb = 0;
        !          2158:        }
        !          2159:        return 0;
        !          2160: }
        !          2161: 
        !          2162: int
        !          2163: mousechanged(void *m)
        !          2164: {
        !          2165:        USED(m);
        !          2166:        return mouse.lastcounter != mouse.counter;
        !          2167: }
        !          2168: 
        !          2169: /*
        !          2170:  *  reverse pixels into little endian order
        !          2171:  */
        !          2172: uchar revtab0[] = {
        !          2173:  0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
        !          2174:  0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
        !          2175:  0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
        !          2176:  0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
        !          2177:  0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
        !          2178:  0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
        !          2179:  0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
        !          2180:  0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
        !          2181:  0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
        !          2182:  0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
        !          2183:  0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
        !          2184:  0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
        !          2185:  0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
        !          2186:  0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
        !          2187:  0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
        !          2188:  0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
        !          2189:  0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
        !          2190:  0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
        !          2191:  0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
        !          2192:  0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
        !          2193:  0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
        !          2194:  0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
        !          2195:  0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
        !          2196:  0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
        !          2197:  0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
        !          2198:  0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
        !          2199:  0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
        !          2200:  0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
        !          2201:  0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
        !          2202:  0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
        !          2203:  0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
        !          2204:  0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff,
        !          2205: };
        !          2206: uchar revtab1[] = {
        !          2207:  0x00, 0x40, 0x80, 0xc0, 0x10, 0x50, 0x90, 0xd0,
        !          2208:  0x20, 0x60, 0xa0, 0xe0, 0x30, 0x70, 0xb0, 0xf0,
        !          2209:  0x04, 0x44, 0x84, 0xc4, 0x14, 0x54, 0x94, 0xd4,
        !          2210:  0x24, 0x64, 0xa4, 0xe4, 0x34, 0x74, 0xb4, 0xf4,
        !          2211:  0x08, 0x48, 0x88, 0xc8, 0x18, 0x58, 0x98, 0xd8,
        !          2212:  0x28, 0x68, 0xa8, 0xe8, 0x38, 0x78, 0xb8, 0xf8,
        !          2213:  0x0c, 0x4c, 0x8c, 0xcc, 0x1c, 0x5c, 0x9c, 0xdc,
        !          2214:  0x2c, 0x6c, 0xac, 0xec, 0x3c, 0x7c, 0xbc, 0xfc,
        !          2215:  0x01, 0x41, 0x81, 0xc1, 0x11, 0x51, 0x91, 0xd1,
        !          2216:  0x21, 0x61, 0xa1, 0xe1, 0x31, 0x71, 0xb1, 0xf1,
        !          2217:  0x05, 0x45, 0x85, 0xc5, 0x15, 0x55, 0x95, 0xd5,
        !          2218:  0x25, 0x65, 0xa5, 0xe5, 0x35, 0x75, 0xb5, 0xf5,
        !          2219:  0x09, 0x49, 0x89, 0xc9, 0x19, 0x59, 0x99, 0xd9,
        !          2220:  0x29, 0x69, 0xa9, 0xe9, 0x39, 0x79, 0xb9, 0xf9,
        !          2221:  0x0d, 0x4d, 0x8d, 0xcd, 0x1d, 0x5d, 0x9d, 0xdd,
        !          2222:  0x2d, 0x6d, 0xad, 0xed, 0x3d, 0x7d, 0xbd, 0xfd,
        !          2223:  0x02, 0x42, 0x82, 0xc2, 0x12, 0x52, 0x92, 0xd2,
        !          2224:  0x22, 0x62, 0xa2, 0xe2, 0x32, 0x72, 0xb2, 0xf2,
        !          2225:  0x06, 0x46, 0x86, 0xc6, 0x16, 0x56, 0x96, 0xd6,
        !          2226:  0x26, 0x66, 0xa6, 0xe6, 0x36, 0x76, 0xb6, 0xf6,
        !          2227:  0x0a, 0x4a, 0x8a, 0xca, 0x1a, 0x5a, 0x9a, 0xda,
        !          2228:  0x2a, 0x6a, 0xaa, 0xea, 0x3a, 0x7a, 0xba, 0xfa,
        !          2229:  0x0e, 0x4e, 0x8e, 0xce, 0x1e, 0x5e, 0x9e, 0xde,
        !          2230:  0x2e, 0x6e, 0xae, 0xee, 0x3e, 0x7e, 0xbe, 0xfe,
        !          2231:  0x03, 0x43, 0x83, 0xc3, 0x13, 0x53, 0x93, 0xd3,
        !          2232:  0x23, 0x63, 0xa3, 0xe3, 0x33, 0x73, 0xb3, 0xf3,
        !          2233:  0x07, 0x47, 0x87, 0xc7, 0x17, 0x57, 0x97, 0xd7,
        !          2234:  0x27, 0x67, 0xa7, 0xe7, 0x37, 0x77, 0xb7, 0xf7,
        !          2235:  0x0b, 0x4b, 0x8b, 0xcb, 0x1b, 0x5b, 0x9b, 0xdb,
        !          2236:  0x2b, 0x6b, 0xab, 0xeb, 0x3b, 0x7b, 0xbb, 0xfb,
        !          2237:  0x0f, 0x4f, 0x8f, 0xcf, 0x1f, 0x5f, 0x9f, 0xdf,
        !          2238:  0x2f, 0x6f, 0xaf, 0xef, 0x3f, 0x7f, 0xbf, 0xff,
        !          2239: };
        !          2240: uchar revtab2[] = {
        !          2241:  0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70,
        !          2242:  0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0,
        !          2243:  0x01, 0x11, 0x21, 0x31, 0x41, 0x51, 0x61, 0x71,
        !          2244:  0x81, 0x91, 0xa1, 0xb1, 0xc1, 0xd1, 0xe1, 0xf1,
        !          2245:  0x02, 0x12, 0x22, 0x32, 0x42, 0x52, 0x62, 0x72,
        !          2246:  0x82, 0x92, 0xa2, 0xb2, 0xc2, 0xd2, 0xe2, 0xf2,
        !          2247:  0x03, 0x13, 0x23, 0x33, 0x43, 0x53, 0x63, 0x73,
        !          2248:  0x83, 0x93, 0xa3, 0xb3, 0xc3, 0xd3, 0xe3, 0xf3,
        !          2249:  0x04, 0x14, 0x24, 0x34, 0x44, 0x54, 0x64, 0x74,
        !          2250:  0x84, 0x94, 0xa4, 0xb4, 0xc4, 0xd4, 0xe4, 0xf4,
        !          2251:  0x05, 0x15, 0x25, 0x35, 0x45, 0x55, 0x65, 0x75,
        !          2252:  0x85, 0x95, 0xa5, 0xb5, 0xc5, 0xd5, 0xe5, 0xf5,
        !          2253:  0x06, 0x16, 0x26, 0x36, 0x46, 0x56, 0x66, 0x76,
        !          2254:  0x86, 0x96, 0xa6, 0xb6, 0xc6, 0xd6, 0xe6, 0xf6,
        !          2255:  0x07, 0x17, 0x27, 0x37, 0x47, 0x57, 0x67, 0x77,
        !          2256:  0x87, 0x97, 0xa7, 0xb7, 0xc7, 0xd7, 0xe7, 0xf7,
        !          2257:  0x08, 0x18, 0x28, 0x38, 0x48, 0x58, 0x68, 0x78,
        !          2258:  0x88, 0x98, 0xa8, 0xb8, 0xc8, 0xd8, 0xe8, 0xf8,
        !          2259:  0x09, 0x19, 0x29, 0x39, 0x49, 0x59, 0x69, 0x79,
        !          2260:  0x89, 0x99, 0xa9, 0xb9, 0xc9, 0xd9, 0xe9, 0xf9,
        !          2261:  0x0a, 0x1a, 0x2a, 0x3a, 0x4a, 0x5a, 0x6a, 0x7a,
        !          2262:  0x8a, 0x9a, 0xaa, 0xba, 0xca, 0xda, 0xea, 0xfa,
        !          2263:  0x0b, 0x1b, 0x2b, 0x3b, 0x4b, 0x5b, 0x6b, 0x7b,
        !          2264:  0x8b, 0x9b, 0xab, 0xbb, 0xcb, 0xdb, 0xeb, 0xfb,
        !          2265:  0x0c, 0x1c, 0x2c, 0x3c, 0x4c, 0x5c, 0x6c, 0x7c,
        !          2266:  0x8c, 0x9c, 0xac, 0xbc, 0xcc, 0xdc, 0xec, 0xfc,
        !          2267:  0x0d, 0x1d, 0x2d, 0x3d, 0x4d, 0x5d, 0x6d, 0x7d,
        !          2268:  0x8d, 0x9d, 0xad, 0xbd, 0xcd, 0xdd, 0xed, 0xfd,
        !          2269:  0x0e, 0x1e, 0x2e, 0x3e, 0x4e, 0x5e, 0x6e, 0x7e,
        !          2270:  0x8e, 0x9e, 0xae, 0xbe, 0xce, 0xde, 0xee, 0xfe,
        !          2271:  0x0f, 0x1f, 0x2f, 0x3f, 0x4f, 0x5f, 0x6f, 0x7f,
        !          2272:  0x8f, 0x9f, 0xaf, 0xbf, 0xcf, 0xdf, 0xef, 0xff,
        !          2273: };
        !          2274: 
        !          2275: void
        !          2276: pixreverse(uchar *p, int len, int ldepth)
        !          2277: {
        !          2278:        uchar *e;
        !          2279:        uchar *tab;
        !          2280: 
        !          2281:        switch(ldepth){
        !          2282:        case 0:
        !          2283:                tab = revtab0;
        !          2284:                break;
        !          2285:        case 1:
        !          2286:                tab = revtab1;
        !          2287:                break;
        !          2288:        case 2:
        !          2289:                tab = revtab2;
        !          2290:                break;
        !          2291:        default:
        !          2292:                return;
        !          2293:        }
        !          2294: 
        !          2295:        for(e = p + len; p < e; p++)
        !          2296:                *p = tab[*p];
        !          2297: }

unix.superglobalmegacorp.com

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