home *** CD-ROM | disk | FTP | other *** search
/ The C Users' Group Library 1994 August / wc-cdrom-cusersgrouplibrary-1994-08.iso / listings / v_02_09 / 2n09034a < prev    next >
Text File  |  1991-08-07  |  16KB  |  470 lines

  1. /**********************************************************
  2.  * MENUC.CTL - Allows you to dynamically change your       *
  3.  * CONFIG.SYS  configuration at boot time.                *
  4.  *                                                        *
  5.  * Add DEVICE = MENUC.CTL [Mx Tx "Text] to your CONFIG.SYS *
  6.  * just ahead of the first group of commands  you wish to *
  7.  * be able to menu.  The x in Tx is the seconds MENUC.CTL  *
  8.  * will pause for a keystroke before booting normally.    *
  9.  * x defaults to zero.  The x in Mx is the default menu   *
  10.  * number (1-8) that will be selected in a normal boot.   *
  11.  * x defaults to one.  The text after the " will be the   *
  12.  * first menu title.  All text after the " will be        *
  13.  * considered part of the title, so it must be the last   *
  14.  * parameter on the line.  The first title can be         *
  15.  * specified this way, or by putting the following        *
  16.  * construct immediately after the DEVICE=MENUC.CTL        *
  17.  *                                                        *
  18.  * Add DEVICE = MTITLE [Text] to give the boot menu       *
  19.  * selection a title to put on the screen.  Each          *
  20.  * MTITLE [Text] (up to * eight) will create a new menu   *
  21.  * selection.                                             *
  22.  *                                                        *
  23.  * Add DEVICE = MENUEND after the last command you wish   *
  24.  * to be able to menu.  MENUEND (like MTITLE) is a dummy  *
  25.  * device and must appear in CONFIG.SYS in order for      *
  26.  * MENUC.CTL to operate.                                   *
  27.  *********************************************************/
  28.  
  29. #include "GENERAL.H"
  30. #include "LIB.H"
  31.  
  32. typedef   struct {        /* The static part of a device */
  33.   BYTE    HEADER_LENGTH;  /* drivers request header. */
  34.   BYTE    UNIT_CODE;      /* See "Writing MS-DOS Device */
  35.   BYTE    COMMAND_CODE;   /* Drivers" by Robert S. Lai  */
  36.   WORD    STATUS;
  37.   double  RESERVED;
  38. } RQ_Header;
  39. typedef   struct {        /* The dynamic part of the    */
  40.   RQ_Header HEADER;       /* "INITIALIZE" request       */
  41.   BYTE      UNITS;        /* header to a device driver  */
  42.   WORD      *ENDING_OFFSET;
  43.   WORD      ENDING_SEGMENT;
  44.   char      far *ARGUMENTS;
  45. } Init_Header;
  46. typedef   struct {         /* Structure to keep track   */
  47.   WORD    str_len;         /* of location of Config.SYS */
  48.   char    menu;            /* commands to be dealt with */
  49.   char far *start;
  50. } Cmd_Rec;
  51.  
  52.  
  53. #define Last_Record -1
  54.         /* flag to indicate last cmd to process */
  55. #define row_start 9       /* menu start location */
  56. #define col_start 12
  57. #define normal    0x07    /* norman and inverse video */
  58. #define inverse   0x70    /* colors */
  59.  
  60. BYTE   row;     /* variables for screen positioning */
  61. BYTE   col;
  62.  
  63. extern WORD MENU_CTL_END;
  64.        /* end of resident portion of device driver */
  65. WORD   DOS_VERSION;
  66. extern Cmd_Rec _ENDDATA;
  67.        /* free memory location for dynamic allocation */
  68. Cmd_Rec near *MyStorage = &_ENDDATA;
  69.         /* set pointer to free memory */
  70. Cmd_Rec *Cmds;
  71.         /* make it a pointer to Config.Sys commands */
  72. void leave(void);     /* device driver exit point */
  73. void clean_up(void);
  74.      /* disable non selected Config.SYS commands */
  75. char far *make_coff(char far *Buf);
  76.      /* routine to convert non selected Config.Sys *
  77.       * commands to BREAK = OFF                    */
  78. void set_menu(BYTE m);    /* setup menu select text */
  79. void display_far(char far *Buf); /* display a far string */
  80. void xlat_ch(char test); /* make control chars visible */
  81. void menu_name(BYTE cmd);
  82. extern Init_Header far *REQUEST_OFFSET;
  83.        /* pointer to Device Request Header */
  84. BYTE   far *M_Buffer;   /* some global variables */
  85. BYTE   far *Buf_Start;
  86. BYTE   far *Control_End;
  87. BOOL   end_found = FALSE;
  88.        /* make sure there is a "DEVICE=MENUEND" */
  89. BOOL   modified;
  90.        /* flag to indicate display screen needs update */
  91.  
  92. WORD   key = 0;  /* keeps track of keyboard entry */
  93. WORD   junk;
  94. WORD   time = 0; /* default time and menu selection */
  95. BYTE   menu = 0;
  96. WORD   configs;  /* number of menus */
  97. char   test;     /* local char for testing */
  98. char   menu_end[] = "DMENUEND";
  99.        /* Used to find "DEVICE=MENUEND" */
  100. #define l_menuend sizeof(menu_end) - 1
  101. char   bmenu[] = "DMTITLE";
  102.        /* Used to find "DEVICE=MTITLE" */
  103. #define l_bmenu  sizeof(bmenu) - 1
  104. char   menut[7][70];
  105.        /* store the titles for upto 8 selections */
  106.  
  107.  
  108. // #define Debug = TRUE;
  109.  
  110. void main(void) {
  111.   WORD i;
  112.   BYTE j;
  113.   BYTE k;
  114.   BYTE m;
  115.  
  116.   REQUEST_OFFSET->ENDING_OFFSET = 0;
  117.   REQUEST_OFFSET->ENDING_SEGMENT = _CS;
  118.     /* tell MS-Dos where our resident portion ends */
  119.   M_Buffer = REQUEST_OFFSET->ARGUMENTS;
  120.     /* point to rest of Config.Sys Commands */
  121.   printstr("MENUC.CTL V1.0 (C) Dec. 6, 1990 by "
  122.            "Larry Weaver\n\r$");
  123.   /* print a start up line.  */
  124.   DOS_VERSION = dosversion(); /*get MS-Dos version number*/
  125.   if (DOS_VERSION < 0X200) {  /* must be greater than 2 */
  126.     printstr("Wrong Version of Dos, "
  127.               "requires 2X or greater\n\r$");
  128.     leave();
  129.   }
  130.   for (i=0;i < 8;i++) for (j=0;j < 2;j++) menut[i][j] = 0;
  131.     /* assume no menu selection titles */
  132.   for (;((*M_Buffer != LF) & (*M_Buffer != CR));M_Buffer++){
  133.  
  134. /* parse MENUC.CTL command line,  get default time, menu, *
  135.  * and title                                            */
  136.  
  137.     test = *M_Buffer;
  138.     #ifdef Debug
  139.     xlat_ch(test);
  140.     #endif
  141.     if (test == '"') { /* see if title 1 */
  142.       M_Buffer++;
  143.       for (j=1;(*M_Buffer != LF) & (*M_Buffer != CR);
  144.            M_Buffer++,j++) {
  145.         #ifdef Debug
  146.           xlat_ch(*M_Buffer);
  147.         #endif
  148.         menut[0][j] = *M_Buffer;
  149.       }
  150.       /* put text in menu array */
  151.       menut[0][j] = '\0';  /* add terminating 0 */
  152.       menut[0][0] = --j;     /* put length in first element */
  153.       break;
  154.     } else if (test == 'M') { /* see if default menu */
  155.       test = *(M_Buffer + 1);
  156.       if ((test > '0') & (test < '9')) menu = test - '1';
  157.     } else if (test == 'T') { /* see if default time */
  158.       test = *(M_Buffer + 1);
  159.       if ((test > '/') & (test < ':')) time = test - '0';
  160.     }
  161.   }
  162.   while ((*M_Buffer == CR) | (*M_Buffer == LF)) {
  163.     /* go to next command */
  164.     #ifdef Debug
  165.     xlat_ch(*M_Buffer);
  166.     #endif
  167.     M_Buffer++;
  168.   }
  169.   m = 0;
  170.   if (cmpsnf(M_Buffer,bmenu,l_bmenu)) {
  171.     /* see if next command is "DEVICE=MTITLE", if it is *
  172.      * set up title for menu 1                         */
  173.     #ifdef Debug
  174.       display_far(M_Buffer);
  175.     #endif
  176.     set_menu(m);
  177.   }
  178.   Buf_Start = M_Buffer;
  179.   i = 0;
  180.   while (!end_found) {
  181.  
  182. /* parse rest of Config.Sys commands looking for          *
  183.  * "DEVICE=MENUEND".  Will turn all unrecognized commands *
  184.  * into "BREAK=OFF" commands in the process.  Also parses *
  185.  * rest of menus, and sets up their titles for later      *
  186.  * selection.                                            */
  187.  
  188.     for (;(*M_Buffer == CR) | (*M_Buffer == LF);M_Buffer++) {
  189.       #ifdef Debug
  190.         xlat_ch(*M_Buffer);
  191.       #endif
  192.     }
  193.     test = *M_Buffer;
  194.     #ifdef Debug
  195.       display_far(M_Buffer);
  196.     #endif
  197.     Control_End = M_Buffer;
  198.     Cmds = MyStorage + i;
  199.     if (test == 'D') {
  200.       end_found = cmpsnf(M_Buffer,menu_end,l_menuend);
  201.       /*  check for "DEVICE=MENUEND" */
  202.       if (end_found) {
  203.         make_coff(M_Buffer);
  204.         /* deactivate the command line */
  205.         Cmds->menu = Last_Record;
  206.         break;
  207.       } else if (cmpsnf(M_Buffer,bmenu,l_bmenu)) {
  208.         /* check for "DEVICE=MTITLE".  If too many titles *
  209.          * then select menu 1 and leave.                 */
  210.         if (m < 7) {
  211.           set_menu(++m);
  212.           continue;
  213.         } else {
  214.           printstr("Too many menu selections.  Must be less"
  215.                    " than 9!\n\rHit any key to continue!$");
  216.           junk = get_key();
  217.           printstr("\n\r$");
  218.           set_menu(++m);
  219.           key = EnterKey;
  220.           menu = 0;
  221.           Cmds->menu = Last_Record;
  222.           clean_up();
  223.           leave();
  224.         }
  225.       }
  226.     }
  227.     Cmds->start = M_Buffer;
  228.     for (j=0;(*M_Buffer != CR) & (*M_Buffer != LF);
  229.          j++,M_Buffer++);
  230.     if (test == 'Z') {
  231.       if (DOS_VERSION >= DOS4) *Cmds->start = '0';
  232.       /* deactivate all "Unrecognized" commands. */
  233.       /* Dos 4 Config.Sys has a "REM" capability, so we *
  234.        * use it instead of "BREAK=OFF"                 */
  235.       else if (j > 4) {
  236.         make_coff(Cmds->start);
  237.       }
  238.     } else if ((test != -1) & (test != '0'))
  239.       /* don't mess with things Dos has already processed */
  240.       if (j != 0)  {
  241.         Cmds->menu = m;
  242.         i++;
  243.         Cmds->str_len = j;
  244.         /* store the string length (COFF control) */
  245.       }
  246.     if (!((WORD) M_Buffer)) break;
  247.     /* can't process more than 64K */
  248.     if ((WORD) Cmds > 0xF000) break;
  249.     /* could start interfering with the stack, should *
  250.      * never be this big.                            */
  251.   }
  252.   #ifdef Debug
  253.     while (!chk_key());
  254.   #endif
  255.   delay_1();
  256.   if (!end_found) {
  257.  
  258. /* Didn't find DEVICE=MENUEND in the Config.Sys file.     *
  259.  * Don't process any more commands, just print an error   *
  260.  * message and leave                                     */
  261.  
  262.     if (chk_key()) key = get_key();
  263.     if (key == EscKey) key = 0;
  264.     if (time | key) {
  265.       printstr("DEVICE = MENUEND has to be added as a "
  266.                "terminating\r\n"
  267.                "command in CONFIG.SYS before MENUC.CTL "
  268.                "can function.\r\n"
  269.                "Press and key to continue.$");
  270.       get_key();
  271.     }
  272.     leave();
  273.   }
  274.   if (time) {
  275.     /* if default time not = 0, then give chance to hit a   *
  276.      * key.  Max time is 9 seconds, then process continues. *
  277.      * If ESC key is hit, process continues immediately.   */
  278.     printstr("\n\r\rPress any key if you wish to modify the\n\r"
  279.              "CONFIG.SYS configuration.\n\r"
  280.               "Press Esc for quick bypass of MENUC.CTL.\n\r\r$");
  281.     for (;time;time--) {
  282.       if (!chk_key()) delay_1();
  283.       else {
  284.         key = get_key();
  285.         break;
  286.       }
  287.     }
  288.   } else if (chk_key()) key = get_key();
  289.   if (key == EscKey) key = 0;
  290.   /* if no key hit in time, then select default and leave */
  291.   if (!key) {
  292.     if (menu > m) menu = 0; /* default menu exist? */
  293.     clean_up();
  294.   }
  295.   key = 0;
  296.   cls();
  297.   /* someone hit a key, set up the menus, and allow the */
  298.   /* operator to select one. */
  299.   printstr("Press Up/Down arrow keys to select highlighted"
  300.            " configuration\r\n"
  301.            "Press Enter to accept configuration "
  302.            "and exit.\r\n"
  303.            "Press Alt-X to deactivate all configurations "
  304.            "and exit\r\n"
  305.            "Note: Permanent changes are not made to the "
  306.            "CONFIG.SYS file.\r\n\n$");
  307.  
  308.   if (menu > (m)) { /* Does default menu exist? */
  309.     printstr("Menu$ ");
  310.     w_tty(menu+0x31);
  311.     printstr(" doesn't exist.  Default set to Menu 1 "
  312.              "(see AltX).$");
  313.     menu = 0;
  314.   }
  315.   if (i) { /* anything to pick from ? */
  316.     configs = m;
  317.     row = row_start;
  318.     col = 0;
  319.     for (m=0;m <= configs;m++,row++) {
  320.       /* print menu titiles on screen */
  321.       set_curs(row,col);
  322.       menu_name(m);
  323.       fputsh(&menut[m][1]);
  324.     }
  325.   } else leave(); /* no, go home */
  326.   m = 0;
  327.  
  328.   row = row_start + menu;
  329.   col = col_start;
  330.   modified = TRUE;
  331.   while ((key != EscKey) & (key != EnterKey)&(key!=AltX)) {
  332.  
  333.     /* Allow arrowing through menu titles.  Show current  *
  334.      * with -->, and Hi-Lited text (if any).             */
  335.  
  336.     if (modified) {
  337.       set_curs(row,0);
  338.       printstr("--> $");
  339.       hi_lite(row, col, inverse, menut[row - row_start][0]);
  340.       modified = FALSE;
  341.     }
  342.     key = get_key();
  343.     switch (key) {
  344.       case AltX   :
  345.       case EnterKey :
  346.       case EscKey : break;
  347.       case DnArrow :
  348.       case UpArrow : {
  349.         modified = TRUE;
  350.         set_curs(row,0);
  351.         printstr("    $");
  352.         hi_lite(row, col=col_start ,normal,
  353.                 menut[row - row_start][0]);
  354.         if (key==DnArrow) {
  355.           if (++m <= configs) row++;
  356.           else { row = row_start; m=0; }
  357.           break;
  358.         }
  359.         if (m > 0) { row--; m--; }    /* down arrow */
  360.         else { m = configs; row = row_start + configs; }
  361.         break;
  362.       }
  363.       case PgDn    :
  364.       case PgUp    : {
  365.         modified = TRUE;
  366.         set_curs(row,0);
  367.         printstr("    $");
  368.         hi_lite(row,col=col_start,normal,
  369.                 menut[row_start - row][0]);
  370.         if (key==PgDn) {
  371.           m = configs;
  372.           row = row_start + configs;
  373.         }else {
  374.           m = 0;
  375.           row = row_start;
  376.         }
  377.         break;
  378.       }
  379.     }
  380.   }
  381.   if (key == EnterKey) menu = m;
  382.   clean_up();
  383. }
  384.  
  385. /*********************************************************
  386.  *     disable the non selected menu items, and leave    *
  387.  ********************************************************/
  388.  
  389. void clean_up() {
  390.   BYTE i;
  391.   for (i=0,Cmds=MyStorage;
  392.        (Cmds->menu != Last_Record);Cmds = MyStorage + i) {
  393.  
  394.     M_Buffer = Cmds->start;
  395.         #ifdef Debug
  396.           display_far(M_Buffer);
  397.         #endif
  398.     if ((key == AltX) | (Cmds->menu != menu)) {
  399.       if (DOS_VERSION >= DOS4) *M_Buffer = '0';
  400.       else if (Cmds->str_len < 5) {
  401.         *M_Buffer = 'Z';
  402.       } else make_coff(M_Buffer);
  403.     }
  404.         #ifdef Debug
  405.           display_far(M_Buffer);
  406.           junk = get_key();
  407.         #endif
  408.     i++;
  409.   }
  410.   leave(); /* return to DEVICE.ASM */
  411. }
  412.  
  413. /********************************************************
  414.  * disable the current config sys command by replacing  *
  415.  * it with "BREAK=OFF".                                 *
  416.  *******************************************************/
  417.  
  418. char far *make_coff(char far *Buf) {
  419.   Buf = Buf + movesnf(Buf,"COFF");
  420.   for (;(*Buf != CR) & (*Buf != LF);Buf++) *Buf = ' ';
  421.   return(Buf);
  422. }
  423. /*********************************************************
  424.  * Move the text pointed to by M_Buffer into the current *
  425.  * menu title                                            *
  426.  ********************************************************/
  427.  
  428. void set_menu(BYTE m) {
  429.   BYTE j;
  430.   char far *Buf;
  431.   Buf = M_Buffer + sizeof(bmenu); /* skip MTITLE */
  432.   for (;(*Buf == ' ');Buf++);   /* remove leading spaces */
  433.   for (j=1;(*Buf != CR) & (*Buf != LF);j++,Buf++)
  434.     menut[m][j] = *Buf; /* put text in menu array */
  435.   menut[m][j] = '\0';  /* add terminating 0 */
  436.   menut[m][0] = --j;     /* put length in first element */
  437.   M_Buffer = make_coff(M_Buffer);
  438.   /* deactivate the command */
  439. }
  440.  
  441.  
  442. void menu_name(BYTE cmd) {
  443.   switch (cmd) {
  444.     case  0 : { printstr("    Menu 1$"); break; }
  445.     case  1 : { printstr("    Menu 2$"); break; }
  446.     case  2 : { printstr("    Menu 3$"); break; }
  447.     case  4 : { printstr("    Menu 4$"); break; }
  448.     case  5 : { printstr("    Menu 5$"); break; }
  449.     case  6 : { printstr("    Menu 6$"); break; }
  450.     case  7 : { printstr("    Menu 7$"); break; }
  451.     case  3 : { printstr("    Menu 8$"); break; }
  452.     }
  453.   printstr("= $");
  454. }
  455.  
  456. #ifdef Debug
  457. void display_far(char far *Buf) {
  458.   for (;(*Buf != CR) & (*Buf != LF);Buf++) xlat_ch(*Buf);
  459. }
  460.  
  461. void xlat_ch(char test) {
  462.   if (test==0) fputsh("<0>"); else
  463.   if (test==CR) fputsh("<CR>\r\n"); else
  464.   if (test==LF) fputsh("<LF>\n\r"); else
  465.   if (test==SP) fputsh("<SP>"); else
  466.   if (test==BELL) fputsh("<BELL>"); else
  467.   w_tty(test);
  468. }
  469. #endif
  470.