home *** CD-ROM | disk | FTP | other *** search
/ Simtel MSDOS 1992 June / SIMTEL_0692.cdr / msdos / turbo_c / rdir.arc / RDIR.C < prev    next >
C/C++ Source or Header  |  1987-06-14  |  23KB  |  752 lines

  1. /*
  2.  * RDIR.C : A resident directory lister.  This shows how to access DOS from
  3.  *          within a Turbo C resident program.  To completely recompile this
  4.  *          code you must have MASM or a compatible compiler.  Unfortunately
  5.  *          everything but trapping the BIOS Disk service software
  6.  *          interrrupt could be done in Turbo C.  See code commentary.
  7.  *
  8.  *  To activate the program once loaded, press Ctrl and Alt together.
  9.  *  I know this combination gets in the way of SideKick, but I don't use
  10.  *  sidekick <grin> and this is meant as a tutorial anyway.  If you would
  11.  *  like to change this combination see Hot_Combo in the source code.
  12.  *  Next, enter the pattern for the directory search followed either by
  13.  *  Enter or Ctrl-Enter.  Enter will not include directories.  Ctrl-Enter
  14.  *  will include directories.  Directories are displayed in white where
  15.  *  other files are displayed in cyan.  Hidden and system files are included.
  16.  *  The page up and page down keys may be used to see other parts of large
  17.  *  directory listings.
  18.  *
  19.  *  Written by Dean D. McCrory
  20.  *  For Turbo C 1.00
  21.  *  May 14, 1987
  22.  *
  23.  *  Compile with:
  24.  *    masm -mx bioshand.asm;
  25.  *    masm -mx intvid.asm;
  26.  *    tcc -N- rdir.c bioshand.obj intvid.obj
  27.  *
  28.  *  The -N- switch turns stack checking off which is a definite requirement
  29.  *  for writing ISRs.  Have fun <grin>.
  30.  */
  31.  
  32. #include <dos.h>
  33. #include <dir.h>
  34.  
  35. #include "intvid.h"
  36.  
  37. /* function prototypes */
  38. int main (void);
  39. unsigned prgsize (void);
  40. void exit (int);
  41. char far * getdosbusy (void);
  42. void interrupt timer_handler (void);
  43. void do_click (void);
  44. void interrupt special_handler (void);
  45. void interrupt keyboard_handler (void);
  46. extern void interrupt biosdisk_handler (void);
  47. void interrupt break_handler (void);
  48. void list_directory (void);
  49. void set_screen (void);
  50. void get_pattern (void);
  51. void display_entries (void);
  52. void find_entry (void);
  53. void sc_putsa (int, int, char *, int);
  54. void sc_putca (int, int, char, int);
  55. void sc_repvca (int, int, char, int, int);
  56. void sc_rephca (int, int, char, int, int);
  57. void sc_savbox (int, int, int, int, char *);
  58. void sc_resbox (int, int, int, int, char *);
  59. void sc_rptpos (int *, int *);
  60. void sc_setpos (int, int);
  61. char far * sc_cca (int, int);
  62. int getkey ();
  63.  
  64. /* Define the structure which will be attached to interrupt d0 so we can
  65.    determine if rdir is already loaded */
  66. typedef struct s_rdir_cfg
  67.    {
  68.    char iret;        /* iret first, just in case */
  69.    long * signature; /* signature string */
  70.    } t_rdir_cfg;
  71.  
  72. /* Suppress some library functions to conserve space */
  73. _setargv () {}
  74. _setenvp () {}
  75.  
  76. /* defines for various things, in alot of these things we are looking right
  77.    into the BIOS data area. See Peter Norton's Guide to the IBM-PC or
  78.    your Tech. Ref. for an expanation of these data items. */
  79. #define Screen_Ram   ((char far *) 0xb8000000L) + (*(int far *) 0x0000044eL)
  80. #define Display_Page (*(char far *) 0x00000462L)
  81. #define Iret         0xcf     /* for iret in int d1 just in case */
  82. #define Intr         0xd1     /* interrupt for install checking */
  83. #define Timer        0x1c     /* timer interrupt number */
  84. #define Keyboard     0x09     /* keyboard hardware interrupt */
  85. #define Special      0x28     /* special interrupt 28h */
  86. #define Critical     0x24     /* hardware critical interrupt 24h */
  87. #define Break        0x1b     /* bios ctrl-break interrupt */
  88. #define BiosDisk     0x13     /* bios diskette services */
  89. #define NotOk        1        /* already installed return code */
  90. #define Ok           0        /* success return code */
  91. #define Shift_Bits   ((char far *) 0x00000417L)
  92. #define Hot_Combo    ((*Shift_Bits & 12) == 12) /* Our hot key combo */
  93.  
  94. #define  Box_Row     4     /* row of box */
  95. #define  Box_Col     4     /* column of box */
  96. #define  Box_Hgt     17    /* height of box */
  97. #define  Box_Wdth    70    /* widht of box */
  98. #define  Box_Attr    0x4f  /* attribute of box border */
  99. #define  Box_Incr    14    /* number of columns between start of filenames */
  100. #define  Pat_Size    64    /* size of a pattern string */
  101. #define  Norm_Attr   3     /* attribute of normal files */
  102. #define  Dir_Attr    15    /* attribute of directories */
  103. #define  Name_Size   12    /* size of each file name when displayed */
  104. #define  Per_Screen  5 * (Box_Hgt - 2) /* number of dir entries in box */
  105.  
  106. /* Defines for key values as returned by getkey () */
  107. #define  Page_Up_Key    329
  108. #define  Page_Dn_Key    337
  109. #define  Escape_Key     27
  110. #define  BackSpace_Key  8
  111. #define  Enter_Key      13
  112. #define  Ctrl_Enter_Key 10
  113.  
  114. char  box_buf[Box_Hgt * Box_Wdth * 2]; /* buffer for saving screen */
  115. int   old_row, old_col;                /* row and col of cursor */
  116. int   current_entry;                   /* last dir entry read */
  117. int   entries_to_skip;                 /* first entry on display */
  118. char  pattern[Pat_Size];               /* pattern for dir searches */
  119. int   attrib;                          /* attrib for dir searches */
  120. struct ffblk ffblk;                    /* file-find block */
  121. int   key, status;                     /* last key, and last ff status */
  122. t_vidreg regs;                         /* global regs structure */
  123. char far * ptr;                        /* general purpose far pointer */
  124. char far * buf_pos;                    /* another of the same */
  125. int   next_line;                       /* used by screen stuff */
  126.  
  127. /* Our configuration structure... nothing in it but the signature */
  128. t_rdir_cfg rdir_cfg =
  129.    {
  130.    Iret, (long *) "rdir"
  131.    };
  132.  
  133. void interrupt (* old_timer) ();    /* previous timer interrupt vector */
  134. void interrupt (* old_keyboard) (); /* previous keyboard int vector */
  135. void interrupt (* old_special) ();  /* previous int 28h vector */
  136. void interrupt (* old_biosdisk) (); /* previous bios disk svc vector */
  137. void interrupt (* old_critical) (); /* previous int 24h vector */
  138. void interrupt (* old_break) ();    /* pervious int 1bh vector */
  139. char far * old_dta;                 /* disk transfer address save area */
  140.  
  141. static char far * dosbusy_fl;    /* dos maintains this */
  142. char biosbusy_fl = 0;            /* I maintain this */
  143. static int request_fl = 0;       /* 0 - no request
  144.                                     1 - request made
  145.                                     2 - request being serviced
  146.                                   */
  147. int main ()
  148. {
  149.    t_rdir_cfg far * cfg_ptr;
  150.  
  151.    /* get old configuration information (mayebe) */
  152.    cfg_ptr = (t_rdir_cfg far *) getvect (Intr);
  153.  
  154.    /* check to see if we are already installed */
  155.    if (*cfg_ptr->signature != *rdir_cfg.signature)
  156.       {
  157.       /* we were not installed so install ourselves */
  158.       old_timer = getvect (Timer);
  159.       old_keyboard = getvect (Keyboard);
  160.       old_special = getvect (Special);
  161.       old_biosdisk = getvect (BiosDisk);
  162.       setvect (Timer, timer_handler);
  163.       setvect (Special, special_handler);
  164.       setvect (BiosDisk, biosdisk_handler);
  165.       setvect (Keyboard, keyboard_handler);
  166.       setvect (Intr, (void interrupt (*) ()) &rdir_cfg);
  167.       dosbusy_fl = getdosbusy ();
  168.       keep (Ok, prgsize ());
  169.       }
  170.  
  171.    return (NotOk);
  172. }
  173.  
  174. /* prgsize ()
  175.  *
  176.  * Calculates the program size by looking at __brklvl which is set to
  177.  * the end of initialized and uninitialized data whithin the data segment
  178.  * at program startup.  __brklvl is then changed as memory space is
  179.  * malloc'd.  __brklvl is decremented as malloc'd areas are free'd.
  180.  *
  181.  *   ** This function should work in Tiny, Small, and Meduim models **
  182.  */
  183.  
  184. unsigned prgsize ()
  185. {
  186.    extern unsigned __brklvl;     /* current top of heap == sbrk (0) */
  187.    extern unsigned _psp;         /* lowest segment address occupied */
  188.  
  189.    return (_DS + (__brklvl + 15) / 16 - _psp);
  190. }
  191.  
  192. /* exit ()
  193.  *
  194.  * Rewrite exit for memory conservation.  This exit () does not close files
  195.  * or flush buffers, which is fine in this case because we have no open
  196.  * files or buffers which need to be flushed.
  197.  *
  198.  */
  199. void exit (status)
  200.    int status;
  201. {
  202.    _exit (status);
  203. }
  204.  
  205. /* getdosbusy ()
  206.  *
  207.  * Gets the Dos busy flag through interrupt 34h.  This Dos function returnes
  208.  * the busy flag address in es:bx.  This is an UNDOCUMENTED feature of Dos,
  209.  * however it has worked in Dos versions 2.11 - 3.30 for me.
  210.  */
  211. char far * getdosbusy ()
  212. {
  213.    struct SREGS sregs;        /* segment registers */
  214.    union REGS regs;           /* normal registers */
  215.  
  216.    regs.h.ah = 0x34;          /* get dos busy flag address (UNDOCUMENTED) */
  217.    intdosx (®s, ®s, &sregs);
  218.    return (MK_FP (sregs.es, regs.x.bx));
  219. }
  220.  
  221. /* timer_handler ()
  222.  *
  223.  * This function intercepts the hardware timer interrupt.  It checks the
  224.  * request flag set by the keyboard handler and if set pops the directory
  225.  * function up only if it is currently "safe" to do so.
  226.  */
  227. void interrupt timer_handler ()
  228. {
  229.    static int in_fl = 0;
  230.  
  231.    /* if the following statement is NOT coded, the 8259 blocks all hardware
  232.       interrupts including the keyboard interrupt.  Since we wait for a key
  233.       in list_directory (), this causes the PC to lock up.  This one took
  234.       a while to figure out */
  235.    outportb (0x20, 0x20);        /* send eoi to 8259 */
  236.  
  237.    if (! in_fl)
  238.       {
  239.       in_fl = 1;                 /* we are in our ISR */
  240.       if (request_fl == 1)       /* has there been a request for popup? */
  241.          if (! *dosbusy_fl && ! biosbusy_fl)
  242.             list_directory ();   /* call the directory lister */
  243.          else
  244.             do_click ();         /* click to let user know we are trying */
  245.       in_fl = 0;
  246.       }
  247.  
  248.    (*old_timer) ();           /* chain to previous timer handler */
  249.    return;                    /* return from ISR */
  250. }
  251.  
  252. /* do_click ()
  253.  *
  254.  * I guess I got lazy here.  I wanted to just output a short click like
  255.  * sidekick does when it can't pop up because Dos is busy.  At any rate,
  256.  * the function is here if I want to implement that type of thing.
  257.  */
  258. void do_click ()
  259. {
  260. }
  261.  
  262. /* special_handler ()
  263.  *
  264.  * This interrupt is called from Dos at times when it is "safe" to use Dos
  265.  * functions.  It seems to be called constantly when waiting for keystrokes
  266.  * at the Dos prompt.  Here, we don't have to check the Dos busy flag
  267.  * because it is ALWAYS ok to call Dos from this point.
  268.  */
  269. void interrupt special_handler ()
  270. {
  271.    static int in_fl = 0;
  272.  
  273.    (*old_special) ();         /* chain to previous int 28 handler */
  274.  
  275.    if (! in_fl)
  276.       {
  277.       in_fl = 1;                 /* we are in our ISR */
  278.       if (request_fl == 1)       /* see if rdir has been requested */
  279.          list_directory ();      /* ok, list the directory */
  280.       in_fl = 0;
  281.       }
  282.    return;
  283. }
  284.  
  285. /* keyboard_handler ()
  286.  *
  287.  * This is what starts the whole ball rolling!  First we call the old
  288.  * keyboard handler, then check for our hot key.  If our hot key has been
  289.  * pressed, we toggle our internal request flag.  Next, if the request
  290.  * flag is set and it is safe to enter dos, we call the directory lister.
  291.  * If Dos is busy, this request must be handled by either the timer interrupt
  292.  * or the special int 28h interrupt
  293.  */
  294. void interrupt keyboard_handler ()
  295. {
  296.    static int in_fl = 0;
  297.  
  298.    (*old_keyboard) ();
  299.  
  300.    if (! in_fl)
  301.       {
  302.       in_fl = 1;
  303.       if (Hot_Combo && request_fl != 2)
  304.          request_fl = ! request_fl;
  305.  
  306.       if (request_fl == 1 && ! *dosbusy_fl && ! biosbusy_fl) 
  307.          list_directory ();
  308.       in_fl = 0;
  309.       }
  310.  
  311.    return;
  312. }
  313.  
  314. /* critical_handler ()
  315.  *
  316.  * This is only active while in list_directory ().  Its purpose is to avoid
  317.  * the possibility of the user entering a pattern on a floppy drive with
  318.  * no floppy in the drive.  If we did not trap this interrupt, Dos could
  319.  * terminate our TSR which would probably crash the system.
  320.  */
  321. int critical_handler ()
  322. {
  323.    return (0);                /* ignore the error */
  324. }
  325.  
  326. /* break_handler ()
  327.  *
  328.  * Again, this is only active when in list_directory ().  The purpose is
  329.  * the same as critical_handler () except we are trapping the BIOS Ctrl_Brk
  330.  * key.
  331.  */
  332. void interrupt break_handler ()
  333. {
  334.    return;                    /* ignore the break */
  335. }
  336.  
  337. /* list_directory ()
  338.  *
  339.  * This is the actual routine which lists the directory.  It can be called
  340.  * by either the keyboard_handler (), timer_handler (), or the
  341.  * special_handler ().  It does not care which.  While looking at this code
  342.  * you may notice the heavy use of global variables instead of autos; this
  343.  * is becuase we my be popped up from somewhere in DOS... we are using the
  344.  * default (current) stack and we don't know how much there is, therefore
  345.  * we should use as little as possible!
  346.  */
  347. void list_directory ()
  348. {
  349.    request_fl = 2;            /* currently servicing the request */
  350.  
  351.    /* save and set critical error handler */
  352.    old_critical = getvect (Critical);
  353.    harderr (critical_handler);
  354.  
  355.    /* save and set ctrl-break handler */
  356.    old_break = getvect (Break);
  357.    setvect (Break, break_handler);
  358.  
  359.    /* save and set the disk transfer address */
  360.    old_dta = getdta ();
  361.    setdta ((char far *) &ffblk);
  362.  
  363.    set_screen ();
  364.    while (get_pattern (), key != Escape_Key)
  365.       {
  366.       attrib = (key == Enter_Key ? FA_HIDDEN | FA_SYSTEM : FA_HIDDEN |
  367.          FA_SYSTEM | FA_DIREC);
  368.       entries_to_skip = 0;    /* start at beginning of dir list */
  369.       current_entry = -1;     /* have to do a find first */
  370.       display_entries ();
  371.  
  372.       do
  373.          {
  374.          key = getkey ();
  375.          switch (key)
  376.             {
  377.             case Page_Up_Key:
  378.                if (entries_to_skip - Per_Screen >= 0)
  379.                   {
  380.                   current_entry = -1;
  381.                   entries_to_skip -= Per_Screen;
  382.                   display_entries ();
  383.                   }
  384.                break;
  385.  
  386.             case Page_Dn_Key:
  387.                if (status == 0)
  388.                   {
  389.                   entries_to_skip += Per_Screen;
  390.                   display_entries ();
  391.                   }
  392.                break;
  393.             }
  394.          }
  395.       while (key != Escape_Key);
  396.       }
  397.  
  398.    /* restore critical error handler, break handler and dta address */
  399.    setvect (Critical, old_critical);
  400.    setvect (Break, old_break);
  401.    setdta (old_dta);
  402.  
  403.    /* restore the screen, and cursor position */
  404.    sc_resbox (Box_Row, Box_Col, Box_Hgt, Box_Wdth, box_buf);
  405.    sc_setpos (old_row, old_col);
  406.  
  407.    /* request has been filled, and now no request is active */
  408.    request_fl = 0;            /* no request made */
  409. }
  410.  
  411. /* set_screen ()
  412.  *
  413.  * This function sets up the initial screen for list_directory ()
  414.  */
  415. void set_screen ()
  416. {
  417.    /* save area on screen */
  418.    sc_savbox (Box_Row, Box_Col, Box_Hgt, Box_Wdth, box_buf);
  419.    sc_rptpos (&old_row, &old_col);
  420.  
  421.    /* draw our box */
  422.    sc_repvca (Box_Row + 1, Box_Col, '\xb3', Box_Hgt - 2,  Box_Attr);
  423.    sc_repvca (Box_Row + 1, Box_Col + Box_Wdth - 1, '\xb3', Box_Hgt - 2,
  424.       Box_Attr);
  425.    sc_rephca (Box_Row + Box_Hgt - 1, Box_Col + 1, '\xc4', Box_Wdth - 2,
  426.       Box_Attr);
  427.    sc_putca (Box_Row, Box_Col, '\xda', Box_Attr);
  428.    sc_putca (Box_Row, Box_Col + Box_Wdth - 1, '\xbf', Box_Attr);
  429.    sc_putca (Box_Row + Box_Hgt - 1, Box_Col, '\xc0', Box_Attr);
  430.    sc_putca (Box_Row + Box_Hgt - 1, Box_Col + Box_Wdth - 1, '\xd9', Box_Attr);
  431. }
  432.  
  433. /* get_pattern ()
  434.  *
  435.  * This gets the pattern from the user.  The result is put in the global
  436.  * variable pattern.  The only editing key is backspace.
  437.  */
  438. void get_pattern ()
  439. {
  440.    static int pos;
  441.    static char * ptr;
  442.  
  443.    for (pos = Box_Row + 1; pos < Box_Row + Box_Hgt - 1; pos++)
  444.       sc_rephca (pos, Box_Col + 1, ' ', Box_Wdth - 2, Norm_Attr);
  445.    sc_rephca (Box_Row, Box_Col + 1, ' ', Box_Wdth - 2, Box_Attr);
  446.    pos = Box_Col + 2;
  447.    ptr = pattern;
  448.    *ptr = '\0';
  449.    do
  450.       {
  451.       sc_setpos (Box_Row, pos);
  452.       key = getkey (0);
  453.       switch (key)
  454.          {
  455.          case BackSpace_Key:
  456.             if (pos > Box_Col + 2)
  457.                {
  458.                pos--;
  459.                sc_putca (Box_Row, pos, ' ', Box_Attr);
  460.                *ptr-- = '\0';
  461.                }
  462.             break;
  463.  
  464.          case Escape_Key:
  465.          case Enter_Key:
  466.          case Ctrl_Enter_Key:
  467.             break;
  468.  
  469.          default:
  470.             if (key >= 32 && key <= 127 && pos < Pat_Size + Box_Col + 2)
  471.                {
  472.                sc_putca (Box_Row, pos, key, Box_Attr);
  473.                pos++;
  474.                *ptr++ = key;
  475.                *ptr = '\0';
  476.                }
  477.             break;
  478.          }
  479.       }
  480.    while (key != Escape_Key && key != Enter_Key && key != Ctrl_Enter_Key);
  481.  
  482.    /* if they didn't type anything, or the last character was a directory
  483.       separator, or a drive specifier, make the pattern *.* */
  484.    if (pattern[0] == '\0' || *(--ptr) == '\\' || *ptr == '/' || *ptr == ':')
  485.       strcat (pattern, "*.*");
  486. }
  487.  
  488. /* display_entries ()
  489.  *
  490.  * Displays or redisplays the directory entries.
  491.  */
  492. void display_entries ()
  493. {
  494.    static int entries_to_display;
  495.    static int row;
  496.    static int col;
  497.    static int attr;
  498.    static int len; 
  499.  
  500.    entries_to_display = Per_Screen;
  501.    row = Box_Row + 1;
  502.    col = Box_Col + 1;
  503.  
  504.    /* First skip to the start of the current page */
  505.    while (current_entry < entries_to_skip)
  506.       find_entry ();
  507.  
  508.    /* For every possible entry on the screen: either display the filename
  509.       or display blanks */
  510.    while (entries_to_display--)
  511.       {
  512.       if (! status)
  513.          {
  514.          attr = Norm_Attr;
  515.          if (ffblk.ff_attrib & FA_DIREC)
  516.             attr = Dir_Attr;
  517.          sc_putsa (row, col, ffblk.ff_name, attr);
  518.          len = strlen (ffblk.ff_name);
  519.          sc_rephca (row, col + len, ' ', Name_Size - len, attr);
  520.          find_entry ();
  521.          }
  522.       else
  523.          sc_rephca (row, col, ' ', Name_Size, Norm_Attr);
  524.       if (++row > Box_Row + Box_Hgt - 2)
  525.          col += Box_Incr, row = Box_Row + 1;
  526.       }
  527. }
  528.  
  529. /* find_entry ()
  530.  *
  531.  * Finds the next entry based on the current entry.  If current entry is
  532.  * -1 then a findfirst () is assumed to be needed, else a findnext () is
  533.  * executed.
  534.  */
  535. void find_entry ()
  536. {
  537.    if (current_entry == -1)
  538.       status = findfirst (pattern, &ffblk, attrib);
  539.    else
  540.       status = findnext (&ffblk);
  541.    current_entry++;
  542. }
  543.  
  544. /* The following functions are used to write to the screen.  They do write
  545.    directly to screen RAM so they will cause "snow" on some CGA systems */
  546.  
  547. /* sc_putsa ()
  548.  *
  549.  * Write a string with the given attribute at row, col
  550.  */
  551. void sc_putsa (row, col, string, attr)
  552.    int row;
  553.    int col;
  554.    register char * string;
  555.    int attr;
  556. {
  557.    /* calculate pointer to screen RAM */
  558.    ptr = sc_cca (row, col);
  559.  
  560.    /* write each of the characters in string to the screen RAM */
  561.    while (*string)
  562.       {
  563.       *ptr++ = *string++;           /* write the character */
  564.       *ptr++ = attr;                /* write the attribute */
  565.       }
  566. }
  567.  
  568. /* sc_putca ()
  569.  *
  570.  * Write a single character with the specified attribute, at row, col
  571.  */
  572. void sc_putca (row, col, ch, attr)
  573.    int row;
  574.    int col;
  575.    char ch;
  576.    int attr;
  577. {
  578.    /* calculate pointer to screen RAM */
  579.    ptr = sc_cca (row, col);
  580.  
  581.    *ptr++ = ch;
  582.    *ptr = attr;
  583. }
  584.  
  585. /* sc_repvca ()
  586.  *
  587.  * Repeat the given character length times with the specified attribute
  588.  * starting from row, col in a vertical direction.
  589.  */
  590. void sc_repvca (row, col, ch, length, attr)
  591.    int row;
  592.    int col;
  593.    char ch;
  594.    int attr;
  595. {
  596.    /* calculate pointer to screen RAM */
  597.    ptr = sc_cca (row, col);
  598.    next_line = 80 * 2 - 2;
  599.  
  600.    while (length--)
  601.       {
  602.       *ptr++ = ch;            /* write the character */
  603.       *ptr++ = attr;          /* write the attribute */
  604.       ptr += next_line;       /* move to the next line */
  605.       }
  606. }
  607.  
  608. /* sc_rephca ()
  609.  *
  610.  * Repeat the given character length times with the specified attribute
  611.  * starting from row, col in a horizontal direction.
  612.  */
  613. void sc_rephca (row, col, ch, length, attr)
  614.    int row;
  615.    int col;
  616.    char ch;
  617.    int length;
  618.    int attr;
  619. {
  620.    /* calculate pointer to screen RAM */
  621.    ptr = sc_cca (row, col);
  622.  
  623.    while (length--)
  624.       {
  625.       *ptr++ = ch;        /* write the character */
  626.       *ptr++ = attr;      /* write the attribute */
  627.       }
  628. }
  629.  
  630. /* sc_savbox ()
  631.  *
  632.  * Saves the screen image into buf.  Row, col specify the upper left hand
  633.  * corner of the box, height and width specify the number of rows and
  634.  * columns to save.
  635.  */
  636. void sc_savbox (row, col, height, width, buf)
  637.    int row;
  638.    int col;
  639.    int height;
  640.    int width;
  641.    char * buf;
  642. {
  643.    /* calculate pointer to screen RAM */
  644.    ptr = sc_cca (row, col);
  645.  
  646.    buf_pos = (char far *) buf;
  647.    width *= 2;
  648.  
  649.    while (height--)          /* while we still have rows to do */
  650.       {
  651.       movedata (FP_SEG (ptr), FP_OFF (ptr), FP_SEG (buf_pos), FP_OFF
  652.          (buf_pos), width);
  653.       buf_pos += width;
  654.       ptr += 160;
  655.       }
  656. }
  657.  
  658. /* sc_resbox ()
  659.  *
  660.  * Performs the opposite function of sc_savbox ()
  661.  */
  662. void sc_resbox (row, col, height, width, buf)
  663.    int row;
  664.    int col;
  665.    int height;
  666.    int width;
  667.    char * buf;
  668. {
  669.    ptr = sc_cca (row, col);
  670.    width *= 2;
  671.    buf_pos = (char far *) buf;
  672.  
  673.    while (height--)
  674.       {
  675.       movedata (FP_SEG (buf_pos), FP_OFF (buf_pos), FP_SEG (ptr), FP_OFF
  676.          (ptr), width);
  677.       buf_pos += width;
  678.       ptr += 160;
  679.       }
  680. }
  681.  
  682. /* sc_rptpos ()
  683.  *
  684.  * Reports the current cursor row and column values.  These values are
  685.  * placed in the integers which are pointed at by row and col.   I had to
  686.  * use my own intvid () routine here instead of int86 because int86 reserves
  687.  * some space on the stack for temporary vars.  It also assumes that the
  688.  * current ss (stack segment) is the same as ds (data segment).  This is
  689.  * not true in this case, so they end up writing to random places in memory
  690.  * and usually crash the machine.  Be carefull with using library routines
  691.  * within an ISR.
  692.  */
  693. void sc_rptpos (row, col)
  694.    register int * row;
  695.    register int * col;
  696. {
  697.    regs.h.ah = 3;
  698.    regs.h.bh = Display_Page;
  699.    intvid (®s, 1); 
  700.    *row = regs.h.dh;
  701.    *col = regs.h.dl;
  702. }
  703.  
  704.  
  705. /* sc_setpos ()
  706.  *
  707.  * Sets the cursor positon at row, col.
  708.  */
  709. void sc_setpos (row, col)
  710.    register int row;
  711.    register int col;
  712. {
  713.    regs.h.ah = 2;
  714.    regs.h.dh = row;
  715.    regs.h.dl = col;
  716.    regs.h.bh = Display_Page;
  717.    intvid (®s, 0); 
  718. }
  719.  
  720.  
  721. /* sc_cca ()
  722.  *
  723.  * Calculates a far pointer into screen RAM based on row, col.
  724.  */
  725. char far * sc_cca (row, col)
  726.    int row;
  727.    int col;
  728. {
  729.    return (Screen_Ram + row * 160 + col * 2);
  730. }
  731.  
  732. /* getkey ()
  733.  *
  734.  * Gets a single key from the keyboard (waits for one if necessary).  If the
  735.  * key is a special key (low byte is 0) the returned value is 256 plus
  736.  * the scan code (high byte).  If it is normal key, just the ASCII code is
  737.  * returned
  738.  */
  739. int getkey ()
  740. {
  741.    static unsigned key;
  742.  
  743.    key = bioskey (0);
  744.    if (! (key & 0xff))
  745.       key = (key >> 8) | 256;
  746.    else
  747.       key = key & 0xff;
  748.    
  749.    return (key);
  750. }
  751.  
  752.