home *** CD-ROM | disk | FTP | other *** search
/ back2roots/padua / padua.7z / padua / shell / csh548src.lha / comm2.c < prev    next >
C/C++ Source or Header  |  1995-09-12  |  44KB  |  1,953 lines

  1. /*
  2.  * COMM2.C
  3.  *
  4.  * (c)1986 Matthew Dillon     9 October 1986
  5.  *
  6.  * Version 2.07M by Steve Drew 10-Sep-87
  7.  * Version 4.01A by Carlo Borreo & Cesare Dieni 17-Feb-90
  8.  * Version 5.00L by Urban Mueller 17-Feb-91
  9.  * Version 5.20L by Andreas M. Kirchwitz (Fri, 13 Mar 1992)
  10.  *
  11.  */
  12.  
  13. #include "shell.h"
  14.  
  15. /* comm2.c */
  16. static long dptrtosecs(DPTR *d);
  17. static long timeof(char *s);
  18. static int evalif(void);
  19. static int clinum(char *name);
  20. static int copydir(long srcdir, long destdir, int recur, char *path);    /*GMD27Jun95 */
  21. static int copyfile(char *srcname, long srcdir, char *destname, long destdir);
  22. static void changedisk(char *name);
  23. static int func_array( char *fav[], int fac);
  24. static int func_int(int i);
  25. static int func_err (void);    /*GMD 13FEB94*/
  26. static int func_bool(int i);
  27. static int func_string(char *str);
  28. static int commas(char *av[], int ac, int n);
  29. static int wordset(char **av, int ac, char **(*func)(char **,int,char**,int,int*,int));
  30. static int split_arg(char **av, int ac);
  31. static char *info_part(char **av, int ac, int n, char *buf);
  32. static char *get_filedate (char *file);    /* GMD */
  33. static char *get_filenote (char *file);    /* GMD */
  34.  
  35. /* Casting conveniences */
  36. #define BPTR_TO_C(strtag, var)  ((struct strtag *)(BADDR( (ULONG) var)))
  37. #define PROC(task)              ((struct Process *)task)
  38. #define CLI(proc)               (BPTR_TO_C(CommandLineInterface, proc->pr_CLI))
  39.  
  40. /* Externs */
  41. extern int has_wild;                    /* flag set if any arg has a ? or * */
  42.  
  43. int
  44. do_abortline( void )
  45. {
  46.     Exec_abortline = 1;
  47.     return 0;
  48. }
  49.  
  50. int
  51. do_error( void )
  52. {
  53.     return atoi(av[1]);
  54. }
  55.  
  56. int
  57. do_return( void )
  58. {
  59.     int retcode=(ac<2 ? 0 : atoi(av[1]));
  60.  
  61.     Exec_abortline = 1;
  62.     if (Src_stack) {
  63.         Src_abort[Src_stack-1]=1;
  64.         return retcode;
  65.     } else
  66.         main_exit(retcode);
  67.     return 0;
  68. }
  69.  
  70. /*
  71.  * STRHEAD
  72.  *
  73.  * place a string into a variable removing everything after and including
  74.  * the 'break' character
  75.  *
  76.  * strhead varname breakchar string
  77.  *
  78.  */
  79.  
  80. int
  81. do_strhead( void )
  82. {
  83.     char *s;
  84.     if (*av[2] && (s=index( av[3], *av[2]))) 
  85.         *s='\0';
  86.     set_var (LEVEL_SET, av[1], av[3]);
  87.     return 0;
  88. }
  89.  
  90. int
  91. do_strtail( void )
  92. {
  93.     char *s;
  94.     if (*av[2] && (s=index(av[3],*av[2]))) s++; else s=av[3];
  95.     set_var (LEVEL_SET, av[1], s);
  96.     return 0;
  97. }
  98.  
  99. static long
  100. dptrtosecs(DPTR *d)
  101. {
  102.     struct DateStamp *ds=(&d->fib->fib_Date);
  103.     return ds->ds_Days*86400 + ds->ds_Minute*60 + ds->ds_Tick/TICKS_PER_SECOND;
  104. }
  105.  
  106. static long
  107. timeof(char *s)
  108. {
  109.     DPTR *d;
  110.     int  dummy;
  111.     long n;
  112.  
  113.     if ( (d=dopen(s,&dummy))==NULL ) return 0L;
  114.     n=dptrtosecs(d);
  115.     dclose(d);
  116.     return n;
  117. }
  118.  
  119. /*
  120.  * if -f file (exists) or:
  121.  *
  122.  * if A < B   <, >, =, <=, >=, <>, where A and B are either:
  123.  * nothing
  124.  * a string
  125.  * a value (begins w/ number)
  126.  */
  127.  
  128. #define IF_NOT 128
  129.  
  130. int
  131. do_if( char *garbage, int com )
  132. {
  133.     int result;
  134.  
  135.     switch (com) {
  136.     case 0:
  137.         if (If_stack && If_base[If_stack - 1])
  138.             If_base[If_stack++] = 1;
  139.         else {
  140.             result=evalif();
  141.             If_base[If_stack++]=(options & IF_NOT ? result : !result);
  142.         }
  143.         break;
  144.     case 1:
  145.         if (If_stack > 1 && If_base[If_stack - 2]) break;
  146.         if (If_stack) If_base[If_stack - 1] ^= 1;
  147.         break;
  148.     case 2:
  149.         if (If_stack) --If_stack;
  150.         break;
  151.     }
  152.     disable = (If_stack) ? If_base[If_stack - 1] : 0;
  153.     if (If_stack >= MAXIF) {
  154.         fprintf(stderr,"If's too deep\n");
  155.         disable = If_stack = 0;
  156.         return -1;
  157.     }
  158.     return 0;
  159. }
  160.  
  161. static int
  162. isint( char *s )
  163. {
  164.     while( ISSPACE(*s) ) ++s;
  165.     return *s=='+' || *s=='-' || *s>='0' && *s<='9';
  166. }
  167.  
  168. static int
  169. evalif( void )
  170. {
  171.     char c, *str, *left, *right, *cmp;
  172.     long num, t0, i=1;
  173.     int nac=ac-1, err;
  174.  
  175.     if(!strcmp(av[ac-1],"then")) ac--;
  176.  
  177.     switch(options & ~IF_NOT) {
  178.     case 0:
  179.         for( i=1; i<ac; i++ )
  180.             if( strlen(str=av[i])<=2 && *str && index("!<=>",*str) &&
  181.                    (!str[1] || index("<=>",str[1])))
  182.                 break;
  183.  
  184.         if ( i==ac )
  185.             return ac>1 && *av[1] && strcmp(av[1],"0");
  186.  
  187.         left =av[1];
  188.         right=av[i+1];
  189.         if( 1+1!=i )    left = compile_av(av,1,i   ,0xA0, 0);
  190.         if( i+1+1!=ac ) right= compile_av(av,i+1,ac,0xA0, 0);
  191.         cmp  = av[i];
  192.         num  = atol(left) - atol(right);
  193.         if( *cmp=='!' )  cmp++, options^=IF_NOT;
  194.         if( !isint(left) || !isint(right)) num=strcmp(left,right);
  195.         if( 1+1!=i )    free(left);
  196.         if( i+1+1!=ac ) free(right);
  197.  
  198.         if (num < 0)       c='<';
  199.         else if (num > 0)  c='>';
  200.         else               c='=';
  201.         return index(cmp, c) != NULL;
  202.     case 1:
  203.         return do_rpn(NULL,i);
  204.     case 2:
  205.     case 256:
  206.         return exists(av[i]);
  207.     case 4:
  208.         t0=timeof(av[i++]);
  209.         for ( ; i<ac ; i++)
  210.             if (t0<=timeof(av[i])) return 1;
  211.         return 0;
  212.     case 8:
  213.         return AvailMem( MEMF_FAST )!=0;
  214.     case 16:
  215.         return isdir(av[i])!=0;
  216.     case 32:
  217.         return get_var(LEVEL_SET,av[i]) != 0;
  218.     case 64:
  219.         if( ac>1 )
  220.             return get_opt(av+1,&nac,-*av[1],&err);
  221.         return 0;
  222.     default:
  223.         ierror(NULL,500);
  224.     }
  225.     return 0;
  226. }
  227.  
  228. #if 0
  229. do_while( void )
  230. {
  231.     char *com=av[--ac];
  232.     int ret=0;
  233.  
  234.     while( evalif() && ret==0 && !CHECKBREAK() )
  235.         ret=execute( com );
  236.     return ret;
  237. }
  238. #endif
  239.  
  240.  
  241. int
  242. do_label( void )
  243. {
  244.     char aseek[32], *fwd;
  245.  
  246.     if (Src_stack == 0) {
  247.         ierror (NULL, 502);
  248.         return -1;
  249.     }
  250.  
  251.     sprintf (aseek, "%ld %d", Src_pos[Src_stack-1], If_stack);
  252.     set_var (LEVEL_LABEL + Src_stack - 1, av[1], aseek);
  253.  
  254.     fwd=get_var(LEVEL_SET,v_gotofwd);
  255.     if (fwd && !strcmp(av[1],fwd))
  256.         forward_goto = 0;
  257.     return 0;
  258. }
  259.  
  260. int
  261. do_goto( void )
  262. {
  263.     int new;
  264.     long pos;
  265.     char *lab;
  266.  
  267.     if (Src_stack == 0) {
  268.         ierror (NULL, 502);
  269.     } else {
  270.         lab = get_var (LEVEL_LABEL + Src_stack - 1, av[1]);
  271.         if (lab == NULL) {
  272.             forward_goto = 1;
  273.             set_var (LEVEL_SET, v_gotofwd, av[1]);
  274.             return(0);
  275.         } else {
  276.             pos = atoi(lab);
  277.             fseek (Src_base[Src_stack - 1], pos, 0);
  278.             Src_pos[Src_stack - 1] = pos;
  279.             new = atoi(next_word(lab));
  280.             for (; If_stack < new; ++If_stack)
  281.                 If_base[If_stack] = 0;
  282.             If_stack = new;
  283.         }
  284.     }
  285.     Exec_abortline = 1;
  286.     return (0);      /* Don't execute rest of this line */
  287. }
  288.  
  289.  
  290. int
  291. do_inc(char *garbage, int com)
  292. {
  293.     char *var, num[32];
  294.  
  295.     if (ac>2) com *= atoi(av[2]);
  296.     if (var = get_var (LEVEL_SET, av[1])) {
  297.         sprintf (num, "%d", atoi(var)+com);
  298.         set_var (LEVEL_SET, av[1], num);
  299.     }
  300.     return 0;
  301. }
  302.  
  303. BPTR Input(void);
  304. BPTR Output(void);
  305.  
  306. int
  307. do_input( void )
  308. {
  309.     char *str, in[256], *get, *put;
  310.     int i, quote=0;
  311.  
  312.     if( options&2 ) {
  313.         if( !IsInteractive(Input()) ) return 20;
  314.         setrawcon( -1, 0 );
  315.         in[1]=0;
  316.         for ( i=1; i<ac && !CHECKBREAK(); ++i) {
  317.             Read( Input(), in, 1 );
  318.             set_var (LEVEL_SET, av[i], in);
  319.         }
  320.         setrawcon( 0, 0 );
  321.         return 0;
  322.     }
  323.  
  324.     for ( i=1; i<ac; ++i)
  325.         if (fgets(in,256,stdin)) {
  326.             str=in, put=in+strlen(in)-1;
  327.             if( *put=='\n' ) *put=0;
  328.             if( !(options&1) ) {
  329.                 while( *str==' ' ) str++;
  330.                 for( put=get=str; *get; ) {
  331.                     if( *get=='\"' )
  332.                         quote=1-quote, get++;
  333.                     else if( *get==' ' && !quote ) {
  334.                         while( *get==' ' ) get++;
  335.                         if( *get ) *put++=0xA0;
  336.                     } else 
  337.                         *put++ = *get++;
  338.                 }
  339.                 *put=0;
  340.             }
  341.             set_var (LEVEL_SET, av[i], str);
  342.         }
  343.     return 0;
  344. }
  345.  
  346. int
  347. do_version( void )
  348. {
  349.     extern char shellname[];
  350.     extern char shellcompiled[];
  351.     int i;
  352.     char str[256];
  353.  
  354.     if (ac > 1) {
  355.         for ( i=1; i<ac; ++i) {
  356.             sprintf(str,"C:Version%s%s%s%s \"%s\"",
  357.                 (options&1) ? " FILE" : "",        /* -f */
  358.                 (options&2) ? " INTERNAL" : "",        /* -i */
  359.                 (options&4) ? " FULL" : "",        /* -l */
  360.                 (options&8) ? " RES" : "",        /* -r */
  361.                 av[i]);
  362.             execute(str);
  363.         }
  364.     }
  365.     else {
  366.         puts(shellname);
  367.         puts("1.00 Lattice (c) 1986 Matthew Dillon\n"
  368.              "2.05 Manx(M) versions by Steve Drew\n"
  369.              "3.00 ARP (A) versions by Carlo Borreo, Cesare Dieni\n"
  370.              "4.00 ARP 1.3 versions by Carlo Borreo, Cesare Dieni\n"
  371.              "5.00 Lattice versions by U. Dominik Mueller\n"
  372.              "5.20+ OS 2.0 versions by Andreas M. Kirchwitz\n");
  373.         printf( shellcompiled );
  374.         printf("Currently running: ");
  375.         fflush(stdout);
  376.         sprintf(str,"C:Version%s%s%s%s",
  377.             (options&1) ? " FILE" : "",        /* -f */
  378.             (options&2) ? " INTERNAL" : "",        /* -i */
  379.             (options&4) ? " FULL" : "",        /* -l */
  380.             (options&8) ? " RES" : ""        /* -r */
  381.             );
  382.         execute(str);
  383.     }
  384.  
  385.     return 0;
  386. }
  387.  
  388.  
  389. static int
  390. clinum( char *name )
  391. {
  392.     long ncli=MaxCli(), count;
  393.     struct Process *proc;
  394.     char cmd[40+1];
  395.  
  396.     if( *name>='0' && *name<='9' )
  397.         return atoi( name );
  398.  
  399.     Forbid();
  400.     for (count = 1; count <= ncli ; count++)
  401.         if (proc = FindCliProc(count)) {
  402.             if( !proc->pr_TaskNum || proc->pr_CLI == 0)
  403.                 continue;
  404.             BtoCStr(cmd,CLI(proc)->cli_CommandName, 40L);
  405.             if( !stricmp( FilePart( cmd ), FilePart( name )))
  406.                 goto done;
  407.         }
  408.     count = -1;
  409. done:
  410.     Permit();
  411.     return count;
  412. }
  413.  
  414.  
  415. char task_state(struct Task *task)
  416. {
  417.     char state = '?';
  418.     switch (task->tc_State) {
  419.         case TS_INVALID: state='i'; break;
  420.         case TS_ADDED  : state='a'; break;
  421.         case TS_RUN    : state='r'; break;
  422.         case TS_READY  : state='r'; break;
  423.         case TS_WAIT   : state='w'; break;
  424.         case TS_EXCEPT : state='e'; break;
  425.         case TS_REMOVED: state='d'; break;
  426.         default: break;
  427.     }
  428.     return(state);
  429. }
  430.  
  431. int
  432. do_ps( void )
  433. {
  434.     /* this code fragment based on ps.c command by Dewi Williams */
  435.     long count;            /* loop variable         */
  436.     struct Task *task;     /* EXEC descriptor       */
  437.     struct Process *proc;  /* EXEC descriptor       */
  438.     char strbuf[64+1];     /* scratch for btocstr() */
  439.     char cmd[40+1], *com;  /* holds cmd name        */
  440.     long ncli,mycli,cli,i;
  441.     long ssize;            /* stack size */
  442.     char fmt[256];
  443.  
  444.     char **dev_list=NULL;
  445.     long dev_num=0;
  446.  
  447.     char onoff[80];
  448.     memset( onoff, 0, 80 );
  449.     for( i=1; i<ac; i++ )
  450.         onoff[ 1+clinum( av[i] ) ]=1;
  451.     if( options&2 )
  452.         for( i=0; i<80; i++ )
  453.             onoff[i]=1-onoff[i];
  454.  
  455.     if (options&4)
  456.         printf("Proc Command Name         CLI Type    Pri.  Address  Directory\n");
  457.     else
  458.         printf("Proc Command Name         Typ  Stack  Pri.  Address  Directory\n");
  459.  
  460.     Forbid();
  461.  
  462.     ncli=(LONG)MaxCli();
  463.     mycli= Myprocess->pr_TaskNum;
  464.  
  465.     for (count = 1; count <= ncli ; count++) {
  466.         if (proc = FindCliProc(count)) {    /* Sanity check */
  467.             task = (struct Task *)proc;
  468.             cli=proc->pr_TaskNum;
  469.             if( ac>1 && !onoff[1+cli] )
  470.                 continue;
  471.             if ( cli==0 || proc->pr_CLI == 0) continue; /* or complain? */
  472.                 BtoCStr(cmd,   CLI(proc)->cli_CommandName, 40L);
  473.                 BtoCStr(strbuf,CLI(proc)->cli_SetName    , 64L);
  474.             com=cmd;
  475.             if( !(options&1) )
  476.                 com=FilePart(com);
  477.             if (options&4) {
  478.                 sprintf(fmt,"%c%2d  %-20.20s %-10.10s %4d  %8lx  %s",
  479.                     cli==mycli ? '*' : ' ',
  480.                     count,
  481.                     com,
  482.                     task->tc_Node.ln_Name,
  483.                     (signed char)task->tc_Node.ln_Pri,
  484.                     proc,
  485.                     strbuf
  486.                 );
  487.             }
  488.             else {
  489.                 if (task->tc_SPReg>=task->tc_SPLower && task->tc_SPReg<task->tc_SPUpper)
  490.                     ssize = (long)task->tc_SPUpper-(long)task->tc_SPLower;
  491.                 else
  492.                     ssize = (CLI(proc)->cli_DefaultStack)*4;
  493.                 sprintf(fmt,"%c%2d  %-20.20s %c%c %7ld %4d  %8lx  %s",
  494.                     cli==mycli ? '*' : ' ',
  495.                     count,
  496.                     com,
  497.                     CLI(proc)->cli_Background?'b':'f',
  498.                     task_state(task),
  499.                     ssize,
  500.                     (signed char)task->tc_Node.ln_Pri,
  501.                     proc,
  502.                     strbuf
  503.                 );
  504.             }
  505.             add_array_list(&dev_list,&dev_num,fmt);
  506.         }
  507.     }
  508.  
  509.     Permit();
  510.  
  511.     for(i=0; !dobreak() && i<dev_num; i++)
  512.         printf("%s\n",dev_list[i]);
  513.  
  514.     free_array_list(dev_list,dev_num);
  515.  
  516.     return 0;
  517. }
  518.  
  519. #if 0
  520. int
  521. do_ps( void )
  522. {
  523.     /* this code fragment based on ps.c command by Dewi Williams */
  524.     int count;             /* loop variable         */
  525.     struct Task *task;     /* EXEC descriptor       */
  526.     char strbuf[64+1];     /* scratch for btocstr() */
  527.     char cmd[40+1], *com;  /* holds cmd name        */
  528.     long ncli,mycli,cli,i;
  529.  
  530.     char onoff[80];
  531.     memset( onoff, 0, 80 );
  532.     for( i=1; i<ac; i++ )
  533.         onoff[ 1+clinum( av[i] ) ]=1;
  534.     if( options&2 )
  535.         for( i=0; i<80; i++ )
  536.             onoff[i]=1-onoff[i];
  537.  
  538.     printf("Proc Command Name         CLI Type    Pri.  Address  Directory\n");
  539.     Forbid();
  540.  
  541.     ncli=(LONG)MaxCli();
  542.     mycli= Myprocess->pr_TaskNum;
  543.     for (count = 1; count <= ncli ; count++)             /* or just assume 20?*/
  544.         if (task = (struct Task *)FindCliProc((LONG)count)) {/* Sanity check      */
  545.             cli=PROC(task)->pr_TaskNum;
  546.             if( ac>1 && !onoff[1+cli] )
  547.                 continue;
  548.             if ( cli==0 || PROC(task)->pr_CLI == 0) continue; /* or complain? */
  549.                 BtoCStr(cmd,   CLI(PROC(task))->cli_CommandName, 40L);
  550.                 BtoCStr(strbuf,CLI(PROC(task))->cli_SetName    , 64L);
  551.             com=cmd;
  552.             if( !(options&1) )
  553.                 com=FilePart(com);
  554.                 printf("%c%2d  %-20.20s %-11.11s %3d  %8lx  %s\n",
  555.                 cli==mycli ? '*' : ' ',
  556.                 count,
  557.                 com,
  558.                 task->tc_Node.ln_Name,
  559.                 (signed char)task->tc_Node.ln_Pri,
  560.                 task,
  561.                 strbuf
  562.             );
  563.         }
  564.  
  565.     Permit();
  566.     return 0;
  567. }
  568. #endif
  569.  
  570. /*
  571.  * CP [-d] [-u] file file
  572.  * CP [-d] [-u] file file file... destdir
  573.  * CP [-r][-u][-d] dir dir dir... destdir
  574.  */
  575.  
  576. #define CP_RECUR         0x1
  577. #define CP_UPDATE        0x2
  578. #define CP_NODATE        0x4
  579. #define CP_NOFLAGS       0x8
  580. #define CP_FRESH         0x10
  581. #define CP_MOVE          0x20
  582. #define CP_QUIET         0x40
  583. #define CP_OVERWRITE     0x80
  584. #define CP_LEAVE_ARCHIVE 0x100
  585. #define CP_OUTPUTFORMAT2 0x200
  586.  
  587. static char *errstr = NULL;          /* let's be a little more informative */
  588. static int level;
  589. static char **dir_lst;        /*GMD27Jun95 */
  590. static int dir_lst_sz;        /*GMD27Jun95 */
  591.  
  592. void print_path(int j);        /*GMD27Jun95 */
  593. void push_dir_path(char *zz);    /*GMD27Jun95 */
  594. void pop_dir_path(int offs);    /*GMD27Jun95 */
  595.  
  596. int do_copy( void )
  597. {
  598.     int recur, ierr;
  599.     char *destname;
  600.     char destisdir;
  601.     FIB *fib;
  602.     int i;
  603.  
  604.     if (OPT(CP_OUTPUTFORMAT2)) {
  605.         level = 0;        /*GMD27Jun95, be safe */
  606.         dir_lst = NULL;        /*GMD27Jun95, be safe */
  607.         dir_lst_sz = 0;        /*GMD27Jun95, be safe */
  608.     }
  609.  
  610.     errstr = NULL;
  611.     ierr   = 0;
  612.  
  613.     fib = (FIB *)SAllocMem((long)sizeof(FIB), MEMF_PUBLIC);
  614.  
  615.     recur    = OPT( CP_RECUR );
  616.     destname = av[ac - 1];
  617.  
  618.     if (ac < 3) {
  619.         ierr = 500;
  620.         goto done;
  621.     }
  622.     destisdir = isdir(destname);
  623.     if (ac > 3 && !destisdir) {
  624.         ierr = 507;
  625.         goto done;
  626.     }
  627.  
  628. /*
  629.  * copy set:                        reduce to:
  630.  *    file to file                     file to file
  631.  *    dir  to file (NOT ALLOWED)
  632.  *    file to dir                      dir to dir
  633.  *    dir  to dir                      dir to dir
  634.  *
  635.  */
  636.  
  637.     for ( i=1; i<ac-1 && !dobreak(); ++i) {
  638.         short srcisdir = isdir(av[i]);
  639.  
  640.         /*
  641.          *  hack to stop dir's from
  642.          *  getting copied if specified
  643.          *  from wild expansion         
  644.          */
  645.  
  646.         if (srcisdir && has_wild && (ac >2))
  647.             continue;
  648.  
  649.         if (srcisdir) {
  650.             BPTR srcdir, destdir;
  651.             if (!destisdir) {
  652.                 if (exists(destname)) {
  653.                     ierr = 507;    /* disallow dir to file */
  654.                     goto done;
  655.                     }
  656.                 if (destdir = CreateDir(destname)) UnLock(destdir);
  657.                 destisdir = 1;
  658.             }
  659.             if (!(destdir = Lock(destname, ACCESS_READ))) {
  660.                 ierr = 205;
  661.                 errstr = strdup(destname);
  662.                 goto done;
  663.             }
  664.             if (!(srcdir = Lock(av[i], ACCESS_READ))) {
  665.                 ierr = 205;
  666.                 errstr = strdup(av[i]);
  667.                 UnLock(destdir);
  668.                 goto done;
  669.             }
  670.             ierr = copydir(srcdir, destdir, recur, av[i]);    /*GMD27Jun95 */
  671.             UnLock(srcdir);
  672.             UnLock(destdir);
  673.             if (ierr) break;
  674.         } else {                   /* FILE to DIR,   FILE to FILE   */
  675.             BPTR destdir, srcdir, tmp;
  676.             char *destfilename;
  677.  
  678.             srcdir = (BPTR)(Myprocess->pr_CurrentDir);
  679.  
  680.             if ((tmp = Lock(av[i], ACCESS_READ)) == NULL || !Examine(tmp,fib)) {
  681.                 if (tmp) UnLock(tmp);
  682.                 ierr = 205;
  683.                 errstr = strdup(av[i]);
  684.                 goto done;
  685.             }
  686.             UnLock(tmp);
  687.             if (destisdir) {
  688.                 destdir = Lock(destname, ACCESS_READ);
  689.                 destfilename = fib->fib_FileName;
  690.             } else {
  691.                 destdir = srcdir;
  692.                 destfilename = destname;
  693.             }
  694.             ierr = copyfile(av[i], srcdir, destfilename, destdir);
  695.             if (destisdir) UnLock(destdir);
  696.             if (ierr) break;
  697.         }
  698.     }
  699.  
  700. done:
  701.  
  702.     FreeMem(fib, sizeof(FIB));
  703.  
  704.     if (ierr) {
  705.         ierror( errstr?errstr:"", ierr);
  706.         if (errstr) {
  707.             free(errstr);
  708.             errstr = NULL;
  709.         }
  710.         return 20;
  711.     }
  712.  
  713.     /* just to be sure if ierr was 0 */
  714.     if (errstr) {
  715.         free(errstr);
  716.         errstr = NULL;
  717.     }
  718.  
  719.     if (OPT(CP_OUTPUTFORMAT2)) {
  720.         if (dir_lst) {        /*GMD27Jun95 */
  721.             while (level)
  722.                 pop_dir_path(level--);    /* free dirname str */
  723.             free(dir_lst);
  724.         }
  725.     }
  726.  
  727.     return 0;
  728. }
  729.  
  730.  
  731. static int copydir(BPTR srcdir, BPTR destdir, int recur, char *path)
  732.                             /*GMD27Jun95 */
  733. {
  734.     BPTR cwd;
  735.     BPTR destlock, srclock;
  736.     char *srcname;
  737.     FIB *srcfib;
  738.     int ierr=0;
  739.  
  740.     srcfib = (FIB *)SAllocMem((long)sizeof(FIB), MEMF_PUBLIC);
  741.     if( !Examine(srcdir, srcfib)) {
  742.         ierr=IoErr();
  743.         goto done;
  744.     }
  745.     srcname=srcfib->fib_FileName;
  746.  
  747.     if (OPT(CP_OUTPUTFORMAT2)) {
  748.         push_dir_path(path);    /*GMD27Jun95 */
  749.     }
  750.  
  751.     while (ExNext(srcdir, srcfib)) {
  752.         if (CHECKBREAK())
  753.             break;
  754.         if (srcfib->fib_DirEntryType < 0) {
  755.             ierr = copyfile(srcname,srcdir,srcname,destdir);
  756.             if (ierr) break;
  757.         } else {
  758.             if ( srcfib->fib_DirEntryType!=ST_USERDIR ) {
  759.                 if (OPT(CP_OUTPUTFORMAT2)) {
  760.                     print_path(3);    /*GMD27Jun95 */
  761.                     printf(" ....[Skipped. Is a link]\n");
  762.                 }
  763.                 else {
  764.                     printf("%*s%s (Dir)....[Skipped. Is a link]\n",level * 6," ",srcname);
  765.                 }
  766.                 continue;
  767.             }
  768.             if (recur) {
  769.                 cwd = CurrentDir(srcdir);
  770.                 if (srclock = Lock(srcname, ACCESS_READ)) {
  771.                     CurrentDir(destdir);
  772.                     if (!(destlock = Lock(srcname,ACCESS_READ))) {
  773.                         destlock = CreateDir(srcname);
  774.                         if (!OPT(CP_OUTPUTFORMAT2)) {
  775.                             printf("%*s%s (Dir)....[Created]\n",level * 6," ",srcname);
  776.                         }
  777. #if 0
  778.                         printf("....[Created]\n");    /*GMD27Jun95 */
  779. #endif
  780.  
  781.                         /* UnLock and re Lock if newly created
  782.                          * for file_date() to work properly */
  783.                         if (destlock)
  784.                             UnLock(destlock);
  785.                         destlock = Lock(srcname, ACCESS_READ);
  786.                     } else {
  787.                         if (!OPT(CP_OUTPUTFORMAT2)) {
  788.                             printf("%*s%s (Dir)\n",level * 6," ",srcname);
  789.                         }
  790.                     }
  791.                     if (destlock) {
  792.                         level++;
  793.                         ierr = copydir(srclock, destlock, recur, srcname);    /*GMD27Jun95 */
  794.  
  795.                         if (OPT(CP_OUTPUTFORMAT2)) {
  796.                             pop_dir_path(level);    /*GMD27Jun95 */
  797.                         }
  798.  
  799.                         level--;
  800.                         UnLock(destlock);
  801.                     } else
  802.                         ierr = IoErr();
  803.                     UnLock(srclock);
  804.                     if (!OPT(CP_NOFLAGS)) {
  805.                         setProtection(srcname,srcfib->fib_Protection );
  806.                         if( *srcfib->fib_Comment )
  807.                             SetComment( srcname, srcfib->fib_Comment );
  808.                     }
  809.                 } else {
  810.                     ierr = IoErr();
  811.                 }
  812.                 CurrentDir(cwd);
  813.                 if (ierr)
  814.                     break;
  815.             }
  816.         }
  817.     }
  818. done:
  819.     FreeMem(srcfib, sizeof(FIB));
  820.     return ierr;
  821. }
  822.  
  823.  
  824.  
  825. #define COPYBUF 32768
  826.  
  827. static int
  828. copyfile(char *srcname, BPTR srcdir, char *destname, BPTR destdir)
  829. {
  830.     BPTR cwd;
  831.     BPTR f_src  = NULL;
  832.     BPTR f_dest = NULL;
  833.     long dest_mode;
  834.     long j;
  835.     int  stat,ierr=0,reset=0;
  836.     char *buf;
  837.     DPTR *dpd = NULL;
  838.     DPTR *dps;
  839.     long src_pbits;
  840.  
  841.     if (errstr) {
  842.         free(errstr);
  843.         errstr = NULL;
  844.     }
  845.  
  846.     if ( !(buf= (char *)AllocMem(COPYBUF, MEMF_PUBLIC|MEMF_CLEAR)))
  847.         return ERROR_NO_FREE_STORE;
  848.  
  849.     cwd = CurrentDir(srcdir);
  850.  
  851.     if ( !(dps = dopen(srcname,&stat))) {
  852.         errstr = strdup(srcname);    /* set up file name [GMD] */
  853.         ierr = IoErr();
  854.         goto done;
  855.     }
  856.     UnLock(dps->lock);
  857.     dps->lock = NULL;
  858.     src_pbits = dps->fib->fib_Protection ;
  859.     /*
  860.      * ensure src file can be read - if not, force it so (maybe)
  861.      */
  862.     if ( src_pbits & FIBF_READ) {            /* not readable */
  863.         if (!OPT(CP_OVERWRITE)) {
  864.             errstr    = strdup(srcname);
  865.             ierr    = ERROR_READ_PROTECTED ;
  866.             goto done;
  867.         }
  868.         if (!setProtection(srcname, 0)) {    /* ----rwed */
  869.             pError(srcname);
  870.             goto done;
  871.         }
  872.         reset=1;
  873.     }
  874.  
  875.     if ( (f_src=Open(srcname, MODE_OLDFILE)) == NULL) { 
  876.         errstr    = strdup(srcname);
  877.         ierr    = IoErr();
  878.         goto done;
  879.     }
  880.  
  881.     CurrentDir(destdir);
  882.  
  883.     /*
  884.      *    if dest does not exist, open it with 'rwed' protections
  885.      *    if dest does exist, get its protections.
  886.      *    if -o option , set its protections to enable a write
  887.      *        (and reset them to original status when copied)
  888.      *    if not -o , then error
  889.      */
  890.  
  891.     dest_mode    = MODE_NEWFILE;
  892.  
  893.     if( (dpd=dopen(destname, &stat)) != NULL) {
  894.         UnLock(dpd->lock);
  895.         dpd->lock  = NULL;
  896.  
  897.         if ( OPT(CP_OVERWRITE)) {
  898.             if (!setProtection(destname, 0)) {    /* ----rwed */
  899.                 pError(destname);
  900.                 goto done;
  901.             }
  902.         } else if( dpd->fib->fib_Protection & FIBF_WRITE ) { /* not writeable */
  903.             errstr = strdup(destname);
  904.             ierr   = ERROR_WRITE_PROTECTED;
  905.             goto done;
  906.         }
  907.     }
  908.  
  909.     /*
  910.      *  check if copying necessary (update, fresh)
  911.      */
  912.     if (OPT( CP_UPDATE | CP_FRESH )) {
  913.         if (!dpd && OPT(CP_FRESH)) {
  914.             if( !OPT(CP_QUIET)) {
  915.                 if (OPT(CP_OUTPUTFORMAT2)) {
  916.                     print_path(21);        /*GMD27Jun95 */
  917.                     printf("%s....not there\n", srcname);
  918.                 }
  919.                 else {
  920.                     printf("%*s%s....not there\n",level*6," ",srcname);
  921.                 }
  922.             }
  923.             goto done;
  924.         } else if ( dpd && dptrtosecs(dpd) >= dptrtosecs(dps) &&
  925.                      !stricmp(dps->fib->fib_FileName, dpd->fib->fib_FileName)) {
  926.             if (!OPT(CP_QUIET)) {
  927.                 if (OPT(CP_OUTPUTFORMAT2)) {
  928.                     print_path(22);        /*GMD27Jun95 */
  929.                     printf("%s....not newer\n", srcname);
  930.                 }
  931.                 else {
  932.                     printf("%*s%s....not newer\n",level*6," ",srcname);
  933.                 }
  934.             }
  935.             goto done;
  936.         }
  937.     }
  938.  
  939.     /*
  940.      *    now open dest file
  941.      */
  942.     if ( !(f_dest= Open(destname, dest_mode))) {
  943.         errstr   = strdup(destname);
  944.         ierr     = IoErr();
  945.         goto done;
  946.     }
  947.  
  948.     if (OPT(CP_OUTPUTFORMAT2)) {
  949.         print_path(23);        /*GMD27Jun95 */
  950.         printf("%s..", srcname);    /*GMD27Jun95 */
  951.     }
  952.     else {
  953.         printf("%*s%s..",level*6," ",srcname);
  954.     }
  955.  
  956.     fflush(stdout);
  957.  
  958.     /*
  959.      * now actually copy something :-)
  960.      */
  961.     while (j = Read(f_src, buf, COPYBUF)) {
  962.         if( dobreak() ) { 
  963.             ierr = 513;
  964.             break; 
  965.         }
  966.         if (Write(f_dest, buf, j) != j) { 
  967.             ierr = IoErr(); 
  968.             break; 
  969.         }
  970.     }
  971.     Close(f_src);
  972.     Close(f_dest);
  973.     f_src= f_dest= NULL;
  974.  
  975.     /*
  976.      *    replace original src protection bits - maybe
  977.      */
  978.     if ( reset ) {
  979.         CurrentDir( srcdir );
  980.         if (!setProtection(srcname, src_pbits )) {
  981.             pError(srcname);
  982.             goto done;
  983.         }
  984.         CurrentDir( destdir );
  985.     }
  986.  
  987.     if (!ierr) {
  988.         LONG tmp_pbits = src_pbits;
  989.         /*
  990.          *  now check archive bit options (GMD)
  991.          */
  992.         if (!OPT(CP_LEAVE_ARCHIVE)) {
  993.             tmp_pbits &= ~FIBF_ARCHIVE;    /* no -a option, so clear bit */
  994.         }
  995.  
  996.         setProtection(destname,tmp_pbits);
  997.  
  998.         if (!OPT(CP_NODATE)) 
  999.             SetFileDate( destname, &dps->fib->fib_Date );
  1000.  
  1001.         if (!OPT(CP_NOFLAGS)) {
  1002.             if( *dps->fib->fib_Comment )
  1003.                 SetComment( destname, dps->fib->fib_Comment );
  1004.         }
  1005.         if( OPT(CP_MOVE) ) {
  1006.             CurrentDir(srcdir);
  1007.             DeleteFile(srcname);
  1008.             printf("..moved\n");
  1009.         } else
  1010.             printf("..copied\n");
  1011.     } else {
  1012.         DeleteFile(destname);
  1013.     }
  1014.  
  1015. done:
  1016.  
  1017.     if ( f_src  )    Close(f_src);
  1018.     if ( f_dest )    Close(f_dest);
  1019.     if ( dps )       dclose(dps);
  1020.     if ( dpd )       dclose(dpd);
  1021.     if ( buf )       FreeMem(buf, COPYBUF);
  1022.     CurrentDir(cwd);
  1023.  
  1024.     return ierr;
  1025. }
  1026.  
  1027. /***************************************************************/
  1028. /*GMD27Jun95 stuff concerning dir copy */
  1029.  
  1030. #define DIR_PTRS_INC 32        /* increase dirname array by this amount  */
  1031.  
  1032. void push_dir_path(char *ptr)
  1033. {
  1034.     char *z_ptr;
  1035.     int nbytes;
  1036.     char **cur_dir_lst = dir_lst;
  1037.  
  1038.     /*
  1039.      * now create (or increase) an array to hold dirname ptrs
  1040.      */
  1041.     if (dir_lst == NULL) {
  1042.         dir_lst_sz = DIR_PTRS_INC;
  1043.         nbytes = dir_lst_sz * sizeof(char *);
  1044.  
  1045.         if ((dir_lst = (char **) malloc(nbytes)) == NULL) {
  1046.             return;
  1047.         }
  1048.     }
  1049.     else
  1050.         /* array exists */
  1051.     {
  1052.         /*
  1053.          * if array full, rebuild it bigger
  1054.          */
  1055.         if ((level % DIR_PTRS_INC) == 0) {
  1056.             dir_lst_sz = level + DIR_PTRS_INC;
  1057.             nbytes = dir_lst_sz * sizeof(char *);
  1058.  
  1059.             if ((dir_lst = (char **) malloc(nbytes)) == NULL) {
  1060.                 return;
  1061.             }
  1062.  
  1063.             memcpy(dir_lst, cur_dir_lst, nbytes);    /* copy old array to new */
  1064.  
  1065.             free(cur_dir_lst);    /* free old array */
  1066.         }
  1067.     }
  1068.  
  1069.     dir_lst[level] = NULL;
  1070.     /*
  1071.      * copy name to a malloc'd buffer
  1072.      */
  1073.  
  1074.     if ((z_ptr = (char *) malloc(strlen(ptr) + 1)) == NULL) {
  1075.         return;
  1076.     }
  1077.  
  1078.     strcpy(z_ptr, ptr);
  1079.  
  1080.     dir_lst[level] = z_ptr;
  1081. }
  1082.  
  1083. void pop_dir_path(int offs)
  1084. {
  1085.     free(dir_lst[offs]);
  1086.     dir_lst[offs] = NULL;
  1087. }
  1088.  
  1089.  
  1090. void print_path(int z)
  1091. {
  1092.     int j;
  1093.  
  1094.     if (dir_lst[0] == NULL)
  1095.         return;
  1096.  
  1097.     for (j = 0; j <= level; ++j) {
  1098.         char *ptr = dir_lst[j];
  1099.  
  1100.         printf("%s", ptr);
  1101.         if (j == 0) {
  1102.             if (ptr[strlen(ptr) - 1] == ':')
  1103.                 continue;
  1104.         }
  1105.         printf("/");
  1106.     }
  1107. }
  1108. /***************************************************************/
  1109.  
  1110. /* AMK: "touch" uses Dos.SetFileDate() now instead of internal file_date() */
  1111. int
  1112. do_touch( void )
  1113. {
  1114.     struct DateStamp ds;
  1115.     int i;
  1116.     BPTR lock;
  1117.     DateStamp(&ds);
  1118.     for (i=1; i<ac; i++) {
  1119.         if (SetFileDate(av[i],&ds))
  1120.             clear_archive_bit( av[i] );
  1121.         else {
  1122.             /* create file if it does not exist */
  1123.             if(lock=Open(av[i],MODE_READWRITE))
  1124.                 Close(lock);
  1125.             else
  1126.                 ierror(av[i],500);
  1127.         }
  1128.     }
  1129.     return 0;
  1130. }
  1131.  
  1132.  
  1133. int
  1134. do_addbuffers( void )
  1135. {
  1136.     long i,buffs,new;
  1137.  
  1138.     if (ac==2) {
  1139.         if (lastch(av[1])==':') {
  1140.             if (new=AddBuffers(av[1],0)) {
  1141.                 if (new==DOSTRUE)
  1142.                     new = IoErr();
  1143.                 printf("%s has %ld buffers\n",av[1],new);
  1144.             }
  1145.             else {
  1146.                 pError(av[1]);
  1147.             }
  1148.         }
  1149.         else
  1150.             printf("Invalid device or volume name '%s'\n",av[1]);
  1151.  
  1152.         return 0;
  1153.     }
  1154.  
  1155.     for( i=1; i<=ac-2; i+=2 ) {
  1156.         if( i==ac-1 ) {
  1157.             ierror( av[i], 500 );
  1158.             return 20;
  1159.         }
  1160.         buffs=myatoi(av[i+1],-32768,32767);
  1161.         if (atoierr)
  1162.             return 20;
  1163.         if (lastch(av[i])==':') {
  1164.             if (new=AddBuffers(av[i],buffs)) {
  1165.                 if (new==DOSTRUE)
  1166.                     new = IoErr();
  1167.                 printf("%s has %ld buffers\n",av[i],new);
  1168.             }
  1169.             else {
  1170.                 pError(av[i]);
  1171.             }
  1172.         }
  1173.         else
  1174.             printf("Invalid device or volume name '%s'\n",av[i]);
  1175.  
  1176.     }
  1177.     return 0;
  1178. }
  1179.  
  1180. int
  1181. do_relabel( void )
  1182. {
  1183.     /* AMK: using dos.Relabel() */
  1184.     if(!Relabel(av[1],av[2]))
  1185.         pError(av[2]);
  1186. #if 0
  1187.     Delay(10);
  1188.     changedisk(av[1]);
  1189. #endif
  1190.     return 0;
  1191. }
  1192.  
  1193. int
  1194. do_diskchange( void )
  1195. {
  1196.     int i;
  1197.     for (i=1; i<ac; i++)
  1198.         changedisk(av[i]);
  1199.     return 0;
  1200. }
  1201.  
  1202.  
  1203. #if 0
  1204. static void
  1205. changedisk(char *name)
  1206. {
  1207.     /*
  1208.      *  2 calls to Inhibit() will break some stupid handlers,
  1209.      *  so that DeviceProc()/GetDeviceProc() will fail on an
  1210.      *  inhibited device.  So we first call GetDeviceProc()
  1211.      *  2 times and send the packet ourself.  1 call to Get-
  1212.      *  DeviceProc() won't be enough because it's not guaranteed
  1213.      *  that the address is still valid after the first packet
  1214.      *  sent to it (eg, for "diskchange CON:").
  1215.      */
  1216.  
  1217.     struct MsgPort *task1=(struct MsgPort *)GetDeviceProc(name,NULL);
  1218.     struct MsgPort *task2=(struct MsgPort *)GetDeviceProc(name,NULL);
  1219.  
  1220.     printf("bla1 (%lu/%lu)\n",task1,task2);
  1221.     if (task1 && task2) {
  1222.         long rc;
  1223.         rc=DoPkt( task1, ACTION_INHIBIT, DOSTRUE,  NULL,NULL,NULL,NULL );
  1224.         printf("bla2 (%ld)\n",rc);
  1225.         Delay(10);
  1226.         rc=DoPkt( task2, ACTION_INHIBIT, DOSFALSE, NULL,NULL,NULL,NULL );
  1227.         printf("bla3 (%ld)\n",rc);
  1228.         Delay(10);
  1229.     }
  1230.  
  1231.     if (task1) FreeDeviceProc((struct DevProc *)task1);
  1232.     if (task2) FreeDeviceProc((struct DevProc *)task2);
  1233. }
  1234.  
  1235. #else
  1236.  
  1237. static void
  1238. changedisk(char *name)
  1239. {
  1240.     /* AMK: using dos.Inhibit() instead of DOS-Packets */
  1241.     Inhibit(name,DOSTRUE);
  1242.     Inhibit(name,DOSFALSE);
  1243. }
  1244. #endif
  1245.  
  1246.  
  1247. #if 0
  1248. /* old changedisk */
  1249. static void changedisk(struct MsgPort *task)
  1250. {
  1251.     DoPkt( task, ACTION_INHIBIT, DOSTRUE,  NULL,NULL,NULL,NULL );
  1252.     DoPkt( task, ACTION_INHIBIT, DOSFALSE, NULL,NULL,NULL,NULL );
  1253. }
  1254. #endif
  1255.  
  1256.  
  1257. extern int atoierr;
  1258.  
  1259. static int
  1260. func_array( char *fav[], int fac)
  1261. {
  1262.     char *ret;
  1263.     if( atoierr ) return 20;
  1264.     if( fac ) {
  1265.         ret=compile_av( fav, 0, fac, 0xa0, 0);
  1266.         set_var( LEVEL_SET, v_value, ret );
  1267.         free( ret );
  1268.     } else
  1269.         unset_var( LEVEL_SET, v_value );
  1270.     return 0;
  1271. }
  1272.  
  1273. static int
  1274. func_int( int i )
  1275. {
  1276.     char buf[12];
  1277.     if( atoierr ) return 20;
  1278.     sprintf(buf,"%d",i);
  1279.     set_var( LEVEL_SET, v_value, buf );
  1280.     return 0;
  1281. }
  1282.  
  1283. /*
  1284.  * called on error to create a NULL stringed VAR
  1285.  *
  1286.  */
  1287. static int
  1288. func_err () /*GMD 13FEB94*/
  1289. {
  1290.   set_var (LEVEL_SET, v_value, "");
  1291.   return 0;
  1292. }
  1293.  
  1294. static int
  1295. func_bool( int i )
  1296. {
  1297.     if( atoierr ) return 20;
  1298.     set_var( LEVEL_SET, v_value, i ? "1" : "0" );
  1299.     return 0;
  1300. }
  1301.  
  1302. static int
  1303. func_string( char *str )
  1304. {
  1305.     if( atoierr ) return 20;
  1306.     set_var( LEVEL_SET, v_value, str ? str : "" );
  1307.     return 0;
  1308. }
  1309.  
  1310. static int
  1311. commas( char *av[], int ac, int n )
  1312. {
  1313.     int i=0;
  1314.  
  1315.     while( --ac>=0 )
  1316.         if( !strcmp( *av++, ",") )
  1317.             i++;
  1318.     if( i-=n )
  1319.         fprintf( stderr, "Need %d comma%s\n", n, (n==1) ? "" : "s" );
  1320.     return i;
  1321. }
  1322.  
  1323. static int
  1324. wordset( char *av[], int ac, char **(*func)(char **,int,char**,int,int*,int) )
  1325. {
  1326.     char **av1=av, **av2;
  1327.     int  ac1=0, ac2, ret;
  1328.  
  1329.     if( commas( av, ac, 1 ) ) return 20;
  1330.     while( strcmp( *av++, ",") ) ac1++;
  1331.     av2=av, ac2=ac-ac1-1;
  1332.     av=(*func)( av1, ac1, av2, ac2, &ac, 0 );
  1333.     ret=func_array( av, ac );
  1334.     free( av );
  1335.     return ret;
  1336. }
  1337.  
  1338. static int
  1339. split_arg( char **av, int ac )
  1340. {
  1341.     char **arr, **old, *arg;
  1342.     int i, j=1, ret;
  1343.  
  1344.     for( i=strlen(av[0])-1; i>=0; i-- )
  1345.         if( av[0][i]==' ' )
  1346.             av[0][i]=0, j++;
  1347.  
  1348.     arr=old=(char **)salloc( j*sizeof( char * ) );
  1349.     arg = *av;
  1350.     for( ; j>0; j-- ) {
  1351.         *arr++=arg;
  1352.         arg+=strlen(arg)+1;
  1353.     }
  1354.     ret=func_array( old, arr-old );
  1355.     free(old);
  1356.     return ret;
  1357. }
  1358.  
  1359. static char *
  1360. info_part( char **av, int ac, int n, char *buf )
  1361. {
  1362.     char *str;
  1363.     DPTR *dp;
  1364.     int  len=0, i, t;
  1365.  
  1366.     buf[0]=0;
  1367.     while( --ac>=0 ) {
  1368.         if( dp=dopen( *av++, &t) ) {
  1369.             if( n==0 ) {
  1370.                 for (str=buf, i=7; i>=0; i--)
  1371.                     *str++= (dp->fib->fib_Protection & (1L<<i) ?
  1372.                             "hspa----" : "----rwed")[7-i];
  1373.                 *str=0;
  1374.             } else
  1375.                 len+= dp->fib->fib_NumBlocks+1;
  1376.             dclose( dp );
  1377.         }
  1378.     }
  1379.     if( n ) sprintf(buf, "%d", len);
  1380.     return buf;
  1381. }
  1382.  
  1383.  
  1384. /* AMK: now with asl filerequester */
  1385. static char *
  1386. file_request(char **av, int ac, char *path)
  1387. {
  1388.     struct FileRequester *frq;
  1389.     struct TagItem frq_tags[4];
  1390.     int tag = 0;
  1391.     BOOL ret = FALSE;
  1392.  
  1393.     if (ac>0) {
  1394.       frq_tags[tag].ti_Tag  = ASL_Hail;
  1395.       frq_tags[tag].ti_Data = (ULONG)av[0];
  1396.       tag++;
  1397.       if (ac>1) {
  1398.         frq_tags[tag].ti_Tag  = ASL_Dir;
  1399.         frq_tags[tag].ti_Data = (ULONG)av[1];
  1400.         tag++;
  1401.         if (ac>2) {
  1402.           frq_tags[tag].ti_Tag  = ASL_File;
  1403.           frq_tags[tag].ti_Data = (ULONG)av[2];
  1404.           tag++;
  1405.         }
  1406.       }
  1407.     }
  1408.     frq_tags[tag].ti_Tag  = TAG_DONE;
  1409.  
  1410.     if (frq = AllocAslRequest(ASL_FileRequest,frq_tags)) {
  1411.       if (ret=AslRequest(frq,NULL)) {
  1412.         strcpy(path,frq->rf_Dir);
  1413.         AddPart(path,frq->rf_File,200L);
  1414.         /* AMK: length from dofunc().buf */
  1415.       }
  1416.       FreeAslRequest(frq);
  1417.     }
  1418.  
  1419.     if (ret) return(path);
  1420.  
  1421.     return(NULL);
  1422. }
  1423.  
  1424.  
  1425.  
  1426. /* NOTE (if you change something): ask() and confirm() are very similar */
  1427. int confirm( char *title, char *file )
  1428. {
  1429.     char buf[80];
  1430.     char *p;
  1431.  
  1432.     buf[0]=0;
  1433.  
  1434.     if( !confirmed ) {
  1435.         fprintf(stderr,"%s %s%-16s%s [YES/no/all/done] ? ",
  1436.                         title,o_hilite,file,o_lolite);
  1437.         fflush(stderr);
  1438.         if (p=fgets(buf,80,stdin))
  1439.             strupr(p);
  1440.         if (*buf=='A')
  1441.             confirmed=1;
  1442.         if (*buf=='D' || breakcheck())
  1443.             confirmed=2;
  1444.     }
  1445.  
  1446.     if( confirmed==2 )
  1447.         return 0;
  1448.     return confirmed || *buf != 'N';
  1449. }
  1450.  
  1451. /* NOTE (if you change something): ask() and confirm() are very similar */
  1452. int ask(char *title, char *file)
  1453. {
  1454.     char buf[80];
  1455.     char *p;
  1456.  
  1457.     buf[0]=0;
  1458.  
  1459.     if (!asked) {
  1460.         fprintf(stderr,"%s %s%-16s%s [yes/NO/all/quit] ? ",
  1461.                         title,o_hilite,file,o_lolite);
  1462.         fflush(stderr);
  1463.         if (p=fgets(buf,80,stdin))
  1464.             strupr(p);
  1465.         if (*buf=='A')
  1466.             asked=1;
  1467.         if (*buf=='Q' || breakcheck())
  1468.             asked=2;
  1469.     }
  1470.  
  1471.     if (asked==2)
  1472.         return 0;
  1473.     return asked || *buf == 'Y';
  1474. }
  1475.  
  1476.  
  1477.  
  1478. enum funcid {
  1479.     FN_STUB=1, FN_MEMBER, FN_DIRS, FN_NAMEEXT, FN_NAMEROOT, FN_FILES,
  1480.     FN_FILELEN, FN_SORTARGS, FN_UPPER, FN_WORDS, FN_ABBREV, FN_ABS,
  1481.     FN_BINTODEC, FN_CENTER, FN_COMPARE, FN_DECTOHEX, FN_DELWORD,
  1482.     FN_DELWORDS, FN_EXISTS, FN_INDEX, FN_STRCMP, FN_SUBWORDS,
  1483.     FN_WORD, FN_MIN, FN_MAX, FN_DRIVES, FN_WITHOUT, FN_UNION, FN_INTERSECT,
  1484.     FN_AVAILMEM, FN_UNIQUE, FN_RPN, FN_CONCAT, FN_SPLIT, FN_DRIVE,
  1485.     FN_FILEPROT, FN_FILEBLKS, FN_LOWER, FN_HOWMANY, FN_COMPLETE, FN_FIRST,
  1486.     FN_LAST, FN_MATCH, FN_CLINUM, FN_FREEBYTES, FN_FREEBLKS, FN_INFO,
  1487.     FN_MEGS, FN_FREESTORE, FN_CHECKPORT, FN_PICKOPTS, FN_PICKARGS,
  1488.     FN_FILEREQ, FN_VOLUME, FN_LOOKFOR, FN_APPSUFF, FN_DIRNAME, FN_AGE,
  1489.     FN_AGE_MINS,            /*GMD 13FEB94 */
  1490.     FN_GETCLASS, FN_CONFIRM, FN_WINWIDTH, FN_WINHEIGHT, FN_WINTOP,
  1491.     FN_WINLEFT, FN_CONSOLE, FN_SORTNUM, FN_IOERROR, FN_TRIM, FN_MOUNTED,
  1492.     FN_RND, FN_DIRSTR, FN_MIX, FN_WINROWS, FN_WINCOLS, FN_SUBFILE,
  1493.     FN_SCRHEIGHT, FN_SCRWIDTH, FN_FLINES, FN_STRICMP, FN_ASK,
  1494.     FN_HEXTODEC, FN_FILEINFO, FN_FILESIZE, FN_FILEDATE, FN_FILENOTE
  1495. };
  1496.  
  1497. #define MAXAV        30000        /* Max. # of arguments            */
  1498.  
  1499. struct FUNCTION {
  1500.     short id, minargs, maxargs;
  1501.     char *name;
  1502. } Function[]={
  1503. FN_ABBREV,   2, 3,     "abbrev",
  1504. FN_ABS,      1, 1,     "abs",
  1505. FN_AGE,      1, 1,     "age",
  1506. FN_AGE_MINS, 1, 1,     "age_mins",    /*GMD 13FEB94 */
  1507. FN_APPSUFF,  2, 2,     "appsuff",
  1508. FN_PICKARGS, 0, MAXAV, "arg",
  1509. FN_ASK,      1, MAXAV, "ask",
  1510. FN_AVAILMEM, 0, 1,     "availmem",
  1511. FN_STUB,     1, 1,     "basename",
  1512. FN_CENTER,   2, 2,     "center",
  1513. FN_CHECKPORT,1, 1,     "checkport",
  1514. FN_CLINUM,   1, 1,     "clinum",
  1515. FN_COMPLETE, 1, MAXAV, "complete",
  1516. FN_CONCAT,   0, MAXAV, "concat",
  1517. FN_CONFIRM,  1, MAXAV, "confirm",
  1518. FN_CONSOLE,  1, 1,     "console",
  1519. FN_DECTOHEX, 1, 1,     "dectohex",
  1520. FN_DELWORD,  1, MAXAV, "delword",
  1521. FN_DELWORDS, 2, MAXAV, "delwords",
  1522. FN_DIRNAME,  1, 1,     "dirname",
  1523. FN_DIRS,     0, MAXAV, "dirs",
  1524. FN_DIRSTR,   2, 2,     "dirstr",
  1525. FN_DRIVE,    1, 1,     "drive",
  1526. FN_DRIVES,   0, 0,     "drives",
  1527. FN_EXISTS,   1, 1,     "exists",
  1528. FN_FILEBLKS, 1, MAXAV, "fileblks",
  1529. FN_FILEDATE, 1, 1,     "filedate",    /* GMD */
  1530. FN_FILEINFO, 2, 2,     "fileinfo",    /* GMD , alias for FN_DIRSTR */
  1531. FN_FILELEN,  0, MAXAV, "filelen",
  1532. FN_FILENOTE, 1, 1,     "filenote",    /* GMD */
  1533. FN_FILEPROT, 1, 1,     "fileprot",
  1534. FN_FILEREQ,  0, 3,     "filereq",
  1535. FN_FILES,    0, MAXAV, "files",
  1536. FN_FILESIZE, 1, 1,     "filesize",    /* GMD , alias for FN_FILELEN */
  1537. FN_FIRST,    0, MAXAV, "first",
  1538. FN_FLINES,   1, 1,     "flines",
  1539. FN_FREEBLKS, 1, 1,     "freeblks",
  1540. FN_FREEBYTES,1, 1,     "freebytes",
  1541. FN_FREESTORE,1, 1,     "freestore",
  1542. FN_STUB,     1, 1,     "getenv",
  1543. FN_GETCLASS, 1, 1,     "getclass",
  1544. FN_HEXTODEC, 1, 1,     "hextodec",    /* GMD */
  1545. FN_HOWMANY,  0, 0,     "howmany",
  1546. FN_IOERROR,  1, 1,     "ioerr",
  1547. FN_INDEX,    2, 2,     "index",
  1548. FN_INFO,     1, 1,     "info",
  1549. FN_INTERSECT,1, MAXAV, "intersect",
  1550. FN_LAST,     0, MAXAV, "last",
  1551. FN_LOOKFOR,  2, 2,     "lookfor",
  1552. FN_LOWER,    0, MAXAV, "lower",
  1553. FN_MATCH,    1, MAXAV, "match",
  1554. FN_MAX,      1, MAXAV, "max",
  1555. FN_MEGS,     1, 1,     "megs",
  1556. FN_MEMBER,   1, MAXAV, "member",
  1557. FN_MIN,      1, MAXAV, "min",
  1558. FN_MIX,      0, MAXAV, "mix",
  1559. FN_MOUNTED,  1, 1,     "mounted",
  1560. FN_NAMEEXT,  1, 1,     "nameext",
  1561. FN_NAMEROOT, 1, 1,     "nameroot",
  1562. FN_PICKOPTS, 0, MAXAV, "opt",
  1563. FN_DIRNAME,  1, 1,     "pathname",
  1564. FN_PICKARGS, 0, MAXAV, "pickargs",
  1565. FN_PICKOPTS, 0, MAXAV, "pickopts",
  1566. FN_RND,      0, 1,     "rnd",
  1567. FN_RPN,      1, MAXAV, "rpn",
  1568. FN_SCRHEIGHT,0, 0,     "scrheight",
  1569. FN_SCRWIDTH, 0, 0,     "scrwidth",
  1570. FN_SORTARGS, 0, MAXAV, "sortargs",
  1571. FN_SORTNUM,  0, MAXAV, "sortnum",
  1572. FN_SPLIT,    0, MAXAV, "split",
  1573. FN_STRCMP,   2, 2,     "strcmp",
  1574. FN_STRICMP,  2, 2,     "stricmp",
  1575. FN_STUB,     2, 2,     "strhead",
  1576. FN_STUB,     2, 2,     "strleft",
  1577. FN_STUB,     2, 3,     "strmid",
  1578. FN_STUB,     2, 2,     "strright",
  1579. FN_STUB,     2, 2,     "strtail",
  1580. FN_SUBFILE,  3, 3,     "subfile",
  1581. FN_SUBWORDS, 2, MAXAV, "subwords",
  1582. FN_STUB,     2, 2,     "tackon",
  1583. FN_TRIM,     0, MAXAV, "trim",
  1584. FN_UNION,    1, MAXAV, "union",
  1585. FN_UNIQUE,   0, MAXAV, "unique",
  1586. FN_UPPER,    0, MAXAV, "upper",
  1587. FN_VOLUME,   1, 1,     "volume",
  1588. FN_WINCOLS,  0, 0,     "wincols",
  1589. FN_WINHEIGHT,0, 0,     "winheight",
  1590. FN_WINLEFT,  0, 0,     "winleft",
  1591. FN_WINROWS,  0, 0,     "winrows",
  1592. FN_WINTOP,   0, 0,     "wintop",
  1593. FN_WINWIDTH, 0, 0,     "winwidth",
  1594. FN_WITHOUT,  1, MAXAV, "without",
  1595. FN_WORD,     1, MAXAV, "word",
  1596. FN_WORDS,    0, MAXAV, "words",
  1597. 0,           0, 0,     NULL
  1598. };
  1599.  
  1600. extern char shellctr[];
  1601. extern int  w_width, w_height;
  1602.  
  1603. int
  1604. dofunc( int id, char **av, int ac)
  1605. {
  1606.     char **oldav=av, **get=av, buf[200], *str=buf, *t;
  1607.     int oldac=ac, i=0, j=0, n=0, n2=1, l;
  1608.     buf[0]=0;
  1609.     av[ac]=NULL;
  1610.     atoierr=0;
  1611.  
  1612.     switch( id ) {
  1613.     case FN_ABBREV:
  1614.         if( ac==3 ) i=posatoi(av[2] ); else i=strlen(av[0]);
  1615.         return func_bool( !strnicmp( av[0], av[1], i ));
  1616.     case FN_ABS:
  1617.         i=unlatoi(av[0]);
  1618.         return func_int( i>= 0 ? i : -i );
  1619.     case FN_AGE: {
  1620.         struct DateStamp ds;
  1621.         long time;
  1622.  
  1623.         DateStamp(&ds);
  1624.         if( ds.ds_Days==0 )
  1625.             return func_err(); /* GMD 13FEB94, previously: return func_int(99999); */
  1626.         if( !(time = timeof(av[0])))
  1627.             return func_err(); /* GMD 13FEB94, previously: return func_int(99999); */
  1628.         return func_int( (ds.ds_Days*86400+ds.ds_Minute*60-time)/86400 );
  1629.         }
  1630.     case FN_AGE_MINS: {        /* GMD 13FEB94 */
  1631.         struct DateStamp ds;
  1632.         long time;
  1633.         long secs;
  1634.  
  1635.         DateStamp(&ds);
  1636.         secs = ds.ds_Days * 24 * 60 * 60;
  1637.         secs += ds.ds_Minute * 60;
  1638.  
  1639.         if (!(time = timeof(av[0])))
  1640.             return func_err();
  1641.  
  1642.         return func_int((secs - time) / 60);
  1643.         }
  1644.     case FN_APPSUFF:
  1645.         strcpy(buf,av[0]);
  1646.         l=strlen(av[0])-strlen(av[1]);
  1647.         if( l<0 || stricmp(av[0]+l,av[1])) {
  1648.             strcat(buf,".");
  1649.             strcat(buf,av[1]);
  1650.         }
  1651.         return func_string( buf );
  1652.     case FN_ASK:
  1653.         for (i=1, get++, asked=0; i<ac; i++)
  1654.             if (ask(av[0],av[i]))
  1655.                 *get++=av[i];
  1656.         return func_array(av+1, (get-av)-1);
  1657.     case FN_AVAILMEM:
  1658.         if( ac==1 && !stricmp(av[0],"chip")) n=MEMF_CHIP;
  1659.         if( ac==1 && !stricmp(av[0],"fast")) n=MEMF_FAST;
  1660.         return func_int( AvailMem( n ));
  1661.     case FN_CENTER:
  1662.         if( (n=posatoi( av[1] )) > (l=strlen(av[0])) ) i=(n-l)/2, j=n-i-l;
  1663.         sprintf( buf, "%*s%s%*s", i,"",av[0], j,"" );
  1664.         return func_string( buf );
  1665.     case FN_CHECKPORT:
  1666.         return func_bool( (int)FindPort( av[0] ) );
  1667.     case FN_GETCLASS:
  1668.         if( str=getclass(av[0]) )
  1669.             if( str=index(strncpy( buf,str,100 ),0xA0) )
  1670.                 *str=0;
  1671.         return func_string(buf);
  1672.     case FN_COMPLETE:
  1673.         for( i=1, l=strlen(av[0]); i<ac; i++ )
  1674.             if( !strnicmp( av[0], av[i], l ) )
  1675.                 { str=av[i]; break; }
  1676.         return func_string( str );
  1677.     case FN_CONCAT:
  1678.         return func_string( compile_av( av, 0, ac, ' ', 1));
  1679.     case FN_CONFIRM:
  1680.         for( i=1, get++, confirmed=0; i<ac; i++ )
  1681.             if( confirm( av[0], av[i]) )
  1682.                 *get++=av[i];
  1683.         return func_array( av+1, (get-av)-1 );
  1684.     case FN_CONSOLE:
  1685.         if( !strcmp(av[0],"STDIN")) i=IsInteractive(Input());
  1686.         else if( !strcmp(av[0],"STDOUT")) i=IsInteractive(Output());
  1687.         return func_bool(i);
  1688.     case FN_DECTOHEX:
  1689.         sprintf( buf, "%x", unlatoi( av[0] ));
  1690.         return func_string( buf );
  1691.     case FN_DELWORDS:
  1692.         n2=posatoi( av[--ac] ); if( atoierr ) return 20;
  1693.     case FN_DELWORD:
  1694.         n=posatoi( av[--ac] )-1;
  1695.         for( ; i<ac && i<n; i++ ) *av++ = *get++;
  1696.         for( ; i<ac && i<n+n2; i++ ) get++;
  1697.         for( ; i<ac ; i++ ) *av++ = *get++;
  1698.         return func_array( oldav, av-oldav );
  1699.     case FN_DIRNAME:
  1700.         str=av[0]+strlen(av[0])-1;
  1701.         while( str>av[0] && *str!=':' && *str!='/' ) str--;
  1702.         if( *str==':' ) str++;
  1703.         *str=0;
  1704.         return func_string(av[0]);
  1705.     case FN_DIRS:
  1706.         for( ; --ac>=0; get++ )
  1707.             if( exists( *get ) && isdir( *get ) )
  1708.                 *av++ = *get;
  1709.         return func_array( oldav, av-oldav );
  1710.     case FN_FILEINFO:
  1711.     case FN_DIRSTR:
  1712.         if( av=expand(oldav[1],&n2)) {
  1713.             lformat(oldav[0], buf, (FILEINFO *)av[0]-1);
  1714.             free_expand(av);
  1715.         }
  1716.         if( str=index(buf,'\n' )) *str=0;
  1717.         return func_string( buf );
  1718.     case FN_DRIVE:
  1719.         return func_string( drive_name( av[0] ) );
  1720.     case FN_DRIVES:
  1721.         get_drives( buf );
  1722.         return func_string( buf );
  1723.     case FN_EXISTS:
  1724.         return func_bool( exists( av[0] ));
  1725.     case FN_FILEBLKS:
  1726.         return func_string( info_part( av, ac, 1, buf ) );
  1727.     case FN_FILESIZE:
  1728.     case FN_FILELEN:
  1729.         while( --ac>=0 )
  1730.             i+=filesize( *av++ );
  1731.         return func_int( i );
  1732.     case FN_FLINES:
  1733.         if( str=get_var(LEVEL_SET, av[0]))
  1734.             for( n=1; str=index(str,0xA0); str++, n++ ) ;
  1735.         return func_int( n );
  1736.     case FN_FILEPROT:
  1737.         return func_string( info_part( av, ac, 0, buf ) );
  1738.     case FN_FILEREQ:
  1739.         return func_string( file_request( av, ac, buf ) );
  1740.     case FN_FILES:
  1741.         for( ; --ac>=0; get++ )
  1742.             if( exists( *get ) && !isdir( *get ) )
  1743.                 *av++ = *get;
  1744.         return func_array( oldav, av-oldav );
  1745.     case FN_FILEDATE:
  1746.         return func_string(get_filedate(av[0]));
  1747.     case FN_FILENOTE:
  1748.         return func_string(get_filenote(av[0]));
  1749.     case FN_FIRST:
  1750.         return func_string(av[0]);
  1751.     case FN_FREEBLKS:
  1752.         return func_string(oneinfo(av[0],3));
  1753.     case FN_FREEBYTES:
  1754.         return func_string(oneinfo(av[0],2));
  1755.     case FN_FREESTORE:
  1756.         return func_string(oneinfo(av[0],4));
  1757.     case FN_HEXTODEC:
  1758.         {
  1759.         long num = 0;
  1760.         stch_l((av[0]),&num);
  1761.         sprintf(buf,"%ld",num);
  1762.         return func_string(buf);
  1763.         }
  1764.     case FN_HOWMANY:
  1765.         /* AMK: OS20-GetVar replaces ARP Getenv */
  1766.         GetVar(shellctr,buf,10,GVF_GLOBAL_ONLY|GVF_BINARY_VAR);
  1767.         return func_string( buf );
  1768.     case FN_IOERROR:
  1769.         return func_string( ioerror( atoi( av[0] )));
  1770.     case FN_INDEX:
  1771.         str=strstr( av[0], av[1] );
  1772.         return func_int( str ? (str-av[0])+1 : 0 );
  1773.     case FN_INFO:
  1774.         return func_string( oneinfo( av[0], 1 ));
  1775.     case FN_INTERSECT:
  1776.         return wordset( av, ac, and );
  1777.     case FN_LAST:
  1778.         return func_string( ac ? av[ac-1] : "" );
  1779.     case FN_LOOKFOR:
  1780.         return func_string( dofind( av[0], "", buf, av[1]));
  1781.     case FN_LOWER:
  1782.         while( --ac>=0 ) strlwr( *av++ );
  1783.         return func_array( oldav, av-oldav );
  1784.     case FN_MATCH:
  1785.         { PATTERN *pat=compare_preparse( av[--ac], 0 );
  1786.         for( ; --ac>=0; get++ )
  1787.             if( compare_ok( pat, *get ) )
  1788.                 *av++ = *get;
  1789.         compare_free(pat);
  1790.         return func_array( oldav, av-oldav );
  1791.         }
  1792.     case FN_MAX:
  1793.         for( n=MININT; i<ac; i++ ) 
  1794.             { if( (j=unlatoi(av[i] )) > n ) n=j; if( atoierr ) return 20; }
  1795.         return func_int( n );
  1796.     case FN_MEGS:
  1797.         return func_string( itok( atoi( av[0] )));
  1798.     case FN_MEMBER:
  1799.         for( i=1; i<ac && stricmp(av[0],av[i]) ; i++ ) ;
  1800.         return func_bool( ac!=i );
  1801.     case FN_MIN:
  1802.         for( n=MAXINT; i<ac; i++ )
  1803.             { if( (j=unlatoi(av[i] )) < n ) n=j; if( atoierr ) return 20; }
  1804.         return func_int( n );
  1805.     case FN_MIX:
  1806.         for( ; i<ac; i++ )
  1807.             j=rand()%ac, str=av[j], av[j]=av[i], av[i]=str;
  1808.         return func_array(av,ac);
  1809.     case FN_MOUNTED:
  1810.         return func_bool((int)mounted(av[0]));
  1811.     case FN_NAMEEXT:
  1812.         return func_string( rindex(av[0],'.')?rindex(av[0],'.')+1:(char *)NULL);
  1813.     case FN_NAMEROOT:
  1814.         if( rindex(av[0],'.') ) *rindex(av[0],'.')=0;
  1815.         return func_string( av[0] );
  1816.     case FN_PICKARGS:
  1817.         while( *get && **get=='-' ) get++;
  1818.         while( *get )  *av++ = *get++ ;
  1819.         return func_array( oldav, av-oldav );
  1820.     case FN_PICKOPTS:
  1821.         while( *get && **get=='-' ) *av++ = *get++;
  1822.         return func_array( oldav, av-oldav );
  1823.     case FN_CLINUM:
  1824.         return func_int( clinum( av[0] ) );
  1825.     case FN_RND:
  1826.         if (ac>0) {
  1827.             if (atoi(av[0]) == 0)
  1828.                 srand(time(NULL));
  1829.             else
  1830.                 srand(atoi(av[0]));
  1831.         }
  1832.         return func_int( rand() );
  1833. #if 0
  1834.     case FN_RNDSEED: {
  1835.         struct DateStamp ds;
  1836.         DateStamp(&ds);
  1837.         if (ac>0) srand(atoi(av[0]));
  1838.         return func_int( rand() );
  1839.         }
  1840. #endif
  1841.     case FN_RPN:
  1842.         return func_int( eval_rpn( av, ac, 1 ));
  1843.     case FN_SCRHEIGHT:
  1844.         return func_int( Mywindow ? Mywindow->WScreen->Height: 0 );
  1845.     case FN_SCRWIDTH:
  1846.         return func_int( Mywindow ? Mywindow->WScreen->Width : 0 );
  1847.     case FN_SORTARGS:
  1848.         QuickSort( av, ac );
  1849.         return func_array( av, ac );
  1850.     case FN_SORTNUM:
  1851.         DirQuickSort( av, ac, numcmp, 0, 0 );
  1852.         return func_array( av, ac );
  1853.     case FN_SPLIT:
  1854.         return split_arg( av, ac );
  1855.     case FN_STRCMP:
  1856.         return func_int( strcmp( av[0], av[1] ) );
  1857.     case FN_STRICMP:
  1858.         return func_int( stricmp( av[0], av[1] ) );
  1859.     case FN_TRIM:
  1860.         for( ; *av; av++ ) {
  1861.             for( ; **av==' '; (*av)++ ) ;
  1862.             for( str = *av+strlen(*av); str>*av && str[-1]==' '; *--str=0 ) ;
  1863.         }
  1864.         return func_array( oldav, av-oldav );
  1865.     case FN_UNION:
  1866.         return wordset( av, ac, or );
  1867.     case FN_UNIQUE:
  1868.         QuickSort( av, ac );
  1869.         while( *get )
  1870.             { *av++ = *get++; while( *get && !stricmp(*get,*(get-1)))
  1871.                 get++; }
  1872.         return func_array( oldav, av-oldav );
  1873.     case FN_UPPER:
  1874.         while( --ac>=0 ) strupr( *av++ );
  1875.         return func_array( oldav, oldac );
  1876.     case FN_VOLUME:
  1877.         return func_string( oneinfo( av[0], 5 ));
  1878.     case FN_WINCOLS:
  1879.         newwidth(); /**/
  1880.         return func_int(w_width);
  1881.     case FN_WINTOP:
  1882.         return func_int( Mywindow ? Mywindow->TopEdge : 0 );
  1883.     case FN_WINLEFT:
  1884.         return func_int( Mywindow ? Mywindow->LeftEdge: 0 );
  1885.     case FN_WINHEIGHT:
  1886.         return func_int( Mywindow ? Mywindow->Height : 0 );
  1887.     case FN_WINROWS:
  1888.         newwidth(); /**/
  1889.         return func_int(w_height);
  1890.     case FN_WINWIDTH:
  1891.         return func_int( Mywindow ? Mywindow->Width  : 0 );
  1892.     case FN_WORD:
  1893.         n2=1; goto wordf;
  1894.     case FN_SUBFILE:
  1895.         n2= posatoi( av[2] ); if( atoierr ) return 20;
  1896.         n = posatoi( av[1] ); if( atoierr ) return 20;
  1897.         if( !(str=get_var( LEVEL_SET, av[0] ))) return 20;
  1898.         for( i=1; i<n; i++ )
  1899.             str= (str=index(str,0xA0)) ? str+1 : "";
  1900.         for( t=str, i=0; i<n2; i++ )
  1901.             if(t=index(t+1,0xA0));
  1902.         if( t ) *t=0;
  1903.         set_var( LEVEL_SET, v_value, str );
  1904.         if( t ) *t=0xA0;
  1905.         return 0;
  1906.     case FN_SUBWORDS:
  1907.         n2=posatoi( av[--ac] ); if( atoierr ) return 20;
  1908.     wordf:
  1909.         n=posatoi( av[--ac] )-1; if( atoierr ) return 20;
  1910.         for( i=0; i<ac && i<n; i++ ) get++;
  1911.         for(    ; i<ac && i<n+n2; i++ ) *av++ = *get++;;
  1912.         return func_array( oldav, av-oldav );
  1913.     case FN_WITHOUT:
  1914.         return wordset( av, ac, without );
  1915.     case FN_WORDS:
  1916.         return func_int( ac );
  1917.     }
  1918.     return func_string( "" );
  1919. }
  1920.  
  1921.  
  1922.  
  1923. static char *get_filenote(char *file)    /* new function by GMD */
  1924. {
  1925.     static char buf[80];
  1926.     DPTR *dp;
  1927.     int stat;
  1928.  
  1929.     buf[0] = '\0';
  1930.     if (dp = dopen(file, &stat)) {
  1931.         strcpy(buf, dp->fib->fib_Comment);
  1932.         dclose(dp);
  1933.     }
  1934.     return buf;
  1935. }
  1936.  
  1937. static char *get_filedate(char *file)    /* new function by GMD */
  1938. {
  1939.     static char buf[80];
  1940.     DPTR *dp;
  1941.     int stat;
  1942.     char *ptr;
  1943.  
  1944.     buf[0] = '\0';
  1945.     if (dp = dopen(file,&stat)) {
  1946.         ptr = dates(&dp->fib->fib_Date,0);
  1947.         strcpy(buf,ptr);
  1948.         dclose(dp);
  1949.     }
  1950.     return buf;
  1951. }
  1952.  
  1953.