home *** CD-ROM | disk | FTP | other *** search
/ Shareware 1 2 the Maxx / sw_1.zip / sw_1 / EDITORS / TDE20.ZIP / CFGFILE.C < prev    next >
C/C++ Source or Header  |  1992-06-05  |  24KB  |  762 lines

  1. /*
  2.  * This module contains all the routines needed to redefine key, colors, and
  3.  *   modes via a configuration file.
  4.  *
  5.  * Program Name:  tdecfg
  6.  * Author:        Frank Davis
  7.  * Date:          June 5, 1992
  8.  */
  9.  
  10.  
  11. #include <io.h>
  12. #include <stdio.h>
  13. #include <stdlib.h>
  14. #include <string.h>
  15.  
  16. #include "tdecfg.h"
  17. #include "cfgfile.h"
  18.  
  19.  
  20. /*
  21.  * reference the structures in config files.
  22.  */
  23. extern struct vcfg cfg;
  24. extern FILE *tde_exe;                  /* FILE pointer to tde.exe */
  25. extern unsigned char key_func[MAX_KEYS];
  26. extern MACRO macros;
  27. extern int temp_colors[2][NUM_COLORS];
  28. extern MODE_INFO in_modes;
  29.  
  30.  
  31.  
  32. char line_in[2000];             /* line buffer */
  33. int  stroke_count;              /* global variable for macro strokes */
  34. unsigned int line_no;           /* global variable for line count */
  35. int *color_pointer = (int *)temp_colors;
  36. int modes[NUM_MODES];
  37.  
  38.  
  39. /*
  40.  * Name:    tdecfgfile
  41.  * Date:    June 5, 1992
  42.  * Notes:   read in a configuration file
  43.  */
  44. void tdecfgfile( void )
  45. {
  46. FILE *config;
  47. char fname[80];
  48. int  ch;
  49. int  i;
  50. int  rc;
  51.  
  52.    /*
  53.     * prompt for the configuration file name.
  54.     */
  55.    cls( );
  56.    xygoto( 0, 3 );
  57.    puts( "Enter configuration file name, e.g. tde.cfg  :" );
  58.    gets( fname );
  59.  
  60.    if (strlen( fname ) != 0) {
  61.       rc = OK;
  62.       if ((rc = access( fname, EXIST )) != 0) {
  63.          puts( "\n\n Error: File not found." );
  64.          getkey( );
  65.          rc = ERROR;
  66.       } else if ((config = fopen( fname, "r" )) == NULL ) {
  67.          puts( "\n\nError: Cannot open configuration file." );
  68.          getkey( );
  69.          rc = ERROR;
  70.       }
  71.  
  72.       /*
  73.        * if everything is everthing so far, get the current editor settings.
  74.        */
  75.       if (rc == OK) {
  76.          fseek( tde_exe, KEYS_OFFSET, SEEK_SET );
  77.          fread( (void *)key_func, sizeof(unsigned char), MAX_KEYS, tde_exe );
  78.          fseek( tde_exe, MACRO_OFFSET, SEEK_SET );
  79.          fread( (void *)¯os, sizeof(MACRO), 1, tde_exe );
  80.          fseek( tde_exe, COLOR_OFFSET, SEEK_SET );
  81.          fread( (void *)color_pointer, sizeof(temp_colors), 1, tde_exe );
  82.          fseek( tde_exe, MODE_OFFSET, SEEK_SET );
  83.          fread( (void *)&in_modes, sizeof( MODE_INFO ), 1, tde_exe );
  84.  
  85.          stroke_count = get_stroke_count( );
  86.  
  87.          /*
  88.           * put the current modes into an array.  it's easier to work
  89.           *   with them in an array.  This is from cfgmode.c.
  90.           */
  91.          modes[Ins]     = in_modes.insert;
  92.          modes[Ind]     = in_modes.indent;
  93.          modes[TAB]     = in_modes.tab_size;
  94.          modes[Smart]   = in_modes.smart_tab;
  95.          modes[Write_Z] = in_modes.control_z;
  96.          modes[Crlf]    = in_modes.crlf;
  97.          modes[Trim]    = in_modes.trailing;
  98.          modes[Eol]     = in_modes.show_eol;
  99.          modes[WW]      = in_modes.word_wrap;
  100.          modes[Left]    = in_modes.left_margin;
  101.          modes[Para]    = in_modes.parg_margin;
  102.          modes[Right]   = in_modes.right_margin;
  103.          modes[Size]    = in_modes.cursor_size;
  104.          modes[Backup]  = in_modes.do_backups;
  105.          modes[Ruler]   = in_modes.ruler;
  106.          modes[Date]    = in_modes.date_style;
  107.          modes[Time]    = in_modes.time_style;
  108.  
  109.          line_no = 1;
  110.          while (!feof( config )) {
  111.             if (fgets( line_in, 1500, config ) == NULL)
  112.                break;
  113.             parse_line( line_in );
  114.             ++line_no;
  115.          }
  116.  
  117.          /*
  118.           *  if we changed any modes, reset them b4 we write them to tde.exe.
  119.           */
  120.          in_modes.insert       = modes[Ins];
  121.          in_modes.indent       = modes[Ind];
  122.          in_modes.tab_size     = modes[TAB];
  123.          in_modes.smart_tab    = modes[Smart];
  124.          in_modes.control_z    = modes[Write_Z];
  125.          in_modes.crlf         = modes[Crlf];
  126.          in_modes.trailing     = modes[Trim];
  127.          in_modes.show_eol     = modes[Eol];
  128.          in_modes.word_wrap    = modes[WW];
  129.          in_modes.left_margin  = modes[Left];
  130.          in_modes.parg_margin  = modes[Para];
  131.          in_modes.right_margin = modes[Right];
  132.          in_modes.cursor_size  = modes[Size];
  133.          in_modes.do_backups   = modes[Backup];
  134.          in_modes.ruler        = modes[Ruler];
  135.          in_modes.date_style   = modes[Date];
  136.          in_modes.time_style   = modes[Time];
  137.  
  138.          fseek( tde_exe, KEYS_OFFSET, SEEK_SET );
  139.          fwrite( (void *)key_func, sizeof(unsigned char), MAX_KEYS, tde_exe );
  140.          fseek( tde_exe, MACRO_OFFSET, SEEK_SET );
  141.          fwrite( (void *)¯os, sizeof(MACRO), 1, tde_exe );
  142.          fseek( tde_exe, COLOR_OFFSET, SEEK_SET );
  143.          fwrite( (void *)color_pointer, sizeof(temp_colors), 1, tde_exe );
  144.          fseek( tde_exe, MODE_OFFSET, SEEK_SET );
  145.          fwrite( (void *)&in_modes, sizeof( MODE_INFO ), 1, tde_exe );
  146.          fclose( config );
  147.          printf( "\n\n    Configuration file read.  Press a key to continue :" );
  148.          getkey( );
  149.       }
  150.    }
  151.    cls( );
  152. }
  153.  
  154.  
  155. /*
  156.  * Name:    parse_line
  157.  * Purpose: real work horse of the configuration utility, figure out what
  158.  *          we need to do with each line of the config file.
  159.  * Date:    June 5, 1992
  160.  * Passed:  line:  line that contains the text to parse
  161.  */
  162. void parse_line( char *line )
  163. {
  164. char key[1042];         /* buffer to hold any token that we parse */
  165. char *residue;          /* pointer to next item in line, if it exists */
  166. int key_no;             /* index into key array */
  167. int color;              /* color field */
  168. int mode_index;         /* index in mode array */
  169. int func_no;            /* function number we want to assign to a key */
  170. int color_no;           /* attribute we want to assign to a color field */
  171. int mode_no;            /* mode number we want to assign to a mode */
  172. int found;              /* boolean, did we find a valid key, color, or mode? */
  173.  
  174.    /*
  175.     * find the first token and put it in key.  residue points to next token.
  176.     */
  177.    residue = parse_token( line, key );
  178.    if (*key != '\0' && *key != ';') {
  179.       if (strlen( key ) > 1) {
  180.          /*
  181.           * try to find a valid key
  182.           */
  183.          found = FALSE;
  184.          key_no = search( key, valid_keys, AVAIL_KEYS-1 );
  185.          if (key_no != ERROR) {
  186.             /*
  187.              * find the function assignment
  188.              */
  189.             found = TRUE;
  190.             if (residue != NULL) {
  191.                residue = parse_token( residue, key );
  192.  
  193.                /*
  194.                 * if this is not a comment, find the function to assign
  195.                 *   to key.  clear any previous macro or key assignment.
  196.                 */
  197.                if (*key != '\0' && *key != ';') {
  198.                   func_no = search( key, valid_func, NUM_FUNC );
  199.                   if (func_no != ERROR) {
  200.                      clear_previous_macro( key_no );
  201.                      key_func[key_no] = func_no;
  202.                      if (func_no == PlayBack)
  203.                         parse_macro( key_no, residue );
  204.                   } else {
  205.                      printf( "==> %s", line_in );
  206.                      printf( "Unrecognized function: line %u  : function %s\n",
  207.                               line_no, key );
  208.                   }
  209.                }
  210.             }
  211.          }
  212.  
  213.          /*
  214.           * valid key not found, now try a valid color
  215.           */
  216.          if (!found) {
  217.             color = search( key, valid_colors, (NUM_COLORS * 2) - 1 );
  218.             if (color != ERROR) {
  219.                found = TRUE;
  220.                if (residue != NULL) {
  221.                   residue = parse_token( residue, key );
  222.  
  223.                   /*
  224.                    * we found a color field and attribute.  now, make sure
  225.                    *   everything is everything before we assign the attribute
  226.                    *   to the color field.
  227.                    */
  228.                   if (*key != '\0' && *key != ';') {
  229.                      color_no = atoi( key );
  230.                      if (color_no >= 0 && color_no <= 127)
  231.                         *(color_pointer+color) = color_no;
  232.                      else {
  233.                         printf( "==> %s", line_in );
  234.                         printf( "Color number out of range: line %u  : number %s\n",
  235.                                  line_no, key );
  236.                      }
  237.                   }
  238.                }
  239.             }
  240.          }
  241.  
  242.          /*
  243.           * valid color not found, now try a valid mode
  244.           */
  245.          if (!found) {
  246.             mode_index = search( key, valid_modes, NUM_MODES-1 );
  247.             if (mode_index != ERROR) {
  248.                found = TRUE;
  249.  
  250.                /*
  251.                 * if we find a valid mode, we need to search different
  252.                 *   option arrays before we find a valid assignment.
  253.                 */
  254.                if (residue != NULL) {
  255.                   residue = parse_token( residue, key );
  256.                   if (*key != '\0' && *key != ';') {
  257.                      switch ( mode_index ) {
  258.                         case Ins     :
  259.                         case Ind     :
  260.                         case Smart   :
  261.                         case Trim    :
  262.                         case Eol     :
  263.                         case Backup  :
  264.                         case Ruler   :
  265.                            mode_no = search( key, off_on, 1 );
  266.                            if (mode_no == ERROR) {
  267.                               printf( "==> %s", line_in );
  268.                               printf( "Off/On error: " );
  269.                            }
  270.                            break;
  271.                         case TAB     :
  272.                            mode_no = atoi( key );
  273.                            if (mode_no > 520 || mode_no < 1) {
  274.                               mode_no = ERROR;
  275.                               printf( "==> %s", line_in );
  276.                               printf( "Tab error: " );
  277.                            }
  278.                            break;
  279.                         case Left    :
  280.                            mode_no = atoi( key );
  281.                            if (mode_no < 1 || mode_no > modes[Right]) {
  282.                               mode_no = ERROR;
  283.                               printf( "==> %s", line_in );
  284.                               printf( "Left margin error: " );
  285.                            } else
  286.                               --mode_no;
  287.                            break;
  288.                         case Para    :
  289.                            mode_no = atoi( key );
  290.                            if (mode_no < 1 || mode_no > modes[Right]) {
  291.                               mode_no = ERROR;
  292.                               printf( "==> %s", line_in );
  293.                               printf( "Paragraph margin error: " );
  294.                            } else
  295.                               --mode_no;
  296.                            break;
  297.                         case Right   :
  298.                            mode_no = atoi( key );
  299.                            if (mode_no < modes[Left] || mode_no > 1040) {
  300.                               mode_no = ERROR;
  301.                               printf( "==> %s", line_in );
  302.                               printf( "Right margin error: " );
  303.                            } else
  304.                               --mode_no;
  305.                            break;
  306.                         case Crlf    :
  307.                            mode_no = search( key, valid_crlf, 1 );
  308.                            if (mode_no == ERROR) {
  309.                               printf( "==> %s", line_in );
  310.                               printf( "CRLF or LF error: " );
  311.                            }
  312.                            break;
  313.                         case WW      :
  314.                            mode_no = search( key, valid_wraps, 2 );
  315.                            if (mode_no == ERROR) {
  316.                               printf( "==> %s", line_in );
  317.                               printf( "Word wrap error: " );
  318.                            }
  319.                            break;
  320.                         case Size    :
  321.                            mode_no = search( key, valid_cursor, 1 );
  322.                            if (mode_no == ERROR) {
  323.                               printf( "==> %s", line_in );
  324.                               printf( "Cursor size error: " );
  325.                            }
  326.                            break;
  327.                         case Write_Z :
  328.                            mode_no = search( key, valid_z, 1 );
  329.                            if (mode_no == ERROR) {
  330.                               printf( "==> %s", line_in );
  331.                               printf( "Control Z error: " );
  332.                            }
  333.                            break;
  334.                         case Date    :
  335.                            mode_no = search( key, valid_dates, 5 );
  336.                            if (mode_no == ERROR) {
  337.                               printf( "==> %s", line_in );
  338.                               printf( "Date format error: " );
  339.                            }
  340.                            break;
  341.                         case Time    :
  342.                            mode_no = search( key, valid_times, 1 );
  343.                            if (mode_no == ERROR) {
  344.                               printf( "==> %s", line_in );
  345.                               printf( "Time format error: " );
  346.                            }
  347.                            break;
  348.                      }
  349.                      if (mode_no != ERROR)
  350.                         modes[mode_index] = mode_no;
  351.                      else
  352.                         printf( " line = %u  :  unknown mode = %s\n",
  353.                               line_no, key );
  354.                   }
  355.                }
  356.             }
  357.          }
  358.          if (!found) {
  359.             printf( "==> %s", line_in );
  360.             printf( "Unrecognized editor setting: line %u  :  %s\n", line_no, key );
  361.          }
  362.       }
  363.    }
  364. }
  365.  
  366.  
  367. /*
  368.  * Name:    parse_token
  369.  * Purpose: given an input line, find the first token
  370.  * Date:    June 5, 1992
  371.  * Passed:  line:  line that contains the text to parse
  372.  *          token:   buffer to hold token
  373.  * Returns: pointer in line to start next token search.
  374.  * Notes:   assume tokens are delimited by spaces.
  375.  */
  376. char *parse_token( char *line, char *token )
  377. {
  378.    /*
  379.     * skip over any leading spaces.
  380.     */
  381.    while (*line == ' ')
  382.       ++line;
  383.  
  384.    /*
  385.     * put the characters into the token array until we run into a space
  386.     *   or the terminating '\0';
  387.     */
  388.    while (*line != ' ' && *line != '\0' && *line != '\n')
  389.       *token++ = *line++;
  390.    *token = '\0';
  391.  
  392.    /*
  393.     * return what's left on the line, if anything.
  394.     */
  395.    if (*line != '\0' && *line != '\n')
  396.       return( line );
  397.    else
  398.       return( NULL );
  399. }
  400.  
  401.  
  402. /*
  403.  * Name:    search
  404.  * Purpose: binary search a CONFIG_DEFS structure
  405.  * Date:    June 5, 1992
  406.  * Passed:  token:  token to search for
  407.  *          list:   list of valid tokens
  408.  *          num:    number of valid tokens in list
  409.  * Returns: value of token assigned to matching token.
  410.  * Notes:   do a standard binary search.
  411.  *          instead of returning mid, lets return the value of the token
  412.  *          assigned to mid.
  413.  */
  414. int  search( char *token, CONFIG_DEFS list[], int num )
  415. {
  416. int bot;
  417. int mid;
  418. int top;
  419. int rc;
  420.  
  421.    bot = 0;
  422.    top = num;
  423.    while (bot <= top) {
  424.       mid = (bot + top) / 2;
  425.       rc = stricmp( token, list[mid].key );
  426.       if (rc == 0)
  427.          return( list[mid].key_index );
  428.       else if (rc < 0)
  429.          top = mid - 1;
  430.       else
  431.          bot = mid + 1;
  432.    }
  433.    return( ERROR );
  434. }
  435.  
  436.  
  437. /*
  438.  * Name:    parse_macro
  439.  * Purpose: separate literals from keys in a macro definition
  440.  * Date:    June 5, 1992
  441.  * Passed:  macro_key:  key that we are a assigning a macro to
  442.  *          residue:    pointer to macro defs
  443.  * Notes:   for each token in macro def, find out if it's a literal or a
  444.  *             function key.
  445.  *          a literal begins with a ".  to put a " in a macro def, precede
  446.  *             a " with a ".
  447.  */
  448. void parse_macro( int macro_key, char *residue )
  449. {
  450. int  rc;
  451. int  key;
  452. char literal[1042];
  453. char *l;
  454. int  key_no;
  455.  
  456.    /*
  457.     * reset any previous macro def.
  458.     */
  459.    initialize_macro( macro_key );
  460.    while (residue != NULL) {
  461.       /*
  462.        * skip over any leading spaces.
  463.        */
  464.       while (*residue == ' ')
  465.          ++residue;
  466.  
  467.       /*
  468.        * done if we hit a comment
  469.        */
  470.       if (*residue == ';')
  471.          residue = NULL;
  472.  
  473.       /*
  474.        * check for a literal.
  475.        */
  476.       else if (*residue == '\"') {
  477.          rc = parse_literal( macro_key, residue, literal, &residue );
  478.          if (rc == OK) {
  479.             l = literal;
  480.             while (*l != '\0'  &&  rc == OK) {
  481.                rc = record_keys( macro_key, *l );
  482.                ++l;
  483.             }
  484.          } else {
  485.             printf( "==> %s", line_in );
  486.             printf( "Literal not recognized: line %u  : literal  %s\n", line_no, literal );
  487.          }
  488.  
  489.       /*
  490.        * check for a function key.
  491.        */
  492.       } else {
  493.          residue = parse_token( residue, literal );
  494.          key_no = search( literal, valid_keys, AVAIL_KEYS );
  495.          if (key_no != ERROR)
  496.             record_keys( macro_key, key_no+256 );
  497.          else {
  498.             printf( "==> %s", line_in );
  499.             printf( "Unrecognized key: line %u  : key %s\n", line_no, literal );
  500.          }
  501.       }
  502.    }
  503.    check_macro( macro_key );
  504. }
  505.  
  506.  
  507. /*
  508.  * Name:    parse_literal
  509.  * Purpose: get all letters in a literal
  510.  * Date:    June 5, 1992
  511.  * Passed:  macro_key:  key that we are a assigning a macro to
  512.  *          line:       current line position
  513.  *          literal:    buffer to hold literal
  514.  *          residue:    pointer to next token in line
  515.  * Notes:   a literal begins with a ".  to put a " in a macro def, precede
  516.  *             a " with a ".
  517.  */
  518. int  parse_literal( int macro_key, char *line, char *literal, char **residue )
  519. {
  520. int quote_state = 1;    /* we've already seen one " before we get here */
  521.  
  522.    line++;
  523.    /*
  524.     * put the characters into the literal array until we run into the
  525.     *   end of literal or terminating '\0';
  526.     */
  527.    while (*line != '\0' && *line != '\n') {
  528.       if (*line != '\"')
  529.          *literal++ = *line++;
  530.       else {
  531.          if (*(line+1) == '\"') {
  532.             *literal++ = '\"';
  533.             line++;
  534.             line++;
  535.          } else {
  536.             line++;
  537.             --quote_state;
  538.             break;
  539.          }
  540.       }
  541.    }
  542.    *literal = '\0';
  543.  
  544.    /*
  545.     * return what's left on the line, if anything.
  546.     */
  547.    if (*line != '\0' && *line != '\n')
  548.       *residue = line;
  549.    else
  550.       *residue = NULL;
  551.    if (quote_state != 0) {
  552.       *residue = NULL;
  553.       return( ERROR );
  554.    } else
  555.       return( OK );
  556. }
  557.  
  558.  
  559. /*
  560.  * Name:    initialize_macro
  561.  * Purpose: initialize the first key of a macro def
  562.  * Date:    June 5, 1992
  563.  * Passed:  macro_key:  key that we are a assigning a macro to
  564.  * Notes:   this function is ported directly from tde.
  565.  */
  566. void initialize_macro( int macro_key )
  567. {
  568. register int next;
  569. int prev;
  570. int line;
  571. int key;
  572. int func;
  573.  
  574.    next = macros.first_stroke[macro_key];
  575.  
  576.    /*
  577.     * initialize the first key in a macro def
  578.     */
  579.    if (next != STROKE_LIMIT+1) {
  580.       do {
  581.          prev = next;
  582.          next = macros.strokes[next].next;
  583.          macros.strokes[prev].key  = MAX_KEYS+1;
  584.          macros.strokes[prev].next = STROKE_LIMIT+1;
  585.          ++stroke_count;
  586.       } while (next != -1);
  587.    }
  588.  
  589.    /*
  590.     * find the first open space and initialize
  591.     */
  592.    for (next=0; macros.strokes[next].next != STROKE_LIMIT+1;)
  593.       next++;
  594.    macros.first_stroke[macro_key] = next;
  595.    macros.strokes[next].key  = -1;
  596.    macros.strokes[next].next = -1;
  597. }
  598.  
  599.  
  600. /*
  601.  * Name:    clear_previous_macro
  602.  * Purpose: clear any macro previously assigned to a key
  603.  * Date:    June 5, 1992
  604.  * Passed:  macro_key:  key that we are a assigning a macro to
  605.  * Notes:   this function is ported directly from tde.
  606.  */
  607. void clear_previous_macro( int macro_key )
  608. {
  609. register int next;
  610. int prev;
  611.  
  612.    next = macros.first_stroke[macro_key];
  613.  
  614.    /*
  615.     * if key has already been assigned to a macro, clear macro def.
  616.     */
  617.    if (next != STROKE_LIMIT+1) {
  618.       do {
  619.          prev = next;
  620.          next = macros.strokes[next].next;
  621.          macros.strokes[prev].key  = MAX_KEYS+1;
  622.          macros.strokes[prev].next = STROKE_LIMIT+1;
  623.       } while (next != -1);
  624.    }
  625. }
  626.  
  627.  
  628. /*
  629.  * Name:    check_macro
  630.  * Purpose: see if macro def has any valid key.  if not, clear macro
  631.  * Date:    June 5, 1992
  632.  * Passed:  macro_key:  key that we are a assigning a macro to
  633.  * Notes:   this function is ported directly from tde.
  634.  */
  635. void check_macro( int macro_key )
  636. {
  637. register int next;
  638. register int key;
  639.  
  640.    /*
  641.     * see if the macro has any keystrokes.  if not, then wipe it out.
  642.     */
  643.    key = macro_key;
  644.    if (key != 0) {
  645.       next = macros.first_stroke[key];
  646.       if (macros.strokes[next].key == -1) {
  647.          macros.strokes[next].key  = MAX_KEYS+1;
  648.          macros.strokes[next].next = STROKE_LIMIT+1;
  649.          macros.first_stroke[key-256] = STROKE_LIMIT+1;
  650.          if (key_func[key] == PlayBack)
  651.             key_func[key] = 0;
  652.       }
  653.    }
  654. }
  655.  
  656.  
  657. /*
  658.  * Name:    record_keys
  659.  * Purpose: save keystrokes in keystroke buffer
  660.  * Date:    June 5, 1992
  661.  * Passed:  line: line to display prompts
  662.  * Notes:   -1 in .next field indicates the end of a recording
  663.  *          STROKE_LIMIT+1 in .next field indicates an unused space.
  664.  *           Recall, return codes are for macros.  Since we do not allow
  665.  *           keys to be assigned to macro functions, let's just return OK;
  666.  */
  667. int  record_keys( int macro_key, int key )
  668. {
  669. register int next;
  670. register int prev;
  671. int func;
  672. int rc;
  673.  
  674.    rc = OK;
  675.    if (stroke_count == 0) {
  676.       printf( "==> %s", line_in );
  677.       printf( "No more room in macro buffer:  line %u\n",
  678.                line_no );
  679.       rc = ERROR;
  680.    } else {
  681.       func = getfunc( key );
  682.       if (func != RecordMacro && func != SaveMacro && func != LoadMacro &&
  683.           func != ClearAllMacros) {
  684.  
  685.          /*
  686.           * a -1 in the next field marks the end of the keystroke recording.
  687.           */
  688.          next = macros.first_stroke[macro_key];
  689.          if (macros.strokes[next].next != STROKE_LIMIT+1) {
  690.             while (macros.strokes[next].next != -1)
  691.                next = macros.strokes[next].next;
  692.          }
  693.          prev = next;
  694.  
  695.          /*
  696.           * now find an open space to record the current key.
  697.           */
  698.          if (macros.strokes[next].key != -1) {
  699.             for (; next < STROKE_LIMIT &&
  700.                          macros.strokes[next].next != STROKE_LIMIT+1;)
  701.                next++;
  702.             if (next == STROKE_LIMIT) {
  703.                for (next=0; next < prev &&
  704.                             macros.strokes[next].next != STROKE_LIMIT+1;)
  705.                   next++;
  706.             }
  707.          }
  708.          if (next == prev && macros.strokes[prev].key != -1) {
  709.             rc = ERROR;
  710.          } else {
  711.          /*
  712.           * next == prev if we are recording the initial macro node.
  713.           */
  714.             macros.strokes[prev].next = next;
  715.             macros.strokes[next].next = -1;
  716.             macros.strokes[next].key  = key;
  717.             stroke_count--;
  718.          }
  719.       }
  720.    }
  721.    return( rc );
  722. }
  723.  
  724.  
  725. /*
  726.  * Name:    get_stroke_count
  727.  * Purpose: count unassigned nodes in macro buff
  728.  * Date:    June 5, 1992
  729.  * Returns: number of strokes left in macro buffer.
  730.  */
  731. int  get_stroke_count( void )
  732. {
  733. int count = 0;
  734. int i;
  735.  
  736.    for (i=0; i<STROKE_LIMIT; i++)
  737.       if (macros.strokes[i].next == STROKE_LIMIT+1)
  738.          ++count;
  739.    return( count );
  740. }
  741.  
  742.  
  743.  
  744. /*
  745.  * Name:    getfunc
  746.  * Purpose: get the function assigned to key c
  747.  * Date:    June 5, 1992
  748.  * Passed:  c:  key just pressed
  749.  * Notes:   key codes less than 256 or 0x100 are not assigned a function.
  750.  *          The codes in the range 0-255 are ASCII and extended ASCII chars.
  751.  */
  752. int  getfunc( int c )
  753. {
  754. register int i = c;
  755.  
  756.    if (i <= 256)
  757.       i = 0;
  758.    else
  759.       i = key_func[i-256];
  760.    return( i );
  761. }
  762.