Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Path: utzoo!mnetor!seismo!rutgers!mit-eddie!uw-beaver!ubc-vision!van-bc!jlydiatt From: jlydiatt@van-bc.UUCP (Jeff Lydiatt) Newsgroups: comp.sys.amiga Subject: Cp: A replacement for AmigaDos Copy Message-ID: <741@van-bc.UUCP> Date: Fri, 22-May-87 20:54:59 EDT Article-I.D.: van-bc.741 Posted: Fri May 22 20:54:59 1987 Date-Received: Sat, 23-May-87 19:34:56 EDT Organization: Public Access Network, Vancouver, BC. Lines: 1217 Keywords: AmigaDos Copy Regular Expressions Here is a replacement for AmigaDog "copy" program that I have been working on for quite a while. It implements the AmigaDos pattern matching algorithm, the "all" command, and has the added bonus that it retains the date of copied file. It's my first posting to the net, and I have my fingers crossed that all goes well... Contents: cp.doc - documentation cp.c - the main program PatMatch.c - supporting routines to implement the pattern matching. setDate.c - gets and sets the file date. wb_parse.c - Aztec allows you to skip the workbench parms parse. makefile - to compile and link the whole thing. cp.uue - uuencoded cp ============ cat ============ Cp - a replacement for AmigaDos Copy that retains the date. by Jeff Lydiatt Vancouver, Canada Release 1.0, May 17, 1987 Cp and the c source is freely redistributable for personal non-commercial use. Commercial rights are reserved by the author. Feel free to make any modifications or use any of the modules in other programs. I encourage you to do so and hope you will release the code so others can learn by it. Cp has most of the features of the AmigaDos copy command: -------------------------------------------------------- o Cp supports the AmigaDos style pattern matching in the "from" name. o Cp supports the All option. o Cp supports the optional "from" and "to" qualifiers for file names. o Cp will copy directories Cp has a number of features not found in AmigaDos copy: ------------------------------------------------------- o Cp will retain the date of the copied file. o Cp uses a 32000 byte buffer, which speeds copies when the from and to file is on the same disk. o You may specify the current directory by a "to" name of ".". For example if your current directory is "Df0:", "cp ram:x ." will copy the file called x in your ram: disk to "df0:x". o Cp will also create the "to" file for you if you use the "All" option. For example if "x" is a directory, "cp from x to y" will create a directory called "y", and will copy all the files in x to the newly created "y" directory. About the AmigaDos-style pattern matching. ----------------------------------------- Cp uses a compact function for regular expression pattern matching. The algorithm was taken from a paper by Martin Richards, that was published in the September 1979 issue of "Software, Practice and Experience". Professor Richards published his example in BCPL, and I have (sucessfully I think) translated it to C. It's interesting to note that I translated it verbatim, with no special modifications to adapt it to AmigaDos conventions. Cp recognises a number of special characters with special meanings, which can be used to recognise any other charcaters that match them. ? Matches any single character. % Matches the null character. #

Matches zero or more occurrences of the pattern

| Matches either pattern or . () Can be used to group expressions together. '# Can be used to turn off the special meaning of the special characters #, ?, %, |, (, ), or '. Some examples will help to make this clearer. cp a|b . copies a or b to the current directory. cp a#bc . copies ac abc abbc. cp a#(b|c)d . copies ad abd abcd. cp a?b . copies axb ayb aab. cp a#?b copies ab axxb ax.ab. cp '?#?'# . copies ?# ?ab# ??##. cp a(b|%)#c . copies a abc accc. ========== cat ========== /* Cp: A replacement for AmigaDos Copy that does not modify the date * by Jeff Lydiatt * Vancouver, Canada. * * Features: * 1) Handles all functions of AmigaDos copy, including the All switch. * 2) Regular expression pattern matching that handles the AmigaDos' * pattern matching characters "#?|%'()". * 3) This copy keeps the date of the copied file! * 4) Uses a 32K buffer which should speed up single disk copies. * 5) In "Cp filex .", the "." is taken to mean the current directory. * * Created: 07May87 * * Cp has been compiled and tested under Aztec v3.40a with patch v3 * applied. The 16 bit integer and small code, small data option is * used in compiling and linking all modules. * * Maintenance Notes: * 17May87 - Version 1.0 Released. * */ /* Cp and the c source is freely redistributable for personal non-commercial use. Commercial rights are reserved by the author. Feel free to make any modifications or use any of the modules in other programs. I encourage you to do so and hope you will release the code so others can learn by it. */ #include #include #include #include #define BUFMAX 32768 #define MAXSTR 127 extern int Enable_Abort; extern char *malloc(); extern int CmplPat(), Match(); extern long Chk_Abort(); /*--- A poor man's "printf" which avoids the overhead of printf ---*/ static void msg(str, parm) char *str, *parm; { register char *s; register struct FileHandle *console; console = Output(); for ( s=str; *s; ++s ) { if ( *s == '%' && *(s+1) == 's' ) { (void)Write( console, str, (long)(s - str)); (void)Write( console, parm, (long)strlen(parm)); (void)Write( console, (char *)(s + 2), (long)strlen((char *)(s+2))); break; } } if ( *s == '\0' ) (void)Write( console, str, (long)strlen(str)); } static void error( str, parm ) char *str, *parm; { msg( str, parm ); exit(NULL); } static void useage(name) char *name; { msg( "%s V1.0 buffered file copy by Jeff Lydiatt. Usage:\n", name ); msg( " %s [From] filein [To] fileout [All]\n", name ); msg( " AmigaDos style pattern matching characters permitted in filein.\n" ); msg( " Pattern matching characters not allowed in Fileout.\n\n" ); } /*-----------------------------------------------------------*/ /* Parse the command string */ /*-----------------------------------------------------------*/ static int toupper(c) register char c; { if ( 'a' <= c && c <= 'z' ) return c + ('A' - 'a'); return c; } /* Case-blind implementation of strcmp() */ static int blindcmp( s1, s2 ) register char *s1, *s2; { while (*s1 && *s2) { if ( (toupper( *s1 )) == (toupper( *s2 )) ) { ++s1; ++s2; } else break; } if ( toupper(*s1) == toupper(*s2) ) return 0; /* It's Equal */ else if ( toupper(*s1) > toupper(*s2) ) return 1; else return -1; } static void parsecmd(fparm, tparm, All, argc, argv) char *fparm, *tparm; register char *argv[]; int *All, argc; { int nextparm; register char *parm; if ((argc < 2) || ( strcmp( argv[1], "?" ) == 0) ) { useage( argv[0] ); exit( NULL ); } *All = FALSE; nextparm = 1; argc--; fparm [0] = '\0'; tparm[0] = '\0'; while ( nextparm <= argc ) { parm = argv[ nextparm ]; if ( (nextparm < argc) && (blindcmp( parm, "from" ) == 0) ) { ++nextparm; (void)strncpy( fparm, argv [nextparm], MAXSTR); } else if ( (nextparm < argc) && (blindcmp( parm, "to" ) == 0) ) { ++nextparm; (void)strncpy( tparm, argv [nextparm], MAXSTR ); } else if ( (nextparm == argc) && (blindcmp( parm, "all") == 0) ) *All = TRUE; else if ( fparm[0] == '\0' ) (void)strncpy( fparm, parm, MAXSTR ); else (void)strncpy( tparm, parm, MAXSTR ); ++nextparm; } } /*--------------------------------------------------------------*/ /* Internal stack manipulation routines */ /*--------------------------------------------------------------*/ struct stackframe { struct stackframe *next; char *strptr; }; static struct stackframe *Stackhead; static void initstack() { Stackhead = NULL; } static int isempty() { return Stackhead == NULL; } /*--------------push a string on the stack------------------*/ static void push(str) char *str; /* Push a string on the stack */ { register struct stackframe *p; register char *s; if ( (p = (struct stackframe *)malloc(sizeof(struct stackframe))) == NULL ||(s = malloc( strlen(str)+1 )) == NULL) { msg("Not enough memory\n"); return; } strcpy( s, str ); p->next = Stackhead; p->strptr = s; Stackhead = p; } /*---------pop the next string from the stack------------------*/ static void pop(str) char *str; { register struct stackframe *p; if (isempty()) error("Can't happen: stack popped with nothing there\n"); p = Stackhead; strcpy( str, p->strptr ); free( p->strptr ); Stackhead = p->next; free( p ); } /*--------------------------------------------------------------*/ /* Some handy path manipulation routines. */ /*--------------------------------------------------------------*/ /*------------separate path and pattern from str----------------*/ static char *getpath( path, pattern, str) char *path, *pattern, *str; { register char *s1, *s2; char *mark; mark = NULL; for ( s1=str; *s1; ++s1) if ( *s1 == ':' || *s1 == '/' ) mark = s1; if ( isdir(str) ) { strcpy( path, str ); *pattern = '\0'; } else if ( !mark ) { strcpy( pattern, str ); *path = '\0'; } else { s2 = path; s1 = str; while ( s1 < mark ) *s2++ = *s1++; if ( *s1 == ':' ) *s2++ = *s1; *s2 = '\0'; strcpy( pattern, (char*)( mark+1)); } return path; } /*------return path from parent directory and member name-------*/ static char *makepath(path, parent, member) register char *path; char *member; register char *parent; { register int len; strcpy( path, parent ); len = strlen( path ); if ( len > 0 && *member ) if ( (path[len-1] != ':') && (path[len-1] != '/') ) strcat( path, "/" ); strcat( path, member ); return path; } /*--- isdir: Returns 0 if NOT a directory, 1 otherwise. ---*/ static int isdir(filename) char *filename; { struct FileInfoBlock *f; struct Lock *outlk; int result; result = 0; outlk = (struct Lock *)Lock(filename,ACCESS_READ); if (outlk) { f = (struct FileInfoBlock *) AllocMem((long)sizeof(struct FileInfoBlock), MEMF_CHIP); if (f == 0) error("Unable to allocate space for FileInfoBlock!\n"); if (Examine(outlk,f)) if (f->fib_DirEntryType >= 0) result = 1; UnLock(outlk); FreeMem((void *)f,(long) sizeof(struct FileInfoBlock)); } return(result); } static int iswild(pattern) register char *pattern; { for (; *pattern; ++pattern ) { switch( *pattern ) { case '#': case '?': case '(': case '%': case '\'': case '|': return 1; } } return 0; } static int cp(fpath, tpath, name ) char *fpath, *tpath, *name; { char fname[MAXSTR+1], tname[MAXSTR+1]; char *buffer; long status, count, bufsize; struct FileHandle *fin, *fout; struct DateStamp date; (void)makepath( fname, fpath, name ); if ( tpath[0] != '\0' && !isdir(tpath) ) strcpy( tname, tpath ); else (void)makepath( tname, tpath, name ); msg( "%s ==> ", fname ); msg( "%s\n", tname); if ( (fin = Open( fname, MODE_OLDFILE )) == NULL ) { msg( "Can't open %s for input.\n", fname ); return 1; } if ( (fout = Open( tname, MODE_NEWFILE )) == NULL ) { msg( "Can't open %s for ouput.\n", tname ); Close( fin ); return 1; } for ( bufsize = BUFMAX; bufsize > 2048; bufsize -= 2048 ) if ( (buffer = malloc( (unsigned int)bufsize)) != NULL ) break; if ( bufsize <= 2048 ) { Close( fin ); Close( fout ); msg( "Not enough memory.\n" ); return 1; } status = 1; while( status > 0 && (count = Read( fin, buffer, bufsize )) == bufsize ) if ( Chk_Abort() ) status = -1; else status = Write( fout, buffer, count ); if (status > 0 && count > 0 ) status = Write( fout, buffer, count ); Close( fin ); Close( fout); free( buffer ); if ( status < 0 || count < 0 ) { (void)DeleteFile( tname ); msg( " %s [removed].\n", tname ); return 1; } if ( getDate( fname, &date )) (void)setDate( tname, &date ); return 0; } main(argc,argv) int argc; char *argv[]; { int aux[MAXSTR+1]; char fparm[MAXSTR+1], tparm[MAXSTR+1]; char fpath[MAXSTR+1], tpath[MAXSTR+1]; char fparent[MAXSTR+1], dontSearch[MAXSTR+1]; char fpattern[MAXSTR+1]; char relpath[MAXSTR+1], junk[MAXSTR+1]; void *dirlock; register struct FileInfoBlock *fileptr; int All; Enable_Abort = 0; parsecmd( fparm, tparm, &All, argc, argv ); (void)getpath( fparent, fpattern, fparm ); if ( strcmp(tparm, ".") == 0 ) tparm[0] = '\0'; /*--- Are the parms ok? --- */ if ( iswild(fparent) ) error( "Regular expression not allowed in path: %s.\n", fparm ); if ( iswild(tparm) ) error( "Regular expression not allowed as output name.\n" ); /*----- if it's just a single file copy, just do it and exit----*/ if ( !All && !iswild( fpattern ) && !isdir( fparm )) { (void)cp( fparent, tparm, fpattern ); exit( NULL ); } /*--- For "All" option, don't search the "to" directory --- */ fileptr = (struct FileInfoBlock *) AllocMem( (long)sizeof(struct FileInfoBlock), MEMF_CHIP); strcpy( dontSearch, tparm ); if ( dontSearch[0] == '\0' ) { dirlock = Lock("", ACCESS_READ); if ( dirlock ) { (void)Examine( dirlock, fileptr ); strcpy( dontSearch, fileptr->fib_FileName ); UnLock( dirlock ); } } initstack(); push( "" ); if ( fpattern[0] == '\0' ) strcpy( fpattern, "#?" ); if ( CmplPat( fpattern, aux ) == 0 ) { msg("Bad regular expression pattern: %s.\n", fpattern); goto all_done; } while( !isempty() ) { pop( relpath ); (void)makepath( fpath, fparent, relpath ); (void)makepath( tpath, tparm, relpath ); if ( All && !isdir(tpath) ) { if ( (dirlock = CreateDir( tpath )) == NULL ) { msg( "Can't create %s \n", tpath ); continue; } else { msg("%s ... [created]\n", tpath); UnLock( dirlock ); } } if ( (dirlock = Lock( fpath, ACCESS_READ )) == NULL || !Examine( dirlock, fileptr) ) { msg( "Can't find directory %s\n", fpath ); if ( dirlock ) UnLock( dirlock ); goto all_done; } while ( ExNext( dirlock, fileptr ) ) { if ( fileptr->fib_DirEntryType > 0 ) { if ( All && strcmp( dontSearch, fileptr->fib_FileName) ) push( makepath( junk, relpath, fileptr->fib_FileName ) ); } else if (Match( fpattern, aux, fileptr->fib_FileName ) ) { if ( Chk_Abort() || cp( fpath, tpath, fileptr->fib_FileName ) ) { UnLock( dirlock ); goto all_done; } } } UnLock( dirlock ); } all_done: FreeMem( fileptr, (long)sizeof(struct FileInfoBlock)); exit(NULL); } ================ cat ================ /* PatMatch.c - Implements AmigaDos Regular Expression Pattern Matching. ** ** This program will test whether a string is an AmigaDos regular expression ** It may be used to implement wild expressions such as: ** ** "copy #?.c to

" to copy any file ending in .c ** ** The program has two entry points: CmplPat, and Match. ** ** CmplPat - takes a pattern and returns an auxilliary integer vector ** which is used by Match. The pattern is not modified in ** any way. CmplPat returns 1 if no errors were detected ** while compiling the pattern; otherwise it returns 0; ** ** Match - takes the pattern, the auxilliary vector, and the string ** to be matched. It returns 1 if the string matches the ** pattern; otherwise it returns 0; ** ** Translated from BCPL by: ** Jeff Lydiatt ** Richmond B.C. Canada ** 16 May 1986. ** ** Source: "A Compact Function for Regular Expression Pattern Matching", ** Software - Practice and Experience, September 1979. ** ** Useage: ** To test if "file.c" matches the regular expression "#?.c" ** char *Pat = "#?.c"; ** char *Str = "file.c"; ** WORD Aux[128]; ** ** if ( CmplPat( Pat, Aux ) == 0 ) ** { ** printf("Bad Wildcard Expression\n"); ** exit(1); ** } ** if ( Match( Pat, Aux, Str ) == 1 ) ** printf("String matches the pattern\n"); ** else ** printf("String does NOT match the pattern\n"); **/ /*--- Included files ----*/ #include #include #include #define EOS '\0' /*--- Global Variables ---*/ static char Ch; /* The current character in Pattern */ static char *Pat; /* Pointer to the Pattern */ static int *Aux; /* Pointer to returned auxilliary vector */ static int PatP; /* Current position in Pat */ static int Patlen; /* strlen(pat) */ static BOOL Errflag; /* TRUE if error */ static int *Work; /* Pointer to Active work area */ static int Wp; /* Current position in work */ static BOOL Succflag;/* True if "str" matches "pat" */ /*----------------------------------------------------------------*/ /* The Interpreter */ /*----------------------------------------------------------------*/ static void Put(N) int N; { register int *ip; register int *to; if ( N == 0 ) Succflag = TRUE; else { for ( ip = &Work[ 1 ], to = &Work[ Wp ]; ip <= to; ip++) if ( *ip == N ) return; Work[ ++Wp ] = N; } } int Match( Pat, Aux, Str ) char Pat[]; int Aux[]; char Str[]; { int W[ 128 ]; int S = 0; int I, N, Q, P, Strlength; char K; int strlen(); void Put(); Work = W; Wp = 0; Succflag = FALSE; Strlength = strlen( Str ); Put( 1 ); if ( Aux[ 0 ] != 0 ) Put( Aux[ 0 ] ); for(;;) { /* First complete the closure */ for( N=1; N <= Wp; N++ ) { P = Work[ N ]; K = Pat[ P-1 ]; Q = Aux[ P ]; switch( K ) { case '#': Put( P + 1 ); case '%': Put( Q ); default : break; case '(': case '|': Put( P + 1); if ( Q != 0 ) Put( Q ); } } if ( S >= Strlength ) return Succflag; if ( Wp == 0 ) return FALSE; Ch = Str[ S++ ]; /* Now deal with the match items */ N = Wp; Wp = 0; Succflag = FALSE; for ( I = 1; I <= N; I++) { P = Work[ I ]; K = Pat[ P - 1 ]; switch( K ) { case '#': case '|': case '%': case '(': break; case '\'': K = Pat[ P ]; default : if ( _toupper( Ch ) != _toupper( K ) ) break; case '?': /* Successful match */ Put ( Aux[ P ] ); } /* End Switch */ } /* End For I */ } /* End for(;;) */ } /*----------------------------------------------------------------*/ /* The Compiler */ /*----------------------------------------------------------------*/ static void Rch() /* Read next character from Pat */ { if ( PatP >= Patlen ) Ch = EOS; else Ch = Pat[ PatP++ ]; } static void Nextitem() /* Get next char from Pat; recognize the ' escape char */ { if ( Ch == '\'' ) Rch(); Rch(); } static void Setexits( List, Val ) int List; int Val; { int A; do { A = Aux[ List ]; Aux[ List ] = Val; List = A; } while ( List != 0 ); } static int Join( A, B ) int A, B; { int T = A; if ( A == 0 ) return B; while ( Aux[ A ] != 0 ) A = Aux[ A ]; Aux[ A ] = B; return T; } static int Prim() /* Parse a Prim symbol */ { int A = PatP; char Op = Ch; int Exp(); void Setexits(), Nextitem(); Nextitem(); switch( Op ) { case EOS: case ')': case '|': Errflag = TRUE; default : return A; case '#': Setexits( Prim(), A ); return A; case '(': A = Exp( A ); if ( Ch != ')' ) { Errflag = TRUE; } Nextitem(); return A; } } static int Exp( AltP ) /* Parse an expression */ int AltP; { int Exits = 0; int A; int Prim(), Exits(), Join(); void Nextitem(), Setexits(); for (;;) { A = Prim(); if ( Ch == '|' || Ch == ')' || Ch == EOS ) { Exits = Join( Exits, A ); if ( Ch != '|' ) return Exits; Aux[ AltP ] = PatP; AltP = PatP; Nextitem(); } else Setexits( A, PatP ); } } int CmplPat( Pattern, CmplPattern) char Pattern[]; int CmplPattern[]; { int i, strlen(); void Rch(), Setexits(); Pat = Pattern; Aux = CmplPattern; PatP = 0; Patlen = strlen( Pat ); Errflag = FALSE; for ( i = 0; i <= Patlen; i++ ) Aux[ i ] = 0; Rch(); Setexits( Exp(0), 0 ); return (!Errflag); } =============== cat =============== #include "exec/types.h" #include "exec/ports.h" #include "exec/io.h" #include "exec/memory.h" #include "libraries/dos.h" #include "libraries/dosextens.h" #include #define AZTEC 1 #ifdef AZTEC #include "functions.h" /* aztec C include */ #endif #define ACTION_SETDATE_MODE 34L /* The packet type we will be playing with */ #define DOSTRUE -1L /* AmigaDos TRUE */ #define MAXARGS 7L /* limit in packet structure (dosextens.h) */ #define NARGS 4L /* Number of args for setdate */ /*---------------------------------------------------------------------*/ /* sendpkt: generalized send a dos packet. */ /*---------------------------------------------------------------------*/ static long sendpkt(pid,action,args,nargs) struct MsgPort *pid; /* process indentifier ... (handlers message port ) */ long action, /* number of arguments in list */ nargs; /* number of arguments in list */ ULONG args[]; /* a pointer to a argument list */ { struct MsgPort *replyport; struct StandardPacket *packet; long count, res1; ULONG *pargs; if(nargs > MAXARGS) return NULL; replyport = (struct MsgPort *) CreatePort(NULL,NULL); /* make reply port */ if(!replyport) return NULL; packet = (struct StandardPacket *) AllocMem((long)sizeof(struct StandardPacket),MEMF_PUBLIC | MEMF_CLEAR); if(!packet) { FreeMem((void *)packet,(long)sizeof(struct StandardPacket)); return(NULL); } packet->sp_Msg.mn_Node.ln_Name = (char *) &(packet->sp_Pkt); /* link packet- */ packet->sp_Pkt.dp_Link = &(packet->sp_Msg); /* to message */ packet->sp_Pkt.dp_Port = replyport; /* set-up reply port */ packet->sp_Pkt.dp_Type = action; /* what to do... */ /* move all the arguments to the packet */ pargs = (ULONG *)&(packet->sp_Pkt.dp_Arg1); /* address of first argument */ for(count=NULL;count < nargs && count < MAXARGS; ++count) pargs[count]=args[count]; PutMsg(pid,packet); /* send packet */ (void)WaitPort(replyport); /* wait for packet to come back */ (void)GetMsg(replyport); /* pull message */ res1 = packet->sp_Pkt.dp_Res1; /* get result */ /* all done clean up */ FreeMem((void *)packet,(long)sizeof(*packet)); DeletePort(replyport); return(res1); } /*---------------------------------------------------------------------*/ /* setDate: datestamp the given file with the given date. */ /*---------------------------------------------------------------------*/ BOOL setDate( name, date ) char *name; struct DateStamp *date; { struct MsgPort *task; /* for process id handler */ ULONG arg[4]; /* array of arguments */ char *bstr, strcpy(); /* of file to be set */ long rc; char *strchr(); int strlen(); rc = 0; if ( !(bstr = (char *)AllocMem(68L, (long)(MEMF_PUBLIC)))) goto exit2; if ( !(task = (struct MsgPort *)DeviceProc( name ))) goto exit1; /* Dos Packet needs the filename in Bstring format */ (void)strcpy( bstr+1, name ); *bstr = strlen( name ); arg[0] = (ULONG)NULL; arg[1] = (ULONG)IoErr(); /* lock on parent director set by DeviceProc() */ arg[2] = (ULONG) bstr >> 2; arg[3] = (ULONG) date; rc = sendpkt( task, ACTION_SETDATE_MODE, arg, 4L ); exit1: if ( bstr ) FreeMem( (void *)bstr, 68L ); exit2: if ( rc == DOSTRUE ) return TRUE; else return FALSE; } /*---------------------------------------------------------------------*/ /* getDate: get the datestamp the given file. */ /*---------------------------------------------------------------------*/ BOOL getDate(name, date ) char *name; register struct DateStamp *date; { struct FileInfoBlock *Fib; ULONG FLock; int result; register struct DateStamp *d; if ( (FLock = (ULONG) Lock(name, (long)(ACCESS_READ) )) == NULL) return FALSE; Fib = (struct FileInfoBlock * ) AllocMem( (long)sizeof(struct FileInfoBlock), (long)(MEMF_CHIP)); if (Fib == NULL ) result = FALSE; else { if ( !Examine( FLock, Fib )) result = FALSE; else if ( Fib->fib_DirEntryType > 0 ) result = FALSE; /* It's a directory */ else { d = &Fib->fib_Date; date->ds_Days = d->ds_Days; date->ds_Minute = d->ds_Minute; date->ds_Tick = d->ds_Tick; result = TRUE; } FreeMem( (void *)Fib, (long)sizeof(struct FileInfoBlock) ); } UnLock( FLock ); return result; } ================ cat ================ /* Aztec v3.20a allows you to omit the startup parsing for workbench */ /* by including this module. Since this is a cli utility, we are */ /* going to do just that - well it only saves 232 bytes, but it helps. */ _wb_parse() {} ============== cat ============== cp: cp.o PatMatch.o setDate.o wb_parse.o ln cp.o PatMatch.o setDate.o wb_parse.o -lc ============ cat ============ begin 644 Cp M #\P # ( =/ & $ /I '3T[Z%!Y. M50 2.< ,$ZZ&S F0"1M A@9 P2 "5F7 PJ ', 694( J0K0 (+P O+0 ( M+PM.NALV3^\ #"\M Q.NA?&6$](P"\ +RT #"\+3KH;&D_O P@2E2(+PA. MNA>H6$](P"\ ($I4B"\(+PM.NAKZ3^\ #& &4HI*$F:82A)F'"\M A.NA=^ M6$](P"\ +RT ""\+3KH:TD_O Q,WPP 3EU.=4Y5 O+0 ,+RT "$ZZ_TY0 M3T*G3KH8BEA/3EU.=4Y5 O+0 (2'H +DZZ_S!03R\M A(>@!53KK_(E!/ M2'H 61I871T+B @57-A9V4Z"@ @("5S(%M&3F]T(&5N;W5G:"!M M96UO/_^+RT "$ZZ%0903RM __A*K?_X9UQ(> "2'@!!$ZZ M%F!03RM __Q*K?_\9@I(>@!*3KKZ:%A/+RW__"\M__A.NA284$]*0&<0(&W_ M_$JH 1M!CM\ '_]B\M__A.NA3P6$](> $$+RW__$ZZ%CQ03S M__9.74YU M56YA8FQE('1O(&%L;&]C871E('-P86-E(&9O@&P3KKXJE!/2&W_ $AZ :I. MNOB<4$](> /M2&W_@$ZZ$[903RM _NQF%$AM_X!(>@&,3KKX>E!/< %.74YU M2'@#[DAM_P!.NA..4$\K0/[H9AQ(;?\ 2'H!?DZZ^%)03R\M_NQ.NA+F6$]P M 6#,*WP ( _O _+?[R3KH0NE1/*T#^_&82!*T @ _O ,K0 " #^\&[> M#*T @ _O!N)"\M_NQ.NA*D6$\O+?[H3KH2FEA/2'H!.$ZZ]_)83W !8 #_ M=BM\ ?[X2JW^^&]*+RW^\"\M_OPO+?[L3KH3$D_O PK0/[TL*W^\&8L M3KH0HDJ 9PHK?/_____^^& 8+RW^]"\M_OPO+?[H3KH3!$_O PK0/[X8+!* MK?[X;QY*K?[T;Q@O+?[T+RW^_"\M_NA.NA+>3^\ #"M _O@O+?[L3KH2!%A/ M+RW^Z$ZZ$?I83R\M_OQ.N@_N6$]*K?[X;09*K?[T;!Y(;?\ 3KH2 EA/2&W_ M $AZ (A.NO2X* " @("5S(%MR96UO=F5D72X* $Y5^GHO"D)L@"8O+0 */RT "$AM^GI( M;?X 2&W^@$ZZ^0!/[P 22&W^@$AM^X!(;?R 3KK[2$_O Q(>@+"2&W^ $ZZ M#AA03TI 9@1"+?X 2&W\@$ZZ_/)83TI 9PY(;?Z 2'H"G$ZZ]M103TAM_@!. MNOS66$]*0&<*2'H"L4ZZ]KQ83TIM^GIF.$AM^X!.NORX6$]*0&8J2&W^@$ZZ M^_A83TI 9AQ(;?N 2&W^ $AM_(!.NOS>3^\ #$*G3KH/'EA/2'@ DAX 01. MNA)44$\D0$AM_@!(;?P 3KH-L%!/2BW\ &8^2'C__DAZ G%.NA"^4$\K0/I\ M2JWZ?&3^\ #$AM^P!(;?X 2&W] $ZZ^HI/[P ,2FWZ>F=& M2&W] $ZZ^N183TI 9CA(;?T 3KH/AEA/*T#Z?&802&W] $AZ ;=.NO3$4$]@ MD$AM_0!(>@&Y3KKTM%!/+RWZ?$ZZ$ )83TAX__Y(;?V 3KH/LE!/*T#Z?&<0 M+PHO+?I\3KH/;%!/2D!F(DAM_8!(>@&/3KKT>%!/2JWZ?&<*+RWZ?$ZZ#\!8 M3V *XO"B\M^GQ.N@],4$]*0&< (Y*J@ $;SI*;?IZ9S(@2E"(+PA(;?P M3KH+^E!/2D!G'B!*4(@O"$AM^P!(;?J 3KKYL$_O PO $ZZ^!!83V!(($I0 MB"\(2&W_ $AM^X!.N@&$3^\ #$I 9RY.N@S:2H!F&B!*4(@O"$AM_0!(;?V M3KKZUD_O Q*0&<,+RWZ?$ZZ#R183V 28 #_9"\M^GQ.N@\46$]@ /Z(2'@! M!"\*3KH07E!/0J=.N@SH6$\D7TY=3G4N %)E9W5L87(@97AP,"R 'DC XX @;( :,:T " @ 8-I.5?[R M0FW^_D'M_P I2( :0FR 'D)L@" O+0 03KH*8%A/.T#^]#\\ %.NO]Z5$\@ M;0 ,2E!G#"!M P_$$ZZ_V943SM\ '^^F )@P+?[Z2,#C@"!L@!H[< @ M_O8P+?[V4T @;0 (&W /[S,"W^]DC XX @;0 ,.W ( /[X$"W^\TB 2,!@ M.C M_O920#\ 3KK_$%1//RW^^$ZZ_P943V Z,"W^]E) /P!.NO[V5$]*;?[X M9PH_+?[X3KK^YE1/8!J0O "-GOE6 9\A7@&?0D+P !49\A@Q%)M_OHP M+?[ZL&R 'F\ _V P+?[^L&W^]&T(,"R ($Y=3G5*;( >9@1P &#R,"W^_E)M M_OX@;0 0&7 ( *.VR 'O[Z0FR 'D)L@" [? !_OQ@ "8,"W^_$C XX @ M;( :.W ( /[V,"W^]E- (&T "!MP #^\Q M_O-(@$C 8$!@9# M_O8@;0 ( M&W /[S$"R "DB P'P 7Q(M_O-(@<)\ %^P068^,"W^]DC XX @;0 ,/S ( M $ZZ_@I43V FD+P C9[A5@&>T58!GLE. 9ZR0O !=GS)"\ /6>< M8*I2;?[\,"W^_+!M_OIO /]@8 #^:F _R!.50 ,"R %+!L@!9M!D(L@ I@ M$C L@!12;( 4(&R #!EP " "DY=3G5.50 #"P )X *9@)AR&'&3EU.=4Y5 M__XP+0 (2,#C@"!L@! [< @ __XP+0 (2,#C@"!L@! QK0 *" [;?_^ A* M;0 (9M!.74YU3E7__CMM C__DIM AF"# M I.74YU,"T "$C XX @;( 0 M2G ( &<4,"T "$C XX @;( 0.W ( (8-HP+0 (2,#C@"!L@! QK0 *" P M+?_^8+Y.5?_\.VR %/_^&VR "O_]3KK_3! M__U(@$C 8$8Y? !@!@P+?_^ M3EU.=3\M__YASC\ 3KK_/%A/,"W__F#H/RW__F$^5$\[0/_^#"P *8 *9P8Y M? !@!A.NO\","W__F#$2H!GMI"\ (V>\6X!GS%. 9Z:0O %-GGF"B M8*1.5?_\0FW__DZZ_W([0/_\#"P ?( *9PX,+ I@ IG!DHL@ IF0#\M__P_ M+?_^3KK^]EA/.T#__@PL 'R "F<(,"W__DY=3G4P+0 (2,#C@"!L@! QK( 4 M" [;( 4 A.NOYX8 X_+( 4/RW__$ZZ_GY83V"28,Q.5?_^*6T "( ,*6T M#( 00FR %"\L@ Q.N@:\6$\Y0( 60FR &$)M__Y@%# M__Y(P.. (&R $$)P M" !2;?_^,"W__K!L@!9OXDZZ_>Q"9T)G3KK_-%1//P!.NOX:6$]*;( 89@1P M 6 "< !.74YU3E7_[ RM !P 4;P9P $Y=3G5"IT*G3KH)YE!/*T#__$JM M__QF!' 8.1(>0 ! %(> !$3KH*LE!/*T#_^$JM__AF$DAX $0O+?_X3KH* MQ%!/< !@N"!M__@@+?_XT+P 4(4 "B!M__@A;?_X !0@;?_X(6W__ 8 M(&W_^"%M P '" M__C0O "@K0/_L0JW_]& >("W_].6 (&T $"(M__3E M@2)M_^PCL @ & !2K?_T("W_]+"M !1L"@RM !__T; !2'@ 1$ZZ";Y03RM M_^AG?B\M A.N@?\6$\K0/_\9UHO+0 ((&W_Z%*(+PA.N@4"4$\O+0 (3KH% M"%A/(&W_Z!" 0JW_[$ZZ!_XK0/_P("W_Z.2(*T#_]"MM S_^$AX 1(;?_L M2'@ (B\M__Q.NOYJ3^\ $"M _^1*K?_H9PY(> !$+RW_Z$ZZ"6103PRM____ M___D9@9P 4Y=3G5P ϧ_]DCG # D;0 ,2'C__B\M A.N@>:4$\K0/_X M9@IP $S?# !.74YU2'@ DAX 01.N@CN4$\K0/_\2JW__&8&0FW_]F!4+RW_ M_"\M__A.N@ @ @N 0!*6<02_H "$ZN_^)@!D*G\U].0!)^0 M?_Y.=4Y5 O"DAY $ # L@ +!_ &+P!.N@?>4$\I0( T9A1"ITAY $ M $ZZ!KA03RYL@"A.=2!L@#1": $(&R -#%\ $ $")L@#0S? ! H@;( H M("R *)"H 10@"E @#@@;( X(+Q-04Y80J=.N@>66$\D0$JJ *QG+B\M PO M+0 (+PI.N@"R3^\ ##E\ & )B!L@#0 :( 0@;( T &B *8$1(:@!< M3KH'Y%A/2&H 7$ZZ!X183RE @#P@;( \2J@ )&<0(&R /")H "0O$4ZZ!4I8 M3R\L@#PO"DZZ_IA03REL@#R 0$ZZ!7H@;( T((!.N@6L(&R -"% 9G%DAX M ^U(>@ L3KH%A%!/(&R -"% PO+(! /RR 1$ZZ\ZI<3T)G3KH#?E1/)%]. M74YU*@!.50 2.<,,"1M ! @;0 (("@ K.6 * @1" H !#E@"9 $!-(@$C MT*T #%2 .4" 1D*G,"R 1DC +P!.N@9\4$\I0(!(9@A,WPPP3EU.=1 32( _ M "!+4H@O""\L@$A.N@%$3^\ "DAZ 3H0$TB 2,#0K(!(+P!.N@&H4$\_+0 . M+PHO+(!(3KH!1$_O I";(!$)FR 2"1+$!-(@#H L'P (&<8NGP "6<2NGP M#&<,NGP #6<&NGP "F8$4HM@V P3 "!M>@P3 ")F+E*+($M2BQ 02( Z &<> M($I2BA"%NGP (F80#!, (F8$4HM@!D(J__]@ F#68#@@2U*+$!!(@#H 9R:Z M? @9R"Z? )9QJZ? ,9Q2Z? -9PZZ? *9P@@2E**$(5@SB!*4HI"$$I% M9@)3BU)L@$1@ /]:0A)"IS L@$120$C Y8 O $ZZ!6903RE @$!F"$)L@$1@ M /[D>@ F;(!(8!XP!4C Y8 @;(! (8L( "\+3KH LEA/4D!(P-? 4D6Z;(!$ M;=PP!4C Y8 @;(! 0K ( & _J8@ $SO P !" (,B\ #& "$-E7R?_\9P92 M06 "0AA1R?_\3G4P/'__8 0P+P ,(&\ !$H89OQ32")O A30!#95\C__&<" M0A @+P $3G4P/'__8 0P+P ,4T!K%"!O 0B;P (L0EF#%-(2AA7R/_V< !. M=6,$< %.=7#_3G4@;P $( @B;P ($-EF_$YU(&\ !" (2AAF_)' ( A3@$YU M3E4 $CG # D;( B8!0F4B J 10@"\ +PI.N@2$4$\D2R *9NA"K( B3-\, M $Y=3G5.50 +PI!^O_&*4B 3$*G("T "%" +P!.N@0J4$\D0$J 9@AP "1? M3EU.=22L@"(E;0 ( 0I2H B( I0@&#F3E4 ' ,"T ""\ 8;)83TY=3G5. M50 2.< ,)?+)&R (F .(&T "%&(L@ > M3KH"&"\ 3KH"0$_O P_/ !3KH #%1/3EU.=5Y#"@!.50 2JR 7F<&(&R M7DZ0/RT "$ZZ A43TY=3G5.5?_\+P0P+0 (2, K0/_\2JR -& !@"C\$ M3KH T%1/4D2X;( ";? P+( "P?P !B\ +RR -$ZZ QI03TJL@$QG!B!L@$Q. MD$JL@%!G"B\L@%!.N@':6$]*K(!49PHO+(!43KH!REA/2JR 6&<*+RR 6$ZZ M ;I83RQX 0(+@ $ 2EG%"\-2_H "DZN_^(J7V &0J?S7TYS2JR /&8P2JR M2&