home *** CD-ROM | disk | FTP | other *** search
/ Frozen Fish 1: Amiga / FrozenFish-Apr94.iso / bbs / alib / d5xx / d512 / csh.lha / Csh / Csh515s.lzh / comm3.c < prev    next >
C/C++ Source or Header  |  1991-06-23  |  30KB  |  1,616 lines

  1. /*
  2.  * COMM3.C
  3.  *
  4.  * Version 4.01A by Carlo Borreo & Cesare Dieni 17-Feb-90
  5.  * Version 5.00L by Urban Mueller 17-Feb-91
  6.  *
  7.  */
  8.  
  9. #include "shell.h"
  10.  
  11. /* comm3.c */
  12. static void doassign(char *log, char *phy);
  13. static void assignlist(void);
  14. static int strings_in_file(char *s);
  15. static int htype_a_file(char *s);
  16. static void install_menu(char **mav, int mac);
  17. static int line_filter( char *(*line)(char *) );
  18.  
  19. static int
  20. myfgets( char *buf, FILE *in )
  21. {
  22.     int l;
  23.     char *ret;
  24.     if( ret=fgets(buf,253,in) ) {
  25.         l=strlen(buf);
  26.         if( buf[l-1]!='\n' )
  27.             buf[l]='\n', buf[l+1]=0;
  28.     }
  29.     return ret!=NULL && !dobreak();
  30. }
  31.  
  32. do_tee( void )
  33. {
  34.     char buf[256];
  35.     FILE *out;
  36.  
  37.     prepscroll( ac==1 );
  38.     if( ac>2 ) { ierror( av[2], 500 ); return 20; }
  39.     if( ac==1 ) out=stderr;
  40.     else if( !(out=fopen( av[1], "w" ))) { pError( av[1] ); return 20; }
  41.     while (myfgets(buf,stdin)) {
  42.         fputs(buf, stdout);
  43.         quickscroll();
  44.         fprintf(out, "%s", buf);
  45.     }
  46.     if( ac!=1 ) fclose( out );
  47.     return 0;
  48. }
  49.  
  50. do_head( char *garbage, int com )
  51. {
  52.     int i, n;
  53.     FILE *f;
  54.     char buf[256];
  55.  
  56.     if (ac>2) {
  57.         n=(int)(long)Atol(av[2]);
  58.         if (IoErr()) {
  59.             ierror(av[2],511);
  60.             return 20;
  61.         }
  62.     } else n=10;
  63.  
  64.     f=fopen(av[1], "r");
  65.     if (f==NULL) {
  66.         pError(av[1]);
  67.         return 20;
  68.     }
  69.     if (com) {    /* tail specific part */
  70.         i=0;
  71.         while (fgets(buf, 256, f) && ! dobreak()) i++;
  72.         rewind(f);
  73.         if (n>i) n=i;
  74.         i=i-n;
  75.         while (i-- && fgets(buf, 256, f) && ! dobreak()) ;
  76.     }
  77.     for (i=1; i<=n && fgets(buf, 256, f) && ! dobreak(); i++)
  78.         printf("%s", buf);
  79.     fclose(f);
  80.     return 0;
  81. }
  82.  
  83. static int
  84. exword( char **src, char *buf )
  85. {
  86.     *buf=0;
  87.     if( **src==0 ) return 0;
  88.     while( **src && **src!=0xA0 )
  89.         *buf++=*(*src)++;
  90.     *buf=0;
  91.     if( **src ) (*src)++;
  92.     return 1;
  93. }
  94.  
  95. static char helpfound=0;
  96.  
  97. void
  98. man( FILE *f, char *s)
  99. {
  100.     char buf[140], entry[100];
  101.     int len=sprintf(entry, "    %s", s);
  102.  
  103.     prepscroll(0);
  104.     rewind(f);
  105.     do                                  /* look for required argument */
  106.         if (fgets(buf, 140, f) == NULL)
  107.             return;
  108.     while ( Strncmp(entry, buf, len) );
  109.     helpfound=1;
  110.     do {                                /* display help */
  111.         quickscroll();
  112.         printf("%s", buf);
  113.         if (fgets(buf, 140, f) == NULL) return;
  114.     } while ( ( !isalphanum(*buf) ) && strncmp(buf, "    ", 4) && !dobreak() );
  115. }
  116.  
  117.  
  118. do_man( void )
  119. {
  120.     FILE *f;
  121.     int i;
  122.     char buf[200], name[60], *src, *var, docfound=0;
  123.  
  124.     buf[0]=0;
  125.     if( var=get_var(LEVEL_SET,"_man" ) )
  126.         strcpy(buf,var);
  127.  
  128.     if (ac==1) ac=2, av[1]="MAN";
  129.     for (i=1; i<ac; i++) {
  130.         src=buf, helpfound=0;
  131.         while( exword( &src, name) )
  132.             if( f=fopen(name, "r") ) {
  133.                 docfound=1;
  134.                 man(f, av[i]);
  135.                 fclose(f);
  136.                 if( helpfound )
  137.                     break;
  138.             }
  139.         if( !docfound )
  140.             fprintf(stderr,"%s not found\n",buf);
  141.         else if( !helpfound )
  142.             fprintf(stderr, "Help not found for %s\n", av[i]);
  143.     }
  144.     return 0;
  145. }
  146.  
  147. do_assign( void )
  148. {
  149.     int i;
  150.  
  151.     if     (  ac==1  ) assignlist();
  152.     else if(  ac==2  ) doassign(av[1], NULL);
  153.     else if( !(ac&1) ) ierror(NULL, 500);
  154.     else
  155.         for( i=1; i<ac; i+=2 )
  156.             doassign( av[i],av[i+1] );
  157.     return 0;
  158. }
  159.  
  160. static char *assign_errors[4]={
  161.     "",
  162.     "Name %s is not valid\n",
  163.     "Weird error\n",
  164.     "Can't cancel %s:\n"
  165.     };
  166.  
  167.  
  168. static void
  169. doassign(char *log, char *phy)
  170. {
  171.     int last=strlen(log) - 1;
  172.  
  173.     if (log[last] != ':') fprintf(stderr, "Bad name %s\n", log);
  174.     else {
  175.         log[last] = 0;
  176.         if( options && phy && o_kick20 ) {
  177.             BPTR lock;
  178.             int succ=0;
  179.             if     ( options&1 ) succ=AssignLate( (UBYTE*)log,(UBYTE*)phy );
  180.             else if( options&2 ) succ=AssignPath( (UBYTE*)log,(UBYTE*)phy );
  181.             else if( options&4 )
  182.                 if( lock=Lock(phy,ACCESS_READ) )
  183.                     if( !(succ=AssignAdd((UBYTE *)log,lock)))
  184.                         UnLock(lock);
  185.             if( !succ )
  186.                 pError( log );
  187.         } else if( !(options&4) ) {
  188.             int err=Assign(log, phy);
  189.             fprintf(stderr,assign_errors[err],err==1?phy:log);
  190.         }
  191.     }
  192. }
  193.  
  194. extern struct RootNode2x *RootNode;
  195. #define ENTRIES 128
  196.  
  197. static void
  198. assignlist()
  199. {
  200.     char *ptr, *log, **arr;
  201.     int ctr, i;
  202.  
  203.     if(!(arr=expand_devs()))
  204.         return;
  205.  
  206.     printf("Devices:\n");
  207.     for (i=ctr=0; arr[i] && *arr[i]==1; i++) {
  208.         printf("%-8s",arr[i]+1);
  209.         if (ctr++ == 5) { ctr=0; printf("\n"); }
  210.     }
  211.  
  212.     printf("\n\nVolumes:\n");
  213.     for( ; arr[i] && *arr[i]==2; i++ )
  214.         printf( "%-16s [Mounted]\n",arr[i]+1);
  215.  
  216.     printf("\nDirectories:\n");
  217.     for( ; arr[i] && !dobreak(); i++ ) {
  218.         log=arr[i]+1; ptr=log+strlen(log)+1;
  219.         switch( *(log-1)) {
  220.         case 3:
  221.             printf("%-20s%s\n", log, ptr);
  222.             for(;;) {
  223.                 ptr+=strlen(ptr)+1;
  224.                 if( !*ptr ) break;
  225.                     printf("%-19s+%s\n", "", ptr);
  226.             }
  227.             break;
  228.         case 4: printf("%-20s<%s>\n", log, ptr); break;
  229.         case 5: printf("%-20s[%s]\n", log, ptr); break;
  230.         }
  231.     }
  232.  
  233.     free_expand( arr );
  234. }
  235.  
  236. char **
  237. expand_devs(void)
  238. {
  239.     static char Type[]={1,3,2,4,5};
  240.     struct DosInfo *info=(void*)((long)RootNode->rn_Info*4);
  241.     struct DosList2x *list=(void*)((long) info->di_DevInfo*4);
  242.     struct AssignList2x *path;
  243.     char buf[256], **arr, *ptr;
  244.     int n;
  245.  
  246.     if( !(arr=malloc(ENTRIES*sizeof(char *))))
  247.         return NULL;
  248.  
  249.     Forbid();
  250.     for( n=0; list && n<ENTRIES; list=(void*)((long)list->dol_Next*4)) {
  251.         if( list->dol_Type<0 || list->dol_Type>DLST_NONBINDING )
  252.             continue;
  253.         ptr=buf;
  254.         *ptr++=Type[list->dol_Type];
  255.         ptr+=BtoCStr(ptr,list->dol_Name,200);
  256.         *ptr++=':'; *ptr++=0;
  257.         switch( list->dol_Type) {
  258.         case DLST_DIRECTORY : 
  259.             if(list->dol_Lock)
  260.                 PathName(list->dol_Lock, ptr, 200);
  261.             else 
  262.                 strcpy(ptr,"Nonexisting lock");
  263.             ptr+=strlen(ptr)+1;
  264.             if( o_kick20 ) {
  265.                 path=(void*)list->dol_misc.dol_assign.dol_List;
  266.                 for( ; o_kick20 && path; path=(void*)path->al_Next ) {
  267.                     if(list->dol_Lock)
  268.                         PathName(path->al_Lock, ptr, 200);
  269.                     else 
  270.                         strcpy(ptr,"Nonexisting lock");
  271.                     ptr+=strlen(ptr)+1;
  272.                 }
  273.             }
  274.             *ptr++=0;
  275.             break;
  276.         case DLST_LATE      : 
  277.         case DLST_NONBINDING:
  278.             ptr+= sprintf(ptr,"%s",list->dol_misc.dol_assign.dol_AssignName);
  279.             *ptr++=0;
  280.             break;
  281.         default:
  282.             *ptr++=0;
  283.         }
  284.         arr[n]=salloc(ptr+1-buf);
  285.         memcpy(arr[n++],buf,ptr+1-buf);
  286.     }
  287.     arr[n]=NULL;
  288.     Permit();
  289.  
  290.     QuickSort( arr, n );
  291.  
  292.     return arr;
  293. }
  294.  
  295.  
  296. do_join( void )
  297. {
  298.     BPTR sou, dest;
  299.     char *buffer;
  300.     int i;
  301.     long n;
  302.     char *namedest=av[--ac];
  303.  
  304.     if (options==0 && exists(namedest)) { ierror(namedest,203); return 20; }
  305.     if ( (buffer=malloc(8192)) == NULL ) { ierror(NULL,103); return 20; }
  306.     if ( (dest=Open(namedest, MODE_NEWFILE)) == NULL )
  307.         { pError(namedest); goto fail1; }
  308.     for (i=1; i<ac; i++) {
  309.         if ( (sou=Open(av[i], MODE_OLDFILE)) == NULL ) pError(av[i]);
  310.         else
  311.             while( (n=Read(sou, buffer, 8192L)) > 0 )
  312.                 if (Write(dest, buffer, n) != n)
  313.                     { pError(namedest); Close(sou); goto fail2; }
  314.         Close(sou);
  315.     }
  316. fail2:
  317.     Close(dest);
  318. fail1:
  319.     free(buffer);
  320.     return 0;
  321. }
  322.  
  323. #define BUFDIM 512L
  324. #define MAXSTR 256
  325.  
  326. int minstr;
  327.  
  328. static int
  329. strings_in_file(char *s)
  330. {
  331.     char c;
  332.     char readbuf[BUFDIM+1], strbuf[MAXSTR+1];
  333.     int i, strctr=0;
  334.     BPTR fh;
  335.     int out, n, inter=IsInteractive(Output());;
  336.  
  337.     prepscroll(0);
  338.     if ( fh=Open(s, MODE_OLDFILE) ) {
  339.         fprintf(stderr, "Strings in %s (len>=%d):\n",s,minstr);
  340.         while ( (n=(int)Read(fh, readbuf, BUFDIM)) > 0 && !CHECKBREAK() )
  341.             for (i=0; i<n; i++) {
  342.                 c=readbuf[i];
  343.                 if (c<0x20 || c>0x7f) {
  344.                     out=(strctr>=minstr);
  345.                     if (!out) strctr=0;
  346.                 } else {
  347.                     strbuf[strctr++]=c;
  348.                     out=(strctr>=BUFDIM);
  349.                 }
  350.                 if (out) {
  351.                     strbuf[strctr]='\0';
  352.                     puts(strbuf);
  353.                     if( inter ) fflush(stdout);
  354.                     quickscroll();
  355.                     strctr=0;
  356.                 }
  357.             }
  358.         Close(fh);
  359.     } else
  360.         pError(s);
  361.     return 0;
  362. }
  363.  
  364. do_strings( void )
  365. {
  366.     minstr=myatoi(av[--ac],1,255);
  367.     all_args( strings_in_file, 0);
  368.     return 0;
  369. }
  370.  
  371. BPTR myfile[MAXMYFILES];
  372.  
  373. do_open( void )
  374. {
  375.     long mode;
  376.     int n;
  377.  
  378.     switch (toupper(av[2][0])) {
  379.         case 'R': mode=MODE_OLDFILE; break;
  380.         case 'W': mode=MODE_NEWFILE; break;
  381.         default : ierror(NULL,500); return 1;
  382.     }
  383.     n=myatoi(av[3],0,MAXMYFILES-1); if (atoierr) return 20;
  384.     if (myfile[n]) myclose(n);
  385.     myfile[n]=Open(av[1],mode);
  386.     return myfile[n]==NULL;
  387. }
  388.  
  389. do_close( void )
  390. {
  391.     int i, n;
  392.  
  393.     if (ac==1)
  394.         for (i=1; i<MAXMYFILES; i++)
  395.             myclose(i);
  396.     for (i=1; i<ac; i++) {
  397.         n=myatoi(av[i],0,MAXMYFILES-1); if (atoierr) return 20;
  398.         myclose(n);
  399.     }
  400.     return 0;
  401. }
  402.  
  403. void
  404. myclose(int n)
  405. {
  406.     if (myfile[n]) { Close(myfile[n]); myfile[n]=NULL; }
  407. }
  408.  
  409. do_fileslist( void )
  410. {
  411.     int i, flag=0;
  412.  
  413.     printf("Open files:");
  414.     for (i=0; i<MAXMYFILES; i++)
  415.         if (myfile[i]) { printf(" %d",i); flag=1; }
  416.     if (!flag) printf(" None!");
  417.     printf("\n");
  418.     return 0;
  419. }
  420.  
  421. BPTR
  422. extOpen( char *name, long mode )
  423. {
  424.     if (name[0]=='.' && name[1]>='0' && name[1]<='9')
  425.         return myfile[atoi(name+1)];
  426.     return Open(name,mode);
  427. }
  428.  
  429.  
  430. void
  431. extClose(BPTR fh)
  432. {
  433.     int i;
  434.  
  435.     for (i=0; i<MAXMYFILES; i++)
  436.         if (myfile[i]==fh) return;
  437.     Close(fh);
  438. }
  439.  
  440. do_basename( void )
  441. {
  442.     char *res;
  443.     int  i;
  444.  
  445.     for( i=2; i<ac; i++ )
  446.         av[i]=BaseName(av[i]);
  447.     set_var(LEVEL_SET, av[1], res=compile_av(av,2,ac,0xA0,0));
  448.     free(res);
  449.     return 0;
  450. }
  451.  
  452. do_tackon( void )
  453. {
  454.     char buf[256];
  455.  
  456.     strcpy(buf, av[2]);
  457.     TackOn(buf, av[3]);
  458.     set_var(LEVEL_SET, av[1], buf);
  459.     return 0;
  460. }
  461.  
  462. extern char shellres[];
  463.  
  464. do_resident( void )
  465. {
  466.     int i=1;
  467.     struct ResidentProgramNode *p;
  468.     char buf[256];
  469.  
  470.     if (options==0 && ac>1) options=1;
  471.     switch (options) {
  472.     case 0:
  473.         ObtainSemaphore (& (ArpBase->ResPrgProtection) );
  474.         if (p=ArpBase->ResidentPrgList) {
  475.             printf("Name             Users Access\n");
  476.             for (; p; p=p->rpn_Next)
  477.                 printf("%-17s%5d%6d\n",
  478.                     p->rpn_Name, p->rpn_Usage, p->rpn_AccessCnt);
  479.         } else
  480.             printf("No resident program(s)\n");
  481.         ReleaseSemaphore(& (ArpBase->ResPrgProtection) );
  482.         break;
  483.     case 1:
  484.         for (; i<ac; i++)
  485.             if (loadres(av[i]))
  486.                 printf("OK! %s is now resident\n", BaseName(av[i]));
  487.             else
  488.                 pError(av[i]);
  489.         break;
  490.     case 2:
  491.         for (; i<ac; i++)
  492.             if (RemResidentPrg(av[i])) ierror(av[i],202);
  493.             else printf("Removed %s\n",av[i]);
  494.         break;
  495.     case 4:
  496.         for (; i<ac; i++) {
  497.             if( !o_resident ) {
  498.                 Setenv(shellres,"1");
  499.                 o_resident=1;
  500.             }
  501.             sprintf(buf,"res_%s",BaseName(av[i]));
  502.             Setenv(buf,av[i]);
  503.         }
  504.         break;
  505.     default:
  506.         ierror(NULL,500);
  507.         break;
  508.     }
  509.     return 0;
  510. }
  511.  
  512. int
  513. loadres(char *s)
  514. {
  515.     BPTR seg;
  516.  
  517.     if (seg=(BPTR)LoadPrg(s)) AddResidentPrg(seg,BaseName(s));
  518.     return (seg != NULL);
  519. }
  520.  
  521. static struct ProcessControlBlock pcb={
  522.     4000,        /* pcb_StackSize    */
  523.     0,            /* pcb_Pri            */
  524.     };
  525. /* remaining fields are NULL */
  526.  
  527. do_truerun(char *avline, int backflag)
  528. {
  529.     char name[100], *args, buf[10];
  530.     int cli;
  531.  
  532.     if (backflag) {
  533.         pcb.pcb_Control=NULL;
  534.         pcb.pcb_Input=pcb.pcb_Output=Open("NIL:",MODE_OLDFILE);
  535.     } else {
  536.         pcb.pcb_Control=NULL;
  537.         pcb.pcb_Input=pcb.pcb_Output =NULL;
  538.     }
  539.     args=next_word(next_word(avline));
  540.  
  541.     if((cli=ASyncRun(av[1],args,&pcb))<0)
  542.         if (dofind(av[1], "", name,v_path))
  543.             cli=ASyncRun(name,args,&pcb);
  544.  
  545.     sprintf(buf,"%d",cli);
  546.     set_var(LEVEL_SET,"_newproc",buf);
  547.  
  548.     if( cli<0 ) {
  549.         ierror(av[1],205);
  550.         return 20;
  551.     }
  552.     return 0;
  553. }
  554.  
  555. int
  556. exists( char *name )
  557. {
  558.     BPTR lock;
  559.  
  560.     if ( strlen(name)<=MAXFILENAME && (lock=Lock(name,ACCESS_READ))) {
  561.         UnLock(lock);
  562.         return 1;
  563.     }
  564.     return 0;
  565. }
  566.  
  567. do_aset( void )
  568. {
  569.     Setenv(av[1],av[2]);
  570.     return 0;
  571. }
  572.  
  573. #define HTYPELINE 16L
  574.  
  575. static int
  576. htype_a_file( char *s )
  577. {
  578.     BPTR fh;
  579.     long n, filesize=0;
  580.     UBYTE buf[HTYPELINE+1];
  581.     char out[80], *put;
  582.     int i, inter=IsInteractive(Output());
  583.  
  584.     if ( (fh=Open(s,MODE_OLDFILE))==NULL ) { pError(s); return 20; }
  585.     prepscroll(0);
  586.     while ( (n=Read(fh,(char *)buf,HTYPELINE))>0 && !dobreak()) {
  587.         put=out;
  588.         put+=sprintf(put,"%06lx: ",filesize);
  589.         filesize+=n;
  590.         for (i=0; i<n; i++) {
  591.             put+=sprintf( put,(i&3) ? "%02x" : " %02x",buf[i]);
  592.             if ((buf[i]&127)<0x20) buf[i]='.';
  593.         }
  594.         for ( ; i<HTYPELINE; i++) {
  595.             put+=sprintf( put, (i&3) ? "  " : "   ");
  596.             buf[i]=' ';
  597.         }
  598.         buf[i]=0;
  599.         sprintf(put,"    %s",buf);
  600.         puts(out);
  601.         if( inter ) fflush(stdout);
  602.         quickscroll();
  603.     }
  604.     Close(fh);
  605.     return 0;
  606. }
  607.  
  608. do_htype( void )
  609. {
  610.     all_args( htype_a_file, 0);
  611.     return 0;
  612. }
  613.  
  614. do_stack( void )
  615. {
  616.     long n;
  617.  
  618.     if (ac>1) {
  619.         n=Atol(av[1]);
  620.         if (!IoErr()) Mycli->cli_DefaultStack=(long)(n >> 2L);
  621.     }
  622.     else printf("current stack size is %ld bytes\n",
  623.                 (long)Mycli->cli_DefaultStack << 2L);
  624.     return 0;
  625. }
  626.  
  627. do_fault( void )
  628. {
  629.     struct PERROR *p;
  630.     int i, n;
  631.  
  632.     for (i=1; i<ac; i++) {
  633.         n=myatoi(av[i],0,32767);
  634.         if (!atoierr) {
  635.             for (p=Perror; p->errnum && p->errnum!=n; p++);
  636.             if (p->errnum)
  637.                 printf("Fault %d: %s\n",n,p->errstr);
  638.             else
  639.                 printf("Fault %d not recognized\n",n);
  640.         }
  641.     }
  642.     return 0;
  643. }
  644.  
  645. struct rpncommand {
  646.     char *str;
  647.     int parsin, parsout;
  648.     };
  649.  
  650. static struct rpncommand rpn[]={
  651.     "+",    2,    1,
  652.     "-",    2,    1,
  653.     "*",    2,    1,
  654.     "/",    2,    1,
  655.     "%",    2,    1,
  656.     "&",    2,    1,
  657.     "|",    2,    1,
  658.     "~",    1,    1,
  659.     ">",    2,    1,
  660.     "<",    2,    1,
  661.     "==",    2,    1,
  662.     "!",    1,    1,
  663.     "MAX",    2,    1,
  664.     "MIN",    2,    1,
  665.     "DUP",    1,    2,
  666.     "DROP",    1,    0,
  667.     "SWAP",    2,    2,
  668.     "HELP",    0,    0,
  669.     NULL,    0,    1,    /* this looks for a number */
  670. };
  671.  
  672. static long stack[50];
  673. static int sp;
  674.  
  675.  
  676. eval_rpn( char **av, int ac, int flag )
  677. {
  678.     char *zero="Division by zero\n";
  679.     struct rpncommand *temp;
  680.     long n0, n1, t;
  681.     int j, i=0, oldsp=sp;
  682.  
  683.     for (; i<ac; i++) {
  684.         for (j=0; rpn[j].str && Strcmp(rpn[j].str,av[i]); j++) ;
  685.         n0=stack[sp-1];
  686.         n1=stack[sp-2];
  687.         sp -= (rpn[j].parsin);
  688.         if (sp<0) { fprintf(stderr, "RPN: Empty stack\n"); goto error; }
  689.         switch (j) {
  690.           case 0:    n0 += n1;            break;
  691.           case 1:    n0 = n1-n0;            break;
  692.           case 2:    n0 *= n1;            break;
  693.           case 3:    if(n0) n0=n1/n0; else fprintf(stderr,zero); break;
  694.           case 4:    if(n0) n0=n1%n0; else fprintf(stderr,zero); break;
  695.           case 5:    n0 &= n1;            break;
  696.           case 6:    n0 |= n1;            break;
  697.           case 7:    n0 =  ~n0    ;        break;
  698.           case 8:    n0 = (n1 > n0);        break;
  699.           case 9:    n0 = (n1 < n0);        break;
  700.           case 10:    n0 = (n0 == n1);    break;
  701.           case 11:    n0 = !n0;            break;
  702.           case 12:    n0=n1>n0 ? n1 : n0;    break;
  703.           case 13:    n0=n1<n0 ? n1 : n0;    break;
  704.           case 14:    n1=n0;                break;
  705.           case 15:    t=n0; n0=n1; n1=t;    break;
  706.           case 16:                        break;
  707.           case 17:    printf("In Commands Out\n");
  708.             for (temp=rpn; temp->str; temp++)
  709.                 printf(" %d %-10s%d\n",
  710.                 temp->parsin,temp->str,temp->parsout);
  711.             break;
  712.           default:    n0=Atol(av[i]);
  713.                 if (IoErr()) {
  714.                     fprintf(stderr, "Bad RPN cmd: %s\n",av[i]);
  715.                     goto error;
  716.                 }
  717.                 break;
  718.           }
  719.         stack[sp]=n0;
  720.         stack[sp+1]=n1;
  721.         sp += rpn[j].parsout;
  722.     }
  723.     if( flag && sp-1)
  724.         fprintf( 
  725.           stderr,
  726.           "RPN: Stack not empty\n"
  727.         );
  728.  
  729.     t=sp; sp=oldsp;
  730.     if( flag )
  731.         return stack[t-1]; /* return top value */
  732.     else 
  733.         return t-sp;
  734.  
  735. error:
  736.     sp=oldsp;
  737.     return 0;
  738. }
  739.  
  740.  
  741. do_rpn(char *garbage,int ifflag) /* ifflag!=0 if called from if */
  742. {
  743.     int i=1;
  744.     long t;
  745.  
  746.     t=eval_rpn( av+i, ac-i, ifflag );
  747.     if (ifflag) return t;              /* called from if: return top value */
  748.     for (i=sp+t-1;i>=sp;i--) printf("%ld\n", stack[i]);/* else print stack */
  749.  
  750.     return t ? 0 : 20;
  751. }
  752.  
  753. do_path( void )
  754. {
  755.     ULONG ll, ll1, *lp, new, *newp;
  756.     char buf[256];
  757.     BPTR lock;
  758.     int i;
  759.  
  760.     if( options&1 ) {
  761.         Forbid();
  762.         for( ll= Mycli->cli_CommandDir; ll; ll= ll1 ) {
  763.             lp=(ULONG *)(4*ll);
  764.             ll1=*lp;
  765.             DosFreeMem( lp );
  766.         }
  767.         Mycli->cli_CommandDir=0;
  768.         Permit();
  769.     } else if( ac==1 ) {     /* Should Forbid() here, but puts() Permit()s */
  770.         puts("Current dir"); /* and failure here is not really harmful...  */
  771.         for( ll= Mycli->cli_CommandDir; ll; ll= *lp ) {
  772.             lp=(ULONG *)(4*ll);
  773.             PathName(lp[1], buf, 256L);
  774.             puts(buf);
  775.         }
  776.         puts("C:");
  777.         return 0;
  778.     }
  779.     for( i=1; i<ac; i++ ) {
  780.         if( !(lock=Lock(av[i],ACCESS_READ)) ) {
  781.             ierror(av[i],205);
  782.             continue;
  783.         }
  784.         if( !isdir(av[i])) {
  785.             ierror(av[i],212);
  786.             UnLock(lock);
  787.             continue;
  788.         }
  789.         Forbid();
  790.         for( ll= Mycli->cli_CommandDir, lp=NULL; ll; ll= lp[0] ) {
  791.             lp=(ULONG *)(4*ll);
  792.             if( CompareLock(lp[1],lock)==LCK_EQUAL) {
  793.                 UnLock(lock), lock=0;
  794.                 break;
  795.             }
  796.         }
  797.         if( lock && (newp=DosAllocMem( 8 ))) {
  798.             newp[1]=lock;
  799.             new =(ULONG)newp/4;
  800.             if( lp )
  801.                 *lp=new;
  802.             else
  803.                 Mycli->cli_CommandDir=new;
  804.         }
  805.         Permit();
  806.     }
  807.     return 0;
  808. }
  809.  
  810. do_pri( void )
  811. {
  812.     int t, pri;
  813.     struct Process *proc;
  814.  
  815.     t=(int)(long)FindCLI(0L);
  816.     t=myatoi(av[1],0,t); if (atoierr) return 20;
  817.     pri=myatoi(av[2],-128,127); if (atoierr) return 20;
  818.     Forbid();
  819.     proc=(t==0 ? Myprocess : FindCLI((long)t));
  820.     if (proc==NULL) fprintf(stderr, "process not found\n");
  821.     else SetTaskPri((struct Task *)proc, (long)pri);
  822.     Permit();
  823.     return 0;
  824. }
  825.  
  826. do_strleft( void )
  827. {
  828.     int n;
  829.  
  830.     n=posatoi(av[3]); if (atoierr) return 20;
  831.     set_var_n(LEVEL_SET, av[1], av[2], n);
  832.     return 0;
  833. }
  834.  
  835. do_strright( void )
  836. {
  837.     int n, len=strlen(av[2]);
  838.  
  839.     n=posatoi(av[3]); if (atoierr) return 20;
  840.     if( n>len ) n=len;
  841.     set_var(LEVEL_SET, av[1], av[2]+len-n );
  842.     return 0;
  843. }
  844.  
  845. do_strmid( void )
  846. {
  847.     int n1, n2=999999, len=strlen(av[2]);
  848.  
  849.     n1=myatoi(av[3],1,999999)-1; if (atoierr) return 20;
  850.     if (n1>len) n1=len;
  851.     if (ac>4) {
  852.         n2=posatoi(av[4]); if (atoierr) return 20;
  853.     }
  854.     set_var_n(LEVEL_SET, av[1], av[2]+n1, n2);
  855.     return 0;
  856. }
  857.  
  858. do_strlen( void )
  859. {
  860.     char buf[16];
  861.  
  862.     sprintf(buf,"%d",strlen(av[2]));
  863.     set_var(LEVEL_SET, av[1], buf);
  864.     return 0;
  865. }
  866.  
  867. int atoierr;
  868.  
  869. myatoi(char *s,int mmin,int mmax)
  870. {
  871.     int n;
  872.  
  873.     n=Atol(s);
  874.     if (atoierr=IoErr())
  875.         ierror(s,511);
  876.     else if (n<mmin || n>mmax) {
  877.         atoierr=1; n=mmin;
  878.         fprintf( stderr, "%s(%d) not in (%d,%d)\n",s,n,mmin,mmax );
  879.     }
  880.     return n;
  881. }
  882.  
  883. unlatoi(char *s)
  884. {
  885.     int n=Atol(s);
  886.     if (atoierr=IoErr())
  887.         ierror(s,511), n=0;
  888.     return n;
  889. }
  890.  
  891. posatoi(char *s)
  892. {
  893.     int n=Atol(s);
  894.     if (atoierr=IoErr())
  895.         ierror(s,511);
  896.     else if (n<0 )
  897.         atoierr=1, n=0, fprintf( stderr, "%s must be positive\n",s );
  898.     return n;
  899. }
  900.  
  901.  
  902. do_fltlower( void )
  903. {
  904.     return line_filter( strlwr );
  905. }
  906.  
  907. do_fltupper( void )
  908. {
  909.     return line_filter( strupr );
  910. }
  911.  
  912. #if 0
  913. char *
  914. stripcr( char *get )
  915. {
  916.     char *old=get, *put;
  917.  
  918.     for( put=get; *get; get++ )
  919.         if( *get!=13 )
  920.             *put++=*get;
  921.     *put++=0;
  922.     return old;
  923. }
  924.  
  925. do_fltstripcr( void )
  926. {
  927.     return line_filter( stripcr );
  928. }
  929. #endif
  930.  
  931. int
  932. line_filter( char *(*func)( char * ) )
  933. {
  934.     char buf[256];
  935.  
  936.     while (!CHECKBREAK() && gets(buf))
  937.         puts((*func)(buf));
  938.     return 0;
  939. }
  940.  
  941. int
  942. do_linecnt( void )
  943. {
  944.     int count=0;
  945.     char buf[256];
  946.  
  947.     while (!CHECKBREAK() && gets(buf)) ++count;
  948.     printf("%d lines\n",count);
  949.     return 0;
  950. }
  951.  
  952. int
  953. do_uniq( void )
  954. {
  955.     int firstline=1;
  956.     char buf[256], oldbuf[256];
  957.  
  958.     while (!CHECKBREAK() && gets(buf)) {
  959.         if ( firstline || strcmp(buf, oldbuf)) {
  960.             strcpy(oldbuf, buf);
  961.             puts(buf);
  962.         }
  963.         firstline=0;
  964.     }
  965.     return 0;
  966. }
  967.  
  968.  
  969. #define RXFB_RESULT  17
  970.  
  971. static struct rexxmsg {
  972.     struct Message cm_Node;
  973.     LONG   RFU1;
  974.     LONG   RFU2;
  975.     LONG   rm_Action;
  976.     LONG   rm_Result1;
  977.     LONG   rm_Result2;
  978.     char   *cm_Args[16];
  979.     LONG   RFU7;
  980.     LONG   RFU8;
  981.     LONG   RFU9;
  982.     LONG   RFU10;
  983.     LONG   RFU11;
  984.     LONG   RFU12;
  985. } mymsg;
  986.  
  987. do_rxsend( char *avline )
  988. {
  989.     int i;
  990.     long result;
  991.     struct MsgPort *port, *reply;
  992.     long len;
  993.     char buf[20], *resptr;
  994.  
  995.     if (!(port = FindPort(av[1])))
  996.         { fprintf(stderr, "No port %s!\n", av[1]); return 20; }
  997.     mymsg.cm_Node.mn_Node.ln_Type = NT_MESSAGE;
  998.     mymsg.cm_Node.mn_Length = sizeof(struct rexxmsg);
  999.     mymsg.rm_Action = (options&1 ? 1L << RXFB_RESULT : 0);
  1000.     if (!(reply = CreatePort(NULL, 0L))) {
  1001.         fprintf(stderr, "No reply port\n");
  1002.         return 20;
  1003.     }
  1004.     mymsg.cm_Node.mn_ReplyPort = reply;
  1005.  
  1006.     if( options&2 )
  1007.         av[2]=compile_av( av,2,ac,' ',0), ac=3;
  1008.     for ( i=2; i<ac; i++) {
  1009.         mymsg.cm_Args[0] = av[i];
  1010.         mymsg.rm_Result2 = 0;        /* clear out the last result. */
  1011.         PutMsg(port, &mymsg.cm_Node);
  1012.  
  1013.         Wait( 1<<reply->mp_SigBit | SIGBREAKF_CTRL_C );
  1014.  
  1015.         if( CHECKBREAK() )
  1016.             break;
  1017.  
  1018.         if (options&1) {
  1019.             if( (result=mymsg.rm_Result2)<1000000 ) { /* like AREXX */
  1020.                 sprintf(buf,"%d",result);              
  1021.                 set_var(LEVEL_SET,v_result,buf);
  1022.             } else {
  1023.                 resptr=(char *)(result-4);
  1024.                 len=*(long *)resptr;
  1025.                 memmove(resptr,resptr+4,len);  /* Null terminate */
  1026.                 resptr[len]=0;      
  1027.                 set_var(LEVEL_SET,v_result,resptr);
  1028.                 FreeMem(resptr, len+4 );
  1029.             }
  1030.         } else 
  1031.             unset_var( LEVEL_SET, v_result );
  1032.     }
  1033.     if( options&2 )
  1034.         free( av[2] );
  1035.  
  1036.     if (reply) DeletePort(reply);
  1037.     return 0;
  1038. }
  1039.  
  1040. static char *rxreturn;
  1041.  
  1042. do_rxrec( void )
  1043. {
  1044.     struct MsgPort *port;
  1045.     struct rexxmsg *msg;
  1046.     char *portname, *str;
  1047.  
  1048.     if (ac > 1)
  1049.         portname=av[1];
  1050.     else
  1051.         portname="rexx_csh";
  1052.  
  1053.     port=CreatePort(portname, 0L);
  1054.     if (port==NULL) {
  1055.         fprintf(stderr, "Can't have MsgPort %s\n", portname);
  1056.         return 20;
  1057.     }
  1058.     for (;;) {
  1059.         WaitPort(port);
  1060.         while (msg=(struct rexxmsg *)GetMsg(port)) {
  1061.             if ( ! Strcmp(msg->cm_Args[0], "bye")) {
  1062.                 ReplyMsg((struct Message *)msg);
  1063.                 DeletePort(port);
  1064.                 return 0;
  1065.             }
  1066.             rxreturn=NULL;
  1067.             exec_command(msg->cm_Args[0]);
  1068.             if (msg->rm_Action & (1L << RXFB_RESULT)) {
  1069.                 if( rxreturn ) {
  1070.                     str= SAllocMem( strlen( rxreturn )+5 , 0 );
  1071.                     *(long *)str=strlen( rxreturn );
  1072.                     strcpy( str+4, rxreturn );
  1073.                     msg->rm_Result2=(long)str;
  1074.                 } else {
  1075.                     str = get_var(LEVEL_SET, v_lasterr);
  1076.                     msg->rm_Result2=(str) ? atoi(str) : 20;
  1077.                 }
  1078.             }
  1079.             ReplyMsg((struct Message *)msg);
  1080.         }
  1081.     }
  1082. }
  1083.  
  1084. int
  1085. do_waitport( void )
  1086. {
  1087.     int count=4*10;
  1088.     struct MsgPort *port=NULL;
  1089.  
  1090.     if( ac==3 ) 
  1091.         { count=2*myatoi(av[2],0, 32000); if( atoierr ) return 20; }
  1092.  
  1093.     while( --count>=0 && !(port=FindPort(av[1])) && !dobreak() )
  1094.         Delay(12);
  1095.  
  1096.     return port ? 0 : 20;
  1097. }
  1098.  
  1099. int
  1100. do_rxreturn( void )
  1101. {
  1102.     rxreturn=compile_av( av, 1, ac, ' ', 1 );
  1103.     return 0;
  1104. }
  1105.  
  1106. do_ascii( void )
  1107. {
  1108.     int x=1, y, c, c1, t;
  1109.     char *fmt1=" %3d %c%c |", *fmt2=" %4d";
  1110.  
  1111.     if( options&1 ) fmt1=" %3o %c%c |", fmt2="%4o";
  1112.     if( options&2 ) fmt1=" %3x %c%c |", fmt2="%4x";
  1113.     if( ac==x )
  1114.         for( y=0; y<32 && !dobreak(); y++ ) {
  1115.             printf("|");
  1116.             for( x=0; x<8; x++ ) {
  1117.                 c1=c=y+32*x; t=' ';
  1118.                 if( c<32 ) t='^', c1+=64;
  1119.                 printf(fmt1,c, t, c1<128 || c1>=160?c1:'.');
  1120.             }
  1121.             printf("\n");
  1122.         }
  1123.     else 
  1124.         for( ; x<ac && !dobreak(); x++ ) {
  1125.             for( y=0; y<strlen(av[x]); y++ )
  1126.                 printf(fmt2,av[x][y]);
  1127.             printf("\n");
  1128.         }
  1129.     return 0;
  1130. }
  1131.  
  1132. void
  1133. appendslash( char *path )
  1134. {
  1135.     int c;
  1136.  
  1137.     if( (c=path[strlen(path)-1]) !='/' && c!=':' )
  1138.         strcat(path,"/");
  1139. }
  1140.  
  1141. static void
  1142. whereis( char *path, char *file )
  1143. {
  1144.     char **eav, buf[100];
  1145.     int  eac, j;
  1146.  
  1147.     buf[0]=0;
  1148.     if( path ) {
  1149.         strcpy(buf,path);
  1150.         appendslash(buf);
  1151.     }
  1152.     strcat(buf,".../");
  1153.     strcat(buf,file);
  1154.     if( !index( file, '*' ) && !index( file, '?') )
  1155.         strcat(buf,"*");
  1156.     if(eav=expand(buf,&eac)) {
  1157.         for( j=0; j<eac && !dobreak(); j++ )
  1158.             printf("%s\n",eav[j]);
  1159.         free_expand(eav);
  1160.     }
  1161. }
  1162.  
  1163. do_whereis( void )
  1164. {
  1165.     char buf[200], *prev, *devs;
  1166.     int i;
  1167.  
  1168.     if( index( av[1],':') || index( av[1],'/' ) )
  1169.         { fprintf(stderr,"No paths please\n"); return 20; };
  1170.  
  1171.     if( options&1 ) {
  1172.         Myprocess->pr_WindowPtr = (APTR)(-1);
  1173.         get_drives( devs=buf );
  1174.         do {
  1175.             prev=devs; devs=index(devs,0xA0);
  1176.             if( devs ) *devs++=0; 
  1177.             whereis( prev, av[1] );
  1178.         } while( devs );
  1179.         Myprocess->pr_WindowPtr = (APTR) o_noreq;
  1180.     } else if( ac==2 ) {
  1181.         whereis( NULL, av[1] );
  1182.     } else {
  1183.         for( i=2; i<ac; i++ ) {
  1184.             strcpy(buf,av[i]);
  1185.             appendslash( buf );
  1186.             whereis( buf, av[1] );
  1187.         }
  1188.     }
  1189.     return 0;
  1190. }
  1191.  
  1192. do_usage( void )
  1193. {
  1194.     int i;
  1195.  
  1196.     if( ac==1 ) {
  1197.         printf("Usage: usage [command...command]\n");
  1198.         printf("[ ]=option   [ | ]=choice   { }=repetition   name...name=1 or more names\n");
  1199.     } else 
  1200.         for( i=1; i<ac; i++ )
  1201.             show_usage( av[i] );
  1202.     return 0;
  1203. }
  1204.  
  1205. int NumMenus;
  1206.  
  1207. do_menu( void )
  1208. {
  1209.     if( o_nowindow )
  1210.         return 5;
  1211.  
  1212.     if( options&1 )
  1213.         remove_menu();
  1214.  
  1215.     if( ac==2 )
  1216.         show_usage( NULL );
  1217.     else if( NumMenus<MAXMENUS && ac!=1)
  1218.         install_menu( av+1, ac-1 );
  1219.  
  1220.     set_menu();
  1221.     return 0;
  1222. }
  1223.  
  1224. #define NUMITE 40
  1225. #define TITWID 90
  1226. #define ITEWID 148
  1227.  
  1228. static struct Menu DefaultMenu= {0, 0,0,TITWID,10, MENUENABLED,0,0};
  1229. static struct IntuiText DefaultIntuiText= {0,1,JAM2, 1,1,NULL,0,0};
  1230. static struct MenuItem DefaultMenuItem=
  1231.   {0, 0,0,ITEWID,0, HIGHCOMP|ITEMTEXT|ITEMENABLED,0,0,0,0,0,0};
  1232.  
  1233. struct Menu Menus[10];
  1234. char *MenuCommand[MAXMENUS][MAXITEMS];
  1235.  
  1236. static void
  1237. install_menu( char *mav[], int mac )
  1238. {
  1239.     struct TextAttr *ta;
  1240.     struct Menu *m;
  1241.     struct MenuItem *mi, **pmi;
  1242.     struct IntuiText *it;
  1243.     int y, i, fonthei;
  1244.     char *p, *com;
  1245.  
  1246.     if( o_nowindow || !Win )
  1247.         return;
  1248.  
  1249.     if( mac>=MAXITEMS )
  1250.         mac=MAXITEMS-1;
  1251.  
  1252.     ClearMenuStrip( Win );
  1253.     Delay(3);
  1254.  
  1255.     if( NumMenus )
  1256.         Menus[NumMenus-1].NextMenu=Menus+NumMenus;
  1257.     m  =&Menus[NumMenus];
  1258.     *m =DefaultMenu;
  1259.     m->LeftEdge  = NumMenus*TITWID;
  1260.     m->MenuName  = strcpy(salloc(strlen(mav[0])+1),mav[0]);
  1261.     if( strlen(m->MenuName)>TITWID/8 )
  1262.         m->MenuName[TITWID/8+1]=0;
  1263.     DefaultIntuiText.ITextFont=ta=Win->WScreen->Font;
  1264.     DefaultMenuItem.Height=2+(fonthei=ta->ta_YSize);
  1265.  
  1266.     y=0;
  1267.     pmi=&m->FirstItem;
  1268.     for( i=1; i<mac; i++) {
  1269.         it =(void *)salloc(sizeof(struct IntuiText));
  1270.         *it=DefaultIntuiText;
  1271.         mi =(void *)salloc(sizeof(struct MenuItem ));
  1272.         *mi=DefaultMenuItem;
  1273.  
  1274.         com=NULL;
  1275.         if( p=index(mav[i],',')) {
  1276.             *p=0; com=++p;
  1277.             if( p=index(com,',')) {
  1278.                 *p=0;
  1279.                 mi->Command=p[1];
  1280.                 mi->Flags |=COMMSEQ;
  1281.             }
  1282.         }
  1283.  
  1284.         if( !com || !*com) {
  1285.             com=strcpy(salloc(strlen(mav[i])+2),mav[i]);
  1286.             MenuCommand[NumMenus][i-1]=com;
  1287.             com+=strlen(com);
  1288.             *com++=13;
  1289.             *com=0;
  1290.         } else {
  1291.             MenuCommand[NumMenus][i-1]=strcpy(salloc(strlen(com)+1),com);
  1292.         }
  1293.  
  1294.         it->IText=(UBYTE *)strcpy(salloc(strlen(mav[i])+2),mav[i]);
  1295.  
  1296.         *pmi= mi;
  1297.         pmi = &mi->NextItem;
  1298.         mi->TopEdge = y;
  1299.         mi->ItemFill= (APTR)it;
  1300.  
  1301.         y+=DefaultMenuItem.Height;
  1302.     }
  1303.  
  1304.     NumMenus++;
  1305. MError:
  1306.     return;
  1307. }
  1308.  
  1309.  
  1310. void
  1311. remove_menu()
  1312. {
  1313.     if( NumMenus>0 ) {
  1314.         struct MenuItem *mi, *nextmi;
  1315.         int i,j;
  1316.  
  1317.         for( i=0; i<NumMenus; i++ ) {
  1318.             for( mi=Menus[i].FirstItem,j=0 ; mi; mi=nextmi,j++ ) {
  1319.                 free( ((struct IntuiText *)mi->ItemFill)->IText );
  1320.                 free( ((struct IntuiText *)mi->ItemFill) );
  1321.                 nextmi=mi->NextItem;
  1322.                 free(mi);
  1323.                 free(MenuCommand[i][j]);
  1324.             }
  1325.         }
  1326.  
  1327.         NumMenus=0;
  1328.         set_menu();
  1329.     }
  1330. }
  1331.  
  1332.  
  1333. void
  1334. set_menu()
  1335. {
  1336.     if( o_nowindow || !Win )
  1337.         return;
  1338.  
  1339.     if( NumMenus>0 )
  1340.         SetMenuStrip( Win, Menus );
  1341.     else 
  1342.         ClearMenuStrip( Win );
  1343.  
  1344.     Delay(3);
  1345. }
  1346.  
  1347. int
  1348. do_getenv( void )
  1349. {
  1350.     char buf[256], *val=buf;
  1351.  
  1352.     if( ac!=3 && ac!=2 ) {
  1353.         show_usage( NULL );
  1354.         return 20;
  1355.     }
  1356.     if( !Getenv(av[ac-1],buf,256))
  1357.         val="";
  1358.  
  1359.     if( ac==2 )
  1360.         printf( "%s\n", val );
  1361.     else 
  1362.         set_var( LEVEL_SET, av[1], val );
  1363.     return 0;
  1364. }
  1365.  
  1366. int
  1367. do_setenv( void )
  1368. {
  1369.     if( ac!=3 ) {
  1370.         show_usage( NULL );
  1371.         return 20;
  1372.     } else
  1373.         setenv( av[1], av[2] );
  1374.     return 0;
  1375. }
  1376.  
  1377. char **
  1378. read_name( char *name, int *ac )
  1379. {
  1380.     FILE *file;
  1381.     char **av=NULL;
  1382.  
  1383.     *ac=0;
  1384.     if( file=name ? fopen( name, "r") : stdin ) {
  1385.         av=read_file( file, ac );
  1386.         if( name ) fclose( file );
  1387.     } else 
  1388.         pError( name );
  1389.     return av;
  1390. }
  1391.  
  1392.  
  1393. char **
  1394. read_file( FILE *file, int *ac )
  1395. {
  1396.     int buflen=4096, lines=0, i, offs;
  1397.     char *buf, *tmp, *ptr, *got=NULL, **lineptr;
  1398.  
  1399.     if( !(buf=ptr=DosAllocMem( buflen )))
  1400.         goto error;
  1401.     do {
  1402.         while( ptr+400 < buf+buflen && (got=fgets( ptr, 400, file ) ) &&
  1403.                !dobreak()) {
  1404.             ptr+=strlen(ptr)-1, lines++;
  1405.             *ptr++=0;
  1406.         }
  1407.         if( ptr+256 < buf+buflen ) {
  1408.             offs=ptr-buf;
  1409.             if( !(tmp=DosAllocMem( buflen*2 )))
  1410.                 goto error;
  1411.             memcpy( tmp, buf, buflen );
  1412.             DosFreeMem( buf );
  1413.             buflen*=2, buf=tmp;
  1414.             ptr=buf+offs;
  1415.         }
  1416.     } while( got && !dobreak());
  1417.     if( !(lineptr=(char **)DosAllocMem( (lines+1)*sizeof( char * ))))
  1418.         goto error;
  1419.     *lineptr++=buf;
  1420.     for( ptr=buf, i=0; i<lines; i++ ) {
  1421.         lineptr[i]=ptr;
  1422.         ptr+=strlen(ptr)+1;
  1423.     }
  1424.     *ac=lines;
  1425.     return lineptr;
  1426.  
  1427. error:
  1428.     if( buf ) DosFreeMem( buf );
  1429.     fprintf( stderr, "Out of memory\n" );
  1430.     *ac=0;
  1431.     return NULL;
  1432. }
  1433.  
  1434. void
  1435. free_file( ptr )
  1436.     char **ptr;
  1437. {
  1438.     if( ptr-- ) {
  1439.         if( *ptr )
  1440.             DosFreeMem( *ptr );
  1441.         DosFreeMem(ptr);
  1442.     }
  1443. }
  1444.  
  1445.  
  1446. do_qsort( void )
  1447. {
  1448.     char **lineptr;
  1449.     int  lines, i;
  1450.  
  1451.     if( ac==1 ) {
  1452.         lineptr=read_file( stdin, &lines);
  1453.         DirQuickSort( lineptr, lines, cmp, options&1, 0 );
  1454.         prepscroll(0);
  1455.         for( i=0; i<lines && !dobreak(); i++ ) {
  1456.             quickscroll();
  1457.             puts( lineptr[i] );
  1458.         }
  1459.         free_file( lineptr );
  1460.     } else
  1461.         ierror( NULL,506 );
  1462.     return 0;
  1463. }
  1464.  
  1465. extern int w_width;
  1466.  
  1467. do_truncate( void )
  1468. {
  1469.     char buf[256];
  1470.     int  w=newwidth(), c;
  1471.     char *ptr;
  1472.  
  1473.     if( ac==2 )
  1474.         w=atoi( av[1] );
  1475.  
  1476.     prepscroll(0);
  1477.     while( gets(buf) && !dobreak() ) {
  1478.         for( c=0, ptr=buf; *ptr && c<w; ptr++ )
  1479.             if( *ptr=='\t' )
  1480.                 c+=8-(c&7);
  1481.             else if( *ptr==27 ) {
  1482.                 while( *ptr<'@' )
  1483.                     ptr++;
  1484.             } else 
  1485.                 c++;
  1486.         *ptr=0;
  1487.         quickscroll();
  1488.         puts(buf);
  1489.     }
  1490.     return 0;
  1491. }
  1492.  
  1493. int
  1494. do_readfile( void )
  1495. {
  1496.     char **rav, *str=NULL, *file=NULL;
  1497.     int rac;
  1498.  
  1499.     if( ac>2 ) file=av[2];
  1500.     if( rav=read_name( file, &rac ) ) { 
  1501.         if( str= compile_av( rav, 0, rac, 0xA0, 0 ) )
  1502.             set_var( LEVEL_SET, av[1], str );
  1503.         free_file( rav );
  1504.     }
  1505.     return str ? 0 : 20;
  1506. }
  1507.  
  1508. void
  1509. foreach( char **s, int (*func)(char *s) )
  1510. {
  1511.     char *str;
  1512.  
  1513.     for( ;; ) {
  1514.         str=*s;
  1515.         if( !(*s=index(*s,0xA0)))
  1516.             break;
  1517.         **s=0;
  1518.         (*func)(str);
  1519.         *(*s)++=0xA0;
  1520.         if( breakcheck())
  1521.             return;
  1522.     }
  1523.     (*func)(str);
  1524. }
  1525.  
  1526. int
  1527. do_writefile( void )
  1528. {
  1529.     char *ptr;
  1530.  
  1531.     if( !(ptr=get_var(LEVEL_SET,av[1])))
  1532.         { fprintf(stderr,"Undefined variable %s\n",av[1]); return 20; }
  1533.  
  1534.     foreach( &ptr, puts );
  1535.  
  1536.     return 0;
  1537. }
  1538.  
  1539. int
  1540. do_split( void )
  1541. {
  1542.     int i;
  1543.     char *val, *gap, *oldval;
  1544.  
  1545.     if( !(val=get_var( LEVEL_SET, av[1] )))
  1546.         { fprintf( stderr, "undefined variable %s\n", av[1] ); return 20; }
  1547.     oldval=val=strcpy(salloc(strlen(val)+1),val);
  1548.     for( i=2; i<ac-1; i++ ) {
  1549.         if( gap=index(val,0xA0 )) *gap=0;
  1550.         set_var( LEVEL_SET, av[i], val );
  1551.         val="";
  1552.         if( gap ) *gap=0xA0, val=gap+1;
  1553.     }
  1554.     set_var( LEVEL_SET, av[ac-1], val );
  1555.     free(oldval);
  1556.     return 0;
  1557. }
  1558.  
  1559. char *
  1560. copyof( char *str )
  1561. {
  1562.     return strcpy(salloc(strlen(str)+1),str);
  1563. }
  1564.  
  1565. int
  1566. do_class( char *avline )
  1567. {
  1568.     CLASS *new;
  1569.  
  1570.     if( options&1 ) {
  1571.         avline=next_word(avline);
  1572.         for( new=CRoot,CRoot=NULL; new; new=new->next )
  1573.             Free(new);
  1574.     }
  1575.  
  1576.     if( ac==1 ) {
  1577.         for( new=CRoot; new; new=new->next )
  1578.             printf("%s\n",new->name);
  1579.         return 0;
  1580.     }
  1581.  
  1582.     avline=next_word(avline);
  1583.     if(!(new=malloc( strlen(avline)+5)))
  1584.         ierror( NULL, 512 );
  1585.     else {
  1586.         new->next=NULL;
  1587.         strcpy( new->name,avline );
  1588.         if( CRoot )
  1589.             LastCRoot->next=new;
  1590.         else 
  1591.             CRoot=new;
  1592.         LastCRoot=new;
  1593.     }
  1594.     return 0;
  1595. }
  1596.  
  1597. do_getcl( void )
  1598. {
  1599.     char *s=getclass(av[1]);
  1600.     if( s ) printf("%s\n",s);
  1601.     return 0;
  1602. }
  1603.  
  1604. do_action( char *argline )
  1605. {
  1606.     char *args, err;
  1607.     int abort=options&1;
  1608.  
  1609.     args=compile_av( av,3,ac,' ',0 );
  1610.     err=doaction(av[2],av[1],args);
  1611.     if( !abort )
  1612.         if( err==10 )    fprintf(stderr,"Can't identify %s\n", av[2] );
  1613.         else if(err==11) fprintf(stderr,"Can't '%s' this file\n",av[1] );
  1614.     return abort ? !err : err;
  1615. }
  1616.