/*
 * File: 4th2text.c
 *   By: Dave Hiebeler
 *       August 1989
 *   Massively hacked by Andy Valencia, Jan 2002
 *
 * Copyright 1990 David Hiebeler and Automatrix, Inc.
 * This code can be freely copied and modified for personal use, provided
 * the copyright notice is retained. This code cannot be sold for profit.
 *
 * This program reads in a standard Forth "screen" file (e.g. a .EXP
 * or .4TH file) which is arranged in SCRSIZ blocks of characters.
 * It simply inserts a line-feed after every BLKCOLth character, thus
 * turning it into a file that can be edited by normal means.
 * It will also truncate trailing spaces on each line, to make the resulting
 * file smaller to conserve disk space.
 *
 * If you use the "-n" flag, it will put the string "|x.y|" at the beginning
 * of each line, where "x" is the block number, and "y" is the line number
 * within that block.
 * If you use "-k", classic 1k Forth blocks will be converted, otherwise
 * new-fangled 4k two-screen-per-block ForthOS blocks.
 *
 * Usage: 4th2text [-n] [-k] infile outfile
 * If infile or outfile is "-", then stdin or stdout will be used,
 * respectively.
 */
#include <stdio.h>
#ifdef VSTA
#include <std.h>
#include <alloc.h>
#include <getopt.h>
#else
#include <unistd.h>
#include <stdlib.h>
#endif
#include "defs.h"

static char *cmd;	/* argv[0] */
static int nflag,	/* Put block # comments in */
	kflag;		/* Convert to 1k blocks instead of ForthOS's */
static int blkrows,	/* Screen geometry */
	blkcols;
static FILE *infile,	/* Input and output files */
	*outfile;

/*
 * usage()
 *	Tell how to use this utility
 */
static void
usage(void)
{
    fprintf(stderr, "Usage: %s [-n] [-k] <infile> <outfile>\n", cmd);
    exit(1);
}

/*
 * show_block()
 *	Display the next block off the "fp" stream
 */
static void
show_block(int screen, char *suffix)
{
    char *lb = alloca(blkcols+1), *p;
    int line = 0;

    lb[blkcols] = '\0';
    while (fread(lb, sizeof(char), blkcols, infile) == blkcols) {
	line += 1;

	/* Show prefix if selected */
	if (nflag) {
	    fprintf(outfile, "|%d.%d%s|", screen, line, suffix);
	}

	/* Trim trailing blanks */
	for (p = lb + blkcols - 1; p > lb; --p) {
	    if (*p != ' ') {
		break;
	    }
	}
	p[1] = '\0';

	/* Display it */
	(void)fprintf(outfile, "%s\n", lb);

	/* If we've reached end of screen, break out */
	if ((line % blkrows) == 0) {
	    break;
	}
    }
}

int
main(int argc, char **argv)
{
    int screen, i, scrblk, resid;

    /*
     * Process switches and arguments
     */
    cmd = argv[0];
    while ((i = getopt(argc, argv, "nk")) > 0) {
    	switch (i) {
	case 'n': nflag = 1; break;
	case 'k': kflag = 1; break;
	default:
	    usage();
	}
    }
    if (optind >= argc) {
	usage();
    }
    if (!strcmp(argv[optind], "-")) {
	infile = stdin;
    } else {
	infile = fopen(argv[optind], "r");
	if (infile == NULL) {
	    perror(argv[optind]);
	    exit(1);
	}
    }
    if (++optind >= argc) {
	usage();
    }
    if (!strcmp(argv[optind], "-")) {
	outfile = stdout;
    } else {
	outfile = fopen(argv[optind], "w");
	if (outfile == NULL) {
	    perror(argv[optind]);
	    exit(1);
	}
    }

    /*
     * Configure line geometry
     */
    if (kflag) {
	blkcols = 64;
	blkrows = 16;
	scrblk = 1;
	resid = 0;
    } else {
    	blkcols = BLKCOLS;
	blkrows = BLKROWS;
	scrblk = SCRBLK;
	resid = BLKSIZ - 2*SCRSIZ;
    }

    /*
     * Process screens until EOF
     */
    while (!feof(infile)) {
	/* First screen */
    	show_block(screen, " ");
	/* Second, if present */
	if (scrblk > 1) {
	    /* ASSERT(scrblk == 2) */
	    show_block(screen, "s");
	    /* Trim off residual in block */
	    for (i = 0; i < resid; ++i) {
	    	(void)getc(infile);
	    }
	}
	screen += 1;
    }

    /*
     * Clean up
     */
    (void)fclose(outfile);
    (void)fclose(infile);
    return(0);
}
