home *** CD-ROM | disk | FTP | other *** search
/ back2roots/padua / padua.7z / padua / shell / csh519s.lha / comm1.c < prev    next >
C/C++ Source or Header  |  1992-02-07  |  34KB  |  1,537 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.  *
  10.  */
  11.  
  12. #include "shell.h"
  13.  
  14. /* comm1.c */
  15. static void display_file(char *filestr);
  16. static int search_file( long mask, char *s, char *fullpath );
  17. static int rm_file    ( long mask, char *s, char *fullpath );
  18. static int quicksearch(char *name, int nocasedep, char *pattern);
  19. static void setsystemtime(struct DateStamp *ds);
  20. static int found( char *lstart, int lnum, int loffs, char *name, char left );
  21.  
  22. void lformat( char *s, char *d, FILEINFO *info );
  23.  
  24. extern int has_wild;
  25.  
  26. int
  27. do_sleep( void )
  28. {
  29.     int i;
  30.  
  31.     if (ac == 2) for (i=atoi(av[1]); i>0 && !CHECKBREAK(); i--) Delay(50);
  32.     return 0;
  33. }
  34.  
  35. int
  36. do_protect( void )
  37. {
  38.     static char flags[]="DEWRAPSH";
  39.     char *s, *p;
  40.     long setmask=0, clrmask=0xFF, mask;
  41.     int  i, mode=0, stat;
  42.     DPTR *dp;
  43.  
  44.     for (s=strupr(av[--ac]); *s; s++) {
  45.         if (*s=='=') { mode=0; continue; }
  46.         if (*s=='+') { mode=1; clrmask=FIBF_ARCHIVE; continue; }
  47.         if (*s=='-') { mode=2; clrmask=FIBF_ARCHIVE; continue; }
  48.  
  49.         if (*s=='X') *s='E';
  50.         if (p=index(flags, *s)) {
  51.             if( mode==0 ) setmask|= 1<<(p-flags), clrmask=0xFF;
  52.             if( mode==1 ) setmask|= 1<<(p-flags);
  53.             if( mode==2 ) clrmask|= 1<<(p-flags);
  54.         } else {
  55.             ierror(av[ac],500);
  56.             return 20;
  57.         }
  58.     }
  59.  
  60.     for (i=1; i<ac; i++) {
  61.         if( (dp=dopen(av[i],&stat))) {
  62.             mask = dp->fib->fib_Protection ^ 0x0F;
  63.             mask&=~clrmask;
  64.             mask|= setmask;
  65.             dclose(dp);
  66.             if( !SetProtection( av[i], mask ^ 0x0F))
  67.                 pError(av[i]);
  68.         } else
  69.             pError(av[i]);
  70.     }
  71.     return 0;
  72. }
  73.  
  74. int
  75. do_filenote( void )
  76. {
  77.     DPTR *dp;
  78.     char *note;
  79.     int i, stat;
  80.  
  81.     if( options&1 ) {
  82.         for( i=1; i<ac && !dobreak(); i++ )
  83.             if( dp=dopen( av[i], &stat )) {
  84.                 printf( "%-12s %s\n", av[i],dp->fib->fib_Comment );
  85.                 dclose( dp );
  86.             }
  87.     } else {
  88.         note=av[--ac];
  89.         for (i=1; i<ac; i++) if (!SetComment(av[i], note)) pError(av[i]);
  90.     }
  91.     return 0;
  92. }
  93.  
  94. int
  95. do_cat( void )
  96. {
  97.     FILE *fi;
  98.     int lctr, i, docr=0;
  99.     char buf[256], *l;
  100.  
  101.     prepscroll(0);
  102.     if (ac<=1) {
  103.         if (has_wild) { printf("No files matching\n"); return 20; }
  104.         lctr=0;
  105.         while (fgets(buf,256,stdin) && !dobreak()) {
  106.             if (options) printf("%4d ",++lctr);
  107.             quickscroll();
  108.             l=buf+strlen( buf )-1; docr=1;
  109.             if( l>=buf && *l=='\n' ) docr=0;
  110.             fputs(buf,stdout);
  111.         }
  112.     } else {
  113.         for (i=1; i<ac; i++)
  114.             if (fi = fopen (av[i], "r")) {
  115.                 lctr=0;
  116.                 while (fgets(buf,256,fi) && !dobreak()) {
  117.                     if (options&1) printf("%4d ",++lctr);
  118.                     quickscroll();
  119.                     l=buf+strlen( buf )-1; docr=1;
  120.                     if( l>=buf && *l=='\n' ) docr=0;
  121.                     fputs(buf,stdout); fflush(stdout);
  122.                 }
  123.                 fclose (fi);
  124.             } else
  125.                 pError(av[i]);
  126.     }
  127.     if( docr && isconsole(Output()))
  128.         putchar('\n');
  129.     return 0;
  130. }
  131.  
  132.  
  133. void
  134. get_drives(char *buf)
  135. {
  136.     struct DirectoryEntry *de_head=NULL, *de;
  137.  
  138.     buf[0]=0;
  139.     AddDADevs(&de_head, DLF_DEVICES | DLF_DISKONLY );
  140.     for(de=de_head; de; de=de->de_Next) {
  141.         if( buf[0] )
  142.             strcat( buf, "\240" );
  143.         strcat( buf, de->de_Name );
  144.     }
  145.     FreeDAList(de_head);
  146. }
  147.  
  148. static char infobuf[100];
  149. static char namebuf[12];
  150.  
  151. char *
  152. drive_name( char *name )
  153. {
  154.     struct DirectoryEntry *de_head=NULL, *de;
  155.     struct MsgPort *proc= (struct MsgPort *)DeviceProc( (void*)name );
  156.  
  157.     strcpy( namebuf, name );
  158.     AddDADevs(&de_head, DLF_DEVICES | DLF_DISKONLY );
  159.     for(de=de_head; de; de=de->de_Next)
  160.         if( (struct MsgPort *)DeviceProc( (void*)de->de_Name) == proc )
  161.             strcpy( namebuf, de->de_Name );
  162.     FreeDAList(de_head);
  163.  
  164.     return namebuf;
  165. }
  166.  
  167. int
  168. do_info( void )
  169. {
  170.     struct DirectoryEntry *de_head=NULL, *de;
  171.     int i;
  172.  
  173.     puts("Unit    Size  Bytes  Used Blk/Byt-Free Full Errs  Status    Name");
  174.  
  175.     if( ac==1 ) {
  176.         AddDADevs(&de_head, DLF_DEVICES | DLF_DISKONLY );
  177.         for(de=de_head; de; de=de->de_Next)
  178.             oneinfo( de->de_Name, 0);
  179.         FreeDAList(de_head);
  180.     } else {
  181.         for( i=1; i<ac; i++ )
  182.             oneinfo( drive_name( av[i] ), 0 );
  183.     }
  184.  
  185.     return 0;
  186. }
  187.  
  188. char *
  189. oneinfo( char *name, int mode )
  190. {
  191.     BPTR lock;
  192.     struct InfoData *info;
  193.     long size, free, freebl, blocks;
  194.     char *p, buf[130], *state="          ";
  195.     char *fmt="%s\240%s\240%d\240%d\240%d\240%s\240%d%%\240%d\240%s\240%s";
  196.  
  197.     Myprocess->pr_WindowPtr = (APTR)(-1);
  198.  
  199.     infobuf[0]=0;
  200.     if( !name ) name="";
  201.     strcpy(infobuf,"0");
  202.     info=(struct InfoData *)SAllocMem(sizeof(struct InfoData),MEMF_PUBLIC);
  203.     if (lock=Lock(name,ACCESS_READ)) {
  204.         if (Info(lock, info)) {
  205.             PathName(lock, buf, 128L);
  206.             if (p=index(buf,':')) *p = '\0';
  207.             size  = ((info->id_NumBlocks + 2)* info->id_BytesPerBlock);
  208.             freebl= (info->id_NumBlocks-info->id_NumBlocksUsed);
  209.             free  = freebl * info->id_BytesPerBlock;
  210.             switch(info->id_DiskState) {
  211.                 case ID_WRITE_PROTECTED: state="Read Only "; break;
  212.                 case ID_VALIDATED:       state="Read/Write"; break;
  213.                 case ID_VALIDATING:      state="Validating"; break;
  214.             }
  215.             blocks=info->id_NumBlocks;
  216.             if( mode==0 ) fmt="%-7s%5s%6d%7d%7d %5s%4d%%%4d  %s %s\n";
  217.             sprintf(infobuf,fmt,
  218.                 name,
  219.                 itok( size ),
  220.                 info->id_BytesPerBlock,
  221.                 info->id_NumBlocksUsed,
  222.                 freebl,
  223.                 itok( free ),
  224.                 (blocks) ? (info->id_NumBlocksUsed * 100)/blocks : 0,
  225.                 info->id_NumSoftErrors,
  226.                 state,
  227.                 buf);
  228.             if( mode==2 ) sprintf( infobuf, "%d", free );
  229.             if( mode==3 ) sprintf( infobuf, "%d", freebl );
  230.             if( mode==4 ) sprintf( infobuf, "%s", itok( free ));
  231.             if( mode==5 ) sprintf( infobuf, "%s:",buf );
  232.         } else
  233.             pError (name);
  234.         UnLock(lock);
  235.     } else {
  236.         if     ( mode==1 ) sprintf( infobuf, "%s\240No disk present", name );
  237.         else if( mode==0 ) sprintf( infobuf, "%-7s No disk present\n",name);
  238.         else if( mode==5 ) sprintf( infobuf, ""  );
  239.         else               sprintf( infobuf, "0" );
  240.     }
  241.     if( mode==0 ) printf( "%s",infobuf);
  242.     FreeMem(info,sizeof(struct InfoData));
  243.  
  244.     Myprocess->pr_WindowPtr = (APTR) o_noreq;
  245.  
  246.     return infobuf;
  247. }
  248.  
  249.  
  250. /* things shared with display_file */
  251.  
  252. #define DIR_SHORT 0x1
  253. #define DIR_FILES 0x2
  254. #define DIR_DIRS  0x4
  255. #define DIR_NOCOL 0x8
  256. #define DIR_NAMES 0x10
  257. #define DIR_HIDE  0x20
  258. #define DIR_LEN   0x40
  259. #define DIR_TIME  0x80
  260. #define DIR_BACK  0x100
  261. #define DIR_UNIQ  0x200
  262. #define DIR_IDENT 0x400
  263. #define DIR_CLASS 0x800
  264. #define DIR_QUIET 0x1000
  265. #define DIR_AGE   0x2000
  266. #define DIR_VIEW  0x4000
  267. #define DIR_NOTE  0x8000
  268. #define DIR_PATH  0x10000
  269. #define DIR_LFORM 0x20000
  270. #define DIR_BOT   0x40000
  271. #define DIR_TOP   0x80000
  272.  
  273. static char *lastpath;
  274. static int filecount, dircount, col, colw, wwidth;
  275. static long bytes, blocks;
  276.  
  277. /* the args passed to do_dir will never be expanded */
  278.  
  279. extern expand_err;
  280. extern int w_width;
  281.  
  282. static struct DateStamp Stamp;
  283. static char *LineBuf, *LinePos, LastWasDir, *LFormat, _LFormat[80], NoTitles;
  284.  
  285. int
  286. do_dir( void )
  287. {
  288.     int i=1, c, eac, reverse, nump=ac, retcode=0;
  289.     char **eav=NULL, **av1=NULL, **av2=NULL, inter=isconsole(Output());
  290.     char linebuf[200];
  291.     int (*func)(), ac1, ac2, factor=0;
  292.  
  293.     LineBuf=LinePos=linebuf;
  294.     LastWasDir=NoTitles=0;
  295.     colw=-1;
  296.  
  297.     LFormat=_LFormat;
  298.  
  299.     if( options&DIR_CLASS ) options|=DIR_IDENT;
  300.     if( !(options & (DIR_FILES | DIR_DIRS))) options|= DIR_FILES | DIR_DIRS;
  301.  
  302.     DateStamp( &Stamp );
  303.  
  304.     col = filecount = dircount = bytes = blocks = 0L;
  305.     lastpath=NULL;
  306.  
  307.     wwidth=77;
  308.     if( inter ) 
  309.         wwidth=w_width;
  310.  
  311.     if( options&DIR_SHORT )
  312.         strcpy(LFormat," %-18n%19m");
  313.     else if( options&DIR_PATH )
  314.         strcpy(LFormat," %-50p %7s %d"), NoTitles=1;
  315.     else {
  316.         if( options&DIR_NOTE )
  317.             strcpy(LFormat,"   %-24n %o");
  318.         else {
  319.             strcpy(LFormat,"   %-24n ");
  320.             if( options&DIR_HIDE )
  321.                 strcat(LFormat, "%e");
  322.             strcat(LFormat,"%c%f ");
  323.             if( options&DIR_VIEW )
  324.                 strcat(LFormat,"%10v ");
  325.             else 
  326.                 strcat(LFormat,"%7s ");
  327.             if( !(options&DIR_QUIET) )
  328.                 strcat(LFormat,options&DIR_VIEW?"%5b ":"%4b ");
  329.             if( options&DIR_IDENT )
  330.                 strcat(LFormat,"%k");
  331.             else if( options&DIR_AGE )
  332.                 strcat(LFormat,"%a");
  333.             else 
  334.                 strcat(LFormat,"%d %t");
  335.         }
  336.     }
  337.  
  338.     if( options&DIR_LFORM )
  339.         if( ac>1 )
  340.             LFormat=av[i++];
  341.         else { 
  342.             show_usage(NULL);
  343.             return 20;
  344.         }
  345.  
  346.     if( ac == i) ++nump, av[i]="";
  347.     if( options&DIR_UNIQ) {
  348.         if( ac-i!=2 )  { show_usage(NULL); return 20; }
  349.         i=0, nump=3;
  350.     }
  351.  
  352.     prepscroll(0);
  353.     for( ; i<nump && !CHECKBREAK(); ++i ) {
  354.         if( options&DIR_UNIQ ) {
  355.             switch( i ) {
  356.                 case 0: av1=expand( av[ac-2], &ac1 );
  357.                         av2=expand( av[ac-1], &ac2 );
  358.                         eav=without( av1, ac1, av2, ac2, &eac, 1 );
  359.                         break;
  360.                 case 1: printf("\nCommon files\n");
  361.                         eav=and( av1, ac1, av2, ac2, &eac, 1 );
  362.                         break;
  363.                 case 2: printf("\n");
  364.                         eav=without( av2, ac2, av1, ac1, &eac, 1 );
  365.                         break;
  366.             }
  367.             col = filecount = dircount = bytes = blocks = 0L;
  368.             lastpath=NULL;
  369.         } else if (!(eav = expand(av[i], &eac)) && IoError) {
  370.             ierror(av[i],IoError);
  371.             retcode=5;
  372.             continue;
  373.         }
  374.  
  375.         reverse= ( options&DIR_BACK ) ? 1 : 0;
  376.         func=cmp;
  377.         if( options & DIR_TIME) func=datecmp;
  378.         if( options & DIR_LEN ) func=sizecmp;
  379.         if( options & DIR_CLASS)func=classcmp;
  380.         if( options & DIR_BOT ) factor=-99999999;
  381.         if( options & DIR_TOP ) factor= 99999999;
  382.         DirQuickSort(eav, eac, func, reverse, factor);
  383.         for(c=0; c<eac && !CHECKBREAK(); ++c) {
  384.             if( options & DIR_HIDE ) {
  385.                 char *b=BaseName(eav[c]);
  386.                 int  l=strlen(b)-5;
  387.                 FILEINFO *info =(FILEINFO *)eav[c] - 1;
  388.                 if(*b=='.'|| (l>=0 && !strcmp(b+l,".info"))||(info->flags&128))
  389.                     continue;
  390.             }
  391.             if (options & DIR_NAMES) {
  392.                 if(options&(((FILEINFO *)eav[c])->size<0? DIR_DIRS: DIR_FILES))
  393.                     puts(eav[c]);
  394.             } else
  395.                 display_file(eav[c]);
  396.         }
  397.  
  398.         if (col) { quickscroll(); puts(LinePos=LineBuf); col=0; }
  399.  
  400.         if( LastWasDir )
  401.             printf(o_lolite), LastWasDir=0;
  402.  
  403.         if (options&DIR_UNIQ || (filecount>1 && i==nump-1)) {
  404.             blocks += filecount-dircount; /* account for dir blocks */
  405.             quickscroll();
  406.             printf(" %ld Blocks, %s Bytes used in %d files\n",
  407.                 blocks, itoa(bytes), filecount);
  408.         }
  409.         if( options&DIR_UNIQ )
  410.             free(eav);
  411.         else 
  412.             free_expand (eav);
  413.     }
  414.     lastpath=NULL;
  415.  
  416.     if( options&DIR_UNIQ )
  417.         free_expand( av1 ), free_expand( av2 );
  418.  
  419.     return retcode;
  420. }
  421.  
  422. static int MultiCol=-1;
  423.  
  424. static char
  425. pathcomp( char *s1, char *s2 )
  426. {
  427.     char ret, *t, c;
  428.  
  429.     t=BaseName( s2 ); c=*t; *t=0;
  430.     ret=Strcmp( s1, s2 );
  431.     *t=c;
  432.     return ret;
  433. }
  434.  
  435.  
  436. static void
  437. display_file( char *filestr )
  438. {
  439.     /* struct InfoData *id=AllocMem( sizeof(struct InfoData), 0); */
  440.     int isadir, len, collen;
  441.     char sc, *base, buf[130], *hilite;
  442.     FILEINFO *info;
  443.     BPTR thislock;
  444.  
  445.     base=BaseName(filestr);
  446.     sc = *base;
  447.     *base = 0;
  448.     /* if (thislock==NULL) return; */
  449.     if( !NoTitles ) {
  450.         if( !lastpath || pathcomp( filestr, lastpath)) {
  451.             if(!(thislock=Lock(filestr,SHARED_LOCK)))
  452.                 return;
  453.             if (col) { quickscroll(); puts(LinePos=LineBuf); col=0; }
  454.             quickscroll();
  455.             PathName(thislock, buf, 128L);
  456.             if( LastWasDir )
  457.                 printf(o_lolite), LastWasDir=0;
  458.             printf("Directory of %s\n", buf );
  459.             /* Info( thislock, id ); */
  460.             /* itok((id->id_NumBlocks-id->id_NumBlocksUsed)*id->id_BytesPerBlock));*/
  461.             /* FreeMem( id, sizeof(struct InfoData)); */
  462.             lastpath=filestr;
  463.             UnLock(thislock);
  464.         }
  465.     }
  466.     *base    = sc;
  467.  
  468.     info   = (FILEINFO *)filestr - 1;
  469.     isadir = info->size<0;
  470.  
  471.     if( !(options & (isadir ? DIR_DIRS : DIR_FILES)))
  472.         return;
  473.  
  474.     hilite="";
  475.     if (isadir!=LastWasDir && !(options & DIR_NOCOL)) 
  476.         hilite=isadir ? o_hilite : o_lolite, LastWasDir=isadir;
  477.  
  478.     lformat(LFormat, buf, info);
  479.  
  480.     if( MultiCol==-1 ) {
  481.         quickscroll();
  482.         printf("%s%s",hilite,buf);
  483.     } else {
  484.         len=strlen(buf);
  485.         if( col+len>wwidth ) {
  486.             quickscroll();
  487.             puts(LineBuf);
  488.             LinePos=LineBuf; col=0;
  489.         }
  490.         if( MultiCol )
  491.             colw=MultiCol;
  492.         else if( colw==-1 )
  493.             colw=len;
  494.         collen= (len+colw-1)-(len+colw-1)%colw;
  495.         col+=collen;
  496.         LinePos+=sprintf(LinePos,"%s%-*s",hilite,collen,buf);
  497.     }
  498.  
  499.     if(info->size>0)
  500.         bytes  += info->size;
  501.     blocks += info->blocks;
  502.     filecount++;
  503. }
  504.  
  505. static char linebuf[140];
  506. static long dlen, dblocks;
  507.  
  508. static int
  509. count( long mask, char *s, char *path )
  510. {
  511.     FIB *fib=(FIB*)s-1;
  512.     dlen+=fib->fib_Size;
  513.     dblocks+=fib->fib_NumBlocks+1;
  514.     return 0;
  515. }
  516.  
  517. void
  518. lformat( char *s, char *d, FILEINFO *info )
  519. {
  520.     long mi=0;
  521.     char buf[120], *w, *t, *class;
  522.     DPTR *dp;
  523.     int stat, i, form, sign, cut, size=info->size;
  524.     char *(*func)(int num);
  525.  
  526.     MultiCol=-1;
  527.     while( *s ) {
  528.         if( *s!='%' ) { *d++=*s++; continue; }
  529.         sign=1; form=0; cut=0; s++;
  530.         if( *s=='-' ) s++, sign=-1;
  531.         if( *s=='.' ) s++, cut=1;
  532.         while( *s>='0' && *s<='9' ) form=10*form+*s++-'0';
  533.         w=buf; w[0]=0; w[1]=0; 
  534.         switch( *s ) {
  535.         case 'p': strcpy(w,(char *)(info+1));             break;
  536.         case 'b': sprintf(w,size>=0 ? "%d":"", info->blocks); break;
  537.         case 's': sprintf(w,size>=0 ? "%d":"<Dir>",size); break;
  538.         case 'i': *w= size>=0 ? '-' : 'd';                break;
  539.         case 'r': 
  540.         case 'u':
  541.             if( *s=='r' ) func=itoa; else func=itok;
  542.             strcpy( w,size>=0 ? (*func)(size) : "<Dir>");
  543.             break;
  544.         case 'n': 
  545.         case 'q':
  546.             strcpy(w,BaseName((char *)(info+1)));
  547.             if( *s=='q' && size<0 ) strcat(w,"/");
  548.             break;
  549.         case 'l':
  550.             if( info->flags & INFO_COMMENT ) *w='\n';
  551.             break;
  552.         case 'c':
  553.             *w= info->flags & INFO_COMMENT ? 'c' : '-';
  554.             break;
  555.         case 'e':
  556.             *w= info->flags & INFO_INFO ? 'i' : '-';
  557.             break;
  558.         case '+':
  559.             *w= info->flags & INFO_INFO ? '+' : ' ';
  560.             break;
  561.         case 'f':
  562.             for (i=7; i>=0; i--)
  563.                 *w++ = (info->flags^15) & (1L<<i) ? "hsparwed"[7-i] : '-';
  564.             *w=0;
  565.             break;
  566.         case 'a': 
  567.             if( Stamp.ds_Days!=0 ) {
  568.                 mi =Stamp.ds_Days*1440 + Stamp.ds_Minute;
  569.                 mi-=info->date.ds_Days*1440 + info->date.ds_Minute;
  570.             }
  571.             sprintf(w,mi>=0?"%4d days %02d:%02d":"Future    ",
  572.                       mi/1440,mi/60%60,mi%60);
  573.             break;
  574.         case 'o':
  575.             if( dp=dopen( (char *)(info+1), &stat )) {
  576.                 strcpy( w, dp->fib->fib_Comment );
  577.                 dclose( dp );
  578.             }
  579.             break;
  580.         case 'v':
  581.         case 'w':
  582.             if( *s=='v' ) func=itoa; else func=itok;
  583.             dlen=dblocks=0;
  584.             if( size<0 ) {
  585.                 newrecurse( SCAN_DIR|SCAN_FILE|SCAN_RECURSE,
  586.                             (char *)(info+1),count);
  587.                 strcpy( w, (*func)(dlen));
  588.                 info->size=size=dlen; info->blocks=dblocks;
  589.             } else 
  590.                 strcpy( w, (*func)(size));
  591.             break;
  592.         case 'k':
  593.             if( *info->class!=1 )
  594.                 strcpy(w,info->class);
  595.             else if( class=getclass((char *)(info+1)))
  596.                 if( w=index(strncpy(w,class,50),0xA0) )
  597.                     *w=0;
  598.             break;
  599.         case 'x':
  600.         case 'd':
  601.             sprintf(w,"%9s",dates(&info->date,*s=='x'));
  602.             if(t=index(w,' ')) *t=0;
  603.             break;
  604.         case 't': sprintf(w,"%8s", next_word(dates(&info->date,0))); break;
  605.         case 'm': MultiCol=form; form=0;      break;
  606.         case '%': *w=*++s;                    break;
  607.         case  0 : *w='%';                     break;
  608.         default : *w='%';  *w++=*s; *w=0;     break;
  609.         }
  610.         if( cut ) buf[form]=0;
  611.         *d=0; s++;
  612.         d+=sprintf(d,sign<0?"%-*s":"%*s",form,buf);
  613.     }
  614.     if( MultiCol==-1 ) { *d++='\n'; }
  615.     *d=0;
  616. }
  617.  
  618.  
  619.  
  620. int
  621. do_quit( void )
  622. {
  623.     if (Src_stack) {
  624.         Quit = 1;
  625.         return(do_return());
  626.     }
  627.     main_exit(0);
  628.     return 0;
  629. }
  630.  
  631. int
  632. do_echo( void )
  633. {
  634.     char *args=compile_av(av,1,ac,' ',0);
  635.     fprintf( (options&2)?stderr:stdout, (options&1)?"%s":"%s\n",args );
  636.     free(args);
  637.     return 0;
  638. }
  639.  
  640.  
  641. static int
  642. breakcheckd(void)
  643. {
  644.     int ret=!o_nobreak && SetSignal(0L,0L) & SIGBREAKF_CTRL_D;
  645.     if( ret )
  646.         fprintf(stderr,"^D\n");
  647.     return ret;
  648. }
  649.  
  650. /* gets a line from file, joining lines if they end in '\' */
  651.  
  652. #define MAXLINE 512
  653.  
  654. static int
  655. srcgets(char **buf, int *buflen, FILE *file)
  656. {
  657.     char *bufptr=*buf, *p, *new, concat=0, cont;
  658.     int   totlen=0, len;
  659.  
  660.     do {
  661.         if( totlen+MAXLINE > *buflen ) {
  662.             new=salloc(*buflen *= 2);
  663.             memcpy( new, *buf, 1+bufptr-*buf );
  664.             bufptr+= new-*buf;
  665.             free(*buf);
  666.             *buf=new;
  667.         }
  668.         if (fgets(bufptr, MAXLINE, file)==NULL) {
  669.             if( concat )
  670.                 fprintf(stderr,"Source: missing '}'\n");
  671.             else if (bufptr != *buf)
  672.                 fprintf(stderr,"Source: file ends in '\\'\n");
  673.             return -1;
  674.         }
  675.         len= strlen( bufptr );
  676.         totlen+= len;
  677.  
  678.         cont=0;
  679.  
  680.         p=bufptr+len-1;
  681.         if(  p>=bufptr && *p=='\n') *p--=0;
  682.         if(  p< bufptr   ) ;
  683.         else if( *p=='\\') *p--=0, cont=1;
  684.         else if( *p=='{' ) concat++;
  685.         else if( *p=='}' ) {
  686.             if( concat>0 ) {
  687.                 concat--;
  688.                 if( concat ) *++p='\n';
  689.             }
  690.         } else if( concat ) *++p='\n';
  691.         bufptr=++p;
  692.     } while( cont || concat );
  693.     *bufptr=0;
  694.     return totlen;
  695. }
  696.  
  697.  
  698.  
  699. int
  700. do_source( char *str )
  701. {
  702.     FILE *fi;
  703.     char *buf;
  704.     ROOT *root;
  705.     int  retcode, len, bufsize=512+MAXLINE;
  706.  
  707.     if (Src_stack == MAXSRC) {
  708.         ierror(NULL,217);
  709.         return -1;
  710.     }
  711.  
  712.     if ((fi = fopen (av[1], "r")) == 0)
  713.         { pError(av[1]); return -1;    }
  714.  
  715.     push_locals(root=(ROOT *)salloc( sizeof(ROOT)));
  716.     buf=salloc(bufsize);
  717.  
  718.     set_var(LEVEL_SET | LEVEL_LOCAL, v_passed, next_word(next_word(str)));
  719.     Src_pos  [Src_stack] = 0;
  720.     Src_abort[Src_stack] = 0;
  721.     Src_base [Src_stack] = fi;
  722.     Src_if[Src_stack]=If_stack;
  723.     ++Src_stack;
  724.     while ((len=srcgets(&buf, &bufsize, fi))>=0&& !dobreak()&& !breakcheckd()){
  725.         Src_pos[Src_stack-1] += len;
  726.         if (Verbose&VERBOSE_SOURCE && !forward_goto)
  727.             if( Verbose&VERBOSE_HILITE )
  728.                 fprintf(stderr,"%s)%s%s\n",o_hilite,buf,o_lolite);
  729.             else 
  730.                 fprintf(stderr,")%s\n",buf);
  731.         retcode=execute(buf);
  732.         if( retcode>=o_failat || Src_abort[Src_stack-1] )
  733.             break;
  734.         retcode=0;
  735.     }
  736.     --Src_stack;
  737.     if( If_stack>Src_if[Src_stack] )
  738.         If_stack=Src_if[Src_stack], disable=If_stack && If_base[If_stack-1];
  739.  
  740.     if (forward_goto) ierror(NULL,501);
  741.     forward_goto = 0;
  742.     unset_level(LEVEL_LABEL+ Src_stack);
  743.     unset_var(LEVEL_SET, v_gotofwd);
  744.     unset_var(LEVEL_SET, v_passed);
  745.     fclose (fi);
  746.  
  747.     pop_locals();
  748.     free(buf);
  749.     free(root);
  750.  
  751.     return retcode;
  752. }
  753.  
  754. /* set process cwd name and $_cwd, if str != NULL also print it. */
  755.  
  756. void
  757. set_cwd(void)
  758. {
  759.     char pwd[130];
  760.  
  761.     PathName(Myprocess->pr_CurrentDir, pwd, 128L);
  762.     set_var(LEVEL_SET, v_cwd, pwd);
  763.     /* put the current dir name in our CLI task structure */
  764.     CtoBStr(pwd, Mycli->cli_SetName, 128L);
  765. }
  766.  
  767. int
  768. do_pwd( void )
  769. {
  770.     set_cwd();
  771.     puts( get_var( LEVEL_SET, v_cwd ));
  772.     return 0;
  773. }
  774.  
  775.  
  776. /*
  777.  * CD
  778.  *
  779.  * CD(str, 0)      -do CD operation.
  780.  *
  781.  */
  782.  
  783. extern int qcd_flag;
  784.  
  785. static char lastqcd[80];
  786. static FILE *qcdfile;
  787. static int  NumDirs;
  788.  
  789. static int
  790. countfunc( long mask, char *file, char *fullpath )
  791. {
  792.     fprintf( qcdfile, "%s\n", fullpath );
  793.     fprintf( stdout, "\r Directories: %d", ++NumDirs );
  794.     fflush ( stdout );
  795.     return 0;
  796. }
  797.  
  798. int
  799. do_cd(void)
  800. {
  801.     BPTR oldlock, filelock;
  802.     char buf[100], *old, *str=av[1];
  803.     int  i=1, repeat;
  804.  
  805.     if( options & 1 ) {
  806.         if( !o_csh_qcd ) { fprintf(stderr,"$_qcd unset\n"); return 20; }
  807.         if( !(qcdfile=fopen( o_csh_qcd, "w" )))
  808.             { fprintf(stderr,"Can't open output\n"); return 20; }
  809.         for( ; i<ac && !dobreak(); i++ ) {
  810.             NumDirs=0;
  811.             printf("%s\n",av[i]);
  812.             newrecurse( SCAN_DIRENTRY | SCAN_RECURSE, av[i], countfunc );
  813.             printf("\n");
  814.         }
  815.         fclose(qcdfile);
  816.         return 0;
  817.     }
  818.  
  819.     if( !*str ) {
  820.         printf("%s\n", get_var( LEVEL_SET, v_cwd ));
  821.         return 0;
  822.     }
  823.  
  824.     if (filelock=Lock(str,ACCESS_READ)) {
  825.         lastqcd[0]=0;
  826.         if (!isdir(str)) { UnLock(filelock); ierror(str,212); return 20; }
  827.     } else {
  828.         repeat= !strncmp( lastqcd, str, 79 );
  829.         strncpy( lastqcd, str, 79);
  830.  
  831.         if( !quick_cd( buf, av[i], repeat) )
  832.             { fprintf(stderr,"Object not found %s\n",str); return 20; }
  833.         if (!(filelock=Lock(buf,ACCESS_READ))) 
  834.             { pError(buf); return 20; }
  835.     }
  836.     if (oldlock=CurrentDir(filelock)) UnLock(oldlock);
  837.     if( !(old=get_var(LEVEL_SET, v_cwd)) )
  838.         old="";
  839.     set_var(LEVEL_SET, v_lcd, old);
  840.     set_cwd();
  841.  
  842.     return 0;
  843. }
  844.  
  845. char *
  846. quick_cd( char *buf, char *name, int repeat )
  847. {
  848.     if( !o_csh_qcd || !exists(o_csh_qcd))
  849.         return NULL;
  850.     qcd_flag=repeat ? 2 : 1;
  851.     strcpy(buf,name);
  852.     if( quicksearch( o_csh_qcd, 1, buf)!=2 )
  853.         return NULL;
  854.     return buf;
  855. }
  856.  
  857.  
  858. int
  859. do_mkdir( void )
  860. {
  861.     int i;
  862.     BPTR lock;
  863.     
  864.     for (i=1; i<ac; ++i) {
  865.         if (exists(av[i]))
  866.             ierror(av[i],203);
  867.         else if (lock=CreateDir(av[i]))
  868.             UnLock (lock);
  869.         else
  870.             pError(av[i]);
  871.     }
  872.     return 0;
  873. }
  874.  
  875. int
  876. do_mv( void )
  877. {
  878.     char *dest, buf[256];
  879.     int dirflag, i;
  880.  
  881.     dirflag=isdir(dest=av[--ac]);
  882.     if (ac>3 && !dirflag) { ierror(dest, 507); return (-1); }
  883.     for (i=1; i<ac; ++i) {
  884.         strcpy(buf, dest);
  885.         if (dirflag) TackOn(buf, BaseName(av[i]));
  886.         if (Rename(av[i], buf)==0)
  887.             { pError(av[i]); return -1; }
  888.         else 
  889.             clear_archive_bit( buf );
  890.     }
  891.     return 0;
  892. }
  893.  
  894. static char *searchstring;
  895. static char docr;
  896.  
  897. int
  898. all_args( int (*action)FUNCARG(long,char*,char*), int dirsflag )
  899. {
  900.     int  i;
  901.     long mask= SCAN_FILE;
  902.  
  903.     if( options&1 )
  904.         mask |= SCAN_RECURSE;
  905.     if( dirsflag )
  906.         mask |= SCAN_DIR;
  907.  
  908.     for ( i=1; i<ac && !dobreak(); ++i)
  909.         if (isdir(av[i])) {
  910.             if (options & 1) 
  911.                 newrecurse(mask, av[i], action);
  912.             if (dirsflag) 
  913.                 (*action)(SCAN_DIR,av[i],av[i]);
  914.         } else
  915.             (*action)(SCAN_FILE,av[i],av[i]);
  916.     if(docr) printf("\n"),docr=0;
  917.     dobreak();
  918.     return 0;
  919. }
  920.  
  921. #define SEARCH_REC   1
  922. #define SEARCH_CASE  2
  923. #define SEARCH_WILD  4
  924. #define SEARCH_NUM   8
  925. #define SEARCH_EXCL  16
  926. #define SEARCH_QUIET 32
  927. #define SEARCH_VERB  64
  928. #define SEARCH_BIN   128
  929. #define SEARCH_FILE  256
  930. #define SEARCH_ABORT 512
  931. #define SEARCH_LEFT  1024
  932. #define SEARCH_ONLY  2048
  933.  
  934. static int abort_search;
  935. static char lowbuf[256], file_name, file_cr;
  936.  
  937. static int
  938. search_file( long mask, char *s, char *fullpath )
  939. {
  940.     PATTERN *pat;
  941.     FILE *fi;
  942.     char *p, *q;
  943.     int nocasedep, lctr, len, excl=((options & 16) !=0 ), yesno;
  944.     char buf[256], searchit[120], first, left;
  945.  
  946.     if( abort_search )
  947.         return 0;
  948.  
  949.     nocasedep=!(options & SEARCH_CASE);
  950.     lctr= docr= file_name= file_cr= 0;
  951.     if (!(options & (SEARCH_QUIET|SEARCH_FILE))) {
  952.         if( options & SEARCH_VERB )
  953.             printf("Examining %s...\n",fullpath);
  954.         else 
  955.             printf("\015Examining %s...\033[K",fullpath), docr=1;
  956.         fflush( stdout );
  957.     }
  958.  
  959.     strcpy(searchit,searchstring);
  960.     if (options & SEARCH_WILD) strcat(searchit,"\n");
  961.     len=strlen(searchit);
  962.     if (nocasedep) strupr(searchit);
  963.     first=*searchit;
  964.  
  965.     if( strcmp("STDIN",s) && !(options&SEARCH_WILD) && !excl ||
  966.                  options&SEARCH_BIN )
  967.         if( quicksearch(s,nocasedep,searchit) )
  968.             return 0;
  969.  
  970.     if( options&SEARCH_BIN )
  971.         { fprintf(stderr,"Out of memory\n"); return 20; }
  972.  
  973.     if(!(pat=compare_preparse( searchit, options&SEARCH_CASE ))) 
  974.         { fprintf(stderr,"Invalid pattern\n"); return 20; }
  975.  
  976.     fi = strcmp("STDIN",s) ?  fopen(s,"r") : stdin;
  977.     if (fi==NULL) { pError(s); return 20; }
  978.  
  979.     prepscroll(0);
  980.  
  981.     while (fgets(buf,256,fi) && !dobreak()) {
  982.         lctr++; left=1;
  983.         if (options & SEARCH_WILD)
  984.             yesno=compare_ok(pat, p=buf);
  985.         else {
  986.             if (nocasedep) {
  987.                 strcpy(lowbuf,buf);
  988.                 strupr(lowbuf);
  989.                 p=lowbuf;
  990.             } else
  991.                 p=buf;
  992.             q=p;
  993.             while ((p=index(p,first)) && strncmp(p++,searchit,len)) ;
  994.             yesno= (p!=NULL);
  995.             left = --p - q;
  996.         }
  997.         if( yesno ^ excl )
  998.             if(!(options&SEARCH_ONLY)|| !isalphanum(p[-1])&&!isalphanum(p[len]))
  999.                 if( found(buf, lctr, 0, s, left ) )
  1000.                     break;
  1001.     }
  1002.     compare_free(pat);
  1003.     if (fi!=stdin) fclose (fi);
  1004.     if( file_cr ) printf("\n");
  1005.     return 0;
  1006. }
  1007.  
  1008. int qcd_flag, qcd_offs;
  1009.  
  1010. #define READCHUNK 60000
  1011.  
  1012. static int
  1013. quicksearch( char *name, int nocasedep, char *pattern )
  1014. {
  1015.     int i, ptrn=strlen(pattern);
  1016.     char ut[256], *buffer, *lend;
  1017.     char *uptab=ut, *get, c, *lpos, *lstart;
  1018.     int len, lnum, qcd=qcd_flag, repeat=(qcd==2 && qcd_offs!=0), buflen;
  1019.     int sofar, got;
  1020.     BPTR fh;
  1021.  
  1022. #ifdef AZTEC_C
  1023.     while(0) while(0) c=c=0, uptab=uptab=ut, get=get=NULL;
  1024. #endif
  1025.  
  1026.     qcd_flag=0;
  1027.     if( !(fh=Open(name,MODE_OLDFILE))) { 
  1028.         i=(long)IoErr(), docr=0;
  1029.         printf("\n");
  1030.         ierror(name,i);
  1031.         return 1;
  1032.     }
  1033.     len=filesize( name );
  1034.     buflen=len+3;
  1035.     if( !(buffer=(void *)AllocMem(buflen,0))) { Close(fh); return 0; }
  1036.     sofar=0;
  1037.     do {
  1038.         got=Read( fh, (char *)buffer+sofar, READCHUNK);
  1039.         sofar+=got;
  1040.     } while( got==READCHUNK );
  1041.     Close( fh);
  1042.     if( sofar != len ) { 
  1043.         FreeMem( buffer, buflen );
  1044.         pError(pattern); return 1;
  1045.     }
  1046.     if(buffer[len-1]!='\n')
  1047.         buffer[len++]='\n';
  1048.  
  1049.     if( nocasedep )
  1050.         strupr( pattern );
  1051.  
  1052.     if( !qcd )
  1053.         prepscroll(0);
  1054.  
  1055.     for( i=0; i<256; i++ ) uptab[i]=i;
  1056.     if( nocasedep ) for( i='a'; i<='z'; i++ ) uptab[i]=i-'a'+'A';
  1057. retry:
  1058.     c=*pattern, buffer[len]=c, buffer[len+1]=c;
  1059.     get= (qcd==2) ? buffer+qcd_offs : buffer;
  1060.     if( qcd==1 ) qcd_offs=0;
  1061.  
  1062.     lpos=lstart=buffer, lnum=1;
  1063.     for( ;; ) {
  1064.         do ; while( uptab[*get++]!=c );
  1065.         if( --get>=buffer + len )
  1066.             break;
  1067.         for( i=1; i<ptrn; i++ )
  1068.             if( uptab[get[i]]!=pattern[i] )
  1069.                 break;
  1070.         if( i==ptrn ) {
  1071.             for( ;lpos<get; lpos++ )
  1072.                 if( *lpos=='\n' )
  1073.                     lstart=lpos+1, lnum++;
  1074.             for( lend=lstart+1; *lend!='\n'; lend++ ) ;
  1075.             if( qcd ) {
  1076.                 if( get[-1]==':' || get[-1]=='/' ||
  1077.                       lpos==lstart && lend[-1]==':' ) {
  1078.                     char *tmp;
  1079.                     for( tmp=get+ptrn; *tmp&& *tmp!='\n'&& *tmp!='/'; tmp++ );
  1080.                     if( *tmp!='/' ) {
  1081.                         *lend=0;
  1082.                         strncpy(pattern,lstart,79);
  1083.                         qcd_offs=lend-buffer;
  1084.                         FreeMem( buffer, buflen );
  1085.                         return 2;
  1086.                     }
  1087.                 } else 
  1088.                     lend=lpos+1;
  1089.             } else {
  1090.                 *lend=0;
  1091.                 if(!(options&SEARCH_ONLY) ||
  1092.                      !isalphanum(lpos[-1])&&!isalphanum(lpos[ptrn]))
  1093.                     if(found(lstart, lnum, get-buffer, name, lpos==lstart ))
  1094.                         break;
  1095.                 *lend='\n';
  1096.             }
  1097.             get=lend+1;
  1098.         } else
  1099.             get++;
  1100.     }
  1101.     if( repeat )  { repeat=0; qcd_offs=0; goto retry; }
  1102.     if( file_cr ) { printf("\n"); quickscroll(); }
  1103.     FreeMem( buffer, buflen );
  1104.     return 1;
  1105. }
  1106.  
  1107. static int
  1108. found( char *lstart, int lnum, int loffs, char *name, char left )
  1109. {
  1110.     int fileabort=0;
  1111.  
  1112.     if( (options&SEARCH_LEFT) && !left)
  1113.         return 0;
  1114.  
  1115.     if ( docr )
  1116.         { quickscroll(); printf("\n"); docr=0; }
  1117.  
  1118.     if( options&SEARCH_FILE ) {
  1119.         file_cr=1;
  1120.         if( !file_name )
  1121.             printf("%s",name), file_name=1;
  1122.         if( options&SEARCH_NUM )
  1123.             fileabort=1;
  1124.         else 
  1125.             printf(" %d",lnum);
  1126.     } else if( options & SEARCH_BIN ) {
  1127.         if (!(options & SEARCH_NUM))
  1128.             printf("Byte offset %d\n",loffs);
  1129.         else 
  1130.             printf("%d\n",loffs);
  1131.         quickscroll();
  1132.     } else {
  1133.         if (!(options & SEARCH_NUM))
  1134.             printf("%4d ",lnum);
  1135.         printf((lstart[strlen(lstart)-1]=='\n')?"%s":"%s\n",lstart);
  1136.         quickscroll();
  1137.     }
  1138.     abort_search= options&SEARCH_ABORT;
  1139.     return dobreak() || fileabort || abort_search;
  1140. }
  1141.  
  1142.  
  1143. int
  1144. do_search( void )
  1145. {
  1146.     if(!isconsole(Output())) options |= SEARCH_VERB;
  1147.     abort_search=0;
  1148.     searchstring=av[--ac];
  1149.     all_args(search_file, 0);
  1150.     return 0;
  1151. }
  1152.  
  1153. static int 
  1154. rm_file( long mask, char *file, char *fullpath )
  1155. {
  1156.     if ( *file && file[strlen(file)-1]=='/' ) file[strlen(file)-1]=0;
  1157.     if (has_wild) printf(" %s...",fullpath);
  1158.     if (options & 2) SetProtection(file,0L);
  1159.     if (!DeleteFile(file)) {
  1160.         if( !(options & 4) )
  1161.             { pError (file); return 20; }
  1162.     } else if (has_wild)
  1163.         printf("Deleted\n");
  1164.     return 0;
  1165. }
  1166.  
  1167. int
  1168. do_rm( void )
  1169. {
  1170.     all_args( rm_file, 1);
  1171.     return 0;
  1172. }
  1173.  
  1174.  
  1175. int
  1176. do_history( void )
  1177. {
  1178.     HIST *hist;
  1179.     int i = H_tail_base;
  1180.     int len = av[1] ? strlen(av[1]) : 0;
  1181.     char buf[250];
  1182.  
  1183.     if( options&2 ) {
  1184.         while( safegets(buf,stdin) )
  1185.             add_history(buf);
  1186.         return 0;
  1187.     }
  1188.  
  1189.     for (hist = H_tail; hist && !dobreak(); hist = hist->prev, i++)
  1190.         if (len == 0 || !strncmp(av[1], hist->line, len))
  1191.             if( options&1 )
  1192.                 printf("%s\n", hist->line);
  1193.             else 
  1194.                 printf("%3d %s\n", i, hist->line);
  1195.     return 0;
  1196. }
  1197.  
  1198. int
  1199. do_mem( void )
  1200. {
  1201.     static long clast, flast;
  1202.     long cfree, ffree, i;
  1203.     char *desc="Free", *mem;
  1204.  
  1205.     if( options&32 )
  1206.         for( i=0; i<4; i++ )
  1207.             if(mem=(char*)AllocMem(0x7fffffff,0))
  1208.                 FreeMem(mem,0x7fffffff);
  1209.  
  1210.     Forbid();
  1211.     cfree = AvailMem (MEMF_CHIP);
  1212.     ffree = AvailMem (MEMF_FAST);
  1213.     Permit();
  1214.     if( options&8 ) {
  1215.         clast=cfree, flast=ffree;
  1216.         return 0;
  1217.     }
  1218.     if( options&16 )
  1219.         cfree=clast-cfree, ffree=flast-ffree, desc="Used";
  1220.     if( options&4 ) {
  1221.         if     ( options & 1 ) printf("%ld\n",cfree);
  1222.         else if( options & 2 ) printf("%ld\n",ffree);
  1223.         else                   printf("%ld\n",cfree+ffree);
  1224.     } else {
  1225.         if     ( options & 1 ) printf("Free CHIP memory:%10s\n",itoa(cfree));
  1226.         else if( options & 2 ) printf("Free FAST memory:%10s\n",itoa(ffree));
  1227.         else {
  1228.             if(ffree) {
  1229.                 printf("FAST memory:%10s\n",itoa(ffree));
  1230.                 printf("CHIP memory:%10s\n",itoa(cfree));
  1231.             }
  1232.             printf("Total  %s:%10s\n",desc,itoa(cfree+ffree));
  1233.         }
  1234.     }
  1235.     return 0;
  1236. }
  1237.  
  1238. int
  1239. do_forline( void )
  1240. {
  1241.     char vname[33], buf[256], *cstr;
  1242.     int lctr;
  1243.     FILE *f;
  1244.  
  1245.     strcpy(vname,av[1]);
  1246.     if( !strcmp(av[2],"STDIN") )
  1247.         f=stdin;
  1248.     else 
  1249.         if(!(f=fopen(av[2],"r"))) { pError(av[2]); return 20; }
  1250.  
  1251.     lctr=0;
  1252.     ++H_stack;
  1253.     cstr = compile_av (av, 3, ac, ' ', 0);
  1254.     while (fgets(buf,256,f) && !dobreak() && !breakcheckd()) {
  1255.         buf[strlen(buf)-1]='\0';    /* remove CR */
  1256.         lctr++;
  1257.         set_var(LEVEL_SET | LEVEL_LOCAL, vname, buf);
  1258.         sprintf(buf,"%d",lctr);
  1259.         set_var(LEVEL_SET | LEVEL_LOCAL, v_linenum, buf);
  1260.         exec_command(cstr);
  1261.     }
  1262.     if( f!=stdin ) fclose(f);
  1263.     --H_stack;
  1264.     free (cstr);
  1265.     if( lctr ) {
  1266.         unset_var (LEVEL_SET, vname);
  1267.         unset_var (LEVEL_SET, v_linenum);
  1268.     }
  1269.     return 0;
  1270. }
  1271.  
  1272. int
  1273. do_fornum( void )
  1274. {
  1275.     char vname[33], buf[16];
  1276.     int n1, n2, step, i=1, verbose, runs=0;
  1277.     char *cstr;
  1278.  
  1279.     verbose=(options & 1);
  1280.     strcpy(vname,av[i++]);
  1281.     n1=myatoi(av[i++],-32767,32767); if (atoierr) return 20;
  1282.     n2=myatoi(av[i++],-32767,32767); if (atoierr) return 20;
  1283.     if (options & 2) {
  1284.         step=myatoi(av[i++],-32767,32767); if (atoierr) return 20;
  1285.     } else
  1286.         step=1;
  1287.     ++H_stack;
  1288.     cstr = compile_av (av, i, ac, ' ', 0);
  1289.     for (i=n1; (step>=0 ? i<=n2 : i>=n2) && !CHECKBREAK() && !breakcheckd();
  1290.          i+=step, runs++) {
  1291.         if (verbose) fprintf(stderr, "fornum: %d\n", i);
  1292.         sprintf(buf,"%d",i);
  1293.         set_var (LEVEL_SET | LEVEL_LOCAL, vname, buf);
  1294.         exec_command(cstr);
  1295.     }
  1296.     --H_stack;
  1297.     free (cstr);
  1298.     if( runs )
  1299.         unset_var (LEVEL_SET, vname);
  1300.     return 0;
  1301. }
  1302.  
  1303. /*
  1304.  * foreach var_name  ( str str str str... str ) commands
  1305.  * spacing is important (unfortunately)
  1306.  *
  1307.  * ac=0    1 2 3 4 5 6 7
  1308.  * foreach i ( a b c ) echo $i
  1309.  * foreach i ( *.c ) "echo -n "file ->";echo $i"
  1310.  */
  1311.  
  1312. int
  1313. do_foreach( void )
  1314. {
  1315.     int cstart, cend;
  1316.     char *cstr, vname[33];
  1317.     char **fav;
  1318.     int i=1, verbose;
  1319.  
  1320.     verbose=(options & 1);
  1321.     strcpy(vname, av[i++]);
  1322.     if (*av[i] == '(') i++;
  1323.     cstart = i;
  1324.     while (i<ac && *av[i] != ')') i++;
  1325.     if (i > ac) { fprintf(stderr,"')' expected\n"); return 20; }
  1326.     ++H_stack;
  1327.     cend = i;
  1328.  
  1329.     fav = (char **)salloc(sizeof(char *) * (ac));
  1330.     for (i = cstart; i < cend; ++i) fav[i] = av[i];
  1331.  
  1332.     cstr = compile_av (av, cend + 1, ac, ' ', 0);
  1333.  
  1334.     for (i = cstart; i<cend && !CHECKBREAK() && !breakcheckd(); ++i) {
  1335.         set_var (LEVEL_SET | LEVEL_LOCAL, vname, fav[i]);
  1336.         if (verbose) fprintf(stderr, "foreach: %s\n", fav[i]);
  1337.         execute(cstr);
  1338.     }
  1339.     --H_stack;
  1340.     free (fav);
  1341.     free (cstr);
  1342.     if( cstart<cend)
  1343.         unset_var (LEVEL_SET, vname);
  1344.     return 0;
  1345. }
  1346.  
  1347. int
  1348. do_forever( char *str )
  1349. {
  1350.     int rcode = 0;
  1351.     char *ptr = next_word( str );
  1352.  
  1353.     ++H_stack;
  1354.     for (;;) {
  1355.         if (CHECKBREAK() || breakcheckd()) { rcode = 20; break; }
  1356.         if (exec_command (ptr) > 0) {
  1357.             str = get_var(LEVEL_SET, v_lasterr);
  1358.             rcode = (str) ? atoi(str) : 20;
  1359.             break;
  1360.         }
  1361.     }
  1362.     --H_stack;
  1363.     return rcode;
  1364. }
  1365.  
  1366. extern struct IntuitionBase *IntuitionBase;
  1367.  
  1368.  
  1369. int
  1370. do_window( void )
  1371. {
  1372.     long x=-1, y=-1, w=-1, h=-1, maxwidth, maxheight, arg[5];
  1373.     int i;
  1374.  
  1375.     if(options & 32) { /* -q */
  1376.         struct Screen *scrn;
  1377.         struct Window *window;
  1378.         char buf[80];
  1379.         buf[40]=0;
  1380.         for (scrn=IntuitionBase->FirstScreen; scrn; scrn=scrn->NextScreen) {
  1381.             buf[0]=0;
  1382.             if( scrn->Title )
  1383.                 strncpy(buf,(char*)scrn->Title,40);
  1384.             printf("\nScreen \"%s\" (%d,%d,%dx%dx%d):\n",
  1385.                 buf,
  1386.                 scrn->LeftEdge,
  1387.                 scrn->TopEdge,
  1388.                 scrn->Width,
  1389.                 scrn->Height,
  1390.                 scrn->BitMap.Depth
  1391.             );
  1392.             for (window=scrn->FirstWindow; window; window=window->NextWindow) {
  1393.                 buf[0]=0;
  1394.                 if( window->Title )
  1395.                     strncpy(buf,(char*)window->Title,40);
  1396.                 printf("\tWindow\t\"%s\" (%d,%d,%dx%d)\n",
  1397.                     buf,
  1398.                     window->LeftEdge,
  1399.                     window->TopEdge,
  1400.                     window->Width,
  1401.                     window->Height
  1402.                 );
  1403.             }
  1404.         }
  1405.         return 0;
  1406.     }
  1407.  
  1408.     if( o_nowindow || !Win )
  1409.         return 20;
  1410.  
  1411.     maxwidth = Win->WScreen->Width;
  1412.     maxheight= Win->WScreen->Height;
  1413.     if( options&1 )
  1414.         x=Win->LeftEdge,y=Win->TopEdge,w=Win->MinWidth,h=Win->MinHeight;
  1415.     if( options&2 ) x=y=0, w=maxwidth, h=maxheight;
  1416.     if( options&4 ) WindowToFront(Win);
  1417.     if( options&8 ) WindowToBack(Win);
  1418.     if( options&16) ActivateWindow(Win);
  1419.     if( ac >= 5) {
  1420.         for(i=1; i<5; i++) {
  1421.             arg[i] = myatoi(av[i],0,1023); if (atoierr) return 20;
  1422.         }
  1423.         x=arg[1]; y=arg[2]; w=arg[3]; h=arg[4];
  1424.     }
  1425.     if( w!=-1 ) {
  1426.         int i;
  1427.         if ( x+w>maxwidth || y+h>maxheight ) {
  1428.             ierror(NULL, 500);
  1429.             return 20;
  1430.         }
  1431.         if( w<Win->MinWidth  ) w=Win->MinWidth;
  1432.         if( h<Win->MinHeight ) h=Win->MinHeight;
  1433.         if( Win->LeftEdge!=0 || Win->TopEdge!=0 )
  1434.             MoveWindow(Win, -Win->LeftEdge, -Win->TopEdge );
  1435.         if( Win->Width!=w || Win->Height!=h )
  1436.             SizeWindow(Win, w-Win->Width   , h-Win->Height  );
  1437.         if( x || y )
  1438.             MoveWindow(Win, x, y );
  1439.         for( i=0; i<10; i++ ) {
  1440.             if(  Win->LeftEdge==x && Win->TopEdge==y && 
  1441.                  Win->Width   ==w && Win->Height ==h )
  1442.                 break;
  1443.             Delay(5);
  1444.         }
  1445.     } else 
  1446.         Delay(20); /* pause 1/2 sec. before trying to print */
  1447.  
  1448.     Delay(10);
  1449.     printf("\014");
  1450.     return 0;
  1451. }
  1452.  
  1453. static void
  1454. setsystemtime(struct DateStamp *ds)
  1455. {
  1456.     struct timerequest tr;
  1457.     long secs= ds->ds_Days*86400+ds->ds_Minute*60+ds->ds_Tick/TICKS_PER_SECOND;
  1458.  
  1459.     if (OpenDevice(TIMERNAME, UNIT_VBLANK,(struct IORequest *)&tr, 0L)) {
  1460.         fprintf(stderr,"Clock error: can't open timer device\n");
  1461.         return;
  1462.     }
  1463.  
  1464.     tr.tr_node.io_Message.mn_Node.ln_Type = NT_MESSAGE;
  1465.     tr.tr_node.io_Message.mn_Node.ln_Pri = 0L;
  1466.     tr.tr_node.io_Message.mn_Node.ln_Name = NULL;
  1467.     tr.tr_node.io_Message.mn_ReplyPort = NULL;
  1468.     tr.tr_node.io_Command = TR_SETSYSTIME;
  1469.     tr.tr_time.tv_secs = secs;
  1470.     tr.tr_time.tv_micro = 0L;
  1471.     if (DoIO ((struct IORequest *)&tr))
  1472.         fprintf(stderr,"Clock error: can't talk to timer device\n");
  1473.     CloseDevice ((struct IORequest *)&tr);
  1474. }
  1475.  
  1476. static char tday[10];
  1477.  
  1478. char *
  1479. dates( struct DateStamp *dss, int flags )
  1480. {
  1481.     static char timestr[40];
  1482.     char tdate[10], ttime[10];
  1483.     struct DateTime dt;
  1484.     struct DateStamp *myds=&(dt.dat_Stamp);
  1485.  
  1486.     dt.dat_Format=FORMAT_DOS;
  1487.     dt.dat_StrDay=tday;
  1488.     dt.dat_StrDate=tdate;
  1489.     dt.dat_StrTime=ttime;
  1490.     dt.dat_Flags=flags ? DTF_SUBST : 0;
  1491.     myds->ds_Days=dss->ds_Days;
  1492.     myds->ds_Minute=dss->ds_Minute;
  1493.     myds->ds_Tick=dss->ds_Tick;
  1494.     if(  myds->ds_Days<0   || myds->ds_Days>36500 ||
  1495.          myds->ds_Minute<0 || myds->ds_Minute>1440 || 
  1496.          myds->ds_Tick<0   || myds->ds_Tick>3000 || StamptoStr(&dt) )
  1497.         strcpy(tdate,"---------"), strcpy(ttime,"--------");
  1498.     ttime[8]=0;
  1499.     sprintf(timestr,"%-9s %-8s",tdate,ttime);
  1500.     timestr[18]=0;    /* protection against bad timestamped files */
  1501.     return timestr;
  1502. }
  1503.  
  1504. int
  1505. do_date( void )
  1506. {
  1507.     static long stopwatch;
  1508.     struct DateStamp dss;
  1509.     struct DateTime dt;
  1510.     long time;
  1511.     int i=1;
  1512.  
  1513.     dt.dat_Format=FORMAT_DOS;
  1514.     if (ac==1) {
  1515.         DateStamp(&dss);
  1516.         time=dss.ds_Minute*6000+2*dss.ds_Tick;   /* 2 = 100/TickPerSec   */
  1517.         if( options & 1 )
  1518.             stopwatch=time;
  1519.         else if( options&2 )
  1520.             printf( "%d.%02d\n",(time-stopwatch)/100,(time-stopwatch)%100);
  1521.         else 
  1522.             printf("%s %s\n",tday,dates(&dss,0));
  1523.     } else {
  1524.         DateStamp(&dt.dat_Stamp);
  1525.         for ( ; i<ac; i++) {
  1526.             dt.dat_StrDate=NULL;
  1527.             dt.dat_StrTime=NULL;
  1528.             dt.dat_Flags=DTF_FUTURE;
  1529.             if (index(av[i],':')) dt.dat_StrTime=av[i];
  1530.                 else dt.dat_StrDate=av[i];
  1531.             if (StrtoStamp(&dt)) ierror(av[i],500);
  1532.         }
  1533.         setsystemtime( & (dt.dat_Stamp) );
  1534.     }
  1535.     return 0;
  1536. }
  1537.