// 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);
}