home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 8 Other / 08-Other.zip / OS2CO2.ZIP / CONFIG.C < prev    next >
Text File  |  1989-06-01  |  37KB  |  1,025 lines

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