/*
 *   pr.c:  detabbing file printer -
 *
 *        usage:  pr [options] [file1 file2 ...]
 *        options:
 *               -b#     begin printing with page #
 *               -c#     print # copies
 *               -d      delete file after printing
 *               -e#     end printing with page #
 *               -hs     use title s instead of filename (NULL = no header)
 *               -l      print with line numbers
 *               -m#     print with a left margin of # spaces
 *               -n#     print # lines per page (header xtra)
 *               -s#     print with spacing of # lines
 *               -t#     set tabs every # spaces (default 4)
 *               -w#     define page width (default 256)
 *
 *       Other than tabs, all control characters are suppressed.
 *
 *       Adapted from Software Tools by Chuck Allison - May 1985
 */

#include <stdio.h>
#include <ctype.h>
#include <time.h>
#include <types.h>  /* MWC only */

#define inrange(x) (start <= x && x <= stop)
#define getnum(x) x = atoi(s+1); goto next_arg

#define MAXINT 32767
#define MAXLINE 256
#define yes 1
#define no 0

/* ..set default parameters.. */
int number = no,
    delete = no,
    print_lines_pp = 55,
    text_lines_pp = 55,
    margin = 3,
    spacing = 1,
    tabspace = 4,
    width = 256,
    headers = yes,
    copies = 1,
    start = 1,
    stop = MAXINT;

static tabstops[MAXLINE];
time_t time_val;
static char timestr[25], title[36] = "";
extern char *trim_fspec();

main(argc,argv)
int argc;
char *argv[];
{
    int hour;
    register char *s;

    /* ..process switches.. */
    while (--argc && (**++argv == '-'|| **argv == '/'))
    {
        for (s = *argv+1; *s; ++s)
            switch(tolower(*s))
            {
                case 'b':
                    getnum(start);
                case 'd':
                    delete = yes;
                    break;
                case 'e':
                    getnum(stop);
                case 'h':
                    if (s[1])
                    {
                        strcpy(title,++s);
                        goto next_arg;
                    }
                    else
                    {
                        headers = no;
                        break;
                    }
                case 'l':
                    number = yes;
                    break;
                case 'm':
                    getnum(margin);
                case 'n':
                    getnum(print_lines_pp);
                case 's':
                    getnum(spacing);
                case 't':
                    getnum(tabspace);
                case 'c':
                    getnum(copies);
                case 'w':
                    getnum(width);
                default :
                    fprintf(stderr,"---> ERROR: bad switch: -%c\n",*s);
                    exit(1);
            }
        next_arg: /* ..cycle on outer for().. */ ;
    }

    /* ..initialize tab settings.. */
    settabs();

    /* ..validate line spacing.. */
    if (spacing <= 0 || print_lines_pp <= spacing)
    {
        fprintf(stderr,"---> ERROR: Spacing invalid\n");
        exit(1);
    }
    text_lines_pp = 1 + (print_lines_pp - 1) / spacing;
    
    /* ..get date and time.. */
    time(&time_val);
    strcpy(timestr,ctime(&time_val));
    timestr[24] = '\0';   /* ..zap newline.. */
    /* ..Replace seconds with am/pm.. */
    timestr[16] = ' ';
    hour = 10*(timestr[11] - '0') + (timestr[12] - '0');
    if (hour >= 12)
    {
        timestr[17] = 'p';
        if (hour > 12)
        {
            hour -= 12;
            timestr[12] = hour%10 + '0';
            timestr[11] = (hour /= 10) ? hour + '0' : ' ';
        }
   }
    else
    {
        timestr[17] = 'a';
        if (hour == 0)
        {
            timestr[11] = '1';
            timestr[12] = '2';
        }
        else if (timestr[11] == '0')
            timestr[11] = ' ';
    }
    timestr[18] = 'm';

    /* ..process files.. */
    if (argc == 0)
        process(title);
    else
    {
        /* ..print each file.. */
        for (; *argv; ++argv)
            if (freopen(*argv,"r",stdin) != NULL)
            {
                process((strlen(title) == 0) ? *argv : title);
                if (delete)
                    if (unlink(*argv) != 0)
                        fprintf(stderr,"---> WARNING: can't delete %s\n",*argv);
                    else
                        fprintf(stderr,"---> %s deleted.\n",*argv);
            }
            else
                fprintf(stderr,"---> ERROR: can't process %s\n",*argv);
    }
}

process(f)
char *f;
{
    register i;

    for (i = 0; i < copies; ++i)
    {
         rewind(stdin);
         pr(f);
    }
}

pr(name)
char *name;
{
    register lineno, i;
    int pageno, offset;
    char line[MAXLINE];
    extern char *rindex();
    
    offset = 0;
    pageno = 1;
    lineno = 1;
    
    fprintf(stderr,"---> printing %s...\n",name);

    /* ..trim a long file name.. */
    trim_fspec(name,name,30);

    /* ..output initial header.. */
    if (inrange(pageno))
        if (headers)
            header(name,pageno);
        else
            printf("\n\n\n\n");

    while (fgets(line,MAXLINE-1,stdin) != NULL)
    {
        /* ..check page range.. */
        if (pageno > stop)
            return;
            
        if (lineno == 0)
        {
            lineno = 1;
            if (inrange(pageno))
                if (headers)
                    header(name,pageno);
                else
                    printf("\n\n\n\n");
        }

        if (pageno > stop)
            return;

        /* ..print line, with number, if requested.. */
        if (inrange(pageno))
        {
            do_margin();
            if (number)
                printf("%5d  ",offset+lineno);
            else
                printf("  ");
            detab(line);
            if (lineno+1 <= text_lines_pp)
                for (i = 1; i < spacing; ++i)
                    putchar('\n');
        }

        /* ..check for page break.. */
        if (++lineno > text_lines_pp)
        {
            if (inrange(pageno))
                putchar('\f');
            offset += text_lines_pp;
            ++pageno;
            lineno = 0;
        }
    }

    /* ..form-feed after last partial page.. */
    if (inrange(pageno))
        if (lineno > 0)
            putchar('\f');
}

header(file,page)
char *file;
int page;
{
    register i;

    putchar('\n');
    do_margin();
    for (i = 0; i < 75; ++i)
        putchar('-');
    putchar('\n');
    do_margin();
    printf("%-36.36s%-30.30sPage%5d",file,timestr,page);
    putchar('\n');
    do_margin();
    for (i = 0; i < 75; ++i)
        putchar('-');
    printf("\n\n\n");
}

detab(line)
char *line;
{
    register i, col;

    col = 0;

    /* ..note: line[] has a terminating '\n' per fgets().. */
    for (i = 0; col < width-margin-(number?7:2) && i < strlen(line); ++i)
        if (line[i] == '\t')
            do
            {
                /* ..tab.. */
                putchar(' ');
                ++col;
            } while (!tabstops[col]);
        else if (line[i] == '\n' || isprint(line[i]))
        {
            putchar(line[i]);
            ++col;
        }
    if (i < strlen(line))
        putchar('\n');
}

settabs()
{
    register i;

    tabstops[0] = 0;
    for (i = 1; i < MAXLINE; ++i)
        tabstops[i] = (i % tabspace == 0);
}

do_margin()
{
    register i;
    
    for (i = 0; i < margin; ++i)
        putchar(' ');
}
