home *** CD-ROM | disk | FTP | other *** search
/ back2roots/padua / padua.7z / padua / shell / csh550src.lha / comm1.c next >
Encoding:
C/C++ Source or Header  |  1996-07-02  |  66.6 KB  |  3,012 lines

  1. /*
  2.  * COMM1.C
  3.  *
  4.  * Matthew Dillon, August 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. /* comm1.c */
  16. static void display_file(char *filestr);
  17. static int search_file( long mask, char *s, char *fullpath );
  18. static int rm_file    ( long mask, char *s, char *fullpath );
  19. static int quicksearch(char *name, int nocasedep, char *pattern);
  20. static void setsystemtime(struct DateStamp *ds);
  21. static int found( char *lstart, int lnum, int loffs, char *name, char left );
  22.  
  23. void lformat( char *s, char *d, FILEINFO *info );
  24.  
  25. extern int has_wild;
  26.  
  27. int
  28. do_sleep( void )
  29. {
  30.     long ticks,secs;
  31.  
  32.     if (ac == 2) {
  33.         if (options&1) {    /* ticks */
  34.             ticks  = atoi(av[1]);
  35.             secs   = ticks / 50;
  36.             ticks -= secs*50;
  37.         }
  38.         else {    /* seconds */
  39.             secs   = atoi(av[1]);
  40.             ticks  = 0;
  41.         }
  42.  
  43.         if (ticks>0)
  44.             Delay(ticks);
  45.  
  46.         while (secs>0 && !CHECKBREAK()) {
  47.             Delay(50);
  48.             secs--;
  49.         }
  50.     }
  51.  
  52.     return 0;
  53. }
  54.  
  55. #if 0
  56. /* AMK: if you change this, you must change do_chmod() also!! */
  57. int
  58. do_protect( void )
  59. {
  60.     static char flags[]="DEWRAPSH";
  61.     char *s, *p;
  62.     long setmask=0, clrmask=0xFF, mask;
  63.     int  i, mode=0, stat;
  64.     DPTR *dp;
  65.  
  66.     for (s=strupr(av[--ac]); *s; s++) {
  67.         if (*s=='=') { mode=0; continue; }
  68.         if (*s=='+') { mode=1; clrmask=FIBF_ARCHIVE; continue; }
  69.         if (*s=='-') { mode=2; clrmask=FIBF_ARCHIVE; continue; }
  70.  
  71.         if (*s=='X') *s='E';
  72.         if (p=index(flags, *s)) {
  73.             if( mode==0 ) setmask|= 1<<(p-flags), clrmask=0xFF;
  74.             if( mode==1 ) setmask|= 1<<(p-flags);
  75.             if( mode==2 ) clrmask|= 1<<(p-flags);
  76.         } else {
  77.             ierror(av[ac],500);
  78.             return 20;
  79.         }
  80.     }
  81.  
  82.     for (i=1; i<ac; i++) {
  83.         if( (dp=dopen(av[i],&stat))) {
  84.             mask = dp->fib->fib_Protection ^ 0x0F;
  85.             mask&=~clrmask;
  86.             mask|= setmask;
  87.             dclose(dp);
  88.             if( !setProtection( av[i], mask ^ 0x0F))
  89.                 pError(av[i]);
  90.         } else
  91.             pError(av[i]);
  92.     }
  93.     return 0;
  94. }
  95. #endif
  96.  
  97. /* AMK: same as do_protect, but flags now as first argument */
  98. #if 0
  99. int
  100. do_chmod( void )
  101. {
  102.     static char flags[]="DEWRAPSH";
  103.     char *s, *p;
  104.     long setmask=0, clrmask=0xFF, mask;
  105.     int  i, mode=0, stat;
  106.     DPTR *dp;
  107.  
  108.     for (s=strupr(av[1]); *s; s++) {       /* AMK: changed */
  109.         if (*s=='=') { mode=0; continue; }
  110.         if (*s=='+') { mode=1; clrmask=FIBF_ARCHIVE; continue; }
  111.         if (*s=='-') { mode=2; clrmask=FIBF_ARCHIVE; continue; }
  112.  
  113.         if (*s=='X') *s='E';
  114.         if (p=index(flags, *s)) {
  115.             if( mode==0 ) setmask|= 1<<(p-flags), clrmask=0xFF;
  116.             if( mode==1 ) setmask|= 1<<(p-flags);
  117.             if( mode==2 ) clrmask|= 1<<(p-flags);
  118.         } else {
  119.             ierror(av[1],500);     /* AMK: changed */
  120.             return 20;
  121.         }
  122.     }
  123.  
  124.     for (i=2; i<ac; i++) {                 /* AMK: changed */
  125.         if( (dp=dopen(av[i],&stat))) {
  126.             mask = dp->fib->fib_Protection ^ 0x0F;
  127.             mask&=~clrmask;
  128.             mask|= setmask;
  129.             dclose(dp);
  130.             if( !setProtection( av[i], mask ^ 0x0F))
  131.                 pError(av[i]);
  132.         } else
  133.             pError(av[i]);
  134.     }
  135.     return 0;
  136. }
  137. #endif
  138.  
  139. #define FIBB_HOLD 7
  140. #define FIBF_HOLD (1<<FIBB_HOLD)
  141.  
  142. int do_chmod_internal(long arg_begin,long arg_end,long arg_flags)
  143. {
  144.     char *s;
  145.     LONG mask;
  146.     int  i, stat;
  147.     DPTR *dp;
  148.     BOOL do_user=FALSE,do_group=FALSE,do_other=FALSE,do_default=TRUE;
  149.     BOOL do_incl=FALSE,do_excl=FALSE,do_set=TRUE;
  150.  
  151.     /*strlwr(av[1]);*/
  152.  
  153.     for (i=arg_begin; i<arg_end; i++) {  /* all arguments except 'arg_flags' */
  154.  
  155.         if( (dp=dopen(av[i],&stat))) {
  156.             mask = dp->fib->fib_Protection;
  157.             dclose(dp);
  158.  
  159.             s = av[arg_flags];
  160.  
  161.             if (strchr(s,'+') || strchr(s,'-') || strchr(s,'=')) {
  162.  
  163.                 while (*s && !strchr("+-=",*s)) {
  164.                     switch (*s) {
  165.                     case 'u': do_user  = TRUE; break;
  166.                     case 'g': do_group = TRUE; break;
  167.                     case 'o': do_other = TRUE; break;
  168.                     case 'a': do_user  =
  169.                               do_group = 
  170.                               do_other = TRUE; break;
  171.                     default : ierror(av[1],500); return 20;
  172.                     }
  173.                     do_default = FALSE;
  174.                     ++s;
  175.                 }
  176.  
  177.                 do_set = FALSE;
  178.  
  179.                 switch (*s) {
  180.                 case '+': do_incl = TRUE; break;
  181.                 case '-': do_excl = TRUE; break;
  182.                 case '=': do_set  = TRUE; break;
  183.                 default : ierror(av[1],500); return 20;
  184.                 }
  185.  
  186.                 ++s;
  187.  
  188.             }
  189.  
  190.             if (do_default) {
  191.                 do_user=TRUE;
  192.             }
  193.  
  194.             if (do_set) {
  195.                 do_incl = TRUE;
  196.                 mask = FIBF_READ|FIBF_WRITE|FIBF_EXECUTE|FIBF_DELETE;
  197.             }
  198.  
  199.             mask &= (~FIBF_ARCHIVE);
  200.  
  201.             while (*s) {
  202.                 switch (*s) {
  203.                 case 'r' :
  204.                            if (do_incl) {
  205.                              if (do_user)  mask &= (~FIBF_READ);
  206.                              if (do_group) mask |= FIBF_GRP_READ;
  207.                              if (do_other) mask |= FIBF_OTR_READ;
  208.                            }
  209.                            else {
  210.                              if (do_user)  mask |= FIBF_READ;
  211.                              if (do_group) mask &= (~FIBF_GRP_READ);
  212.                              if (do_other) mask &= (~FIBF_OTR_READ);
  213.                            }
  214.                            break;
  215.                 case 'w' :
  216.                            if (do_incl) {
  217.                              if (do_user)  mask &= (~FIBF_WRITE);
  218.                              if (do_group) mask |= FIBF_GRP_WRITE;
  219.                              if (do_other) mask |= FIBF_OTR_WRITE;
  220.                            }
  221.                            else {
  222.                              if (do_user)  mask |= FIBF_WRITE;
  223.                              if (do_group) mask &= (~FIBF_GRP_WRITE);
  224.                              if (do_other) mask &= (~FIBF_OTR_WRITE);
  225.                            }
  226.                            break;
  227.                 case 'e' :
  228.                 case 'x' :
  229.                            if (do_incl) {
  230.                              if (do_user)  mask &= (~FIBF_EXECUTE);
  231.                              if (do_group) mask |= FIBF_GRP_EXECUTE;
  232.                              if (do_other) mask |= FIBF_OTR_EXECUTE;
  233.                            }
  234.                            else {
  235.                              if (do_user)  mask |= FIBF_EXECUTE;
  236.                              if (do_group) mask &= (~FIBF_GRP_EXECUTE);
  237.                              if (do_other) mask &= (~FIBF_OTR_EXECUTE);
  238.                            }
  239.                            break;
  240.                 case 'd' :
  241.                            if (do_incl) {
  242.                              if (do_user)  mask &= (~FIBF_DELETE);
  243.                              if (do_group) mask |= FIBF_GRP_DELETE;
  244.                              if (do_other) mask |= FIBF_OTR_DELETE;
  245.                            }
  246.                            else {
  247.                              if (do_user)  mask |= FIBF_DELETE;
  248.                              if (do_group) mask &= (~FIBF_GRP_DELETE);
  249.                              if (do_other) mask &= (~FIBF_OTR_DELETE);
  250.                            }
  251.                            break;
  252.                 case 'a' :
  253.                            if (do_incl)
  254.                              mask |= FIBF_ARCHIVE;
  255.                            else
  256.                              mask &= (~FIBF_ARCHIVE);
  257.                            break;
  258.                 case 'p' :
  259.                            if (do_incl)
  260.                              mask |= FIBF_PURE;
  261.                            else
  262.                              mask &= (~FIBF_PURE);
  263.                            break;
  264.                 case 's' :
  265.                            if (do_incl)
  266.                              mask |= FIBF_SCRIPT;
  267.                            else
  268.                              mask &= (~FIBF_SCRIPT);
  269.                            break;
  270.                 case 'h' :
  271.                            if (do_incl)
  272.                              mask |= FIBF_HOLD;
  273.                            else
  274.                              mask &= (~FIBF_HOLD);
  275.                            break;
  276.                 default  :
  277.                            ierror(av[1],500);
  278.                            return 20;
  279.                 }
  280.                 ++s;
  281.             }
  282.  
  283.             if( !setProtection( av[i], mask ))
  284.                 pError(av[i]);
  285.         }
  286.         else
  287.             pError(av[i]);
  288.     }
  289.  
  290.     return 0;
  291. }
  292.  
  293. int do_protect(void)
  294. {
  295.     return do_chmod_internal(1,ac-1,ac-1);
  296. }
  297.  
  298. int do_chmod(void)
  299. {
  300.     return do_chmod_internal(2,ac,1);
  301. }
  302.  
  303.  
  304.  
  305. int do_chown(void)
  306. {
  307.     LONG mask;  /* 2x UWORD */
  308.     UWORD new_uid,new_gid = 0;
  309.     int  i, stat;
  310.     DPTR *dp;
  311.  
  312. #ifdef MULTIUSER_SUPPORT
  313.     struct muUserInfo *info;
  314.     struct muUserInfo *res;
  315.  
  316.     if (muBase) {
  317.         if (info = muAllocUserInfo()) {
  318.             if (isdigit(av[1][0])) {
  319.                 new_uid = myatoi(av[1],0,65535);
  320.                 if (atoierr) {
  321.                     fprintf(stderr,"UID/GID is a 16-bit wide UWORD (0-65535) !\n");
  322.                     muFreeUserInfo(info);
  323.                     return 20;
  324.                 }
  325.                 info->uid = new_uid;
  326.                 res = muGetUserInfo(info,muKeyType_uid);
  327.                 new_gid = info->gid;
  328.             }
  329.             else {
  330.                 if (strlen(av[1]) > muUSERIDSIZE-1) {
  331.                     fprintf(stderr,"%s: string too long for a User-ID.\n",av[1]);
  332.                     muFreeUserInfo(info);
  333.                     return 20;
  334.                 }
  335.                 strcpy(info->UserID,av[1]);
  336.                 if (!(res = muGetUserInfo(info,muKeyType_UserID))) {
  337.                     fprintf(stderr,"%s: no valid user.\n",av[1]);
  338.                     muFreeUserInfo(info);
  339.                     return 20;
  340.                 }
  341.                 new_uid = info->uid;
  342.                 new_gid = info->gid;
  343.             }
  344.             muFreeUserInfo(info);
  345.         }
  346.         else {
  347.             fprintf(stderr,"Not enough memory.\n");
  348.             return 20;
  349.         }
  350.     }
  351.     else {
  352.         new_uid = myatoi(av[1],0,65535);
  353.         if (atoierr) {
  354.             fprintf(stderr,"UID/GID is a 16-bit wide UWORD (0-65535) !\n");
  355.             return 20;
  356.         }
  357.     }
  358. #else
  359.     new_uid = myatoi(av[1],0,65535);
  360.     if (atoierr) {
  361.         fprintf(stderr,"UID/GID is a 16-bit wide UWORD (0-65535) !\n");
  362.         return 20;
  363.     }
  364. #endif /* MULTIUSER_SUPPORT */
  365.  
  366.     for (i=2; i<ac; i++) {  /* all arguments except first */
  367.  
  368.         if( (dp=dopen(av[i],&stat))) {
  369.             /*printf("%s, gid %d, uid %d\n",av[i],dp->fib->fib_OwnerGID,dp->fib->fib_OwnerUID);*/
  370.             mask = dp->fib->fib_OwnerGID + (new_uid<<16);
  371.             if (options&1)    /* also set GID to primary group */
  372.                 mask = new_gid + (new_uid<<16);
  373.             else
  374.                 mask = dp->fib->fib_OwnerGID + (new_uid<<16);
  375.             dclose(dp);
  376.  
  377.             /*printf("  new mask: %ld\n",mask);*/
  378.             if (DOSBase->dl_lib.lib_Version<39) {
  379.                 if( !SetOwner37( av[i], mask ))
  380.                     pError(av[i]);
  381.             }
  382.             else {
  383.                 if( !SetOwner( av[i], mask ))
  384.                     pError(av[i]);
  385.             }
  386.         }
  387.         else
  388.             pError(av[i]);
  389.     }
  390.  
  391.     return 0;
  392. }
  393.  
  394.  
  395.  
  396. int do_chgrp(void)
  397. {
  398.     LONG mask;  /* 2x UWORD */
  399.     UWORD new_gid;
  400.     int  i, stat;
  401.     DPTR *dp;
  402.  
  403. #ifdef MULTIUSER_SUPPORT
  404.     struct muGroupInfo *info;
  405.     struct muGroupInfo *res;
  406.  
  407.     if (muBase && !isdigit(av[1][0])) {
  408.         if (info = muAllocGroupInfo()) {
  409.             if (strlen(av[1]) > muGROUPIDSIZE-1) {
  410.                 fprintf(stderr,"%s: string too long for a Group-ID.\n",av[1]);
  411.                 muFreeGroupInfo(info);
  412.                 return 20;
  413.             }
  414.             strcpy(info->GroupID,av[1]);
  415.             if (!(res = muGetGroupInfo(info,muKeyType_GroupID))) {
  416.                 fprintf(stderr,"%s: no valid group.\n",av[1]);
  417.                 muFreeGroupInfo(info);
  418.                 return 20;
  419.             }
  420.             new_gid = info->gid;
  421.             muFreeGroupInfo(info);
  422.         }
  423.         else {
  424.             fprintf(stderr,"Not enough memory.\n");
  425.             return 20;
  426.         }
  427.     }
  428.     else {
  429.         new_gid = myatoi(av[1],0,65535);
  430.         if (atoierr) {
  431.             fprintf(stderr,"UID/GID is a 16-bit wide UWORD (0-65535) !\n");
  432.             return 20;
  433.         }
  434.     }
  435. #else
  436.     new_gid = myatoi(av[1],0,65535);
  437.     if (atoierr) {
  438.         fprintf(stderr,"UID/GID is a 16-bit wide UWORD (0-65535) !\n");
  439.         return 20;
  440.     }
  441. #endif /* MULTIUSER_SUPPORT */
  442.  
  443.     for (i=2; i<ac; i++) {  /* all arguments except first */
  444.  
  445.         if( (dp=dopen(av[i],&stat))) {
  446.             /*printf("%s, gid %d, uid %d\n",av[i],dp->fib->fib_OwnerGID,dp->fib->fib_OwnerUID);*/
  447.             mask = (dp->fib->fib_OwnerUID<<16) + new_gid;
  448.             dclose(dp);
  449.  
  450.             /*printf("  new mask: %ld\n",mask);*/
  451.             if (DOSBase->dl_lib.lib_Version<39) {
  452.                 if( !SetOwner37( av[i], mask ))
  453.                     pError(av[i]);
  454.             }
  455.             else {
  456.                 if( !SetOwner( av[i], mask ))
  457.                     pError(av[i]);
  458.             }
  459.         }
  460.         else
  461.             pError(av[i]);
  462.     }
  463.  
  464.     return 0;
  465. }
  466.  
  467.  
  468.  
  469. #if 0
  470. int do_chown(void)
  471. {
  472.     LONG mask;  /* 2x UWORD */
  473.     UWORD new_id;
  474.     int  i, stat;
  475.     DPTR *dp;
  476.  
  477.     new_id = myatoi(av[1],0,65535);
  478.     if (atoierr) {
  479.         fprintf(stderr,"UID/GID is a 16-bit wide UWORD (0-65535) !\n");
  480.         return 20;
  481.     }
  482.  
  483.     for (i=2; i<ac; i++) {  /* all arguments except first */
  484.  
  485.         if( (dp=dopen(av[i],&stat))) {
  486.             /*printf("%s, gid %d, uid %d\n",av[i],dp->fib->fib_OwnerGID,dp->fib->fib_OwnerUID);*/
  487.             mask = dp->fib->fib_OwnerGID + (new_id<<16);
  488.             dclose(dp);
  489.  
  490.             /*printf("  new mask: %ld\n",mask);*/
  491.             if (DOSBase->dl_lib.lib_Version<39) {
  492.                 if( !SetOwner37( av[i], mask ))
  493.                     pError(av[i]);
  494.             }
  495.             else {
  496.                 if( !SetOwner( av[i], mask ))
  497.                     pError(av[i]);
  498.             }
  499.         }
  500.         else
  501.             pError(av[i]);
  502.     }
  503.  
  504.     return 0;
  505. }
  506.  
  507.  
  508.  
  509. int do_chgrp(void)
  510. {
  511.     LONG mask;  /* 2x UWORD */
  512.     UWORD new_id;
  513.     int  i, stat;
  514.     DPTR *dp;
  515.  
  516.     new_id = myatoi(av[1],0,65535);
  517.     if (atoierr) {
  518.         fprintf(stderr,"UID/GID is a 16-bit wide UWORD (0-65535) !\n");
  519.         return 20;
  520.     }
  521.  
  522.     for (i=2; i<ac; i++) {  /* all arguments except first */
  523.  
  524.         if( (dp=dopen(av[i],&stat))) {
  525.             /*printf("%s, gid %d, uid %d\n",av[i],dp->fib->fib_OwnerGID,dp->fib->fib_OwnerUID);*/
  526.             mask = (dp->fib->fib_OwnerUID<<16) + new_id;
  527.             dclose(dp);
  528.  
  529.             /*printf("  new mask: %ld\n",mask);*/
  530.             if (DOSBase->dl_lib.lib_Version<39) {
  531.                 if( !SetOwner37( av[i], mask ))
  532.                     pError(av[i]);
  533.             }
  534.             else {
  535.                 if( !SetOwner( av[i], mask ))
  536.                     pError(av[i]);
  537.             }
  538.         }
  539.         else
  540.             pError(av[i]);
  541.     }
  542.  
  543.     return 0;
  544. }
  545. #endif
  546.  
  547.  
  548.  
  549. int
  550. do_filenote( void )
  551. {
  552.     DPTR *dp;
  553.     char *note;
  554.     int i, stat;
  555.  
  556.     if( options&1 ) {
  557.         for( i=1; i<ac && !dobreak(); i++ )
  558.             if( dp=dopen( av[i], &stat )) {
  559.                 printf( "%-12s %s\n", av[i],dp->fib->fib_Comment );
  560.                 dclose( dp );
  561.             }
  562.     } else {
  563.         note=av[--ac];
  564.         for (i=1; i<ac; i++) if (!SetComment(av[i], note)) pError(av[i]);
  565.     }
  566.     return 0;
  567. }
  568.  
  569.  
  570.  
  571. long fgetsn(unsigned char *buf, unsigned long buflen, FILE *fp)
  572. {
  573.     long read = 0;
  574.     int c = 0;
  575.     BOOL go_on = TRUE;
  576.  
  577.     if (fp != NULL && buflen > 1) {
  578.         buflen--;
  579.         while (read < buflen && go_on) {
  580.             c = fgetc(fp);
  581.             if (c == '\n') {
  582.                 buf[read++] = c;
  583.                 buf[read] = '\0';
  584.                 go_on = FALSE;
  585.             }
  586.             else if (c == EOF) {
  587.                 buf[read] = '\0';
  588.                 go_on = FALSE;
  589.             }
  590.             else {
  591.                 buf[read++] = c;
  592.                 buf[read] = '\0';
  593.             }
  594.         }
  595.     }
  596.  
  597.     return(read);
  598. }
  599.  
  600.  
  601.  
  602. #if 1
  603. int do_cat( void )
  604. {
  605.     /*
  606.      *  This command is unable to cat binary files like UNIX cat does,
  607.      *  because this command heavily relies on text-based line structure
  608.      *  of a file and cannot handle 0 characters.
  609.      *
  610.      *  The only solution would be to re-program fgets() to return the
  611.      *  number of bytes read and write off each chunk of bytes with
  612.      *  fwrite() instead of fputs().
  613.      *
  614.      *  NOTE: Now binary clean!, -amk[19950405]
  615.      */
  616.     FILE *fi;
  617.     long read;
  618.     int lctr, i, docr = 0;
  619.     char buf[256];
  620.  
  621.     prepscroll(0);
  622.     if (ac<=1) {
  623.         if (has_wild) { printf("No files matching\n"); return 20; }
  624.         lctr=0;
  625.         while ((read=fgetsn(buf,256,stdin))>0 && !dobreak()) {
  626.             if (options) printf("%4d ",++lctr);
  627.             quickscroll();
  628.             fwrite(buf,1L,read,stdout);
  629.             fflush(stdout);
  630.             docr = strchr(buf, '\n')? 0 : 1;
  631.         }
  632.     } else {
  633.         for (i=1; i<ac; i++)
  634.             if (fi = fopen (av[i], "r")) {
  635.                 lctr=0;
  636.                 while ((read=fgetsn(buf,256,fi))>0 && !dobreak()) {
  637.                     if (options&1) printf("%4d ",++lctr);
  638.                     quickscroll();
  639.                     fwrite(buf,1L,read,stdout);
  640.                     fflush(stdout);
  641.                     docr = strchr(buf, '\n')? 0 : 1;
  642.                 }
  643.                 fclose (fi);
  644.             } else
  645.                 pError(av[i]);
  646.     }
  647.     if ( docr && IsInteractive(Output()) )
  648.         putchar('\n');
  649.     return 0;
  650. }
  651. #else
  652. int do_cat( void )
  653. {
  654.     /*
  655.      *  This command is unable to cat binary files like UNIX cat does,
  656.      *  because this command heavily relies on text-based line structure
  657.      *  of a file and cannot handle 0 characters.
  658.      *
  659.      *  The only solution would be to re-program fgets() to return the
  660.      *  number of bytes read and write off each chunk of bytes with
  661.      *  fwrite() instead of fputs().
  662.      */
  663.     FILE *fi;
  664.     int lctr, i, docr=0;
  665.     char buf[256], *l;
  666.  
  667.     prepscroll(0);
  668.     if (ac<=1) {
  669.         if (has_wild) { printf("No files matching\n"); return 20; }
  670.         lctr=0;
  671.         while (fgets(buf,256,stdin) && !dobreak()) {
  672.             if (options) printf("%4d ",++lctr);
  673.             quickscroll();
  674.             l=buf+strlen( buf )-1; docr=1;
  675.             if( l>=buf && *l=='\n' ) docr=0;
  676.             fputs(buf,stdout);
  677.         }
  678.     } else {
  679.         for (i=1; i<ac; i++)
  680.             if (fi = fopen (av[i], "r")) {
  681.                 lctr=0;
  682.                 while (fgets(buf,256,fi) && !dobreak()) {
  683.                     if (options&1) printf("%4d ",++lctr);
  684.                     quickscroll();
  685.                     l=buf+strlen( buf )-1; docr=1;
  686.                     if( l>=buf && *l=='\n' ) docr=0;
  687.                     fputs(buf,stdout); fflush(stdout);
  688.                 }
  689.                 fclose (fi);
  690.             } else
  691.                 pError(av[i]);
  692.     }
  693.     if ( docr && IsInteractive(Output()) )
  694.         putchar('\n');
  695.     return 0;
  696. }
  697. #endif
  698.  
  699.  
  700.  
  701. char *add_simple_device(char *list,char *dev)
  702. {
  703.     char *new = NULL;
  704.  
  705.     if (list) {
  706.         if (new = malloc(strlen(dev)+strlen(list)+2)) {        /* null byte + \n */
  707.             strcpy(new,list);
  708.             strcat(new,dev);
  709.             strcat(new,"\n");
  710.             free(list);
  711.         }
  712.         else
  713.             new = list;
  714.     }
  715.     else {
  716.         if (new = malloc(strlen(dev)+2)) {            /* null byte + \n */
  717.             strcpy(new,dev);
  718.             strcat(new,"\n");
  719.         }
  720.     }
  721.  
  722.     return(new);
  723. }
  724.  
  725.  
  726.  
  727. void
  728. get_drives(char *buf)
  729. {
  730.     struct DosList *dl;
  731.     ULONG flags = LDF_DEVICES|LDF_READ;
  732.     char devname[256];
  733.     char **dev_list=NULL;
  734.     long i,dev_num=0;
  735.  
  736.     buf[0]=0;
  737.     if (dl=LockDosList(flags)) {
  738.         while (dl=NextDosEntry(dl,flags)) {
  739.             if (dl->dol_Task) {
  740.                 BtoCStr(devname,dl->dol_Name,254L);  /* 256 - '\0' + ':' */
  741.                 strcat(devname,":");
  742.                 add_array_list(&dev_list,&dev_num,devname);
  743.             }
  744.         }
  745.         UnLockDosList(flags);
  746.     }
  747.  
  748.     QuickSort(dev_list,dev_num);
  749.  
  750.     for(i=0; i<dev_num; i++) {
  751.         if (IsFileSystem(dev_list[i])) {
  752.             if (buf[0])
  753.                 strcat(buf,"\240");
  754.             strcat(buf,dev_list[i]);
  755.         }
  756.     }
  757.  
  758.     free_array_list(dev_list,dev_num);
  759. }
  760.  
  761. static char infobuf[100];
  762. static char namebuf[32];  /* AMK: old size was 12, too small for drive names */
  763.  
  764.  
  765. /* AMK: find last occurence of a character in a string */
  766. char *strlast(char *s,char c)
  767. {
  768.   char *p=NULL;
  769.   while(*s) {
  770.     if(*s==c)
  771.       p=s;
  772.     s++;
  773.   }
  774.   return(p);
  775. }
  776.  
  777.  
  778. char *
  779. drive_name( char *name )
  780. {
  781.     struct DosList *dl;
  782.     struct MsgPort *proc= (struct MsgPort *)DeviceProc( (void*)name );
  783.     ULONG flags = LDF_DEVICES|LDF_READ;
  784.     char devname[256];
  785.     char **dev_list=NULL;
  786.     long i,dev_num=0;
  787.  
  788.     /* AMK: we want no self-modifying code */
  789.     strncpy( namebuf, name, 31 );   /* AMK: 30 chars device name + ':' */
  790.     namebuf[31] = '\0';             /* AMK: null-terminated */
  791.     if (dl=LockDosList(flags)) {
  792.         while (dl=NextDosEntry(dl,flags)) {
  793.             if (dl->dol_Task) {
  794.                 BtoCStr(devname,dl->dol_Name,254L);  /* 256 - '\0' + ':' */
  795.                 strcat(devname,":");
  796.                 add_array_list(&dev_list,&dev_num,devname);
  797.             }
  798.         }
  799.         UnLockDosList(flags);
  800.     }
  801.  
  802.     QuickSort(dev_list,dev_num);
  803.  
  804.     for(i=0; i<dev_num; i++) {
  805.         if (IsFileSystem(dev_list[i])) {
  806.             if ((struct MsgPort *)DeviceProc(dev_list[i])==proc)
  807.                 strcpy(namebuf,dev_list[i]);
  808.         }
  809.     }
  810.  
  811.     free_array_list(dev_list,dev_num);
  812.  
  813.     return namebuf;
  814. }
  815.  
  816. int
  817. do_info( void )
  818. {
  819.     struct DosList *dl;
  820.     ULONG flags = LDF_DEVICES|LDF_READ;
  821.     char devname[256];
  822.     char **dev_list=NULL;
  823.     long i,dev_num=0;
  824.  
  825.     if (options&2)
  826.         puts("Unit     Size  Block  Type   Used   Free Full Errs  Status    Name");
  827.     else
  828.         puts("Unit     Size  Bytes  Used Blk/Byte-Free Full Errs  Status    Name");
  829.  
  830.     if( ac==1 ) {
  831.         if (dl=LockDosList(flags)) {
  832.             while (dl=NextDosEntry(dl,flags)) {
  833.                 if (dl->dol_Task) {
  834.                     BtoCStr(devname,dl->dol_Name,254L);  /* 256 - '\0' + ':' */
  835.                     strcat(devname,":");
  836.                     add_array_list(&dev_list,&dev_num,devname);
  837.                 }
  838.             }
  839.             UnLockDosList(flags);
  840.         }
  841.  
  842.         QuickSort(dev_list,dev_num);
  843.  
  844.         for(i=0; !dobreak() && i<dev_num; i++) {
  845.             if (IsFileSystem(dev_list[i])) {
  846.                 oneinfo(dev_list[i],0);
  847.             }
  848.         }
  849.  
  850.         free_array_list(dev_list,dev_num);
  851.     }
  852.     else {
  853.         for( i=1; i<ac; i++ )
  854.             oneinfo( drive_name( av[i] ), 0 );
  855.     }
  856.  
  857.     return 0;
  858. }
  859.  
  860.  
  861.  
  862. /* these defines are new in OS 3.x */
  863. #ifndef ID_FASTDIR_DOS_DISK
  864. #define ID_FASTDIR_DOS_DISK (0x444F5304L)
  865. #endif
  866. #ifndef ID_FASTDIR_FFS_DISK
  867. #define ID_FASTDIR_FFS_DISK (0x444F5305L)
  868. #endif
  869.  
  870.  
  871.  
  872. /* AMK: new mode==6 to suppress output if disk is not present */
  873. char *
  874. oneinfo( char *name, int mode )
  875. {
  876.     struct InfoData *info;
  877.     struct DevProc *devproc;
  878.     struct DeviceList *dl;
  879.     BPTR lock;
  880.     long size, free, freebl, blocks;
  881.     char buf[130], *state, *type;
  882.     char *fmt="%s\240%s\240%d\240%d\240%d\240%s\240%d%%\240%d\240%s\240%s";
  883.  
  884.     Myprocess->pr_WindowPtr = (APTR)(-1);
  885.  
  886.     if (!name) name="";
  887.  
  888.     if (mode<=1 || mode>=5)
  889.         strcpy(infobuf,"");
  890.     else
  891.         strcpy(infobuf,"0");
  892.  
  893.     info=(struct InfoData *)SAllocMem(sizeof(struct InfoData),MEMF_PUBLIC|MEMF_CLEAR);
  894.  
  895.     if (devproc=GetDeviceProc(name,NULL)) {
  896.         if (DoPkt(devproc->dvp_Port,ACTION_DISK_INFO,MKBADDR(info),NULL,NULL,NULL,NULL)==DOSTRUE) {
  897.             BOOL go_on = FALSE;
  898.             char *spclfmt;
  899. #if 0
  900.             if (!NameFromLock(lock, buf, 128L)) {
  901.                 fprintf(stderr,"csh.oneinfo: NameFromLock() failed\n");
  902.                 strcpy(buf,name);
  903.             }
  904.             if (p=strlast(buf,':')) *p = '\0';
  905.             /* AMK: we want the last occurence of ':', not the first;
  906.                     ':' and '/' are legal path name components !!
  907.                     (bug only in RAM: disk)
  908.             if (p=index(buf,':')) *p = '\0';
  909.             */
  910. #endif
  911.             switch (mode) {
  912.                 case 0:
  913.                     if (options&1)
  914.                         spclfmt = "";
  915.                     else
  916.                         spclfmt = "%-7s %s\n";
  917.                     break;
  918.                 case 1:
  919.                     spclfmt = "%s\240%s\n";
  920.                     break;
  921.                 case 2:
  922.                 case 3:
  923.                 case 4:
  924.                     spclfmt = "0";
  925.                     break;
  926.                 case 5:
  927.                     spclfmt = "";
  928.                     break;
  929.                 default:
  930.                     spclfmt = "";
  931.                     break;
  932.             }
  933.  
  934.             switch (info->id_DiskType) {
  935.                 case ID_UNREADABLE_DISK:
  936.                     sprintf(infobuf,spclfmt,name,"Unreadable disk");
  937.                     break;
  938.                 case ID_NOT_REALLY_DOS:
  939.                     sprintf(infobuf,spclfmt,name,"Not a DOS disk");
  940.                     break;
  941.                 case ID_KICKSTART_DISK:
  942.                     sprintf(infobuf,spclfmt,name,"Kickstart disk");
  943.                     break;
  944.                 case (0x42555359L):  /* 'BUSY' */
  945.                     sprintf(infobuf,spclfmt,name,"Disk is busy");
  946.                     break;
  947.                 case ID_NO_DISK_PRESENT:
  948.                     sprintf(infobuf,spclfmt,name,"No disk present");
  949.                     break;
  950.                 default:
  951.                     sprintf(infobuf,spclfmt,name,"Unknown disk type");
  952.                     go_on = TRUE;
  953.                     break;
  954.             }
  955.  
  956.             if (go_on && (lock=Lock(name,ACCESS_READ))) {
  957.                 UnLock(lock);
  958.                 /* note:  we call Lock() to be sure that the volume is readable */
  959.  
  960.                 switch(info->id_DiskType) {
  961.                     case ID_MSDOS_DISK:       type=" MSDOS"; break;
  962.                     case ID_DOS_DISK:         type="   OFS"; break;
  963.                     case ID_FFS_DISK:         type="   FFS"; break;
  964.                     case ID_INTER_DOS_DISK:   type="IN/OFS"; break;
  965.                     case ID_INTER_FFS_DISK:   type="  INTL"; break;
  966.                     case ID_FASTDIR_DOS_DISK: type="DC/OFS"; break;
  967.                     case ID_FASTDIR_FFS_DISK: type="  DCFS"; break;
  968.                     default:                  type="   n/a"; break;
  969.                 }
  970.  
  971.                 strcpy(buf,"n/a");
  972.                 if (dl = (struct DeviceList *)BADDR(info->id_VolumeNode))
  973.                     BtoCStr(buf,dl->dl_Name,100L);
  974.  
  975.                 switch(info->id_DiskState) {
  976.                     case ID_WRITE_PROTECTED: state="Read Only "; break;
  977.                     case ID_VALIDATED:       state="Read/Write"; break;
  978.                     case ID_VALIDATING:      state="Validating"; break;
  979.                     default:                 state="Unknown   "; break;
  980.                 }
  981.  
  982. #if 0
  983.                 size   = (info->id_NumBlocks + 2) * info->id_BytesPerBlock;
  984. #endif
  985.                 size   = info->id_NumBlocks * info->id_BytesPerBlock;
  986.                 freebl = info->id_NumBlocks - info->id_NumBlocksUsed;
  987.                 free   = freebl * info->id_BytesPerBlock;
  988.                 blocks = info->id_NumBlocks;
  989. #if 0
  990.                 printf("percents: %s... %ld, %ld, %ld, %ld, %ld\n",name,
  991.                     ((info->id_NumBlocksUsed+2) * 100)/blocks,
  992.                     (info->id_NumBlocksUsed * 100)/(blocks+2),
  993.                     (((info->id_NumBlocksUsed * 1000)/blocks)+5)/10,
  994.                     ((((info->id_NumBlocksUsed+2) * 1000)/blocks)+5)/10,
  995.                     (((info->id_NumBlocksUsed * 1000)/(blocks+2))+5)/10
  996.                 );
  997. #endif
  998.  
  999.                 if (mode==0 && options&2) {
  1000.                     fmt="%-7s%6s%6d %6s %6s %6s %3d%%%4d  %10s %s\n";
  1001.                     sprintf(infobuf,fmt,
  1002.                         name,
  1003.                         itok( size ),
  1004.                         info->id_BytesPerBlock,
  1005.                         type,
  1006.                         itok( info->id_NumBlocksUsed*info->id_BytesPerBlock ),
  1007.                         itok( free ),
  1008.                         (blocks) ? (int)((( (double)info->id_NumBlocksUsed/(double)blocks ) * 1000.0 + 5.0) / 10.0) : 0,
  1009. #if 0
  1010.                         (blocks) ? ((info->id_NumBlocksUsed * 1000)/blocks + 5) / 10 : 0,
  1011. #endif
  1012.                         info->id_NumSoftErrors,
  1013.                         state,
  1014.                         buf);
  1015.                 }
  1016.                 else if (mode<=1) {
  1017.                     if (mode==0) fmt="%-7s%6s%6d%7d%7d %6s%4d%%%4d  %s %s\n";
  1018.                     sprintf(infobuf,fmt,
  1019.                         name,
  1020.                         itok( size ),
  1021.                         info->id_BytesPerBlock,
  1022.                         info->id_NumBlocksUsed,
  1023.                         freebl,
  1024.                         itok( free ),
  1025.                         (blocks) ? (int)((( (double)info->id_NumBlocksUsed/(double)blocks ) * 1000.0 + 5.0) / 10.0) : 0,
  1026.                         info->id_NumSoftErrors,
  1027.                         state,
  1028.                         buf);
  1029.                 }
  1030.                 else if (mode==2) sprintf(infobuf,"%d",free);
  1031.                 else if (mode==3) sprintf(infobuf,"%d",freebl);
  1032.                 else if (mode==4) sprintf(infobuf,"%s",itok(free));
  1033.                 else if (mode==5) sprintf(infobuf,"%s:",buf);
  1034.             }
  1035.         }
  1036.         else
  1037.             pError(name);
  1038.         FreeDeviceProc(devproc);
  1039.     }
  1040.  
  1041. #if 0
  1042.     else {
  1043.         if (mode==1) {
  1044.             struct MsgPort *devtask;
  1045.             sprintf(infobuf,"%s\240No disk present\n",name);
  1046.             if (devtask=(struct MsgPort *)DeviceProc(name)) {
  1047.                 struct InfoData *infodata;
  1048.                 infodata = SAllocMem(sizeof(struct InfoData),MEMF_PUBLIC|MEMF_CLEAR);
  1049.                 if (DoPkt(devtask,ACTION_DISK_INFO,MKBADDR(infodata),NULL,NULL,NULL,NULL)) {
  1050.                     switch (infodata->id_DiskType) {
  1051.                     case ID_UNREADABLE_DISK:
  1052.                         sprintf(infobuf,"%s\240Unreadable disk\n",name);
  1053.                         break;
  1054.                     case ID_NOT_REALLY_DOS:
  1055.                         sprintf(infobuf,"%s\240Not a DOS disk\n",name);
  1056.                         break;
  1057.                     case ID_KICKSTART_DISK:
  1058.                         sprintf(infobuf,"%s\240Kickstart disk\n",name);
  1059.                         break;
  1060.                     case (0x42555359L):  /* 'BUSY' */
  1061.                         sprintf(infobuf,"%s\240Busy\n",name);
  1062.                         break;
  1063.                     case ID_NO_DISK_PRESENT:
  1064.                     default:
  1065.                         sprintf(infobuf,"%s\240No disk present\n",name);
  1066.                         break;
  1067.                     }
  1068.                 }
  1069.                 FreeMem(infodata,sizeof(struct InfoData));
  1070.             }
  1071.         }
  1072.         else if (mode==0) {
  1073.             if (options&1) {
  1074.                 sprintf(infobuf,"");
  1075.             }
  1076.             else {
  1077.                 struct MsgPort *devtask;
  1078.                 sprintf(infobuf,"%-7s No disk present\n",name);
  1079.                 if (devtask=(struct MsgPort *)DeviceProc(name)) {
  1080.                     struct InfoData *infodata;
  1081.                     infodata = SAllocMem(sizeof(struct InfoData),MEMF_PUBLIC|MEMF_CLEAR);
  1082.                     if (DoPkt(devtask,ACTION_DISK_INFO,MKBADDR(infodata),NULL,NULL,NULL,NULL)) {
  1083.                         switch (infodata->id_DiskType) {
  1084.                         case ID_UNREADABLE_DISK:
  1085.                             sprintf(infobuf,"%-7s Unreadable disk\n",name);
  1086.                             break;
  1087.                         case ID_NOT_REALLY_DOS:
  1088.                             sprintf(infobuf,"%-7s Not a DOS disk\n",name);
  1089.                             break;
  1090.                         case ID_KICKSTART_DISK:
  1091.                             sprintf(infobuf,"%-7s Kickstart disk\n",name);
  1092.                             break;
  1093.                         case (0x42555359L):  /* 'BUSY' */
  1094.                             sprintf(infobuf,"%-7s Disk is busy\n",name);
  1095.                             break;
  1096.                             case ID_NO_DISK_PRESENT:
  1097.                         default:
  1098.                             sprintf(infobuf,"%-7s No disk present\n",name);
  1099.                             break;
  1100.                         }
  1101.                     }
  1102.                     FreeMem(infodata,sizeof(struct InfoData));
  1103.                 }
  1104.             }
  1105.         }
  1106.         else if (mode==5) sprintf(infobuf,"");
  1107.         else              sprintf(infobuf,"0");
  1108.     }
  1109. #endif
  1110.  
  1111.     if (mode==0) printf("%s",infobuf);
  1112.  
  1113.     FreeMem(info,sizeof(struct InfoData));
  1114.     Myprocess->pr_WindowPtr = o_noreq ? (APTR) -1L : 0L/*Mywindow*/;
  1115.  
  1116.     return infobuf;
  1117. }
  1118.  
  1119.  
  1120. /* things shared with display_file */
  1121.  
  1122. #define DIR_SHORT 0x1
  1123. #define DIR_FILES 0x2
  1124. #define DIR_DIRS  0x4
  1125. #define DIR_NOCOL 0x8
  1126. #define DIR_NAMES 0x10
  1127. #define DIR_HIDE  0x20
  1128. #define DIR_LEN   0x40
  1129. #define DIR_TIME  0x80
  1130. #define DIR_BACK  0x100
  1131. #define DIR_UNIQ  0x200
  1132. #define DIR_IDENT 0x400
  1133. #define DIR_CLASS 0x800
  1134. #define DIR_QUIET 0x1000
  1135. #define DIR_AGE   0x2000
  1136. #define DIR_VIEW  0x4000
  1137. #define DIR_NOTE  0x8000
  1138. #define DIR_PATH  0x10000
  1139. #define DIR_LFORM 0x20000
  1140. #define DIR_BOT   0x40000
  1141. #define DIR_TOP   0x80000
  1142. #define DIR_LINK  0x100000
  1143.  
  1144. static char *lastpath = NULL;
  1145. static int filecount, dircount, col, colw, wwidth;
  1146. static long bytes, blocks;
  1147.  
  1148. /* the args passed to do_dir will never be expanded */
  1149.  
  1150. extern expand_err;
  1151. extern int w_width;
  1152.  
  1153. static struct DateStamp Stamp;
  1154. static char *LineBuf, *LinePos, LastWasDir, *LFormat, _LFormat[80], NoTitles;
  1155.  
  1156. int
  1157. do_dir( void )
  1158. {
  1159.     int i=1, c, eac, reverse, nump=ac, retcode=0;
  1160.     char **eav=NULL, **av1=NULL, **av2=NULL, inter=IsInteractive(Output());
  1161.     char linebuf[1024];
  1162.     char *fmtstr;
  1163.     int (*func)(), ac1, ac2, factor=0;
  1164.  
  1165.     LineBuf=LinePos=linebuf;
  1166.     LastWasDir=NoTitles=0;
  1167.     colw = -1;
  1168.  
  1169.     LFormat=_LFormat;
  1170.  
  1171.     if( options&DIR_CLASS ) options|=DIR_IDENT;
  1172.     if( !(options & (DIR_FILES | DIR_DIRS))) options|= DIR_FILES | DIR_DIRS;
  1173.  
  1174.     DateStamp( &Stamp );
  1175.  
  1176.     col = filecount = dircount = bytes = blocks = 0L;
  1177.     if (lastpath) free(lastpath);
  1178.     lastpath=NULL;
  1179.  
  1180.     wwidth=77;
  1181.     if( inter )
  1182.         wwidth=w_width;
  1183.  
  1184.     if( options&DIR_SHORT )
  1185.         strcpy(LFormat," %-18n%19m");
  1186.     else if( options&DIR_PATH )
  1187.         strcpy(LFormat," %-50p %7s %d"), NoTitles=1;
  1188.     else {
  1189.         if ( options&DIR_NOTE )
  1190.             strcpy(LFormat,"  %-30n %o");
  1191.         else if ( options&DIR_LINK )
  1192.             strcpy(LFormat,"  %-30n %L");
  1193.         else {
  1194. #if 1
  1195.             strcpy(LFormat,"  ");
  1196. #else
  1197.             strcpy(LFormat,"  %-30n ");
  1198. #endif
  1199.             if( options&DIR_HIDE )
  1200.                 strcat(LFormat, "%e");
  1201.             strcat(LFormat,"%c%I%f ");
  1202.             if( options&DIR_VIEW )
  1203.                 strcat(LFormat,"%10v  ");
  1204.             else
  1205.                 strcat(LFormat,"%8s  ");
  1206. #if 0
  1207.             if( !(options&DIR_QUIET) )
  1208.                 strcat(LFormat,options&DIR_VIEW?"%5b ":"%4b ");
  1209. #endif
  1210.             if( options&DIR_IDENT )
  1211.                 strcat(LFormat,"%-10k");
  1212.             else if( options&DIR_AGE )
  1213.                 strcat(LFormat,"%a");
  1214.             else
  1215.                 strcat(LFormat,"%d %t");
  1216. #if 1
  1217.             strcat(LFormat,"  %N");
  1218. #endif
  1219.         }
  1220.     }
  1221.  
  1222. #if 1
  1223.     /* if option -z, use variable _dirformat or first argument (if no _dirformat) */
  1224.  
  1225.     if ( options&DIR_LFORM ) {
  1226.         if ( fmtstr=get_var(LEVEL_SET,v_dirformat) ) {
  1227.             strncpy(LFormat,fmtstr,79);    /* copy to _LFormat[80] */
  1228.             LFormat[79]=0;
  1229.         }
  1230.         else if (ac>1)
  1231.             LFormat=av[i++];
  1232.         else {
  1233.             show_usage(NULL);
  1234.             return 20;
  1235.         }
  1236.     }
  1237. #else
  1238.     /* variable _dirformat always used, can be overwritten by -z fmt */
  1239.  
  1240.     if ( fmtstr=get_var(LEVEL_SET,v_dirformat) ) {
  1241.         strncpy(LFormat,fmtstr,79);    /* copy to _LFormat[80] */
  1242.         LFormat[79]=0;
  1243.     }
  1244.  
  1245.     if ( options&DIR_LFORM ) {
  1246.         if (ac>1)
  1247.             LFormat=av[i++];
  1248.         else {
  1249.             show_usage(NULL);
  1250.             return 20;
  1251.         }
  1252.     }
  1253. #endif
  1254.  
  1255.     if( ac == i) ++nump, av[i]="";
  1256.     if( options&DIR_UNIQ) {
  1257.         if( ac-i!=2 )  { show_usage(NULL); return 20; }
  1258.         i=0, nump=3;
  1259.     }
  1260.  
  1261.     prepscroll(0);
  1262.     for( ; i<nump && !CHECKBREAK(); ++i ) {
  1263.         if( options&DIR_UNIQ ) {
  1264.             switch( i ) {
  1265.                 case 0: av1=expand( av[ac-2], &ac1 );
  1266.                         av2=expand( av[ac-1], &ac2 );
  1267.                         eav=without( av1, ac1, av2, ac2, &eac, 1 );
  1268.                         break;
  1269.                 case 1: printf("\nCommon files\n");
  1270.                         eav=and( av1, ac1, av2, ac2, &eac, 1 );
  1271.                         break;
  1272.                 case 2: printf("\n");
  1273.                         eav=without( av2, ac2, av1, ac1, &eac, 1 );
  1274.                         break;
  1275.             }
  1276.             col = filecount = dircount = bytes = blocks = 0L;
  1277.             if (lastpath) free(lastpath);
  1278.             lastpath=NULL;
  1279.  
  1280.         /* AMK: enhanced handling of non-matching patterns */
  1281.         } else if (!(eav = expand(av[i], &eac))) {
  1282.             if (IoError) {
  1283.                 ierror(av[i],IoError);
  1284.                 retcode=5;
  1285.             }
  1286. #if 0
  1287.             else {
  1288.                 if (strlen(av[i])>0)
  1289.                     fprintf(stderr,"%s: No match.\n",av[i]);
  1290.             }
  1291. #endif
  1292.             continue;
  1293.         }
  1294.  
  1295.         reverse= ( options&DIR_BACK ) ? 1 : 0;
  1296.         func=cmp;
  1297.         if( options & DIR_TIME) func   = datecmp_csh;
  1298.         if( options & DIR_LEN ) func   = sizecmp;
  1299.         if( options & DIR_CLASS)func   = classcmp;
  1300.         if( options & DIR_BOT ) factor = -99999999;
  1301.         if( options & DIR_TOP ) factor = 99999999;
  1302.         DirQuickSort(eav, eac, func, reverse, factor);
  1303.         for(c=0; c<eac && !CHECKBREAK(); ++c) {
  1304.             if( options & DIR_HIDE ) {
  1305.                 char *b=FilePart(eav[c]);
  1306.                 int  l=strlen(b)-5;
  1307.                 FILEINFO *info =(FILEINFO *)eav[c] - 1;
  1308.                 if(*b=='.'|| (l>=0 && !strcmp(b+l,".info"))||(info->flags&128))
  1309.                     continue;
  1310.             }
  1311.             if (options & DIR_NAMES) {
  1312.                 FILEINFO *info = (FILEINFO *)eav[c] - 1;
  1313.                 if(options&(info->size<0 ? DIR_DIRS: DIR_FILES))
  1314.                     puts(eav[c]);
  1315.             } else
  1316.                 display_file(eav[c]);
  1317.         }
  1318.  
  1319.         if (col) { quickscroll(); puts(LinePos=LineBuf); col=0; }
  1320.  
  1321.         if( LastWasDir )
  1322.             printf(o_lolite), LastWasDir=0;
  1323.  
  1324.         if (options&DIR_UNIQ || (filecount>1 && i==nump-1)) {
  1325.             blocks += filecount-dircount; /* account for dir blocks */
  1326.             quickscroll();
  1327.             printf(" %ld Blocks, %s Bytes used in %d files\n",
  1328.                 blocks, itoa(bytes), filecount);
  1329.         }
  1330.         if( options&DIR_UNIQ )
  1331.             free(eav);
  1332.         else
  1333.             free_expand (eav);
  1334.     }
  1335.     if (lastpath) free(lastpath);
  1336.     lastpath=NULL;
  1337.  
  1338.     if( options&DIR_UNIQ )
  1339.         free_expand( av1 ), free_expand( av2 );
  1340.  
  1341.     return retcode;
  1342. }
  1343.  
  1344. static int MultiCol = -1;
  1345.  
  1346. static char
  1347. pathcomp( char *s1, char *s2 )
  1348. {
  1349.     char ret, *t, c;
  1350.  
  1351.     t=FilePart( s2 ); c = *t; *t=0;
  1352.     ret=stricmp( s1, s2 );
  1353.     *t=c;
  1354.     return ret;
  1355. }
  1356.  
  1357. static void
  1358. display_file( char *filestr )
  1359. {
  1360.     /* struct InfoData *id=AllocMem( sizeof(struct InfoData), 0); */
  1361.     int isadir, len, collen;
  1362.     char sc, *base, buf[1024], *hilite;
  1363.     FILEINFO *info;
  1364.     BPTR thislock;
  1365.  
  1366.     base=FilePart(filestr);
  1367.     sc = *base;
  1368.     *base = 0;
  1369.     /* if (thislock==NULL) return; */
  1370.     if( !NoTitles ) {
  1371.         if( !lastpath || pathcomp( filestr, lastpath)) {
  1372.             if(!(thislock=Lock(filestr,SHARED_LOCK)))
  1373.                 return;
  1374.             if (col) { quickscroll(); puts(LinePos=LineBuf); col=0; }
  1375.             quickscroll();
  1376.             if (!NameFromLock(thislock, buf, 256)) {
  1377.                 fprintf(stderr,"csh.display_file: NameFromLock() failed\n");
  1378.                 strcpy(buf,filestr);
  1379.             }
  1380.             if( LastWasDir )
  1381.                 printf(o_lolite), LastWasDir=0;
  1382.             printf("Directory of %s\n", buf );
  1383.             /* Info( thislock, id ); */
  1384.             /* itok((id->id_NumBlocks-id->id_NumBlocksUsed)*id->id_BytesPerBlock));*/
  1385.             /* FreeMem( id, sizeof(struct InfoData)); */
  1386.             lastpath = salloc(256);
  1387.             strcpy(lastpath,filestr);
  1388.             /*lastpath=filestr;*/
  1389.             UnLock(thislock);
  1390.         }
  1391.     }
  1392.     *base    = sc;
  1393.  
  1394.     info   = (FILEINFO *)filestr - 1;
  1395.     isadir = info->size<0;
  1396.  
  1397.     if( !(options & (isadir ? DIR_DIRS : DIR_FILES)))
  1398.         return;
  1399.  
  1400.     hilite="";
  1401.     if (isadir!=LastWasDir && !(options & DIR_NOCOL))
  1402.         hilite=isadir ? o_hilite : o_lolite, LastWasDir=isadir;
  1403.  
  1404.     lformat(LFormat, buf, info);
  1405.  
  1406.     if( MultiCol == -1 ) {
  1407.         quickscroll();
  1408.         printf("%s%s",hilite,buf);
  1409.     } else {
  1410.         len=strlen(buf);
  1411.         if( col+len>wwidth ) {
  1412.             quickscroll();
  1413.             puts(LineBuf);
  1414.             LinePos=LineBuf; col=0;
  1415.         }
  1416.         if( MultiCol )
  1417.             colw=MultiCol;
  1418.         else if( colw == -1 )
  1419.             colw=len;
  1420.         collen= (len+colw-1)-(len+colw-1)%colw;
  1421.         col+=collen;
  1422.         LinePos+=sprintf(LinePos,"%s%-*s",hilite,collen,buf);
  1423.     }
  1424.  
  1425.     if(info->size>0)
  1426.         bytes  += info->size;
  1427.     blocks += info->blocks;
  1428.     filecount++;
  1429. }
  1430.  
  1431. static char linebuf[1024];
  1432. static long dlen, dblocks;
  1433.  
  1434. static int
  1435. count( long mask, char *s, char *path )
  1436. {
  1437.     FIB *fib=(FIB*)s-1;
  1438.     dlen+=fib->fib_Size;
  1439.     dblocks+=fib->fib_NumBlocks+1;
  1440.     return 0;
  1441. }
  1442.  
  1443.  
  1444. /* code contribution by Carsten Heyl, modified by AMK */
  1445. void ReadSoftLink(char *path, char *buf, int buflen)
  1446. {
  1447.     BPTR MyLock;
  1448.     BPTR DevLock;
  1449.     LONG Err, l;
  1450.     UBYTE *bs;
  1451.     struct MsgPort *port;
  1452.  
  1453.     if (buflen>9)
  1454.         strcpy(buf,"<unknown>");
  1455.     else
  1456.         buf[0] = '\0';    /* just terminate buffer. alternative ? */
  1457.  
  1458.     if ( (l=strlen(path)) > 254 )
  1459.         return;
  1460.  
  1461.     if (!(bs=AllocMem(256,MEMF_CLEAR|MEMF_PUBLIC)))
  1462.         return;
  1463.  
  1464.     bs[255] = '\0';
  1465.  
  1466.     /* build BCPL string */
  1467.     bs[0] = l;
  1468.     memcpy(&bs[1], path, l+1);
  1469.  
  1470.     /* GetDeviceProc or DeviceProc? */
  1471.     if (!(port = DeviceProc(path))) {
  1472.         FreeMem(bs,256);
  1473.         return;
  1474.     }
  1475.  
  1476.     DevLock = (BPTR)IoErr();
  1477.  
  1478.     MyLock = DoPkt(port,ACTION_LOCATE_OBJECT,DevLock,MKBADDR(bs),
  1479.                 ACCESS_READ,NULL,NULL);
  1480.     Err = IoErr();
  1481.  
  1482.     if (!MyLock && (Err==ERROR_IS_SOFT_LINK)) {
  1483. #if 0
  1484.         ReadLink(port,DevLock,(UBYTE *)path,(UBYTE *)buf,buflen);
  1485. #else
  1486.         DoPkt(port,ACTION_READ_LINK,DevLock,(LONG)path,(LONG)buf,buflen,NULL);
  1487. #endif
  1488.     }
  1489.  
  1490.     if (MyLock) UnLock(MyLock);
  1491.     FreeMem(bs,256);
  1492. }
  1493.  
  1494.  
  1495. void
  1496. lformat( char *s, char *d, FILEINFO *info )
  1497. {
  1498.     long mi=0;
  1499.     char buf[1024], *w, *class;
  1500.     DPTR *dp;
  1501.     int stat, i, form, sign, cut, size=info->size;
  1502.     char *(*func)(int num);
  1503.  
  1504.     MultiCol = -1;
  1505.     while( *s ) {
  1506.         if( *s!='%' ) { *d++ = *s++; continue; }
  1507.         sign=1; form=0; cut=0; s++;
  1508.         if( *s=='-' ) s++, sign = -1;
  1509.         if( *s=='.' ) s++, cut=1;
  1510.         while( *s>='0' && *s<='9' ) form=10*form+*s++-'0';
  1511.         w=buf; w[0]=0; w[1]=0;
  1512.         switch( *s ) {
  1513.         case 'p': strcpy(w,(char *)(info+1));             break;
  1514.         case 'b': sprintf(w,size>=0 ? "%d":"", info->blocks); break;
  1515.         case 's': sprintf(w,size>=0 ? "%d":"<Dir>",size); break;
  1516.         case 'i': *w= size>=0 ? '-' : 'd';                break;
  1517.         case 'r':
  1518.         case 'u':
  1519.             if( *s=='r' ) func=itoa; else func=itok;
  1520.             strcpy( w,size>=0 ? (*func)(size) : "<Dir>");
  1521.             break;
  1522.         case 'n':
  1523.         case 'q':
  1524.             strcpy(w,FilePart((char *)(info+1)));
  1525.             if( *s=='q' && size<0 ) strcat(w,"/");
  1526.             break;
  1527.         case 'l':
  1528.             if( info->flags & INFO_COMMENT ) *w='\n';
  1529.             break;
  1530.         case 'c':
  1531.             *w= info->flags & INFO_COMMENT ? 'c' : '-';
  1532.             break;
  1533.         case 'e':
  1534.             *w= info->flags & INFO_INFO ? 'i' : '-';
  1535.             break;
  1536.         case '+':
  1537.             *w= info->flags & INFO_INFO ? '+' : ' ';
  1538.             break;
  1539.         case 'L':
  1540.         case 'N':
  1541.             if (*s=='N')
  1542.                 strcpy(w,FilePart((char *)(info+1)));
  1543.             else
  1544.                 strcpy(w,"");
  1545.             if (info->type==ST_SOFTLINK) {
  1546.                 strcat(w," -> ");
  1547.                 ReadSoftLink((char *)(info+1),w+strlen(w),256);
  1548.             }
  1549.             else if (info->type==ST_LINKDIR || info->type==ST_LINKFILE) {
  1550.                 BPTR lock;
  1551.                 if (lock=Lock((char *)(info+1),ACCESS_READ)) {
  1552.                     strcat(w," -> ");
  1553.                     if (!NameFromLock(lock,w+strlen(w),256)) {
  1554.                         fprintf(stderr,"csh.lformat: NameFromLock() failed\n");
  1555.                         strcpy(w+strlen(w),(char *)(info+1));
  1556.                     }
  1557.                     UnLock(lock);
  1558.                 }
  1559.             }
  1560.             break;
  1561.         case 'I':
  1562.             switch (info->type) {
  1563.                 case ST_SOFTLINK:
  1564.                     *w='S';
  1565.                     break;
  1566.                 case ST_LINKDIR:
  1567.                 case ST_LINKFILE:
  1568.                     *w='H';
  1569.                     break;
  1570.                 case ST_PIPEFILE:
  1571.                     *w='P';
  1572.                     break;
  1573.                 default:
  1574.                     *w='-';
  1575.                     break;
  1576.             }
  1577.             break;
  1578.         case 'f': /* standard flags */
  1579.             for (i=7; i>=0; i--)
  1580.                 *w++ = (info->flags^15) & (1L<<i) ? "hsparwed"[7-i] : '-';
  1581.             *w=0;
  1582.             break;
  1583.         case 'F': /* group/other flags */
  1584.             for (i=3; i>=0; i--)
  1585.                 *w++ = (info->flags^15) & (1L<<(i+8)) ? "rwed"[3-i] : '-';
  1586.             *w++ = ' ';
  1587.             for (i=3; i>=0; i--)
  1588.                 *w++ = (info->flags^15) & (1L<<(i+12)) ? "rwed"[3-i] : '-';
  1589.             *w=0;
  1590.             break;
  1591.         case 'U': /* user-id */
  1592.             sprintf(w,"%d",info->uid);
  1593.             break;
  1594.         case 'G': /* group-id */
  1595.             sprintf(w,"%d",info->gid);
  1596.             break;
  1597.         case 'a':
  1598.             if( Stamp.ds_Days!=0 ) {
  1599.                 mi =Stamp.ds_Days*1440 + Stamp.ds_Minute;
  1600.                 mi-=info->date.ds_Days*1440 + info->date.ds_Minute;
  1601.             }
  1602.             sprintf(w,mi>=0?"%4d days %02d:%02d":"Future    ",
  1603.                       mi/1440,mi/60%60,mi%60);
  1604.             break;
  1605.         case 'o':
  1606.             if( dp=dopen( (char *)(info+1), &stat )) {
  1607.                 strcpy( w, dp->fib->fib_Comment );
  1608.                 dclose( dp );
  1609.             }
  1610.             break;
  1611.         case 'v':
  1612.         case 'w':
  1613.             if( *s=='v' ) func=itoa; else func=itok;
  1614.             dlen=dblocks=0;
  1615.             if( size<0 ) {
  1616.                 newrecurse( SCAN_DIR|SCAN_FILE|SCAN_RECURSE,
  1617.                             (char *)(info+1),count);
  1618.                 strcpy( w, (*func)(dlen));
  1619.                 info->size=size=dlen; info->blocks=dblocks;
  1620.             } else
  1621.                 strcpy( w, (*func)(size));
  1622.             break;
  1623.         case 'k':
  1624.             if( *info->class!=1 )
  1625.                 strcpy(w,info->class);
  1626.             else if( class=getclass((char *)(info+1)))
  1627.                 if( w=index(strncpy(w,class,50),0xA0) )
  1628.                     *w=0;
  1629.             break;
  1630.         case 'x':
  1631.         case 'd':
  1632.             sprintf(w,"%9.9s",dates(&info->date,*s=='x'));
  1633. #if 0
  1634. /*
  1635.  *  the sprint() already relies on the fact that the date string
  1636.  *  is exactly 9 characters long, so we don't need to search for
  1637.  *  spaces or do other fancy stuff ;-)
  1638.  */
  1639.             /* strip off after first space */
  1640.             if (t=strchr(w,' '))
  1641.                 *t='\0';
  1642. #endif
  1643.             break;
  1644.         case 't':
  1645.             sprintf(w,"%8s", next_word(dates(&info->date,0)));
  1646.             break;
  1647.         case 'm': MultiCol = form; form = 0;    break;
  1648.         case '%': *w = *++s;                    break;
  1649.         case  0 : *w = '%';                     break;
  1650.         default : *w = '%';  *w++ = *s; *w = 0; break;
  1651.         }
  1652.         if( cut ) buf[form]=0;
  1653.         *d=0; s++;
  1654.         d+=sprintf(d,sign<0?"%-*s":"%*s",form,buf);
  1655.     }
  1656.     if( MultiCol == -1 ) { *d++='\n'; }
  1657.     *d=0;
  1658. }
  1659.  
  1660.  
  1661.  
  1662. extern BOOL nologout;    /* defined in main.c */
  1663.  
  1664. int
  1665. do_quit( void )
  1666. {
  1667.     if (Src_stack) {
  1668.         Quit = 1;
  1669.         return(do_return());
  1670.     }
  1671.     if (!nologout) {
  1672.         if( exists("S:.logout"))
  1673.             execute("source S:.logout");
  1674.     }
  1675.     main_exit(0);
  1676.     return 0;
  1677. }
  1678.  
  1679. int
  1680. do_echo( void )
  1681. {
  1682.     char *args=compile_av(av,1,ac,' ',0);
  1683.     fprintf( (options&2)?stderr:stdout, (options&1)?"%s":"%s\n",args );
  1684.     free(args);
  1685.     return 0;
  1686. }
  1687.  
  1688.  
  1689. static int
  1690. breakcheckd(void)
  1691. {
  1692.     long sigs = SetSignal(0L,0L);
  1693.     int ret=!o_nobreak && (sigs & SIGBREAKF_CTRL_D);
  1694.     if (ret)
  1695.         fprintf(stderr,"^D\n");
  1696.     return ret;
  1697. }
  1698.  
  1699. static int
  1700. breakchecke(void)
  1701. {
  1702.     long sigs = SetSignal(0L,0L);
  1703.     int ret=!o_nobreak && (sigs & SIGBREAKF_CTRL_E);
  1704.     if (ret)
  1705.         fprintf(stderr,"^E\n");
  1706.     return ret;
  1707. }
  1708.  
  1709.  
  1710. /* gets a line from file, joining lines if they end in '\' */
  1711.  
  1712. #define MAXLINE 512
  1713.  
  1714. static int
  1715. srcgets(char **buf, int *buflen, FILE *file)
  1716. {
  1717.     char *bufptr = *buf, *p, *new, concat=0, cont;
  1718.     int   totlen=0, len;
  1719.  
  1720.     do {
  1721.         if( totlen+MAXLINE > *buflen ) {
  1722.             new=salloc(*buflen *= 2);
  1723.             memcpy( new, *buf, 1+bufptr-*buf );
  1724.             bufptr+= new-*buf;
  1725.             free(*buf);
  1726.             *buf=new;
  1727.         }
  1728.         if (fgets(bufptr, MAXLINE, file)==NULL) {
  1729.             if( concat )
  1730.                 fprintf(stderr,"Source: missing '}'\n");
  1731.             else if (bufptr != *buf)
  1732.                 fprintf(stderr,"Source: file ends in '\\'\n");
  1733.             return -1;
  1734.         }
  1735.         len= strlen( bufptr );
  1736.         totlen+= len;
  1737.  
  1738.         cont=0;
  1739.  
  1740.         p=bufptr+len-1;
  1741.         if(  p>=bufptr && *p=='\n') *p--=0;
  1742.         if(  p< bufptr   ) ;
  1743.         else if( *p=='\\') *p--=0, cont=1;
  1744.         else if( *p=='{' ) concat++;
  1745.         else if( *p=='}' ) {
  1746.             if( concat>0 ) {
  1747.                 concat--;
  1748.                 if( concat ) *++p='\n';
  1749.             }
  1750.         } else if( concat ) *++p='\n';
  1751.         bufptr = ++p;
  1752.     } while( cont || concat );
  1753.     *bufptr=0;
  1754.     return totlen;
  1755. }
  1756.  
  1757.  
  1758.  
  1759. int
  1760. do_source( char *str )
  1761. {
  1762.     FILE *fi;
  1763.     char *buf;
  1764.     ROOT *root;
  1765.     int  retcode, len, bufsize=512+MAXLINE;
  1766.     int j;
  1767.     char *ptr;
  1768.  
  1769.     if (Src_stack == MAXSRC) {
  1770.         ierror(NULL,217);
  1771.         return -1;
  1772.     }
  1773.  
  1774.     if ((fi = fopen (av[1], "r")) == 0)
  1775.         { pError(av[1]); return -1;    }
  1776.  
  1777.     push_locals(root=(ROOT *)salloc( sizeof(ROOT)));
  1778.     buf=salloc(bufsize);
  1779.  
  1780.     set_var(LEVEL_SET | LEVEL_LOCAL, v_passed, next_word(next_word(str)));
  1781.  
  1782.  
  1783.     /*
  1784.      * now create a bunch of positional parameters , $0, $1 etc
  1785.      */
  1786.     j = 0;
  1787.     ptr = next_word (str);
  1788.     while (*ptr) {
  1789.         char *var;
  1790.         char p[6];
  1791.         char npos[6];
  1792.  
  1793.         var = ptr;
  1794.         sprintf (p, "%d", j);
  1795.         /*
  1796.          * term var str
  1797.          */
  1798.         ptr = next_word (ptr);
  1799.  
  1800.         /* printf("%s\n" , ptr); */
  1801.  
  1802.         if (*ptr)
  1803.             *(ptr - 1) = '\0';
  1804.  
  1805.         set_var (LEVEL_SET | LEVEL_LOCAL, p, var);
  1806.         /*
  1807.          * now set up what should be $# ( number of positionals )
  1808.          */
  1809. #if 0
  1810.         sprintf (p, "_N");    /* should be "#" but csh barfs :( */
  1811. #endif
  1812.         sprintf (p, "#");    /* hackin' */
  1813.         sprintf (npos, "%d", j++);
  1814.         set_var (LEVEL_SET | LEVEL_LOCAL, p, npos);
  1815.     }
  1816.  
  1817.  
  1818.     Src_pos  [Src_stack] = 0;
  1819.     Src_abort[Src_stack] = 0;
  1820.     Src_base [Src_stack] = fi;
  1821.     Src_if[Src_stack]=If_stack;
  1822.     ++Src_stack;
  1823.     while ((len=srcgets(&buf, &bufsize, fi))>=0&& !dobreak()&& !breakcheckd()){
  1824.         Src_pos[Src_stack-1] += len;
  1825.         if (Verbose&VERBOSE_SOURCE && !forward_goto)
  1826.             if( Verbose&VERBOSE_HILITE )
  1827.                 fprintf(stderr,"%s)%s%s\n",o_hilite,buf,o_lolite);
  1828.             else
  1829.                 fprintf(stderr,")%s\n",buf);
  1830.         retcode=execute(buf);
  1831.         if( retcode>=o_failat || Src_abort[Src_stack-1] )
  1832.             break;
  1833.         retcode=0;
  1834.     }
  1835.     --Src_stack;
  1836.     if( If_stack>Src_if[Src_stack] )
  1837.         If_stack=Src_if[Src_stack], disable=If_stack && If_base[If_stack-1];
  1838.  
  1839.     if (forward_goto) ierror(NULL,501);
  1840.     forward_goto = 0;
  1841.     unset_level(LEVEL_LABEL+ Src_stack);
  1842.     unset_var(LEVEL_SET, v_gotofwd);
  1843.     unset_var(LEVEL_SET, v_passed);
  1844.     fclose (fi);
  1845.  
  1846.     pop_locals();
  1847.     free(buf);
  1848.     free(root);
  1849.  
  1850.     return retcode;
  1851. }
  1852.  
  1853. /* set process cwd name and $_cwd, if str != NULL also print it. */
  1854.  
  1855. void
  1856. set_cwd(void)
  1857. {
  1858.     char pwd[256];
  1859.  
  1860.     if (!NameFromLock(Myprocess->pr_CurrentDir, pwd, 254)) {
  1861.         fprintf(stderr,"csh.set_cwd: NameFromLock() failed\n");
  1862.         strcpy(pwd,"<unknown>");
  1863.     }
  1864.     set_var(LEVEL_SET, v_cwd, pwd);
  1865.     /* put the current dir name in our CLI task structure */
  1866.     CtoBStr(pwd, Mycli->cli_SetName, 254);
  1867. }
  1868.  
  1869. int
  1870. do_pwd( void )
  1871. {
  1872.     set_cwd();
  1873.     puts( get_var( LEVEL_SET, v_cwd ));
  1874.     return 0;
  1875. }
  1876.  
  1877.  
  1878. /*
  1879.  * CD
  1880.  *
  1881.  * CD(str, 0)      -do CD operation.
  1882.  *
  1883.  */
  1884.  
  1885. extern int qcd_flag;
  1886.  
  1887. static char lastqcd[256];
  1888. static FILE *qcdfile;
  1889. static int  NumDirs;
  1890.  
  1891. static int
  1892. countfunc( long mask, char *file, char *fullpath )
  1893. {
  1894.     fprintf( qcdfile, "%s\n", fullpath );
  1895.     fprintf( stdout, "\r Directories: %d", ++NumDirs );
  1896.     fflush ( stdout );
  1897.     return 0;
  1898. }
  1899.  
  1900. int
  1901. do_cd(void)
  1902. {
  1903.     BPTR oldlock, filelock;
  1904.     char buf[256], *old, *str=av[1];
  1905.     int  i=1, repeat;
  1906.  
  1907.     if( options & 1 ) {
  1908.         if( !o_csh_qcd ) { fprintf(stderr,"$_qcd unset\n"); return 20; }
  1909.         if( !(qcdfile=fopen( o_csh_qcd, "w" )))
  1910.             { fprintf(stderr,"Can't open output\n"); return 20; }
  1911.         for( ; i<ac && !dobreak(); i++ ) {
  1912.             NumDirs=0;
  1913.             printf("%s\n",av[i]);
  1914.             newrecurse( SCAN_DIRENTRY | SCAN_RECURSE, av[i], countfunc );
  1915.             printf("\n");
  1916.         }
  1917.         fclose(qcdfile);
  1918.         return 0;
  1919.     }
  1920.  
  1921.     if ( !str || !(*str) ) {    /* old "!*str" causes enforcer hit! */
  1922.         printf("%s\n", get_var( LEVEL_SET, v_cwd ));
  1923.         return 0;
  1924.     }
  1925.  
  1926.     if (filelock=Lock(str,ACCESS_READ)) {
  1927.         lastqcd[0]=0;
  1928.         if (!isdir(str)) { UnLock(filelock); ierror(str,212); return 20; }
  1929.     } else {
  1930.         repeat= !strncmp( lastqcd, str, 255 );
  1931.         strncpy( lastqcd, str, 255 );
  1932.  
  1933.         if( !quick_cd( buf, av[i], repeat) )
  1934.             { fprintf(stderr,"Object not found %s\n",str); return 20; }
  1935.         if (!(filelock=Lock(buf,ACCESS_READ)))
  1936.             { pError(buf); return 20; }
  1937.     }
  1938.     if (oldlock=CurrentDir(filelock)) UnLock(oldlock);
  1939.     if( !(old=get_var(LEVEL_SET, v_cwd)) )
  1940.         old="";
  1941.     set_var(LEVEL_SET, v_lcd, old);
  1942.     set_cwd();
  1943.  
  1944.     return 0;
  1945. }
  1946.  
  1947. char *
  1948. quick_cd( char *buf, char *name, int repeat )
  1949. {
  1950.     if( !o_csh_qcd || !exists(o_csh_qcd))
  1951.         return NULL;
  1952.     qcd_flag=repeat ? 2 : 1;
  1953.     strcpy(buf,name);
  1954.     if( quicksearch( o_csh_qcd, 1, buf)!=2 )
  1955.         return NULL;
  1956.     return buf;
  1957. }
  1958.  
  1959.  
  1960. /* AMK: mkdir now builds path to destination directory if neccessary */
  1961. int
  1962. do_mkdir( void )
  1963. {
  1964.     int i;
  1965.     BPTR lock;
  1966.     char *p,c;
  1967.  
  1968.     for (i=1; i<ac; ++i) {
  1969.  
  1970.         /* Are there any sub-directories to build? */
  1971.         if( options&1 && (p=strchr(av[i],'/'))) {
  1972.             do {
  1973.                 c = *p;
  1974.                 *p = '\0';
  1975.                 if (lock=CreateDir(av[i]))
  1976.                     UnLock(lock);
  1977.                 *p = c;
  1978.             } while(p=strchr(++p,'/'));
  1979.         }
  1980.  
  1981.         /* allow trailing slash */
  1982.         if (lastch(av[i]) == '/' )
  1983.             av[i][strlen(av[i])-1] = '\0';
  1984.  
  1985.         /* Okay, sub-directories should exist, now try normal mkdir. */
  1986.  
  1987.         if (lock=CreateDir(av[i]))
  1988.             UnLock(lock);
  1989.         else
  1990.             pError(av[i]);
  1991.  
  1992.     }
  1993.  
  1994.     return 0;
  1995. }
  1996.  
  1997. int
  1998. do_mv( void )
  1999. {
  2000.     char *dest, buf[256];
  2001.     int dirflag, i, len;
  2002.  
  2003.     dirflag=isdir(dest=av[--ac]);
  2004.     if (ac>3 && !dirflag) { ierror(dest, 507); return (-1); }
  2005.     for (i=1; i<ac; ++i) {
  2006.         strcpy(buf, dest);
  2007.  
  2008.         /* source: remove trailing slash */
  2009.         if ((len=strlen(av[i]))>1 && av[i][len-1]=='/' && av[i][len-2]!=':' && av[i][len-2]!='/')
  2010.             av[i][len-1] = '\0';
  2011.  
  2012.         /* destination: remove trailing slash */
  2013.         if ((len=strlen(buf))>1 && buf[len-1]=='/' && buf[len-2]!=':' && buf[len-2]!='/')
  2014.             buf[len-1] = '\0';
  2015.  
  2016.         if (dirflag && stricmp(av[i],buf))
  2017.              AddPart(buf, FilePart(av[i]), 255L);
  2018.  
  2019.         if (Rename(av[i], buf)==0) {
  2020.             pError(av[i]);
  2021.             if (!(options&1))
  2022.                 return -1;
  2023.         }
  2024.         else {
  2025.             clear_archive_bit( buf );
  2026.             if (options&2) {
  2027.                 /*printf("Renaming %s as %s\n",av[i],buf);*/
  2028.                 printf(" %s...%s\n",av[i],dirflag?"moved":"renamed");
  2029.             }
  2030.         }
  2031.     }
  2032.     return 0;
  2033. }
  2034.  
  2035. static char *searchstring;
  2036. static char docr;
  2037.  
  2038. #if 0
  2039. int
  2040. all_args( int (*action)FUNCARG(long,char*,char*), int dirsflag )
  2041. {
  2042.     int  i;
  2043.     long mask= SCAN_FILE;
  2044.  
  2045.     if( options&1 )
  2046.         mask |= SCAN_RECURSE;
  2047.     if( dirsflag )
  2048.         mask |= SCAN_DIR;
  2049.  
  2050.     for ( i=1; i<ac && !dobreak(); ++i)
  2051.         if (isdir(av[i])) {
  2052.             if (options & 1)
  2053.                 newrecurse(mask, av[i], action);
  2054.             if (dirsflag)
  2055.                 (*action)(SCAN_DIR,av[i],av[i]);
  2056.         } else
  2057.             (*action)(SCAN_FILE,av[i],av[i]);
  2058.     if(docr) printf("\n"),docr=0;
  2059.     dobreak();
  2060.     return 0;
  2061. }
  2062. #endif
  2063.  
  2064. /* this is all_args() but with a user definable range from n to m */
  2065. int
  2066. all_args_n2m( int (*action)FUNCARG(long,char*,char*), int dirsflag, int aa_from, int aa_to )
  2067. {
  2068.     int  i;
  2069.     long mask= SCAN_FILE;
  2070.  
  2071.     if( options&1 )
  2072.         mask |= SCAN_RECURSE;
  2073.     if( dirsflag )
  2074.         mask |= SCAN_DIR;
  2075.  
  2076.     for ( i=aa_from; i<aa_to && !dobreak(); ++i)
  2077.         if (isdir(av[i])) {
  2078.             if (options & 1)
  2079.                 newrecurse(mask, av[i], action);
  2080.             if (dirsflag)
  2081.                 (*action)(SCAN_DIR,av[i],av[i]);
  2082.         } else
  2083.             (*action)(SCAN_FILE,av[i],av[i]);
  2084.     if(docr) printf("\n"),docr=0;
  2085.     dobreak();
  2086.     return 0;
  2087. }
  2088.  
  2089. int
  2090. all_args( int (*action)FUNCARG(long,char*,char*), int dirsflag )
  2091. {
  2092.     return( all_args_n2m(action,dirsflag,1,ac) );
  2093. }
  2094.  
  2095. #define SEARCH_REC   1
  2096. #define SEARCH_CASE  2
  2097. #define SEARCH_WILD  4
  2098. #define SEARCH_NUM   8
  2099. #define SEARCH_EXCL  16
  2100. #define SEARCH_QUIET 32
  2101. #define SEARCH_VERB  64
  2102. #define SEARCH_BIN   128
  2103. #define SEARCH_FILE  256
  2104. #define SEARCH_ABORT 512
  2105. #define SEARCH_LEFT  1024
  2106. #define SEARCH_ONLY  2048
  2107.  
  2108. /* added by amk, not yet implemented */
  2109. #define SEARCH_STYLE 4096    /* alternative style, inspired by GMD */
  2110. #define SEARCH_ONCE  8192    /* only show first pattern match per file */
  2111.  
  2112. static int abort_search;
  2113. static char lowbuf[256], file_name, file_cr;
  2114.  
  2115. static int
  2116. search_file( long mask, char *s, char *fullpath )
  2117. {
  2118.     PATTERN *pat;
  2119.     FILE *fi;
  2120.     char *p, *q;
  2121.     int nocasedep, lctr, len, excl=((options & 16) !=0 ), yesno;
  2122.     char buf[256], searchit[120], first, left;
  2123.  
  2124.     if( abort_search )
  2125.         return 0;
  2126.  
  2127.     nocasedep=!(options & SEARCH_CASE);
  2128.     lctr= docr= file_name= file_cr= 0;
  2129.     if (!(options & (SEARCH_QUIET|SEARCH_FILE))) {
  2130.         if( options & SEARCH_VERB )
  2131.             printf("Examining %s ...\n",fullpath);
  2132.         else
  2133.             printf("\015Examining %s ...\033[K",fullpath), docr=1;
  2134.         fflush( stdout );
  2135.     }
  2136.  
  2137.     strcpy(searchit,searchstring);
  2138.     if (options & SEARCH_WILD) strcat(searchit,"\n");
  2139.     len=strlen(searchit);
  2140.     if (nocasedep) strupr(searchit);
  2141.     first = *searchit;
  2142.  
  2143.     if( strcmp("STDIN",s) && !(options&SEARCH_WILD) && !excl ||
  2144.                  options&SEARCH_BIN )
  2145.         if( quicksearch(s,nocasedep,searchit) )
  2146.             return 0;
  2147.  
  2148.     if( options&SEARCH_BIN )
  2149.         { fprintf(stderr,"Out of memory\n"); return 20; }
  2150.  
  2151.     if(!(pat=compare_preparse( searchit, options&SEARCH_CASE )))
  2152.         { fprintf(stderr,"Invalid pattern\n"); return 20; }
  2153.  
  2154.     fi = strcmp("STDIN",s) ?  fopen(s,"r") : stdin;
  2155.     if (fi==NULL) { pError(s); return 20; }
  2156.  
  2157.     prepscroll(0);
  2158.  
  2159.     while (fgets(buf,256,fi) && !dobreak()) {
  2160.         lctr++; left=1;
  2161.         if (options & SEARCH_WILD)
  2162.             yesno=compare_ok(pat, p=buf);
  2163.         else {
  2164.             if (nocasedep) {
  2165.                 strcpy(lowbuf,buf);
  2166.                 strupr(lowbuf);
  2167.                 p=lowbuf;
  2168.             } else
  2169.                 p=buf;
  2170.             q=p;
  2171.             while ((p=index(p,first)) && strncmp(p++,searchit,len)) ;
  2172.             yesno= (p!=NULL);
  2173.             left = --p - q;
  2174.         }
  2175.         if( yesno ^ excl )
  2176.             if(!(options&SEARCH_ONLY)|| !isalphanum(p[-1])&&!isalphanum(p[len]))
  2177.                 if( found(buf, lctr, 0, s, left ) )
  2178.                     break;
  2179.     }
  2180.     compare_free(pat);
  2181.     if (fi!=stdin) fclose (fi);
  2182.     if( file_cr ) printf("\n");
  2183.     return 0;
  2184. }
  2185.  
  2186. int qcd_flag, qcd_offs;
  2187.  
  2188. #define READCHUNK 60000
  2189.  
  2190. static int
  2191. quicksearch( char *name, int nocasedep, char *pattern )
  2192. {
  2193.     int i, ptrn=strlen(pattern);
  2194.     char ut[256], *buffer, *lend;
  2195.     char *uptab=ut, *get, c, *lpos, *lstart;
  2196.     int len, lnum, qcd=qcd_flag, repeat=(qcd==2 && qcd_offs!=0), buflen;
  2197.     int sofar, got;
  2198.     BPTR fh;
  2199.  
  2200. #ifdef AZTEC_C
  2201.     while(0) while(0) c=c=0, uptab=uptab=ut, get=get=NULL;
  2202. #endif
  2203.  
  2204.     qcd_flag=0;
  2205.     if( !(fh=Open(name,MODE_OLDFILE))) {
  2206.         i=(long)IoErr(), docr=0;
  2207.         printf("\n");
  2208.         ierror(name,i);
  2209.         return 1;
  2210.     }
  2211.     len=filesize( name );
  2212.     buflen=len+3;
  2213.     if( !(buffer=(void *)AllocMem(buflen,0))) { Close(fh); return 0; }
  2214.     sofar=0;
  2215.     do {
  2216.         got=Read( fh, (char *)buffer+sofar, READCHUNK);
  2217.         sofar+=got;
  2218.     } while( got==READCHUNK );
  2219.     Close( fh);
  2220.     if( sofar != len ) {
  2221.         FreeMem( buffer, buflen );
  2222.         pError(pattern); return 1;
  2223.     }
  2224.     if(buffer[len-1]!='\n')
  2225.         buffer[len++]='\n';
  2226.  
  2227.     if( nocasedep )
  2228.         strupr( pattern );
  2229.  
  2230.     if( !qcd )
  2231.         prepscroll(0);
  2232.  
  2233.     for( i=0; i<256; i++ ) uptab[i]=i;
  2234.     if( nocasedep ) for( i='a'; i<='z'; i++ ) uptab[i]=i-'a'+'A';
  2235. retry:
  2236.     c = *pattern, buffer[len]=c, buffer[len+1]=c;
  2237.     get= (qcd==2) ? buffer+qcd_offs : buffer;
  2238.     if( qcd==1 ) qcd_offs=0;
  2239.  
  2240.     lpos=lstart=buffer, lnum=1;
  2241.     for( ;; ) {
  2242.         do ; while( uptab[*get++]!=c );
  2243.         if( --get>=buffer + len )
  2244.             break;
  2245.         for( i=1; i<ptrn; i++ )
  2246.             if( uptab[get[i]]!=pattern[i] )
  2247.                 break;
  2248.         if( i==ptrn ) {
  2249.             for( ;lpos<get; lpos++ )
  2250.                 if( *lpos=='\n' )
  2251.                     lstart=lpos+1, lnum++;
  2252.             for( lend=lstart+1; *lend!='\n'; lend++ ) ;
  2253.             if( qcd ) {
  2254.                 if( get[-1]==':' || get[-1]=='/' ||
  2255.                       lpos==lstart && lend[-1]==':' ) {
  2256.                     char *tmp;
  2257.                     for( tmp=get+ptrn; *tmp&& *tmp!='\n'&& *tmp!='/'; tmp++ );
  2258.                     if( *tmp!='/' ) {
  2259.                         *lend=0;
  2260.                         strncpy(pattern,lstart,79);
  2261.                         qcd_offs=lend-buffer;
  2262.                         FreeMem( buffer, buflen );
  2263.                         return 2;
  2264.                     }
  2265.                 } else 
  2266.                     lend=lpos+1;
  2267.             } else {
  2268.                 *lend=0;
  2269.                 if(!(options&SEARCH_ONLY) ||
  2270.                      !isalphanum(lpos[-1])&&!isalphanum(lpos[ptrn]))
  2271.                     if(found(lstart, lnum, get-buffer, name, lpos==lstart ))
  2272.                         break;
  2273.                 *lend='\n';
  2274.             }
  2275.             get=lend+1;
  2276.         } else
  2277.             get++;
  2278.     }
  2279.     if( repeat )  { repeat=0; qcd_offs=0; goto retry; }
  2280.     if( file_cr ) { printf("\n"); quickscroll(); }
  2281.     FreeMem( buffer, buflen );
  2282.     return 1;
  2283. }
  2284.  
  2285. static int
  2286. found( char *lstart, int lnum, int loffs, char *name, char left )
  2287. {
  2288.     int fileabort=0;
  2289.  
  2290.     if( (options&SEARCH_LEFT) && !left)
  2291.         return 0;
  2292.  
  2293.     if ( docr )
  2294.         { quickscroll(); printf("\n"); docr=0; }
  2295.  
  2296.     if( options&SEARCH_FILE ) {
  2297.         file_cr=1;
  2298.         if( !file_name )
  2299.             printf("%s",name), file_name=1;
  2300.         if( options&SEARCH_NUM )
  2301.             fileabort=1;
  2302.         else
  2303.             printf(" %d",lnum);
  2304.     } else if( options & SEARCH_BIN ) {
  2305.         if (!(options & SEARCH_NUM))
  2306.             printf("Byte offset %d\n",loffs);
  2307.         else
  2308.             printf("%d\n",loffs);
  2309.         quickscroll();
  2310.     } else {
  2311.         if (!(options & SEARCH_NUM))
  2312.             printf("%4d ",lnum);
  2313.         printf((lstart[strlen(lstart)-1]=='\n')?"%s":"%s\n",lstart);
  2314.         quickscroll();
  2315.     }
  2316.     abort_search= options&SEARCH_ABORT;
  2317.     return dobreak() || fileabort || abort_search;
  2318. }
  2319.  
  2320. int
  2321. do_search( void )
  2322. {
  2323.     if(!IsInteractive(Output())) options |= SEARCH_VERB;
  2324.     abort_search=0;
  2325.     searchstring=av[--ac];
  2326.     all_args(search_file, 0);
  2327.     return 0;
  2328. }
  2329.  
  2330. #if 0
  2331. /* do_grep() is just do_search() with a modified all_args() */
  2332. int
  2333. do_grep( void )
  2334. {
  2335.     if(!IsInteractive(Output())) options |= SEARCH_VERB;
  2336.     abort_search=0;
  2337.     searchstring=av[1];
  2338.     all_args_n2m(search_file, 0, 2, ac);
  2339.     return 0;
  2340. }
  2341. #endif
  2342.  
  2343. static BOOL rm_error_abort = FALSE;
  2344. static int rm_file( long mask, char *file, char *fullpath )
  2345. {
  2346.     if (rm_error_abort)
  2347.         return(20);
  2348.  
  2349.     if ( *file && file[strlen(file)-1]=='/' ) {
  2350.         file[strlen(file)-1]=0;
  2351.     }
  2352.     if (options&16 || has_wild) {
  2353.         fprintf(stdout," %s....",fullpath);
  2354.         fflush(stdout);
  2355.     }
  2356.     if (options&2 || options&4) {
  2357.         setProtection(file,0L);
  2358.     }
  2359.     if (!DeleteFile(file)) {
  2360.         pError(file);
  2361.         if (options & 8) {
  2362.             rm_error_abort = TRUE;
  2363.             return 20;
  2364.         }
  2365.     } else if (options&16 || has_wild)
  2366.         fprintf(stdout,"Deleted\n");
  2367.  
  2368.     return 0;
  2369. }
  2370.  
  2371. int
  2372. do_rm( void )
  2373. {
  2374.     rm_error_abort = FALSE;
  2375.     all_args( rm_file, 1);
  2376.     rm_error_abort = FALSE;
  2377.     return 0;
  2378. }
  2379.  
  2380.  
  2381. int
  2382. do_history( void )
  2383. {
  2384.     HIST *hist;
  2385.     int i = H_tail_base;
  2386.     int len = av[1] ? strlen(av[1]) : 0;
  2387.     char buf[250];
  2388.  
  2389.     if( options&2 ) {
  2390.         while( safegets(buf,stdin) )
  2391.             add_history(buf);
  2392.         return 0;
  2393.     }
  2394.  
  2395.     for (hist = H_tail; hist && !dobreak(); hist = hist->prev, i++)
  2396.         if (len == 0 || !strncmp(av[1], hist->line, len))
  2397.             if( options&1 )
  2398.                 printf("%s\n", hist->line);
  2399.             else
  2400.                 printf("%3d %s\n", i, hist->line);
  2401.     return 0;
  2402. }
  2403.  
  2404. int
  2405. do_mem( void )
  2406. {
  2407.     static ULONG clast, flast;
  2408.     ULONG cfree, ffree, clarg, flarg, i;
  2409.     char *desc="Free", *mem;
  2410.  
  2411.     if( options&32 )
  2412.         for( i=0; i<10; i++ )
  2413.             if(mem=(char*)AllocMem(0x7fffffff,0L))
  2414.                 FreeMem(mem,0x7fffffff);
  2415.  
  2416.     Forbid();
  2417.     cfree = AvailMem(MEMF_CHIP);
  2418.     ffree = AvailMem(MEMF_FAST);
  2419.     clarg = AvailMem(MEMF_CHIP|MEMF_LARGEST);
  2420.     flarg = AvailMem(MEMF_FAST|MEMF_LARGEST);
  2421.     Permit();
  2422.  
  2423.     if( options&8 ) {
  2424.         clast=cfree, flast=ffree;
  2425.         return 0;
  2426.     }
  2427.     if( options&16 )
  2428.         cfree=clast-cfree, ffree=flast-ffree, desc="Used";
  2429.     if( options&4 ) {
  2430.         if     ( options & 1 ) printf("%lu\n",cfree);
  2431.         else if( options & 2 ) printf("%lu\n",ffree);
  2432.         else                   printf("%lu\n",cfree+ffree);
  2433.     } else {
  2434. #if 1
  2435.         if     ( options & 1 ) {
  2436.             printf("Free CHIP memory:%10s",itoa(cfree));
  2437.             if ( options&16 )
  2438.                 printf("\n");
  2439.             else
  2440.                 printf("    largest %10s\n",itoa(clarg));
  2441.         }
  2442.         else if( options & 2 ) {
  2443.             printf("Free FAST memory:%10s",itoa(ffree));
  2444.             if ( options&16 )
  2445.                 printf("\n");
  2446.             else
  2447.                 printf("    largest %10s\n",itoa(flarg));
  2448.         }
  2449.         else {
  2450.             if ( options&16 ) {
  2451.                 if (cfree)
  2452.                     printf("CHIP memory:%10s\n",itoa(cfree));
  2453.                 if (ffree)
  2454.                     printf("FAST memory:%10s\n",itoa(ffree));
  2455.             }
  2456.             else {
  2457.                 printf("CHIP memory:%10s",itoa(cfree));
  2458.                 printf("    largest%10s\n",itoa(clarg));
  2459.                 printf("FAST memory:%10s",itoa(ffree));
  2460.                 printf("    largest%10s\n",itoa(flarg));
  2461.             }
  2462.             printf("Total  %s:%10s\n",desc,itoa(cfree+ffree));
  2463.         }
  2464. #else
  2465.         if     ( options & 1 ) printf("Free CHIP memory:%10s\n",itoa(cfree));
  2466.         else if( options & 2 ) printf("Free FAST memory:%10s\n",itoa(ffree));
  2467.         else {
  2468.             if(ffree) {
  2469.                 printf("CHIP memory:%10s\n",itoa(cfree));
  2470.                 printf("FAST memory:%10s\n",itoa(ffree));
  2471.             }
  2472.             printf("Total  %s:%10s\n",desc,itoa(cfree+ffree));
  2473.         }
  2474. #endif
  2475.     }
  2476.     return 0;
  2477. }
  2478.  
  2479. int
  2480. do_forline( void )
  2481. {
  2482.     char vname[33], buf[256], *cstr;
  2483.     int lctr;
  2484.     FILE *f;
  2485.  
  2486.     strcpy(vname,av[1]);
  2487.     if( !strcmp(av[2],"STDIN") )
  2488.         f=stdin;
  2489.     else 
  2490.         if(!(f=fopen(av[2],"r"))) { pError(av[2]); return 20; }
  2491.  
  2492.     lctr=0;
  2493.     ++H_stack;
  2494.     cstr = compile_av (av, 3, ac, ' ', 0);
  2495.     while (fgets(buf,256,f) && !dobreak() && !breakcheckd()) {
  2496.         buf[strlen(buf)-1]='\0';    /* remove CR */
  2497.         lctr++;
  2498.         set_var(LEVEL_SET | LEVEL_LOCAL, vname, buf);
  2499.         sprintf(buf,"%d",lctr);
  2500.         set_var(LEVEL_SET | LEVEL_LOCAL, v_linenum, buf);
  2501.         exec_command(cstr);
  2502.     }
  2503.     if( f!=stdin ) fclose(f);
  2504.     --H_stack;
  2505.     free (cstr);
  2506.     if( lctr ) {
  2507.         unset_var (LEVEL_SET, vname);
  2508.         unset_var (LEVEL_SET, v_linenum);
  2509.     }
  2510.     return 0;
  2511. }
  2512.  
  2513. int
  2514. do_fornum( void )
  2515. {
  2516.     char vname[33], buf[16];
  2517.     int n1, n2, step, i=1, verbose, runs=0;
  2518.     char *cstr;
  2519.  
  2520.     verbose=(options & 1);
  2521.     strcpy(vname,av[i++]);
  2522.     n1=myatoi(av[i++],-32767,32767); if (atoierr) return 20;
  2523.     n2=myatoi(av[i++],-32767,32767); if (atoierr) return 20;
  2524.     if (options & 2) {
  2525.         step=myatoi(av[i++],-32767,32767); if (atoierr) return 20;
  2526.     } else
  2527.         step=1;
  2528.     ++H_stack;
  2529.     cstr = compile_av (av, i, ac, ' ', 0);
  2530.     for (i=n1; (step>=0 ? i<=n2 : i>=n2) && !CHECKBREAK() && !breakcheckd();
  2531.          i+=step, runs++) {
  2532.         if (verbose) fprintf(stderr, "fornum: %d\n", i);
  2533.         sprintf(buf,"%d",i);
  2534.         set_var (LEVEL_SET | LEVEL_LOCAL, vname, buf);
  2535.         exec_command(cstr);
  2536.     }
  2537.     --H_stack;
  2538.     free (cstr);
  2539.     if( runs )
  2540.         unset_var (LEVEL_SET, vname);
  2541.     return 0;
  2542. }
  2543.  
  2544. /*
  2545.  * foreach var_name  ( str str str str... str ) commands
  2546.  * spacing is important (unfortunately)
  2547.  *
  2548.  * ac=0    1 2 3 4 5 6 7
  2549.  * foreach i ( a b c ) echo $i
  2550.  * foreach i ( *.c ) "echo -n "file ->";echo $i"
  2551.  */
  2552.  
  2553. int
  2554. do_foreach( void )
  2555. {
  2556.     int cstart, cend;
  2557.     char *cstr, vname[33];
  2558.     char **fav;
  2559.     int i=1, verbose;
  2560.  
  2561.     verbose=(options & 1);
  2562.     strcpy(vname, av[i++]);
  2563.     if (*av[i] == '(') i++;
  2564.     cstart = i;
  2565.     while (i<ac && *av[i] != ')') i++;
  2566.     if (i > ac) { fprintf(stderr,"')' expected\n"); return 20; }
  2567.     ++H_stack;
  2568.     cend = i;
  2569.  
  2570.     fav = (char **)salloc(sizeof(char *) * (ac));
  2571.     for (i = cstart; i < cend; ++i) fav[i] = av[i];
  2572.  
  2573.     cstr = compile_av (av, cend + 1, ac, ' ', 0);
  2574.  
  2575.     for (i = cstart; i<cend && !CHECKBREAK() && !breakcheckd() && !breakchecke(); ++i) {
  2576.         set_var (LEVEL_SET | LEVEL_LOCAL, vname, fav[i]);
  2577.         if (verbose) fprintf(stderr, "foreach: %s\n", fav[i]);
  2578.         execute(cstr);
  2579.     }
  2580.     --H_stack;
  2581.     free (fav);
  2582.     free (cstr);
  2583.     if( cstart<cend)
  2584.         unset_var (LEVEL_SET, vname);
  2585.     return 0;
  2586. }
  2587.  
  2588.  
  2589.  
  2590. int
  2591. do_forever( char *str )
  2592. {
  2593.     int rcode = 0;
  2594.     char *ptr = next_word( str );
  2595.  
  2596.     ++H_stack;
  2597.     for (;;) {
  2598.         if (CHECKBREAK() || breakcheckd()) { rcode = 20; break; }
  2599.         if (exec_command (ptr) > 0) {
  2600.             str = get_var(LEVEL_SET, v_lasterr);
  2601.             rcode = (str) ? atoi(str) : 20;
  2602.             break;
  2603.         }
  2604.     }
  2605.     --H_stack;
  2606.     return rcode;
  2607. }
  2608.  
  2609.  
  2610.  
  2611. extern struct IntuitionBase *IntuitionBase;
  2612.  
  2613. void wait_refresh(struct Window *window)
  2614. {
  2615.     if (window) {
  2616.         if (window->IDCMPFlags & IDCMP_CHANGEWINDOW) {
  2617.             struct IntuiMessage *msg;
  2618.             BOOL refreshed = FALSE;
  2619.             while (!refreshed) {
  2620.                 if (msg = (struct IntuiMessage *)GetMsg(window->UserPort)) {
  2621.                     if (msg->Class == IDCMP_CHANGEWINDOW) {
  2622.                         refreshed = TRUE;
  2623.                     }
  2624.                     ReplyMsg((struct Message *)msg);
  2625.                 }
  2626.                 else {
  2627.                     WaitPort(window->UserPort);
  2628.                 }
  2629.             }
  2630.         }
  2631.     }
  2632. }
  2633.  
  2634. int do_window( void )
  2635. {
  2636.     long x = -1, y = -1, w = -1, h = -1, maxwidth, maxheight;
  2637.  
  2638.     if(options & 32) { /* -q */
  2639.         struct Screen *scrn;
  2640.         struct Window *window;
  2641.         ULONG ibase_lock;
  2642.         char **ibase_list=NULL;
  2643.         long i,ibase_num=0;
  2644.         char fmt[256];
  2645.  
  2646.         newwidth(); /**/    /* get current window width */
  2647.  
  2648.         ibase_lock = LockIBase(0);
  2649.  
  2650.         for (scrn=IntuitionBase->FirstScreen; scrn; scrn=scrn->NextScreen) {
  2651.  
  2652.             struct List *list;
  2653.             struct Node *node;
  2654.             UBYTE PubNameBuf[MAXPUBSCREENNAME+4] = "";
  2655.  
  2656.             list = LockPubScreenList();
  2657.             for (node = list->lh_Head; node->ln_Succ; node = node->ln_Succ) {
  2658.                 if (((struct PubScreenNode *)node)->psn_Screen == scrn)
  2659.                     sprintf(PubNameBuf," [%s]",node->ln_Name);
  2660.             }
  2661.             UnlockPubScreenList();
  2662.  
  2663.             sprintf(fmt,"Screen %c%.*s%c%s (%d,%d,%dx%dx%d):\n",
  2664.                 scrn->Title ? '\"' : '(',
  2665.                 (options&64) ? 128 : (((w_width-36-strlen(PubNameBuf)) > 0) ? (w_width-36-strlen(PubNameBuf)) : 30),
  2666.                 scrn->Title ? scrn->Title : "no title",
  2667.                 scrn->Title ? '\"' : ')',
  2668.                 PubNameBuf,
  2669.                 scrn->LeftEdge,
  2670.                 scrn->TopEdge,
  2671.                 scrn->Width,
  2672.                 scrn->Height,
  2673.                 scrn->BitMap.Depth
  2674.             );
  2675.             add_array_list(&ibase_list,&ibase_num,fmt);
  2676.  
  2677.             for (window=scrn->FirstWindow; window; window=window->NextWindow) {
  2678.                 sprintf(fmt,"   win %c%.*s%c (%d,%d,%dx%d)\n",
  2679.                     window->Title ? '\"' : '(',
  2680.                     (options&64) ? 128 : w_width-32,
  2681.                     window->Title ? window->Title : "no title",
  2682.                     window->Title ? '\"' : ')',
  2683.                     window->LeftEdge,
  2684.                     window->TopEdge,
  2685.                     window->Width,
  2686.                     window->Height
  2687.                 );
  2688.                 add_array_list(&ibase_list,&ibase_num,fmt);
  2689.             }
  2690.  
  2691.             if (scrn->NextScreen)
  2692.                 add_array_list(&ibase_list,&ibase_num,"\n");
  2693.         }
  2694.  
  2695.         UnlockIBase(ibase_lock);
  2696.  
  2697.         for(i=0; i<ibase_num; i++)
  2698.             printf("%s",ibase_list[i]);
  2699.  
  2700.         free_array_list(ibase_list,ibase_num);
  2701.  
  2702.         return 0;
  2703.     }
  2704.  
  2705.     if( o_nowindow || !Mywindow )
  2706.         return 20;
  2707.  
  2708.     maxwidth = Mywindow->WScreen->Width;
  2709.     maxheight= Mywindow->WScreen->Height;
  2710.  
  2711.     if( options&1 )
  2712.         x=Mywindow->LeftEdge,y=Mywindow->TopEdge,w=Mywindow->MinWidth,h=Mywindow->MinHeight;
  2713.     if( options&2 ) x=y=0, w=maxwidth, h=maxheight;
  2714.     if( options&4 ) WindowToFront(Mywindow);
  2715.     if( options&8 ) WindowToBack(Mywindow);
  2716.     if( options&16) ActivateWindow(Mywindow);
  2717.  
  2718.     if( ac == 5 ) {
  2719.         x = myatoi(av[1],-2,maxwidth-Mywindow->MinWidth); if (atoierr) return 20;
  2720.         y = myatoi(av[2],-2,maxheight-Mywindow->MinHeight); if (atoierr) return 20;
  2721.         w = myatoi(av[3],-2,maxwidth); if (atoierr) return 20;
  2722.         h = myatoi(av[4],-2,maxheight); if (atoierr) return 20;
  2723.  
  2724.         if (x == -1) x = 0;
  2725.         if (y == -1) y = 0;
  2726.         if (w == -1) w = maxwidth;
  2727.         if (h == -1) h = maxheight;
  2728.  
  2729.         if (x == -2) x = Mywindow->LeftEdge;
  2730.         if (y == -2) y = Mywindow->TopEdge;
  2731.         if (w == -2) w = Mywindow->Width;
  2732.         if (h == -2) h = Mywindow->Height;
  2733.     }
  2734.     else if ( ac != 1 ) {
  2735.         fprintf(stderr,"Usage: window <pos_x> <pos_y> <width> <height>\n");
  2736.         fprintf(stderr,"   or  window -<options>\n");
  2737.         return 20;
  2738.     }
  2739.  
  2740.     if( w != -1 ) {
  2741.         int i;
  2742. #if 0
  2743.         if ( x+w>maxwidth || y+h>maxheight ) {
  2744.             ierror(NULL, 500);
  2745.             return 20;
  2746.         }
  2747. #endif
  2748.         if ( x+w>maxwidth )
  2749.             x = maxwidth - w;    /* alternatively: w=maxwidth-x; */
  2750.         if ( y+h>maxheight )
  2751.             y = maxheight - h;    /* alternatively: h=maxheight-y; */
  2752.         if( w<Mywindow->MinWidth )
  2753.             w = Mywindow->MinWidth;
  2754.         if( h<Mywindow->MinHeight )
  2755.             h = Mywindow->MinHeight;
  2756.  
  2757.         /* IDCMP_CHANGEWINDOW sucks */
  2758.  
  2759.         if (TRUE || options&128) {
  2760.             ChangeWindowBox(Mywindow,x,y,w,h);
  2761.             Delay(25);
  2762.             for( i=0; i<10; i++ ) {
  2763.                 if(  Mywindow->LeftEdge==x && Mywindow->TopEdge==y &&
  2764.                      Mywindow->Width   ==w && Mywindow->Height ==h )
  2765.                     break;
  2766.                 Delay(5);
  2767.             }
  2768.             Delay(25);
  2769.         }
  2770.         else {
  2771. #if 1
  2772.             if (Mywindow->IDCMPFlags & IDCMP_CHANGEWINDOW) {
  2773.                 /* IDCMP_CHANGEWINDOW already recognized */
  2774.                 ChangeWindowBox(Mywindow,x,y,w,h);
  2775.                 Delay(250);
  2776.                 wait_refresh(Mywindow);
  2777.             }
  2778.             else {
  2779.                 /* make window recognize IDCMP_CHANGEWINDOW temporarily */
  2780.                 if (!ModifyIDCMP(Mywindow,Mywindow->IDCMPFlags|IDCMP_CHANGEWINDOW))
  2781.                     fprintf(stderr,"CSHELL ERROR: cannot install IDCMP_CHANGEWINDOW.\n");
  2782.                 ChangeWindowBox(Mywindow,x,y,w,h);
  2783.                 Delay(250);
  2784.                 wait_refresh(Mywindow);
  2785.                 ModifyIDCMP(Mywindow,Mywindow->IDCMPFlags&(~IDCMP_CHANGEWINDOW));
  2786.             }
  2787. #else
  2788.             if( Mywindow->LeftEdge!=0 || Mywindow->TopEdge!=0 )
  2789.                 MoveWindow(Mywindow, -Mywindow->LeftEdge, -Mywindow->TopEdge );
  2790.             if( Mywindow->Width!=w || Mywindow->Height!=h )
  2791.                 SizeWindow(Mywindow, w-Mywindow->Width   , h-Mywindow->Height  );
  2792.             if( x || y )
  2793.                 MoveWindow(Mywindow, x, y );
  2794. #endif
  2795.         }
  2796.     }
  2797.  
  2798.     /* Delay(25); */ /* pause 1/2 sec. before trying to print */
  2799.     /* Delay(10); */
  2800.     /* printf("\014"); */
  2801.  
  2802.     return 0;
  2803. }
  2804.  
  2805.  
  2806.  
  2807. static void
  2808. setsystemtime(struct DateStamp *ds)
  2809. {
  2810.     struct timerequest tr;
  2811.     long secs= ds->ds_Days*86400+ds->ds_Minute*60+ds->ds_Tick/TICKS_PER_SECOND;
  2812.  
  2813.     if (OpenDevice(TIMERNAME, UNIT_VBLANK,(struct IORequest *)&tr, 0L)) {
  2814.         fprintf(stderr,"Clock error: can't open timer device\n");
  2815.         return;
  2816.     }
  2817.  
  2818.     tr.tr_node.io_Message.mn_Node.ln_Type = NT_MESSAGE;
  2819.     tr.tr_node.io_Message.mn_Node.ln_Pri = 0L;
  2820.     tr.tr_node.io_Message.mn_Node.ln_Name = NULL;
  2821.     tr.tr_node.io_Message.mn_ReplyPort = NULL;
  2822.     tr.tr_node.io_Command = TR_SETSYSTIME;
  2823.     tr.tr_time.tv_secs = secs;
  2824.     tr.tr_time.tv_micro = 0L;
  2825.     if (DoIO ((struct IORequest *)&tr))
  2826.         fprintf(stderr,"Clock error: can't talk to timer device\n");
  2827.     CloseDevice ((struct IORequest *)&tr);
  2828. }
  2829.  
  2830.  
  2831. static char tday[LEN_DATSTRING+1];    /* not sure, if +1 (null byte) is neccessary */
  2832.  
  2833. char *
  2834. dates( struct DateStamp *dss, int flags )
  2835. {
  2836.     static char timestr[2*LEN_DATSTRING+3];
  2837.     char tdate[LEN_DATSTRING+1], ttime[LEN_DATSTRING+1];
  2838.     struct DateTime dt;
  2839.     struct DateStamp *myds;
  2840.     char *dp,*tp;
  2841.     int slen;
  2842.  
  2843.     dt.dat_Format  = FORMAT_DOS;    /* bug in DOS, always localized :-( */
  2844.     dt.dat_StrDay  = tday;
  2845.     dt.dat_StrDate = tdate;
  2846.     dt.dat_StrTime = ttime;
  2847.     dt.dat_Flags   = flags ? DTF_SUBST : 0;
  2848.     dt.dat_Stamp   = *dss;
  2849.  
  2850.     myds = &(dt.dat_Stamp);
  2851.  
  2852.     if(  myds->ds_Days<0   || myds->ds_Days>36500 ||
  2853.          myds->ds_Minute<0 || myds->ds_Minute>1440 ||
  2854.          myds->ds_Tick<0   || myds->ds_Tick>3000 || !DateToStr(&dt) )
  2855.         strcpy(tdate,"---------"), strcpy(ttime,"--------");
  2856.  
  2857. #if 0
  2858.     ttime[8] = '\0';
  2859.     sprintf(timestr,"%-9s %-8s",tdate,ttime);
  2860. #endif
  2861.  
  2862.     /* strip off leading spaces from 'tdate' -> result in 'dp' */
  2863.  
  2864.     for (dp=tdate; dp && *dp && (*dp==' ' || *dp=='\t'); dp++)
  2865.         ;
  2866.  
  2867.     /* strip off trailing spaces from 'dp' */
  2868.  
  2869.     for (slen=strlen(dp)-1; slen>=0 && (dp[slen]==' ' || dp[slen]=='\t'); --slen)
  2870.         dp[slen] = '\0';
  2871.  
  2872.     /* strip off leading spaces from 'ttime' -> result in 'tp' */
  2873.  
  2874.     for (tp=ttime; tp && *tp && (*tp==' ' || *tp=='\t'); tp++)
  2875.         ;
  2876.  
  2877.     /* strip off trailing spaces from 'tp' */
  2878.  
  2879.     for (slen=strlen(tp)-1; slen>=0 && (tp[slen]==' ' || tp[slen]=='\t'); --slen)
  2880.         tp[slen] = '\0';
  2881.  
  2882.     /*
  2883.      * month name > 3 chars? (bug in french locale)
  2884.      * [Worse luck, this also affects german "Donnerstag"!]
  2885.      */
  2886.  
  2887.     while (strlen(dp) > 9)
  2888.         strdel(dp,6,1);
  2889.  
  2890.     sprintf(timestr,"%-9.9s %-8.8s",dp,tp);
  2891.  
  2892.     timestr[18] = '\0';    /* protection against bad timestamped files */
  2893.  
  2894.     return timestr;
  2895. }
  2896.  
  2897. /*
  2898.  * returns difference in msecs between two TIMEVALS (GMD)
  2899.  */
  2900.  
  2901. long tv_diff (struct timeval * tv1, struct timeval * tv2)
  2902. {
  2903.     long val;
  2904.  
  2905.     val = ((long) tv2->tv_secs - (long) tv1->tv_secs) * 1000L;
  2906.     val += (((long) tv2->tv_micro) - ((long) tv1->tv_micro)) / 1000L;
  2907.  
  2908.     return val;
  2909. }
  2910.  
  2911. /*
  2912.  * given a DateStamp structure , returns an updated TIMEVAL (GMD)
  2913.  */
  2914.  
  2915. void dss2tv (struct DateStamp * t1, struct timeval * tv)
  2916. {
  2917.     ULONG secs;
  2918.  
  2919.     secs = t1->ds_Days * 24 * 60 * 60;
  2920.     secs += t1->ds_Minute * 60;
  2921.     secs += t1->ds_Tick / TICKS_PER_SECOND;
  2922.  
  2923.     tv->tv_secs = secs;
  2924.     tv->tv_micro = (t1->ds_Tick % TICKS_PER_SECOND) * (1000000 / TICKS_PER_SECOND);
  2925. }
  2926.  
  2927. /*
  2928.  * tv2dss ; converts a timeval structure to a DateStamp structure (GMD)
  2929.  */
  2930.  
  2931. void tv2dss (struct timeval * tv, struct DateStamp * dss)
  2932. {
  2933.     long rem;
  2934.  
  2935.     dss->ds_Days = tv->tv_secs / (24 * 60 * 60);
  2936.     rem = tv->tv_secs % (24 * 60 * 60);    /* secs in last day */
  2937.  
  2938.     dss->ds_Minute = rem / 60;
  2939.     rem = rem % 60;        /* secs in last minute */
  2940.  
  2941.     rem = (rem * 1000) + (tv->tv_micro / 1000);    /* msecs in last minute */
  2942.  
  2943.     dss->ds_Tick = rem / (1000 / TICKS_PER_SECOND);    /* ticks in last minute */
  2944. }
  2945.  
  2946. /* code for battery-clock by Gary Duncan (GMD) */
  2947.  
  2948. int
  2949. do_date (void)
  2950. {
  2951.     static struct DateStamp dss_s; /* set by -s option */
  2952.     static struct timeval tv;
  2953.     struct DateStamp dss;
  2954.     struct DateTime dt;
  2955.     int i = 1;
  2956.  
  2957.     dt.dat_Format = FORMAT_DOS;
  2958.     if (ac == 1) {
  2959.         DateStamp(&dss);
  2960.         if (options & 4) {  /* its read-battery-clock time; GMD */
  2961.             struct timeval tv_batt;
  2962.             if (BattClockBase==NULL) {
  2963.                 fprintf(stderr,"No Battery Clock\n");
  2964.                 return 0;
  2965.             }
  2966.             tv_batt.tv_micro = 0;
  2967.             tv_batt.tv_secs  = ReadBattClock();
  2968.             tv2dss(&tv_batt,&dss);
  2969.         }
  2970.  
  2971.         if (options & 1) {        /* -s option */
  2972.             dss_s = dss;
  2973.             dss2tv(&dss_s,&tv);
  2974.         }
  2975.         else if (options & 2) {        /* -r option */
  2976.             long diff;
  2977.             struct timeval tv1;
  2978.  
  2979.             /*
  2980.              *  if -s not previous done , silently ignore
  2981.              */
  2982.             if (dss_s.ds_Days == 0)
  2983.                 return 0;
  2984.  
  2985.             dss2tv(&dss, &tv1);        /* current time */
  2986.             diff = tv_diff(&tv,&tv1);    /* diff in msecs */
  2987.  
  2988.             printf ("%d.%02d\n", diff / 1000, diff % 1000);
  2989.         }
  2990.         else
  2991.             printf ("%s %s\n", tday, dates (&dss, 0));
  2992.     }
  2993.     else {
  2994.         /* set the time here  */
  2995.         DateStamp (&dt.dat_Stamp);
  2996.         for (; i < ac; i++) {
  2997.             dt.dat_StrDate = NULL;
  2998.             dt.dat_StrTime = NULL;
  2999.             dt.dat_Flags = DTF_FUTURE;
  3000.             if (index (av[i], ':'))
  3001.                 dt.dat_StrTime = av[i];
  3002.             else
  3003.                 dt.dat_StrDate = av[i];
  3004.             if (!StrToDate (&dt))
  3005.                 ierror (av[i], 500);
  3006.         }
  3007.         setsystemtime (&(dt.dat_Stamp));
  3008.     }
  3009.     return 0;
  3010. }
  3011.  
  3012.