//  REMTAB.C
    //  Replaces tab characters with spaces in text files.
    //  Author: Peter Meyer
    
    #include <stdio.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];
    
    FILE *input_file, *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[])
    {
    printf("\nREMTAB.EXE, Version %s, Copyright 1999 Hermetic Systems",version);
    printf("\nThis program replaces tab characters with spaces in a text file.");
    
    _getcwd(line,sizeof(line));
    printf("\nCurrent directory is %s\n",line);
    
    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 )
        {
        printf("\nUse: REMTAB input_file output_file");
        printf("\n or: REMTAB input_file output_file tab_size");
        printf("\ntab_size defaults to 4 spaces.\n");
        exit(0);
        }
    
    //  fopen() does not check for inconsistent openings of same file.
    if ( !strcmp(argv[1],argv[2]) )
        {
        printf("\nOutput file must be different from input file.\n");
        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 )
        {
        printf("\nInvalid value %d for tab_size (must be in the range %u through %u).\n",
            tab_size, MIN_TAB_SIZE, MAX_TAB_SIZE);
        exit(2);
        }
    
    i = tab_size;
    while ( --i >= 0 )
        tab_spaces[i] = SPACE;
    
    tab_spaces[tab_size] = 0;
    }
    
    /*-------------------------*/
    void open_files(char *argv[])
    {
    if ( ( input_file = fopen(argv[1],"rt") ) == NULL )
        {
        printf("\nCannot open input file %s\n",argv[1]);
        exit(3);
        }
    
    if ( ( output_file = fopen(argv[2],"wt") ) == NULL )
        {
        printf("\nCannot open output file %s\n",argv[2]);
        fclose(input_file);
        exit(4);
        }
    
    printf("\nInput file %s opened for reading.\n",argv[1]);
    }
    
    /*-----------------------*/
    int read_line(char *argv[])
    {
    char *ptr;
    
    //  fgets() reads at most sizeof(line)-1 bytes
    //  and keeps the final LINEFEED if found.
    if ( fgets(line,sizeof(line),input_file) == NULL )
        return ( FALSE );
    
    ptr = strchr(line,LINEFEED);
    if ( ptr != NULL )
        *ptr = 0;        //  Remove final line feed
    
    return ( TRUE );
    }
    
    /*-------------------------*/
    void write_line(char *argv[])
    {
    if ( fprintf(output_file,"%s\n",line) == EOF )
        {
        printf("\nError when writing to output file %s.\n",argv[2]);
        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 )
            {
            printf("\nExpanded line exceeds maximum length of %d characters.\n",sizeof(line)-1);
            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[])
    {
    fclose(input_file);
    fclose(output_file);
    
    printf("\nOutput file %s written. ",argv[2]);
    
    if ( !num_tabs )
        printf("No tab characters found.\n");
    else
        printf("%d tab character%s replaced.\n",
            num_tabs,(num_tabs>1?"s":""));
    
    exit(0);
    }