home *** CD-ROM | disk | FTP | other *** search
/ The C Users' Group Library 1994 August / wc-cdrom-cusersgrouplibrary-1994-08.iso / listings / v_10_05 / cmenu13.exe / CMENU2.C < prev    next >
C/C++ Source or Header  |  1992-04-06  |  14KB  |  611 lines

  1. /************************************************************
  2.  *    Program: CMENU Menu Compiler
  3.  *  Module: cmenu2.c    
  4.  *        Menu Compiler:
  5.  *        Menu/Item Token Processing Functions
  6.  *    Written by: Leor Zolman, 7/91
  7.  ************************************************************/
  8.  
  9. #include "cmenu.h"
  10. #include "ccmenu.h"
  11.  
  12. #if __STDC__
  13. #pragma hdrstop
  14. #endif
  15.  
  16. #include <ctype.h>
  17.  
  18.  
  19. /************************************************************
  20.  * do_menu():
  21.  *    Process the MENU keyword
  22.  ************************************************************/
  23.  
  24. int do_menu()
  25. {
  26.     int tok;
  27.  
  28.     if (in_menu)        /* Are we currently processing a menu?    */
  29.     {                    /* yes.                                    */
  30.         warning("Endmenu missing from previous menu");
  31.         do_endmenu();    /* give them the benefit of the doubt    */
  32.     }
  33.  
  34.     if ((tok = gettok()) != T_STRING)
  35.     {
  36.         if (n_menus)
  37.             error("Menu name missing; menu unreachable");
  38.         sprintf(tparam, "menu%d", n_menus + 1);    /* force a name        */
  39.         ungettok(tok);
  40.     }
  41.     
  42.     if (strlen(tparam) > MAX_NAME)
  43.     {
  44.         error("The name '%s' is too long (%d chars max)",
  45.                 tparam, MAX_NAME);
  46.         tparam[MAX_NAME] = '\0';                /* truncate name    */
  47.     }
  48.     
  49.     if ((MIp = find_menu(tparam)) == NULL)        /* menu exist?        */
  50.     {
  51.         MInfo[n_menus] = create_menu(tparam);    /* no.                */
  52.         if (fatal)
  53.             return ERROR;                        /* creation error    */
  54.         else
  55.             MIp = &MInfo[n_menus++];            /* OK, bump count    */
  56.     }
  57.     else
  58.         if (MIp -> Processed)                    /* redefinition?    */
  59.             return fatalerr("Duplicate Menu definition"); /* yes.    */
  60.         
  61.     Mp = &MIp -> Menu;
  62.     *Mp->title = *Mp->path = '\0';
  63.     Mp->nitems = Mp->widest = 0;
  64.     Mp->spacing = Mp->columns = Mp->escape = DEFAULT;
  65.     Mp->align = DEFAULT;
  66.  
  67.     in_item = FALSE;            /* state variables describing the    */    
  68.     in_menu = TRUE;                /* current menu being processed        */
  69.     n_items = 0;                
  70.     n_refs = 0;                    /* no forward item references yet    */
  71.  
  72.     if ((tok = gettok()) != T_COLON)            /* optional colon    */
  73.         ungettok(tok);
  74.     
  75.     return OK;
  76. }
  77.  
  78.  
  79. /************************************************************
  80.  * do_title():
  81.  *    Process the TITLE clause for a menu.
  82.  ************************************************************/
  83.  
  84. int do_title()
  85. {
  86.     int tok;
  87.  
  88.     if ((tok = gettok()) != T_STRING)
  89.     {
  90.         error("Title text missing");
  91.         ungettok(tok);
  92.     }
  93.         
  94.     if (!in_item)            /* Before all items?        */
  95.     {                        /* yes.                        */
  96.         if (*Mp->title)
  97.             return error("A Menu Title has already been specified");
  98.         if (strlen(tparam) > MAX_TXTWID - 1)
  99.             return error("Menu Title is too long (max %d chars)",
  100.                     MAX_TXTWID-1);
  101.         strcpy(Mp->title, tparam);
  102.     }
  103.     else
  104.         return error("The Menu Title must precede all Menu Items.");
  105.  
  106.     return OK;
  107. }
  108.  
  109.  
  110. /************************************************************
  111.  * do_path():
  112.  *    Process the PATH option.
  113.  *    Note that the PATH option may apply to an entire
  114.  *    menu or just to a single menu item (determined
  115.  *    by context.)
  116.  ************************************************************/
  117.  
  118. int do_path()
  119. {
  120.     int tok;
  121.     char c, *cp;
  122.     
  123.     if ((tok = gettok()) != T_STRING)
  124.     {
  125.         error("Path text missing");
  126.         ungettok(tok);
  127.     }
  128.         
  129.     if ((c = tparam[strlen(tparam) - 1]) == '/' || c == '\\')    /* delete */
  130.         tparam[strlen(tparam) - 1] = '\0';                /* traling slash  */
  131.  
  132.     if (strlen(tparam) > MAX_PATH - 1)
  133.         return error("The specified path is too long (max %d chars)",
  134.                 MAX_PATH - 1);
  135.  
  136.     if (!in_item)            /* Referring to the menu?    */
  137.     {                        /* yes.                        */
  138.         if (*Mp->path)
  139.             return error("A Menu Path has already been specified");
  140.         strcpy(Mp->path, tparam);
  141.     }
  142.     else
  143.     {                        /* Must be for the item.    */
  144.         if (*Ip->path)
  145.             return error("An Item Path has already been specified");
  146.         strcpy(Ip->path, tparam);
  147.     }
  148.     return OK;
  149. }
  150.  
  151.  
  152. /************************************************************
  153.  * do_align():
  154.  *    Process text alignment option.
  155.  *  Note: this option is a no-op. I decided there wasn't
  156.  *    any real need for any other than left-justified item
  157.  *    alignment. But, in case anyone thinks of a use for it,
  158.  *    I'm leaving in the ability to process the option.
  159.  ************************************************************/
  160.  
  161. int do_align()
  162. {
  163.     int tok;
  164.     
  165.     if (in_item)
  166.         return error("The Align clause must precede all Menu Items.");
  167.  
  168.     if (Mp->align)
  169.         return error("Align option already specified for this menu");
  170.     
  171.     switch (tok = gettok())
  172.     {
  173.         case T_LEFT:
  174.             Mp->align = 'L'; 
  175.             break;
  176.             
  177.         case T_RIGHT:
  178.             Mp->align = 'R';
  179.             break;
  180.             
  181.         case T_CENTER:
  182.             Mp->align = 'C';
  183.             break;
  184.             
  185.         default:
  186.             ungettok(tok);
  187.             return error("Align missing valid modifier");
  188.     }
  189.     return OK;
  190. }
  191.  
  192.  
  193. /************************************************************
  194.  * do_spacing():
  195.  *    Process the SPACING option (applies
  196.  *    to menus only.)
  197.  ************************************************************/
  198.  
  199. int do_spacing()
  200. {
  201.     int tok;
  202.  
  203.     if ((tok = gettok()) != T_VALUE)
  204.     {
  205.         error("Spacing value missing");
  206.         ungettok(tok);
  207.     }
  208.  
  209.     if (in_item)
  210.         return error("Spacing option must precede all menu items");
  211.  
  212.     if (Mp->spacing)
  213.         return error("Spacing option already specified");
  214.  
  215.              /* only single and double spacing supported    */
  216.     if (vparam != 1 && vparam != 2)
  217.         return error("Spacing value must be either 1 or 2");
  218.  
  219.     Mp->spacing = vparam;
  220.     return OK;
  221. }
  222.  
  223.  
  224. /************************************************************
  225.  * do_columns():
  226.  *    Process the COLUMNS option
  227.  ************************************************************/
  228.  
  229. int do_columns()
  230. {
  231.     int tok;
  232.     
  233.     if ((tok = gettok()) != T_VALUE)
  234.     {
  235.         error("Columns value missing");
  236.         ungettok(tok);
  237.     }
  238.  
  239.     if (in_item)
  240.         return error("Columns option must precede all menu items");
  241.  
  242.     if (Mp->columns)
  243.         return error("Columns option already specified");
  244.  
  245.     if (vparam < 1 || vparam > 6)    /*  6 seems a reasonable max. */
  246.         return error("Columns value must be between 1 and 6");
  247.     Mp->columns = vparam;
  248.     return OK;
  249. }
  250.  
  251.  
  252. /************************************************************
  253.  * do_escape():
  254.  *    Process "escape" and "noescape" menu options
  255.  ************************************************************/
  256.  
  257. int do_escape()
  258. {
  259.     if (in_item)
  260.         return error("\"%s\" must appear before all menu items",
  261.             keywords[token].keyword);
  262.     
  263.     if (Mp->escape)
  264.         return error("Escape option already specified");
  265.     Mp->escape = (token == T_ESCAPE) ? YES : NO;
  266.  
  267.     return OK;
  268. }
  269.  
  270.  
  271. /************************************************************
  272.  * do_endmenu():
  273.  *    Process ENDMENU keyword
  274.  ************************************************************/
  275.  
  276. int do_endmenu()
  277. {
  278.     int i;
  279.     
  280.     if (!n_items)
  281.         error("No menu items specified for this menu");
  282.     
  283.     for (i = 0; i < n_refs; i++)        /* check for unresolved        */
  284.     {                                    /* forward Item references    */
  285.         if (*fwd_refs[i].refp == UNDEF_FWD)
  286.         {
  287.             int save_lineno = lineno;
  288.             lineno = fwd_refs[i].lineno;
  289.             error("Unresolved reference to Item \"%s\"",
  290.                 fwd_refs[i].iname);
  291.             lineno = save_lineno;
  292.         }
  293.     }
  294.     
  295.     in_menu = in_item = FALSE;            /* done with current menu    */
  296.     MIp -> Processed = TRUE;            /* it is now processed        */
  297.     Mp -> nitems = n_items;
  298.     return OK;
  299. }
  300.  
  301.  
  302. /************************************************************
  303.  * do_item():
  304.  *    Process the ITEM clause. Create a new ite
  305.  *    and fill in any existing forward references to it.
  306.  ************************************************************/
  307.  
  308. int do_item()
  309. {
  310.     int tok, i;
  311.     char *cp, c;
  312.     
  313.     if (n_items)
  314.         itemcheck();    /* check for previous item's completion */
  315.  
  316.     if ((tok = gettok()) != T_STRING)    /* label specified?        */
  317.     {                                    /* If not, stuff unique    */
  318.         sprintf(tparam,"dummy!%d", n_items);  /* dummy name in    */    
  319.             ungettok(tok);
  320.     }
  321.     else
  322.     {
  323.         if (strlen(tparam) > MAX_NAME)
  324.         {
  325.             error("Item name \"%s\" too long. Max %d chars.",
  326.                         tparam, MAX_NAME);
  327.             tparam[MAX_NAME] = '\0';
  328.         }
  329.         else for (cp = tparam; c = *cp; cp++)
  330.             if (!(isalpha(c) || isdigit(c) || c == '_'))
  331.             {
  332.                 error("Invalid char in identifier name: \"%s\"",
  333.                             tparam);
  334.                 *cp = '\0';
  335.                 break;
  336.             }
  337.     }
  338.     
  339.     if ((IIp = find_item(tparam)) != NULL)    /* Item name found?    */
  340.         return error("Item name previously used.");
  341.  
  342.     if ((MIp->Items[n_items] = IIp = create_item(tparam))
  343.                 == NULL)
  344.         return ERROR;
  345.  
  346.     in_item = TRUE;
  347.     Ip = &IIp->Item;
  348.  
  349.     for (i = 0; i < n_refs; i++)        /* check for fwd refs    */
  350.         if (!strcmp(fwd_refs[i].iname, tparam))
  351.             *fwd_refs[i].refp = n_items; /* fill in with item #    */
  352.  
  353.     n_items++;                            /* bump item count        */
  354.  
  355.      if ((token = gettok()) != T_COLON)    /* optional colon?        */
  356.     {
  357.         ungettok(token);                /* if not, all done        */
  358.         return OK;
  359.     }
  360.     
  361.     if ((token = gettok()) == T_STRING)    /* short-form text?        */
  362.         return do_text2();                /* if so, go process    */
  363.     else
  364.     {
  365.         ungettok(token);                /* else all done        */
  366.         return OK;
  367.     }
  368. }
  369.  
  370.  
  371. /************************************************************
  372.  * do_opts():
  373.  *    Process simple "binary" options for prompt,
  374.  *    pre- and post-clear specifications.
  375.  *    Note: upon entry, global "token" contains the 
  376.  *    value of the token to be processed.
  377.  ************************************************************/
  378.  
  379. int do_opts()
  380. {
  381.     if (!in_item)
  382.         return error("\"%s\" only valid within an item",
  383.             keywords[token].keyword);
  384.     
  385.     switch(token)
  386.     {
  387.         case T_PROMPT: case T_PAUSE:
  388.         case T_NOPROMPT: case T_NOPAUSE:
  389.             if (Ip->prompt != DEFAULT)
  390.                 return error("Prompt option already specified");
  391.             Ip->prompt= (token==T_PROMPT || token==T_PAUSE)? YES :NO;
  392.             break;
  393.             
  394.         case T_POSTCLEAR:        /* these are actually no-ops,    */
  395.         case T_NOPOSTCLEAR:        /* but again, I've left them in */
  396.             if (Ip->post_clear != DEFAULT)
  397.                 return error("Postclear option already specified");
  398.             Ip->post_clear = (token == T_POSTCLEAR) ? YES : NO;
  399.             break;
  400.  
  401.         case T_PRECLEAR:
  402.         case T_NOPRECLEAR:
  403.             if (Ip->pre_clear != DEFAULT)
  404.                 return error("Preclear option already specified");
  405.             Ip->pre_clear = (token == T_PRECLEAR) ? YES : NO;
  406.             break;
  407.     }
  408.     return OK;
  409. }
  410.  
  411.  
  412. /************************************************************
  413.  * do_nextitem():
  414.  *    Process NEXTIEM option.
  415.  ************************************************************/
  416.  
  417. int do_nextitem()
  418. {
  419.     int tok;
  420.     
  421.     if (Ip->nextcode != DEFAULT)
  422.         error("Nextitem option already specified");
  423.     
  424.     switch (tok = gettok())
  425.     {
  426.         case T_FIRST:
  427.             Ip->nextcode = NXT_FIRST;
  428.             break;
  429.             
  430.         case T_LAST:
  431.             Ip->nextcode = NXT_LAST;
  432.             break;
  433.             
  434.         case T_NEXT:
  435.             Ip->nextcode = NXT_NEXT;
  436.             break;
  437.             
  438.         case T_STRING:
  439.             Ip->nextcode = NXT_DIRECT;
  440.             if (find_item(tparam))
  441.                 Ip->nextitem = item_num;
  442.             else
  443.             {                    /* record forward item reference */
  444.                 strcpy(fwd_refs[n_refs].iname, tparam);
  445.                 fwd_refs[n_refs].refp = &Ip->nextitem;
  446.                 fwd_refs[n_refs++].lineno = lineno;
  447.                 Ip->nextitem = UNDEF_FWD;
  448.             }
  449.             break;
  450.         
  451.         default:
  452.             ungettok(tok);
  453.             return error("Bad Nextitem specification");
  454.     }
  455.     return OK;
  456. }
  457.  
  458.  
  459. /************************************************************
  460.  * do_text():
  461.  *    Process Text parameter
  462.  ************************************************************/
  463.  
  464. int do_text()
  465. {
  466.     int tok;
  467.     
  468.     if (!in_item)
  469.         return error("Text clause must be within an item");
  470.     if (*Ip->text)
  471.         return error("Text clause already specified for this item");
  472.     
  473.     if ((tok = gettok()) != T_STRING)
  474.     {
  475.         ungettok(tok);
  476.         return error("Text clause specified without the text.");
  477.     }
  478.     
  479.     return do_text2();
  480. }
  481.  
  482.  
  483. /************************************************************
  484.  * do_text():
  485.  *    Continued TEXT clause processing, shared between
  486.  *    do_text() and do_item().
  487.  ************************************************************/
  488.  
  489. int do_text2()
  490. {
  491.     if (strlen(tparam) > MAX_TXTWID - 1)
  492.     {
  493.         *Ip->text = 'x';        /* to avoid "missing text" error */
  494.         return error("Text is too long; maximum %d chars",
  495.             MAX_TXTWID - 1);
  496.     }
  497.     else
  498.         strcpy(Ip->text, tparam);
  499.  
  500.     if (strlen(tparam) > Mp -> widest)
  501.         Mp -> widest = strlen(tparam);
  502.  
  503.     return OK;
  504. }
  505.  
  506.  
  507. /************************************************************
  508.  * do_action():
  509.  *    Process standard action, Exit, Lmenu or Emenu clause
  510.  ************************************************************/
  511.  
  512. int do_action()
  513. {
  514.     int tok;
  515.     int old_acttyp = Ip->acttyp;
  516.     
  517.     if (!in_item)
  518.         return error("%s clause only valid within an item",
  519.             keywords[token].keyword);
  520.     
  521.     if (token == T_EXIT || (tok = gettok()) == T_EXIT)
  522.         Ip->acttyp = ACT_EXIT;
  523.     else
  524.         if (tok != T_STRING)
  525.         {
  526.             ungettok(tok);
  527.             error("Incomplete %s specification",
  528.             keywords[token].keyword);
  529.         }
  530.     else 
  531.         if (strlen(tparam) > MAX_CMD - 1)
  532.             error("%s parameter too long (max %d chars)",
  533.                 keywords[token].keyword, MAX_CMD - 1);
  534.     else
  535.         switch(token)
  536.         {
  537.           case T_ACTION:
  538.             strcpy(Ip->action, tparam);
  539.             Ip->acttyp = ACT_CMND;
  540.             break;
  541.             
  542.           case T_LMENU:
  543.             if (find_menu(tparam) != NULL)        /* named menu defined?    */
  544.                 Ip->lmenunum = menu_num;        /* yes.                    */
  545.             else
  546.             {                                    /* no. create entry        */
  547.                 MInfo[n_menus] = create_menu(tparam);
  548.                 if (fatal)
  549.                     return ERROR;                /* creation error        */
  550.                 else
  551.                     Ip->lmenunum = n_menus++;        /* OK; assign.        */
  552.             }
  553.             
  554.             Ip->acttyp = ACT_LMENU;
  555.             break;
  556.             
  557.           case T_EMENU:
  558.             strcpy(Ip->action, tparam);
  559.             Ip->acttyp = ACT_EMENU;
  560.             break;
  561.         }
  562.  
  563.     if (old_acttyp)
  564.         return error("Only one Action clause allowed per item");
  565.     
  566.     return OK;
  567. }
  568.  
  569.  
  570. /************************************************************
  571.  * do_help():
  572.  *    Process help clause.
  573.  ************************************************************/
  574.  
  575. int do_help()
  576. {
  577.     int tok;
  578.     
  579.     if (!in_item)
  580.         return error("Help clause only valid within an item");
  581.  
  582.     if ((tok = gettok()) != T_STRING)
  583.     {
  584.         ungettok(tok);
  585.         return error("No Help text specified");
  586.     }
  587.     
  588.     if (strlen(tparam) > MAX_HELP - 1)
  589.         return error("Help text too long (max %d chars)",
  590.             MAX_HELP - 1);
  591.         
  592.     if (*Ip->help)
  593.         return error("Only one help line allowed per item");
  594.     
  595.     strcpy(Ip->help, tparam);
  596.     return OK;
  597. }
  598.  
  599.  
  600. /************************************************************
  601.  * do_err():
  602.  *    Diagnose hopelessly bad syntax (i.e., encountering a
  603.  *    totally unexpected keyword)
  604.  ************************************************************/
  605.  
  606. int do_err()
  607. {
  608.     return fatalerr("Unrecoverable Syntax error.");
  609. }
  610.  
  611.