/* $Id: word2x.cc,v 1.5 1997/03/31 23:15:38 dps Exp $ */
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <getopt.h>
#include <ctype.h>
#include "interface.h"
#include "lib.h"

#ifndef N
#define N(x) (sizeof(x)/sizeof(x[0]))
#endif

extern docfmt txtfmt, latexfmt;

/* postfix test */
static int postfix(const char *s, const char *t)
{
    unsigned int n;

    n=strlen(t);
    if (strlen(s)<=n)
	return 0;
    return (strcasecmp(s+strlen(s)-n, t)==0) ? 1 : 0;
}

/*
 * open file with .doc or .DOC tacked on the end if the filename alone
 * does not exist
 */
static FILE *open_file(const char *f)
{
    char *s;
    FILE *r;

    if ((r=fopen(f, "r"))!=NULL)
	return r;

    if ((s=(char *) malloc(strlen(f)+4))==NULL)
    {
	fprintf(stderr,"word2x: skipping %s due to malloc failure\n", f);
	return NULL;
    }
    strcpy(s, f);
    strcat(s, ".doc");

    if ((r=fopen(s, "r"))==NULL)
    {
	free(s);
	return r;
    }
    
    strcpy(s+strlen(f), ".DOC");
    r=fopen(s, "r");
    free(s);

    return r;
}


/* Just read the files and pass the results on... */
static void convert(FILE *f, FILE *out, const struct docfmt *fmt)
{
    const tok_seq::tok *d;
    int i;
    void *dptr;
    tok_seq rd(f);

    dptr=fmt->new_state();
    while ((d=rd.read_token())!=NULL)
    {
	i=d->tok;

	if (i<NFUNCS && d->end==tok_seq::tok::TOK_START)
	{
	    (fmt->f[i]).start(d, fmt, out, dptr);
	}
	else
	{
	    (fmt->f[i]).end(d, fmt, out, dptr);
	}
    }
    fmt->free_state(dptr);
}

static const char *outname(const char *in, const char *ext)
{
    char *r, *s;
    int adj;

    if (postfix(in, ".doc"))
	adj=3;
    else
	adj=0;

    if ((r=(char *) malloc(strlen(in)+strlen(ext)-adj+1))==NULL)
	return NULL;
    strcpy(r, in);
    s=r+strlen(r)-adj;
    strcpy(s, ext);

    return r;
}

int main(int argc, const char **argv)
{
    static const struct
    {
	const char *name;
	char *(*fmt)(time_t);
    } dates[]=
    {
	{ "uk", uk_date },
	{ "british", uk_date },
	{ "us", us_date },
    };
    static const struct
    {
	const char *name;
	const char *ext;
	const docfmt *fmt;
    } formats[]=
    {
	{ "text", "txt", &txtfmt },
	{ "latex", "tex", &latexfmt },
    };
    static const struct option lopts[]=
    {
	{ "version", 0, NULL, 'V' },
	{ "help", 0, NULL, 'h' },
	{ "format", 1, NULL, 'f' },
	{ "width", 0, NULL,  'w' },
	{ "dates", 0, NULL, 'd' },
	{ "verbose", 0, NULL, 'v' },
	{ "quiet", 0, NULL, 'q' },
    };

    char *(*dfmt)(time_t);
    FILE *in, *out;
    docfmt fmt;
    int c, i, opt_index, n, wd;
    const char *s,*t, *ext;
    int verbose=0, name_alloced, res;

    res=0;			// Return code 0
    fmt=*(formats[0].fmt);	// Set default format
    dfmt=dates[0].fmt;		// Set default date format
    wd=fmt.maxline;		// Set default width
    ext=formats[0].ext;		// Set default extension

    while ((c=getopt_long(argc, (char *const *) argv, "Vhvqf:w:d:",
			  lopts, &opt_index))!=-1)
    {
	switch(c)
	{
	case 'V':			// Print version and exit
	    fputs("word2x 0.001\n", stderr);
	    return 0;
	    
	case 'h':			// Help
	    fputs("Usage: word2x [-f <output format>] [-dates <date format>]"
		  " [-w <line length>]\n"
		  "              <infile> [<outfile>]\n"
		  "Supported date formats: ", stderr);
	    for (i=0; i<(int) N(dates); i++)
	    {
		if (i!=0)
		    fputs(", ", stderr);
		fputs(dates[i].name, stderr);
	    }
	    fputs("\nSupported output formats: ", stderr);
	    for (i=0; i<(int) N(formats); i++)
	    {
		if (i!=0)
		    fputs(", ", stderr);
		fputs(formats[i].name, stderr);
	    }
	    fputc('\n', stderr);
	    return 0;
	    
	case 'v':			// Verbose mode
	    verbose=1;
	    break;
	    
	case 'q':			// Queit mode
	    verbose=0;
	    break;
	    
	case 'w':			// Width
	    n=0;
	    if (*optarg=='\0')
	    {
		fputs("-w requires a number\n", stderr);
		break;
	    }
	    for (s=optarg; *s; s++)
	    {
		if (!isdigit(*s))
		{
		    res=1;
		    fputs("-w requires a number\n", stderr);
		    break;
		}
		n=n*10+(*s-'0');
	    }
	    if (*s=='\0')
		wd=n;
	    break;
	    
	case 'd':			// Date format
	    for (n=-1, i=0; i<(int) N(dates); i++)
	    {
		if (strcasecmp(dates[i].name, optarg)==0)
		{
		    n=i;
		    break;
		}
	    }
	    if (n==-1)
	    {
		res=1;
		fprintf(stderr, "%s is not a known date format\n", optarg);
	    }
	    else
		dfmt=dates[i].fmt;
	    break;
	    
	case 'f':			// Output format
	    for (n=-1, i=0; i<(int) N(formats); i++)
	    {
		if (strcasecmp(formats[i].name, optarg)==0)
		{
		    n=i;
		    break;
		}
	    }
	    if (n==-1)
	    {
		res=1;
		fprintf(stderr, "%s is not a known output format\n", optarg);
	    }
	    else
	    {
		fmt=*(formats[i].fmt);
		ext=formats[i].ext;
	    }
	    break;
	    
	case '?':
	    break;
	    
	default:
	    abort();
	}
    }

    /* Make sure we have a filename */
    if (optind==argc)
    {
	fputs("word2x: filename required (can not handle stdin)\n", stderr);
	return 1;
    }

    /* Stop if invalid switches */
    if (res!=0)
	return res;

    /* Set line width and date format */
    fmt.date=dfmt;
    fmt.maxline=wd;

    /* Loop through files */
    for (i=optind; i<argc; i++)
    {
	s=argv[i];
	if (i==argc-1 || postfix(argv[i+1],".doc"))
	{
	    /* Generate output file name */
	    if ((t=outname(argv[i], ext))==NULL)
	    {
		fprintf(stderr,
			"word2x: skipping %s due to allocation failure\n",
			s);
		continue;
	    }
	    name_alloced=1;
	}
	else
	{
	    t=argv[++i];
	    name_alloced=0;
	}

	/* Open input file */
	if ((in=open_file(s))==NULL)
	{
	    if (name_alloced)
		free((void *) t);
	    fprintf(stderr, "Could not open %s\n", s);
	    res=1;
	    continue;
	}

	/* Check seekability of in file */
	if (fseek(in, 0L, SEEK_SET)!=0)
	{
	    fprintf(stderr, "word2x: %s is not seekable\n", s);
	    fclose(in);
	    res=1;
	    continue;
	}

	/* Open output file */
	if (strcmp(t,"-")==0)
	{
	    out=stdout;
	    t="standard output";
	}
	else
	{
	    if ((out=fopen(t, "w"))==NULL)
	    {
		fprintf(stderr, "Could not open %s\n", t);
		if (name_alloced)
		    free((void *) t);
		fclose(in);
		res=1;
		continue;
	    }
	}

	/* Finally do something */
	if (verbose)
	    fprintf(stderr, "Converting %s to %s\n", s, t);
	convert(in, out, &fmt);
	fclose(in);
	if (out!=stdout)
	    fclose(out);
    }

    return res;
}







