/*
        ) Copyright Richard G. McCallister 1986, 1988
        Reproduction for commercial purposes prohibited without
        permission in writing from the publisher.
*/
#include <stdio.h>
#ifndef MSDOS
#include <exec/io.h> 
#include <exec/types.h>
#endif
#include <fcntl.h>
#include <time.h>

#ifdef MSDOS
#include <malloc.h>
#define index(x,y) strchr(x,y)
char *strchr();
#else
char	*index();
FILE	*freopen();
#endif

#define CHAR_LIN 256
#define SZ_TITLE 80

#define TAB	9

long time();
#include "rgm.h"
/* History
	Ver. 2.00 : Nov. 9, 1986 	R. McCallister
			First Amiga Version
	Ver. 2.01 : Dec. 10, 1986	R. McCallister
			Subtitle defaults to current time and date for each file.
	Ver. 3.00 : July 12, 1988   R. McCallister
			Height and Width options changed.
*/

int line_no = 1;
char title[SZ_TITLE] = "",subttl[SZ_TITLE] = "";
int pagelen = 58;
int lines_left = 58;
int	tab = 4;
int	width = 80;
BOOL numflag = TRUE;
BOOL invflag = FALSE;
int page_no = 1;
#define HEADER_SIZE 5

page_eject()
{
    printf("\014\n\n%-*.*s%s%5d\n%s\n\n",
		width - 10, width - 10, title, "Page ", page_no, subttl);
	lines_left = pagelen;
	page_no++;
}
/* page */
char *skip(s,c)
char *s;
char c;
{
    for(;;)
    {
        if (*s == c)
            s++;
        else
            return(s);
    }
}


/* sub=String Matching Routines */
char *match_n(m,s,n,partial)
char *m;    /* Pattern to be matched */
char *s;    /* String being searched for a match */
int n;       /* Maximum number of characters to search */
int partial; /* TRUE if partial matching (including 0 character length matching)
                 will return a pointer to the character after the last one
                 matched; FALSE otherwise */
{
    int i;
    char *new_s;

    for (;;n--)
    {
        if ( n == 0  )
            return (s);
        if ( *s == *m)
        {
            if (*m == ' ' && *(s + 1) == ' ')
            {
                m--;
                n++;
            }
            s++;
            m++;
        }
        else
            if (*m == '[')
            {
                for (i = 1;;i++)
                    if (m[i] == ']' || m[i] == NULL)
                        break;
                s = match_n(++m,s,i - 1,TRUE);
                m += i;
                n -= i;
            }
            else
                if (partial == TRUE)
                    return (s);
        else
            return (NULL);
    }
}

char *match(m,s)
char *m;
char *s;
{
    return (match_n(m,s,strlen(m),FALSE));
}

#define CHAR_LIN 256


char s[CHAR_LIN];
char s2[sizeof(s)];

char *untab();

/* page */

char *untab(s,s2,tab)
char *s;
char *s2;
int  tab;
{
    int i;
    int count;

    for (i = 0;;s++)
    {
        if (*s == TAB)
        {
            count = tab - (i - tab * (i / tab)) - 1;
            for (; count >= 0 ; count--)
            {
                s2[i++] = ' ';
            }
        }
        else
            s2[i++] = *s;
        if (*s == NULL)
            break;
    }
    return(s2);
}
/* sub=Read Loop*/
/*page*/
read_loop(argc,argv)
int		argc;
char	**argv;
{
    char 	s[CHAR_LIN];
    char	*p;
    int		i;
    long	the_time;

    line_no = 1;
	page_no = 1;

    for (i = 1; i < argc; ++i)
    {
        p = argv[i];
        if ( *p == '/')
        {
            ++p;
            pars_opt(p);
        }
    }
    /* Default subtitle set to current time and date*/
    time (&the_time);
    strcpy (subttl, ctime(&the_time));
	 subttl [strlen(subttl) - 1] = NULL;

    page_eject();
    for (;;)
    {
        gets(s);
        if (feof(stdin))
            break;
        pars_line(s);
    }
}
/* sub= Main Routine */
/*page*/
main(argc,argv)
char *argv[];
int argc;
{
    int i;
    char *p;
    FILE	*fp2;	/* Handle for redirected stdin */
    char	*temp;
    int 	files;	/* Number of files processed */

    files = 0;
    for (i = 1; i < argc; ++i)
    {
        p = argv[i];
        if ( *p != '/')
        {
            files++;
            fp2 = freopen (p,"r",stdin);
            if (fp2 == NULL)
            {
                fprintf(stderr,"Can't open %s \n",p);
                exit(0);
            }

            /* Default title set to name of input file */
            strcpy (title, p);

            read_loop(argc,argv);
        }
    }
    if (files == 0)
        read_loop(argc,argv);
    exit(0);
}
/* sub = Help! */
/* page */
help()
{
    fprintf(stderr,"\n Version 3.00   July 12, 1988");
    fprintf(stderr,"\n PRETTY takes commands from comments in a C program or in the command");
    fprintf(stderr,"\nline, to control the formatting of a C program listing.");
    fprintf(stderr,"\nSyntax: pretty [<IN] [>OUT] [/aOUT] [/lX] [/non] [/oOUT]");
    fprintf(stderr,"\n\t[/hX] [/sSUB] [/TX] [/tTITLE] [/?]");
    fprintf(stderr,"\n");
    fprintf(stderr,"\n<IN\tSpecifies IN as the input file.");
    fprintf(stderr,"\n>OUT\tSpecifies output file OUT.");
    fprintf(stderr,"\nIN\tSame as <IN");
    fprintf(stderr,"\n/aOUT\tAppends output to end of file OUT.");
    fprintf(stderr,"\n/lX\tSets initial line number to X (a decimal number)");
    fprintf(stderr,"\n/non\tTurns off the printing of line numbers.");
    fprintf(stderr,"\n/oOUT\tSame effect as >OUT.");
    fprintf(stderr,"\n/hX\tSpecifies maximum of X lines per page (includes titles)");
    fprintf(stderr,"\n\tDefault is 66.");
    fprintf(stderr,"\n/sSUB\tCauses \"SUB\" to be the current subtitle.");
    fprintf(stderr,"\n\tDefault is the current time and date.");
    fprintf(stderr,"\n/TX\tSets tabs every Xth column. Default is 4.");
    fprintf(stderr,"\n/tTITLE Causes \"TITLE\" to be used as the title. Default is the");
    fprintf(stderr,"\n\tname of the file being printed (unless standard input is used).");
    fprintf(stderr,"\n/?\tPrints this help message.");
    fprintf(stderr,"\n\t(Hit RETURN or ENTER for more information)");
    gets(s); /* Wait for RETURN */
    fprintf(stderr,"\nThe following commands may be included in C program comments.");
    fprintf(stderr,"\nThey must be the first non-whitespace in the comment, and the");
    fprintf(stderr,"\ncomment must be the first non-whitespace on the line.");
    fprintf(stderr,"\n");
    fprintf(stderr,"\npage\tCauses a form feed.");
    fprintf(stderr,"\nsu=SUB\tCauses \"SUB\" to be the current subtitle.");
    fprintf(stderr,"\nti=TITLE Causes \"TITLE\" to be used as the title.");
    fprintf(stderr,"\n");
    exit (0);

}
/* sub=Option Parser */
/* page */
pars_opt(p)
char *p;
/* History
   5/1/86 - buffer s2 made static; title and subttl changed to use
	  SZ_TITLE to adjust their sizes.
   6/6/86 - Header commands (h-, h+) implemented. Nonum command added.
*/
{
    FILE	*fp2; /* File pointer for a, o  options */

    switch(*p)
    {

    case 'a':
        fp2 = freopen (++p,"a",stdout);
        if (fp2 != NULL)
        {
            fprintf(stderr,"Can't open %s \n",p);
            exit(0);
        }
        break;

    case 'h':
        sscanf(p + 1,"%d",&pagelen);
        pagelen -= HEADER_SIZE;
        break;

    case 'i':
        if (match ("inv[isible]-",p) != NULL)
            invflag = FALSE;
        else if (match ("inv[isible][+]",p) != NULL)
            invflag = TRUE;
        break;

    case 'l':
        sscanf(p + 1,"%d",&line_no);
        break;

    case 'n':
        if ( (match ("non[umber]",p) != NULL))
            numflag = FALSE;
        else if ( (match ("nu[mber]",p) != NULL))
            numflag = TRUE;
        break;

    case 'o':
        fp2 = freopen (++p,"w",stdout);
        if (fp2 != NULL)
        {
            fprintf(stderr,"Can't open %s \n",p);
            exit(0);
        }
        break;

    case 'p':
        sscanf(p + 1,"%d",&page_no);
        break;

    case 's':
        strcpy(subttl,p + 1);
        break;

    case 't':
        strcpy(title,p + 1);
        break;

    case 'T':
        sscanf(p + 1,"%d",&tab);
        break;

    case '?':
    case '-':
        help();
        break;
    case 'w':
        sscanf(p + 1,"%d",&width);
        if (width > (unsigned int) 255)
            width = 255;
        break;
    default:
        break;
    }
    return(0);
}
/* sub= Print Line */
/* page */
#define LN_SIZE 6

pr_line (s, numflag, recursion)
char	*s;
BOOL	numflag;
BOOL	recursion;
{
    char s2[CHAR_LIN + LN_SIZE];

    if (numflag != FALSE && recursion == FALSE)
		sprintf(s2,"%4d: ", line_no);
    else if (numflag == TRUE && recursion == TRUE)
		strcpy (s2,"      ");
	else
		*s2 = NULL;
	untab (s,s2 + strlen(s2), tab);
    printf("%.*s",width,s2);

    if ( --lines_left <= 0)
        page_eject();
	else
		printf ("\n");

	if (strlen (s2) > width)
		pr_line (s2 + width, numflag, TRUE);
}
/* sub=Input Line Parser */
/* page */

pars_line(s)
char *s;
/* History
   5/1/86 - buffer s2 made static; title and subttl changed to use
	  SZ_TITLE to adjust their sizes.
   6/6/86 - Header commands (h-, h+) implemented. Nonum command added.
*/
{
    char  this_inv;
    char *p;
    char *temp;
    char comment;

    comment = TRUE;
    p = skip(s,' ');
    p = match("/*",s);
    if (p == NULL)
    {
        p = skip(s,' ');
        comment = FALSE;
    }
    else
        p = skip(p,' ');
    this_inv = TRUE;

    switch(*p)
    {

    case 'p':
        if (match ("page[ ]*/",p) != NULL && comment == TRUE)
        {
            page_eject();
        }
        else
            this_inv = FALSE;
        break;

    case 's':
        if (match ("su[btitle ]=",p) != NULL)
        {
            strcpy(subttl,index(p,'=') + 1);
            temp = index(subttl,'*');
            if (*temp == '*' && *(temp + 1) == '/')
                *temp = NULL;
        }
        else
            this_inv = FALSE;
        break;

    case 't':
        if (match ("ti[tle ]=",p) != NULL)
        {
            strcpy(title,index(p,'=') + 1);
            temp = index(title,'*');
            if (*temp == '*' && *(temp + 1) == '/')
                *temp = NULL;
        }
        else
            this_inv = FALSE;
        break;

    default:
        this_inv = FALSE;
        break;
    }
    if (invflag == TRUE && this_inv == TRUE)
    {
        s = "";
    }
	pr_line (s, numflag, FALSE);

    line_no++;

    return(0);
}
