
	/* beautify a request file:

	          1. start all keywords in column 1 (and put in upper case)
	          2. put all equal-signs in column 9
	          3. start all values in column 11

	   however, don't modify COMMENT lines, or blank ones, or those
	   which start with a comment character */

#include <stdio.h>
#include <ctype.h>
#include "pf.h"
#include "header.h"


#define PRETTYTEMP  "pretty.temp"
#define LINELEN      100
#define COMM_STR     "COMMENT"		/* the string denoting a comment line */
#define COMMENT_CHAR '/'			/* this IS defined in pf.h, but ?! */
#define DELIM_COL    8				/* column into which delim char goes */
#define VALUE_COL   (DELIM_COL + 2)	/* column in which value starts */
#define COMM_COL     30				/* col in which comments go, if possible */
	
static int isblank( /* char *line */ );
static int iscomment( /* char *line */ );
static void fixcomment( /* char *line */ );
static int parse( /* char *line, int *key, *delim, *value, *comment */ );
static void putline( /* FILE *fp, char *line, int key, delim, value, comment */ );


char *progname = "prettyrqs";

main(argc, argv)
int argc;
char *argv[];
{
	int i, code;
	char filename[80];

	code = 0;
	for (i = 1; i < argc; i++) {
		strcpy(filename, argv[i]);
		if (beautify(filename) != 0) {
			fprintf(stderr, "error fixing up file %s\n", filename);
			code = 1;
		}
	}

	exit(code);
}

	/* actually fix up the file. return 0 if all OK, or 1 if a problem. */

int
beautify(filename)
char *filename;
{
	int code, key, delim, val, comment;
	char line[LINELEN + 1];
	FILE *infp, *outfp;

	
	if ((infp = fopen(filename, "r")) == NULL) {
		fprintf(stderr, "can't open file %s\n", filename);
		return(1);
	}
	if ((outfp = fopen(PRETTYTEMP, "w")) == NULL) {
		fprintf(stderr, "can't open temp file %s\n", filename);
		fclose(infp);
		return(1);
	}
	code = 0;
	while (fgets(line, LINELEN, infp) != NULL) {
		if ((line[0] == SKIP_CHAR) || (isblank(line))) {
			fprintf(outfp, "%s\n", line);
			continue;
		}
		if (iscomment(line)) {
			fixcomment(line);
			fprintf(outfp, "%s\n", line);
			continue;
		}
		if (parse(line, &key, &delim, &val, &comment) != 0) { 
			printf("line ..%s.. is not a valid header line \n", line);
			code = 1;
			break;
		}
		putline(outfp, line, key, delim, val, comment);
	}

	fclose(infp);
	fclose(outfp);
	if (code == 0) {
		if ((infp == fopen(PRETTYTEMP, "r")) == NULL) {
			fprintf(stderr, "can't re-open temp file %s for reading\n", PRETTYTEMP);
			unlink(PRETTYTEMP);
			return(1);
		}
		if ((outfp == fopen(filename, "w")) == NULL) {
			fprintf(stderr, "can't re-open file %s for writing\n", filename);
			unlink(PRETTYTEMP);
			return(1);
		}
		while (fgets(line, LINELEN, infp) != NULL) {
			fputs(line, outfp);
		}
		fclose(infp);
		fclose(outfp);
	}
	unlink(PRETTYTEMP);
	return(code);
}
		

	/* return 1 if the given line has only blanks or tabs, or 0 otherwise */

static int
isblank(line)
char *line;
{
	int i, len;

	len = strlen(line);
	for (i = 0; i < len; i++) {	
		if ((line[i] != ' ') && (line[i] != '\t') && (line[i] != '\n'))
			return(0);
	}
	return(1);
}

	/* return 1 if the given line's first chars are the COMMENT string,
	   in upper or lower case.  otherwise, return 0. */

static int
iscomment(line)
char *line;
{
	int i;
	static int diff = 'A' - 'a';
	char c, buf[LINELEN + 1];
	
	if (strlen(line) < strlen(COMM_STR))
		return(0);
	strcpy(buf, COMM_STR);
	for (i = 0; i < strlen(COMM_STR); i++) {
		c = line[i];
		if (islower(c))
			c += diff;
		if (c != buf[i])
			return(0);
	}
	if (!isspace(line[i]) && (line[i] != '\0'))
		return(0);

	return(1);
}

	/* take the given line and make it one which starts with an 
	   uppercase COMMENT keyword, then has a single space, then 
	   has the rest of the initial line, untouched */

static void
fixcomment(line)
char *line;
{
	int i, len;
	char buf[LINELEN + 1];

	len = strlen(line);
	strcpy(buf, COMM_STR);
	i = strlen(COMM_STR);
	buf[i] = ' ';
	for (i++; i < len; i++) {
		buf[i] = line[i];
	}
	buf[i] = '\0';
	strcpy(line, buf);
}

	/* parse the line, finding the positions of the keyword, delimiter,
	   value and comment-marker (if any) and placing them in the given
	   parameters.  All parameters are set to -1 initially.

	   return 0 if all OK, 1 if there's some problem. */

#define OUTSIDE_QUOTE   0
#define INSIDE_QUOTE    1
	
static int 
parse(line, key, delim, value, comment)
char *line;
int *key, *delim, *value, *comment;
{
	int i, state;

	state = OUTSIDE_QUOTE;

	*key = -1;
	*delim = -1;
	*value = -1;
	*comment = -1;

	for (i = 0; i < strlen(line); i++) {
		if (line[i] == QUOTE_CHAR) 
			state = (state == OUTSIDE_QUOTE ? INSIDE_QUOTE : OUTSIDE_QUOTE);

		if ((*key == -1) && (!isspace(line[i])) && (line[i] != DELIM_CHAR) &&
		    (line[i] != COMMENT_CHAR)) {
			*key = i;
			continue;
		}
		if ((*key != -1) && (*delim == -1) && (line[i] == DELIM_CHAR)) {
			*delim = i;
			continue;
		}
		if ((*delim != -1) && (*value == -1) && (!isspace(line[i])) &&
		    (line[i] != COMMENT_CHAR)) {
			*value = i;
			continue;
		}
		if ((*comment == -1) && (state == OUTSIDE_QUOTE) && 
		    (line[i] == COMMENT_CHAR)) {
			*comment = i;
			continue;
		}
	}

	return(0);
}
			
	/* reformat a line into a 'pretty' one, and put the new version
	   into the given file */

static void
putline(fp, line, key, delim, value, comment)
FILE *fp;
char *line;
int key, delim, value, comment;
{
	int i, lp, bp, state, done, start;
	char buf[LINELEN + 1];

	i = 0;
	lp = 0;
	bp = 0;

	/* first check to see if there is a keyword */
	if (key > -1) {
		for (lp = key; ((!isspace(line[lp])) && (isprint(line[lp])) &&
		          (line[lp] != DELIM_CHAR)); lp++)
			buf[bp++] = line[lp];
	}
	if (delim > -1) {
		for ( ; bp < DELIM_COL; bp++)
			buf[bp] = ' ';
		buf[bp++] = DELIM_CHAR;
	}
	if (value > -1) {
		for ( ; bp < VALUE_COL; bp++)
			buf[bp] = ' ';
		state = OUTSIDE_QUOTE;
		done = 0;
		for (lp = value; done == 0; lp++) {
			if (line[lp] == QUOTE_CHAR) {
				buf[bp++] = line[lp];
				state = (state == OUTSIDE_QUOTE ? INSIDE_QUOTE : OUTSIDE_QUOTE);
			}
			else if ((state == OUTSIDE_QUOTE) && (line[lp] == COMMENT_CHAR)) {
				done = 1;
			}
			else if ((line[lp] == '\n')	|| (line[lp] == '\0'))
				done = 1;
			else {
				if ((state == INSIDE_QUOTE) || (!isspace(line[lp])))
					buf[bp++] = line[lp];
				else 
					buf[bp++] = ' ';
			}
		}
	}

	/* try to put the comment starting at COMM_COL, but don't overwrite
	   any information that might extend that far. Also, start before COMM_COL
	   if we would go past 80 characters. */
	if (comment > -1) {
		/* back up to the last non-blank char in the line */
		bp--;
		if ((buf[bp] == COMMENT_CHAR) || (buf[bp] == '\0') || (buf[bp] == '\n'))
			bp--;
		while ((isspace(buf[bp])) && (bp > 0))
			bp--;
		i = strlen(line) - comment;
		start = (i > (80 - COMM_COL) ? 80 - i : COMM_COL);
		while (bp < start)
			buf[bp++] = ' ';
		buf[bp++] = COMMENT_CHAR;
		lp = comment + 1;
		while ((line[lp] != '\n') && (line[lp] != '\0'))
			buf[bp++] = line[lp++];
	}

	buf[bp] = '\0';
	fprintf(fp, "%s\n", buf);
}
		

