home *** CD-ROM | disk | FTP | other *** search
/ Amiga GigaPD 3 / Amiga_GigaPD_v3_3of3.iso / fred_fish / fish_601-700_lha / fish_624.lha / CSH / csh519s.lha / sub.c < prev    next >
C/C++ Source or Header  |  1992-02-24  |  23KB  |  1,233 lines

  1.  
  2. /*
  3.  * SUB.C
  4.  *
  5.  * (c)1986 Matthew Dillon     9 October 1986
  6.  *
  7.  * Version 2.07M by Steve Drew 10-Sep-87
  8.  * Version 4.01A by Carlo Borreo & Cesare Dieni 17-Feb-90
  9.  * Version 5.00L by Urban Mueller 17-Feb-91
  10.  *
  11.  */
  12.  
  13. #include "shell.h"
  14.  
  15. static void del_history( void );
  16. static int dnext( DPTR *dp, char **pname, int *stat);
  17. static char *svfile( char *s1, char *s2, FIB *fib);
  18. static void quicksort( char **av, int n );
  19.  
  20. void
  21. seterr( int err )
  22. {
  23.     static int LastErr;
  24.     char buf[32], *val;
  25.     int  stat=0;
  26.  
  27.     Lastresult=err;
  28.  
  29.     if( LastErr!=err ) {
  30.         LastErr=err;
  31.         sprintf(buf, "%d", err);
  32.         set_var(LEVEL_SET, v_lasterr, buf);
  33.  
  34.         if( val=get_var(LEVEL_SET, v_stat))
  35.             stat = atoi(val);
  36.         if (stat < Lastresult) set_var(LEVEL_SET, v_stat, buf);
  37.     }
  38. }
  39.  
  40. char *
  41. next_word( char *str )
  42. {
  43.     while (*str && ! ISSPACE(*str)) ++str;
  44.     while (*str &&   ISSPACE(*str)) ++str;
  45.     return str;
  46. }
  47.  
  48. /*
  49.  * FREE(ptr)   --frees without actually freeing, so the data is still good
  50.  *               immediately after the free.
  51.  */
  52.  
  53.  
  54. void
  55. Free( void *ptr )
  56. {
  57.     static char *old_ptr;
  58.  
  59.     if (old_ptr) free (old_ptr);
  60.     old_ptr = ptr;
  61. }
  62.  
  63. /*
  64.  * Add new string to history (H_head, H_tail, H_len,
  65.  *  S_histlen
  66.  */
  67.  
  68. void
  69. add_history( char *str )
  70. {
  71.     HIST *hist;
  72.     char *get;
  73.  
  74.     for( get=str; *get; get++ )
  75.         if( (*get&127)<' ')
  76.             *get=' ';
  77.  
  78.     if (H_head != NULL && !strcmp(H_head->line, str))
  79.         return;
  80.     while (H_len > S_histlen)
  81.         del_history();
  82.     hist = (HIST *)salloc (sizeof(HIST));
  83.     if (H_head == NULL) {
  84.         H_head = H_tail = hist;
  85.         hist->next = NULL;
  86.     } else {
  87.         hist->next = H_head;
  88.         H_head->prev = hist;
  89.         H_head = hist;
  90.     }
  91.     hist->prev = NULL;
  92.     hist->line = salloc (strlen(str) + 1);
  93.     strcpy (hist->line, str);
  94.     ++H_len;
  95.     H_num= H_tail_base+ H_len;
  96. }
  97.  
  98. static void
  99. del_history()
  100. {
  101.     if (H_tail) {
  102.         --H_len;
  103.         ++H_tail_base;
  104.         free (H_tail->line);
  105.         if (H_tail->prev) {
  106.             H_tail = H_tail->prev;
  107.             free (H_tail->next);
  108.         H_tail->next = NULL;
  109.         } else {
  110.             free (H_tail);
  111.             H_tail = H_head = NULL;
  112.         }
  113.     }
  114. }
  115.  
  116. char *
  117. get_history( char *ptr )
  118. {
  119.     int   hnum=find_history( ptr+1, 1 );
  120.     HIST *hist;
  121.  
  122.     for( hist=H_head; hist && hnum--; hist=hist->next) ;
  123.     if( !hist ) {
  124.         fprintf(stderr,"History failed\n");
  125.         return "";
  126.     }
  127.     fprintf(stderr, "%s\n", hist->line );
  128.     return hist->line;
  129. }
  130.  
  131.  
  132. int
  133. find_history( char *ptr, int min )
  134. {
  135.     HIST *hist;
  136.     int  len, num;
  137.  
  138.     if     ( *ptr=='!' )
  139.         return 1;
  140.     else if( *ptr=='-' )
  141.         return atoi(ptr+1);
  142.     else if (*ptr >= '0' && *ptr <= '9')
  143.         return H_len-(atoi(ptr)-H_tail_base)-1;
  144.  
  145.     len = strlen(ptr);
  146.     for (hist=H_head,num=0; hist; hist=hist->next, num++)
  147.         if ( !Strncmp(hist->line, ptr, len) && num>=min)
  148.             return num;
  149.     return -1;
  150. }
  151.  
  152. void
  153. replace_head( char *str )
  154. {
  155.     if (str && strlen(str) && H_head) {
  156.         free (H_head->line);
  157.         H_head->line = salloc (strlen(str)+1);
  158.         strcpy (H_head->line, str);
  159.     }
  160. }
  161.  
  162.  
  163. void
  164. pError(char *str )
  165. {
  166.     int ierr = (long)IoErr();
  167.     ierror(str, ierr);
  168. }
  169.  
  170. ierror( char *str, int err )
  171. {
  172.     PERROR *per = Perror;
  173.  
  174.     setioerror(err);
  175.  
  176.     if (err) {
  177.         for (; per->errstr; ++per) {
  178.             if (per->errnum == err) {
  179.                 fprintf (stderr, "%s%s%s\n",
  180.                 per->errstr,
  181.                 (str) ? ": " : "",
  182.                 (str) ? str : "");
  183.                 return err;
  184.             }
  185.         }
  186.         fprintf (stderr, "Unknown DOS error %d: %s\n", err, (str) ? str : "");
  187.     }
  188.     return err;
  189. }
  190.  
  191. void
  192. setioerror( int err )
  193. {
  194.     static int LastIoError=-1;
  195.     char buf[20];
  196.  
  197.     IoError=err;
  198.     if( IoError<0 ) IoError=0;
  199.     if( LastIoError!=IoError) {
  200.         LastIoError=IoError;
  201.         sprintf(buf, "%d", IoError);
  202.         set_var(LEVEL_SET, v_ioerr, buf);
  203.     }
  204. }
  205.  
  206. char *
  207. ioerror(int num)
  208. {
  209.     PERROR *per = Perror;
  210.  
  211.     for ( ; per->errstr; ++per)
  212.         if (per->errnum == num)
  213.             return per->errstr;
  214.     return NULL;
  215. }
  216.  
  217. /*
  218.  * Disk directory routines
  219.  *
  220.  * dptr = dopen(name, stat)
  221.  *    DPTR *dptr;
  222.  *    char *name;
  223.  *    int *stat;
  224.  *
  225.  * dnext(dptr, name, stat)
  226.  *    DPTR *dptr;
  227.  *    char **name;
  228.  *    int  *stat;
  229.  *
  230.  * dclose(dptr)                  -may be called with NULL without harm
  231.  *
  232.  * dopen() returns a struct DPTR, or NULL if the given file does not
  233.  * exist.  stat will be set to 1 if the file is a directory.  If the
  234.  * name is "", then the current directory is openned.
  235.  *
  236.  * dnext() returns 1 until there are no more entries.  The **name and
  237.  * *stat are set.  *stat != 0 if the file is a directory.
  238.  *
  239.  * dclose() closes a directory channel.
  240.  *
  241.  */
  242.  
  243. DPTR *
  244. dopen( char *name, int *stat)
  245. {
  246.     DPTR *dp;
  247.  
  248.     IoError=0;
  249.     *stat = 0;
  250.     dp = (DPTR *)salloc(sizeof(DPTR));
  251.     if (*name == '\0')
  252.         dp->lock = DupLock(Myprocess->pr_CurrentDir);
  253.     else
  254.         dp->lock = Lock (name,ACCESS_READ);
  255.     if (dp->lock == NULL) {
  256.         IoError=IoErr();
  257.         free (dp);
  258.         return NULL;
  259.     }
  260.     dp->fib = (FIB *)SAllocMem((long)sizeof(FIB), MEMF_PUBLIC);
  261.     if (!Examine (dp->lock, dp->fib)) {
  262.         pError (name);
  263.         dclose (dp);
  264.         return NULL;
  265.     }
  266.     if (dp->fib->fib_DirEntryType >= 0) *stat = 1;
  267.     return dp;
  268. }
  269.  
  270. static int
  271. dnext( DPTR *dp, char **pname, int *stat)
  272. {
  273.     if (dp == NULL) return (0);
  274.  
  275.     if (ExNext (dp->lock, dp->fib)) {
  276.         *stat = 0;
  277.         if( dp->fib->fib_DirEntryType >= 0)
  278.             *stat= dp->fib->fib_DirEntryType!=ST_USERDIR ? 2 : 1;
  279.         *pname = dp->fib->fib_FileName;
  280.         return 1;
  281.     }
  282.     return 0;
  283. }
  284.  
  285. int
  286. dclose( DPTR *dp )
  287. {
  288.     if (dp == NULL)
  289.         return 1;
  290.     if (dp->fib)
  291.         FreeMem (dp->fib,(long)sizeof(*dp->fib));
  292.     if (dp->lock)
  293.         UnLock (dp->lock);
  294.     free (dp);
  295.     return 1;
  296. }
  297.  
  298.  
  299. int
  300. isdir( char *file )
  301. {
  302.     DPTR *dp;
  303.     int stat;
  304.  
  305.     stat = 0;
  306.     if (dp = dopen (file, &stat))
  307.         dclose(dp);
  308.     return (stat!=0);
  309. }
  310.  
  311.  
  312. void
  313. free_expand( char **av )
  314. {
  315.     char **get = av;
  316.  
  317.     if (av) {
  318.         while (*get)
  319.         free (*get++-sizeof(FILEINFO));
  320.         free (av);
  321.     }
  322. }
  323.  
  324. /*
  325.  * EXPAND(base,pac)
  326.  *    base           - char * (example: "df0:*.c")
  327.  *    pac            - int  *  will be set to # of arguments.
  328.  *
  329.  * 22-May-87 SJD.  Heavily modified to allow recursive wild carding and
  330.  *                 simple directory/file lookups. Returns a pointer to
  331.  *                 an array of pointers that contains the full file spec
  332.  *                 eg. 'df0:c/sear*' would result in : 'df0:C/Search'
  333.  *
  334.  *                 Now no longer necessary to Examine the files a second time
  335.  *                 in do_dir since expand will return the full file info
  336.  *                 appended to the file name. Set by formatfile().
  337.  *
  338.  *                 Caller must call free_expand when done with the array.
  339.  *
  340.  * base             bname =       ename =
  341.  * ------           -------       -------
  342.  *  "*"               ""            "*"
  343.  *  "!*.info"         ""            "*.info" (wild_exclude set)
  344.  *  "su*d/*"          ""            "*"      (tail set)
  345.  *  "file.*"          ""            "file.*"
  346.  *  "df0:c/*"         "df0:c"       "*"
  347.  *  ""                ""            "*"
  348.  *  "df0:.../*"       "df0:"        "*"      (recur set)
  349.  *  "df0:sub/.../*"   "df0:sub"     "*"      (recur set)
  350.  *
  351.  * ---the above base would be provided by execom.c or do_dir().
  352.  * ---the below base would only be called from do_dir().
  353.  *
  354.  *  "file.c"          "file.c"      ""       if (dp == 0) fail else get file.c
  355.  *  "df0:"            "df0:"        "*"
  356.  *  "file/file"       "file/file"   ""       if (dp == 0) fail
  357.  *  "df0:.../"        "df0:"        "*"      (recur set)
  358.  *
  359.  */
  360.  
  361. char **
  362. expand( char *base, int *pac )
  363. {
  364.     char *ptr;
  365.     char **eav = (char **)salloc(sizeof(char *) * (2));
  366.     short eleft, eac;
  367.     char *name;
  368.     char *bname, *ename, *tail;
  369.     int  stat, recur, scr, bl;
  370.     DPTR *dp;
  371.     PATTERN *pat;
  372.  
  373.     IoError = *pac = recur = eleft = eac = 0;
  374.  
  375.     base = strcpy(salloc(strlen(base)+1), base);
  376.     for (ptr = base; *ptr && *ptr != '?' && *ptr != '*'; ++ptr);
  377.  
  378.     if (!*ptr)   /* no wild cards */
  379.         --ptr;
  380.     else
  381.         for (; ptr >= base && !(*ptr == '/' || *ptr == ':'); --ptr);
  382.  
  383.     if (ptr < base) {
  384.         bname = strcpy (salloc(1), "");
  385.     } else {
  386.         scr = ptr[1];
  387.         ptr[1] = '\0';
  388.         if (!strcmp(ptr-3,".../")) {
  389.             recur = 1;
  390.             *(ptr-3) = '\0';
  391.         }
  392.         bname = strcpy (salloc(strlen(base)+2), base);
  393.         ptr[1] = scr;
  394.     }
  395.     bl = strlen(bname);
  396.     ename = ++ptr;
  397.     for (; *ptr && *ptr != '/'; ++ptr);
  398.     scr = *ptr;
  399.     *ptr = '\0';
  400.     if (scr) ++ptr;
  401.     tail = ptr;
  402.  
  403.     if ((dp = dopen (bname, &stat)) == NULL || (stat == 0 && *ename)) {
  404.         free (bname);
  405.         free (base);
  406.         free (eav);
  407.         return NULL;
  408.     }
  409.  
  410.     if (!stat) {                /* eg. 'dir file' */
  411.         char *p,*s;
  412.         for(s = p = bname; *p; ++p) if (*p == '/' || *p == ':') s = p;
  413.         if (*s=='/' || *s==':') s++;
  414.         *s=0;
  415.         eav[eac++] = svfile(bname,dp->fib->fib_FileName,dp->fib);
  416.         goto done;
  417.     }
  418.     if (!*ename) ename = "*";    /* eg. dir df0: */
  419.     if (*bname && bname[bl-1] != ':' && bname[bl-1] != '/') { /* dir df0:c */
  420.         bname[bl] = '/';
  421.         bname[++bl] = '\0';
  422.     }
  423.  
  424.     pat= compare_preparse( ename, 0 );
  425.     while ((dnext (dp, &name, &stat)) && !breakcheck()) {
  426.         int match = compare_ok( pat, name);
  427.         if (match && (recur || !*tail)) {
  428.             if (eleft < 2) {
  429.                 char **scrav = (char **)salloc(sizeof(char *) * (eac + 10));
  430.                 memmove (scrav, eav, (eac + 1) << 2);
  431.                 free (eav);
  432.                 eav = scrav;
  433.                 eleft = 10;
  434.             }
  435.             eav[eac++] = svfile(bname,name,dp->fib);
  436.             --eleft;
  437.         }
  438.         if ((*tail && match) || recur) {
  439.             int alt_ac;
  440.             char *search, **alt_av, **scrav;
  441.             BPTR lock;
  442.  
  443.             if (stat!=1)           /* expect more dirs, but this not a dir */
  444.                 continue;
  445.             lock = CurrentDir (dp->lock);
  446.             search = salloc(strlen(ename)+strlen(name)+strlen(tail)+6);
  447.             strcpy (search, name);
  448.             strcat (search, "/");
  449.             if (recur) {
  450.                 strcat(search, ".../");
  451.                 strcat(search, ename);
  452.             }
  453.             strcat (search, tail);
  454.             scrav = alt_av = expand (search, &alt_ac);
  455.             free(search);
  456.             CurrentDir (lock);
  457.             if (scrav) {
  458.                 while (*scrav) {
  459.                     int l;
  460.                     if (eleft < 2) {
  461.                         char **scrav = (char **)salloc(sizeof(char *)*(eac+10));
  462.                         memmove ( scrav, eav, (eac + 1) << 2);
  463.                         free (eav);
  464.                         eav = scrav;
  465.                         eleft = 10;
  466.                     }
  467.  
  468.                     l = strlen(*scrav);
  469.                     eav[eac] = salloc(bl+l+1+sizeof(FILEINFO));
  470.                     memcpy( eav[eac], *scrav-sizeof(FILEINFO),sizeof(FILEINFO));
  471.                     eav[eac]+=sizeof(FILEINFO);
  472.                     strcpy( eav[eac], bname);
  473.                     strcat( eav[eac], *scrav);
  474.  
  475.                     free (*scrav-sizeof(FILEINFO));
  476.                     ++scrav;
  477.                     --eleft, ++eac;
  478.                 }
  479.                 free (alt_av);
  480.             }
  481.         }
  482.     }
  483.     compare_free( pat );
  484. done:
  485.     dclose (dp);
  486.     *pac = eac;
  487.     eav[eac] = NULL;
  488.     free (bname);
  489.     free (base);
  490.  
  491.     if (eac) {
  492.         int i, j, len;
  493.  
  494.         QuickSort( eav, eac );
  495.         for( i=0; i<eac-1; i++ ) {
  496.             len=strlen(eav[i]);
  497.  
  498.             for( j=i+1; j<eac && !Strncmp(eav[i],eav[j],len); j++ )
  499.                 if( !Strcmp(eav[j]+len,".info")) {
  500.                     ((FILEINFO*)eav[i]-1)->flags |= INFO_INFO;
  501.                     break;
  502.                 }
  503.         }
  504.         return eav;
  505.     }
  506.  
  507.     free (eav);
  508.     return NULL;
  509. }
  510.  
  511. char *
  512. strupr( char *s )
  513. {
  514.     char *old=s;
  515.     while (*s) *s=toupper(*s), s++;
  516.     return old;
  517. }
  518.  
  519. char *
  520. strlwr( char *s )
  521. {
  522.     char *old=s;
  523.     while (*s) *s=tolower(*s), s++;
  524.     return old;
  525. }
  526.  
  527. /*
  528.  * Compare a wild card name with a normal name
  529.  */
  530.  
  531. extern void *PatternBase;
  532.  
  533. PATTERN *
  534. compare_preparse( char *wild, int casedep )
  535. {
  536.     struct pattern *pat=salloc(256);
  537.  
  538.     pat->casedep=casedep;
  539.     if (pat->queryflag=(*wild=='&')) wild++;
  540.     if (*wild=='!') *wild='~';
  541.     if( !casedep ) strlwr( wild );
  542.  
  543.     if( !PatternBase )
  544.         PreParse(wild, pat->pattern);
  545.     else
  546.         if((pat->patptr= AllocPattern( wild, 0 ))<0) {
  547.             free(pat);
  548.             return NULL;
  549.         }
  550.  
  551.     return pat;
  552. }
  553.  
  554. int
  555. compare_ok( PATTERN *pat, char *name )
  556. {
  557.     char buf[260], *lowname=name;
  558.  
  559.     if( !pat )
  560.         return 0;
  561.  
  562.     if (!pat->casedep) {
  563.         strncpy(buf,name,256);
  564.         strlwr(buf);
  565.         lowname=buf;
  566.     }
  567.  
  568.     if( !PatternBase ) {
  569.         if ( !PatternMatch(pat->pattern,lowname))
  570.             return 0;
  571.     } else {
  572.         if( MatchThePattern(pat->patptr,lowname )!=1)
  573.             return 0;
  574.     }
  575.  
  576.     if (pat->queryflag) {
  577.         printf("Select %s%-16s%s [y/n] ? ",o_hilite,name,o_lolite);
  578.         gets(buf);
  579.         return (toupper(*buf)=='Y');
  580.     }
  581.     return 1;
  582. }
  583.  
  584. void
  585. compare_free( PATTERN *pat )
  586. {
  587.     if( !pat )
  588.         return;
  589.     if( PatternBase )
  590.         FreePattern(pat->patptr);
  591.     free( pat );
  592. }
  593.  
  594. #if 0
  595. int
  596. compare_strings( char *pattern, char *str, int casedep )
  597. {
  598.     PATTERN *pat=compare_preparse( pattern, casedep );
  599.     int ret=compare_ok(pat,str);
  600.     compare_free(pat);
  601.     return ret;
  602. }
  603. #endif
  604.  
  605. static char *
  606. svfile( char *s1, char *s2, FIB *fib)
  607. {
  608.     FILEINFO *info=salloc(sizeof(FILEINFO)+strlen(s1)+strlen(s2)+1);
  609.     char     *p = (char *)(info+1);
  610.  
  611.     strcpy(p, s1);
  612.     strcat(p, s2);
  613.     info->flags = fib->fib_Protection | (*fib->fib_Comment ? 1<<30 : 0);
  614.     info->size  = fib->fib_DirEntryType<0 ? fib->fib_Size      : -1;
  615.     info->blocks= fib->fib_DirEntryType<0 ? fib->fib_NumBlocks :  0;
  616.     info->date  = fib->fib_Date;
  617.     info->class[0]=1;
  618.     return p;
  619. }
  620.  
  621. static char   *FullPath;
  622. static FIB    *PrevFile;
  623. static int   (*Action)(long, char *, char *);
  624. static long    Mask;
  625. static int     Queued=0;
  626.  
  627. static int
  628. passinfo( FIB *fib )
  629. {
  630.     char   *p = (char *)(PrevFile+1);
  631.     int    oldlen, ret=0;
  632.  
  633.     if( Queued ) {
  634.         oldlen=strlen(FullPath);
  635.         TackOn( FullPath, p );
  636.         ret=(*Action)( Mask, p, FullPath );
  637.         FullPath[oldlen]=0;
  638.         Queued=0;
  639.     }
  640.  
  641.     if( fib ) {
  642.         *PrevFile= *fib;
  643.         strcpy( p, fib->fib_FileName);
  644.         Queued=1;
  645.     }
  646.  
  647.     return ret;
  648. }
  649.  
  650.  
  651. static int
  652. nu_recurse( char *name )
  653. {
  654.     BPTR lock, cwd;
  655.     FIB  *fib  =(FIB *)SAllocMem(sizeof(FIB),MEMF_PUBLIC);
  656.     int  oldlen=strlen( FullPath ), ret=0;
  657.  
  658.     TackOn( FullPath, name );
  659.  
  660.     if (lock=Lock(name,ACCESS_READ)) {
  661.         if( Mask & SCAN_DIRENTRY )
  662.             (*Action)( SCAN_DIRENTRY, name, FullPath );
  663.  
  664.         cwd =CurrentDir(lock);
  665.         if (Examine(lock, fib)) {
  666.             while (ExNext(lock, fib) && !breakcheck()) {
  667.                 if (fib->fib_DirEntryType==ST_USERDIR) {
  668.                     if ( Mask & SCAN_RECURSE ) {
  669.                         if(!ret && !(ret=passinfo( NULL )))
  670.                             ret=nu_recurse(fib->fib_FileName);
  671.                     }
  672.                     if ( Mask & SCAN_DIR     )
  673.                         if( !ret )
  674.                             ret=passinfo( fib );
  675.                 } else if( fib->fib_DirEntryType<0 && Mask & SCAN_FILE )
  676.                     if( !ret )
  677.                         ret=passinfo( fib );
  678.             }
  679.             if( breakcheck() )
  680.                 ret=5;
  681.  
  682.             if( !ret )
  683.                 passinfo( NULL );
  684.  
  685.         }
  686.         UnLock(CurrentDir(cwd));
  687.  
  688.         if( Mask & SCAN_DIREND )
  689.             (*Action)( SCAN_DIREND, name, FullPath );
  690.     } else
  691.         pError(name);
  692.  
  693.     FullPath[oldlen]=0;
  694.     FreeMem(fib, sizeof(FIB));
  695.     return ret;
  696. }
  697.  
  698. int
  699. newrecurse(int mask, char *name, int (*action)FUNCARG(long,char *,char *))
  700. {
  701.     int ret;
  702.  
  703.     FullPath = salloc( 512 );
  704.     PrevFile = salloc( sizeof(FIB)+108+1 );
  705.     Action   = action;
  706.     Mask     = mask;
  707.     Queued   = 0;
  708.     *FullPath= 0;
  709.  
  710.     ret=nu_recurse( name );
  711.  
  712.     free( PrevFile );
  713.     free( FullPath );
  714.  
  715.     return ret;
  716. }
  717.  
  718.  
  719. /* Sort routines */
  720.  
  721. static int reverse, factor;
  722.  
  723. int
  724. cmp( FILEINFO *s1, FILEINFO *s2)
  725. {
  726.     return Strcmp( (char *)(s1+1), (char *)(s2+1) );
  727. }
  728.  
  729. int
  730. sizecmp( FILEINFO *s1, FILEINFO *s2)
  731. {
  732.     return s2->size - s1->size;
  733. }
  734.  
  735. int
  736. datecmp( FILEINFO *s1, FILEINFO *s2 )
  737. {
  738.     int r;
  739.     struct DateStamp *d1=&s1->date, *d2=&s2->date;
  740.     if( !(r= d2->ds_Days - d1->ds_Days))
  741.         if( !(r=d2->ds_Minute - d1->ds_Minute ) )
  742.             r=d2->ds_Tick - d1->ds_Tick;
  743.     return r;
  744. }
  745.  
  746.  
  747. int
  748. numcmp( FILEINFO *s1, FILEINFO *s2 )
  749. {
  750.     return atoi((char *)(s1+1))-atoi((char *)(s2+1));
  751. }
  752.  
  753. static void
  754. enterclass( FILEINFO *info )
  755. {
  756.     char *class, *iclass=info->class, *t;
  757.  
  758.     if( *iclass==1 ) {
  759.         if( class=getclass( (char *)(info+1))) {
  760.             strncpy( iclass, class, 11 );
  761.             iclass[11]=0;
  762.             if( t=index(iclass,0xA0))
  763.                 *t=0;
  764.         } else 
  765.             iclass[0]=0;
  766.     }
  767. }
  768.  
  769. int
  770. classcmp( FILEINFO *info1, FILEINFO *info2 )
  771. {
  772.     int r;
  773.  
  774.     enterclass( info1 );
  775.     enterclass( info2 );
  776.  
  777.     r= Strcmp( info1->class, info2->class );
  778.     if( !r ) r=Strcmp((char *)(info1+1),(char *)(info2+1));
  779.     return r;
  780. }
  781.  
  782.  
  783. void
  784. QuickSort( char *av[], int n)
  785. {
  786.     reverse=factor=0;
  787.     DirQuickSort( av, n, cmp, 0, 0 );
  788. }
  789.  
  790. static int (*compare)(FILEINFO *, FILEINFO *);
  791.  
  792. static int
  793. docompare(char *s1,char *s2)
  794. {
  795.     FILEINFO *i1=(FILEINFO *)s1-1, *i2=(FILEINFO *)s2-1;
  796.     int r=(*compare)( i1,i2 );
  797.  
  798.     if( reverse ) r =-r;
  799.     if( factor )  r+= factor*((i2->size<0) - (i1->size<0));
  800.     return r;
  801. }
  802.  
  803. #define QSORT
  804.  
  805. void
  806. DirQuickSort( char *av[], int n, int (*func)(FILEINFO *,FILEINFO *), int rev, int fac)
  807. {
  808.     reverse=rev; compare=func; factor=fac;
  809.  
  810.     quicksort( av, n-1 );
  811. }
  812.  
  813. static void
  814. quicksort( char **av, int n )
  815. {
  816.     char **i, **j, *x, *t;
  817.  
  818.  
  819.     if( n>0 ) {
  820.         i=av; j=av+n; x=av[ n>>1 ];
  821.         do {
  822.             while( docompare(*i,x)<0 ) i++;
  823.             while( docompare(x,*j)<0 ) --j;
  824.             if( i<=j )
  825.                 { t=*i; *i=*j; *j=t; i++; j--; }
  826.         } while( i<=j );
  827.  
  828.         if( j-av < av+n-i ) {
  829.             quicksort( av, j-av  );
  830.             quicksort( i , av+n-i);
  831.         } else {
  832.             quicksort( i , av+n-i);
  833.             quicksort( av, j-av  );
  834.         }
  835.     }
  836. }
  837.  
  838. int
  839. filesize( char *name )
  840. {
  841.     BPTR lock;
  842.     struct FileInfoBlock *fib;
  843.     int  len=0;
  844.  
  845.     if( lock = Lock (name,ACCESS_READ)) {
  846.         if( fib=(struct FileInfoBlock *)AllocMem(sizeof(*fib),MEMF_PUBLIC)) {
  847.             if (Examine (lock, fib))
  848.                 len=fib->fib_Size;
  849.             FreeMem( fib, sizeof(*fib));
  850.         }
  851.         UnLock(lock);
  852.     }
  853.     return len;
  854. }
  855.  
  856.  
  857. #ifndef MIN
  858. #define MIN(x,y) ((x)<(y)?(x):(y))
  859. #endif
  860.  
  861. char **
  862. and( char **av1, int ac1, char **av2, int ac2, int *ac, int base )
  863. {
  864.     char **av=(char **)salloc(MIN(ac1,ac2)*sizeof(char *) ), *str;
  865.     int i, j, k=0;
  866.  
  867.     for( i=0; i<ac1; i++ )
  868.         for( j=0, str=base ? (char*)BaseName(av1[i]) : av1[i]; j<ac2; j++ )
  869.             if( !Strcmp(str, base ? (char*)BaseName(av2[j]) : av2[j]))
  870.                 av[k++]=av1[i];
  871.     *ac=k;
  872.     return av;
  873. }
  874.  
  875. char **
  876. without( char **av1, int ac1, char **av2, int ac2, int *ac, int base )
  877. {
  878.     char **av=(char **)salloc(ac1*sizeof(char *) ), *str;
  879.     int i, j, k=0;
  880.  
  881.     for( i=0; i<ac1; i++ ) {
  882.         for( j=0, str=base ? (char*)BaseName(av1[i]) : av1[i]; j<ac2; j++ )
  883.             if( !Strcmp(str, base ? (char*)BaseName(av2[j]) : av2[j] ) )
  884.                 break;
  885.         if( j==ac2 )
  886.             av[k++]=av1[i];
  887.     }
  888.     *ac=k;
  889.     return av;
  890. }
  891.  
  892. char **
  893. or( char **av1, int ac1, char **av2, int ac2, int *ac, int base )
  894. {
  895.     char **av=(char **)salloc((ac1+ac2)*sizeof(char *) ), *str;
  896.     int i, j, k=0;
  897.  
  898.     for( i=0; i<ac1; i++ )
  899.         av[k++]=av1[i];
  900.  
  901.     for( i=0; i<ac2; i++ ) {
  902.         for( j=0, str=base ? (char*)BaseName(av2[i]) : av2[i]; j<ac1; j++ )
  903.             if( !Strcmp(str, base ? (char*)BaseName(av1[j]) : av1[j] ) )
  904.                 break;
  905.         if( j==ac1 )
  906.             av[k++]=av2[i];
  907.     }
  908.  
  909.     *ac=k;
  910.     return av;
  911. }
  912.  
  913. void
  914. clear_archive_bit( char *name )
  915. {
  916.     DPTR *dp;
  917.     int  stat;
  918.  
  919.     if(dp = dopen(name,&stat) ) {
  920.         SetProtection( name, dp->fib->fib_Protection&~FIBF_ARCHIVE);
  921.         dclose( dp );
  922.     }
  923. }
  924.  
  925. char *
  926. itoa( int i )
  927. {
  928.     static char buf[20];
  929.     char *pos=buf+19;
  930.     int count=4, flag=0;
  931.  
  932.     if( i<0 )
  933.         flag=1, i=-i;
  934.  
  935.     do {
  936.         if( !--count )
  937.             count=3, *--pos=',';
  938.         *--pos= i%10+'0';
  939.     } while( i/=10 );
  940.  
  941.     if( flag )
  942.         *--pos='-';
  943.  
  944.     return pos;
  945. }
  946.  
  947. char *
  948. itok( int i )
  949. {
  950.     static char buf[16], which;
  951.     char *exp=" KMG", *ptr= buf+(which=8-which);
  952.  
  953.     do
  954.         i=(i+512)/1024, exp++;
  955.     while( i>1024 );
  956.     sprintf( ptr,"%d%c",i,*exp);
  957.  
  958.     return ptr;
  959. }
  960.  
  961. char *
  962. next_a0( char *str )
  963. {
  964.     while( *str && (UBYTE)*str!=0xA0 && *str!='=' && *str!=',') str++;
  965.     if( *str )
  966.         return str+1;
  967.     return NULL;
  968. }
  969.  
  970. static int
  971. gethex( char *str, int l )
  972. {
  973.     int i, val=0, n, c;
  974.  
  975.     if( *str=='.' ) return l==2 ? 256 : 0;
  976.  
  977.     for( i=0; i<l || !l; i++ ) {
  978.         c=*str++;
  979.         if     ( c>='0' && c<='9' ) n=c-'0';
  980.         else if( c>='a' && c<='f' ) n=c-'a'+10;
  981.         else if( c>='A' && c<='F' ) n=c-'A'+10;
  982.         else break;;
  983.         val=16*val+n;
  984.     }
  985.     return (l && i!=l) ? -1 : val;
  986. }
  987.  
  988. strwrdcmp( char *str, char *wrd )
  989. {
  990.     PATTERN *pat;
  991.     int ret;
  992.     char *ind=index(wrd,0xA0);
  993.  
  994.     if( ind ) *ind=0;
  995.     pat=compare_preparse( wrd,0 );
  996.     ret=compare_ok(pat,str);
  997.     compare_free( pat );
  998.     if( ind ) *ind=0xA0;
  999.     return !ret;
  1000. }
  1001.  
  1002. int
  1003. wrdlen( char *str )
  1004. {
  1005.     char *old=str;
  1006.  
  1007.     while( *str && (UBYTE)*str!=0xA0 ) str++;
  1008.     return str-old;
  1009. }
  1010.  
  1011. char *
  1012. getclass(char *file)
  1013. {
  1014.     CLASS *cl;
  1015.     char *class, *str, *arg, *get, *buf;
  1016.     int offs, byte, len, fail;
  1017.     BPTR fh;
  1018.  
  1019.     if( isdir(file) ) return "dir";
  1020.  
  1021.     if( !(buf=calloc(1024,1))) return NULL;
  1022.     if( !(fh=Open(file,MODE_OLDFILE))) return NULL;
  1023.     len=Read( fh,buf,1023);
  1024.     Close(fh);
  1025.  
  1026.     for( cl=CRoot; cl; cl=cl->next ) {
  1027.         class=cl->name;
  1028.         if(!(str=next_a0(cl->name))) continue;
  1029.         while( str ) {
  1030.             if(!(arg=next_a0( str ))) goto nextclass;
  1031.             switch( *str ) {
  1032.             case 's':
  1033.                 if( (offs=strlen(file)-wrdlen(arg))<0 ) break;
  1034.                 if( !strwrdcmp(file+offs,arg)) goto found;
  1035.                 break;
  1036.             case 'n':
  1037.                 if( !strwrdcmp(BaseName(file),arg) ) goto found;
  1038.                 break;
  1039.             case 'd':
  1040.                 goto found;
  1041.             case 'o':
  1042.                 offs=gethex(arg,0);
  1043.                 if( !(arg=index(arg,','))) goto nextclass;
  1044.                 if( offs>len-10 ) break;
  1045.                 for( get=buf+offs, ++arg; (byte=gethex(arg,2))>=0; arg+=2 )
  1046.                     if( (UBYTE)*get++!=byte && byte!=256 )
  1047.                         goto nexttry;
  1048.                 goto found;
  1049.             case 'c':
  1050.                 if( !len )
  1051.                     break;
  1052.                 for( get=buf, fail=0; get<buf+len; get++ )
  1053.                     if( *get<9 || *get>13 && *get<32 || *get>127  )
  1054.                         fail++;
  1055.                 if( fail*8>len )
  1056.                     break;
  1057.                 goto found;
  1058.             case 'i':
  1059.                 break;
  1060.             case 'a':
  1061.                 goto nextclass;
  1062.             default:
  1063.                 goto nextclass;
  1064.             }
  1065. nexttry:    str=next_a0(arg);
  1066.         }
  1067. nextclass: ;
  1068.     }
  1069.  
  1070.     free(buf);
  1071.     return NULL;
  1072.  
  1073. found:
  1074.     free(buf);
  1075.     return (char *)class;
  1076. }
  1077.  
  1078. char *
  1079. superclass( char *subclass )
  1080. {
  1081.     CLASS *cl;
  1082.     char *cur;
  1083.     int len;
  1084.  
  1085.     for( len=0; subclass[len] && (UBYTE)subclass[len]!=0xA0; len++ ) ;
  1086.     for( cl=CRoot; cl; cl=cl->next ) {
  1087.         if( strncmp( cur=cl->name,subclass,len ))
  1088.             continue;
  1089.         do
  1090.             cur=index( cur,0xA0 );
  1091.         while( cur && *++cur!='i');
  1092.  
  1093.         if( cur && (cur=index(cur,'=')))
  1094.             return ++cur;
  1095.     }
  1096.     return NULL;
  1097. }
  1098.  
  1099. char *
  1100. getaction( char *class, char *action )
  1101. {
  1102.     CLASS *cl;
  1103.     char *cur, *ind;
  1104.     int len;
  1105.  
  1106.     for( len=0; class[len] && (UBYTE)class[len]!=0xA0; len++ ) ;
  1107.     for( cl=CRoot; cl; cl=cl->next ) {
  1108.         if( strncmp( cur=cl->name,class,len ) || !issep(cur[len]))
  1109.             continue;
  1110.         do
  1111.             cur=index( cur,0xA0 );
  1112.         while( cur && *++cur!='a');
  1113.  
  1114.         if( cur && (cur=index( ++cur,0xA0 ))) {
  1115.             do {
  1116.                 if( !(ind=index( ++cur,'=' )))
  1117.                     return NULL;
  1118.                 len=ind-cur;
  1119.                 if( len==strlen(action) && !strncmp(action,cur,len))
  1120.                     return ++ind;
  1121.             } while( cur=index(cur,0xA0) );
  1122.         }
  1123.     }
  1124.     return NULL;
  1125. }
  1126.  
  1127. int
  1128. doaction( char *file, char *action, char *args )
  1129. {
  1130.     char *class, *com, *c, *copy;
  1131.     int ret, spc=hasspace(file), i=0;
  1132.  
  1133.     if( !(class=getclass(file)))
  1134.         return exists(file) ? 10 : 9;
  1135.  
  1136.     do
  1137.         if( com=getaction(class,action))
  1138.             break;
  1139.     while( (class=superclass( class )) && ++i<4 );
  1140.     if( !class )
  1141.         return 11;
  1142.     if( c=index(com,0xA0) )
  1143.         *c=0;
  1144.     copy=salloc( strlen(com)+strlen(file)+strlen(args)+7 );
  1145.     sprintf(copy,spc?"%s \"%s\" %s":"%s %s %s", com, file, args);
  1146.     ret=execute(copy);
  1147.     free(copy);
  1148.     if( c )
  1149.         *c=0xA0;
  1150.     return ret ? 12 : 0;
  1151. }
  1152.  
  1153. void *
  1154. salloc( int len )
  1155. {
  1156.     void *ret;
  1157.  
  1158.     if( !len ) len++;
  1159.  
  1160.     if( !(ret=malloc(len))) {
  1161.         fprintf(stderr,"Out of memory -- exiting\n");
  1162.         main_exit( 20 );
  1163.     }
  1164.     return ret;
  1165. }
  1166.  
  1167. void *
  1168. SAllocMem( long size, long req  )
  1169. {
  1170.     void *ret;
  1171.  
  1172.     if( !(ret=AllocMem(size,req))) {
  1173.         fprintf(stderr,"Out of memory -- exiting\n");
  1174.         main_exit( 20 );
  1175.     }
  1176.     return ret;
  1177. }
  1178.  
  1179. int
  1180. issep( char s )
  1181. {
  1182.     return !s || ISSPACE(s) || s=='/' || s==';' || s=='|' || s=='&';
  1183. }
  1184.  
  1185.  
  1186. char *
  1187. filemap( char *buf, int last )
  1188. {
  1189.     char *s=buf, *d, *lcd;
  1190.     int  len;
  1191.  
  1192.     if( last && *s=='~' && issep(s[1])) {
  1193.         if (!(lcd=get_var(LEVEL_SET,v_lcd)))
  1194.             return buf;
  1195.         len= strlen(lcd);
  1196.         memmove( s+len, s+1, strlen(s)+1);
  1197.         memcpy( s, lcd, strlen(lcd));
  1198.         if( s[len]!='/' )
  1199.             return buf;
  1200.         s+=len+1;
  1201.     }
  1202.     d=s;
  1203.     for( ;; ) {
  1204.         if( s[0]=='.' && issep(s[1]) )
  1205.             s+=1+(s[1]!=0);
  1206.         else if( s[0]=='.' && s[1]=='.' && issep(s[2]))
  1207.             *d++='/', s+=2+(s[2]!=0);
  1208.         else 
  1209.             break;
  1210.     }
  1211.     while( *d++=*s++ ) ;
  1212.  
  1213.     return buf;
  1214. }
  1215.  
  1216.  
  1217. char *
  1218. safegets( char *buf, FILE *in )
  1219. {
  1220.     char *t;
  1221.  
  1222.     if( dobreak() )
  1223.         return NULL;
  1224.  
  1225.     if( !fgets(buf,249,in) )
  1226.         return NULL;
  1227.  
  1228.     if( t=index(buf,'\n' ))
  1229.         *t=0;
  1230.  
  1231.     return buf;
  1232. }
  1233.