Annotation of os2sdk/demos/apps/life/life.c, revision 1.1.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.