|
|
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:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.