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