/* MEMO: tried TABCHAR stuff, for various files */ #define LASTDITCH 1 /* ---------------------------------------------------------------------- */ /* Copyright (C) 1992 by Natrlich! */ /* This file is copyrighted! */ /* Refer to the documentation for details. */ /* ---------------------------------------------------------------------- */ /* rev. history 1.0 -- */ /* 1.1 -- */ /* 1.2 -- */ /* 1.3 -- got a bit more userfriendly */ /* 1.4 -- bug fix ? */ /* 1.5 -- merged with tos_unix */ /* 1.6 -- fixed little masking bug in */ /* different tabchar */ /* last ditch code added */ /* 1.7 -- increased portability */ /* time date setting for everyone */ /* ---------------------------------------------------------- */ #include "defines.h" #undef VERSION #undef REVISION #define VERSION 1 #define REVISION 7 #include #include #include #include #include OSBIND #include "nasm.h" #ifndef __hp9000s300 # define MALLOCING 1 #endif #if OS == AMIGA || defined( SUN) # include #endif #if OS == MSDOS && __TURBOC__ # define perror( s) fputs( s, stderr) #endif #if OS == TOS || OS == MSDOS # if OS == TOS # include /* for stat */ # endif static struct ffblk fbuf; #endif #if OS == TOS # define LOSER() keypress() int tossable; void keypress() { if( tossable) { while( Bconstat( 2)) Bconin( 2); Bconin( 2); } } # ifdef __TURBOC__ /* PUREC fouls up too */ # define stat( x, y) mystat( y) void mystat( p) struct stat *p; { p->st_size = fbuf.ff_fsize; p->st_mtime = *(long *) &fbuf.ff_ftime; /* sorta hackish */ } # endif #else # define LOSER() #endif #ifdef __TURBOC__ # define off_t slword #endif #if LASTDITCH # if OS == TOS || OS == MSDOS static char ditch[ 128] = "f:\\tmp\\"; # define DIR_SLASH '\\' # else static char ditch[ 128] = "/tmp/"; # define DIR_SLASH '/' # endif void last_ditch( to_file, abuffer, size) char *to_file; void huge *abuffer; lword size; { int fd; char *z; strcat( ditch, (z = strrchr( to_file, DIR_SLASH)) ? z + 1 : to_file); if( (fd = (int) Fkreate( ditch, 0644)) >= 0) { # if OS == /* fucking */ MSDOS _fmode = O_BINARY; # endif Fwrite( fd, size, abuffer); Fclose( fd); fprintf( stderr, "*** Backup in \"%s\" ***\n", ditch); } } #else # define last_ditch( x, y, z) #endif void nerror( s) char *s; { static char buf[256]; sprintf( buf, "crlf155: Error \"%s\"\n", s); perror( buf); LOSER(); exit(1); } void nserror( s, t) char *s, *t; { static char buf[256]; sprintf( buf, s, t); nerror( buf); } #define MAXBUF 0x40000 /* sorry but the fucking HP malloc commits */ /* suicide when fragmenting ... (or what ?)*/ #if ! MALLOCING static char foobuf[ MAXBUF], memerr2[] = "static buffer too small, recompile!"; #endif static char huge *p; static char memerr1[] = "out of memory", blurb[] = { 'c','r','l','f','1','5','5',' ','v',VERSION+'0','.',REVISION+'0',' ', '(','c',')',' ','1','9','9','2',' ','b','y',' ', 'N','a','t','u','e','r','l','i','c','h','!', ' ','-','-',' ','c','o','n','v','e','r','t','s',' ', #if OS == UNIX || AMIGA 'C','R','/','L','F',' ','t','o',' ','L','F', #else 'L','F',' ','t','o',' ','C','R','/','L','F', #endif ' ','a','n','d',' ','m','o','r','e','.','.','.','\n' }; #if OS == TOS || OS == MSDOS # define UNIX_TOS 0 # define TOS_UNIX 4 # else # define TOS_UNIX 0 # define UNIX_TOS 4 #endif #define ATARI_UNIX 1 #define ATARI_TOS 2 #define UNIX_ATARI 5 #define TOS_ATARI 6 FILE *fp, *fq, *fopen(); int fd, showstuff, mode, untabify, tabchar, eliminate, tabs = -1, xtabc = -1, hardtabs = 1, unmatched= 1; char huge *atari_tos( size) register lword size; { register byte huge *q; #if MALLOCING if( ! (p = Malloc( size + size))) nerror( memerr1); #else if( size >= MAXBUF) nerror( memerr2); #endif for( q = (byte huge *) p; size--;) if( (*q++ = getc( fp)) == 155) { q[ -1] = '\r'; *q++ = '\n'; } return( (char huge *) q); } char huge *atari_unix( size) register lword size; { register byte *q; register int c; #if MALLOCING if( ! (p = Malloc( size))) nerror( memerr1); #else if( size >= MAXBUF) nerror( memerr2); #endif for( q = (byte huge *) p; size--;) *q++ = ((c = getc( fp)) == 155) ? '\n' : c; return( (char huge *) q); } char huge *tos_atari( size) register lword size; { register char huge *q; #if MALLOCING if( ! (p = Malloc( size))) nerror( memerr1); #else if( size >= MAXBUF) nerror( memerr2); #endif for( q = p; size--;) if( (*q++ = getc( fp)) == '\r' && (size-- ? ((*q++ = getc( fp)) == '\n') : (size = 0))) q--[ -2] = 155; return( q); } char huge *unix_atari( size) register lword size; { register char huge *q; register int c; #if MALLOCING if( ! (p = Malloc( (lword) size))) nerror( memerr1); #else if( size + size >= MAXBUF) nerror( memerr2); #endif for( q = p; size--;) *q++ = (c = getc( fp)) == '\n' ? 155 : c; return( q); } char huge *none( size) register lword size; { register char huge *q; #if MALLOCING if( ! (p = Malloc( (lword) size))) nerror( memerr1); #else if( size + size >= MAXBUF) nerror( memerr2); #endif for( q = p; size--;) *q++ = getc( fp); return( q); } char huge *unix_tos( size) lword size; { register char huge *q; register int c; #if MALLOCING if( ! (p = Malloc( (lword) (size + size)))) nerror( memerr1); #else if( size + size >= MAXBUF) nerror( memerr2); #endif for( q = p, c = 'a'; c != EOF;) if( (*q++ = c = getc( fp)) == '\n') { q[ -1] = '\r'; *q++ = '\n'; } return( q - 1); } char huge *tos_unix( size) lword size; { register char huge *q; register int c; #if MALLOCING if( ! (p = Malloc( (lword) size))) nerror( memerr1); #else if( size >= MAXBUF) nerror( memerr2); #endif if( eliminate) { for( q = p, c = 'a'; c != EOF;) { while( (c = getc( fp)) == 032); #if OS == UNIX || AMIGA if( (*q++ = c) == '\r' && (q[-1] = getc( fp)) != '\n') { *q = q[-1]; q[ -1] = c; c = *q; } #else *q++ = c; #endif } } else for( q = p, c = 'a'; c != EOF;) #if OS == UNIX || AMIGA if( (*q++ = c = getc( fp)) == '\r' && (q[-1] = getc( fp)) != '\n') { *q = q[-1]; q[ -1] = c; c = *q; } #else *q++ = c = getc( fp); #endif return( q - 1); } void do_it( to_file) char *to_file; { off_t size, oldsize; struct stat sbuf; register char huge *q; register lword y; #if ! MALLOCING p = foobuf; #endif if( q = getenv( "TMPDIR")) strcpy( ditch, (char *) q); if( ! (fp = fopen( to_file, (mode & 0xB) ? "rb" : "r" ))) nserror("File open of \"%s\" failed", to_file); stat( to_file, &sbuf); if( ! (oldsize = sbuf.st_size)) { printf("File \"%s\" is empty\n", to_file); return; } if( showstuff) { printf("Converting \"%s\" with %ld bytes ", to_file, (long) oldsize); fflush( stdout); } if( (size_t) oldsize != (off_t) oldsize) nerror("runtime: conversion problem"); switch( mode) { default : q = none( oldsize); break; case UNIX_TOS : q = unix_tos( oldsize); break; case TOS_UNIX : q = tos_unix( oldsize); break; case ATARI_UNIX: q = atari_unix( oldsize); break; case UNIX_ATARI: q = unix_atari( oldsize); break; case TOS_ATARI: q = tos_atari( oldsize); break; case ATARI_TOS: q = atari_tos( oldsize); } fclose( fp); size = (off_t) ( q - p); if( untabify) for( q = p, y = size; *q++ != tabchar && y; y--); if( untabify && y) { register lword i, len; register int j, c; if( ! (fq = fopen( to_file, "wb"))) nserror("Opening of \"%s\" failed", to_file); if( hardtabs) /* won't expand last char in file */ for( q = p, i = len = 0, j = tabs; i != size - 1; i++) if( (c = *q++) != tabchar) { if( putc( c, fq) == '\n' || ! --j) j = tabs; len++; } else { while( j) { putc( ' ', fq); len++; j--; } j = tabs; } else for( q = p, len = i = 0; i != size - 1; i++) { if( (c = *q++) != tabchar) { putc( c, fq); len++; } else for( j = tabs; j; putc( ' ', fq), len++, j--); } if( putc( *q, fq) == EOF) { fclose( fq); last_ditch( to_file, p, size); nerror("write failed"); } if( showstuff) printf("%s to %ld bytes\n", (len > oldsize) ? "up" : "down", (long) len); fclose( fq); } else if( (mode & 0x3) || size != oldsize) { if( (fd = (int) Fkreate( to_file, 0644)) < 0) nserror("Creation of \"%s\" failed", to_file); #if OS == /* fucking */ MSDOS _fmode = O_BINARY; #endif if( showstuff) printf("%s to %ld bytes\n", (size > oldsize) ? "up" : "down", (long) size); if( size != Fwrite( fd, size, p)) { Fclose( fd); last_ditch( to_file, p, size); nerror("write failed"); } Fclose( fd); } else { if( showstuff) puts( "to equal size. [no update]"); goto free_em; } /* due to CLOSE writing the creation date, we got to do this */ #if OS == TOS if( (fd = (int) Fopen( to_file, 0)) < 0) fprintf( stderr, "Someone snarfed your output file (not me!)\n"); else { Fdatime( (DOSTIME *) &sbuf.st_mtime, fd, 1); Fclose( fd); } #else { struct utimbuf time; time.actime = sbuf.st_atime; time.modtime = sbuf.st_mtime; if( utime( to_file, &time)) nserror("Timestamp update failed on \"%s\"", to_file); } #endif free_em: #if MALLOCING Mfree( (void *) p) #endif ; } main( argc, argv) int argc; char **argv; { int i = 0, foo; if( argc == 1) goto usage; while( ++i < argc) { if( *argv[ i] == '-') switch( argv[ i][ 1]) { #ifdef __DATE__ case ':' : fputs( __DATE__, stderr); # ifdef __TIME__ fprintf( stderr, " %s", __TIME__); # endif putc( '\n', stderr); break; #endif #if OS == TOS case 'T' : case 't' : tossable = ! tossable; break; #endif case 'V' : /* at runtime would be better, but more painful */ case 'v' : /* to code */ fputs( blurb, stderr); break; case 'h' : case 'H' : hardtabs = ! hardtabs; break; case 'z' : case 'Z' : eliminate = ! eliminate; break; case 'a' : case 'A' : mode = (mode & 0xFC) | ATARI_UNIX; break; case 'x' : case 'X' : mode = (mode & 0xFC) | ATARI_TOS; break; case 'b' : case 'B' : mode ^= UNIX_TOS | TOS_UNIX; break; case 'u' : case 'U' : untabify = ! untabify; if( argv[ i][ 2] && sscanf( &argv[ i][ 2],"%X", &foo)) tabs = foo; break; case 's' : case 'S' : showstuff = ! showstuff; break; case 'N' : case 'n' : mode ^= 0x8; break; case 'C' : case 'c' : { unsigned char d = argv[ i][ 2]; if( d == '\\') switch( argv[ i][ 2]) { case 't' : d = '\t'; break; case 'r' : d = '\r'; break; case 'b' : d = '\b'; break; case 'n' : d = '\b'; break; default : goto usage; } else if( d >= '0' && d <= '9') d = (char) atoi( &argv[ i][ 2]); xtabc = d; break; } default : goto usage; } else { static char xbuf[ 256]; static char fname[ 13]; char *p, *q; if( tabs < 0) tabs = (mode == TOS_UNIX || mode == TOS_ATARI) ? 3 : 8; tabchar = (xtabc < 0) ? ((mode == ATARI_UNIX || mode == ATARI_TOS) ? 127 : '\t') : xtabc; #if OS == TOS || OS == MSDOS /* if findfirst works */ q = argv[ i]; p = xbuf; strcpy( p, q); if( ! (p = strrchr( q, '\\'))) p = xbuf; else p = xbuf + (int) ((q = p + 1) - argv[ i]); strcpy( p, "*.*"); if( findfirst( xbuf, &fbuf, 0)) /* only normal files ? */ nserror("Directory search failed for \"%s\"", xbuf); { register char *x, *y; do { for( x = fbuf.ff_name, y = fname; *x; y++, x++) *y = tolower( *x); *y = 0; if( wildmat( fname, q)) { unmatched = 0; strcpy( p, fname); do_it( xbuf); } } while( ! findnext( &fbuf)); } #else do_it( argv[ i]); unmatched = 0; #endif } } return( unmatched); usage: fputs( "\ usage: crlf155 ([flags] )+\n\ \t-a\t: convert 155 to LF\n\ \t-n\t: just untabify\n\ \t-x\t: convert 155 to CR/LF\n\ \t-c\t: tab character\n\ \t-h\t: no hardtabs\n\ \t-z\t: eliminates ^Zs from MSDOS files\n\ \t-b\t: backwards, change conversion direction, f.e. LF to 155\n\ \t-u[val]\t: untabify, default spaces: TOS->UNIX : 3, UNIX->TOS : 8\n\ \t-s\t: show some statistics for user amusement\n", stderr); #if OS == TOS fputs( "\ \t-t\t: halt screen before exiting\n\n\ \t\t* Warning: filenames and patterns: all lowercase!\n\ \t\t *.C won't work, *.c will\n", stderr); #endif fputs( "\n\ \t\t Insure that there is enough discspace, else one file might\n\ \t\t get truncated\n", stderr); LOSER(); exit(1); } #if OS != UNIX /* $Revision: 1.7 $ ** ** Do shell-style pattern matching for ?, \, [], and * characters. ** Might not be robust in face of malformed patterns; e.g., "foo[a-" ** could cause a segmentation violation. It is 8bit clean. ** ** Written by Rich $alz, mirror!rs, Wed Nov 26 19:03:17 EST 1986. ** Rich $alz is now . ** April, 1991: Replaced mutually-recursive calls with in-line code ** for the star character. ** ** Special thanks to Lars Mathiesen for the ABORT code. ** This can greatly speed up failing wildcard patterns. For example: ** pattern: -*-*-*-*-*-*-12-*-*-*-m-*-*-* ** text 1: -adobe-courier-bold-o-normal--12-120-75-75-m-70-iso8859-1 ** text 2: -adobe-courier-bold-o-normal--12-120-75-75-X-70-iso8859-1 ** Text 1 matches with 51 calls, while text 2 fails with 54 calls. Without ** the ABORT, then it takes 22310 calls to fail. Ugh. The following ** explanation is from Lars: ** The precondition that must be fulfilled is that DoMatch will consume ** at least one character in text. This is true if *p is neither '*' nor ** '\0'.) The last return has ABORT instead of FALSE to avoid quadratic ** behaviour in cases like pattern "*a*b*c*d" with text "abcxxxxx". With ** FALSE, each star-loop has to run to the end of the text; with ABORT ** only the last one does. ** ** Once the control of one instance of DoMatch enters the star-loop, that ** instance will return either TRUE or ABORT, and any calling instance ** will therefore return immediately after (without calling recursively ** again). In effect, only one star-loop is ever active. It would be ** possible to modify the code to maintain this context explicitly, ** eliminating all recursive calls at the cost of some complication and ** loss of clarity (and the ABORT stuff seems to be unclear enough by ** itself). I think it would be unwise to try to get this into a ** released version unless you have a good test data base to try it out ** on. */ #define TRUE 1 #define FALSE 0 #define ABORT -1 /* What character marks an inverted character class? */ #define NEGATE_CLASS '^' /* Is "*" a common pattern? */ #define OPTIMIZE_JUST_STAR /* Do tar(1) matching rules, which ignore a trailing slash? */ #undef MATCH_TAR_PATTERN /* ** Match text and p, return TRUE, FALSE, or ABORT. */ static int DoMatch(text, p) char *text; char *p; { int last; int matched; int reverse; for ( ; *p; text++, p++) { if (*text == '\0' && *p != '*') return ABORT; switch (*p) { case '\\': /* Literal match with following character. */ p++; /* FALLTHROUGH */ default: if (*text != *p) return FALSE; continue; case '?': /* Match anything. */ continue; case '*': while (*++p == '*') /* Consecutive stars act just like one. */ continue; if (*p == '\0') /* Trailing star matches everything. */ return TRUE; while (*text) if ((matched = DoMatch(text++, p)) != FALSE) return matched; return ABORT; case '[': reverse = p[1] == NEGATE_CLASS ? TRUE : FALSE; if (reverse) /* Inverted character class. */ p++; for (last = 0400, matched = FALSE; *++p && *p != ']'; last = *p) /* This next line requires a good C compiler. */ if (*p == '-' ? *text <= *++p && *text >= last : *text == *p) matched = TRUE; if (matched == reverse) return FALSE; continue; } } #ifdef MATCH_TAR_PATTERN if (*text == '/') return TRUE; #endif /* MATCH_TAR_ATTERN */ return *text == '\0'; } /* ** User-level routine. Returns TRUE or FALSE. */ int wildmat(text, p) char *text; char *p; { #ifdef OPTIMIZE_JUST_STAR if (p[0] == '*' && p[1] == '\0') return TRUE; #endif /* OPTIMIZE_JUST_STAR */ return DoMatch(text, p) == TRUE; } #endif