home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 11 Util / 11-Util.zip / CONFIG.ZIP / CONFIG.C next >
Text File  |  1989-05-15  |  38KB  |  1,067 lines

  1. /*
  2.     CONFIG.C    OS/2 System Configuration Utility
  3.     Copyright (C) 1989 Ziff Davis Communications
  4.     PC Magazine * Ray Duncan
  5.  
  6.     Compile:    CL CONFIG.C
  7.  
  8.     Usage:      CONFIG <Enter>              edits CONFIG.SYS in root
  9.                                             directory of boot drive
  10.                 or
  11.  
  12.                 CONFIG <Filename> <Enter>   edits specified file
  13. */
  14.  
  15. #include <stdio.h>
  16. #include <stdlib.h>
  17. #include <string.h>
  18. #include <memory.h>
  19. #include <malloc.h>
  20.  
  21. #define TRUE    1                           // logical values
  22. #define FALSE   0
  23.  
  24. #define WAIT    0                           // parameters for KbdCharIn 
  25. #define NOWAIT  1
  26.  
  27. #define VISIBLE 0                           // parameters for VioSetCurType
  28. #define HIDDEN  -1  
  29.  
  30. #define BROWSE  0                           // possible program "modes"
  31. #define EDNAME  1
  32. #define EDVAL   2
  33.  
  34. #define ESC     0x1b                        // normal keycodes
  35. #define BS      0x08
  36. #define TAB     0x09
  37. #define ENTER   0x0d
  38. #define TILDE   0x7e
  39. #define BL      0x20
  40.  
  41. #define UP      0x48                        // extended key codes 
  42. #define DOWN    0x50                    
  43. #define RIGHT   0x4d
  44. #define LEFT    0x4b
  45. #define HOME    0x47
  46. #define END     0x4f
  47. #define CTRLEND 0x75
  48. #define INS     0x52
  49. #define DEL     0x53
  50. #define PGUP    0x49
  51. #define PGDN    0x51
  52. #define BACKTAB 0x0f
  53.  
  54. #define VBAR    0xb3                        // graphics characters
  55. #define HBAR    0xc4
  56. #define UPARROW 0x18
  57. #define DNARROW 0x19
  58. #define RTARROW 0x1a
  59. #define LTARROW 0x1b
  60.  
  61. #define MAXLN   256                         // maximum number of lines
  62.                                             // allowed in CONFIG.SYS
  63.  
  64. #define F0COL   0                           // field 0 starting column
  65. #define F1COL   6                           // field 1 starting column
  66. #define F2COL   21                          // field 2 starting column
  67.  
  68. #define API unsigned extern far pascal      // OS/2 function prototypes
  69.  
  70. API DosBeep(int, unsigned);
  71. API DosGetInfoSeg(unsigned far *, unsigned far *);
  72. API KbdCharIn(void far *, unsigned, unsigned);
  73. API VioGetCurType(void far *, unsigned);
  74. API VioGetMode(void far *, unsigned);
  75. API VioScrollUp(int, int, int, int, int, unsigned far *, unsigned);
  76. API VioScrollDn(int, int, int, int, int, unsigned far *, unsigned);
  77. API VioSetCurType(void far *, unsigned);
  78. API VioSetCurPos(int, int, unsigned);
  79. API VioReadCharStr(char far *, int far *, int, int, unsigned);
  80. API VioWrtCharStr(char far *, int, int, int, unsigned);
  81. API VioWrtCharStrAtt(char far *, int, int, int, char far *, unsigned);
  82. API VioWrtNAttr(char far *, int, int, int, unsigned);
  83.  
  84. void addline(void);                         // local function prototypes
  85. int  ask(char *);
  86. void blap(void);
  87. void blip(void);
  88. void changeline(void);
  89. void changename(void);
  90. void changeval(void);
  91. int  chkname(char *);
  92. void cls(void);
  93. void deleteline(void);
  94. int  editfile(void);
  95. void errexit(char *);
  96. void highlite(int);
  97. void insertline(void);
  98. void linedown(void);
  99. void lineup(void);
  100. void makestrings(void);
  101. void newline(void);
  102. void pagedown(void);
  103. void pageup(void);
  104. void readfile(void);
  105. void restore(void);
  106. void setcurpos(int, int);
  107. void setcurtype(int);
  108. void showline(int, int);
  109. void showpage(void);
  110. void showstatus(char *p);
  111. void signon(void);
  112. void writefile(void);
  113.  
  114. char iname[80];                             // name of input file 
  115. char oname[80];                             // name of output file 
  116. FILE *ifile;                                // input file stream
  117. FILE *ofile;                                // output file stream
  118.  
  119. struct _kbdinfo {                           // KbdCharIn info structure 
  120.     char charcode;                          // ASCII character code 
  121.     char scancode;                          // keyboard scan code 
  122.     char status;                            // misc. status flags 
  123.     char reserved1;                         // reserved byte 
  124.     unsigned shiftstate;                    // keyboard shift state 
  125.     long timestamp;                         // character timestamp 
  126.     } kbdinfo;
  127.  
  128. struct _modeinfo {                          // display mode information
  129.     int len;                                // length of structure 
  130.     char type;                              // display type 
  131.     char colors;                            // available colors 
  132.     int cols;                               // width of screen 
  133.     int rows;                               // height of screen 
  134.     } modeinfo;
  135.  
  136. struct _curinfo {                           // cursor information
  137.     int start;                              // starting line
  138.     int end;                                // ending line
  139.     int width;                              // width
  140.     unsigned attr;                          // attribute (visible/hidden)
  141.     } curinfo;
  142.  
  143. char *directives[] = {  
  144.     "",     
  145.     "BREAK",
  146.     "BUFFERS",      
  147.     "CODEPAGE",     
  148.     "COUNTRY",      
  149.     "DEVICE",       
  150.     "DEVINFO",      
  151.     "DISKCACHE",    
  152.     "FCBS",         
  153.     "IOPL",         
  154.     "LIBPATH",      
  155.     "MAXWAIT",      
  156.     "MEMMAN",       
  157.     "PAUSEONERROR", 
  158.     "PRIORITY",     
  159.     "PROTSHELL",    
  160.     "PROTECTONLY",  
  161.     "REM",          
  162.     "RMSIZE",       
  163.     "RUN",          
  164.     "SET",          
  165.     "SHELL",        
  166.     "SWAPPATH",     
  167.     "THREADS",      
  168.     "TIMESLICE",    
  169.     "TRACE",        
  170.     "TRACEBUF", };
  171.  
  172. int DIRMAX = sizeof(directives)/sizeof(directives[0]);
  173.  
  174. int totln;                                  // total lines in file
  175. int curln;                                  // line no. being edited 
  176. char *ln[MAXLN][2];                         // pointers to parsed directives
  177. char namestr[16];                           // working copy of name string
  178. char valstr[256];                           // working copy of value string
  179. int dirix;                                  // index to 'directives' array
  180. int valix;                                  // index to value string
  181.  
  182. int insflag;                                // TRUE=insert, FALSE=overwrite 
  183. int edmode;                                 // BROWSE, EDNAME, or EDVAL
  184.  
  185. int curx;                                   // cursor X coordinate 
  186. int cury;                                   // cursor Y coordinate 
  187. int lpp;                                    // lines per page 
  188. int lps;                                    // total rows on screen
  189. int cpl;                                    // columns per line
  190. int cstart;                                 // original cursor start line
  191.  
  192. unsigned normcell = 0x0720;                 // blank cell, normal video 
  193. unsigned revcell = 0x7020;                  // blank cell, reverse video 
  194. char normattr = 0x07;                       // normal (white on black)
  195. char revattr  = 0x70;                       // reverse (black on white)
  196.  
  197. char *copyright = "OS/2 Configuration Editor (C) 1989 Ziff Davis";
  198.  
  199. char format1[80];                           // format string for directives
  200. char format2[80];                           // format for filename line
  201.  
  202. char helpstr1[80];                          // help string, browse mode
  203. char helpstr2[80];                          // help string, name editing
  204. char helpstr3[80];                          // help string, value editing
  205. char *help[] = { helpstr1, helpstr2, helpstr3 };
  206.  
  207. main(int argc, char *argv[])
  208. {
  209.     unsigned gseg, lseg;                    // info segment selectors
  210.     char far *ginfo;                        // global info segment pointer
  211.  
  212.     if(argc < 2)                            // get name of file to edit
  213.     {                                       // else \CONFIG.SYS boot drive
  214.         strcpy(iname, "c:\\config.sys");
  215.         DosGetInfoSeg(&gseg, &lseg);        // get info segment selectors
  216.         (long) ginfo = (long) gseg << 16;   // make far pointer
  217.         iname[0] = ginfo[0x24]+'a'-1;       // boot drive into filename
  218.     }
  219.     else strcpy(iname, argv[1]);
  220.  
  221.     VioGetCurType(&curinfo, 0);             // get cursor information
  222.     cstart = curinfo.start;                 // save cursor start line
  223.  
  224.     modeinfo.len = sizeof(modeinfo);        // get display information
  225.     VioGetMode(&modeinfo, 0);
  226.     lps = modeinfo.rows;                    // rows on screen
  227.     lpp = modeinfo.rows-3;                  // lines per editing page
  228.     cpl = modeinfo.cols;                    // columns per line
  229.  
  230.     if(cpl < 80)                            // reject 40 column modes
  231.         errexit("Use display mode with at least 80 columns.");
  232.  
  233.     makestrings();                          // build format strings
  234.  
  235.     readfile();                             // read CONFIG.SYS file 
  236.  
  237.     signon();                               // display sign-on info
  238.  
  239.     if(editfile())                          // edit in-memory info
  240.  
  241.         writefile();                        // write modified file
  242.  
  243.     cls();                                  // clear screen and exit
  244. }
  245.  
  246. /* Edit the parsed in-memory copy of the CONFIG.SYS file */
  247.  
  248. int editfile(void)
  249. {
  250.     edmode = BROWSE;                        // initialize editing mode
  251.     setcurtype(edmode);                     // initialize cursor state
  252.     showpage();                             // display first page
  253.     showstatus(help[edmode]);               // and help line
  254.  
  255.     while(! KbdCharIn(&kbdinfo, WAIT, 0))
  256.     {
  257.         switch(toupper(kbdinfo.charcode))
  258.         {
  259.             case 'A':                       // add new line at
  260.                 addline();                  // end of file
  261.                 break;
  262.  
  263.             case 'C':                       // change current line
  264.                 changeline();
  265.                 break;
  266.         
  267.             case 'D':                       // delete current line
  268.                 deleteline();
  269.                 break;
  270.  
  271.             case 'I':                       // insert new line at 
  272.                 insertline();               // current line
  273.                 break;
  274.  
  275.             case 'R':                       // revert to original file
  276.                 if(ask("Revert to original file")) restore();
  277.                 break;
  278.  
  279.             case 'X':                       // exit, write file
  280.                 if(ask("Write modified file and exit")) return(TRUE);
  281.                 break;
  282.  
  283.             case ESC:                       // exit, don't write file
  284.                 if(ask("Quit without writing file")) return(FALSE);
  285.                 break;
  286.  
  287.             case 0:                         // extended keycodes
  288.             case 0xe0:
  289.                 switch(kbdinfo.scancode)
  290.                 {
  291.                     case HOME:              // go to start of file
  292.                         curln = 0;
  293.                         cury = 0;
  294.                         showpage();
  295.                         break;
  296.  
  297.                     case UP:                // move one line towards
  298.                         lineup();           // start of file
  299.                         break;
  300.  
  301.                     case DOWN:              // move one line towards
  302.                         linedown();         // end of file
  303.                         break;
  304.  
  305.                     case PGUP:              // move one page towards
  306.                         pageup();           // start of file
  307.                         break;
  308.  
  309.                     case PGDN:              // move one page towards
  310.                         pagedown();         // end of file
  311.                         break;
  312.  
  313.                     case END:               // go to end of file
  314.                         curln = totln-1;
  315.                         cury = min(lpp-1, totln-1);
  316.                         showpage();
  317.                         break;
  318.  
  319.                     default:                // unrecognized extended key
  320.                         blap(); 
  321.                 }
  322.                 break;
  323.  
  324.             default:                        // unrecognized normal key
  325.                 blap();
  326.         }
  327.     }
  328. }
  329.  
  330. /*
  331.     Add a new line at the end of file, allocating heap space for
  332.     two null strings: the directive's name and its value
  333. */
  334.  
  335. void addline(void)
  336. {
  337.     if(totln == MAXLN)                      // don't allow add operation
  338.     {                                       // if line array already full
  339.         blap();
  340.         return;
  341.     }
  342.  
  343.     curln = totln++;                        // move to end of file
  344.     newline();                              // create an empty line
  345.     cury = min(totln-1, lpp-1);             // adjust cursor position
  346.     showpage();                             // update display
  347.     changeline();                           // now edit the new line
  348. }
  349.  
  350. /*
  351.     Insert a new (empty) line before the current line, allocating heap
  352.     space for two null strings: the directive's name and its value
  353. */
  354.  
  355. void insertline(void)
  356. {
  357.     int i;                                  // scratch variable
  358.  
  359.     if(totln == MAXLN)                      // don't allow insert if
  360.     {                                       // line array already full
  361.         blap();
  362.         return;
  363.     }
  364.  
  365.     if(totln == 0)                          // if empty file, use
  366.     {                                       // the add new line 
  367.         addline();                          // routine instead
  368.         return;
  369.     }
  370.  
  371.     for(i = totln-1; i >= curln; i--)       // OK to insert...
  372.     {
  373.         ln[i+1][0] = ln[i][0];              // move current line and 
  374.         ln[i+1][1] = ln[i][1];              // subsequent lines down 
  375.     }
  376.  
  377.     totln++;                                // bump total line count
  378.     newline();                              // current becomes empty line
  379.     showpage();                             // update the display
  380.     changeline();                           // now edit the new line
  381. }
  382.  
  383. /*
  384.     Create a new (empty) line.  Heap space is allocated for
  385.     two null strings: the directive's name and its value
  386. */
  387.  
  388. void newline(void)
  389. {                                           // allocate space from heap
  390.     if(((ln[curln][0] = malloc(strlen("")+1)) == NULL) ||
  391.        ((ln[curln][1] = malloc(strlen("")+1)) == NULL))
  392.         errexit("out of heap space.");
  393.  
  394.     strcpy(ln[curln][0], "");               // assign null strings as
  395.     strcpy(ln[curln][1], "");               // initial name and value
  396. }
  397.  
  398. /* Change the name and/or value strings of the current line */
  399.  
  400. void changeline(void)
  401. {
  402.     char buff[256];                         // scratch buffer 
  403.     int i;                                  // scratch variable
  404.  
  405.     edmode = EDNAME;                        // start in name field
  406.     insflag = FALSE;                        // insert initially off
  407.  
  408.     memset(valstr, 0, sizeof(valstr));
  409.     strcpy(namestr, ln[curln][0]);          // make local copies of
  410.     strcpy(valstr, ln[curln][1]);           // name and value strings
  411.  
  412.     dirix = chkname(namestr);               // initialize name string index
  413.     valix = 0;                              // initialize value string index
  414.  
  415.     if(dirix<0)                             // if unrecognized name...
  416.     {
  417.         if(ask("Unknown directive.  Erase it"))
  418.         {
  419.             dirix = 0;                      // optionally zap out   
  420.             strcpy(namestr, "");            // the current line
  421.             strcpy(valstr, "");
  422.         }
  423.     }
  424.  
  425.     highlite(edmode);                       // position highlight
  426.     showstatus(help[edmode]);               // update help line
  427.  
  428.     while(TRUE)
  429.     {
  430.         i = max(0, valix-(cpl-F2COL-1));    // display current line
  431.         sprintf(buff, format1, curln+1, namestr, &valstr[i]);
  432.         VioWrtCharStr(buff, min(strlen(buff), cpl), cury, 0, 0);
  433.  
  434.         if(edmode == EDVAL)                 // position blinking cursor
  435.         {                                   // if editing value string
  436.             curx = min(F2COL+valix, cpl-1);
  437.             setcurpos(curx, cury);
  438.         }
  439.  
  440.         KbdCharIn(&kbdinfo, WAIT, 0);
  441.  
  442.         switch(kbdinfo.charcode)
  443.         {
  444.             case ESC:                       // Escape key
  445.                 if(! ask("Discard changes to this line")) break;
  446.                 edmode = BROWSE;
  447.                 showline(curln, cury);      // restore previous text
  448.                 setcurtype(edmode);         // hide blinking cursor
  449.                 highlite(edmode);           // highlight entire line 
  450.                 showstatus(help[edmode]);   // display help line
  451.                 return;
  452.  
  453.             case ENTER:                     // Enter key
  454.                 if(! ask("Accept changes to this line")) break;
  455.                 edmode = BROWSE;
  456.  
  457.                                             // copy new text to heap
  458.                 ln[curln][0] = realloc(ln[curln][0], strlen(namestr)+1);
  459.                 ln[curln][1] = realloc(ln[curln][1], strlen(valstr)+1);
  460.                 if((ln[curln][0] == NULL) || (ln[curln][1] == NULL))
  461.                     errexit("out of heap space.");
  462.                 strcpy(ln[curln][0], namestr);
  463.                 strcpy(ln[curln][1], valstr);   
  464.  
  465.                 showline(curln, cury);      // restore previous text
  466.                 setcurtype(edmode);         // hide blinking cursor
  467.                 highlite(edmode);           // highlight entire line 
  468.                 showstatus(help[edmode]);   // display help line
  469.                 return;
  470.  
  471.             case TAB:                       // tab key
  472.                 if((edmode == EDVAL) || (dirix <= 0)) blap();
  473.                 else                        // if not there already
  474.                 {               
  475.                     edmode = EDVAL;         // move to value field
  476.                     valix = 0;              // init. index to string
  477.                     curx = F2COL;           // set cursor position
  478.                     setcurpos(curx, cury);          
  479.                     setcurtype(edmode);     // and cursor appearance 
  480.                     highlite(edmode);       // highlight value field
  481.                     showstatus(help[edmode]);   // display help info
  482.                 }
  483.                 break;
  484.  
  485.             case 0:                         // extended key code
  486.             case 0xe0:
  487.                 if(kbdinfo.scancode == BACKTAB)
  488.                 {
  489.                     if(edmode == EDNAME) blap();    // backtab key
  490.                     else          
  491.                     {             
  492.                         valix = 0;          // left-align value string
  493.                         edmode = EDNAME;    // move to name field
  494.                         setcurtype(edmode); // hide blinking cursor
  495.                         highlite(edmode);   // highlight name field
  496.                         showstatus(help[edmode]); // display help info
  497.                     }
  498.                     break;        
  499.                 }
  500.  
  501.             default:                        // other keys field-specific
  502.                 if(edmode == EDNAME) changename();
  503.                 else changeval();
  504.         }
  505.     }
  506. }
  507.  
  508. /* Handle editing of directive's name field only */
  509.  
  510. void changename(void)
  511. {
  512.     if((kbdinfo.charcode == 0) || (kbdinfo.charcode == 0xe0))
  513.     {
  514.         switch(kbdinfo.scancode)
  515.         {
  516.             case DOWN:                      // advance to next
  517.                 dirix++;                    // directive name
  518.                 if(dirix == DIRMAX) dirix = 0;
  519.                 strcpy(namestr, directives[dirix]);
  520.                 break;
  521.  
  522.             case UP:                        // back up to previous
  523.                 dirix--;                    // directive name
  524.                 if(dirix <0) dirix = DIRMAX - 1;
  525.                 strcpy(namestr, directives[dirix]);
  526.                 break;
  527.  
  528.             default:                        // unrecognized extended key
  529.                 blap();
  530.         }
  531.     }
  532.     else blap();                            // unrecognized normal key
  533. }
  534.  
  535. /* Handle editing of directive's value string only */
  536.  
  537. void changeval(void)
  538. {
  539.     int vlen = strlen(valstr);              // get current length
  540.  
  541.     while((vlen > 0) && (valstr[vlen-1] == BL))
  542.         valstr[--vlen] == 0;                // trim trailing blanks
  543.  
  544.     if((kbdinfo.charcode == 0) || (kbdinfo.charcode == 0xe0))
  545.     {
  546.         switch(kbdinfo.scancode)            // extended key?
  547.         {
  548.             case RIGHT:                     // move right one character
  549.                 valix = min(valix++, vlen);
  550.                 break;
  551.  
  552.             case LEFT:                      // move left one character
  553.                 valix = max(valix--, 0);
  554.                 break;
  555.  
  556.             case HOME:                      // go to start of line
  557.                 valix = 0;
  558.                 break;
  559.  
  560.             case END:                       // go to end of line
  561.                 valix = vlen;
  562.                 break;
  563.  
  564.             case CTRLEND:                   // clear to end of line
  565.                 memset(&valstr[valix], 0, sizeof(valstr)-valix);
  566.                 break;
  567.  
  568.             case INS:                       // toggle insert flag
  569.                 insflag ^= TRUE;
  570.                 setcurtype(edmode);
  571.                 break;
  572.  
  573.             case DEL:                       // delete char under cursor
  574.                 strcpy(&valstr[valix], &valstr[valix+1]);
  575.                 break;
  576.  
  577.             default:                        // unrecognized extended key
  578.                 blap();
  579.         }
  580.     }
  581.     else if((kbdinfo.charcode >= BL) &&     // printable ASCII character
  582.             (kbdinfo.charcode <= TILDE) &&  // and string not full?
  583.             (valix < sizeof(valstr)-1) &&
  584.             !(insflag && (vlen > (sizeof(valstr)-2))))
  585.     {
  586.         if(insflag)                         // if insert on, open up string
  587.             memmove(&valstr[valix+1], &valstr[valix], sizeof(valstr)-valix-1);
  588.         valstr[valix++] = kbdinfo.charcode; // store new character
  589.     }
  590.     else if((kbdinfo.charcode == BS) &&     // backspace key and not
  591.             (valix != 0))                   // at start of line?
  592.     {
  593.         valix--;                            // back up one character
  594.         if(insflag)
  595.             memmove(&valstr[valix], &valstr[valix+1], sizeof(valstr)-valix-1);
  596.         else valstr[valix] = BL;
  597.     }
  598.     else blap();                            // unrecognized normal key
  599. }
  600.  
  601. /* Delete the current line, also releasing its heap space */
  602.  
  603. void deleteline(void)
  604. {
  605.     int i;                                  // scratch variable
  606.  
  607.     if(totln == 0)                          // bail out if no lines exist
  608.     {
  609.         blap();
  610.         return; 
  611.     }
  612.  
  613.     free(ln[curln][0]);                     // give back heap memory 
  614.     free(ln[curln][1]);
  615.  
  616.     for(i = curln; i < (totln-1); i++)
  617.     {
  618.         ln[i][0] = ln[i+1][0];              // close up array of 
  619.         ln[i][1] = ln[i+1][1];              // pointers to parsed lines
  620.     }
  621.  
  622.     totln--;                                // adjust total line count
  623.  
  624.     curln = max(0, min(curln, totln-1));    // ensure current line valid
  625.  
  626.     if(totln < lpp)                         // adjust current line and
  627.     {                                       // cursor position as needed
  628.         curln = min(curln, totln-1);
  629.         cury = min(cury, totln-1);
  630.     }
  631.     else if((totln-curln) < (lpp-cury))
  632.     {
  633.         cury = min(cury+1, lpp-1);
  634.     }
  635.  
  636.     showpage();                             // update the display
  637. }
  638.  
  639. /* Restore in-memory copy of CONFIG.SYS file to its original state */
  640.  
  641. void restore(void)
  642. {
  643.     int i;                                  // scratch variable
  644.  
  645.     for(i = 0; i < totln-1; i++)
  646.     {
  647.         free(ln[i][0]);                     // give back heap memory 
  648.         free(ln[i][1]);
  649.     }
  650.  
  651.     readfile();                             // re-read the original file
  652.     showpage();                             // update the display
  653. }
  654.  
  655. /*
  656.     Search the directives table to match the given name.
  657.     Return an index to the table if the directive name is
  658.     valid, or -1 if the name can't be matched
  659. */
  660.  
  661. int chkname(char *p)
  662. {
  663.     int i;
  664.  
  665.     for(i = 0; i < DIRMAX; i++) 
  666.     {
  667.         if(! strcmp(directives[i], p)) return i;
  668.     }
  669.     return(-1);
  670. }
  671.  
  672. /*
  673.     Read the CONFIG.SYS file into memory, parsing each line
  674.     into its two components: the directive's name and the value.
  675. */
  676.  
  677. void readfile(void)
  678. {
  679.     char buff[256];                         // temporary input buffer 
  680.     char *p, *q;                            // scratch pointers
  681.  
  682.     totln = 0;                              // initialize line count 
  683.     curln = 0;                              // initialize curln line
  684.     cury = 0;                               // initialize cursor position
  685.  
  686.     if((ifile = fopen(iname, "r+"))==NULL)  // open input file 
  687.         errexit("file not found or read-only.");
  688.  
  689.     while(fgets(buff, 256, ifile) != NULL)  // read next line
  690.     {
  691.         if(totln == MAXLN)
  692.             errexit("too many lines in file.");
  693.  
  694.         p = strtok(buff, " =\x0a");         // parse out the name
  695.         q = strtok(NULL, "\x0a");           // get pointer to remainder
  696.         
  697.         if(strcmp(strupr(p), "REM"))        // if not REM scan off 
  698.         {                                   // leading delimiters
  699.             while((*q == ' ') || (*q == '=')) q++;
  700.         }
  701.                                             // allocate heap space
  702.         if(((ln[totln][0] = malloc(strlen(p)+1)) == NULL) ||
  703.            ((ln[totln][1] = malloc(strlen(q)+1)) == NULL))
  704.             errexit("out of heap space.");
  705.  
  706.         strcpy(ln[totln][0], p);            // copy parsed directive name
  707.         strcpy(ln[totln++][1], q);          // and value to the heap
  708.     }
  709.  
  710.     fclose(ifile);                          // close input file
  711. }
  712.  
  713. /* Write modified file */
  714.  
  715. void writefile(void)
  716. {
  717.     int i;                                  // scratch variables
  718.     char c, *p;
  719.  
  720.     showstatus("Writing file...");
  721.  
  722.     strcpy(oname, iname);                   // build temporary filename
  723.     if(! (p = strchr(oname, '.')))          // clip off old extension
  724.         p = strchr(oname, '\0');            // (if any) and add .$$$ 
  725.     strcpy(p, ".$$$");
  726.  
  727.     if((ofile = fopen(oname, "w"))==NULL)   // open output file
  728.         errexit("can't create output file.");
  729.  
  730.     for(i = 0; i < totln; i++)              // write next line
  731.     {
  732.         if((! strcmp(ln[i][0], "REM")) ||   // use = delimiter unless
  733.            (! strcmp(ln[i][0], "SET")) ||   // REM or SET directive
  734.            (strlen(ln[i][0]) == 0))
  735.              c = ' ';
  736.         else c = '=';
  737.  
  738.         if(! fprintf(ofile, "%s%c%s\n", ln[i][0], c, ln[i][1]))
  739.             errexit("can't write file.  Disk full?");
  740.     }
  741.  
  742.     fclose(ofile);                          // close output file
  743.  
  744.     strcpy(p, ".bak");                      // build .BAK filename 
  745.     unlink(oname);                          // delete previous .BAK file
  746.     rename(iname, oname);                   // make original file .BAK
  747.     strcpy(p, ".$$$");                      // give new file same name
  748.     rename(oname, iname);                   // as original file 
  749. }
  750.  
  751. /*
  752.     Move cursor down one line; if cursor is already at end of screen,
  753.     scroll down through the file until the end of file is reached
  754. */
  755. void linedown(void)
  756. {
  757.     if((curln == (totln-1)) || (totln == 0))
  758.     {                                   
  759.         blip();                             // if already at end of
  760.         return;                             // file, do nothing
  761.     }
  762.  
  763.     highlite(-1);                           // hide the highlight bar
  764.     curln++;                                // advance through file
  765.  
  766.     if(cury != (lpp-1))                     // if not at end of screen,
  767.     {                                       // move cursor down
  768.         cury++;
  769.     }   
  770.     else                                    // otherwise scroll screen
  771.     {                                   
  772.         VioScrollUp(0, 0, lpp-1, cpl-1, 1, &normcell, 0);
  773.         showline(curln, lpp-1);
  774.     }
  775.  
  776.     highlite(0);                            // display the highlight bar
  777. }
  778.  
  779. /*
  780.     Move cursor up one line; if cursor is already at top of screen,
  781.     scroll up through the file until the start of file is reached
  782. */
  783.  
  784. void lineup(void)
  785. {
  786.     if((curln == 0) || (totln == 0))
  787.     {                               
  788.         blip();                             // if already at start 
  789.         return;                             // of file, do nothing
  790.     }
  791.  
  792.     highlite(-1);                           // hide the highlight bar
  793.     curln--;                                // back up through file
  794.  
  795.     if(cury != 0)                           // if not at start of
  796.     {                                       // screen, move cursor up
  797.         cury--;
  798.     }   
  799.     else                                    // otherwise scroll screen
  800.     {
  801.         VioScrollDn(0, 0, lpp-1, cpl-1, 1, &normcell, 0);
  802.         showline(curln, 0);
  803.     }
  804.  
  805.     highlite(0);                            // display the highlight bar
  806. }
  807.  
  808. /*
  809.     Scroll display down by one page.  Cursor is left in same relative
  810.     position on the screen unless we bump into end of file or the
  811.     number of lines in the file is less than the number of lines
  812.     per page
  813. */
  814.  
  815. void pagedown(void)
  816. {
  817.     if((curln == (totln-1)) || (totln == 0))
  818.     {  
  819.         blip();                             // if already at end of
  820.         return;                             // file, do nothing
  821.     }
  822.  
  823.     curln += lpp;                           // advance through file
  824.  
  825.     if((curln >= totln) || ((curln+lpp-cury) >= totln))
  826.     {
  827.         curln = totln-1;                    // if already in last page
  828.         cury = min(lpp-1, totln-1);         // force last line, move
  829.     }                                       // cursor to bottom
  830.                                         
  831.     showpage();                             // rewrite entire screen
  832. }
  833.  
  834. /*
  835.     Scroll display up by one page.  Cursor is left in same relative
  836.     position on the screen unless we bump into start of file or the
  837.     number of lines in the file is less than the number of lines
  838.     per page
  839. */
  840.  
  841. void pageup(void)
  842. {
  843.     if((curln == 0) || (totln == 0))
  844.     {          
  845.         blip();                             // if already at start
  846.         return;                             // of file, do nothing
  847.     }
  848.  
  849.     curln -= lpp;                           // back up through file
  850.  
  851.     if((curln <0) || ((curln-cury) < 0))
  852.     {
  853.         curln = 0;                          // if already in first page,
  854.         cury = 0;                           // force cursor to top
  855.     }
  856.  
  857.     showpage();                             // rewrite entire screen
  858. }
  859.  
  860. /*
  861.     Update the entire display.  If there are not enough lines
  862.     to fill the page, just clear the remainder
  863. */
  864.  
  865. void showpage(void)
  866. {
  867.     int i, j;                               // scratch variables
  868.  
  869.     j = min(totln, lpp);                    // find last line to display
  870.  
  871.     for(i = 0; i < j; i++)                  // display all lines
  872.         showline(curln-cury+i, i);
  873.  
  874.     if(j < lpp)                             // clear remainder of screen
  875.         VioScrollUp(j, 0, lpp-1, cpl-1, lpp-j, &normcell, 0);
  876.  
  877.     highlite(BROWSE);                       // highlight current line
  878. }
  879.  
  880. /*
  881.     Display line "l" on the screen on the specified row "y".
  882. */
  883.  
  884. void showline(int l, int y)
  885. {
  886.     char buff[256];                         // scratch buffer
  887.  
  888.     sprintf(buff, format1, l+1, ln[l][0], ln[l][1]);
  889.     VioWrtCharStrAtt(buff, min(strlen(buff), cpl), y, 0, &normattr, 0);
  890. }
  891.  
  892. /* Display status or help message centered on last line of screen */
  893.  
  894. void showstatus(char *msg)
  895. {
  896.     VioScrollUp(lpp+2, 0, lpp+2, cpl-1, 1, &normcell, 0);
  897.     VioWrtCharStr(msg, strlen(msg), lpp+2, max(0, (cpl-strlen(msg))/2), 0);
  898. }
  899.  
  900. /*
  901.     Display prompt, accept Y/y/N/n keys only
  902.     Return TRUE (Y) or FALSE (N) to caller
  903. */
  904.  
  905. int ask(char *msg)
  906. {
  907.     char c, p[80], *q;                      // scratch variables & ptrs
  908.     int i = cpl;                            // length of line to save
  909.  
  910.     q = malloc(cpl+1);                      // allocate some heap space
  911.  
  912.     VioReadCharStr(q, &i, lpp+2, 0, 0);     // save current status line
  913.     q[i] = 0;                               // and make it ASCIIZ
  914.  
  915.     sprintf(p, "%s? (Y/N)", msg);           // format the prompt
  916.  
  917.     do      
  918.     {
  919.         blip();                             // wake up the user
  920.         showstatus(p);                      // display prompt
  921.         KbdCharIn(&kbdinfo, WAIT, 0);       // get key from user
  922.         c = toupper(kbdinfo.charcode);
  923.  
  924.     } while((c != 'Y') && (c != 'N'));      // retry if not Y or N
  925.  
  926.     showstatus(q);                          // restore original status line
  927.     free(q);                                // give back heap space
  928.     return(c == 'Y');                       // result is TRUE or FALSE
  929. }
  930.  
  931. /* Build miscellaneous formatting and help strings */
  932.  
  933. void makestrings(void)
  934. {
  935.     sprintf(format1,                        // built format for directives
  936.         "%%%dd %c %%%d.%ds %c %%-%d.%ds", 
  937.         F1COL-3,                            // width of first column
  938.         VBAR,                               // graphics divider character
  939.         F2COL-F1COL-3, F2COL-F1COL-3,       // width of second column
  940.         VBAR,                               // graphics divider character
  941.         cpl-F2COL, cpl-F2COL);              // width of third column
  942.  
  943.     sprintf(format2,                        // built format for filename
  944.         "%s  %%%d.%ds",                     // and copyright line
  945.         copyright,
  946.         cpl - strlen(copyright) - 2,
  947.         cpl - strlen(copyright) - 2);
  948.  
  949.     sprintf(helpstr1,"%c %c %s %s",         // build help string for
  950.         UPARROW, DNARROW,                   // browse mode
  951.         "<PgUp> <PgDn> <Home> <End>",
  952.         "Add Change Delete Insert Revert eXit <Esc>");
  953.  
  954.     sprintf(helpstr2,"%c %c %s",            // build help string for
  955.         UPARROW, DNARROW,                   // name string editing
  956.         "<Tab> <Enter> <Esc>");
  957.  
  958.     sprintf(helpstr3,"%c %c %s %s",         // build help string for
  959.         LTARROW, RTARROW,                   // value string editing
  960.         "<Home> <End> <Ins> <Del> <Backsp> <Ctrl-End>",
  961.         "<Shift-Tab> <Enter> <Esc>");
  962. }
  963.  
  964. void signon(void)
  965. {
  966.     char *msg = malloc(cpl);                // allocate heap memory
  967.     char *divider = malloc(cpl);
  968.  
  969.     memset(divider, HBAR, cpl);             // build horizontal divider
  970.     sprintf(msg, format2, iname);           // build copyright message
  971.  
  972.     VioWrtCharStr(divider, cpl, lpp, 0, 0); // display horizontal divider
  973.     VioWrtCharStr(msg, cpl, lpp+1, 0, 0);   // display copyright message
  974.     
  975.     free(msg);                              // give back heap memory
  976.     free(divider);
  977. }
  978.  
  979. /*
  980.     Hide or display the highlight on the "current line" 
  981.     according to the argument "mode":
  982.      -1     = remove the highlight from the current line
  983.      BROWSE = highlight the entire current line
  984.      EDNAME = highlight the name field of the current line
  985.      EDVAL  = highlight the value string field of the current line
  986. */
  987.  
  988. void highlite(int mode)
  989. {
  990.     if(totln == 0) return;                  // if empty file, do nothing
  991.  
  992.                                             // remove current highlight
  993.     VioWrtNAttr((char far *) &normattr, cpl, cury, F0COL, 0);
  994.  
  995.     switch(mode)
  996.     {
  997.         case 0:                             // highlight entire line
  998.             VioWrtNAttr((char far *) &revattr, cpl, cury, F0COL, 0);
  999.             break;
  1000.  
  1001.         case 1:                             // highlight name field
  1002.             VioWrtNAttr((char far *) &revattr, 12, cury, F1COL, 0);
  1003.             break;
  1004.     
  1005.         case 2:                             // highlight value field
  1006.             VioWrtNAttr((char far *) &revattr, cpl-F2COL, cury, F2COL, 0);
  1007.             break;
  1008.     }
  1009. }
  1010.  
  1011. /* Position the blinking (hardware) cursor */
  1012.  
  1013. void setcurpos(int x, int y)
  1014. {
  1015.     VioSetCurPos(y, x, 0);
  1016. }
  1017.  
  1018. /*
  1019.     Hide or reveal cursor and set cursor size
  1020.     according to the current editing mode
  1021. */
  1022.  
  1023. void setcurtype(int mode)
  1024. {
  1025.     curinfo.attr = ((mode == EDVAL) ? VISIBLE : HIDDEN );
  1026.     curinfo.start = (insflag ? 0 : cstart);
  1027.     VioSetCurType(&curinfo, 0);
  1028. }
  1029.  
  1030. /*
  1031.     Clear the screen, restore cursor to its normal appearance,
  1032.     and place cursor in the home position (upper left corner)
  1033. */
  1034.  
  1035. void cls(void)
  1036. {
  1037.     VioScrollUp(0, 0, -1, -1, -1, &normcell, 0);
  1038.     curinfo.attr = VISIBLE;
  1039.     curinfo.start = cstart;
  1040.     VioSetCurType(&curinfo, 0);
  1041.     setcurpos(0, 0);
  1042. }
  1043.  
  1044. /* Clear screen, display error message, exit with non-zero return code */
  1045.  
  1046. void errexit(char *p)
  1047. {
  1048.     cls();
  1049.     fprintf(stderr, "\nCONFIG.EXE (%s):  %s\n", iname, p);
  1050.     exit(1);
  1051. }
  1052.  
  1053. /* Make a mildly obnoxious error beep */
  1054.  
  1055. void blip(void)
  1056. {
  1057.     DosBeep(880,50);
  1058. }
  1059.  
  1060. /* Make a moderately obnoxious error beep */
  1061.  
  1062. void blap(void)
  1063. {
  1064.     DosBeep(440,100);
  1065. }
  1066.  
  1067.