home *** CD-ROM | disk | FTP | other *** search
/ rtsi.com / 2014.01.www.rtsi.com.tar / www.rtsi.com / OS9 / OSK / TELECOM / stg_v4.lzh / smenu.c < prev    next >
C/C++ Source or Header  |  1994-11-11  |  20KB  |  1,227 lines

  1. /*
  2.  * smenu
  3.  *
  4.  * Copyright (c) 1993 by Scott Griepentrog
  5.  *
  6. */
  7.  
  8. #include <time.h>
  9. #include "stgnet.h"
  10. #include "trm.h"
  11. #include "pwd.h"
  12.  
  13. char *malloc();
  14. extern char **environ;
  15.  
  16. #define MAX_SIZE 8192    /* max .mnu file size */
  17.  
  18. char acBuffer[BUF_SIZE];
  19.  
  20. struct passwd *pwd;
  21. char *pcUser;
  22.  
  23. int iTest=0;            /* test mode */
  24.  
  25. char *apcHigh[]=
  26. {
  27.     "so","se",
  28.     "us","ue",
  29.     "mb","mr",
  30.     "md","me",
  31.     0
  32. };
  33.  
  34. char acHigh[32];            /* highlight start */
  35. char acHend[32];            /* highlight end */
  36.  
  37. struct sSel
  38. {
  39.     struct sSel *psNext;        /* linked list */
  40.     char *pcKey;            /* key label */
  41.     char *pcCmd;            /* command string */
  42.     char cKey;            /* key to press */
  43.     char cOff;            /* offset in pcKey to cKey */
  44. };
  45.  
  46. struct sMenu
  47. {
  48.     struct sMenu *psNext;        /* linked list */
  49.     char acFile[32];        /* menu name */
  50.     char *pcText;            /* entire menu file */
  51.     int iSize;            /* length of text */
  52.     struct sSel *psSel;        /* link list of selections */
  53.     char *pcPrompt;            /* prompt string */
  54.     char cInUse;            /* recusrion check */
  55. } *psMenuList=0;
  56.  
  57. char *
  58. strsav(s)
  59. char *s;
  60. {
  61.     char *p;
  62.  
  63.     p=malloc(strlen(s)+1);
  64.     if (!p)
  65.     {
  66.         syserr("malloc: %m");
  67.         exit(errno);
  68.     }
  69.     strcpy(p,s);
  70.     return(p);
  71. }
  72. char *
  73. strnsav(s,n)
  74. char *s;
  75. int n;
  76. {
  77.     char *p;
  78.  
  79.     p=malloc(n+1);
  80.     if (!p)
  81.     {
  82.         syserr("malloc: %m");
  83.         exit(errno);
  84.     }
  85.     strncpy(p,s,n);
  86.     p[n]=0;
  87.     return(p);
  88. }
  89.  
  90. /* reload menus in use - termcap has changed */
  91. void
  92. ReLoad()
  93. {
  94.     struct sMenu *psMenu;
  95.  
  96.     psMenu=psMenuList;
  97.     while (psMenu)
  98.     {
  99.         Prompt(psMenu);
  100.         psMenu=psMenu->psNext;
  101.     }
  102. }
  103.  
  104. void
  105. PickHigh()
  106. {
  107.     char *hi,*he;
  108.     char **ppcCode;
  109.  
  110.     ppcCode=apcHigh;
  111.     while (*ppcCode)
  112.     {
  113.         hi=_TrmString(*ppcCode++);
  114.         he=_TrmString(*ppcCode++);
  115.         if (!hi || !he)
  116.             continue;
  117.  
  118.         strcpy(acHigh,_TrmConvert(hi));
  119.         strcpy(acHend,_TrmConvert(he));
  120.         return;
  121.     }
  122.     *acHigh=*acHend=0;
  123. }
  124.  
  125. Fork(pcCmd)
  126. char *pcCmd;
  127. {
  128.     int iPid;
  129.  
  130.     int iWait;
  131.     char **ppcArgs;
  132.  
  133.     ppcArgs=arglist(pcCmd,0);
  134.     if (*pcCmd=='-')
  135.         pcCmd++;
  136.  
  137.     if (!stricmp(ppcArgs[0],"unsetenv"))
  138.     {
  139.         if (!ppcArgs[1])
  140.         {
  141.             syserr("unsetenv take one argument\n");
  142.             return(ERR);
  143.         }
  144.         set_env(ppcArgs[1],0);
  145.         return(0);
  146.     }
  147.     if (!stricmp(ppcArgs[0],"setenv"))
  148.     {
  149.         if (!ppcArgs[1] || !ppcArgs[2])
  150.         {
  151.             syserr("setenv takes two arguments\n");
  152.             return(ERR);
  153.         }
  154.  
  155.         if (!strcmp(ppcArgs[1],"TERM"))
  156.         {
  157.             if (_Trm(ppcArgs[2])==ERR)
  158.             {
  159.                 wstringf(2,"smenu: unknown terminal type '%s'\n",ppcArgs[2]);
  160.  
  161.                 /* reload from var */
  162.                 if (_Trm(getenv("TERM"))!=ERR)
  163.                     PickHigh();
  164.                 return(ERR);
  165.             }
  166.             else
  167.             {
  168.                 PickHigh();
  169.                 ReLoad();
  170.             }
  171.         }
  172.  
  173.         set_env(ppcArgs[1],ppcArgs[2]);
  174.  
  175.         return(0);
  176.     }
  177.  
  178.     iPid=_fork(pcCmd,ppcArgs,environ);
  179.     if (iPid==ERR)
  180.     {
  181.         syserr("cant fork %s: %m",*ppcArgs);
  182.         return(ERR);
  183.     }
  184.  
  185.     /* for unix: ignore ^C while waiting */
  186.     signal(SIGINT,SIG_IGN);
  187.     signal(SIGQUIT,SIG_IGN);
  188.  
  189.     while (1)
  190.     {
  191.         iWait=wait(&errno);
  192.         if (iWait==ERR)
  193.         {
  194.             syserr("wait %s %m",*ppcArgs);
  195.             goto fork_err;
  196.         }
  197.         if (iWait==iPid)
  198.             break;
  199.     }
  200.     if (errno)
  201.     {
  202. #ifdef _OS9
  203.         syserr("'%s' exited: %m",pcCmd);
  204. #else
  205.         if (errno&0x7F)
  206.             syserr("'%s' exit signal %d",pcCmd,errno&0x7F);
  207.         else
  208.             syserr("'%s' exit code %d",pcCmd,errno>>8);
  209. #endif
  210.         goto fork_err;
  211.     }
  212.     return(0);
  213.  
  214. fork_err:
  215.     signal(SIGINT,SIG_DFL);
  216.     signal(SIGQUIT,SIG_DFL);
  217.  
  218.     return(ERR);
  219. }
  220.  
  221. Run(pcCmd,ppcArgs)
  222. char *pcCmd;
  223. char **ppcArgs;
  224. {
  225.     int iMenu=0;
  226.     int iExit=0;
  227.     char *pcBuf;
  228.     char *pcTemp;
  229.     char **ppcTemp;
  230.     int iTemp;
  231.     char acInput[256];
  232.     char acTemp[256];
  233.  
  234.     pcBuf=acBuffer;
  235.     *acInput=0;
  236.  
  237.     switch (*pcCmd)
  238.     {
  239.     case '-':
  240.         iMenu++;
  241.         pcCmd++;
  242.         break;
  243.  
  244.     case '+':
  245.         iMenu++;
  246.     case '#':
  247.         iExit++;
  248.         pcCmd++;
  249.         break;
  250.  
  251.     case '=':
  252.         pcCmd++;
  253.     default:
  254.         break;
  255.     }
  256.  
  257.     while (*pcCmd)
  258.     {
  259.         if (*pcCmd=='\\')
  260.         {
  261.             /* pass next character regardless */
  262.             *pcCmd++;
  263.             *pcBuf++=*pcCmd++;
  264.             continue;
  265.         }
  266.         if (*pcCmd=='%')
  267.         {
  268.             if (!*++pcCmd)
  269.                 break;
  270.  
  271.             switch(*pcCmd)
  272.             {
  273.             case '(':
  274.                 pcCmd++;
  275.                 pcTemp=acTemp;
  276.                 while (*pcCmd && *pcCmd!=')')
  277.                     *pcTemp++=*pcCmd++;
  278.                 if (*pcCmd)
  279.                     pcCmd++;
  280.                 *pcTemp=0;
  281.                 pcTemp=getenv(acTemp);
  282.                 if (pcTemp) while (*pcTemp)
  283.                     *pcBuf++=*pcTemp++;
  284.                 break;
  285.  
  286.             case '\'':
  287.                 pcCmd++;
  288.                 pcTemp=acTemp;
  289.                 while (*pcCmd && *pcCmd!='\'')
  290.                     *pcTemp++=*pcCmd++;
  291.                 if (*pcCmd)
  292.                     pcCmd++;
  293.                 *pcTemp=0;
  294.                 writeln(2,acTemp,strlen(acTemp));
  295.                 if (get_line(acInput,128,0)==ERR)
  296.                     return(ERR);
  297.                 pcTemp=acInput;
  298.                 while (*pcTemp)
  299.                     *pcBuf++=*pcTemp++;
  300.                 break;
  301.  
  302.             case '@':
  303.                 pcTemp=acInput;
  304.                 while (*pcTemp)
  305.                     *pcBuf++=*pcTemp++;
  306.                 break;
  307.  
  308.             case '0':
  309.             case '1':
  310.             case '2':
  311.             case '3':
  312.             case '4':
  313.             case '5':
  314.             case '6':
  315.             case '7':
  316.             case '8':
  317.             case '9':
  318.                 if (ppcArgs)
  319.                 {
  320.                     ppcTemp=ppcArgs;
  321.                     iTemp=*pcCmd++-'0';
  322.                     while (iTemp-- && *ppcTemp)
  323.                         ppcTemp++;
  324.                     if (*ppcTemp)
  325.                     {
  326.                         pcTemp=*ppcTemp;
  327.                         while (*pcTemp)
  328.                             *pcBuf++=*pcTemp++;
  329.                     }
  330.                 }
  331.                 break;
  332.  
  333.             case '^':
  334.                 pcCmd++;
  335.                 if (!*acInput)
  336.                     return(0);
  337.                 break;
  338.  
  339.             default:
  340.                 syserr("unknown code %%%c",*pcCmd);
  341.                 return(ERR);
  342.             }
  343.             continue;
  344.         }
  345. /* don't need quotes with \ escape
  346.         if (*pcCmd==34)
  347.         {
  348.             if (*++pcCmd==34)
  349.             {
  350.                 *pcBuf++=34;
  351.                 pcCmd++;
  352.                 continue;
  353.             }            
  354.             while (*pcCmd && *pcCmd!=34)
  355.                 *pcBuf++=*pcCmd++;
  356.             if (*pcCmd)
  357.                 pcCmd++;
  358.             continue;
  359.         }
  360. */
  361.         if (*pcCmd==';')
  362.         {
  363.             *pcBuf=0;
  364.             if (Fork(acBuffer)==ERR)
  365.                 return(0);
  366.             pcCmd++;
  367.             pcBuf=acBuffer;
  368.             continue;
  369.         }
  370.         *pcBuf++=*pcCmd++;
  371.     }
  372.     *pcBuf=0;
  373.  
  374.     if (iMenu)
  375.         Menu(acBuffer);
  376.     else
  377.         Fork(acBuffer);
  378.  
  379.     if (iExit)
  380.         exit(0);
  381.  
  382.     return(0);
  383. }
  384.  
  385. Prompt(psMenu)
  386. struct sMenu *psMenu;
  387. {
  388.     struct sSel *psSel;
  389.     char acPrompt[256];
  390.     char *pcPrompt;
  391.     char *pcTemp;
  392.     char *pcHigh;
  393.     int iPrompt;
  394.     int iWidth;
  395.     int iFirst;
  396.  
  397.     iWidth=_TrmNumber("co");
  398.     if (!iWidth)
  399.         iWidth=80;
  400.  
  401.     pcPrompt=acPrompt;
  402.     iPrompt=0;
  403.     iFirst=1;
  404.  
  405.     /* have to put menu name in prompt string for later width adjustment */
  406.     pcTemp=psMenu->acFile;
  407.     while (*pcTemp)
  408.     {
  409.         if (!iPrompt)
  410.             *pcPrompt++=toupper(*pcTemp++);
  411.         else
  412.             *pcPrompt++=*pcTemp++;
  413.         iPrompt++;
  414.     }
  415.     *pcPrompt++=':';
  416.     *pcPrompt++=' ';
  417.     iPrompt+=2;
  418.  
  419.     /* loop on selection list */
  420.     psSel=psMenu->psSel;
  421.     while (psSel)
  422.     {
  423.         /* if no pcCmd, selection is not allowed */
  424.         if (!psSel->pcCmd)
  425.         {
  426.             psSel=psSel->psNext;
  427.             continue;
  428.         }
  429.  
  430.         /* is there enough space for this entry? */
  431.         if (iPrompt>iWidth/2 && iPrompt+strlen(psSel->pcKey)+3+10>iWidth)
  432.         {
  433.             /* no, go to next line */
  434.             *pcPrompt++='\n';
  435.             *pcPrompt++='\r';
  436.             iPrompt=0;
  437.             iFirst=1;
  438.             pcTemp=psMenu->acFile;
  439.             while (*pcTemp++)
  440.             {
  441.                 *pcPrompt++=' ';
  442.                 iPrompt++;
  443.             }
  444.             *pcPrompt++=' ';
  445.             *pcPrompt++=' ';
  446.             iPrompt+=2;
  447.         }
  448.  
  449.         /* add to prompt */
  450.         if (!iFirst)
  451.         {
  452.             *pcPrompt++=',';
  453.             *pcPrompt++=' ';
  454.             iPrompt+=2;
  455.         }
  456.         else
  457.             iFirst=0;
  458.  
  459.         pcTemp=psSel->pcKey;
  460.         while (*pcTemp)
  461.         {
  462.             if (pcTemp-psSel->pcKey==psSel->cOff)
  463.             {
  464.                 pcHigh=acHigh;
  465.                 if (!*pcHigh)
  466.                 {
  467.                     *pcPrompt++='[';
  468.                     iPrompt++;
  469.                 }
  470.                 else
  471.                 while (*pcHigh)
  472.                     *pcPrompt++=*pcHigh++;
  473.                 *pcPrompt++=toupper(*pcTemp++);
  474.                 iPrompt++;
  475.                 pcHigh=acHend;
  476.                 if (!*pcHigh)
  477.                 {
  478.                     *pcPrompt++=']';
  479.                     iPrompt++;
  480.                 }
  481.                 else
  482.                 while (*pcHigh)
  483.                     *pcPrompt++=*pcHigh++;
  484.             }
  485.             else if (pcTemp-psSel->pcKey<psSel->cOff)
  486.             {
  487.                 *pcPrompt++=tolower(*pcTemp++);
  488.                 iPrompt++;
  489.             }
  490.             else
  491.             {
  492.                 *pcPrompt++=*pcTemp++;
  493.                 iPrompt++;
  494.             }
  495.         }
  496.         psSel=psSel->psNext;
  497.     }
  498.     *pcPrompt++=' ';
  499.     *pcPrompt++=':';
  500.     *pcPrompt=0;
  501.  
  502.     if (psMenu->pcPrompt)
  503.         free(psMenu->pcPrompt);
  504.     psMenu->pcPrompt=strsav(acPrompt);
  505.     return(0);
  506. }
  507.  
  508. Parse(psMenu)
  509. struct sMenu *psMenu;
  510. {
  511.     char *pcText;
  512.     char *pcEnd;
  513.     char *pcLine;
  514.     char *pcTemp;
  515.     char *pcLast;
  516.     char cLast;
  517.     struct sSel *psSel;
  518.     struct sSel *psSeek;
  519.     char acKeyUsed[128];
  520.  
  521.     /* clear key map */
  522.     memset(acKeyUsed,0,128);
  523.     pcLast="";
  524.  
  525.     /* skip display section */
  526.     pcText=psMenu->pcText;
  527.     pcEnd=pcText+psMenu->iSize;
  528.     while (pcText<pcEnd)
  529.     {
  530.         if (*pcText=='~' && pcText[1]=='\n')
  531.             break;
  532.         while (pcText<pcEnd && *pcText!='\n')
  533.             pcText++;
  534.         if (pcText<pcEnd)
  535.             pcText++;
  536.     }
  537.     if (pcText==pcEnd)
  538.     {
  539.         syserr("unexpected EOF in %s",
  540.             psMenu->acFile);
  541.         return(ERR);
  542.     }
  543.  
  544.     /* terminate display section */
  545.     *pcText++=0;
  546.     *pcText++=0;
  547.  
  548.     /* loop through remainder */
  549.     while (pcText<pcEnd)
  550.     {
  551.         pcLine=pcText;
  552.  
  553.         /* find end of line */
  554.         while (pcText<pcEnd && *pcText!='\n')
  555.             pcText++;
  556.  
  557.         if (pcText==pcEnd)
  558.         {
  559.             syserr("unexpected EOF in %s",
  560.                 psMenu->acFile);
  561.             return(ERR);
  562.         }
  563.         *pcText++=0;
  564.  
  565.         /* ignore empty or single char line */
  566.         if (!*pcLine || !pcLine[1])
  567.             continue;
  568.  
  569.         /* add line to selection list */
  570.         psSel=(struct sSel *)malloc(sizeof(*psSel));
  571.         if (!psSel)
  572.         {
  573.             syserr("malloc: %m");
  574.             return(ERR);
  575.         }
  576.         memset(psSel,0,sizeof(*psSel));
  577.  
  578.         /* add to END of list */
  579.         if (!psMenu->psSel)
  580.             psMenu->psSel=psSel;
  581.         else
  582.         {
  583.             psSeek=psMenu->psSel;
  584.             while (psSeek && psSeek->psNext)
  585.                 psSeek=psSeek->psNext;
  586.  
  587.             psSeek->psNext=psSel;
  588.         }
  589.  
  590.         /* now parse selection line */
  591.         pcTemp=pcLine;
  592.  
  593.         /* first, hunt separator code */
  594.         pcTemp++;    /* first char at least is not a char */
  595.         while (*pcTemp)
  596.         {
  597.             if (*pcTemp=='\\')
  598.             {
  599.                 pcTemp++;
  600.                 if (*pcTemp)
  601.                     pcTemp++;
  602.                 continue;
  603.             }
  604.             if (*pcTemp==' ' || *pcTemp=='/')
  605.             {
  606.                 pcTemp++;
  607.                 continue;
  608.             }
  609.             if (*pcTemp<'@')
  610.                 break;
  611.  
  612.             pcTemp++;
  613.         }
  614.         if (!*pcTemp)
  615.         {
  616.             syserr("syntax error at '%s' in %s",
  617.                 pcLine,psMenu->acFile);
  618.             return(ERR);
  619.         }
  620.  
  621.         /* save key label */
  622.         psSel->pcKey=strnsav(pcLine,pcTemp-pcLine);
  623.         pcLine=pcTemp;
  624.  
  625.         /* and remove \'s */
  626.         pcTemp=psSel->pcKey;
  627.         while (*pcTemp)
  628.         {
  629.             if (*pcTemp=='\\')
  630.             {
  631.                 strcpy(pcTemp,pcTemp+1);
  632.                 if (*pcTemp)
  633.                     pcTemp++;
  634.             }
  635.             else
  636.                 pcTemp++;
  637.         }
  638.  
  639.         /* and select key code */
  640.         pcTemp=psSel->pcKey;
  641.         while (*pcTemp)
  642.         {
  643.             if (*pcTemp=='~')
  644.             {
  645.                 strcpy(pcTemp,pcTemp+1);
  646.                 break;
  647.             }
  648.             pcTemp++;
  649.         }
  650.         if (!*pcTemp)
  651.         {
  652.             pcTemp=psSel->pcKey;
  653.             if (!strcmp(pcTemp,pcLast))
  654.                 pcTemp=psSel->pcKey+cLast;
  655.             else
  656.             while (*pcTemp)
  657.             {
  658.                 if (!acKeyUsed[toupper(*pcTemp)])
  659.                     break;
  660.                 pcTemp++;
  661.             }
  662.         }
  663.         if (!*pcTemp)
  664.         {
  665.             syserr("cant set key for %s in %s",
  666.                 psSel->pcKey,psMenu->acFile);
  667.             return(ERR);
  668.         }
  669.  
  670.         psSel->cKey=toupper(*pcTemp);
  671.         acKeyUsed[psSel->cKey]++;
  672.         psSel->cOff=pcTemp-psSel->pcKey;
  673.  
  674.         pcLast=psSel->pcKey;
  675.         cLast=psSel->cOff;
  676. next_code:
  677.         switch (*pcLine)
  678.         {
  679.         case '-':
  680.         case '=':
  681.         case '#':
  682.             psSel->pcCmd=pcLine;
  683.             break;
  684.         case '?':
  685.         case '!':
  686.             pcTemp=pcLine+1;
  687.             while (*pcTemp && *pcTemp>'@')
  688.                 pcTemp++;
  689.             strncpy(b,pcLine+1,pcTemp-pcLine);
  690.             b[pcTemp-pcLine-1]=0;
  691.             if (*pcLine=='?')
  692.             {
  693.                 if (!isgrpmem(b,pcUser))
  694.                     continue;
  695.             }
  696.             else
  697.             {
  698.                 if (isgrpmem(b,pcUser))
  699.                     continue;
  700.             }
  701.             pcLine=pcTemp;
  702.             goto next_code;
  703.  
  704.         default:
  705.             strcpy(b,pcLine);
  706.             if (strlen(b)>10)
  707.                 strcpy(b+10,"...");
  708.             syserr("unknown code '%s' in %s",
  709.                 b,psMenu->acFile);
  710.             return(ERR);
  711.         }
  712.  
  713.     }
  714.  
  715.     /* set prompt from selection list */
  716.     if (Prompt(psMenu))
  717.         return(ERR);
  718.  
  719.     return(0);
  720. }
  721.  
  722. struct sMenu *
  723. Load(pcFile)
  724. char *pcFile;
  725. {
  726.     struct sMenu *psMenu;
  727.     int hFile;
  728.     long lSize;
  729.  
  730.     stringf(b,"%s/%s.mnu",MENU_DIR,pcFile);
  731.  
  732.     hFile=open(b,O_RDONLY);
  733.     if (hFile==ERR)
  734.     {
  735.         syserr("cant open %s: %m",b);
  736.         return(0);
  737.     }
  738.  
  739.     lSize=_gs_size(hFile);
  740.     if (lSize>MAX_SIZE)
  741.     {
  742.         syserr("menu %s is too large",pcFile);
  743.         close(hFile);
  744.         return(0);
  745.     }
  746.     psMenu=(struct sMenu *)malloc(sizeof(*psMenu));
  747.     if (!psMenu)
  748.     {
  749.         syserr("malloc: %m");
  750.         close(hFile);
  751.         return(0);
  752.     }
  753.     memset(psMenu,0,sizeof(*psMenu));
  754.  
  755.     psMenu->iSize=(int)lSize;
  756.  
  757.     psMenu->pcText=malloc(psMenu->iSize);
  758.     if (!psMenu->pcText)
  759.     {
  760.         syserr("malloc: %m");
  761.         close(hFile);
  762.         free(psMenu);
  763.         return(0);
  764.     }
  765.     if (read(hFile,psMenu->pcText,psMenu->iSize)==ERR)
  766.     {
  767.         syserr("read %s: %m",pcFile);
  768.         close(hFile);
  769.         free(psMenu->pcText);
  770.         free(psMenu);
  771.         return(0);
  772.     }
  773.     close(hFile);
  774.  
  775.     strcpy(psMenu->acFile,pcFile);
  776.  
  777.     if (Parse(psMenu)==ERR)
  778.     {
  779.         free(psMenu->pcText);
  780.         free(psMenu);
  781.         return(0);
  782.     }
  783.     return(psMenu);
  784. }
  785.  
  786. Display(psMenu,iMode,ppcArgs)
  787. struct sMenu *psMenu;
  788. int iMode;
  789. char **ppcArgs;
  790. {
  791.     char *pcText;
  792.     char *pcOut;
  793.     char *pcEnd;
  794.     char *pcTemp;
  795.     int x,y;
  796.     int iTerm;        /* next terminator is not for ~& */
  797.  
  798.     if (iTest)
  799.         return;
  800.  
  801.     iTerm=0;
  802.  
  803.     pcOut=acBuffer;
  804.     pcEnd=pcOut+BUF_SIZE;
  805.  
  806.     pcText=psMenu->pcText;
  807.  
  808.     /* skip to first ~& for minimal display */
  809.     if (iMode>1)
  810.     {
  811.         while (*pcText)
  812.         {
  813.             if (*pcText=='~' && pcText[1]=='&')
  814.             {
  815.                 pcText+=2;
  816.                 break;
  817.             }
  818.             pcText++;
  819.         }
  820.     }
  821.  
  822.     while (*pcText) switch(*pcText)
  823.     {
  824.     case '~':
  825.         switch (*++pcText)
  826.         {
  827.         case '\n':
  828.         case '&':
  829.             pcText++;
  830.             continue;
  831.  
  832.         case ':':
  833.             pcText++;
  834.             if (iMode>1)
  835.             {
  836.                 if (iTerm)
  837.                 {
  838.                     /* that terminator for ~? or ~! */
  839.                     iTerm=0;
  840.                     continue;
  841.                 }
  842.                 while (*pcText)
  843.                 {
  844.                     if (*pcText=='~' && pcText[1]=='&')
  845.                     {
  846.                         pcText+=2;
  847.                         break;
  848.                     }
  849.                     pcText++;
  850.                 }
  851.             }
  852.             continue;
  853.         
  854.         case '$':
  855.             pcText++;
  856.             x=0;
  857.             while (*pcText && *pcText>='0' && *pcText<='9')
  858.             {
  859.                 x*=10;
  860.                 x+=*pcText++-'0';
  861.             }
  862.             if (!*pcText)
  863.                 continue;
  864.             while (x--)
  865.                 *pcOut++=*pcText;
  866.             pcText++;
  867.             continue;
  868.  
  869.         case '=':
  870.             write(1,acBuffer,pcOut-acBuffer);
  871.             pcOut=acBuffer;
  872.             pcTemp=b;
  873.             while (*pcText && *pcText!='\n')
  874.             {
  875.                 *pcTemp++=*pcText++;
  876.             }
  877.             if (*pcText)
  878.                 pcText++;
  879.             *pcTemp=0;
  880.             Run(b,ppcArgs);
  881.             continue;
  882.  
  883.         case '?':
  884.             pcText++;
  885.             if (!(b[0]=*pcText++)) break;
  886.             if (b[0]=='^')
  887.             {
  888.                 if (iMode)
  889.                     goto skip;
  890.                 iTerm=1;
  891.                 continue;
  892.             }
  893.             if (!(b[1]=*pcText++)) break;
  894.             b[2]=0;
  895.             pcTemp=_TrmString(b);
  896.             if (!pcTemp)
  897.                 goto skip;
  898.  
  899.             iTerm=1;
  900.             continue;
  901.  
  902.         case '!':
  903.             pcText++;
  904.             if (!(b[0]=*pcText++)) break;
  905.             if (b[0]=='^')
  906.             {
  907.                 if (!iMode)
  908.                     goto skip;
  909.                 iTerm=1;
  910.                 continue;
  911.             }
  912.             if (!(b[1]=*pcText++)) break;
  913.             b[2]=0;
  914.             pcTemp=_TrmString(b);
  915.             if (pcTemp)
  916.                 goto skip;
  917.  
  918.             iTerm=1;
  919.             continue;            
  920. skip:
  921.             while (*pcText)
  922.             {
  923.                 if (pcText[0]=='~' && pcText[1]==':')
  924.                 {
  925.                     pcText+=2;
  926.                     break;
  927.                 }
  928.                 pcText++;
  929.             }
  930.             continue;
  931.  
  932.         case '@':
  933.             if (!*++pcText) break;
  934.             pcTemp=acHigh;
  935.             while (*pcTemp)
  936.                 *pcOut++=*pcTemp++;
  937.             *pcOut++=*pcText++;
  938.             pcTemp=acHend;
  939.             while (*pcTemp)
  940.                 *pcOut++=*pcTemp++;
  941.             continue;
  942.  
  943.         case '(':
  944.             pcText++;
  945.             x=atoi(pcText);
  946.             while (*pcText && *pcText!=',' && *pcText!=')')
  947.                 pcText++;
  948.             y=0;
  949.             if (*pcText==',')
  950.                 y=atoi(++pcText);
  951.             while (*pcText && *pcText!=')')
  952.                 pcText++;
  953.             if (*pcText)
  954.                 pcText++;
  955.             pcTemp=_TrmGoXY(x,y);
  956.             if (pcTemp)
  957.                 pcTemp=_TrmConvert(pcTemp);
  958.             if (pcTemp) while (*pcTemp)
  959.                 *pcOut++=*pcTemp++;
  960.             continue;
  961.  
  962.         default:
  963.             if (!(b[0]=*pcText++)) break;
  964.             if (!(b[1]=*pcText++)) break;
  965.             b[2]=0;
  966.             pcTemp=_TrmString(b);
  967.             pcTemp=_TrmConvert(pcTemp);
  968.             if (pcTemp) while (*pcTemp)
  969.                 *pcOut++=*pcTemp++;
  970.             continue;
  971.         }
  972.  
  973.     case '\n':
  974.         *pcOut++=*pcText++;
  975.         *pcOut++='\r';
  976.         break;
  977.  
  978.     default:
  979.         *pcOut++=*pcText++;
  980.  
  981.         /* dump output if getting too big */
  982.         if (pcOut-acBuffer>BUF_SIZE/2)
  983.         {
  984.             write(1,acBuffer,pcOut-acBuffer);
  985.             pcOut=acBuffer;
  986.         }
  987.         break;
  988.     }
  989.  
  990.     if (pcOut-acBuffer)
  991.         write(1,acBuffer,pcOut-acBuffer);
  992. }
  993.  
  994. Menu(pcCmd)
  995. char *pcCmd;
  996. {
  997.     struct sMenu *psMenu;
  998.     struct sSel *psSel;
  999.     char cKey;
  1000.     char **ppcMenu;
  1001.     char acCmd[128];
  1002.     int iTemp;
  1003.  
  1004.     if (strlen(pcCmd)>127)
  1005.         pcCmd[127]=0;
  1006.  
  1007.     strcpy(acCmd,pcCmd);
  1008.     ppcMenu=arglist(acCmd,0);
  1009.  
  1010.     if (iTest)
  1011.     {
  1012.         iTemp=iTest-1;
  1013.         while (iTemp--)
  1014.             write(1,"  ",2);
  1015.         wstringf(1,"%s\n",acCmd);
  1016.     }
  1017.  
  1018.     psMenu=psMenuList;
  1019.     while (psMenu)
  1020.     {
  1021.         if (!stricmp(*ppcMenu,psMenu->acFile))
  1022.             break;
  1023.         psMenu=psMenu->psNext;
  1024.     }
  1025.     if (!psMenu)
  1026.     {
  1027.         psMenu=Load(*ppcMenu);
  1028.         if (!psMenu)
  1029.             return(ERR);
  1030.         psMenu->psNext=psMenuList;
  1031.         psMenuList=psMenu;
  1032.         if (!iTest && _gs_rdy(2)==ERR)
  1033.             Display(psMenu,0,ppcMenu);
  1034.     }
  1035.     else 
  1036.     {
  1037.         if (!iTest && _gs_rdy(2)==ERR)
  1038.             Display(psMenu,2,ppcMenu);
  1039.     }
  1040.  
  1041.     if (psMenu->cInUse)
  1042.     {
  1043.         syserr("recursion to menu %s",*ppcMenu);
  1044.         return(ERR);
  1045.     }
  1046.     psMenu->cInUse=1;
  1047.  
  1048.     if (iTest)
  1049.     {
  1050.         iTemp=0;
  1051.         psSel=psMenu->psSel;
  1052.         while (psSel)
  1053.         {
  1054.             if (*psSel->pcCmd=='-')
  1055.             {
  1056.                 if (psSel->pcCmd[1])
  1057.                 {
  1058.                     iTest++;
  1059.                     Menu(psSel->pcCmd+1);
  1060.                     iTest--;
  1061.                 }
  1062.                 else
  1063.                     iTemp++;
  1064.             }
  1065.             if (*psSel->pcCmd=='#')
  1066.                 iTemp++;
  1067.  
  1068.             psSel=psSel->psNext;
  1069.         }
  1070.         if (!iTemp && iTest>1)
  1071.             wstringf(2,"ERROR: no exit (- or #) from menu!\n");
  1072.  
  1073.         psMenu->cInUse=0;
  1074.         return(0);
  1075.     }
  1076.  
  1077. prompt:
  1078.     if (_gs_rdy(2)==ERR)
  1079.         write(1,psMenu->pcPrompt,strlen(psMenu->pcPrompt));
  1080.  
  1081. getkey:
  1082.     cKey=get_key();
  1083.     if (cKey==ERR)
  1084.         exit(228);
  1085.  
  1086.     if (cKey=='\n')
  1087.     {
  1088.         writeln(1,"\n",1);
  1089.         Display(psMenu,1,ppcMenu);
  1090.         goto prompt;
  1091.     }
  1092.     if (!cKey)
  1093.         goto getkey;
  1094.  
  1095.     psSel=psMenu->psSel;
  1096.     while (psSel)
  1097.     {
  1098.         if (psSel->pcCmd)
  1099.             if (psSel->cKey==toupper(cKey))
  1100.                 break;
  1101.         psSel=psSel->psNext;
  1102.     }
  1103.     if (!psSel)
  1104.     {
  1105.         writeln(1,"\7",1);
  1106.         goto getkey;
  1107.     }
  1108.  
  1109.     wstringf(2,"%s\n",psSel->pcKey);
  1110.  
  1111.     if (!strcmp(psSel->pcCmd,"-"))
  1112.     {
  1113.         psMenu->cInUse=0;
  1114.         return(0);
  1115.     }
  1116.  
  1117.     Run(psSel->pcCmd,ppcMenu);
  1118.  
  1119.     Display(psMenu,2,ppcMenu);
  1120.  
  1121.     goto prompt;
  1122. }
  1123.  
  1124. void
  1125. Startup()
  1126. {
  1127.     int hFile;
  1128.     int iTemp;
  1129.  
  1130.     stringf(b,"%s/startup",MENU_DIR);
  1131.     hFile=open(b,O_RDONLY);
  1132.     if (hFile==ERR)
  1133.         return;
  1134.  
  1135.     while ((iTemp=readln(hFile,b,BUF_SIZE))>0)
  1136.     {
  1137.         *(b+iTemp-1)=0;
  1138.         if (*b!='*' && *b!='#' && *b!=';')
  1139.             Fork(b);
  1140.     }
  1141.     close(hFile);
  1142. }
  1143.  
  1144. main(argc,argv)
  1145. char **argv;
  1146. {
  1147.     int iLoad=1;
  1148.     int iStartup=1;
  1149.  
  1150.     char start;
  1151.     
  1152.     start=tolower(**argv);
  1153.     
  1154.     openerr("smenu",0,LOG_STGNET);
  1155.  
  1156.     signal(SIGINT,SIG_IGN);
  1157.     signal(SIGQUIT,SIG_IGN);
  1158.  
  1159. /*    if (**argv!='-')
  1160.         iLoad=0;
  1161. */
  1162.  
  1163.     dash(argv)
  1164.     {
  1165.     case '#':
  1166.         wstringf(2,"smenu: %s\n",STG_VER);
  1167.         exit(0);
  1168.  
  1169.     case '?':
  1170.         wstringf(2,"smenu {-e} {-t} {menu-file}\n");
  1171.         wstringf(2,"  -e  - do not load environ.dat\n");
  1172.         wstringf(2,"  -s  - do not run startup\n");
  1173.         wstringf(2,"  -t  - test sub-menu arrangment\n");
  1174.         STGVER;
  1175.         exit(0);
  1176.  
  1177.     case 'e':
  1178.         iLoad=0;
  1179.         break;
  1180.  
  1181.     case 's':
  1182.         iStartup=0;
  1183.         break;
  1184.  
  1185.     case 't':
  1186.         iTest=1;
  1187.         break;
  1188.  
  1189.     default:
  1190.         wstringf(2,"invalid option: %s\n",--*argv);
  1191.         exit(1);
  1192.     }
  1193.  
  1194.     /* who are we? */
  1195. /*    pcUser=getlogin(); 
  1196.     if (!pcUser)
  1197.         exit(214);
  1198. */
  1199.     pwd=getpwuid(getuid());
  1200.     if (!pwd)
  1201.         exit(214);
  1202.     pcUser=pwd->pw_name;
  1203.  
  1204.     /* load environment */
  1205.     if (iLoad)
  1206.         load_env();
  1207.  
  1208.     /* run menu/startup file */
  1209.     if (iStartup)
  1210.         Startup();
  1211.  
  1212.     /* load termcap (optional) */
  1213.     if (_Trm(getenv("TERM"))!=ERR)
  1214.     {
  1215.         PickHigh();
  1216.     }
  1217.  
  1218.     /* execute first menu */
  1219.     if (*argv)
  1220.         Menu(*argv);
  1221.     else
  1222.         if (start=='u')
  1223.             Menu(pcUser);
  1224.         else
  1225.             Menu("main");
  1226. }
  1227.