// REMTAB.CPP // Replaces tab characters with spaces in text files. // Author: Peter Meyer #include <fstream.h> // This automatically includes <iostream.h> #include <stdlib.h> #include <string.h> #include <direct.h> #define TRUE 1 #define FALSE 0 #define loop while(TRUE) #define TAB 9 #define LINEFEED 10 #define SPACE 32 #define MAX_TAB_SIZE 8 #define MIN_TAB_SIZE 1 #define DEFAULT_TAB_SIZE 4 #define MAX_LINE_LENGTH 1023 int tab_size, num_tabs=0; char *version = "1.1"; char line[MAX_LINE_LENGTH+1]; char tab_spaces[MAX_TAB_SIZE+1]; ifstream input_file; ofstream output_file; void read_command_line(int ac, char *argv[]); void set_tab(void); void open_files(char *argv[]); int read_line(char *argv[]); void write_line(char *argv[]); void replace_tabs(void); void terminate(char *argv[]); /*-----------------------------*/ void main(int argc, char *argv[]) { cout << "\nREMTAB.EXE, Version " << version << "++, Copyright 1999 Hermetic Systems"; cout << "\nThis program replaces tab characters with spaces in a text file."; _getcwd(line,sizeof(line)); cout << "\nCurrent directory is " << line << endl; read_command_line(argc,argv); set_tab(); open_files(argv); loop { if ( !read_line(argv) ) terminate(argv); replace_tabs(); write_line(argv); } } /*----------------------------------------*/ void read_command_line(int ac, char *argv[]) { if ( ac < 3 || ac > 4 ) { cout << "\nUse: REMTAB input_file output_file"; cout << "\n or: REMTAB input_file output_file tab_size"; cout << "\ntab_size defaults to 4 spaces." << endl; exit(0); } // open() does not check for inconsistent openings of same file. if ( !strcmp(argv[1],argv[2]) ) { cout << "\nOutput file must be different from input file." << endl; exit(1); } tab_size = ( ac > 3 ? atoi(argv[3]) : DEFAULT_TAB_SIZE ); } /*--------------*/ void set_tab(void) { int i; if ( tab_size < MIN_TAB_SIZE || tab_size > MAX_TAB_SIZE ) { cout << "\nInvalid value " << tab_size << " for tab_size " << "(must be in the range " << MIN_TAB_SIZE << " through " << MAX_TAB_SIZE << "." << endl; exit(2); } i = tab_size; while ( --i >= 0 ) tab_spaces[i] = SPACE; tab_spaces[tab_size] = 0; } /*-------------------------*/ void open_files(char *argv[]) { input_file.open(argv[1]); if ( !input_file ) { cout << "\nCannot open input file " << argv[1] << endl; exit(3); } output_file.open(argv[2]); if ( !output_file ) { cout << "\nCannot open output file " << argv[2] << endl; input_file.close(); exit(4); } cout << "\nInput file " << argv[1] << " opened for reading." << endl; } // This differs somewhat from the C version. /*-----------------------*/ int read_line(char *argv[]) { input_file.getline(line,sizeof(line),LINEFEED); // This reads a maximum of sizeof(line)-1 bytes // and throws away the LINEFEED (if read). return ( input_file ? TRUE : FALSE ); } /*-------------------------*/ void write_line(char *argv[]) { output_file << line << endl; if ( !output_file ) { cout << "\nError when writing to output file " << argv[2] << "." << endl; exit(6); } } // This replaces all occurrences of tab characters in line[] // with the appropriate number of spaces // (as long as there is sufficient space in line[]). /*-------------------*/ void replace_tabs(void) { int i, num_spaces; char *ptr1, *ptr2; while ( ( ptr1 = strchr(line,TAB) ) != NULL ) { num_tabs++; num_spaces = tab_size - (ptr1-line)%tab_size; if ( strlen(line) + num_spaces > sizeof(line) - 1 ) { cout << "\nExpanded line exceeds maximum length of " << sizeof(line)-1 << " characters." << endl; exit(7); } ptr2 = strchr(line,0) + 1; while ( --ptr2 > ptr1 ) *(ptr2+num_spaces-1) = *ptr2; for ( i=0; i<num_spaces; i++ ) *(ptr1+i) = SPACE; } } /*------------------------*/ void terminate(char *argv[]) { input_file.close(); output_file.close(); cout << "\nOutput file " << argv[2] << " written. "; if ( !num_tabs ) cout << "No tab characters found." << endl; else cout << num_tabs << " tab character" << (num_tabs>1?"s":"") << " replaced." << endl; exit(0); }