/* -*- Mode: Text -*- */
#ifndef lint
static char Rcs_Id[] =
    "$Id: icombine.c,v 2.13 91/07/15 19:55:02 geoff Exp $";
#endif

#define MAIN

/*
 * icombine:  combine multiple ispell dictionary entries into a single 
 *            entry with the options of all entries
 *
 * The original version of this program was written by Gary Puckering at
 * Cognos, Inc.  The current version is a complete replacement, created by
 * reducing Pace Willisson's buildhash program.  By using routines common
 * to buildhash and ispell, we can be sure that the rules for combining
 * capitalizations are compatible.
 *
 * Copyright 1988, 1989, by Geoff Kuenning, Manhattan Beach, CA
 * Permission for non-profit use is hereby granted.
 * All other rights reserved.
 * See "version.h" for a more complete copyright notice.
 */

/*
 * $Log:	icombine.c,v $
 * Revision 2.13  91/07/15  19:55:02  geoff
 * Make sure the argument to makedent is properly converted to canonical form.
 * 
 * Revision 2.12  91/07/15  19:26:52  geoff
 * Provide the "canonical" parameter to all strtoichar calls.
 * 
 * Revision 2.11  91/07/11  19:52:08  geoff
 * Remove the include of stdio.h, since ispell.h now does this.
 * 
 * Revision 2.10  91/07/04  00:04:09  geoff
 * Add the "-T" switch to support conversion between different stringchar
 * standards.
 * 
 * Revision 2.9  91/07/03  18:20:39  geoff
 * Don't include types.h, dir.h, or param.h, since config.h now does that.
 * 
 * Revision 2.8  91/06/23  22:01:03  geoff
 * On non-USG systems, include sys/dir.h for MAXNAMLEN
 * 
 * Revision 2.7  90/12/31  01:04:06  geoff
 * Reformat to follow a consistent convention throughout ispell.
 * 
 * Revision 2.6  89/06/09  15:53:14  geoff
 * Add support for the internal "character" type, ichar_t.
 * 
 * Revision 2.5  89/04/28  01:08:51  geoff
 * Change Header to Id;  nobody cares about my pathnames.
 * 
 * Revision 2.4  89/04/03  01:55:26  geoff
 * Fix some lint complaints.
 * 
 * Revision 2.3  88/12/26  02:26:01  geoff
 * Update the copyright notice.
 * 
 * Revision 2.2  88/11/25  19:50:46  geoff
 * Get rid of some unused variables.  Add proper casts in two calls to
 * myfree.
 * 
 * Revision 2.1  88/04/30  22:12:31  geoff
 * Fix some lint complaints.
 * 
 * Revision 2.0  88/03/26  23:20:57  geoff
 * Complete rewrite making use of code from buildhash.c
 * 
 */

#include <ctype.h>
#include "config.h"
#include "ispell.h"
#include "msgs.h"

char *		Lfile;			/* Language-description file */

extern char *	index ();
extern char *	malloc ();
extern char *	realloc ();
extern void	free ();
extern char *	strcpy ();
extern void	exit ();

extern void yyinit();
extern void upcase();
#ifdef CAPITALIZATION
extern long whatcap();
#endif

main (argc, argv)
    int		argc;
    char *	argv[];
    {
    char *	argp;
    char *	preftype = NULL;

    while (argc > 1  &&  argv[1][0] == '-')
	{
	argc--;
	argv++;
	switch (argv[0][1])
	    {
	    case 'T':
		argp = (*argv)+2;
		if (*argp == '\0')
		    {
		    argv++; argc--;
		    if (argc == 0)
			usage ();
		    argp = *argv;
		    }
		preftype = argp;
		break;
	    default:
		usage ();
		break;
	    }
	}

    if (argc > 1)			/* Figure out what language to use */
	Lfile = argv[1];
    else
	Lfile = DEFLANG;

    if (yyopen (Lfile))			/* Open the language file */
      return 1;
    yyinit ();				/* Set up for the parse */
    if (yyparse ())			/* Parse the language tables */
	exit (1);

    if (preftype != NULL)
	{
	defdupchar = findfiletype (preftype, 1);
	if (defdupchar < 0
	  &&  strcmp (preftype, "tex") != 0
	  &&  strcmp (preftype, "nroff") != 0)
	    {
	    (void) fprintf (stderr, ICOMBINE_C_BAD_TYPE, preftype);
	    exit (1);
	    }
	}
    if (defdupchar < 0)
	defdupchar = 0;

    combinedict ();			/* Combine words */

    return 0;
    }

usage ()
    {

    (void) fprintf (stderr, ICOMBINE_C_USAGE);
    exit (1);
    }

char * mymalloc (size)
    int		size;
    {
    return malloc ((unsigned) size);
    }

/* ARGSUSED */
char * myrealloc (ptr, size, oldsize)
    char *	ptr;
    int		size;
    int		oldsize;
    {
    return realloc (ptr, (unsigned) size);
    }

void myfree (ptr)
    char *	ptr;
    {
    free (ptr);
    }

combinedict ()
    {
    struct dent		d;
    register struct dent * dp;
    char		lbuf[INPUTWORDLEN + MAXAFFIXLEN + 2 * MASKBITS];
    ichar_t		ucbuf[INPUTWORDLEN + MAXAFFIXLEN + 2 * MASKBITS];
    ichar_t		lastbuf[INPUTWORDLEN + MAXAFFIXLEN + 2 * MASKBITS];

    lastbuf[0] = '\0';
    hashtbl = (struct dent *) mymalloc (sizeof (struct dent));
    hashtbl->flagfield = 0;
    hashtbl->word = 0;
    while (fgets (lbuf, sizeof lbuf, stdin) != NULL)
	{
	if (makedent (ichartosstr (strtosichar (lbuf, 0), 1), &d) < 0)
	    continue;

	strtoichar (ucbuf, d.word, 1);
	upcase (ucbuf);
	if (icharcmp (ucbuf, lastbuf) != 0)
	    {
	    /*
	    ** We have a new word.  Put the old one out.
	    */
	    combineout ();
	    (void) icharcpy (lastbuf, ucbuf);
	    }

	dp = hashtbl;
	if ((dp->flagfield & USED) == 0)
	    {
	    *dp = d;
#ifdef CAPITALIZATION
	    /*
	    ** If it's a followcase word, we need to make this a
	    ** special dummy entry, and add a second with the
	    ** correct capitalization.
	    */
	    if (captype (d.flagfield) == FOLLOWCASE)
		{
		if (addvheader (dp))
		  exit (1);
		}
#endif
	    }
	else
	    {
	    /*
	    ** A different capitalization is already in
	    ** the dictionary.  Combine capitalizations.
	    */
	    if (combinecaps (dp, &d) < 0)
	      exit (1);
	    }
	}
    combineout ();
    }

combineout ()
    {
    register struct dent *	ndp;
    register struct dent *	tdp;

    /*
    ** Put out the dictionary entry on stdout in text format,
    ** freeing it as we go.
    **/
    if (hashtbl->flagfield & USED)
	{
	for (tdp = hashtbl;  tdp != NULL;  tdp = ndp)
	    {
	    toutent (stdout, tdp, 0);
	    myfree (tdp->word);
	    ndp = tdp->next;
#ifdef CAPITALIZATION
	    while (tdp->flagfield & MOREVARIANTS)
		{
		if (tdp != hashtbl)
		    myfree ((char *) tdp);
		tdp = ndp;
		if (tdp->word)
		    myfree (tdp->word);
		ndp = tdp->next;
		}
#endif
	    if (tdp != hashtbl)
		myfree ((char *) tdp);
	    }
	}
    hashtbl->flagfield = 0;
    hashtbl->word = NULL;
    }
