/* PROGRAM TABIN 5.3 converts spaces to tabs usage : TABIN.exe Myfile.TXT - collapses spaces to tabs - leaves spaces alone inside " " and ' ' on single line. - does not know full C++ \ conventions. - trims off ^z Eof char - ensures each line ends in CrLf - single spaces are never converted to tabs. */ /* Roedy Green Canadian Mind Products #101 - 2536 Wark Street Victoria, BC Canada V8T 4G8 tel:(250) 361-9093 mailto:roedyg@mindprod.com http://mindprod.com */ /* Windows console application. For Visual C++ Express options see http://mindprod.com/jgloss/cpp.html#COMPILING Version History: 5.0 1996-10-25 embed Quathiaski address. convert to C from Pascal new algorithm without max line length 5.1 1998-11-08 embed Barker address 5.2 2008-02-03 convert from DOS to Windows to handle long file names use safe character library POSIX compliant display banner on all errors 5.3 2009-03-11 add ANT build script */ /* Previous versions were written in Pascal - embed new address and phone The program convert spaces to tabs in the following sorts of files: .ASM .C .CMD .CPP .H .HPP .TXT If you examine the files produced by TABIN, you may sometimes see long strings of blanks. You may think you have found a bug in TABIN. However, TABIN is not a compressing utility, it is a tabbing utility. A tab does not necessarily represent 8 spaces, it means tab to the next tab stop which are spaced every 8 columns. Only strings of blanks longer than 2 chars are replaced by a tab. Only strings of blanks that stretch all the way to the next tab stop can be converted to a tab. The moral of this tale is that if you use Tabin to compress your source code, keep your columns aligned on columns 1, 9, 17, 25 etc. Please report bugs and problems to: Roedy Green Canadian Mind Products #101 - 2536 Wark Street Victoria, BC Canada V8T 4G8 tel:(250) 361-9093 mailto:roedyg@mindprod.com http://mindprod.com Source and executables may be freely used for any purpose except military. */ /* ==================================== */ #define Esc '\x1B' #define TabSpacing 8 #include /* exit, putenv, _splitpath */ #include /* fclose, fgetc, printf, remove, rename, setvbuf */ #include /* strcat, strcmp, strupr */ #include /* getch, putch */ #include /* isUpper isLower toUpper */ /* ==================================== */ /* use all global variables and no parameter passing for simplicity. */ static FILE *Before; /* input file containing no ^Z chars, except possibly at the end */ static FILE *After; /* output file with spaces collapsed to tabs */ static char * BFilename; /* name of file we will convert */ static char * AFilename; /* name of the temporary output file */ static int col = 0; /* 1-based column we have written */ /* 0 = no non-blank chars on line yet */ static int pendingSpaces = 0; /* spaces to convert to tabs/spaces */ static int insideQuote = 0; /* 1 if inside ' ' */ static int insideDQuote = 0; /* 1 if inside " " */ /* ==================================== */ /* P R O T O T Y P E S */ int main (int argc, char *argv[]); void Banner (void); void Die (void); void HandlePendingSpaces(void); void Honk (void); void OpenAFile (void); void OpenBFile (void); void SafeFilename (void); /* ==================================== */ int main( int argc, char *argv[] ) /* main TABIN */ { int c; /* process char by char */ if ( argc != 2 /* 0=Tabin.Exe 1=MyFile.Txt */ ) { Banner(); printf("Oops! usage: TABIN Myfile.TXT"); printf("Only one file allowed on the command line.\n"); Die(); } BFilename = *++argv; /* want first arg, not progname */ OpenBFile(); /* Open input "before" file. */ /* Make sure file exists before */ /* song and dance about extension. */ SafeFilename(); /* make sure filename has sane extension */ OpenAFile(); /* open output "after" file */ printf("Converting spaces to tabs in %s ...\n",BFilename); while ( (c=fgetc(Before)) != EOF ) { switch ( c ) { case ' ': /* save up spaces to be handled by tabs */ ++pendingSpaces; break; case '\'': HandlePendingSpaces(); /* toggle state if not inside " " */ if ( !insideDQuote )insideQuote= (~insideQuote) & 1; fputc(c,After); col++; break; case '\"': HandlePendingSpaces(); /* toggle state if not inside ' ' */ if ( !insideQuote ) insideDQuote= (~insideDQuote) & 1; fputc(c,After); col++; break; case '\t': /* effectively expand tab to 1 to 8 spaces */ pendingSpaces += (TabSpacing - ((col+pendingSpaces) % TabSpacing)); break; case '\n': /* ignore pending/trailing spaces */ fputc('\n',After); /* runtime library expands to CrLf */ /* Assume quotes never span more than one line. */ /* This way a stray apostrophe won't throw us off. */ col = 0; pendingSpaces = 0; insideQuote= 0; insideDQuote= 0; break; default: HandlePendingSpaces(); fputc(c,After); col++; break; } /* end switch */ } /* end while */ /* Rename output to input */ fclose (Before); fclose (After); remove (BFilename); rename (AFilename, BFilename); return(0); } /* main TABIN */ /* ==================================== */ void HandlePendingSpaces (void) { int i; /* local loop counter */ int effect; /* net effect of tab */ if ( insideQuote | insideDQuote ) { /* don't convert to tab, put out as raw spaces */ for ( i=0; i 0 */ if ( effect == 1 ) fputc(' ', After); else fputc('\t',After); col += effect; pendingSpaces -= effect; } /* handle remaining spaces after the generated tabs */ for ( i=0; i