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

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

unix.superglobalmegacorp.com

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