Annotation of os2sdk/demos/apps/life/life.c, revision 1.1

1.1     ! root        1: /***
        !             2:  *  Title:
        !             3:  *
        !             4:  *     LIFE - An OS/2 Game of Life
        !             5:  *
        !             6:  *
        !             7:  *  Author:
        !             8:  *
        !             9:  *     Brian J. Smith
        !            10:  *     (c) Microsoft Corporation
        !            11:  *     1987
        !            12:  *
        !            13:  *
        !            14:  *  Description:
        !            15:  *
        !            16:  *     This is a OS/2 implementation of the game of Life.  It is designed
        !            17:  *     to be bound to allow it to operate in both the protect mode of OS/2
        !            18:  *     and in earlier MS-DOS versions.  The program uses a mouse if one
        !            19:  *     is installed, but one is not needed.
        !            20:  *
        !            21:  *     Keyboard commands:   B(lank) - redraw screen
        !            22:  *                          G(o)    - step through generations until a key or
        !            23:  *                                    button is hit
        !            24:  *                          H(alt)  - freeze at current generation
        !            25:  *                          Q(uit)  - exit program
        !            26:  *                          R(ead)  - read a game board from the disk
        !            27:  *                          S(step) - advance a single generation
        !            28:  *                          W(rite) - write the current board to disk
        !            29:  *                          D(own-speed) - slow down GOs
        !            30:  *                          U(p-speed) - speed up GOs
        !            31:  *
        !            32:  */
        !            33: 
        !            34: 
        !            35: #include <doscalls.h>                  /* definitions for DOS calls and */
        !            36: #include <subcalls.h>                  /*    associated data structures */
        !            37: 
        !            38: /* defines */
        !            39: #define SCR_WID 80                     /* screen buffer row width in bytes */
        !            40: #define SIGNATURE 0x5342               /* 1st word of all files from this */
        !            41: 
        !            42: /* these defines are all coordinates to put various messsages */
        !            43: #define COM_ROW 23                     /* alpha row for command line */
        !            44: #define COM_COL 0                      /* column for same */
        !            45: #define PROMPT_ROW 24                  /* alpha row for prompts */
        !            46: #define PROMPT_COL 0                   /* column for same */
        !            47: #define GEN_COL 13                     /* column to put generation number on*/
        !            48: #define FILE_COL 37                    /* column to put filespec */
        !            49: 
        !            50: /* misc. defines */
        !            51: #define FONT_ROW 8                     /* pixel rows in the font */
        !            52: #define BIT 8                          /* number of bits in a byte */
        !            53: #define BYTEINCOLS 8                   /* no. of interal columns in a byte */
        !            54: 
        !            55: /****  all functions in this file ******/
        !            56: int main();             /* setup and master loop for life game*/
        !            57: void blank();           /* blank internal and screen grid*/
        !            58: void go();              /* steps through generations until a key is pressed*/
        !            59: void halt();            /* does nothing */
        !            60: void quit();            /* exit after prompting for certainty*/
        !            61: void diskread();        /* read new grid from disk*/
        !            62: int step();             /* advance one generation on screen and internally*/
        !            63: void diskwrite();       /* write internal grid to disk*/
        !            64: void up();              /* speeds up GO if possible */
        !            65: void down();            /* slows down GO */
        !            66: void beep();            /* beep the speaker for bad commands*/
        !            67: void showingrid();      /* display internal grid on screen*/
        !            68: int getfilespec();      /* get a file name from the user*/
        !            69: void putgen();          /* puts the current generation counter on prompt line*/
        !            70: void fill();            /*  fill in a grid cell on the screen and internally*/
        !            71: void remove();          /* clear a grid cell on the screen and internal grids*/
        !            72: int kbdreadeventque();  /* simulates MouReadEventQue with the keyboard*/
        !            73: void xorptr();          /* xors the mouse ptr on the screen*/
        !            74: void gputs();           /* put a character string on the graphics screen*/
        !            75: void gputchar();        /* put a character on the graphics screen*/
        !            76: void anerror();         /* error handler*/
        !            77: char gethit();          /* waits for a key hit or mouse button hit*/
        !            78: void wait4release();    /* wait until mouse buttons are up before returning*/
        !            79: void far pascal exitlife();/* exit program, resetting original screen mode*/
        !            80: 
        !            81: 
        !            82: /* global data */
        !            83: /* global variables for the internal and screen grids */
        !            84: int InRow = 45;                        /* rows & columns of cells w/ default*/
        !            85: int InCol = 80;                        /*   in internal grid. Col must be /8*/
        !            86: int ScrRow = 45;                       /* rows & column on screen grid */
        !            87: int ScrCol = 79;
        !            88: int SizeScrRow = 4;                    /* pixel rows per screen grid row */
        !            89: int SizeScrCol = 8;                    /* pixels cols per screen grid column*/
        !            90: char far *InGrid;                      /* pointer to internal grid, a simple
        !            91:                                         * bit map of the space and cells */
        !            92: char far *InGrid2;                     /* pointer for secondary map used
        !            93:                                         *   to calculate next generation */
        !            94: 
        !            95: /* screen related global data */
        !            96: static struct ModeData Highres = {12, 3, 1, 80, 25, 640, 200}; /* 640x200 b/w*/
        !            97: struct ModeData Savemode = {12};       /* place to save old screen mode */
        !            98: unsigned ScrSeg;                       /* screen buffer segment address */
        !            99: char Cell[]={32,7};                    /* blank for clear screen */
        !           100: unsigned OddPage=0x2000;               /* offset on Cga of odd row bit plane*/
        !           101:                                        /*   should be 0 on non-Cga modes */
        !           102: unsigned Cga=2;                        /* if using a Cga, screen adresses on
        !           103:                                         *   must be divided by 2 because of
        !           104:                                         *   the odd and even row bit planes
        !           105:                                         * if using non-Cga mode, should be 1*/
        !           106: /* mouse related global data */
        !           107: unsigned Mouse = 0;                    /* handle if mouse is present, else */
        !           108: int MouBoundRow = COM_ROW*FONT_ROW+6;  /* last row mouse is allowed on */
        !           109: int MouBoundCol = 631;                 /* last column mouse is allowed on */
        !           110: 
        !           111: /* misc. global data */
        !           112: char Filespec[79-FILE_COL];            /* file name holder (allows default)*/
        !           113: unsigned Generation;                   /* current generation count */
        !           114: char Logo[] = "                                                             \
        !           115:     Microsoft LIFE";                    /* logo used to clear prompt line */
        !           116: int Slow=0;                            /* number of slow-down loops for Go */
        !           117: 
        !           118: /* Data for commands.  Column of command on COM_ROW for printed name,
        !           119:  *     name for printing on command line, flag if not 0 then the command
        !           120:  *     can be executed within a Go command without stopping execution,
        !           121:  *     and the function that does the command. */
        !           122: struct Commands {
        !           123:        int Col;
        !           124:        char *Name;
        !           125:        char GoAble;
        !           126:        void (*Fun)();
        !           127: } ComLine[] = { 0, "Command:", 0, beep,
        !           128:                10, "Blank", 0, blank,
        !           129:                16, "Go", 0, go,
        !           130:                19, "Halt", 0, halt,
        !           131:                24, "Quit", 0, quit,
        !           132:                29, "Read", 0, diskread,
        !           133:                34, "Step", 0, step,
        !           134:                39, "Write", 0, diskwrite,
        !           135:                46, "Down-speed", 1, down,
        !           136:                57, "Up-speed", 1, 0,
        !           137:                67, 0, 0
        !           138:              };
        !           139: 
        !           140: 
        !           141: /***   main - setup and master loop for life game
        !           142:  *
        !           143:  *     First this sets the screen mode, gets the address of the screen buffer,
        !           144:  *     sets the ctrl-C handle to a routine to reset the screen mode on exit,
        !           145:  *     and allocates the data structures for the internal representation of
        !           146:  *     the life grid.  The main loop of the program continuously reads from
        !           147:  *     the keyboard and the mouse and translates the key or location of the
        !           148:  *     mouse with the ComLine structure into a command to execute.
        !           149:  */
        !           150: main () {
        !           151:     struct KeyData kbd;                        /* return for KBD call */
        !           152:     struct PhysBufData get_phys;               /* return for GetPhysBufData */
        !           153:     unsigned long throwaway;                   /* for returns I don't use */
        !           154:     int i;                                     /* just a counter */
        !           155:     unsigned far *ptr;                         /*used to clear internal grid*/
        !           156: 
        !           157:     /* data for the mouse (or keyboard emulator) */
        !           158:     int ptrrow = 86;           /* current pointer position */
        !           159:     int ptrcol = 316;
        !           160:     unsigned status = 0x100;   /* for MouSetDevStatus */
        !           161:     int type=0;                /* for no waits on mouse read */
        !           162:     struct EventInfo event;    /* return for mouse reads */
        !           163:     struct PtrLoc loc;         /* data for MouSetPtrPos */
        !           164: 
        !           165: 
        !           166:     /* try to open and initialize mouse.  If none installed, Mouse will
        !           167:      *     stay 0 to show keyboard emulation must be used */
        !           168:     if (!MOUOPEN (0L, (unsigned far *) &Mouse))   /* get handle */
        !           169:            /* mouse is here and well, so initialize it */
        !           170:            MOUSETDEVSTATUS ((unsigned far *) &status, Mouse);
        !           171: 
        !           172:     /* get current screen mode and save it for restoring on exit */
        !           173:     if (VIOGETMODE ((struct ModeData far *) &Savemode, 0)) {
        !           174:            printf ("Error setting screen mode, exitting\n");
        !           175:            DOSEXIT (1, 0);        /* exit if error */
        !           176:     }
        !           177:     /* set screen mode to 640x200 b/w (Cga high resolution */
        !           178:     if (VIOSETMODE ((struct ModeData far *) &Highres, 0)) {
        !           179:            printf ("Error setting screen mode, exitting\n");
        !           180:            DOSEXIT (1, 0);        /* exit if error */
        !           181:     }
        !           182: 
        !           183:     /* set mouse pointer to middle of screen */
        !           184:     if (Mouse) {
        !           185:        loc.RowPos=ptrrow;
        !           186:        loc.ColPos=ptrcol;
        !           187:        MOUSETPTRPOS ((struct PtrLoc far *) &loc, Mouse);
        !           188:     }
        !           189: 
        !           190:     /* get screen buffer segment */
        !           191:     get_phys.buf_start=0xb8000L;
        !           192:     get_phys.buf_length=16*1024L;
        !           193:     if (VIOGETPHYSBUF ((struct PhysBufData far *) &get_phys, 0)) {
        !           194:            /* if error here, restore screen and exit */
        !           195:            VIOSETMODE ((struct ModeData far *) &Savemode, 0);
        !           196:            printf ("Error accessing screen memory, exitting\n");
        !           197:            DOSEXIT (1, 0);
        !           198:     }
        !           199:     ScrSeg = get_phys.selectors[0];        /* store in global */
        !           200: 
        !           201:     /* set ctrl-C to quit() to reset screen at even a break */
        !           202:     DOSSETSIGHANDLER (exitlife, &throwaway, (unsigned far *)&throwaway, 2, 1);
        !           203: 
        !           204:     /* allocate a segment to hold internal grid representation */
        !           205:     if (DOSALLOCSEG (InRow*InCol/BYTEINCOLS, (unsigned far *) &InGrid, 0))
        !           206:            /* from here on use anerror() to report errors */
        !           207:            anerror ("Error allocating memory", 1);
        !           208:     (long) InGrid *= 0x10000L;             /* move selector to high word*/
        !           209: 
        !           210:     /* allocate a segment to hold second buffer used in stepping */
        !           211:     if (DOSALLOCSEG(InRow*InCol/BYTEINCOLS, (unsigned far *) &InGrid2, 0))
        !           212:            anerror ("Error allocating memory", 1);
        !           213:     (long) InGrid2 *= 0x10000L;            /* move selector to high word*/
        !           214: 
        !           215:     /* blank internal grid and draw screen */
        !           216:     for (i=InRow*InCol/16, ptr=(unsigned far *) InGrid ; i--;)
        !           217:            *ptr++ = 0;
        !           218:     showingrid ();
        !           219:     xorptr (ptrrow, ptrcol);               /* show cursor */
        !           220: 
        !           221: 
        !           222:     /* main input loop, polling mouse and keyboard */
        !           223:     while (1) {
        !           224:        /* try to get mouse event from keyboard or mouse */
        !           225:        kbd.char_code=0;                        /* clear key buffer residue */
        !           226:        kbdreadeventque (&event, ptrrow, ptrcol);
        !           227:        if (Mouse)
        !           228:            MOUREADEVENTQUE ((struct EventInfo far *) &event,
        !           229:                                 (unsigned far *) &type, Mouse);
        !           230: 
        !           231:        /* if any mouse-like events, do this */
        !           232:        if (event.Mask) {
        !           233:            xorptr (ptrrow, ptrcol);        /* hide cursor */
        !           234:            if (event.Mask & 1+2+8) {       /* if any motion */
        !           235:                    /* update position, if off screen grid,ptr=max or min*/
        !           236:                    ptrrow = event.Row;
        !           237:                    ptrcol = event.Col;
        !           238:                    if (ptrrow > MouBoundRow)
        !           239:                        ptrrow = MouBoundRow;
        !           240:                    if (ptrcol > MouBoundCol)
        !           241:                        ptrcol = MouBoundCol;
        !           242:            }
        !           243:            /* if a button was hit */
        !           244:            if (event.Mask & (2|4|8|16)) {
        !           245:                if (ptrrow < COM_ROW*FONT_ROW-SizeScrRow) { /* if on grid */
        !           246:                    Generation=0;                      /* reset Gen if   */
        !           247:                    putgen();                          /*   grid modified*/
        !           248:                    if (event.Mask & (2 | 4))          /* if left down*/
        !           249:                        fill (ptrcol/SizeScrCol, ptrrow/SizeScrRow);
        !           250:                    else if (event.Mask & (8 | 16))    /* if right */
        !           251:                        remove (ptrcol/SizeScrCol, ptrrow/SizeScrRow);
        !           252:                }
        !           253:                else {                                 /* on command line*/
        !           254:                    /* if pointing at command word, execute it, highlighting */
        !           255:                    for(i=0; ComLine[i].Fun != 0; i++)
        !           256:                        if (ptrcol/BIT >= ComLine[i].Col &&
        !           257:                                ptrcol/BIT < ComLine[i+1].Col-1) {
        !           258:                            gputs(ComLine[i].Name,COM_ROW,ComLine[i].Col,0xff);
        !           259:                            wait4release ();            /* execute on release*/
        !           260:                            (*(ComLine[i].Fun))();
        !           261:                            if (ComLine[i].Fun) /*restore name if not removed*/
        !           262:                               gputs(ComLine[i].Name,COM_ROW,ComLine[i].Col,0);
        !           263:                        }
        !           264:                }
        !           265:            }
        !           266:            xorptr (ptrrow, ptrcol);               /* show cursor */
        !           267:        }
        !           268: 
        !           269:        /* check keys, no wait */
        !           270:        KBDPEEK ((struct KeyData far *) &kbd, 0);
        !           271:        if (kbd.char_code) {            /* get key only if not regular char */
        !           272:                KBDCHARIN ((struct KeyData far *) &kbd, 1, 0);  /*get command*/
        !           273:                xorptr (ptrrow, ptrcol);                /* avoid overwrites */
        !           274:                /* walk command structure and execute function, highlighting */
        !           275:                for(i=0; ComLine[i].Fun != 0; i++)
        !           276:                    if ((kbd.char_code & 0xdf) == *(ComLine[i].Name)) {
        !           277:                        gputs(ComLine[i].Name,COM_ROW,ComLine[i].Col,0xff);
        !           278:                        (*(ComLine[i].Fun))();
        !           279:                        if (ComLine[i].Fun) /*restore name if not removed*/
        !           280:                            gputs(ComLine[i].Name,COM_ROW,ComLine[i].Col,0);
        !           281:                    }
        !           282:                xorptr (ptrrow, ptrcol);                /* restore pointer */
        !           283:        }
        !           284:     }
        !           285: }
        !           286: 
        !           287: 
        !           288: /***   blank - blank internal and screen grid
        !           289:  *
        !           290:  *     Sets the internal grid to all 0's and calls draw_grid() to
        !           291:  *     clear the screen and put up a screen grid.  blank() then draws
        !           292:  *     the command line and the program logo.
        !           293:  *
        !           294:  *     Entry:  ScrSeg = current screen segment
        !           295:  *             InGrid points to internal grid defined by InCol and InRow
        !           296:  *             Logo points to program logo that also clears the prompt line
        !           297:  *
        !           298:  *     Exit:   Generation = 0
        !           299:  *
        !           300:  *     Calls:  gputs(), putgen(), draw_grid [assembler routine]
        !           301:  */
        !           302: void
        !           303: blank (){
        !           304:        unsigned far *ptr;
        !           305:        int i;
        !           306: 
        !           307:        gputs (Logo, PROMPT_ROW, PROMPT_COL, 0);
        !           308:        gputs ("Are you sure?", PROMPT_ROW, PROMPT_COL, 0);
        !           309:        if (gethit () == 'Y') {
        !           310:                /* if yes, blank screen and internal grid */
        !           311:                draw_grid ();                   /* draw blank grid on screen */
        !           312:                for (i=InRow*InCol/16, ptr=(unsigned far *) InGrid ; i--;)
        !           313:                        *ptr++ = 0;             /* blank internal grid */
        !           314:                for (i=0; ComLine[i].Fun != 0; i++) /* print command line */
        !           315:                        gputs (ComLine[i].Name, COM_ROW, ComLine[i].Col, 0);
        !           316:                Generation=0;                   /* reset generation count */
        !           317:        }
        !           318:        gputs (Logo, PROMPT_ROW, PROMPT_COL, 0);   /* put on logo */
        !           319:        putgen ();                              /* initial generation message*/
        !           320: }
        !           321: 
        !           322: 
        !           323: /***   go - steps through generations until a key is pressed
        !           324:  *
        !           325:  *     Calls step() until a key is hit, which terminates the loop
        !           326:  *     and the key is left on the buffer for main() to process
        !           327:  *     as a command.
        !           328:  *     step()'s return is checked to see if this program has just
        !           329:  *     moved from background to foreground, in which case the
        !           330:  *     the screen will need manual updating with showingrid().
        !           331:  *     If the D or U keys are hit, down() or up() is executed.
        !           332:  *
        !           333:  *     Entry:  none
        !           334:  *
        !           335:  *     Exit:   None
        !           336:  *
        !           337:  *     Calls:  step(), showingrid()
        !           338:  */
        !           339: void
        !           340: go () {
        !           341:     struct KeyData kbd;                        /* return from KBD call */
        !           342:     int background=0;                          /* 0 if forground, 1 backgrd */
        !           343:     struct EventInfo event;                    /* return from mouse read */
        !           344:     int type=0;                                /* for no waits on mouse read*/
        !           345:     struct QueInfo num;                        /* return for GetNumQueEl */
        !           346:     unsigned x,y;                              /* for slowing down loops */
        !           347: 
        !           348:     /* step until key or button is hit, executing GoAble commands */
        !           349:     kbd.scan_code=0;
        !           350:     event.Mask=0;
        !           351:     while (!kbd.scan_code) {
        !           352:        if (step ())
        !           353:                background=1;
        !           354:        else if (background==1) {
        !           355:                background=0;
        !           356:                showingrid();
        !           357:        }
        !           358:        if (Mouse) {
        !           359:                /* read all events on que */
        !           360:                MOUGETNUMQUEEL ((struct QueInfo far *) &num, Mouse);
        !           361:                while (num.Events--) {
        !           362:                        MOUREADEVENTQUE ((struct EventInfo far *) &event,
        !           363:                                 (unsigned far *) &type, Mouse);
        !           364:                        if (event.Mask & (2|4|8|16)) {  /* leave if mouse hit*/
        !           365:                                wait4release();
        !           366:                                return;
        !           367:                        }
        !           368:                }
        !           369:        }
        !           370: 
        !           371:        /* check keys, no wait.  Execute if GoAble command */
        !           372:        KBDPEEK ((struct KeyData far *) &kbd, 0);
        !           373:        if (kbd.scan_code) {
        !           374:                /* walk command structure and execute function, highlighting */
        !           375:                for(x=0; ComLine[x].Fun != 0; x++)
        !           376:                    if ((kbd.char_code & 0xdf) == *(ComLine[x].Name)
        !           377:                               && ComLine[x].GoAble) {
        !           378:                        gputs(ComLine[x].Name,COM_ROW,ComLine[x].Col,0xff);
        !           379:                        KBDCHARIN ((struct KeyData far *) &kbd, 1, 0);
        !           380:                        kbd.scan_code=0;
        !           381:                        (*(ComLine[x].Fun))();
        !           382:                        if (ComLine[x].Fun) /*restore name if not removed*/
        !           383:                            gputs(ComLine[x].Name,COM_ROW,ComLine[x].Col,0);
        !           384:                    }
        !           385:        }
        !           386:        if (Slow)                  /* slow down if requested */
        !           387:                for (x=Slow; x--;)
        !           388:                        for (y=50000; y--;);
        !           389:     }
        !           390: }
        !           391: 
        !           392: 
        !           393: /***   halt - does nothing
        !           394:  */
        !           395: void
        !           396: halt () {
        !           397:        int i;
        !           398: 
        !           399:        for (i=30000; i--;);            /* short pause */
        !           400: }
        !           401: 
        !           402: 
        !           403: /***   quit - exit after prompting for certainty
        !           404:  *
        !           405:  *     Entry:  None
        !           406:  *
        !           407:  *     Exit:   None
        !           408:  */
        !           409: void
        !           410: quit () {
        !           411:        gputs (Logo, PROMPT_ROW, PROMPT_COL, 0);
        !           412:        gputs ("Are you sure?", PROMPT_ROW, PROMPT_COL, 0);
        !           413:        if (gethit () == 'Y')
        !           414:                exitlife ();                    /* if yes, do quit routine */
        !           415:        gputs (Logo, PROMPT_ROW, PROMPT_COL, 0);   /* else, continue */
        !           416:        putgen();                               /* put back gen count*/
        !           417: }
        !           418: 
        !           419: 
        !           420: /***   diskread - read new grid from disk
        !           421:  *
        !           422:  *     getfilespec() is called to get a file name from the user which
        !           423:  *     is put in Filespec.
        !           424:  *     Then an internal grid is read from the disk which is in the form:
        !           425:  *                             WORD SIGNATURE ; Life file signature
        !           426:  *                             WORD rows
        !           427:  *                             WORD columns
        !           428:  *                             WORD generation
        !           429:  *    (rows*columns/BYTEINCOLS) BYTES of the bit mapped grid
        !           430:  *
        !           431:  *     InGrid is ReAlloced to the size of the newly read grid and
        !           432:  *     InCol, InRow, and Generation are all set the values contained
        !           433:  *     in the file read.
        !           434:  *
        !           435:  *     Entry:  InGrid points to internal grid defined by InCol and InRow
        !           436:  *
        !           437:  *     Exit:   InGrid is ReAlloced to size of newly read grid.
        !           438:  *             InCol, InRow, and Generation are all set the values
        !           439:  *                     contained in the file read.
        !           440:  *                                              d
        !           441:  *     Calls:  getfilespec ();
        !           442:  */
        !           443: void
        !           444: diskread () {
        !           445:        unsigned handle;                        /* file handle */
        !           446:        unsigned action;                        /* return for file calls */
        !           447:        unsigned signature;                     /* life file signature word */
        !           448: 
        !           449:        /* get file name into Filespec */
        !           450:        if (getfilespec ())
        !           451:                return;                         /* return if user hit ESC */
        !           452: 
        !           453:        /* open file, fail if it doesn't exist */
        !           454:        if (DOSOPEN ((char far *) Filespec, (unsigned far *) &handle,
        !           455:            (unsigned far *) &action, 0L, 0, 0x01, 0x42, 0L)) {
        !           456:                anerror ("Can't open file", 0);
        !           457:                Filespec[0]=0;  /* clear bad file name */
        !           458:                return;
        !           459:        }
        !           460: 
        !           461:        /* read appropriate from file */
        !           462:        if (DOSREAD (handle, (char far *) &signature, sizeof (signature),
        !           463:            (unsigned far *) &action) || action != sizeof (signature))
        !           464:                anerror ("Error writing to file", 0);
        !           465: 
        !           466:        else if (signature != SIGNATURE) {
        !           467:                anerror ("Not a life file", 0);
        !           468:                if (DOSCLOSE (handle))
        !           469:                        anerror ("Error closing file", 0);
        !           470:                return;
        !           471:        }
        !           472:        else if (DOSREAD (handle, (char far *) &InRow, sizeof (InRow),
        !           473:            (unsigned far *) &action) || action != sizeof (InRow))
        !           474:                anerror ("Error reading from file", 0);
        !           475: 
        !           476:        else if (DOSREAD (handle, (char far *) &InCol, sizeof (InCol),
        !           477:            (unsigned far *) &action) || action != sizeof (InCol))
        !           478:                anerror ("Error reading from file", 0);
        !           479: 
        !           480:        else if (DOSREAD (handle, (char far *) &Generation,
        !           481:            sizeof (Generation), (unsigned far *) &action) ||
        !           482:            action != sizeof (Generation))
        !           483:                anerror ("Error reading from file", 0);
        !           484: 
        !           485:        /* change size of *InGrid to match saved pattern */
        !           486:        else if (DOSREALLOCSEG (InRow*InCol/BYTEINCOLS, (unsigned)
        !           487:            ((long) InGrid/0x10000L)))
        !           488:                anerror ("Error allocating memory", 0);
        !           489: 
        !           490:        else if (DOSREAD (handle, InGrid, InRow*InCol/BYTEINCOLS,
        !           491:            (unsigned far *) &action) || action != InRow*InCol/BYTEINCOLS)
        !           492:                anerror ("Error reading from file", 0);
        !           493: 
        !           494:        /* show the newly loaded pattern on the screen */
        !           495:        showingrid ();
        !           496: 
        !           497:        /* close file */
        !           498:        if (DOSCLOSE (handle))
        !           499:                anerror ("Error closing file", 0);
        !           500: }
        !           501: 
        !           502: 
        !           503: /***   step - advance one generation on screen and internally
        !           504:  *
        !           505:  *     Uses dostep to advance the current internal and screen grid
        !           506:  *     to the next generation.  dostep() returns 1 if the screen
        !           507:  *     was not available and thus no update was made, this allows
        !           508:  *     the program to continue to execute in the background.
        !           509:  *     The return from dostep() is passed back to step()'s caller.
        !           510:  *
        !           511:  *     Entry:  None
        !           512:  *
        !           513:  *     Exit:   Returns 1 if executing in background and there was thus
        !           514:  *                   no screen update.
        !           515:  *             Else, returns 0 if in forground
        !           516:  *             Generation is incremented.
        !           517:  *
        !           518:  *     Calls:  putgen(), dostep [assembler routine]
        !           519:  */
        !           520: int
        !           521: step() {
        !           522:        int     rc;                             /* return code from dostep */
        !           523: 
        !           524:        /* do the stepping using an assembler routine for speed */
        !           525:        rc=dostep(InGrid, InGrid2, InRow, InCol);  /* do the step */
        !           526: 
        !           527:        Generation++;                           /* advance the count */
        !           528:        putgen();                               /* and display gen */
        !           529:        return(rc);
        !           530: }
        !           531: 
        !           532: 
        !           533: /***   diskwrite - write internal grid to disk
        !           534:  *
        !           535:  *     getfilespec() is called to get a file name from the user which
        !           536:  *     is put in Filespec.
        !           537:  *     Then the internal grid is saved to disk in the form:
        !           538:  *                             WORD SIGNATURE ; Life file signature
        !           539:  *                             WORD rows
        !           540:  *                             WORD columns
        !           541:  *                             WORD generation
        !           542:  *    (rows*columns/BYTEINCOLS) BYTES of the bit mapped grid
        !           543:  *
        !           544:  *     Entry:  InGrid points to internal grid defined by InCol and InRow
        !           545:  *
        !           546:  *     Exit:   None
        !           547:  *
        !           548:  *     Calls:  getfilespec ();
        !           549:  */
        !           550: void
        !           551: diskwrite () {
        !           552:        unsigned handle;                        /* file handle */
        !           553:        unsigned action;                        /* return for file calls */
        !           554:        unsigned signature=SIGNATURE;           /* life file signature word */
        !           555: 
        !           556:        /* get file name into Filespec */
        !           557:        if (getfilespec ())
        !           558:                return;                         /* return if user hit ESC */
        !           559: 
        !           560:        /* open file and truncate or create it if it doesn't exist */
        !           561:        if (DOSOPEN ((char far *) Filespec, (unsigned far *) &handle,
        !           562:            (unsigned far *) &action, 0L, 0, 0x12, 0x42, 0L)) {
        !           563:                anerror ("Can't open file", 0);
        !           564:                Filespec[0]=0;  /* clear bad file name */
        !           565:                return;
        !           566:        }
        !           567: 
        !           568:        /* write appropriate info to file */
        !           569:        if (DOSWRITE (handle, (char far *) &signature, sizeof (signature),
        !           570:            (unsigned far *) &action)   || action != sizeof (signature))
        !           571:                anerror ("Error writing to file", 0);
        !           572: 
        !           573:        else if (DOSWRITE (handle, (char far *) &InRow, sizeof (InRow),
        !           574:            (unsigned far *) &action) || action != sizeof (InRow))
        !           575:                anerror ("Error writing to file", 0);
        !           576: 
        !           577:        else if (DOSWRITE (handle, (char far *) &InCol, sizeof (InCol),
        !           578:            (unsigned far *) &action) || action != sizeof (InCol))
        !           579:                anerror ("Error writing to file", 0);
        !           580: 
        !           581:        else if (DOSWRITE (handle, (char far *) &Generation,
        !           582:            sizeof (Generation), (unsigned far *) &action) ||
        !           583:            action != sizeof (Generation))
        !           584:                anerror ("Error writing to file", 0);
        !           585: 
        !           586:        else if (DOSWRITE (handle, InGrid, InRow*InCol/BYTEINCOLS,
        !           587:            (unsigned far *) &action) || action != InRow*InCol/BYTEINCOLS)
        !           588:                anerror ("Error writing to file", 0);
        !           589: 
        !           590:        /* close file */
        !           591:        if (DOSCLOSE (handle))
        !           592:                anerror ("Error closing file", 0);
        !           593: }
        !           594: 
        !           595: 
        !           596: /***   up - speeds up GOs (decrement Slow)
        !           597:  */
        !           598: void
        !           599: up() {
        !           600:        int i;
        !           601: 
        !           602:        if (Slow)
        !           603:                Slow--;
        !           604:        if (!Slow) {
        !           605:                /* if at top speed take out message */
        !           606:                for(i=0; *(ComLine[i].Name) != 'U'; i++);
        !           607:                ComLine[i].Fun=0;
        !           608:                gputs ("        ", COM_ROW, ComLine[i].Col, 0);
        !           609:        }
        !           610:        for (i=30000; i--;);            /* short pause */
        !           611: }
        !           612: 
        !           613: 
        !           614: /***   down - slows down GOs (increment Slow)
        !           615:  */
        !           616: void
        !           617: down() {
        !           618:        int i;
        !           619: 
        !           620:        Slow++;
        !           621:        for (i=30000; i--;);            /* short pause */
        !           622:        if (Slow){                  /* if at top speed, display UP */
        !           623:                for(i=0; *(ComLine[i].Name) != 'U'; i++);
        !           624:                ComLine[i].Fun=up;
        !           625:                for (i=0; ComLine[i].Fun != 0; i++) /* print command line */
        !           626:                        gputs (ComLine[i].Name, COM_ROW, ComLine[i].Col, 0);
        !           627:        }
        !           628: }
        !           629: 
        !           630: 
        !           631: /***   beep - beep the speaker for bad commands
        !           632:  */
        !           633: void
        !           634: beep () {
        !           635:        DOSBEEP (500, 50);
        !           636: }
        !           637: 
        !           638: 
        !           639: /***   showingrid - display internal grid on screen
        !           640:  *
        !           641:  *     Clears the screen using the draw_grid routine and then
        !           642:  *     puts the internal grid on the screen using fill() so as to
        !           643:  *     not be resolution dependent.
        !           644:  *
        !           645:  *     Entry:  InGrid points to internal grid defined by InCol and InRow.
        !           646:  *             ScrSeg points to the screen buffer.
        !           647:  *             ScrRow and ScrCol describe the dimensions of the screen grid.
        !           648:  *             Logo points to program logo that also clears the prompt line
        !           649:  *
        !           650:  *     Exit:   None
        !           651:  *
        !           652:  *     Calls:  fill(), putgen(), gputs(), draw_grid [assembler routine]
        !           653:  */
        !           654: void
        !           655: showingrid () {
        !           656:        int x, y;                               /* cell coordinates for loop */
        !           657:        char retcode;                           /* for VIOSCRLOCK */
        !           658: 
        !           659:        /* prepare blank screen so we only have to fill in cells that are on */
        !           660:        draw_grid ();                           /* draw blank grid on screen */
        !           661:        /* print command line */
        !           662:        for (x=0; ComLine[x].Fun != 0; x++)
        !           663:                gputs (ComLine[x].Name, COM_ROW, ComLine[x].Col, 0);
        !           664:        gputs (Logo, PROMPT_ROW, PROMPT_COL, 0);
        !           665:        putgen ();
        !           666: 
        !           667:        /* loop through the screen sized area of the grid */
        !           668:        VIOSCRLOCK (1, (char far *) &retcode, 0);   /* get screen access */
        !           669:        for (y=ScrRow; y--;)
        !           670:                for (x=ScrCol; x--;)
        !           671:                    /* if the internal cell is on, turn on the screen one*/
        !           672:                    if (*(InGrid + (x + y*InCol)/BYTEINCOLS) & (0x80 >> (x&7)))
        !           673:                            fill (x, y);
        !           674:        VIOSCRUNLOCK (0);
        !           675: }
        !           676: 
        !           677: 
        !           678: /***   getfilespec - get a file name from the user
        !           679:  *
        !           680:  *     Prompts user for a file name for use with diskread() or diskwrite().
        !           681:  *     The last file name used is shown on the screen as a default
        !           682:  *     and the user can hit enter (or left mouse button) to specify the
        !           683:  *     default name.  If any other key is pressed, this routine takes the
        !           684:  *     input until an enter and returns in Filespec.  If ESC is hit any time
        !           685:  *     during typeing, the input will be aborted and the buffer cleared.
        !           686:  *
        !           687:  *     Entry:  Filespec points to default file name
        !           688:  *             Logo points to program logo that also clears the prompt line
        !           689:  *
        !           690:  *     Exit:   Filespec points to new file name
        !           691:  *             returns 0x1b if ESC was hit during entry, else 0
        !           692:  *
        !           693:  *     Calls:  gputs(), putgen()
        !           694:  */
        !           695: int
        !           696: getfilespec () {
        !           697:        int c=0;                                /* index for Filespec[] */
        !           698:        struct KeyData kbd;                     /* return for KBD call */
        !           699:        unsigned space=0x0020;                  /* space character for print */
        !           700:        struct EventInfo event;                 /* return for mouse */
        !           701:        int type=0;                             /* mouse reads w/no wait */
        !           702: 
        !           703:        kbd.scan_code=0;
        !           704:        event.Mask=0;
        !           705:        /* put up default file name if one exists */
        !           706:        if (Filespec[0]) {
        !           707:            gputs ("Type file name or enter for default:  ", PROMPT_ROW,
        !           708:                                                             PROMPT_COL,0);
        !           709:            gputs (Filespec, PROMPT_ROW, FILE_COL, 0);
        !           710:            /* wait for first key or button to see if they accept default */
        !           711:            while (!kbd.scan_code && !(event.Mask & (2|4|8|16))) {
        !           712:                    if (Mouse)
        !           713:                            MOUREADEVENTQUE ((struct EventInfo far *) &event,
        !           714:                                             (unsigned far *) &type, Mouse);
        !           715:                    KBDPEEK ((struct KeyData far *) &kbd, 0);
        !           716:            }
        !           717:        }
        !           718:        if (event.Mask & (8 | 16)) {    /* if right button hit, same as ESC */
        !           719:                kbd.char_code = 0x1b;
        !           720:                wait4release();
        !           721:        }
        !           722:        if (event.Mask & (2 | 4)) {     /* if left button hit, same as \r */
        !           723:                wait4release();
        !           724:                gputs (Logo, PROMPT_ROW, PROMPT_COL, 0);
        !           725:                putgen();
        !           726:                return (0);
        !           727:        }
        !           728:        if (kbd.char_code == 0x1b) {    /* if ESC, return */
        !           729:                gputs (Logo, PROMPT_ROW, PROMPT_COL, 0);
        !           730:                putgen();
        !           731:                return (0x1b);                     /*   return escape */
        !           732:        }
        !           733: 
        !           734:        gputs(Logo, PROMPT_ROW, PROMPT_COL, 0);
        !           735:        gputs("Type file name,  followed by enter:  ",PROMPT_ROW,PROMPT_COL,0);
        !           736: 
        !           737:        /* read chars and print them until \r */
        !           738:        while (!(KBDCHARIN ((struct KeyData far *) &kbd, 0, 0)) &&
        !           739:           kbd.char_code != '\r') {
        !           740:             if (kbd.char_code == '\b') { /* if backspace, backspace */
        !           741:                     if (c > 0) {                       /* prevent underflow*/
        !           742:                             Filespec[--c]=0;
        !           743:                             /* erase backed-out character*/
        !           744:                             gputs (&space, PROMPT_ROW, FILE_COL+c,0);
        !           745:                     }
        !           746:                     else                               /* if overflow, yell */
        !           747:                             beep();
        !           748:             }
        !           749:             else if (kbd.char_code == 0x1b) {          /* if escape was hit */
        !           750:                     Filespec[0]=0;                     /*   blank name */
        !           751:                     gputs (Logo, PROMPT_ROW, PROMPT_COL, 0);
        !           752:                     putgen();
        !           753:                     return (0x1b);                     /*   return escape */
        !           754:             }
        !           755:             else if (kbd.char_code <46 || kbd.char_code > 122)
        !           756:                     beep();                            /* if not char, beep */
        !           757:             else
        !           758:                     if (c < sizeof (Filespec)) {    /* prevent overflow */
        !           759:                             Filespec[c]=kbd.char_code;  /* add to string */
        !           760:                             Filespec[++c]=0;            /* null terminal */
        !           761:                     }
        !           762:                     else                               /* if overflow, yell */
        !           763:                             beep();
        !           764: 
        !           765:             gputs (Filespec, PROMPT_ROW, FILE_COL, 0);   /* print new name */
        !           766:        }
        !           767:        /* return generation count to screen */
        !           768:        gputs (Logo, PROMPT_ROW, PROMPT_COL, 0);
        !           769:        putgen();
        !           770:        return (0);
        !           771: }
        !           772: 
        !           773: 
        !           774: /***   putgen - puts the current generation counter on prompt line
        !           775:  *
        !           776:  *     Entry:  Generation = current generation number
        !           777:  *
        !           778:  *     Exit:   None
        !           779:  *
        !           780:  *     Calls:  gputs()
        !           781:  */
        !           782: void
        !           783: putgen ()
        !           784: {
        !           785:        char num[8];                            /* number string to print */
        !           786:        int i, g;
        !           787: 
        !           788:        gputs ("Generation:         ", PROMPT_ROW, PROMPT_COL,0);/* gen label*/
        !           789: 
        !           790:        if (Generation == 0)
        !           791:                gputs ("0", PROMPT_ROW,GEN_COL,0);/*if special case need this*/
        !           792:        else {                                  /* not 0, do this: */
        !           793:                for (g=Generation, i=sizeof(num)-1; i-- >= 0 && g; g/=10)
        !           794:                        num[i]=(g%10)+'0';      /* convert int to string */
        !           795:                num[sizeof(num)-1]= 0;       /* zero terminated for gputs */
        !           796:                gputs (&num[i+1], PROMPT_ROW, GEN_COL,0); /* print number */
        !           797:        }
        !           798: }
        !           799: 
        !           800: 
        !           801: /***   fill -  fill in a grid cell on the screen and internally
        !           802:  *
        !           803:  *     fill (x, y)
        !           804:  *
        !           805:  *     Entry:  x = grid horizontal coordinate
        !           806:  *             y = grid vertical coordinate
        !           807:  *             ScrSeg = screen buffer segment
        !           808:  *             VioScrLock is active
        !           809:  *             InGrid points to internal grid defined by InCol and InRow
        !           810:  *             ScrRow and ScrCol define limits of screen grid
        !           811:  *             Currently, must use 79x25 grid drawn by draw_grid()
        !           812:  *             Currently, screen must be in 640x200 b/w mode
        !           813:  *
        !           814:  *     Exit:   None
        !           815:  */
        !           816: void
        !           817: fill (x, y)
        !           818: int x,y;
        !           819: {
        !           820:        char far *gridptr;
        !           821: 
        !           822:        /* only do if within screen grid limits */
        !           823:        if (x < ScrCol && y < ScrRow) {
        !           824:            /* set gridptr to & in screen buff of cell to fill */
        !           825:            (long) gridptr = ScrSeg*0x10000;      /* fill in address */
        !           826:            (unsigned) gridptr = (x*SizeScrCol/BIT)+(y*SizeScrRow/Cga*SCR_WID);
        !           827:            /* fill in screen cell */
        !           828:            *(gridptr+OddPage)=0x7f;
        !           829:            *(gridptr+SCR_WID)=0x7f;
        !           830:            *(gridptr+OddPage+SCR_WID)=0x7f;
        !           831:        }
        !           832:        /* fill in internal cell*/
        !           833:        /*InGrid= &internal grid of x,y*/
        !           834:        gridptr = InGrid + x/BYTEINCOLS + y*InCol/BYTEINCOLS;
        !           835:        *gridptr = *gridptr | (0x80 >> (x & 7));   /* fill bit */
        !           836: }
        !           837: 
        !           838: 
        !           839: /***   remove - clear a grid cell on the 79x45 grid screen and internally
        !           840:  *
        !           841:  *     remove (x, y)
        !           842:  *
        !           843:  *     Entry:  x = grid horizontal coordinate
        !           844:  *             y = grid vertical coordinate
        !           845:  *             ScrSeg = screen buffer segment
        !           846:  *             VioScrLock is active
        !           847:  *             InGrid points to internal grid defined by InCol and InRow
        !           848:  *             ScrRow and ScrCol define limits of screen grid
        !           849:  *             Currently, must use 79x25 grid drawn by draw_grid()
        !           850:  *             Currently, screen must be in 640x200 b/w mode
        !           851:  *
        !           852:  *     Exit:   None
        !           853:  */
        !           854: void
        !           855: remove (x, y)
        !           856: int x,y;
        !           857: {
        !           858:        char far *gridptr;
        !           859: 
        !           860:        /* only do if within screen grid limits */
        !           861:        if (x < ScrCol && y < ScrRow) {
        !           862:            /* set gridptr to & in screen buff of cell to fill */
        !           863:            (long) gridptr = ScrSeg*0x10000;      /* fill in address */
        !           864:            (unsigned) gridptr = (x*SizeScrCol/BIT)+(y*SizeScrRow/Cga*SCR_WID);
        !           865:            /* fill in screen cell */
        !           866:            *(gridptr+OddPage)=0x80;
        !           867:            *(gridptr+SCR_WID)=0x80;
        !           868:            *(gridptr+OddPage+SCR_WID)=0x80;
        !           869:        }
        !           870: 
        !           871:        /* remove internal cell*/
        !           872:        /*InGrid= &internal grid of x,y*/
        !           873:        gridptr = InGrid + x/BYTEINCOLS + y*InCol/BYTEINCOLS;
        !           874:        *gridptr = *gridptr & ~((0x80 >> (x & 7)));   /* remove bit */
        !           875: }
        !           876: 
        !           877: 
        !           878: /***   kbdreadeventque - simulates MouReadEventQue with the keyboard
        !           879:  *
        !           880:  *     F9 key is responded to as left button, F10 key as right.
        !           881:  *     Pointer location is advanced by SizeScrCol or SizeScrRow according
        !           882:  *     to direction of direction key hits.
        !           883:  *     Does not wait for input, instead returns 0 event mask.
        !           884:  *     Does not check MouDevStatus, instead always returns pixel coordinates
        !           885:  *     Event buffer is filled according to MouReadEventQue
        !           886:  *
        !           887:  *     Entry:  event  - structure to return data
        !           888:  *             ptrrow - current point row
        !           889:  *             ptrcol - current pointer column
        !           890:  *
        !           891:  *     Exit:   None
        !           892:  *             *event contains any event that may have occurred
        !           893:  */
        !           894: int
        !           895: kbdreadeventque (event, ptrrow, ptrcol)
        !           896: struct EventInfo *event;
        !           897: int ptrrow, ptrcol;
        !           898: {
        !           899:        struct KeyData kbd;                     /* return for KBD call */
        !           900: 
        !           901:        kbd.char_code=0;                        /* clear data struct residue*/
        !           902:        kbd.scan_code=0;
        !           903:        /* peek at key buffer */
        !           904:        KBDPEEK ((struct KeyData far *) &kbd, 0);
        !           905: 
        !           906:        /* if it is an extended key code, process it */
        !           907:        if (kbd.char_code == 0 && kbd.scan_code) {
        !           908:                KBDCHARIN ((struct KeyData far *) &kbd, 1, 0); /* take char */
        !           909:                event->Row=ptrrow;              /* initial position */
        !           910:                event->Col=ptrcol;
        !           911:                switch (kbd.scan_code) {        /* check second byte of code */
        !           912:                    case 0x48:                  /* cursor up */
        !           913:                        event->Row -= SizeScrRow;
        !           914:                        event->Mask=1;
        !           915:                        break;
        !           916:                    case 0x50:                  /* cursor down */
        !           917:                        event->Row += SizeScrRow;
        !           918:                        event->Mask=1;
        !           919:                        break;
        !           920:                    case 0x4b:                  /* cursor left */
        !           921:                        event->Col -= SizeScrCol;
        !           922:                        event->Mask=1;
        !           923:                        break;
        !           924:                    case 0x4d:                  /* cursor right */
        !           925:                        event->Col += SizeScrCol;
        !           926:                        event->Mask=1;
        !           927:                        break;
        !           928:                    case 0x43:                  /* left button (F9) */
        !           929:                        event->Mask=4;
        !           930:                        break;
        !           931:                    case 0x52:                  /* left button (INS) */
        !           932:                        event->Mask=4;
        !           933:                        break;
        !           934:                    case 0x44:                   /* right button (F10) */
        !           935:                        event->Mask=16;
        !           936:                        break;
        !           937:                    case 0x53:                   /* right button (DEL) */
        !           938:                        event->Mask=16;
        !           939:                        break;
        !           940:                    default:                    /* anything else is no good */
        !           941:                        event->Mask=0;
        !           942:                        break;
        !           943:                }
        !           944:        }
        !           945:        else
        !           946:                event->Mask=0;                  /* if no extended key */
        !           947: }
        !           948: 
        !           949: 
        !           950: /***   xorptr - xors the mouse ptr on the screen
        !           951:  *
        !           952:  *     xorptr (ptrrow, ptrcol)
        !           953:  *
        !           954:  *     Entry:  ptrrow = pixel row on screen
        !           955:  *             ptrcol = pixel column on screen
        !           956:  *             ScrSeg = screen buffer segment
        !           957:  *
        !           958:  *     Exit:   None
        !           959:  */
        !           960: void
        !           961: xorptr (ptrrow, ptrcol)
        !           962: unsigned ptrrow, ptrcol;
        !           963: {
        !           964:        char far *gridptr;
        !           965:        unsigned mask=0;                        /* bit mask for pointer shape*/
        !           966:        int x=8;                                /* count for rows of pointer */
        !           967:        char retcode;                           /* return from VioScrLock */
        !           968: 
        !           969:        /* set gridptr to & in screen buff to xor */
        !           970:        ptrrow++;                               /* 1st move ptr to next row*/
        !           971:        (long) gridptr = ScrSeg*0x10000;        /* fill in segment address */
        !           972:        (unsigned) gridptr = ptrcol/x+(ptrrow/Cga*SCR_WID);/* fill offset*/
        !           973: 
        !           974:        /* fill in screen pointer */
        !           975:        VIOSCRLOCK (1, (char far *) &retcode, 0);       /* get screen */
        !           976:        while (x--) {
        !           977:                mask = mask >> 1;                       /* make mask thicker */
        !           978:                mask |= 0x8000;                         /*    at bottom */
        !           979:                if (ptrrow & 1 && Cga == 2)             /* if odd bit plane */
        !           980:                        gridptr += OddPage;
        !           981:                /* xor mask to scr, being sure to reverse bytes in word */
        !           982:                *(gridptr+1) ^= (char) (mask >> (ptrcol & 7));
        !           983:                *(gridptr) ^= (char) ((mask >> (ptrcol & 7)) / 256);
        !           984:                if (ptrrow & 1 && Cga == 2)             /* if odd bit plane */
        !           985:                        gridptr -= OddPage;             /*    plane, next row*/
        !           986:                ptrrow++;                               /* next row */
        !           987:                if (!(ptrrow & 1) && Cga == 2)          /*only advance on odd*/
        !           988:                        gridptr += SCR_WID;             /*   row w/o CGA */
        !           989:         }
        !           990:        VIOSCRUNLOCK (0);                               /* give back screen */
        !           991: }
        !           992: 
        !           993: 
        !           994: /***   gputs - put a character string on the graphics screen
        !           995:  *
        !           996:  *     gputs (string, row, col)
        !           997:  *
        !           998:  *     Draws the passed asciiz string on the screen unless the screen
        !           999:  *     is not available (i.e., if running in background screen group)
        !          1000:  *     in which case this routine does nothing so as to not hold up
        !          1001:  *     the program.
        !          1002:  *
        !          1003:  *     Entry:  string - address of asciiz string to print
        !          1004:  *             row    - alpha row to print at
        !          1005:  *             col    - alpha col to print at
        !          1006:  *             mask   - xor'ed with bytes of character as printed
        !          1007:  *
        !          1008:  *     Exit:   None
        !          1009:  *
        !          1010:  *     Calls:  gputchar()
        !          1011:  *
        !          1012:  *     Warning: Prints graphics characters for ascii control codes (<32).
        !          1013:  *              Does not wrap-around at line end.
        !          1014:  */
        !          1015: void
        !          1016: gputs (string, row, col, mask)
        !          1017: char *string;
        !          1018: unsigned col, row;
        !          1019: char mask;
        !          1020: {
        !          1021:        static struct VIOFONT fontdata = {14,1,FONT_ROW,8,0L,0};/*for GetFont*/
        !          1022:        char c;
        !          1023:        char retcode;                           /* for VIOSCRLOCK */
        !          1024:        char far *scr_addr;                     /* address in screen buffer
        !          1025:                                                   to print at */
        !          1026: 
        !          1027:        /* try lock without waiting for availability */
        !          1028:        VIOSCRLOCK (0, (char far *) &retcode, 0);       /* get screen access */
        !          1029: 
        !          1030:        /* do display only if screen available now */
        !          1031:        if (retcode == 0) {
        !          1032:                /* get address of font table if haven't yet */
        !          1033:               if (!fontdata.font_data)
        !          1034:                       VIOGETFONT ((struct VIOFONT far *) &fontdata, 0);
        !          1035: 
        !          1036:               (long) scr_addr = ScrSeg*0x10000;   /* fill in segment address*/
        !          1037:               (unsigned)scr_addr = col+(row*SCR_WID*(FONT_ROW/Cga));/*offset*/
        !          1038:               while ((c=*(string++)) != 0)            /* print each char */
        !          1039:                      gputchar(scr_addr++, fontdata.font_data+c*FONT_ROW,mask);
        !          1040:               VIOSCRUNLOCK (0);                       /* give up screen */
        !          1041:        }
        !          1042: }
        !          1043: 
        !          1044: 
        !          1045: /***   gputchar - put a character on the graphics screen
        !          1046:  *
        !          1047:  *     gputchar (scr_addr, font_addr, mask)
        !          1048:  *
        !          1049:  *     Entry:  scr_addr  - far address in screen buffer to place character
        !          1050:  *                         must be on even Cga bit plane
        !          1051:  *             font_addr - far address in font table bit pattern
        !          1052:  *             mask      - xor'ed with each byte put on screen
        !          1053:  *             VIOSCRLOCK is active
        !          1054:  *
        !          1055:  *     Exit:   None
        !          1056:  */
        !          1057: void
        !          1058: gputchar(scr_addr, font_addr, mask)
        !          1059: char far *scr_addr;
        !          1060: char far *font_addr;
        !          1061: char mask;
        !          1062: {
        !          1063:        int i=FONT_ROW;                 /* count to draw whole character */
        !          1064: 
        !          1065:        while (i--) {
        !          1066:                if (i & 1 && Cga == 2)          /* if odd bit plane */
        !          1067:                        scr_addr += OddPage-SCR_WID;
        !          1068:                *scr_addr = (*(font_addr++) ^ mask);/* put byte on even plane*/
        !          1069:                if (i & 1 && Cga == 2)          /* if odd bit plane */
        !          1070:                        scr_addr -= OddPage;
        !          1071:                scr_addr+=SCR_WID;              /* move down a line */
        !          1072:        }
        !          1073: }
        !          1074: 
        !          1075: 
        !          1076: /***   anerror - error handler
        !          1077:  *
        !          1078:  *     anerror (message, fatal);
        !          1079:  *
        !          1080:  *     Prints passed error message and waits for a key hit to allow
        !          1081:  *     user to read it.  If fatal flag is 0, the routine then returns,
        !          1082:  *     otherwise the routine restores the original screen mode, clears
        !          1083:  *     the screen, and exits.
        !          1084:  *
        !          1085:  *     Entry:  message - string to print describing error
        !          1086:  *             fatal - flag, if == 0, this procedure prompts for any key hit
        !          1087:  *                     then returns.  If != 0, error is fatal & program exits.
        !          1088:  *             Logo points to program logo that also clears the prompt line
        !          1089:  *
        !          1090:  *     Exit:   None
        !          1091:  *
        !          1092:  *     Calls:  gputs(), putgen()
        !          1093:  */
        !          1094: void
        !          1095: anerror (message, fatal)
        !          1096: char message[];
        !          1097: int fatal;
        !          1098: {
        !          1099:        struct KeyData kbd;                     /* return for KBD call */
        !          1100: 
        !          1101:        gputs (Logo, PROMPT_ROW, PROMPT_COL,0);
        !          1102:        gputs (message, PROMPT_ROW, PROMPT_COL, 0);/* print passed message */
        !          1103: 
        !          1104:        if (fatal) {
        !          1105:                gputs(":  Press any key to exit",PROMPT_ROW,strlen(message),0);
        !          1106:                gethit ();
        !          1107:                exitlife();
        !          1108:        }
        !          1109:        else  {
        !          1110:                gputs (":  Press any key to continue",PROMPT_ROW,
        !          1111:                                                      strlen(message), 0);
        !          1112:                gethit ();
        !          1113:                gputs (Logo, PROMPT_ROW, PROMPT_COL, 0);
        !          1114:                putgen();
        !          1115:        }
        !          1116: }
        !          1117: 
        !          1118: 
        !          1119: /***   gethit - waits for a key hit or mouse button hit
        !          1120:  *
        !          1121:  *     Entry:  None
        !          1122:  *
        !          1123:  *     Exit:   Returns character hit (forced upper case) or 'Y' for left
        !          1124:  *             mouse button and 'N' for right mouse
        !          1125:  */
        !          1126: char
        !          1127: gethit () {
        !          1128:        struct KeyData kbd;                     /* for keyboard */
        !          1129:        struct EventInfo event;                 /* for mouse */
        !          1130:        int type=0;
        !          1131:        char rc;                                /* return code */
        !          1132: 
        !          1133:        /* loop till a hit */
        !          1134:        kbd.scan_code=0;
        !          1135:        event.Mask=0;
        !          1136:        while (!kbd.scan_code && !(event.Mask & (2|4|8|16))) {
        !          1137:                if (Mouse)
        !          1138:                        MOUREADEVENTQUE ((struct EventInfo far *) &event,
        !          1139:                                         (unsigned far *) &type, Mouse);
        !          1140:                KBDCHARIN ((struct KeyData far *) &kbd, 1, 0);
        !          1141:        }
        !          1142:        if (kbd.scan_code)                      /* if key, return char */
        !          1143:                rc=kbd.char_code & 0xdf;
        !          1144:        else if (event.Mask & (8 | 16)) {       /* if right */
        !          1145:                rc='N';
        !          1146:                wait4release ();
        !          1147:        }
        !          1148:        else if (event.Mask & (2 | 4))  {       /* if left down*/
        !          1149:                rc='Y';
        !          1150:                wait4release ();
        !          1151:        }
        !          1152:        return (rc);
        !          1153: }
        !          1154: 
        !          1155: 
        !          1156: /***   wait4release - wait until mouse buttons are up before returning
        !          1157:  *
        !          1158:  *     Entry:  Mouse = mouse handle or 0 if no mouse
        !          1159:  */
        !          1160: void
        !          1161: wait4release () {
        !          1162:        struct EventInfo event;
        !          1163:        unsigned type = 0;              /* if OS/2, wait for events */
        !          1164: 
        !          1165:        event.Mask=2;                    /* force 1st read */
        !          1166:        if (Mouse)                      /* loop till no button events */
        !          1167:                while ((event.Mask & (2|4|8|16)) || event.Time==0)
        !          1168:                        MOUREADEVENTQUE ((struct EventInfo far *) &event,
        !          1169:                                         (unsigned far *) &type, Mouse);
        !          1170: }
        !          1171: 
        !          1172: 
        !          1173: /***   exitlife - exit program, resetting original screen mode
        !          1174:  *
        !          1175:  *     Called by a Ctrl-C
        !          1176:  *
        !          1177:  *     Entry:  Savemode contains original screen mode info
        !          1178:  *
        !          1179:  *     Exit:   None
        !          1180:  */
        !          1181: void far pascal
        !          1182: exitlife() {
        !          1183:                VIOSETMODE ((struct ModeData far *) &Savemode, 0); /* restore*/
        !          1184:                VIOSCROLLUP (0,0,-1,-1,-1, (char far *) Cell,0);   /* cls */
        !          1185:                DOSEXIT (1, 0);         /* exit all threads */
        !          1186: }
        !          1187: 

unix.superglobalmegacorp.com

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