// (c) 1990-2007 Electronic Arts Inc.

const char *SPIT_history[] =
{
"------------------------------------------------------------------",
"                                                                  ",
"                          Abstract v3.29                          ",
"                                                                  ",
"                     by FrANK G. Barchard, EAC                    ",
"                                                                  ",
"                    Main program - Jun 22, 2006                   ",
"                                                                  ",
"------------------------------------------------------------------",
"                                                                  ",
" Version Date   SE History:                                       ",
" ------- ----   -- --------                                       ",
"    1.00 90xxxx FB amiga version of ibm remheadr                  ",
"    1.10 901030 FB converted to ANSI by FrANK                     ",
"    1.13 901106 FB machine independency include                   ",
"    1.14 901125 FB spit version                                   ",
"    1.15 901126 FB spit v1.11 w/builtin options                   ",
"    1.16 901128 FB spit v1.12 upgrade                             ",
"    1.17 901206 FB wildcard Spit v1.15, dont write empty files    ",
"    1.18 901210 FB ibm abstract format added                      ",
"    1.20 901211 FB cr/lf inserted                                 ",
"    1.21 901216 FB huff-style output                              ",
"    1.22 901220 FB spit v1.22/sargv,dargv list format             ",
"    1.23 910110 FB strip path from source file name in header     ",
"    1.24 910205 FB write enable/disable option                    ",
"    1.25 910211 FB verbose level 1 (terse) output                 ",
"    1.26 910219 FB file size stats bug fix                        ",
"    1.27 910318 FB case independent sort                          ",
"    1.28 910401 FB two column usage/auto opts environment var     ",
"    1.30 910404 FB lattice optimizer bug with strlen avoided      ",
"    1.31 910405 FB abstract delims surround by white space        ",
"    1.32 910509 FB dynamic memory on the fly/1 meg max            ",
"    1.33 910529 FB aztec style options list                       ",
"    1.34 910604 FB generate dsihelp for st/secondary help         ",
"    1.35 910717 FB generate dsihelp for ibm                       ",
"    1.36 910718 FB more intelligent second abstract name detect   ",
"    1.37 910719 FB -o-/secondary names smarter yet                ",
"    1.38 910719 FB abstract output/more dyna mem modules          ",
"    1.39 910822 FB mac cr/lf                                      ",
"    1.40 910909 FB brief output format                            ",
"    1.41 911021 FB output file name first                         ",
"    1.42 911119 FB SPITNL for crlf/Back/strip . from name if last ",
"    1.43 911120 FB ms help default/<Contents> <Index>/$$$ cli opt ",
"    1.44 911120 FB openabs take flen                              ",
"    1.45 911126 FB don't remove c comments from within abstracts  ",
"    1.46 911201 FB @silent lines/new lines within abstract        ",
"    1.47 911204 FB .catagories/dsis.h                             ",
"    1.48 911210 FB prefix optional/mac 411 help/nl based on type  ",
"    1.49 911211 FB fix in get context for nl                      ",
"    1.50 911218 FB remove trailing white spaces from lines        ",
"    1.51 920113 FB primary name with AND without '.' in name      ",
"    1.52 920118 FB multiple output files for MS QuickHelp         ",
"    1.53 920219 FB allow @ silent lines to be indented any amount ",
"    1.54 920323 FB <Content> goto eac table of contents           ",
"    1.55 920427 FB convert source \\ to \\\\ for Quick Help       ",
"    1.56 920617 FB start/stop delim                               ",
"    1.57 920726 FB eac.h, expand tabs 4 to spaces                 ",
"    1.58 920914 FB spit 2.0                                       ",
"    1.59 920928 FB index in menu for quick help                   ",
"    1.60 921006 FB isv changed to eac                             ",
"    1.61 921008 FB allow numberics for abstract names             ",
"    1.62 921111 FB require 'END ABSTRACT' to match 'ABSTRACT'     ",
"    1.63 930112 FB helppc format output                           ",
"    1.64 930219 FB Mac MPW format output                          ",
"    1.65 930418 FB MS convention of ... for suffixes on topics    ",
"    1.66 930520 FB MPW see alsos no lf                            ",
"    1.67 930602 FB skip asis text files if too large              ",
"    1.68 930607 FB MPW indent '-'/allow '-' in secondary names    ",
"    1.69 930616 FB MPW stop at 'DESCRIPTION'                      ",
"    1.70 930618 FB 411 help put undotted key first                ",
"    1.71 930820 FB -t9 PreText/sort context by type/-t10 index    ",
"    1.72 930825 FB description parsing dangling pointer(olds) fix ",
"    1.73 930919 FB Quote @ literals for PreText/header - if text  ",
"    1.74 930920 FB Sort PreText by header.  Sort context longer   ",
"    1.75 931020 FB -t11 SGI 'man' format                          ",
"    1.76 931021 FB SGI man files dump sep file with full name     ",
"    1.77 931022 FB SGI man return value bold                      ",
"    1.78 931105 FB save fixed for 411 help (SGI version broke it) ",
"    1.79 931112 FB truncate QuickHelp topics to 32k               ",
"    1.80 931123 FB putc take int to make SGI happy                ",
"    1.81 931124 FB IBM changed to EAC                             ",
"    1.82 940118 FB -t12 Unsorted Index                            ",
"    1.83 940225 FB HelpPC limit to 16384 bytes and add \n if cut  ",
"    1.84 940325 FB QuickHelp limit to 32000 bytes                 ",
"    1.85 950403 FB -c catagory                                    ",
"    1.86 950511 FB html output                                    ",
"    1.87 950515 FB html add back.gif for 1.1 backgrounds          ",
"    1.88 951003 FB spit 2.5 update                                ",
"    1.89 951022 FB HTML index                                     ",
"    1.90 951023 FB HTML index include catagory headings           ",
"    1.91 951030 FB . every 16, xref secondary, NLs, -pprefix file ",
"    1.92 951102 FB fix < and > for html                           ",
"    1.93 951103 FB remove blank lines for condensed HTML          ",
"    1.94 951104 FB remove dup headings                            ",
"    1.95 951107 FB -i to ignore case for -r; keep case in context ",
"    1.96 951109 FB default prefix use toolbar.gif/.map            ",
"    1.97 951110 FB get HTML name from after </H4> NAME lowercase  ",
"    1.98 951112 FB prefix NetScape friendly                       ",
"    1.99 951122 FB strip // from start of lines                   ",
"    2.00 951124 FB gimex abstract; default to html                ",
"    2.01 951126 FB dont treat empty lines like underlines         ",
"    2.02 951206 FB parse stock ticker for web page                ",
"    2.03 951211 FB -c<cymbal> file                                ",
"    2.04 951212 FB format cymbal                                  ",
"    2.05 951213 FB support .o for sgi cym files                   ",
"    2.06 960119 FB stock link                                     ",
"    2.06 960120 FB quote >> and <<                                ",
"    2.07 960124 FB many secondary names,-l for linked headings    ",
"    2.08 960201 FB allow silent primary names                     ",
"    2.09 960201 FB & end quote only if current character quoted   ",
"    2.10 960227 FB alt fields                                     ",
"    2.11 960305 FB correct category heading links to overviews    ",
"    2.12 960305 FB html labels to category headings               ",
"    2.13 960411 FB sort html indexes                              ",
"    2.14 960627 FB use kevins hash functions for cross reference  ",
"    2.15 960628 FB shorter hash function                          ",
"    2.16 960706 FB index overviews, malloc check                  ",
"    2.17 960723 FB crossref ignore trailing period                ",
"    2.18 960731 FB crossref HTML input files (no abstracts)       ",
"    2.19 960818 FB title html                                     ",
"    2.20 960822 FB dont xref headings                             ",
"    2.21 960905 FB heading for SOURCE                             ",
"    2.22 960905 KW embeded HTML markups                           ",
"    2.23 960910 FB special symbols (128..255) for HTML            ",
"    2.24 961030 KW sorted HTML indeces                            ",
"    2.25 970114 FB renamed raw index to cross reference           ",
"    2.26 970203 FB category,rating                                ",
"    2.27 970523 KW fixed cross ref within HTML link               ",
"    2.28 970928 FB added 3rash headings                           ",
"    2.29 971027 KW added -l2 heading link                         ",
"    2.30 971031 FB allow number in word for xref 3rash            ",
"    2.31 971124 KW -l2 heading link bug fix                       ",
"    2.32 980416 KW added HTML Help content and index files        ",
"    2.33 980506 KW added OPTlinewidth and OPTlineindent           ",
"    2.34 980520 KW added abstract type TYPEEXAMPLE                ",
"    2.35 980522 KW no longer removes C-comments within abstract   ",
"    2.36 980618 KW fixed .txt option, added OPTasis               ",
"    2.37 980619 KW -OPTkeepcomments keeps comments in abstracts   ",
"    2.38 980730 KW -OPTfullname.  -l3 headerless HTML index       ",
"    2.39 980910 KW -l4 option for no icons & link to overview     ",
"    2.40 980930 KW changed TYPEHH output to not refer to lib dir  ",
"    2.41 981006 FB -r 3rd field is alt.                           ",
"    2.42 981014 KW fixed link popup to correctly place quotes     ",
"    2.43 981019 KW added TYPEHHCONTENTFLAT and TYPEHHINDEXFLAT    ",
"    2.44 981020 FB bumped max abstract to 256k for frapi          ",
"    2.45 981021 FB keep comments default. -k0 to disable          ",
"    2.46 981105 KW -l5 option for no icons&link to local overview ",
"    2.47 981119 KW fixed infinite looping bug with TYPEHTMLNOABS  ",
"    2.48 990108 KW fixed title= tag with double quotes            ",
"    2.49 990122 KW added author info, bold obselete functions     ",
"    2.50 990125 KW renamed AUTHOR heading to CONTACT, added email ",
"    2.51 990201 KW increased abs size limits                      ",
"    2.52 990209 KW added partial support for C++-style abstracts  ",
"    2.53 990212 KW added full support for C++-style abstracts     ",
"    2.54 990215 KW added parsing of http and ftp references       ",
"    2.55 990215 KW for http and ftp links, make target=_top       ",
"    2.56 990309 KW C++-style abstracts: removed full classpath    ",
"    2.57 990310 KW added -z option: HTML font size                ",
"    2.58 990407 FB added TIP heading for 3rash                    ",
"    2.59 990714 KW removed platform name from hhc & hhk files     ",
"    2.60 990716 KW fixed infinite loop with '>' char in -t18 mode ",
"    2.61 990827 KW added header file index to hhc output          ",
"    2.62 990827 KW added -l3 no overviews to HHC output           ",
"    2.63 990830 KW removed prefixes to HHC output                 ",
"    2.64 990901 KW OPTasis, add file extension to abstract name   ",
"    2.65 990917 KW multiple primary refs now seperate abstracts   ",
"    2.66 990921 KW added suffix file option                       ",
"    2.67 990924 KW crossreferencenoabs - skip existing HTML links ",
"    2.68 990928 KW generate link to overview under SEE ALSO       ",
"    2.69 991020 KW fixed problem with secondary ref parsing       ",
"    2.70 991022 KW fixed xref uppercase & skipping 2 lines        ",
"    2.71 991117 KW fixed <i><b> titles, added http/ftp/mail refs  ",
"    2.72 991119 KW fixed links having multiple .htm suffixes      ",
"    2.73 991123 KW removed hardcoded ../functions from link       ",
"    2.74 991124 KW remove .htm suffix from -t18 xrefs             ",
"    2.75 991124 KW fixed hhc generating early </UL>               ",
"    2.76 991129 FB 2 word cross reference                         ",
"    2.77 991209 FB -gglossary same as -r                          ",
"    2.78 991210 FB glossary use style sheet, bumped xref space    ",
"    2.79 000105 KW fixed glossary crossref                        ",
"    2.80 000105 KW fixed glossary refs overwriting xrefs          ",
"    2.81 000107 KW added purging of hash table                    ",
"    2.82 000111 KW crossreferencenoabs, hash glossary             ",
"    2.83 000121 FB crossref to html as is, gimex headings         ",
"    2.84 000301 FB line count                                     ",
"    2.85 000307 FB only first word glossary link                  ",
"    2.86 000308 KW ABSTRACT only detected if first word           ",
"    2.87 000310 KW added '_' char as valid abs name               ",
"    2.88 000310 KW fixed sorting when only one category exists    ",
"    2.89 000413 KW fixed sorting of xref file                     ",
"    2.90 000423 FB .h for heading (section, author, rating)       ",
"    2.91 000525 FB volatile on some arrays                        ",
"    2.92 000601 KW close with proper number of </UL> for hhc files",
"    2.93 000901 FB removed volatile                               ",
"    2.94 001020 KW open http: ftp: mailto: links in new window    ",
"    2.95 001214 FB </PRE><H4>title</H4><PRE>                      ",
"    2.96 010128 KW fixed crash bug when generating terse index    ",
"    2.97 010202 KW fixed to properly skip <a>...</a> tags         ",
"    2.98 010213 KW fixed to skip <a>...</a> tags in abstracts     ",
"    2.99 010214 KW fixed cymbal info not being included           ",
"    3.00 010418 KW added -e option for error output file          ",
"    3.01 010419 KW added external example check and author to errs",
"    3.02 010503 FB crlf output                                    ",
"    3.03 010504 KW more specific example errors                   ",
"    3.04 010516 KW fixed HTML tag bug of extra '<'                ",
"    3.05 010518 FB -opera to add a space to end of line           ",
"    3.06 010522 FB -opera reimplemented                           ",
"    3.07 010522 KW fixed extra <PRE> with -t14                    ",
"    3.08 010525 FB FILE FORMATS & TYPES headings for gimex tools  ",
"    3.09 010530 KW added EXAMPLES OVERVIEW, EXAMPLES INDEX to egs ",
"    3.10 010601 FB SAMPLE OUTPUT heading                          ",
"    3.11 010917 FB optimize on for intel c                        ",
"    3.12 010926 KW crossreference: skip HMTL header               ",
"    3.13 010926 KW added OPTlibraryname                           ",
"    3.14 010927 KW fixed parse bug with getfullnamefromman        ",
"    3.15 011002 FB OPTIONS heading for tags tool                  ",
"    3.16 011015 FB terse author                                   ",
"    3.17 011018 KW fixed missing </UL> with HHC files             ",
"    3.18 011019 KW fixed glossary links                           ",
"    3.19 011031 KW removed DEMOS LISTING from EXAMPLE section     ",
"    3.20 011122 KW fixed extra line feed in CONTACT e-mail        ",
"    3.21 011123 KW example links feed abstract name for hiliting  ",
"    3.22 011127 KW cymbal info - match library                    ",
"    3.23 011212 KW added source file when generating abstracts    ",
"    3.24 020125 KW removed xref of words inside HMTL tags         ",
"    3.25 020305 FB sort dont set absn                             ",
"    3.26 020401 KW mailto author fills in body w/ template fields ",
"    3.27 031020 FB isalnum utf8 and sort off end of list check    ",
"    3.28 050206 FB strip # from perl comments & // from C++       ",
"    3.29 060622 FB dot options explicitely enabled                ",
"                                                                  ",
"------------------------------------------------------------------",
"\0"
};

/****************************************************************/
/*  Spit Setup                                                  */
/****************************************************************/

#if defined(_MSC_VER) && _MSC_VER<1400
#pragma optimize("g", off)
#endif

#include "spit.h"
#include "hash.h"

const char TextVersion[]="3.29b (Samba) 2007.12.4";
#define TOOL_VERSION 329
#define TOOL_NAME "abstract"

#define TYPEDOC         0
#define TYPEMSHLP       1
#define TYPEMACHLP      2
#define TYPEMPWHLP      3
#define TYPESTHLP       4
#define TYPEABS         5
#define TYPEBRIEFSUM    6
#define TYPEBRIEFNOSUM  7
#define TYPEHELPPC      8
#define TYPEPRETEXT     9
#define TYPEINDEX       10
#define TYPEUSINDEX     11
#define TYPESGIMAN      12
#define TYPEHTML        13
#define TYPEHTMLINDEX   14
#define TYPEXREF        15
#define TYPETERSEHINDEX 16
#define TYPETICKER      17
#define TYPEHTMLNOABS   18
#define TYPEHHCONTENT   19
#define TYPEHHINDEX     20
#define TYPEEXAMPLE     21
#define TYPEHHCONTENTFLAT 22
#define TYPEHHINDEXFLAT   23
#define TYPEHTMLINDEXTREE 24

#define LANGUAGEC       0
#define LANGUAGECPP     1

#define MAXABSS         4096
#define MAXSECS         256

#define COLWIDTH        22
#define COLSPERLINE     4

#define ABSTYPEMETHOD   0
#define ABSTYPECLASS    1
#define ABSTYPEDATA     2
#define ABSTYPEFILE     3

#define ABSERR_NONE     0
#define ABSERR_GENERIC  1
#define ABSERR_NOENDABS 2

int  OPTcatagory;
int  OPTabstype;
int  OPTabsperfile;
int  OPTignorecase;
int  OPTlinkhead;
char OPTnl[8];
SPITMEM OPTcrossreffile;
SPITMEM OPTglossaryfile;
SPITMEM OPTprefixfile;
SPITMEM OPTsuffixfile;
SPITMEM OPTcymbalfile;
SPITMEM OPTauthorfile;
FILE *OPTerrorfile;
char OPTplatformname[80];
char OPTlibraryname[80];
int  OPTlinewidth;
int  OPTlineindent;
int  OPTkeepcomments;
int  OPTfullname;
int  OPTsrclanguage;
int  OPTfontsize;
int  OPTopera;
int  OPTasis;

int  ABSerr;
HASH *xlinkhasher = 0;
HASH *glinkhasher = 0;

/****************************************************************/
/*  Global Vars                                                 */
/****************************************************************/

char stmpwchr[4];
int  dynan;
SPITMEM dynamem[1024];
char *abslist[MAXABSS];
char *dstart;
int  absn;
int abslen;
int abslinecount;
char catagory[SPITMAXLINE];
char previouscatagory[SPITMAXLINE];
char previousheading[SPITMAXLINE];
char moldyheading[SPITMAXLINE];
char rating[SPITMAXLINE];
char authorinitial[SPITMAXLINE];
int  newcatagory;
int  absnstart, absnend;
int  levelnum;

/****************************************************************/
/*  Function Prototypes (for ANSI compilers)                    */
/****************************************************************/

#define SPIT_ptrdif(s,d) (int)((char *)(d)-(char *)(s))

/****************************************************************/
/*  Put a string to dest                                        */
/****************************************************************/

#define ABSSTYLEBOLD  1
#define ABSSTYLEUPPER 0

int ABSstyle=0;
int isbold=0;

static char *ABSputc(char *d,int c)
{
    if (ABSstyle&ABSSTYLEUPPER)
        c = toupper(c);

    if ((ABSstyle&ABSSTYLEBOLD) && c>=' ')
    {
        if (OPTabstype==TYPEHTML)
        {
            if (!isbold)
            {
                strcpy(d,"</PRE><H4>");
                d += strlen(d);
                isbold = 1;
            }
            *d++ = (char) c;
        }
        else if (OPTabstype==TYPEEXAMPLE)
        {
            *d++ = (char) c;
        }
        else
        {
            *d++ = (char) c;
            *d++ = (char) 8;
            *d++ = (char) c;
            *d++ = (char) 8;
            *d++ = (char) c;
            *d++ = (char) 8;
            *d++ = (char) c;
        }

    }
    else
    {
        if (isbold)
        {
            if (OPTabstype==TYPEHTML)
            {
                strcpy(d,"</H4><PRE>");
                d += strlen(d);
            }
            isbold = 0;
        }

        *d++ = (char) c;
    }

    return(d);
}

static char *ABSputs(char *d,char *s)
{
    while (*s)
    {
        if (*s==(char)10)
        {
            ++s;
            if (*s==(char)13)
                ++s;

//            d = ABSputc(d,13);
            d = ABSputc(d,10);
        }
        else if (*s==(char)13)
        {
            ++s;
            if (*s==(char)10)
                ++s;

//            d = ABSputc(d,13);
            d = ABSputc(d,10);
        }
        else
            d = ABSputc(d,(int)*s++);
    }

    return(d);
}

/* ABSstrips takes a string and strips away non-alphanumeric characters,  */
/* compressing the valid characters together */
/* mode 0 - strips all non-alphanumeric characters */
/* mode 1 - strips non-alphanumeric characters from end */
/* mode 2 - strips away leading classpath */

static char *ABSstrips(char *d,char *s,int mode)
{
    if(mode==0)
    {
        do
        {
            if(isalnum(*s) || *s=='_')
                *d++ = *s++;
            else
                s++;
        }
        while(*s);
        *d = '\0';
    }
    else if(mode==1)
    {
        strcpy(d,s);
        d += strlen(d)-1;
        while(!isalnum(*d) && *d!='_')
            d--;
        *(d+1) = '\0';
    }
    else if(mode==2)
    {
        char    *sptr;
        sptr = s + strlen(s)-1;
        while(!(isalnum(*sptr) || *sptr=='_' || *sptr=='.') && sptr>=s)
            sptr--;
        while((isalnum(*sptr) || *sptr=='_' || *sptr=='.') && sptr>=s)
            sptr--;
        sptr++;
        strcpy(d,sptr);
    }

    return(d);
}


/****************************************************************/
/*  Reserve memory for next abstract                            */
/****************************************************************/

#define BLOCKMAX 600*1024L
#define ABSMAX   512*1024L

static char *openabstract(char *d,int flen,int verbose)
{
    char *memlim;
    int thresh;
    int scaledflen;
    int  mkblock;

    if (OPTverbose>=6)
    {
        printf("starting openabstract(%d)\n",flen);
        SPIT_flush();
    }

    scaledflen = flen*2+8192;
    thresh = ABSMAX;
    if (thresh < scaledflen)
        thresh = scaledflen;

    mkblock = SPITYES;
    if (d)
    {
        memlim = dynamem[dynan-1].ptr + dynamem[dynan-1].len - thresh;
        if (d<memlim)
            mkblock = SPITNO;
    }
    if (mkblock)
    {
        d = SPIT_alloc(&dynamem[dynan], BLOCKMAX);
        if (d)
        {
            ++dynan;
            *d++ = 0;   /* so abstract can backtrack and stop at 0 */
        }
        else
        {
            if (verbose>=2)
                fprintf(OPTerrorfile, "ERROR allocating memory for abstract\n");
            exit(1000);
        }
    }

    if (OPTverbose>=6)
    {
        printf("ending openabstract returning pointer %lx\n",d);
        SPIT_flush();
    }

    return(d);
}

/****************************************************************/
/*  Close abstract                                              */
/****************************************************************/

static char *closeabstract(char *d)
{
    return(d);
}

static char *ABSstrstr(char *s, char *str)
{
    int l=strlen(str);

    do
    {
        s = strchr(s,*str);
        if (!s)
            return((char *)0);

        if (!strncmp(s,str,l))
            return(s);
        s += 1;

    } while (*s);
    return((char *)0);
}

static char *ABSstrstri(char *s, char *str)    /* case-independent substring search */
{
    int l=strlen(str);

    do
    {
        s = strchr(s,tolower((int)*str));
        if (!s)
            return((char *)0);

        if (!strnicmp(s,str,l))
            return(s);
        s += 1;

    } while (*s);
    return((char *)0);
}


/****************************************************************/
/*  Parse HTML line of ticker tape into new form                */
/****************************************************************/

/* Source: */
/* Symbol: <B>ERTS<\B> Price: <B>  22 3\4  <\B> Change: <B><font color=#ff0000>  -1 */
/*  1\8  <\font><\B><br> */
/*  High: <B>  24      <\B> Low: <B>  22 1\2  <\B><br> */
/*  Bid: <B>  22 3\4  <\B>  Ask: <B>  22 7\8  <\B><br> */
/*  Previous: <B>  23 7\8  <\B><br> */
/*  Volume: <B>742,800<\B><br> */

/* dest:    ERTS 951206 7:07pm Last 29 1\2 Change <font color=#ff0000> -0 3\8 <\font>Prev 29 7\8 High 30 1\4 Low 29 1\2 Volume 530,700 */
/* look for <B> */


/* old source:  <TR align=right><TD align=left>ERTS<\TD><TD>  29 1\2  <\TD><TD><font color=#ff0000>  -0 3\8  <\font><\TD><TD>  29 7\8  <\TD><TD>  30 1\4  <\TD><TD>  29 1\2  <\TD><TD>     530,700<\TD><\TR> */
/* look for <\TD><TD> */

static char *findnth(char *str, char *search, int n)
{
    char *s=str;
    char *next;

    while (n--)
    {
        if (!strncmp(s,search,strlen(search)))
            next = ABSstrstr(s+strlen(search),search);
        else
            next = ABSstrstr(s,search);
        if (next)
            s = next;
    }
    return(s);
}

static char *findtbls(char *str, int n)
{
    return(findnth(str,"<B>",n+1));
}

static char *findtble(char *str, int n)
{
    return(findnth(str,"</B>",n+1));
}


static char *formatfield(char *d, char *s, char *s2)
{
    int setfont=0;

    s += strlen("<B>");
    if (*s=='<')
    {
        while (*s && *s!='>')
            *d++ = *s++;
        *d++ = *s++;
        setfont=1;
        s2 -= strlen("</font>");
    }
    while (*s==' ') /* find start of number */
        ++s;
    while (*(s2-1)==' ')    /* find end of number */
        --s2;

    while (*s && s<s2)
        *d++ = *s++;
    if (setfont)
    {
        strcpy(d,"</font>");
        d += strlen("</font>");
    }
    *d = 0;
    return(d);
}

static char *ABSparsetickerline(char *dest,char *source)
{
    char *s;
    char *s2;
    char *d;
    char linebuf[SPITMAXLINE];

    d=linebuf;
    strcpy(d,"<A HREF=\"stock/index.htm\">");
    d += strlen(d);

    /* symbol */
    s = findtbls(source,0);
    strncpy(d,s+3,4);
    d += 4;

    strcpy(d,"</A> ");
    d += strlen(d);

    /* date\time... */

    {
        time_t timebuf;
        time_t timeval;
        struct tm *t;

        timeval = time(&timebuf);
        t = localtime(&timeval);

        sprintf(d,"%02d%02d%02d %d:%02d%s",
            t->tm_year,
            t->tm_mon+1,
            t->tm_mday,

            t->tm_hour%12 ? t->tm_hour%12 : 12,
            t->tm_min,
            t->tm_hour<12?"am":"pm");
        d += strlen(d);
    }

    /* last */

    strcpy(d," <b>Last ");  d += strlen(d);
    s  = findtbls(source,1);
    s2 = findtble(source,1);
    d = formatfield(d,s,s2);

    /* change */

    strcpy(d,"</b> Change ");  d += strlen(d);
    s  = findtbls(source,2);
    s2 = findtble(source,2);
    d = formatfield(d,s,s2);

    /* prev */

    strcpy(d," Prev ");  d += strlen(d);
    s  = findtbls(source,7);
    s2 = findtble(source,7);
    d = formatfield(d,s,s2);

    /* high */

    strcpy(d," High ");  d += strlen(d);
    s  = findtbls(source,3);
    s2 = findtble(source,3);
    d = formatfield(d,s,s2);

    /* low */

    strcpy(d," Low ");  d += strlen(d);
    s  = findtbls(source,4);
    s2 = findtble(source,4);
    d = formatfield(d,s,s2);

    /* volume */

    strcpy(d," Volume ");  d += strlen(d);
    s  = findtbls(source,8);
    s2 = findtble(source,8);
    d = formatfield(d,s,s2);
    *d = 0;
    strcpy(dest,linebuf);
    return(dest);
}

/****************************************************************/
/*  Put a Header on Abstract                                    */
/****************************************************************/

char msline[]=
{
    '\304','\304','\304','\304','\304','\304','\304','\304','\304','\304',
    '\304','\304','\304','\304','\304','\304','\304','\304','\304','\304',
    '\304','\304','\304','\304','\304','\304','\304','\304','\304','\304',
    '\304','\304','\304','\304','\304','\304','\304','\304','\304','\304',
    '\304','\304','\304','\304','\304','\304','\304','\304','\304','\304',
    '\304','\304','\304','\304','\304','\304','\304','\304','\304','\304',
    '\304','\304','\304','\304','\304','\304','\304','\304','\304','\304',
    '\304','\304','\304','\304','\304','\304',0
};

/* go to next line */
static char *nextline(char *s)
{
    /* go to end of current line */
    while (*s && *s!=(char)13 && *s!=(char)10)
        s++;
    if(*s)
    /* skip past EOL stuff */
    if(*s==(char)13)
        s++;
    if(*s==(char)10)
        s++;
    return(s);
}

/* parse abstract header for abstract names and descriptions */
/* if a primary abstract, name is placed into primarybuf */
/* if a secondary abstract, name is placed into secondarybuf */
/* if no abstract name to parse, all return strings are untouched */
/* returns pointer past char it last parsed */
/* primindent - number of spaces that primary abstract names are indented */
static char *parseheader(char *s,int primindent,char *primarybuf,char *primarynodotbuf,char *descriptionbuf,char *secondarybuf)
{
    char *t,*namebuf;
    char *secondlinestart,*olds;
    int  issec=0;
    int  secindent;
    int  moredesc;

    /* scan to reference name */
    while(!isalnum(*s) && *s!='_' && *s!='@' && *s!=(char)13 && *s!=(char)10 && *s!=(char)'\0')
    {
        ++s;
    }
    if (*s=='@')    // tag for secondary references
    {
        issec = 1;
        ++s;
    }

    if(*s==(char)13 || *s==(char)10 || *s==(char)'\0')
    {
        /* no alpha-numeric found on this line */
        return(++s);
    }

    if(!issec)
        t = primarybuf;
    else
        t = secondarybuf;
    namebuf = t;

    /* get abstract name */

    if(OPTsrclanguage!=LANGUAGECPP && !OPTfullname)
        while (*s>' ' && *s!=(char)'(' && *s!=(char)':' &&  *s!=(char)'!' && *s!=(char)'?' && *s!=(char)',' && *s!=(char)'/' && *s!=(char)'*')
            *t++ = *s++;
    else
        while (*s>' ' && *s!=(char)'!' && *s!=(char)'?' && *s!=(char)',' && *s!=(char)'/' && *s!=(char)'*')
            *t++ = *s++;
    *t++='\0';

    /* skip to next line if a secondary reference */
    if(issec)
    {
        s = nextline(s);
        return(s);
    }

    /* get primary abstract name without period or hyphen */
    if(primarybuf[0])
    {
        strcpy(primarynodotbuf,primarybuf);
        if(OPTsrclanguage!=LANGUAGECPP && !OPTfullname)
        {
            t = strchr(primarynodotbuf,'.');
            if (t)
            {
                *t++ = (char) 0;
            }
        }
    }

    /*  Find Description That Follows Name */
    while (*s && *s!=(char)13 && *s!=(char)10)
    {
        if (*s=='-' && (*(s+1)==' ' || *(s+1)=='\t'))
        {
            while (*s && *s!=(char)10 && *s!=(char)13 && !(isalnum(*s)))   /* find first alphanumeric on line */
                ++s;

            t = descriptionbuf;
            while (*s && *s!=(char)13 && *s!=(char)10 && strncmp(s,"*/",2))
            {
                if (*s<=' ')    /* replace any white spaces with 1 space */
                {
                    *t = ' ';
                    if (*(s-1)>' ')
                        ++t;
                    ++s;
                }
                else if (*s=='"')    /* replace any double quotes with single quotes (wreaks havoc with HTML tags) */
                {
                    *t = '\'';
                    ++t; ++s;
                }
                else
                    *t++ = *s++;
            }
            if (*s==(char)10)
            {
                ++s;
                if (*s==(char)13)
                    ++s;
            }
            else
            {
                if (*s==(char)13)
                {
                    ++s;
                    if (*s==(char)10)
                        ++s;
                }
            }

            /* do a second line of description if indented more then end of abstract name */

            secondlinestart = s;
            while (*s && *s!=(char)10 && *s!=(char)13 && !(isalnum(*s)))   /* find first alphanumeric on line */
            {
                ++s;
            }
            olds = secondlinestart;

            secindent = (int) (s-secondlinestart);
            if (secindent==primindent)  /* this line is indented the same as previous line - must be a new reference */
                moredesc = 0;
            else if (secindent>primindent)  /* this line is indented more than previous line, must be a second line of description*/
                moredesc = 1;
            else
                moredesc = 0;

            if (moredesc)
            {
                *t++ = ' ';
                while (*s && *s!=(char)13 && *s!=(char)10 && strncmp(s,"*/",2))
                {
                    if (*s<=' ')    /* replace any white spaces with 1 space */
                    {
                        *t = ' ';
                        if (*(s-1)>' ')
                            ++t;
                        ++s;
                    }
                    else
                        *t++ = *s++;
                }
                *t = (char) 0;
            }
            else
            {
                *t = (char) 0;
                s = secondlinestart;
                return(s);
            }
        }
        ++s;
    }
    return(s);
}

/* header  - get abstract header information - reference names and descriptions */
/* numprim - return value.  Number of primary references in abstract. */
/*           If more than one, should call this function again for subsequent refs using getprim */
/* getprim - get the additional references.  0=1st primary reference. */
static char *header(char *dateptr,char *fnameptr,char *s,char *d,int abstype,int linecount,int *numprim, int getprim)
{
    int  primindent;
    int  i;
    int  nprim; /* number of primaries */
    int  nsec;  /* number of secondaries */
    char *primarylinestart;
    char (*primarybuf)[MAXSECS][SPITMAXLINE];
    char (*descriptionbuf)[MAXSECS][SPITMAXLINE];
    char (*secondarybuf)[MAXSECS][SPITMAXLINE];
    char (*primarynodotbuf)[MAXSECS][SPITMAXLINE];
    char *primary,*description,*primarynodot;
    char strippedprimarynodot0[SPITMAXLINE];
    char strippedprimarynodot1[SPITMAXLINE];
    char strippedprimarynodot2[SPITMAXLINE];
    char headerbuf[SPITMAXLINE];
    char stampbuf[SPITMAXLINE];
    int  parsecompleted;

    primarybuf      = (char (*)[MAXSECS][SPITMAXLINE]) galloc(MAXSECS*SPITMAXLINE);
    descriptionbuf  = (char (*)[MAXSECS][SPITMAXLINE]) galloc(MAXSECS*SPITMAXLINE);
    secondarybuf    = (char (*)[MAXSECS][SPITMAXLINE]) galloc(MAXSECS*SPITMAXLINE);
    primarynodotbuf = (char (*)[MAXSECS][SPITMAXLINE]) galloc(MAXSECS*SPITMAXLINE);

    /****************************************************************/
    /*  Find Abstract Names                                         */
    /****************************************************************/

    /* first skip line that opened abstract */

    s = nextline(s);

    /* then find first line with alpha-numeric chars (can be several lines down) */

    primarylinestart = s;
    while ((*s<'0'||(*s>'9'&&*s<'A')) && *s!=(char)'\0')
    {
        if (*s==(char)13 || *s==(char)10)
        {
            primarylinestart = s+1;
        }
        ++s;
    }
    primindent = (int) (s-primarylinestart);

    /* get abstract names, descriptions */
    nprim = 0;
    nsec = 0;
    parsecompleted = 0;
    do
    {
        (*primarybuf)[nprim][0]        = (char)0;
        (*descriptionbuf)[nprim][0]    = (char)0;
        (*secondarybuf)[nsec][0]       = (char)0;
        s = parseheader(s,primindent,(*primarybuf)[nprim],(*primarynodotbuf)[nprim],(*descriptionbuf)[nprim],(*secondarybuf)[nsec]);
        if(!(*primarybuf)[nprim][0] && !(*secondarybuf)[nsec][0]) // nothing to parse
            parsecompleted=1;
        if((*primarybuf)[nprim][0]) nprim++;
        if((*secondarybuf)[nsec][0]) nsec++;
    }
    while(!parsecompleted);


    /****************************************************************/
    /*  Output header based on output type                          */
    /****************************************************************/

    primary      = (*primarybuf)[getprim];
    description  = (*descriptionbuf)[getprim];
    primarynodot = (*primarynodotbuf)[getprim];

    /* start header and primary name */

    if (abstype==TYPEDOC)                                       /* midl.doc format header */
    {
        SPIT_getname( stampbuf,fnameptr);
        sprintf(headerbuf,"%-40s%s",dateptr,stampbuf);
        d = ABSputs(d,headerbuf);
        d = ABSputs(d,OPTnl);
        d = ABSputs(d,OPTnl);
    }
    else if (abstype==TYPEPRETEXT)                              /* pretext doc for PS printing */
    {
        SPIT_getname( stampbuf,fnameptr);
        sprintf(headerbuf,"@header %s@%-40s%s",primary,dateptr,stampbuf);
        d = ABSputs(d,headerbuf);
        d = ABSputs(d,OPTnl);
        d = ABSputs(d,OPTnl);
    }
    else if (abstype==TYPESGIMAN)                               /* sgi manual header */
    {
        d = ABSputs(d,OPTnl);
        d = ABSputs(d,OPTnl);
        d = ABSputs(d,OPTnl);
        ABSstyle = ABSSTYLEBOLD|ABSSTYLEUPPER;
        strcpy(stampbuf,primary);
        strcat(stampbuf,"(1)");
        sprintf(headerbuf,"%-31s",stampbuf);
        d = ABSputs(d,headerbuf);
        ABSstyle = ABSSTYLEBOLD;
        d = ABSputs(d,"Electronic Arts ");
        ABSstyle = ABSSTYLEBOLD|ABSSTYLEUPPER;
        sprintf(headerbuf,"%31s",stampbuf);
        d = ABSputs(d,headerbuf);
        d = ABSputs(d,OPTnl);
        d = ABSputs(d,OPTnl);
        d = ABSputs(d,OPTnl);
        d = ABSputs(d,OPTnl);
        ABSstyle = ABSSTYLEBOLD;
        d = ABSputs(d,"NAME");
        ABSstyle = 0;
    }
    else if (abstype==TYPEHTML)
    {
        ABSstyle = ABSSTYLEUPPER;
        if (OPTprefixfile.ptr)
        {
            strcpy(d,OPTprefixfile.ptr);
        }
        else
        {
            strcpy(d,"<BODY BGCOLOR=#FFFFFF TEXT=#000000 LINK=#000066 VLINK=#808080 ALINK=#FF0000>");
        }
        d += strlen(d);
        sprintf(headerbuf,"<title>%s</title>",primary);
        d = ABSputs(d,headerbuf);
        if (OPTfontsize)
            sprintf(headerbuf,"<H1>%s</H1><PRE><FONT SIZE=%d><PRE>",primary,OPTfontsize);
        else
            sprintf(headerbuf,"<H1>%s</H1><PRE>",primary);
        d = ABSputs(d,headerbuf);
        ABSstyle = ABSSTYLEBOLD;
        d = ABSputs(d,"NAME");
        d = ABSputs(d,OPTnl);
        ABSstyle = 0;
    }
    else if (abstype==TYPEBRIEFSUM || abstype==TYPEBRIEFNOSUM)  /* brief doc format header */
    {
        SPIT_getname( stampbuf,fnameptr);
        sprintf(headerbuf,"*** %s.%d",stampbuf,linecount);
        d = ABSputs(d,headerbuf);
        d = ABSputs(d,OPTnl);
    }
    else if (abstype==TYPEINDEX || abstype==TYPEUSINDEX)  /* index file */
    {
        if (description[0])
            sprintf(headerbuf,"%-18s- %s",primarynodot,description);
        else
            sprintf(headerbuf,"%-18s",primarynodot);
        d = ABSputs(d,headerbuf);
        d = ABSputs(d,OPTnl);
    }
    else if (abstype==TYPEXREF)  /* index file */
    {
        if(OPTsrclanguage==LANGUAGECPP || OPTfullname)
        {
            ABSstrips(strippedprimarynodot1,primarynodot,1);
            ABSstrips(strippedprimarynodot0,(*primarynodotbuf)[0],0);   // (*primarynodotbuf)[0] because addition primary refs should always link to first primary ref
            sprintf(headerbuf,"%s,%s,%s",strippedprimarynodot1,strippedprimarynodot0,description);
        }
        else
        {
            sprintf(headerbuf,"%s,%s,%s",primarynodot,(*primarynodotbuf)[0],description);   // (*primarynodotbuf)[0] because addition primary refs should always link to first primary ref
        }
        d = ABSputs(d,headerbuf);
        d = ABSputs(d,OPTnl);
    }
    else if (abstype==TYPEHTMLINDEX)        /* html index file */
    {
        if (catagory[0] && strcmp(catagory,previouscatagory))
        {
            /* start a new category */
            strcpy(previouscatagory,catagory);
            absnend = absn;
            newcatagory = SPITYES;
        }
        if (strcmp(previousheading,primarynodot) && strcmp(moldyheading,primarynodot))
        {
            /* write header */
            if(catagory[0])
            {
                char libcatagory[SPITMAXLINE];

                if (OPTlibraryname[0])
                    sprintf(libcatagory, "%s_%s", OPTlibraryname, catagory);
                else
                    strcpy(libcatagory, catagory);

                switch(OPTlinkhead)
                {
                    case 1:
                        sprintf(headerbuf,"</PRE><H3><A NAME=\"%s\"></A><A HREF=\"../overview/%s.htm\" title=\"%s Overview\"><IMG SRC=\"%s.gif\" ALT=\"%s Overview\" ALIGN=\"MIDDLE\" border=0>%s</A></H3><PRE>",catagory,libcatagory,catagory,catagory,catagory,catagory);
                        break;
                    case 2:
                        sprintf(headerbuf,"</PRE><H3><A NAME=\"%s\"></A><A HREF=\"../../overview/%s.htm\" title=\"%s Overview\"><IMG SRC=\"%s.gif\" ALT=\"%s Overview\" ALIGN=\"MIDDLE\" border=0>%s</A></H3><PRE>",catagory,libcatagory,catagory,catagory,catagory,catagory);
                        break;
                    case 3:         /* no header */
                        sprintf(headerbuf,"");
                        break;
                    case 4:
                        sprintf(headerbuf,"</PRE><H3><A NAME=\"%s\"></A><A HREF=\"../overview/%s.htm\" title=\"%s Overview\">%s</A></H3><PRE>",catagory,libcatagory,catagory,catagory);
                        break;
                    case 5:
                        sprintf(headerbuf,"</PRE><H3><A NAME=\"%s\"></A><A HREF=\"%s.htm\" title=\"%s Overview\">%s</A></H3><PRE>",catagory,libcatagory,catagory,catagory);
                        break;
                    default:
                        sprintf(headerbuf,"</PRE><H3><A NAME=\"%s\"></A>%s</H3><PRE>",catagory,catagory);
                        break;
                }
                d = ABSputs(d,headerbuf);
            }

            /* start a new abstract */
            strcpy(moldyheading,previousheading);
            strcpy(previousheading,primarynodot);

            if(OPTauthorfile.ptr)   /* add author's initials */
            {
                sprintf(headerbuf,"[%s] ",authorinitial);
                d = ABSputs(d,headerbuf);
            }

            /* (*primarynodotbuf)[0] is used because we always want to link to the first primary reference */
            if(OPTsrclanguage==LANGUAGECPP || OPTfullname)
                ABSstrips(strippedprimarynodot0,(*primarynodotbuf)[0],0);
            else
                strcpy(strippedprimarynodot0,(*primarynodotbuf)[0]);
            if(rating[0]=='1')  /* make obsolete function names BOLDED */
            {
                if(OPTfullname)
                    sprintf(headerbuf,"<a href=\"%s.htm\" title=\"%s\"><b>%s</b></a>",strippedprimarynodot0,description,primary);
                else
                    sprintf(headerbuf,"<a href=\"%s.htm\" title=\"%s\"><b>%s</b></a>",strippedprimarynodot0,description,primarynodot);
            }
            else
            {
                if(OPTfullname)
                    sprintf(headerbuf,"<a href=\"%s.htm\" title=\"%s\">%s</a>",strippedprimarynodot0,description,primary);
                else
                    sprintf(headerbuf,"<a href=\"%s.htm\" title=\"%s\">%s</a>",strippedprimarynodot0,description,primarynodot);
            }
            d = ABSputs(d,headerbuf);

            if (description[0])
            {
                int COLDESCRIPTION;
                int len;

                if(OPTsrclanguage==LANGUAGECPP)
                    COLDESCRIPTION = 34;
                else
                    COLDESCRIPTION = 24;
                len=COLDESCRIPTION-(strlen(primarynodot));
                if (len<0)
                    len = 0;

                for (i=0; i<len; ++i)
                    headerbuf[i] = ' ';

                headerbuf[i] = 0;
                strcat(headerbuf," - ");
                strcat(headerbuf,description);
                d = ABSputs(d,headerbuf);
            }
            d = ABSputs(d,OPTnl);
        }
    }
    else if (abstype==TYPEHTMLINDEXTREE || (abstype==TYPEHHCONTENT && OPTsrclanguage==LANGUAGECPP))        /* hierarchial html index file or hierarchial html help contents file */
    {
        if (strcmp(previousheading,primarynodot) && strcmp(moldyheading,primarynodot))
        {
            /* write header with sorting tag and tree info */
            int     levels;     /* number of levels in hierarchy */
            int     abstype;    /* type of abstract (class, method, other) */
            int     i;
            char    *headerptr,*primaryptr,*lastptr;
            char    substr[SPITMAXLINE];
            char    classfound;

            primaryptr = primarynodot;
            levels = 0;
            classfound = 0;
            abstype=ABSTYPEFILE;
            headerptr = headerbuf;
            sprintf(headerptr,"<!-");   /* start of sort code (HTML comment tag) */
            headerptr = strchr(headerbuf,'\0');

            while(*primaryptr)
            {
                lastptr = primaryptr;
                /* scan to next non-alphanumeric char: */
                while(*primaryptr && (isalnum(*primaryptr) || *primaryptr=='_'))
                    primaryptr++;

                if(*primaryptr==':')
                {
                    abstype=ABSTYPECLASS;
                    classfound = 1;
                    levels++;
                }
                else if(*primaryptr=='(')
                    abstype=ABSTYPEMETHOD;
                else if(*primaryptr=='\0' && classfound)
                    abstype=ABSTYPEDATA;

                /* write sort code: */
                strncpy(substr,lastptr,primaryptr-lastptr);
                substr[primaryptr-lastptr] = '\0';
                sprintf(headerptr,"%d%s",abstype,substr);
                headerptr = strchr(headerbuf,'\0');

                /* scan to next alphanumeric char: */
                while(*primaryptr && !isalnum(*primaryptr) && *primaryptr!='_')
                    primaryptr++;
            }

            if(abstype==ABSTYPECLASS)
                levels--;
            sprintf(headerptr,"->");    /* end of sort code (HTML comment tag) */
            headerptr = strchr(headerbuf,'\0');

            /* add icons and tree levels graphics: */
            if(levels)  /* indent */
            {
                for(i=1;i<levels;i++)
                    strcat(headerbuf,"<img src=\"spacer.gif\">");
                strcat(headerbuf,"<img src=\"tree.gif\">");
            }
            if(abstype==ABSTYPECLASS)
                strcat(headerbuf,"<img src=\"classicon.gif\">");
            else if(abstype==ABSTYPEMETHOD)
                strcat(headerbuf,"<img src=\"methodicon.gif\">");
            else if(abstype==ABSTYPEDATA)
                strcat(headerbuf,"<img src=\"dataicon.gif\">");
            else if(abstype==ABSTYPEFILE)
                strcat(headerbuf,"<img src=\"fileicon.gif\">");

            d = ABSputs(d,headerbuf);

            /* start a new abstract */
            strcpy(moldyheading,previousheading);
            strcpy(previousheading,primarynodot);

            if(OPTsrclanguage==LANGUAGECPP || OPTfullname)
            {
                ABSstrips(strippedprimarynodot0,(*primarynodotbuf)[0],0);
                ABSstrips(strippedprimarynodot2,(*primarynodotbuf)[0],2);
            }
            else
                strcpy(strippedprimarynodot0,(*primarynodotbuf)[0]);
            if(abstype==ABSTYPECLASS)   /* make class abstracts BOLDED */
                d = ABSputs(d,"<b>");
            if(OPTfullname)
                sprintf(headerbuf,"<a href=\"%s.htm\" title=\"%s\">%s</a>",strippedprimarynodot0,description,primary);
            else
                sprintf(headerbuf,"<a href=\"%s.htm\" title=\"%s\">%s</a>",strippedprimarynodot0,description,strippedprimarynodot2);
            d = ABSputs(d,headerbuf);
            if(abstype==ABSTYPECLASS)   /* make class abstracts BOLDED */
                d = ABSputs(d,"</b>");
            d = ABSputs(d,OPTnl);
        }
    }
    else if (abstype==TYPETERSEHINDEX)        /* terse html index file */
    {
        if (catagory[0] && (strcmp(catagory,previouscatagory)))
        {
            strcpy(previouscatagory,catagory);
            absnend = absn;
            newcatagory = SPITYES;
        }

        if (strcmp(previousheading,primarynodot) && strcmp(moldyheading,primarynodot))
        {
            /* print category header */
            if(catagory[0])
            {
                char libcatagory[SPITMAXLINE];

                if (OPTlibraryname[0])
                    sprintf(libcatagory, "%s_%s", OPTlibraryname, catagory);
                else
                    strcpy(libcatagory, catagory);

                switch(OPTlinkhead)
                {
                case 1:
                    sprintf(headerbuf,"</PRE><H3><A NAME=\"%s\"></A><A HREF=\"../overview/%s.htm\" title=\"%s Overview\"><IMG SRC=\"%s.gif\" ALT=\"%s Overview\" ALIGN=\"MIDDLE\" border=0>%s</A></H3><PRE>",catagory,libcatagory,catagory,catagory,catagory,catagory);
                    break;
                case 2:
                    sprintf(headerbuf,"</PRE><H3><A NAME=\"%s\"></A><A HREF=\"../../overview/%s.htm\" title=\"%s Overview\"><IMG SRC=\"%s.gif\" ALT=\"%s Overview\" ALIGN=\"MIDDLE\" border=0>%s</A></H3><PRE>",catagory,libcatagory,catagory,catagory,catagory,catagory);
                    break;
                case 3:
                    sprintf(headerbuf,"");
                    break;
                case 4:
                    sprintf(headerbuf,"</PRE><H3><A NAME=\"%s\"></A><A HREF=\"../overview/%s.htm\" title=\"%s\">%s</A></H3><PRE>",catagory,libcatagory,catagory,catagory);
                    break;
                case 5:
                    sprintf(headerbuf,"</PRE><H3><A NAME=\"%s\"></A><A HREF=\"%s.htm\" title=\"%s\">%s</A></H3><PRE>",catagory,libcatagory,catagory,catagory);
                    break;
                default:
                    sprintf(headerbuf,"</PRE><H3><A NAME=\"%s\"></A>%s</H3><PRE>",catagory,catagory);
                     break;
                }
                d = ABSputs(d,headerbuf);
            }

            strcpy(moldyheading,previousheading);
            strcpy(previousheading,primarynodot);

            if(OPTsrclanguage==LANGUAGECPP || OPTfullname)
                ABSstrips(strippedprimarynodot0,(*primarynodotbuf)[0],0);
            else
                strcpy(strippedprimarynodot0,(*primarynodotbuf)[0]);
            if(rating[0]=='1')  /* make obsolete function names BOLDED */
            {
                if(OPTfullname)
                    sprintf(headerbuf,"<a href=\"%s.htm\" title=\"%s\"><b>%s</b></a>",strippedprimarynodot0,description,primary);
                else
                    sprintf(headerbuf,"<a href=\"%s.htm\" title=\"%s\"><b>%s</b></a>",strippedprimarynodot0,description,primarynodot);
            }
            else
            {
                if(OPTfullname)
                    sprintf(headerbuf,"<a href=\"%s.htm\" title=\"%s\">%s</a>",strippedprimarynodot0,description,primary);
                else
                    sprintf(headerbuf,"<a href=\"%s.htm\" title=\"%s\">%s</a>",strippedprimarynodot0,description,primarynodot);
            }
            d = ABSputs(d,headerbuf);

            /* pad with column spaces */
            for(i=0;i<COLWIDTH;i++)
                d = ABSputc(d,(int)' ');
        }
    }
    else if (abstype==TYPEHHCONTENT || abstype==TYPEHHCONTENTFLAT)        /* html help contents file */
    {
        if (catagory[0] && strcmp(catagory,previouscatagory))
        {
            /* start a new category */
            strcpy(previouscatagory,catagory);
            absnend = absn;
            newcatagory = SPITYES;
            levelnum++;
        }
        if (strcmp(previousheading,primarynodot) && strcmp(moldyheading,primarynodot))
        {
            /* write header */
            sprintf(headerbuf,                  "<LI> <OBJECT type=\"text/sitemap\">\n");
            sprintf(headerbuf+strlen(headerbuf),"     <param name=\"Name\" value=\"%s\">\n",catagory);
            sprintf(headerbuf+strlen(headerbuf),"     </OBJECT>\n<UL>\n");

            /* overview */
            if(OPTlinkhead!=3)  // show overview
            {
                char libcatagory[SPITMAXLINE];

                if (OPTlibraryname[0])
                    sprintf(libcatagory, "%s_%s", OPTlibraryname, catagory);
                else
                    strcpy(libcatagory, catagory);

                sprintf(headerbuf+strlen(headerbuf),"<LI> <OBJECT type=\"text/sitemap\">\n");
                sprintf(headerbuf+strlen(headerbuf),"     <param name=\"Name\" value=\"OVERVIEW\">\n");
                if(abstype==TYPEHHCONTENTFLAT)
                    sprintf(headerbuf+strlen(headerbuf),"     <param name=\"Local\" value=\"%s.htm\">\n",libcatagory);
                else
                    sprintf(headerbuf+strlen(headerbuf),"     <param name=\"Local\" value=\"overview/%s.htm\">\n",libcatagory);
                sprintf(headerbuf+strlen(headerbuf),"     <param name=\"ImageNumber\" value=\"17\">\n");
                sprintf(headerbuf+strlen(headerbuf),"     </OBJECT>\n");
            }
            sprintf(headerbuf+strlen(headerbuf),"<!-C-->\n");

            d = ABSputs(d,headerbuf);

            /* start a new abstract */
            strcpy(moldyheading,previousheading);
            strcpy(previousheading,primarynodot);

            /* (*primarynodotbuf)[0] is used because we always want to link to the first primary reference */
            if(OPTsrclanguage==LANGUAGECPP || OPTfullname)
                ABSstrips(strippedprimarynodot0,(*primarynodotbuf)[0],0);
            else
                strcpy(strippedprimarynodot0,(*primarynodotbuf)[0]);

            if(abstype==TYPEHHCONTENTFLAT)
                sprintf(headerbuf,"<LI> <OBJECT type=\"text/sitemap\">\n     <param name=\"Name\" VALUE=\"%s\">\n     <param name=\"Local\" value=\"%s.htm\">\n     </OBJECT>       \n",primarynodot,strippedprimarynodot0);
            else
                sprintf(headerbuf,"<LI> <OBJECT type=\"text/sitemap\">\n     <param name=\"Name\" VALUE=\"%s\">\n     <param name=\"Local\" value=\"functions/%s.htm\">\n     </OBJECT>       \n",primarynodot,strippedprimarynodot0);
            d = ABSputs(d,headerbuf);
        }
    }
    else if (abstype==TYPEHHINDEX || abstype==TYPEHHINDEXFLAT)        /* html help index file */
    {
        if (catagory[0] && strcmp(catagory,previouscatagory))
        {
            /* start a new category */
            strcpy(previouscatagory,catagory);
            absnend = absn;
            newcatagory = SPITYES;
        }
        if (strcmp(previousheading,primarynodot) && strcmp(moldyheading,primarynodot))
        {
            /* start a new abstract */
            strcpy(moldyheading,previousheading);
            strcpy(previousheading,primarynodot);

            /* (*primarynodotbuf)[0] is used because we always want to link to the first primary reference */
            if(OPTsrclanguage==LANGUAGECPP || OPTfullname)
                ABSstrips(strippedprimarynodot0,(*primarynodotbuf)[0],0);
            else
                strcpy(strippedprimarynodot0,(*primarynodotbuf)[0]);

            if(abstype==TYPEHHINDEXFLAT)
                sprintf(headerbuf,"<LI> <OBJECT type=\"text/sitemap\">\n     <param name=\"Name\" VALUE=\"%s\">\n     <param name=\"Local\" value=\"%s.htm\">\n     </OBJECT>       \n",primarynodot,strippedprimarynodot0);
            else
                sprintf(headerbuf,"<LI> <OBJECT type=\"text/sitemap\">\n     <param name=\"Name\" VALUE=\"%s\">\n     <param name=\"Local\" value=\"functions/%s.htm\">\n     </OBJECT>       \n",primarynodot,strippedprimarynodot0);
            d = ABSputs(d,headerbuf);
        }
    }
    else if (abstype==TYPEABS)                                  /* rick-style abstract format */
    {
        d = ABSputs(d,OPTnl);
        d = ABSputs(d,"/*");
        d = ABSputs(d,OPTnl);
        d = ABSputs(d," ");
        d = ABSputs(d,"ABSTRACT");
        d = ABSputs(d," ");
        d = ABSputs(d,OPTnl);
    }
    else if (abstype==TYPEMSHLP)
    {
        sprintf(headerbuf, ".context %s", primary);
        d = ABSputs(d,headerbuf);
        d = ABSputs(d,OPTnl);

        if (strcmp(primarynodot,primary))
        {
            sprintf(headerbuf, ".context %s", primarynodot);
            d = ABSputs(d,headerbuf);
            d = ABSputs(d,OPTnl);
        }
    }
    else if (abstype==TYPEHELPPC)
    {
        sprintf(headerbuf, ":%s", primary);
        d = ABSputs(d,headerbuf);
    }
    else if (abstype==TYPEMACHLP)
    {
        sprintf(headerbuf, "\276KY %s", primarynodot);
        d = ABSputs(d,headerbuf);
        d = ABSputs(d,OPTnl);

        if (strcmp(primarynodot,primary))
        {
            sprintf(headerbuf, "%s", primary);
            d = ABSputs(d,headerbuf);
            d = ABSputs(d,OPTnl);
        }
    }

    /* output secondary names */

    for (i=0; i<nsec; ++i)
    {
        if ((abstype==TYPESTHLP) || (abstype==TYPEMPWHLP))
        {
            sprintf(headerbuf, "%s%s", stmpwchr,(*secondarybuf)[i]);
            d = ABSputs(d,headerbuf);
            d = ABSputs(d,OPTnl);
            sprintf(headerbuf, "    See %s", primarynodot);
            d = ABSputs(d,headerbuf);
            d = ABSputs(d,OPTnl);
            d = ABSputs(d,OPTnl);
        }
        else if (abstype==TYPEMACHLP)
        {
            sprintf(headerbuf, "%s", (*secondarybuf)[i]);
            d = ABSputs(d,headerbuf);
            d = ABSputs(d,OPTnl);
        }
        else if (abstype==TYPEMSHLP)
        {
            sprintf(headerbuf, ".context %s", (*secondarybuf)[i]);
            d = ABSputs(d,headerbuf);
            d = ABSputs(d,OPTnl);
        }
        else if (abstype==TYPEXREF)  /* index file */
        {
            if(OPTsrclanguage==LANGUAGECPP || OPTfullname)
            {
                ABSstrips(strippedprimarynodot1,(*secondarybuf)[i],1);
                ABSstrips(strippedprimarynodot0,primarynodot,0);
                sprintf(headerbuf,"%s,%s,%s",strippedprimarynodot1,strippedprimarynodot0,description);
            }
            else
            {
                sprintf(headerbuf,"%s,%s,%s",(*secondarybuf)[i],primarynodot,description);
            }
            d = ABSputs(d,headerbuf);
            d = ABSputs(d,OPTnl);
        }
    }

    /* stuff that comes after secondary abstract names */

    if (abstype==TYPESTHLP || abstype==TYPEMPWHLP)
    {
        sprintf(headerbuf, "%s%s", stmpwchr,primarynodot);
        d = ABSputs(d,headerbuf);
        d = ABSputs(d,OPTnl);
    }
    else if (abstype==TYPEMACHLP)
    {
        sprintf(headerbuf, "\276C");
        d = ABSputs(d,headerbuf);
        d = ABSputs(d,OPTnl);

        if (catagory[0])
        {
            d = ABSputs(d,catagory);
            d = ABSputs(d,OPTnl);
        }

        /* midl.doc format header as first line of ms help */

        SPIT_getname( stampbuf,fnameptr);
        sprintf(headerbuf,"%-40s%s",dateptr,stampbuf);
        d = ABSputs(d,headerbuf);
        d = ABSputs(d,OPTnl);
        d = ABSputs(d,OPTnl);
    }
    else if (abstype==TYPEMSHLP)
    {
        /* freeze 2 lines from scrolling */

        d = ABSputs(d,".freeze 2");
        d = ABSputs(d,OPTnl);

        d = ABSputs(d,"                                          ");
        d = ABSputs(d,"\\i\021\\p\\aeac.h\\veac.hlp!eac\\v\\i\020\\p ");
        d = ABSputs(d,"\\i\021\\p\\aContents\\veac.hlp!eacmenu\\v\\i\020\\p ");
        d = ABSputs(d,"\\i\021\\p\\aIndex\\veac.hlp!eaclib\\v\\i\020\\p ");
        d = ABSputs(d,"\\i\021\\p\\aBack\\v!B\\v\\i\020\\p");
        d = ABSputs(d,OPTnl);

        strcpy(stampbuf, msline);
        if (catagory[0])
        {
            strcpy(stampbuf+4, catagory);
            stampbuf[4+(strlen(catagory))] = stampbuf[3];
        }
        d = ABSputs(d,stampbuf);
        d = ABSputs(d,OPTnl);
        d = ABSputs(d,OPTnl);

        /* midl.doc format header as first line of ms help */

        SPIT_getname( stampbuf,fnameptr);
        sprintf(headerbuf,"\\b%-40s%s\\p",dateptr,stampbuf);
        d = ABSputs(d,headerbuf);
        d = ABSputs(d,OPTnl);
        d = ABSputs(d,OPTnl);
    }
    else if (abstype==TYPEHELPPC)
    {
        d = ABSputs(d,OPTnl);

        /* midl.doc format header as first line of ms help */

        SPIT_getname( stampbuf,fnameptr);
        sprintf(headerbuf,"^%-40s%s",dateptr,stampbuf);
        d = ABSputs(d,headerbuf);
        d = ABSputs(d,OPTnl);
        d = ABSputs(d,OPTnl);
    }

    gfree(primarybuf);
    gfree(secondarybuf);
    gfree(descriptionbuf);
    gfree(primarynodotbuf);

    *numprim = nprim;
    return(d);
}

/****************************************************************/
/*  Check For Abstract Start/End                                */
/****************************************************************/

static int StartAbstractDelimiter(char *infile)
{
    int  found;
    char *s,*t;
    int  isfirstword;

    found = SPITNO;
    s = infile;
    while (*s && *s!=(char)13 && *s!=(char)10)
    {
        if (*(s-1)<=' ')
        {
            if (s[0]==(char)'$' && s[1]==(char)'$' && s[2]==(char)'$' && s[3]<=' ')
            {
                found = SPITYES;
                s = "";
            }
            else
            {
                if (!OPTasis && (!strncmp(s,"END ABSTRACT",12) || !strncmp(s,"END\tABSTRACT",12)) && s[12]<=' ')
                {
                    t = s-1;
                    isfirstword = SPITYES;
                    while (*t && *t!=(char)13 && *t!=(char)10)
                    {
                        if(isalnum(*t))
                        {
                            isfirstword = SPITNO;
                            break;
                        }
                        t--;
                    }
                    if (isfirstword == SPITYES)
                        return(SPITNO);
                }
                if (!OPTasis && !strncmp(s,"ABSTRACT",8) && s[8]<=' ')
                {
                    found = SPITYES;
                    t = s-1;
                    while (*t && *t!=(char)13 && *t!=(char)10)
                    {
                        if(isalnum(*t))
                            return(SPITNO);
                        t--;
                    }
                    s = "";
                }
                else
                    ++s;
            }
        }
        else
            ++s;
    }
    return(found);
}

/****************************************************************/
/*  Check For Abstract Stop/End                                */
/****************************************************************/

static int StopAbstractDelimiter(char *infile)
{
    int  found;
    char *s;

    found = SPITNO;
    s = infile;
    while (*s && *s!=(char)13 && *s!=(char)10)
    {
        if (*(s-1)<=' ')
        {
            if (s[0]==(char)'$' && s[1]==(char)'$' && s[2]==(char)'$' && s[3]<=' ')
            {
                found = SPITYES;
                s = "";
            }
            else
            {
                if (!OPTasis && (!strncmp(s,"END ABSTRACT",12) || !strncmp(s,"END\tABSTRACT",12)) && s[12]<=' ')
                {
                    found = SPITYES;
                    s = "";
                }
                else
                    ++s;
            }
        }
        else
            ++s;
    }
    return(found);
}

/****************************************************************/
/*  Check For Stop Output Delimiter                             */
/*  - used to shorten doc for brief format                      */
/*  - keeps summary but removes everything else                 */
/****************************************************************/


static int QuietDelimiter(char *infile,int abstype)
{
    int  found;
    char *s;

    found = SPITNO;
    if (abstype==TYPEBRIEFSUM || abstype==TYPEBRIEFNOSUM || abstype==TYPEEXAMPLE)
    {
        s = infile;
        while (*s==(char)' ' || *s==(char)'\t')
        {
            ++s;
            if ((abstype==TYPEBRIEFNOSUM || abstype==TYPEEXAMPLE) && !strncmp(s,"SUMMARY",7) && s[7]<' ')
            {
                found = SPITYES;
                s = "";
            }
            if (!strncmp(s,"DESCRIPTION",11) && s[11]<' ')
            {
                found = SPITYES;
                s = "";
            }
            else if (!strncmp(s,"RETURNS",7) && s[7]<' ')
            {
                found = SPITYES;
                s = "";
            }
            else if (!strncmp(s,"RETURN VALUE",12) && s[12]<' ')
            {
                found = SPITYES;
                s = "";
            }
            else if (abstype!=TYPEEXAMPLE && !strncmp(s,"EXAMPLE",7) && s[7]<' ')
            {
                found = SPITYES;
                s = "";
            }
            else if (!strncmp(s,"SEE ALSO",8) && s[8]<' ')
            {
                found = SPITYES;
                s = "";
            }
            else if (!strncmp(s,"SOURCE",6) && s[6]<' ')
            {
                found = SPITYES;
                s = "";
            }
            else if (!strncmp(s,"RANGE SYNTAX",12) && s[12]<' ')
            {
                found = SPITYES;
                s = "";
            }
            else if (!strncmp(s,"KEYS",4) && s[4]<' ')
            {
                found = SPITYES;
                s = "";
            }
        }
    }
    else if (abstype==TYPEINDEX || abstype==TYPEUSINDEX || abstype==TYPEHTMLINDEX || abstype==TYPEHTMLINDEXTREE || abstype==TYPEXREF || abstype==TYPETERSEHINDEX ||
        abstype==TYPEHHCONTENT || abstype==TYPEHHINDEX || abstype==TYPEHHCONTENTFLAT || abstype==TYPEHHINDEXFLAT)
    {
        found = SPITYES;
        s = "";
    }
    else if (abstype==TYPEMPWHLP)
    {
        s = infile;
        while (*s==(char)' ' || *s==(char)'\t')
        {
            ++s;
            if (!strncmp(s,"DESCRIPTION",11) && s[11]<' ')
            {
                found = SPITYES;
                s = "";
            }
        }
    }

    return(found);
}

/****************************************************************/
/*  Check For Resume Output Delimiter                           */
/*  - used resume output after a stop delimiter was found       */
/*  - used by for extracting examples                           */
/****************************************************************/


static int LoudDelimiter(char *infile,int abstype)
{
    int  found;
    char *s;

    found = SPITNO;
    if (abstype==TYPEEXAMPLE)
    {
        s = infile;
        while (*s==(char)' ' || *s==(char)'\t')
        {
            ++s;
            if (!strncmp(s,"EXAMPLE",7) && s[7]<' ')
            {
                found = SPITYES;
                s = "";
            }
        }
    }

    return(found);
}

/****************************************************************/
/*  Check For Headings                                          */
/*  - used to format headings bold                              */
/*  - returns replacement heading or null                       */
/****************************************************************/

static char *isheading(char *s, int *indent)
{
    struct
    {
        int indent;
        char *search;
        char *replace;
    } headings[]=
    {
        0,"SUMMARY","SUMMARY",
        0,"DESCRIPTION","DESCRIPTION",
        0,"SEE ALSO","SEE ALSO",
        0,"OPERATION","OPERATION",
        0,"EFFICIENCY","EFFICIENCY",
        0,"RETURNS","RETURNS",
        0,"RETURN VALUE","RETURN VALUE",
        0,"EXAMPLE","EXAMPLE",
        0,"EXPRESSION VARIABLES","EXPRESSION VARIABLES",
        0,"RANGE SYNTAX","RANGE SYNTAX",
        0,"KEYS","KEYS",
        3,"Version Date   SE History:","REVISION HISTORY",
        3,"Version Date   SE History","REVISION HISTORY",
        0,"REVISION HISTORY","REVISION HISTORY",
        0,"Module Notes:","MODULE NOTES",
        0,"Format Notes:","FORMAT NOTES",
        0,"PLATFORM NOTES","PLATFORM NOTES",
        0,"FILE FORMATS","FILE FORMATS",
        0,"TYPES","TYPES",
        0,"CONSTRUCTORS","CONSTRUCTORS",
        0,"METHODS","METHODS",
        0,"DATA","DATA",
        0,"SOURCE","SOURCE",
        0,"OPERATORS","OPERATORS",
        0,"CAVEAT","CAVEAT",
        0,"FUTURE WORK","FUTURE WORK",
        0,"TEXTURE FORMATS","TEXTURE FORMATS",
        0,"CLUT FORMATS","CLUT FORMATS",
        0,"TEXTURE FILTERS","TEXTURE FILTERS",
        0,"STATES","STATES",
        0,"DISPLAY MODES","DISPLAY MODES",
        0,"EXTENSIONS","EXTENSIONS",
        0,"TIP","TIP",
        0,"APPLICATIONS","APPLICATIONS",
        0,"FORMAT NOTES","FORMAT NOTES",
        0,"SUBTYPE","SUBTYPE",
        0,"PACKTYPE","PACKTYPE",
        0,"FILETYPE","FILETYPE",
        0,"BPP","BPP",
        0,"Expected output:","SAMPLE OUTPUT",
        0,"SAMPLE OUTPUT","SAMPLE OUTPUT",
        0,"OPTIONS","OPTIONS",
        0,"FORMAT SPECIFICATIONS","FORMAT SPECIFICATIONS",
        0,0,0,
    };

    int  i;
    int  l;

    /* skip white space */

    while (*s==(char)' ' || *s==(char)'\t')
        ++s;

    for (i=0;headings[i].search;++i)
    {
        l = strlen(headings[i].search);
        if (!strncmp(headings[i].search,s,l) && s[l]<=' ')
        {
            *indent = headings[i].indent;
            return(headings[i].replace);
        }
    }

    static char headerbuf[SPITMAXLINE];
    char *d = headerbuf;
    while (*s>=' ')
    {
        *d = *s;
        if (*s==':' && s[1]<' ')
        {
            while (d>headerbuf && *(d-1)==' ')
                --d;
            if (d==headerbuf)
                break;
            *d = '\0';
            return headerbuf;
        }
        if (*s!=' ' && (*s<'A' || *s>'Z'))
            break;
        ++s;
        ++d;
    }
    return((char *) 0);
}

/* is the line entirely dashes and spaces? */
/* this is used to remove these from Gimex abstracts following headers */

static int ABSisunderline(const char *s)
{
    int ok=0;

    if (*s)
    {
        ok = 1;
        while (*s)
        {
            if (!(*s=='-' || *s==' '))
                ok = 0;
            ++s;
        }
    }
    return(ok);
}

/* get a raw line, expanding tabs, stripping comments */

static char *ABSgetline(char *dest, char *source, int indent)
{
    char *s;
    char *d;
    char *e;
    char linebuf[SPITMAXLINE];
    int i;

    /* grab line, expanding tabs */

    s = source;
    d = linebuf;
    i = 0;
    while (*s && *s!=(char)13 && *s!=(char)10)  /* goto next line */
    {
        if (*s==(char)'\t')
        {
            do
            {
                d[i++] = ' ';
            } while (i&3);
        }
        else
            d[i++] = *s;
        ++s;
    }
    d[i] = 0;

    /* skip end of line */

    if (*s==(char)13)
    {
        ++s;
        if (*s==(char)10)
            ++s;
    }
    if (*s==(char)10)
    {
        ++s;
        if (*s==(char)13)
            ++s;
    }

    source = s;

    /* remove trailing spaces */

    while (i && d[i-1]==' ')
        --i;
    d[i] = 0;

    s = linebuf;
    e = linebuf;
    if (i>=2)
        e = linebuf+i-2;

    if (*s==(char)';' || *s==(char)'#' || (*s==(char)'*' && *(s+1)!=(char)'/'))
        ++s;
    else if (s[0]=='/' && s[1]=='/')
        s += 2;
    else if(!OPTkeepcomments)
    {
        if (!strncmp(s,"//",2))
            s += 2;
        else if (!strncmp(s,"/*",2) && !strncmp(e,"*/",2))
        {
            /* remove comments and trailing spaces inside comment */

            s += 2;
            while (e>linebuf && *(e-1)==' ')
                --e;
            *e = 0;
        }
    }

    /* remove amount of indent desired */

    while (indent--)
    {
        if (*s==' ')
            ++s;
    }

    strcpy(dest,s);

    return(source);
}

#define MAXCYMBALS 2048
int numcymbals;
char *cymbalptr[MAXCYMBALS];
char *cymbalstart[MAXCYMBALS];
int  cymballen[MAXCYMBALS];

static void initcymbal(char *cym)
{
    char *s;
    char *start;
    char *end;

    numcymbals = 0;
    s = cym;
    if (s)
    {
        do
        {
            start = s;
            if (!strncmp(s,"</PRE><H4>FILE</H4><PRE>",strlen("</PRE><H4>FILE</H4><PRE>")))
            {
                s += strlen("</PRE><H4>FILE</H4><PRE>");
                while (*s && *s<=' ')
                    ++s;

                end = ABSstrstr(s,"</PRE><H4>FILE</H4><PRE>");
                if (!end)
                    end = start+strlen(start);

                cymbalptr[numcymbals] = s;
                cymbalstart[numcymbals] = start;
                cymballen[numcymbals] = (int)(end-start);
                ++numcymbals;
                s = end;
            }
            else
                if (*s) ++s;
        } while (*s);
    }
    if (numcymbals && OPTverbose>=3)
        printf("%d cymbals\n",numcymbals);
}

static char *addcymbal(char *d,char *cym,char *fnameptr)
{
    int i;
    int l;
    char searchbuf[SPITMAXLINE];
    char *lib;
    char *s;

    s = strrchr(fnameptr,SPITDIRSYM);
    if (s)
        ++s;
    else
        s = fnameptr;
    strcpy(searchbuf,s);
    if (strrchr(searchbuf,'.'))
       *strrchr(searchbuf,'.')=0;
    strcat(searchbuf,".o");  /* .o or .obj */
    l = strlen(searchbuf);

    if (OPTverbose>=5)
        printf("added cymbal reference %s... ",searchbuf);

    for (i=0; i<numcymbals; ++i)
    {
        if (cymbalptr[i][0]==searchbuf[0])
        {
            lib = strchr(cymbalptr[i],'(') + 1;
            if (!strnicmp(cymbalptr[i],searchbuf,l) && !strnicmp(lib,OPTlibraryname,strlen(OPTlibraryname)))
            {
                if (OPTverbose>=5)
                    printf("%d\n",cymballen[i]);
                strncpy(d,cymbalstart[i],cymballen[i]);
                d += cymballen[i];
                *d = 0;
                return(d);
            }
        }
    }
    if (OPTverbose>=5)
        printf("not found\n");

    return(d);
}

/****************************************************************
 *  Add the author of the abstract
 ****************************************************************/

static char *addauthor(char *d,char *authorfile,char *authorinitialptr)
{
    char authorname[SPITMAXLINE];
    char authoremail[SPITMAXLINE];
    char *searchptr,*searchptr2;

    strcpy(authorname,authorinitialptr);
    strcat(authorname,",");
    searchptr = strstr(authorfile,authorname);   /* find author's initial in author file */
    if (searchptr)
    {
        /* get matching author name */
        searchptr += strlen(authorname);
        searchptr2 = strchr(searchptr,',');
        if(searchptr2)
        {
            strncpy(authorname,searchptr,searchptr2-searchptr);
            authorname[searchptr2-searchptr]='\0';

            /* get matching author e-mail address */
            searchptr = searchptr2+1;
            searchptr2 = strchr(searchptr,'\n');
            if(!searchptr2)
                searchptr2 = strchr(searchptr,'\0');
            if(searchptr2)
            {
                strncpy(authoremail,searchptr,searchptr2-searchptr-1);
                authoremail[searchptr2-searchptr-1]='\0';
            }
        }
    }
    else    /* no matching author */
    {
        strcpy(authorname,"No contact available.");
        strcpy(authoremail,"");
    }

    /* write author info */
    d = ABSputs(d,"</PRE><H4>CONTACT</H4><PRE>    ");
    d = ABSputs(d,authorname);
    d = ABSputs(d," <A HREF=\"mailto:");
    d = ABSputs(d,authoremail);
    d = ABSputs(d,"?body=");
    d = ABSputs(d,"Name of Library or Tool:   %0A");
    d = ABSputs(d,"Version I am using:   %0A");
    d = ABSputs(d,"Platform I am using:   %0A");
    d = ABSputs(d,"Version of my O/S Libraries (e.g. Sony 2.34):   %0A");
    d = ABSputs(d,"------------------------------------------------------------------%0A");
    d = ABSputs(d,"My issue or question:%0A");
    d = ABSputs(d,"%0A");
    d = ABSputs(d,"\">");
    d = ABSputs(d,"<img src=\"mailto.gif\" border=\"0\" style=\"filter:alpha(opacity=50)\" onMouseover=\"this.filters.alpha.opacity=100\" onMouseout=\"this.filters.alpha.opacity=50\"></A>");
    d = ABSputs(d,OPTnl);
    d = ABSputs(d,OPTnl);

    return(d);
}

/****************************************************************
 *  Add the source file - used in error reporting
 ****************************************************************/

static char *addsourcefile(char *d, char *fnameptr)
{
    d = ABSputs(d,"<A ID=\"SOURCEFILE\" NAME=\"");
    d = ABSputs(d, fnameptr);
    d = ABSputs(d,"\"></A>");
    d = ABSputs(d,OPTnl);

    return(d);
}

/****************************************************************/
/*  Scan Through a File for Abstracts                           */
/****************************************************************/

static char *parsecomments(char *dateptr,char *fnameptr,char *objname,SPITMEM *infile,char *outptr)
{
    char *s;
    char *d;
    char c=0;
    char *absstart=0;
    int abstractlength;
    int  inabstract;
    int  inexample;
    int  linecount;
    int  quietline;
    int  indent;
    int  numprim=0,getprim;

    inabstract = SPITNO;
    inexample = SPITNO;
    linecount = 1;
    s = infile->ptr;
    d = outptr;
    indent = 0;
    getprim = 0;

    while(*s)
    {

/****************************************************************/
/*  Start a new abstract                                        */
/****************************************************************/

        if (!inabstract)
        {
            if (StartAbstractDelimiter(s))
            {
                absstart = s;
                d = openabstract(d, infile->len, OPTverbose);           /* reserve memory */
                if (d)
                {
                    dstart = d;
                    d = header(dateptr, fnameptr, s, d, OPTabstype, linecount, &numprim, getprim);
                    if(getprim<numprim)
                        getprim++;
                    inabstract = 1;

                    s = nextline(s);  /* goto next line */

                    while (*s && (*s<=' ' || *s==';' || *s==(char)'/' || *s==(char) '*'))                  /* don't remove close C comment */
                        ++s;
                    while (*(s-1)!=(char)13 && *(s-1)!=(char)10)    /* back up to start of line */
                        --s;

                    ++linecount;
                }
            }
            else
            {
                while (*s && *s!=(char)13 && *s!=(char)10)      /* goto next line */
                    ++s;
                if (*s==(char)13)
                {
                    ++s;
                    if (*s==(char)10)
                        ++s;
                }
                if (*s==(char)10)
                {
                    ++s;
                    if (*s==(char)13)
                        ++s;
                }
                ++linecount;
            }
        }
        else
        {

/****************************************************************/
/*  End an abstract                                             */
/****************************************************************/

            if (StopAbstractDelimiter(s))
            {
                if (OPTabstype==TYPEHTML && OPTauthorfile.ptr)
                {
                    d = addauthor(d,OPTauthorfile.ptr,authorinitial);
                }
                if (OPTcymbalfile.ptr)
                {
                    d = addcymbal(d,OPTcymbalfile.ptr,objname);
                    d = addsourcefile(d,fnameptr);
                }
                abstractlength = SPIT_ptrdif(dstart, d);    /* truncate if too int */
                d = dstart+abstractlength;
                if (OPTabstype==TYPEHELPPC && abstractlength>16384-16L)
                {
                    abstractlength=16384-16;
                    d = dstart+abstractlength;
                    d = ABSputs(d,"...");
                    d = ABSputs(d,OPTnl);
                }
                else if (OPTabstype==TYPEMSHLP && abstractlength>32000-16L)
                {
                    abstractlength=32000-16;
                    d = dstart+abstractlength;
                    d = ABSputs(d,"...");
                    d = ABSputs(d,OPTnl);
                }
                else if (OPTabstype==TYPEDOC || OPTabstype==TYPEPRETEXT)
                {
                    d = ABSputs(d,"\f");                        /* new page */
                }
                else if (OPTabstype==TYPEMSHLP)
                {
                    d = ABSputs(d,"                                     -\4-");     /* end of help */
                    d = ABSputs(d,OPTnl);
                }
                else if (OPTabstype==TYPEHTML)
                {
                    d = ABSputs(d,"</PRE>");
                    if (OPTsuffixfile.ptr)
                        d = ABSputs(d,OPTsuffixfile.ptr);
                }
                else if (OPTabstype==TYPEABS)                       /* rick-style abstract format */
                {
                    d = ABSputs(d," END ");
                    d = ABSputs(d,"ABSTRACT ");
                    d = ABSputs(d,OPTnl);
                    d = ABSputs(d,"*/");
                    d = ABSputs(d,OPTnl);
                }

                gputm(d, (unsigned int) 0, 1);         /* null terminate */
                d += 1;

                abslen += SPIT_ptrdif(dstart, d);

                d = closeabstract(d);                       /* store it away */

                abslist[absn] = dstart;
                ++absn;
                inabstract = 0;

                while (*s && *s!=(char)13 && *s!=(char)10)  /* goto next line */
                    ++s;
                if (*s==(char)13)
                {
                    ++s;
                    if (*s==(char)10)
                        ++s;
                }
                if (*s==(char)10)
                {
                    ++s;
                    if (*s==(char)13)
                        ++s;
                }
                ++linecount;

                if(getprim>=numprim)
                    getprim = 0;
                else
                    s = absstart;
            }

/****************************************************************/
/*  In abstract                                                 */
/****************************************************************/

            else
            {
                char *source;
                char *oldsource;
                char linebuf[SPITMAXLINE];
                char heading[SPITMAXLINE];

                /* do line of abstract */

                oldsource = s;
                source = ABSgetline(linebuf,s,indent);
                ++abslinecount;

                s = linebuf;

                quietline = SPITNO;
                if (inabstract==2)
                {
                    quietline = SPITYES;
                }
                else if (*s=='@')
                {
                    quietline = SPITYES;
                }
                else if (QuietDelimiter(s,OPTabstype))
                {
                    inabstract = 2;
                    quietline = SPITYES;
                }

                if (LoudDelimiter(s,OPTabstype))
                {
                    inabstract = 1;
                    quietline = SPITNO;
                }

                if (ABSisunderline(s))
                    quietline = 1;

                if (OPTabstype==TYPETICKER)
                {
                    quietline = SPITYES;    /* all lines quiet except one */
                    if (!strncmp(s,"Symbol:",strlen("Symbol:")))
                    {
                        quietline = SPITNO;
                        s = ABSparsetickerline(linebuf,oldsource);
                    }
                }

                if (OPTabstype==TYPESGIMAN || OPTabstype==TYPEHTML || OPTabstype==TYPEEXAMPLE)
                {
                    if (isheading(s,&indent) && quietline!=SPITYES)
                    {
                        if(OPTabstype==TYPEEXAMPLE)
                        {
                            inexample=SPITYES;
                            printf("inexample=SPITYES;\n");
                        }
                        s = isheading(s,&indent);
                        strcpy(heading,s);

                        if (OPTabstype==TYPEHTML || OPTabstype==TYPEEXAMPLE)   /* remove previous blank lines */
                        {
                            while (*(d-1) && *(d-1)<=' ')
                                d -= 1;
                            d = ABSputs(d,OPTnl);  /* put 1 blank line */
                            d = ABSputs(d,OPTnl);
                        }

                        ABSstyle = ABSSTYLEBOLD;
                    }
                    else
                    {
                        if (ABSstyle)           /* if previous line was heading, gobble up blank lines */
                        {
                            if (!*s)
                                quietline = 1;
                        }
                        ABSstyle &= ~(ABSSTYLEBOLD|ABSSTYLEUPPER);
                        if (!quietline && OPTabstype!=TYPEEXAMPLE)
                        {
                            d = ABSputs(d,"    ");

                            if(OPTlinkhead && !strcmp(heading,"SEE ALSO") && catagory[0])         /* add link to catagory's overview */
                            {
                                char buf[SPITMAXLINE];
                                char catagoryuppercase[SPITMAXLINE];
                                char libcatagory[SPITMAXLINE];
                                int  i;

                                i = 0;
                                if (OPTlibraryname[0])
                                    sprintf(libcatagory, "%s_%s", OPTlibraryname, catagory);
                                else
                                    strcpy(libcatagory, catagory);

                                while(catagory[i])
                                {
                                    catagoryuppercase[i] = (unsigned char) toupper(catagory[i]);
                                    i++;
                                };
                                catagoryuppercase[i] = '\0';

                                switch(OPTlinkhead)
                                {
                                    case 1:
                                    case 4:
                                        sprintf(buf," <i><a href=\"../overview/%s.htm\" title=\"%s OVERVIEW\">%s OVERVIEW</a></i>",libcatagory,catagoryuppercase,catagoryuppercase);
                                        break;
                                    case 2:
                                        sprintf(buf," <i><a href=\"../../overview/%s.htm\" title=\"%s OVERVIEW\">%s OVERVIEW</a></i>",libcatagory,catagoryuppercase,catagoryuppercase);
                                        break;
                                    case 5:
                                        sprintf(buf," <i><a href=\"%s.htm\" title=\"%s OVERVIEW\">%s OVERVIEW</a></i>",libcatagory,catagoryuppercase,catagoryuppercase);
                                        break;
                                    default:
                                        sprintf(buf,"");
                                        break;
                                }
                                d = ABSputs(d,buf);
                                d = ABSputs(d,OPTnl);
                                d = ABSputs(d,"    ");
                                heading[0] = '\0';
                            }
                        }
                        else if(OPTlinkhead && !strcmp(heading,"EXAMPLE") && catagory[0])         /* add link to example overview and index */
                        {
                            d = ABSputs(d,"    ");
                            d = ABSputs(d," <i><a href=\"../functions/eg.htm\" title=\"EXAMPLES LISTING\">EXAMPLES LISTING</a></i>");
                            d = ABSputs(d,OPTnl);
                            heading[0] = '\0';
                        }
                    }
                }

                if (quietline)
                {

/*                    while (*s && *s!=(char)13 && *s!=(char)10)  \* goto next line *\ */
/*                        ++s; */

                }
                else
                {
                    /* copy line of abstract */

                    if (OPTabstype==TYPEHELPPC) /* don't shift lines over */
                        *d++ = '<';
                    else if (OPTabstype==TYPEMPWHLP)
                    {
                        if (*s=='-')
                        {
                            *d++ = ' ';
                        }
                    }

                    while (*s && *s!=(char)13 && *s!=(char)10)      /* copy next line */
                    {
                        c = *s++;

                        if (OPTabstype==TYPEMSHLP)
                            if (c=='\\')
                                *d++ = '\\';    /* double quote slashes */
                        if (OPTabstype==TYPEHTML)
                        {
                            if (c=='<')
                            {
                                if (!strnicmp(s,"HTML ",5))     /* HTML markup detected */
                                {
                                    int anchor;

                                    char *closehtml;
                                    s += strlen("HTML ");
                                    d = ABSputc(d,(int)'<');
                                    if (!strnicmp(s,"A ",2))     /* HTML anchor detected */
                                    {
                                        anchor = 1;
                                        closehtml = ABSstrstri(s,"<HTML /A>");
                                    }
                                    else
                                    {
                                        anchor = 0;
                                        closehtml = ABSstrstri(s,">");
                                    }
                                    if (closehtml)
                                    {
                                        while (*s && s<closehtml)      /* copy up to closing HTML tag*/
                                            d = ABSputc(d,(int)*s++);
                                        if (anchor)
                                        {
                                            s += strlen("<HTML ");
                                            d = ABSputc(d,(int)'<');
                                            while (*s && *s!='>')
                                                d = ABSputc(d,(int)*s++);
                                        }
                                        else    // !anchor
                                        {
                                            d = ABSputc(d,(int)*s++);
                                        }
                                        if(*s=='>')
                                        {
                                            c='>';
                                            s++;
                                        }
                                        else
                                            c=0;
                                    }
                                    else    // error: no closing HTML
                                    {
                                        fprintf(OPTerrorfile, "HTML anchor tag (<HTML A >) is missing closing tag (<HTML /A>).\n");
                                    }
                                }
                                else if (!strnicmp(s,"image=",6))
                                {    /* image markup detected */
                                    d = ABSputs(d,"<img src=\"");
                                    s += 6;
                                    while (*s && *s!=(char)13 && *s!=(char)10 && *s!='>')      /* copy up to end of image markup */
                                        d = ABSputc(d,(int)*s++);
                                    d = ABSputc(d,(int)'\"');
                                    if(*s=='>') {
                                        c='>';
                                        s++;
                                    }
                                    else
                                        c=0;
                                }
                                else {  /* just a normal bracket */
                                    d = ABSputs(d,"&lt;");
                                    c = 0;
                                }
                            }
                            else if (c=='>')
                            {
                                d = ABSputs(d,"&gt;");
                                c = 0;
                            }
                            else if ((unsigned char)c>=(unsigned char)128)
                            {
                                char special[16];
                                if ((unsigned char) c == 230)
                                    c = (char)((unsigned char) 181);
                                sprintf(special,"&#%d;",(unsigned char)c);
                                d = ABSputs(d,special);
                                c = 0;
                            }
                            else if (!strnicmp(s-1,"http:// ",7) || !strnicmp(s-1,"ftp:// ",6))     /* http or ftp link */
                            {
                                char    *linkptr;
                                char    link[SPITMAXLINE];

                                s--;
                                linkptr = link;
                                while (isalnum(*s) || *s==':' || *s=='/' || *s=='.' || *s==',' ||
                                    *s=='_' || *s=='-' || *s=='?' || *s=='&' || *s=='#')      /* copy http/ftp link */
                                    *linkptr++ = *s++;
                                *linkptr = '\0';
                                d = ABSputs(d,"<a href=\"");
                                d = ABSputs(d,link);
                                d = ABSputs(d,"\" target=\"_blank\">");
                                d = ABSputs(d,link);
                                d = ABSputs(d,"</a>");
                                c = '\0';
                            }

                        }
                        if (OPTabstype==TYPEPRETEXT)
                            if (c=='@')
                                *d++ = '@';     /* double quote @'s */
                        if (c)
                            d = ABSputc(d,(int)c);
                    }

                    /* remove trailing white spaces */

/*                    while (*(d-1)==(char)' ' || *(d-1)==(char)9) */
/*                        --d; */

                    /* if line is HTML heading, supress nl and following nls */

                    if (OPTabstype==TYPEHTML)
                    {
                        if (!c)
                            d = ABSputc(d,' ');     /* pad if last char was < or > */
                        if (ABSstyle&ABSSTYLEBOLD)
                        {
                            while (*s && *s<=' ')   /* remove blank lines following header */
                                ++s;
                        }
                        else
                            d = ABSputs(d,OPTnl);
                    }
                    else
                        d = ABSputs(d,OPTnl);
                }

                s = source;

                ++linecount;
            }
        }
    }

    if(inabstract)
        ABSerr = ABSERR_NOENDABS;

    return(d);
}

/****************************************************************/
/*  Sort Abstracts Alphabetically                               */
/*  - sorts by primary abstract name                            */
/*  - removes duplicates                                        */
/****************************************************************/

static int isword(char chr)
{
    int c = (int)(unsigned char) chr;   // unsigned for 128..255 range
    if(OPTsrclanguage==LANGUAGEC)
        return(isalnum(c) || c=='_' || c=='.');
    else if(OPTsrclanguage==LANGUAGECPP)
        return(isalnum(c) || c=='_' || c=='.' || c==':' || c=='(' || c==')');
    else
        return(isalnum(c) || c=='_' || c=='.');
}

static int isfilenamechr(char chr)
{
    int c = (int)(unsigned char) chr;   // unsigned for 128..255 range
    return isalnum(c) || (c)=='_' || (c)=='-';
}

static void getfullnamefromman(char *d,char *s,int abstype)
{
    char *dstart=d;

    if (OPTverbose>=6)
    {
        printf("starting fullnamefromman() %lx\n",s);
        SPIT_flush();
    }

    if (abstype==TYPEHTML)
    {
        char *t;

        /* fast forward to <BODY> tag if it exists */
        t = ABSstrstri(s,"<BODY");
        if (t)
            s = t+strlen("<BODY");

        /* fast forward to <TITLE> tag */
        t = ABSstrstri(s,"<TITLE>");
        if (t)
            s = t+strlen("<TITLE>");

        if(!OPTasis)
        {
            /* fast forward to <H1> tag */
            t = ABSstrstri(s,"<H1>");
            if (t)
                s = t+strlen("<H1>");
        }

        if (OPTverbose>=6)
        {
            printf("H4 at %lx\n",s);
            SPIT_flush();
        }
    }

    /* go to start of name */
    while ((unsigned char)*s<=(unsigned char)' ' || *s=='<')
    {
        if (*s=='<')
        {
            while (*s!='>')
                ++s;
        }
        ++s;
    }

    /* scan until end of name */
    while ((unsigned char)*s>(unsigned char)' ' && *s!='(' && *s!='<')
    {
        if(*s!=':')     /* skip by C++-style naming */
            *d++ = *s;

        if (OPTabstype==TYPEHTML || OPTabstype==TYPEEXAMPLE)
            s += 1;
        else
            s += 7;
    }
    *d = 0;

    if (OPTverbose>=6)
    {
        printf("ending fullnamefromman() %s\n",dstart);
        SPIT_flush();
    }

}

static void getnamefromman(char *d,char *s,int abstype)
{
    getfullnamefromman(d,s,abstype);

    if(OPTsrclanguage==LANGUAGECPP || OPTfullname)
        d = ABSstrips(d,d,0);
    else if(OPTasis)
    {
        while (*d!='.') ++d;
    }
    else
        while (*d>' ' && *d!='(' && *d!='.' && *d!='-') ++d;

    if (OPTabstype==TYPEHTML)
        strcpy(d,".htm");
    else if (OPTabstype==TYPEEXAMPLE)
        strcpy(d,".c");
    else
        strcpy(d,".1v");
}

static void getfilefromman(char *d,char *s,int abstype)
{
    char *dend;

    *d = '\0';

    if (abstype==TYPEHTML)
    {
        char *t;
        t = ABSstrstri(s,"<A ID=\"SOURCEFILE\" NAME=\"");
        if (t)
        {
            s = t+strlen("<A ID=\"SOURCEFILE\" NAME=\"");
            dend = ABSstrstri(s,"\">");
            strncpy(d,s,dend-s);
            d[dend-s] = '\0';
        }
    }
}

static void getauthorfromman(char *d,char *s,int abstype)
{
    char *dstart, *dend;

    *d = '\0';

    if (abstype==TYPEHTML)
    {
        dstart = ABSstrstri(s,"<H4>CONTACT</H4>");
        if (dstart)
        {
            dstart = ABSstrstri(dstart,"<PRE>");
            if (dstart)
            {
                dstart = dstart+strlen("<PRE>");
                while (*dstart==' ') dstart++;
                dend = ABSstrstri(dstart,"<A ");
                if (dend)
                {
                    strncpy(d,dstart,dend-dstart-1);
                    d[dend-dstart-1] = '\0';
                }
            }
        }
    }
}

/********************************************************
getexamplefromman:
d       example name, empty if no example
s       source abstract
abstype abstract type
returns:0 if linked example
        1 if unlinked example
        2 if inline example
        3 if no example
********************************************************/

static int getexamplefromman(char *d,char *s,int abstype)
{
    char *dend,*eol;
    int state = 3;

    *d = '\0';

    if (abstype==TYPEHTML)
    {
        char *t;
        t = ABSstrstri(s,"<H4>EXAMPLE</H4>");
        if (t)
        {
            s = t+strlen("<H4>EXAMPLE</H4>");
            eol = ABSstrstri(s,"</PRE>");
            if (eol)
            {
                *eol = '\0';  // temporarily terminate end of line
                /* find .c file: */
                t = ABSstrstri(s,".c");
                if (!t)     // no .c file - assume inline example
                    state = 2;
                else        // check example file
                {
                    do
                    {
                        dend = t+strlen(".c");
                        t--;
                        while(isfilenamechr(*dend)) dend++;
                        while(isfilenamechr(*t))    t--;
                        t++;
                        strncpy(d,t,dend-t);
                        d[dend-t] ='\0';

                        /* is .c file linked?: */
                        if (strnicmp(dend,"</A>",4)==0)
                            state = 0;
                        else
                            state = 1;
                        t = ABSstrstri(dend,".c");
                    }
                    while (t);
                }
                *eol = '<';     // restore
            }
            else
                *d = '\0';
        }
    }

    return state;
}

static char *getheadingfromman(char *s,char *heading,int abstype)
{
    char searchstr[SPITMAXLINE];

    if (OPTabstype==TYPEHTML)
    {
        searchstr[0] = '\0';
        strcat(searchstr,"<H4>");
        strcat(searchstr,heading);
        strcat(searchstr,"</H4>");
    }
    else
        strcpy(searchstr,heading);

    return (ABSstrstri(s,searchstr));
}

static void getcontext(char *s,char *d,int abstype)
{
    int i;

    if (abstype==TYPESGIMAN || abstype==TYPEHTML || abstype==TYPEEXAMPLE)
    {
        getnamefromman(d,s,abstype);
    }
    else
    {
        if (abstype==TYPEMSHLP)
        {
            s += (strlen(".context "));             /* skip ms help .context */
        }
        else if (abstype==TYPEMPWHLP)
        {
            s += 2;                                 /* skip MPW help -<cr> */
        }
        else if (abstype==TYPESTHLP || abstype==TYPEHELPPC)
        {
            s += 1;                                 /* skip ST help @ or HELPPC : */
        }
        else if (abstype==TYPEMACHLP)
        {
            s += 4;                                 /* skip aeKY */
        }
        else if (abstype==TYPEDOC || abstype==TYPEABS
              || abstype==TYPEBRIEFSUM || abstype==TYPEBRIEFNOSUM)
        {
            while (*s!=(char)10 && *s!=(char)13)    /* skip header line */
                ++s;
            while (!(isalnum(*s)))                  /* find first alphanumeric */
                ++s;
        }
        else if (abstype==TYPEUSINDEX || abstype==TYPEXREF)
        {
            s = "";
        }
        else if (abstype==TYPEHTMLINDEX )           /* go to abstract name */
        {
            if(strstr(s,"a href"))
                s = strstr(strstr(s,"a href"),">") + 1;
        }
        else if (abstype==TYPEHTMLINDEXTREE || (abstype==TYPEHHCONTENT && OPTsrclanguage==LANGUAGECPP))        /* skip opening HTML-tag syntax*/
        {
            if(strstr(s,"<!-"))
                s+=3;
        }
        else if (abstype==TYPEHHCONTENT || abstype==TYPEHHINDEX || abstype==TYPEHHCONTENTFLAT || abstype==TYPEHHINDEXFLAT)
        {
            char *tag;
            tag = ABSstrstr(s,"VALUE");             /* find tag for function name */
            if(tag) s=tag;
        }

        /* else TYPEINDEX or TYPEPRETEXT do nothing  (sort on header) */

        if (abstype!=TYPEHTMLINDEXTREE && !(abstype==TYPEHHCONTENT && OPTsrclanguage==LANGUAGECPP))
        {
            i = 0;
            while ((*s>=' ' || *s=='\t') && i<SPITMAXLINE-1)
            {
                *d++ = *s++;
                ++i;
            }
            *d = '\0';
        }
        else        /* abstype==TYPEHTMLINDEXTREE */
        {
            char    *endtag;
            /* search for end of search tag */
            endtag = strstr(s,"->");
            if (endtag)
            {
                strncpy(d,s,endtag-s);
                d += endtag-s;
                *d = '\0';
            }
        }
    }
}

static int sortcomments(int startindex, int endindex, int abstype)
{
    char *a1;
    int  i;
    int  j;
    int  times;
    int  swapped;
    char name1[SPITMAXLINE];
    char name2[SPITMAXLINE];
    int  duplicates;

    if(endindex<startindex)
        return(0);

    /* sort alphabetical based on primary name, case independent */

    times = 0;
    do
    {
        swapped = SPITNO;

        for (i=startindex+times; i<endindex-times; ++i)        /* bottom to top */
        {
            getcontext(abslist[i],name1,abstype);
            getcontext(abslist[i+1],name2,abstype);
            if (strcmp(name1,name2)>0)
            {
                a1 = abslist[i];
                abslist[i] = abslist[i+1];
                abslist[i+1] = a1;
                swapped = SPITYES;
            }
        }

        for (i=endindex-times-1; i>=startindex+times; --i)       /* bottom to top */
        {
            getcontext(abslist[i],name1,abstype);
            getcontext(abslist[i+1],name2,abstype);

            if (strcmp(name1,name2)>0)
            {
                a1 = abslist[i];
                abslist[i] = abslist[i+1];
                abslist[i+1] = a1;
                swapped = SPITYES;
            }
        }

        if (OPTverbose>=4)
        {
            if (!(times&15))
            {
                printf(".");
                SPIT_flush();
            }
        }

        ++times;
    } while (swapped);

    if (OPTverbose>=4)
    {
        printf("\n");
        SPIT_flush();
    }

    /* skip any empty lines... */
    while(startindex<endindex && !abslist[startindex][0])
        startindex++;

    if (OPTabstype == TYPEHTMLINDEX)
    {
        char *header;
        int offset;

        /* remove redundant category headers */
        header = strstr(abslist[startindex],"</H3><PRE>");
        if (header)
        {
            offset = header - abslist[startindex] + strlen("</H3><PRE>");
            for (j=startindex+1;j<=endindex;j++)
            {
                abslist[j] += offset;
            }
        }
    }
    else if (OPTabstype == TYPETERSEHINDEX)
    {
        char *header, *firstabs, *formattag;
        char formattagstr[32];
        int  offset, len, colstaken, colsremain;
/*        int  htmllen = strlen("<a href=\".htm\"><\a>"); */

        firstabs = abslist[startindex];

        /* remove redundant category headers & format into columns */

        header = strstr(abslist[startindex],"</H3><PRE>");
        if (header)
        {
            offset = header - abslist[startindex] + strlen("</H3><PRE>");
            colsremain = COLSPERLINE;
            for(j=startindex;j<=endindex;j++)
            {
                char *namestart;
                char *nameend;

                /* remove redundant category header */
                abslist[j] += offset;

                /* get length of abstract name */
                formattag = strstr(abslist[j],"<b>");
                namestart = strchr(abslist[j],'>')+1;
                if(formattag)
                {
                    namestart += strlen("<b>");
                    strcpy(formattagstr,"</b></a>");
                }
                else
                {
                    strcpy(formattagstr,"</a>");
                }
                nameend = strchr(namestart,'<');
                len = (int)(nameend-namestart);

                /* format into columns */
/*                len = (strlen(abslist[j])-htmllen-COLWIDTH)\2;  \\ abstract name */
                colstaken = len/COLWIDTH + 1;
                colsremain -= colstaken;
                if (colsremain<0)    /* no more room on this line */
                {
                    namestart[strlen(formattagstr)+colstaken*COLWIDTH] = 0; /* cutoff at column end */
/*                    abslist[j][colstaken*COLWIDTH+len+htmllen] = '\0';  \\ cutoff at column end */
                    abslist[j] -= 1;
                    abslist[j][0] = '\n';
                    colsremain=COLSPERLINE-colstaken;
                }
                else if (colsremain==0)  /* at end of line */
                {
                    namestart[strlen(formattagstr)+colstaken*COLWIDTH+0] = '\n';
                    namestart[strlen(formattagstr)+colstaken*COLWIDTH+1] = '\0';
/*                    abslist[j][len*2+htmllen]   = '\n'; */
/*                    abslist[j][len*2+htmllen+1] = '\0'; */
                    colsremain=COLSPERLINE;
                }
                else
                {
                    namestart[strlen(formattagstr)+colstaken*COLWIDTH] = 0; /* cutoff at column end */
/*                    abslist[j][colstaken*COLWIDTH+len+htmllen] = '\0';  \\ cutoff at column end */
                }
            }
        }
        /* cleanup first and last entries */
        abslist[startindex] = firstabs;
        if(abslist[endindex][strlen(abslist[endindex])-1] != '\n')
        {
            abslist[endindex][strlen(abslist[endindex])-1] = '\n';
            abslist[endindex][strlen(abslist[endindex])]   = '\0';
        }
    }
    else if(OPTabstype == TYPEHHCONTENT || OPTabstype == TYPEHHCONTENTFLAT)
    {
        char *header;
        int offset;

        /* remove redundant category headers (yuk! abstract needs a serious rewrite!) */
        header = strstr(abslist[startindex],"<!-C-->\n");

        if (header)
        {
            offset = header - abslist[startindex] + strlen("<!-C-->\n");
            for(j=startindex+1;j<=endindex;j++)
            {
                abslist[j] += offset;
            }
        }
    }

    /* remove duplicates */

    duplicates = 0;
    // DEBUG
    i = startindex;
    j = startindex + 1;
    while (j<=endindex)
    {
        getcontext(abslist[i],name1,abstype);
        getcontext(abslist[j],name2,abstype);

        if (strcmp(name1,name2))
            abslist[++i] = abslist[j];
        else
            duplicates++;
        ++j;
    }
    j=i+1;
    while (j<=endindex)
    {
        abslist[j] = &(abslist[startindex][strlen(abslist[startindex])]);
        ++j;
    }

    if((OPTabstype == TYPEHHCONTENT || OPTabstype == TYPEHHCONTENTFLAT) && endindex>=startindex)
    {
        sprintf(abslist[endindex-duplicates]+strlen(abslist[endindex-duplicates])-8, "\n</UL>\n");
        levelnum--;
    }

    return(duplicates);
}

/****************************************************************/
/*  Cross Reference Documentation                               */
/*  -makes link for any 'word' in cross reference file          */
/****************************************************************/

static char *getlink(char *xfile, char *search, HASH *hasher)
{
    char *replace;
    char searchbuf[SPITMAXLINE];

    if(!xfile)
        return((char*)0);

    if (OPTignorecase)
    {
        char *t=searchbuf;
        while (*search)
        {
            *t = (unsigned char) tolower(*search);
            ++t;
            ++search;
        }
        *t = 0;
        search = searchbuf;
    }

    if (OPTverbose>=6)
    {
        printf("getlink '%s'\n",search);
        SPIT_flush();
    }


    replace = (char *) HASH_check(hasher,search);
    if ((intptr_t)replace==(intptr_t)-1)
        replace = 0;

    if (OPTverbose>=6 && replace)
    {
        printf("getlink returned %s\n",replace);
        SPIT_flush();
    }

    return(replace);
}

static HASH *preprocessxfile(char *xfile, HASH *hasher)
{
    char *search;
    char *replace;
    char *alt;

    if (!xfile)
        return(0);

    if (!hasher)
        hasher = HASH_init(65536);

    while (*xfile)
    {
        search = xfile;
        while ((unsigned char)*xfile>=(unsigned char)' ' && *xfile!=',')
        {
            if (OPTignorecase)
                *xfile = (unsigned char) tolower(*xfile);
            ++xfile;
        }

        replace = 0;
        if (*xfile==',')
        {
            *xfile++ = 0;
            replace = xfile;
            while ((unsigned char)*xfile>=(unsigned char)' ' && *xfile!=',')
            {
                ++xfile;
            }
        }

        alt = 0;
        if (*xfile==',')
        {
            *xfile++ = 0;
            alt = xfile;
            while ((unsigned char)*xfile>=(unsigned char)' ' && *xfile!=',')
            {
                ++xfile;
            }
        }

        if (*xfile)
            *xfile++ = 0;
        if (*xfile==(char)10 || *xfile==(char)13)
            *xfile++ = 0;
        if (replace)
        {
            if (OPTverbose>=6)
            {
                printf("addlink '%s' to '%s'\n",search,replace);
                SPIT_flush();
            }

            HASH_add(hasher,search,(int)(intptr_t)replace);
        }
    }

    return(hasher);
}

static int ishtmlword(char chr)
{
    int c = (int)(unsigned char) chr;   // unsigned for 128..255 range
    return isalnum((c))||(c)=='_'||(c)=='.'||(c)=='<'||(c)=='>';
}

/*
crossreferences an abstract with tags in crossreference and/or glossary file.
if OPTabstype==TYPEHTMLNOABS crossreferences content that is in a HTML format
and not in abstract format.
*/

static int crossreference(char *xfile, char *gfile)
{
    int i;
    int j;
    int refs=0;
    int ok;
    int ishtml;
    char *s;
    char *s1;
    char *d;
    char *dest;
    char *link=0;
    char *xlink=0;
    char *glink=0;
    char *alt=0;
    char absname[SPITMAXLINE];
    char wordbuf[SPITMAXLINE];
    char twowordbuf[SPITMAXLINE];
    int  linelen=0;
    int  wordlen=0;
    HASH *glossed=0;

    if (OPTverbose>=6)
        printf("reffile %s; glossaryfile %s\n",xfile,gfile);

    xlinkhasher = preprocessxfile(xfile,xlinkhasher);
    glinkhasher = preprocessxfile(gfile,glinkhasher);

    if(OPTabstype==TYPEHTMLNOABS)
        absn=1;

    for (i=0; i<absn; ++i)
    {
        s = abslist[i];
        d = dest = openabstract((char *)0,ABSMAX,6);

        glossed = HASH_init(16384);

        if(OPTabstype!=TYPEHTMLNOABS)
        {
            getcontext(s,absname,OPTabstype);
            if (strchr(absname,'.'))
                *strchr(absname,'.') = 0;

            if (OPTverbose>=6)
            {
                printf("starting abstract #%d '%s'\n",i, absname);
                SPIT_flush();
            }
        }

        if(OPTabstype==TYPEHTMLNOABS)
        {
            while (*s)  /* dumb fast forward to HTML body (assumes it exists) */
            {
                if (!strnicmp(s,"<body",5))
                {
                    for(j=0;j<5;j++) *d++ = *s++;
                    while(*s!='>') *d++ = *s++;
                    *d++ = *s++;
                    break;
                }
                else
                    *d++ = *s++;
            }
        }
        else    // OPTabstype!=TYPEHTMLNOABS
        {
            /* fast forward to <BODY> tag if it exists */
            char *skipstr = ABSstrstri(s,"<body");
            if (skipstr)
            {
                strncpy(d,s,skipstr-s);
                d += skipstr-s;
                s += skipstr-s;
            }

            /* fast forward to </TITLE> tag */
            skipstr = ABSstrstri(s,"</title>");
            if (skipstr)
            {
                skipstr += strlen("</title>");
                strncpy(d,s,skipstr-s);
                d += skipstr-s;
                s += skipstr-s;
            }
            else    /* copy first line OPTasis */
            {
                while (*s && *s>=' ')
                    *d++ = *s++;
            }

            linelen = 0;
        }

        while (*s)
        {
            {
                while (*s && !ishtmlword(*s))   /* copy white spaces and HTML markups OPTasis */
                {
                    if(*s=='\n') linelen = 0;
                    else linelen++;
                    *d++ = *s++;    /* copy white spaces */
                }
            }

            ishtml = 0;

            if ((OPTabstype==TYPEHTMLNOABS && !strnicmp(s,"<a",2) && !isword(*(s+2))) || /* HTML anchor, skip to end */
                (OPTabstype!=TYPEHTMLNOABS && !strnicmp(s-1,"<a",2) && !isword(*(s+1))) )
            {
                char *endstr;

                endstr = ABSstrstri(s,"</a>");
                if (endstr)
                {
                    endstr += strlen("</a>");
                    while(s<endstr)
                        *d++ = *s++;
                }
            }
            else if (*s=='<' || *(s-1)=='<' || !strnicmp(s-1,"</",2))        /* start of HTML markup - skip it */
            {
                while(*s && *s!='>')    /* find matching '>' */
                    *d++ = *s++;
                *d++ = *s++;
            }
            else if (*s=='>' || *(s-1)=='>')   /* greater-than character, skip it */
            {
                *d++ = *s++;
            }

            // DEBUG: Need this? else    /* normal text found */
            s1 = s;
            j = 0;
            while (*s1 && isword(*s1))  /* find next word */
            {
                wordbuf[j++] = *s1++;
            }
            wordbuf[j] = 0;
            wordlen = strlen(wordbuf);
            if(OPTlinewidth && (linelen+wordlen > OPTlinewidth))
            {
                int i,spaces;
                *d++ = '\n';
                spaces = 4+OPTlineindent;
                for(i=0;i<spaces;i++)
                    *d++ = ' ';
                linelen = 0;
            }
            else
            {
                linelen += wordlen;
            }

            ok = 0;
            if (isword(wordbuf[0])
             && j>=2
             && strncmp(s-4,"<H1>",4))
            {

                // get 2nd word
                {
                    char *s2 = s1;
                    char *d2;

                    strcpy(twowordbuf,wordbuf);
                    d2 = twowordbuf+strlen(twowordbuf);
                    while (*s2 && !isword(*s2))   /* copy white spaces OPTasis */
                    {
                        if(*s2=='\n') break;
                        *d2++ = *s2++;
                    }

                    if (isword(*s1))
                    {
                        while (*s2 && isword(*s1))  /* find next word */
                        {
                            *d2++ = *s2++;
                        }
                    }
                    else
                        strcpy(twowordbuf,wordbuf);

                    *d2 = 0;
                }

                if (wordbuf[j-1]=='.') /* remove period */
                {
                    --s1;
                    --j;
                }
                wordbuf[j] = 0;

//printf("twowords %s\n",twowordbuf);
                if(OPTsrclanguage==LANGUAGECPP || OPTfullname)
                {
                    char strippedwordbuf[SPITMAXLINE];

                    ABSstrips(strippedwordbuf,twowordbuf,1);
                    xlink = getlink(xfile,strippedwordbuf,xlinkhasher);
                    glink = getlink(gfile,strippedwordbuf,glinkhasher);
                    if (!xlink && !glink)
                    {
                        ABSstrips(strippedwordbuf,wordbuf,1);
                        xlink = getlink(xfile,strippedwordbuf,xlinkhasher);
                        glink = getlink(gfile,strippedwordbuf,glinkhasher);
                    }
                    else
                        strcpy(wordbuf,twowordbuf);
                }
                else
                {
                    xlink = getlink(xfile,twowordbuf,xlinkhasher);
                    glink = getlink(gfile,twowordbuf,glinkhasher);
                    if (!xlink && !glink)
                    {
                        xlink = getlink(xfile,wordbuf,xlinkhasher);
                        glink = getlink(gfile,wordbuf,glinkhasher);
                    }
                    else
                        strcpy(wordbuf,twowordbuf);
                }

                if (xlink)
                    link = xlink;
                else if (glink)
                    link = glink;
                else
                    link = (char *)0;

                if (link)
                {
                    if(OPTabstype!=TYPEHTMLNOABS)
                    {
                        char linkname[256];
                        SPIT_getname(linkname,link);
                        if (strcmp(linkname,absname))
                            ok = 1;
                        else
                            ok = 2;
                    }
                    else    // OPTabstype==TYPEHTMLNOABS
                        ok = 1;

                    alt = link+strlen(link)+1;
                    if (!*alt)
                        alt = link;
                }
            }
            if (ok)
            {
/*                if (isgt) */
/*                    *d++ = '&'; */
                if (ok==2)  /* self reference.. make bold\italic */
                {
                    sprintf(d,"<i><b>%s</b></i>",wordbuf);
                }
                else
                {
                    if (link)
                    {
                        /* html cross reference as is */
                        if (link[0]=='<')
                            strcpy(d,link);
                        /* http: ftp: or mailto: link */
                        else if (!strnicmp(link,"http:",5) || !strnicmp(link,"ftp:",4) || !strnicmp(link,"mailto:",7))
                            sprintf(d,"<a %shref=\"%s\" title=\"%s\" target=\"_blank\">%s</a>",(!xlink&&glink)?"CLASS=\"glossary\" ":"",link,alt,wordbuf);
                        /* openfile JavaScript link (see openfile JavaScript code in prefix.htm) */
                        else if (!strnicmp(link,"openfile(",9))
                            sprintf(d,"<a onclick=\"%s\" title=\"%s\" style=\"text-decoration: none; color:#003399; cursor: hand\">%s</a>",link,alt,wordbuf);
                        /* implied local link */
                        else
                        {
                            char eghiliteword[256];
                            if ( strstr(link,"_eg") || strstr(link,"_demo") || strstr(link,"_test") || strstr(link,"_time") )
                                sprintf (eghiliteword, " onclick='setkeyword(\"%s\");'", absname);
                            else
                                eghiliteword[0] = '\0';
                            sprintf(d,"<a %shref=\"%s.htm\" title=\"%s\"%s>%s</a>",(!xlink&&glink)?"CLASS=\"glossary\" ":"",link,alt,eghiliteword,wordbuf);
                        }
                    }
                    ++refs;
                }
            }
            else
                strcpy(d,wordbuf);

            d += strlen(d);
            s = s1;
        }
        if (OPTverbose>=4)
        {
            if (!(i&15))
            {
                printf(".");
                SPIT_flush();
            }
        }
        if (OPTverbose>=6)
        {
            printf("done abstract #%d '%s'\n",i, absname);
        }
        SPIT_flush(); /* sleep */

        HASH_purge(glossed);
        d = closeabstract(d);
        abslist[i] = dest;
    }

    if (OPTverbose)
    {
        printf("%d references, ",refs);
        SPIT_flush();
    }

    return(1);
}

/****************************************************************/
/*  Save Comments                                               */
/*  - writes out 1 or more files with abstracts                 */
/****************************************************************/

static int ABSwritestr(GSTREAM *g,char *str)
{
    return(gwrite(g,str,strlen(str)));
}

static int savecomments(const char *fname,int abstype)
{
    int  ok;
    int  i;
    int  j;
    int  numberleft;
    int  numberdothisfile;
    char *x;
    char *indexptr;
    char destname[SPITMAXLINE];
    char lastname[SPITMAXLINE];
    char statbuf[SPITMAXLINE];
    char destpath[SPITMAXLINE];
    char fullnamebuf[SPITMAXLINE];
    char filenamebuf[SPITMAXLINE];
    char authorbuf[SPITMAXLINE];
    char examplebuf[SPITMAXLINE];
    GSTREAM *fhdl;

    ok = SPITYES;
    i = 0;
    numberleft = absn;
    strcpy(destname, fname);
    SPIT_getpath(destpath,fname);

    indexptr = destname;
    if (numberleft > OPTabsperfile)
    {
        SPIT_changeext( destname,fname, "");        /* remove the extension */
        strcat(destname, "0");                  /* add index of 0 to name */
        indexptr = destname+(strlen(destname))-1;   /* point to index */

        x = (char *)strrchr(fname,'.');                 /* find extension */
        if (x)
        {
            strcat(destname, x);                /* join it to new indexed name */
        }
    }

    if (abstype==TYPESGIMAN || abstype==TYPEHTML || abstype==TYPEEXAMPLE)
        destname[0] = 0;
    while (numberleft>0)
    {
        numberdothisfile = numberleft;          /* number of abstract to write */
        if (numberdothisfile > OPTabsperfile)
            numberdothisfile = OPTabsperfile;

        if (abstype==TYPESGIMAN || abstype==TYPEHTML || abstype==TYPEEXAMPLE)
        {
            numberdothisfile = 1;
            strcpy(lastname,destname);
            getnamefromman(statbuf,abslist[i],abstype);
            getfullnamefromman(fullnamebuf,abslist[i],abstype);
            getfilefromman(filenamebuf,abslist[i],abstype);
            if (!filenamebuf[0])
                strcpy(filenamebuf,"filename???");
            getauthorfromman(authorbuf,abslist[i],abstype);
            if (!authorbuf[0])
                strcpy(authorbuf,"author???");

            if (OPTverbose>=3)
            {
                /* check for missing sections */
                if(!getheadingfromman(abslist[i],"SUMMARY",abstype))
                {
                    fprintf(OPTerrorfile,"Warning: [%s] Missing SUMMARY section (Abstract: %s, File: %s)\n",authorbuf,fullnamebuf,filenamebuf);
                }
                if(!getheadingfromman(abslist[i],"EXAMPLE",abstype))
                {
                   fprintf(OPTerrorfile,"Warning: [%s] Missing EXAMPLE section (Abstract: %s, File: %s)\n",authorbuf,fullnamebuf,filenamebuf);
                }
                else
                {
                    int egstate = getexamplefromman(examplebuf,abslist[i],abstype);
                    switch (egstate)
                    {
                        case 0:
                            break;
                        case 1:
                            fprintf(OPTerrorfile,"Warning: [%s] Unlinked example %s (Abstract: %s, File: %s)\n",authorbuf,examplebuf,fullnamebuf,filenamebuf);
                            break;
                        case 2:
                            fprintf(OPTerrorfile,"Warning: [%s] No external example (Abstract: %s, File: %s)\n",authorbuf,fullnamebuf,filenamebuf);
                            break;
                        case 3:
                            fprintf(OPTerrorfile,"Warning: [%s] Missing example (Abstract: %s, File: %s)\n",authorbuf,fullnamebuf,filenamebuf);
                            break;
                        default:
                            break;
                    }
                }
                if(!getheadingfromman(abslist[i],"SEE ALSO",abstype))
                    fprintf(OPTerrorfile,"Warning: [%s] Missing SEE ALSO section (Abstract: %s, File: %s)\n",authorbuf,fullnamebuf,filenamebuf);
            }

            SPIT_changepath( destname,statbuf, destpath);

            if (!strncmp(lastname,destname,8))
            {
                char t;
                x = strrchr(lastname,'.');              /* find extension */
                t = *(x+1);
                x = strrchr(destname,'.');
                *(x+1) = (char)(t+1);
            }
        }

        if (OPTverbose)
        {
            if (OPTverbose>=4)
                printf("Writing: %s\n",destname);
            else
            {
                if (OPTverbose>=2)
                    printf("Writing: %s\n",SPIT_getname( statbuf,destname));
            }
            SPIT_flush();
        }

        fhdl = gwopen(destname);
        if (!fhdl)
        {
            if (OPTverbose>=2)
                fprintf(OPTerrorfile, "abstract - ERROR OPEN FILE '%s' FOR WRITE\n",destname);
        }
        else
        {
            /* write out abstracts */
            for (j=0; j<numberdothisfile; ++j)
            {
                if (!ABSwritestr(fhdl,abslist[i]) && abslist[i][0])
                {
                    ok = SPITNO;
                    j = numberdothisfile;
                    numberleft = 0;
                    break;
                }
                ++i;
                --numberleft;
            }

            gclose(fhdl);
        }

        if (abstype==TYPESGIMAN)
        {
            strcat(destname,"f");
            fhdl = gwopen(destname);
            getfullnamefromman(statbuf,abslist[i-1],abstype);
            ABSwritestr(fhdl,statbuf);
            if (fhdl)
                gclose(fhdl);

        }
        else if (numberleft>0)
            ++*indexptr;                        /* increment file name index */
    }

    return(ok);
}

static char *ABSgetdate(char *dateptr)
{
    char  *timeptr;
    time_t curtime;
    int    timelen;

    time(&curtime);
    timeptr = ctime(&curtime);
    strcpy(dateptr,timeptr);

    timelen = (int) strlen(dateptr);            /* remove the cr/lf at end */
    while (timelen)
    {
        if (dateptr[timelen-1]<' ')
            dateptr[--timelen] = '\0';
        else
            timelen = 0;
    }
    return(dateptr);
}

#if 0
/*
;
; ABSTRACT
;
; abstract - read abstracts from source files, sort, and write
;            a documentation file
;
; SUMMARY
;
; abstract -options destfile[.doc] [files]
;   @file     response file, containing a list of options and files
;   =file     specify a output file ie abstract source=dest
;   -t0       plain text file doc
;   -t1       Microsoft Quick Help file
;   -t2       Mac 411 help file
;   -t3       MPW help file
;   -t4       ST help file
;   -t5       abstract file
;   -t6       brief plain text file doc unsorted
;   -t7       brief plain text file doc unsorted with no summary
;   -t8       Help PC file
;   -t9       PS PreText format for printed documentation
;   -t10      Raw index file
;   -t11      Unsorted index file
;   -t12      SGI man online help files
;   -t13      HTML Pages
;   -t14      HTML Index
;   -t15      Cross reference file (for -p)
;   -t16      Terse HTML Index
;   -t17      Stock Ticker HTML
;   -t18      HTML Page (input HTML, no abstract)
;   -t19      HTML Help 1.1 Contents
;   -t20      HTML Help 1.1 Index
;   -t21      Extract examples
;   -t22      HTML Help 1.1 Contents (Flat directory)
;   -t23      HTML Help 1.1 Index (Flat directory)
;   -t24      Hierarchial HTML Index
;   -g0       parse abstracts as C-style functions
;   -g1       parse abstracts as hierarchial C++
;   -l0       unlinked category heading (default)
;   -l1       link category heading (-t14,-t16) to overview file
;   -l2       link category heading (-t14,-t16) to overview file
;   -l3       no headings (-t14,-t16)
;   -l4       link category heading (-t14,-t16) to overview file without icon
;   -l5       link category heading (-t14,-t16) to local overview file without icon
;   -i        ignore case for cross references
;   -r<file>  cross reference file (-t15 to generate one)
;   -g<file>  glossary cross reference file (-t15 to generate one)
;   -p<file>  HTML prefix file (prefixed into each html abstract)
;   -q<file>  author file (initial,fullname format)
;   -n<n>     number of abstracts per file (default 1000)
;   -m<n>     number of columns for word wrap (default none)
;   -o<n>     number of spaces for indenting word wrap (default 0)
;   -a        parse abstract from entire file (i.e. no 'ABSTRACT' tag required)
;   -k        keep C/C++-style comments within abstract
;   -u0       truncate names at periods and hyphens (default)
;   -u1       keep full name with periods and hyphens
;   -nologo   disable banner
;   -v0       no console output
;   -v1       prints source file name and errors
;   -v2       status line for each file (default)
;   -v3       additional info
;   -w0       don't output file
;   -w1       output to file (default)
;   -e<file>  output errors to file
;   -r        recurse subdirectories
;   -z        HTML font size
;   -x<plat>  platform name
;   -l<lib>   library name
;
; DESCRIPTION
;
; This reads each source file and scans for abstracts.  The abstracts
; are sorted by name and written to either a single output file or
; one file per abstract.  Abstracts are expected to be in one of two
; formats.  The IBM format uses the key words 'ABSTRACT' and
; 'END ABSTRACT' while the Amiga/Atari style uses '$$$' to both
; start and end abstracts.  In either case the abstract delimiters
; must be surrounded by white spaces.
;
; RETURNS
;
; no return code
;
; SEE ALSO
;
; remheadr.exe(ibm) Spit
;
; SAMPLE OUTPUT
;
; >abstract c*.c =temp.doc
;
;   Abstract v1.78 (EXtreme) 931105 by FrANK Barchard, EAC
;   cmp.c: Reading, Parsing, 9532->1469 (84.6%)
;   crc.c: Reading, Parsing, 5724->678 (88.2%)
;   Sorting, Writing: temp.doc
;
; END ABSTRACT
;
*/
#endif

/****************************************************************/
/*  Spit Routines                                               */
/****************************************************************/

void SPIT_reset(void)
{
    OPTabstype = 13;
    OPTignorecase = 0;
    OPTlinkhead = 0;
    OPTabsperfile = 1000;
    strcpy(OPTnl, SPITNL);
    catagory[0] = (char) '\0';
    previouscatagory[0] = (char) '\0';
    rating[0] = (char) '\0';
    authorinitial[0] = (char) '\0';
    OPTcrossreffile.ptr = 0;
    OPTglossaryfile.ptr = 0;
    OPTprefixfile.ptr = 0;
    OPTsuffixfile.ptr = 0;
    OPTcymbalfile.ptr = 0;
    OPTauthorfile.ptr = 0;
    OPTerrorfile = stderr;
    OPTplatformname[0] = '\0';
    OPTlibraryname[0] = '\0';
    OPTlinewidth = 0;
    OPTlineindent = 0;
    OPTasis = 0;
    OPTkeepcomments = 1;
    OPTfullname = 0;
    newcatagory = SPITNO;
    OPTsrclanguage = LANGUAGEC;
    OPTfontsize = 0;
    OPTopera = 1;
    OPTdot = '.'; // enable . options
    ABSerr = 0;
    abslinecount = 0;
    if(xlinkhasher)
    {
        HASH_purge(xlinkhasher);
        xlinkhasher = 0;
    }
    if(glinkhasher)
    {
        HASH_purge(glinkhasher);
        glinkhasher = 0;
    }
    return;
}

void SPIT_usage(const char *prgname,const char *envname,const char *urlname,int utype)
{
    printf("Abstract v%s ",TextVersion);
    printf("by FrANK Barchard, EAC\n");

    if (utype>=3)
    {
            puts("");
          printf("VERSION: %s v%s, Spit v%.2f\n",SPIT_MACHINE,TextVersion,(float)SPIT_VERSION/100.0f);
            puts("SUMMARY: Abstract reads test files and extracts documentation");
            puts("         in abstract form, generating online help or test documents.");
          printf("         SPIT environment variable is %s\n",envname);
            puts("");
    }
    if (utype)
        printf("USAGE: %s -options destfile[.doc] [files]\n", prgname);

    switch (utype)
    {
        case 0:
        case 1:
            break;

        case 2:
            puts("    -i ignore case on cross reference");
            puts("    -r cross reference file      -p prefix file");
            puts("    -t type of abstract          -n number of abstracts per file");
            puts("    -v verbose                   -w write file");
            puts("     @ response file              = output file");
            puts("    -r recurse subdirectories");
          printf("type '%s -h' for more help\n", prgname);
          printf("type '%s -help' for web page\n", prgname);
            break;

        case 3:
            puts("    @file     response file, containing a list of options and files");
          printf("    =file     specify a output file ie %s source=dest\n", prgname);
            puts("    -t0       plain text file doc");
            puts("    -t1       Microsoft Quick Help file");
            puts("    -t2       Mac 411 help file");
            puts("    -t3       MPW help file");
            puts("    -t4       ST help file");
            puts("    -t5       abstract file");
            puts("    -t6       brief plain text file doc unsorted");
            puts("    -t7       brief plain text file doc unsorted with no summary");
            puts("    -t8       Help PC file");
            puts("    -t9       PS PreText format for printed documentation");
            puts("    -t10      Raw index file");
            puts("    -t11      Unsorted index file");
            puts("    -t12      SGI man online help files");
            puts("    -t13      HTML Pages");
            puts("    -t14      HTML Index");
            puts("    -t15      Cross reference file (for -p)");
            puts("    -t16      Terse HTML Index");
            puts("    -t17      Stock Ticker HTML");
            puts("    -t18      HTML Page (input HTML, no abstract)");
            puts("    -t19      HTML Help 1.1 Contents");
            puts("    -t20      HTML Help 1.1 Index");
            puts("    -t21      Extract examples");
            puts("    -t22      HTML Help 1.1 Contents (Flat directory)");
            puts("    -t23      HTML Help 1.1 Index (Flat directory)");
            puts("    -t24      Hierarchial HTML Index");
            puts("    -g0       parse abstracts as C-style functions");
            puts("    -g1       parse abstracts as hierarchial C++");
            puts("    -l0       unlinked category heading (default)");
            puts("    -l1       link category heading (-t14,-t16) to overview file");
            puts("    -l2       link category heading (-t14,-t16) to overview file");
            puts("    -l3       no headings (-t14,-t16)");
            puts("    -l4       link category heading (-t14,-t16) to overview file without icon");
            puts("    -l5       link category heading (-t14,-t16) to local overview file without icon");
            puts("    -i        ignore case for cross references");
            puts("    -h<c>,<a>,<r> c=catagory, a=author, r=rating");
            puts("    -r<file>  HTML cross reference file (-t15 to generate one)");
            puts("    -g<file>  HTML glossary cross reference file (-t15 to generate one)");
            puts("    -p<file>  HTML prefix file (prefixed into each html abstract)");
            puts("    -s<file>  HTML suffix file (appened onto each html abstract)");
            puts("    -q<file>  author file (initial,fullname format)");
            puts("    -c<file>  Cymbal file (appended by function)");
            puts("    -n<n>     number of abstracts per file (default 1000)");
            puts("    -m<n>     number of columns for word wrap (default none)");
            puts("    -a        parse abstract from entire file (i.e. no 'ABSTRACT' tag required)");
            puts("    -k        keep C/C++-style comments within abstract");
            puts("    -u0       truncate names at periods and hyphens (default)");
            puts("    -u1       keep full name with periods and hyphens");
            puts("    -o<n>     number of spaces for indenting word wrap (default 0)");
            puts("    -nologo   disable banner");
            puts("    -v0       no console output");
            puts("    -v1       prints source file name and errors");
            puts("    -v2       status line for each file (default)");
            puts("    -v3       additional info");
            puts("    -w0       don't output file");
            puts("    -w1       output to file (default)");
            puts("    -e<file>  output errors to file");
            puts("    -r        recurse subdirectories");
            puts("    -z        HTML font size");
            break;

        default:
            break;
    }
}

char *SPIT_opt(const char *optptr)
{
    const char *d=NULL;
    char optchar;

    optchar = (char)(*optptr|(char)' ');
    switch (optchar)
    {
        case 'a':
            if (!strnicmp(optptr, "abs", 3))
            {
                OPTasis = !OPTasis;
                d = SPIT_getopt( &OPTasis,optptr+3, "abstract files", 0, 1);
                OPTasis = !OPTasis;
            }
            else
            {
                d = SPIT_getopt( &OPTasis,optptr+1, "create abstract w/o 'ABSTRACT' tag", 0, 1);
            }
            break;

        case 'c':
        {
            char cymbalfile[SPITMAXLINE];

            d = SPIT_getstropt( cymbalfile,optptr+1, "cymbal file", "", SPITYES, 80);
            SPIT_loadfile(&OPTcymbalfile, cymbalfile);
            if (OPTverbose>=3)
                printf("cymbal file %s %d bytes\n",cymbalfile,&OPTcymbalfile.len);
            break;
        }

        case 'e':
        {
            char errorfile[SPITMAXLINE];

            d = SPIT_getstropt( errorfile,optptr+1, "output error file", "", SPITYES, 80);
            OPTerrorfile = fopen(errorfile,"w");
            break;
        }

        case 'g':
        {
            if (isdigit(*(optptr+1)))
                d = SPIT_getopt( &OPTsrclanguage,optptr+1, "source language", 0, 1);
            else
            {
                char glossaryfile[SPITMAXLINE];

                d = SPIT_getstropt( glossaryfile,optptr+1, "glossary cross reference file", "", SPITYES, 80);
                SPIT_loadfile(&OPTglossaryfile, glossaryfile);
            }
            break;
        }

        case 'h':
            if (OPTabstype!=TYPEHTMLINDEXTREE && !(OPTabstype==TYPEHHCONTENT && OPTsrclanguage==LANGUAGECPP))
            {
                             d = SPIT_getfield( catagory,optptr+1,1,0);
                if (*d==',') d = SPIT_getfield( authorinitial,d+1,1,0);
                if (*d==',') d = SPIT_getfield( rating,d+1,1,0);
            }
            break;

        case 'i':
            d = SPIT_getopt( &OPTignorecase,optptr+1, "ignore case on cross reference file", 0, 1);
            break;

        case 'k':
            d = SPIT_getopt( &OPTkeepcomments,optptr+1, "do not strip comments within abstract", 0, 1);
            break;

        case 'l':
        {
            if (isdigit(*(optptr+1)) && *(optptr+2)<=' ')
                d = SPIT_getopt( &OPTlinkhead,optptr+1, "linked headings (html indexes)", 0, 5);
            else
            {
                d = SPIT_getstropt(OPTlibraryname,optptr+1, "library name", "", SPITYES, 80);
                strupr(OPTlibraryname);
            }
            break;
        }

        case 'm':
            d = SPIT_getopt( &OPTlinewidth,optptr+1, "maximum columns", 0, 10000);
            break;

        case 'n':
            d = SPIT_getopt( &OPTabsperfile,optptr+1, "abstracts per file", 0, 10000);
            break;

        case 'o':
            if (!strnicmp(optptr,"opera",5))
            {
                d = SPIT_getopt( &OPTopera,optptr+5, "opera add space at eol", 0, 1);
            }
            else
            {
                d = SPIT_getopt( &OPTlineindent,optptr+1, "line indent", 0, 10000);
            }
            break;

        case 'p':
        {
            char prefixfile[SPITMAXLINE];

            d = SPIT_getstropt( prefixfile,optptr+1, "prefix file", "", SPITYES, 80);
            SPIT_loadfile(&OPTprefixfile, prefixfile);
            break;
        }


        case 'q':
        {
            char authorfile[SPITMAXLINE];

            d = SPIT_getstropt( authorfile,optptr+1, "author file", "", SPITYES, 80);
            SPIT_loadfile(&OPTauthorfile, authorfile);
            if (OPTverbose>=3)
                printf("author file %s %d bytes\n",authorfile,&OPTauthorfile.len);
            break;
        }

        case 'r':
        {
            char crossreffile[SPITMAXLINE];

            d = SPIT_getstropt( crossreffile,optptr+1, "cross reference file", "", SPITYES, 80);
            SPIT_loadfile(&OPTcrossreffile, crossreffile);
            break;
        }

        case 's':
        {
            char suffixfile[SPITMAXLINE];

            d = SPIT_getstropt( suffixfile, optptr+1, "suffix file", "", SPITYES, 80);
            SPIT_loadfile(&OPTsuffixfile, suffixfile);
            break;
        }

        case 't':
            if (!strnicmp(optptr, "txt", 3))
            {
                d = SPIT_getopt( &OPTasis,optptr+3, "text files as is", 0, 1);
            }
            else
            {
                d = SPIT_getopt( &OPTabstype,optptr+1, "abstract type", 0, 24);
                if (OPTabstype!=TYPEMSHLP)
                    OPTabsperfile = 10000;
            }
            break;

        case 'u':
            d = SPIT_getopt( &OPTfullname,optptr+1, "keep periods and hypens in name", 0, 1);
            break;

        case 'x':       /* platform name */
            d = SPIT_getstropt( OPTplatformname,optptr+1, "platform name", "", SPITYES, 80);
            strupr(OPTplatformname);
            break;


        case 'z':
            d = SPIT_getopt( &OPTfontsize,optptr+1, "HTML font size", 0, 7);
            break;

        default:
            break;
    }
    return((char *)d);
}

int main(int argc,char **argv)
{
    int more;
    int i;
    int errors=0;
    SPITMEM infile;
    char statbuf[SPITMAXLINE];
    char destname[SPITMAXLINE];
    char *d;
    int  oldabsn;
    int  fileswithabs;
    int totallen;
    int flen;
    int  namelen;
    char datebuf[SPITMAXLINE];
    GSTREAM *fhdl;
    int  duplicates = 0;

    SPIT_init(SPIT_reset, SPIT_usage, SPIT_opt, SPIT_history);
    do
    {
        more = SPIT_parse(argc, argv, TOOL_NAME, TOOL_VERSION);

        {
            int i=0;

            memset(OPTnl,0,sizeof(OPTnl));
            strcpy(OPTnl, SPITNL);
            strcpy(stmpwchr,"@");

            if (OPTopera)
                OPTnl[i++] = (char) ' ';

            if (OPTabstype==TYPEMACHLP || OPTabstype==TYPEMPWHLP)  /* set type of NL for help files */
            {
                stmpwchr[0] = '-';
                stmpwchr[1] = 13;
                stmpwchr[2] = 0;
                OPTnl[i++] = (char) 13;
                OPTnl[i++] = (char) 0;
            }
            else if (OPTabstype==TYPESTHLP || OPTabstype==TYPEMSHLP || OPTabstype==TYPEHELPPC)
            {
                OPTnl[i++] = (char) 13;
                OPTnl[i++] = (char) 10;
                OPTnl[i++] = (char) 0;
            }
            else if (OPTabstype==TYPESGIMAN)  /* set type of NL for unix text */
            {
                OPTnl[i++] = (char) 10;
                OPTnl[i++] = (char) 0;
            }
            else if (OPTabstype==TYPEHTML || OPTabstype==TYPEHTMLINDEX || OPTabstype==TYPEHTMLINDEXTREE  || OPTabstype==TYPEXREF ||
                OPTabstype==TYPETERSEHINDEX || OPTabstype==TYPEHHCONTENT || OPTabstype==TYPEHHINDEX ||
                OPTabstype==TYPEHHCONTENTFLAT || OPTabstype==TYPEHHINDEXFLAT || OPTabstype==TYPEEXAMPLE)
            {
                OPTnl[i++] = (char) 13;
                OPTnl[i++] = (char) 10;
                OPTnl[i++] = (char) 0;
            }
            else if (OPTabstype==TYPETICKER)
            {
                OPTnl[i++] = (char) 0;
            }
        }


        if (OPTverbose>=6)
            printf("nl %d %d %d\n",OPTnl[0],OPTnl[1],OPTnl[2]);

        if (SPITargnum)
        {
            initcymbal(OPTcymbalfile.ptr);

            strcpy(destname,SPITsargv[0]);
            if (!strchr(destname,'.'))
                SPIT_changeext(destname,destname,"htm");

            switch (OPTabstype)
            {
                case TYPEDOC:           strcpy(statbuf, "Doc");             break;
                case TYPEMSHLP:         strcpy(statbuf, "Microsoft Help");  break;
                case TYPEMACHLP:        strcpy(statbuf, "Mac 411 Help");    break;
                case TYPEMPWHLP:        strcpy(statbuf, "Mac MPW Help");    break;
                case TYPESTHLP:         strcpy(statbuf, "ST Help");         break;
                case TYPEABS:           strcpy(statbuf, "Abstract");        break;
                case TYPEBRIEFSUM:      strcpy(statbuf, "Brief Doc");       break;
                case TYPEBRIEFNOSUM:    strcpy(statbuf, "Brief Doc with No Summary");   break;
                case TYPEHELPPC:        strcpy(statbuf, "Help PC");         break;
                case TYPEPRETEXT:       strcpy(statbuf, "PreText Doc");     break;
                case TYPEINDEX:         strcpy(statbuf, "Index");           break;
                case TYPEUSINDEX:       strcpy(statbuf, "Unsorted Index");  break;
                case TYPESGIMAN:        strcpy(statbuf, "SGI Man");         break;
                case TYPEHTML:          strcpy(statbuf, "HTML Pages");      break;
                case TYPEHTMLINDEX:     strcpy(statbuf, "HTML Index");      break;
                case TYPEHTMLINDEXTREE: strcpy(statbuf, "Hierarchial HTML Index");      break;
                case TYPEXREF:          strcpy(statbuf, "Cross Reference"); break;
                case TYPETERSEHINDEX:   strcpy(statbuf, "Terse HTML Index");break;
                case TYPETICKER:        strcpy(statbuf, "Stock Ticker HTML");break;
                case TYPEHTMLNOABS:     strcpy(statbuf, "Non-abstract HTML Pages"); break;
                case TYPEHHCONTENT:     strcpy(statbuf, "HTML Help 1.1 Contents");  break;
                case TYPEHHINDEX:       strcpy(statbuf, "HTML Help 1.1 Index");     break;
                case TYPEHHCONTENTFLAT: strcpy(statbuf, "HTML Help 1.1 Contents (Flat)");   break;
                case TYPEHHINDEXFLAT:   strcpy(statbuf, "HTML Help 1.1 Index (Flat)");      break;
                case TYPEEXAMPLE:       strcpy(statbuf, "Extract examples");        break;
            }

            if (OPTverbose>=3)
                printf("Building %s <%s>\n",statbuf, destname);

            absn = 0;
            OPTasis = 0;
            dynan = 0;
            if (OPTabstype==TYPETICKER || !stricmp(destname,".txt") || OPTasis)
                OPTasis = 1;
            d = openabstract((char *) 0, ABSMAX, OPTverbose);
            if (d)
            {
                ABSgetdate(datebuf);
                totallen = 0L;
                fileswithabs = 0;
                absnstart = 0;
                absnend = 1;
                levelnum = 0;
                for (i=1; i<SPITargnum; ++i)
                {
                    bool isopt = false;
                    if (SPITsargv[i][0]=='-' || SPITsargv[i][0]=='+' || (SPITsargv[i][0]=='.' && SPITsargv[i][1]!='.' && SPITsargv[i][1]!='/' && SPITsargv[i][1]!='\\'))
                        isopt = Zop(SPITsargv[i]+1)?true:false;
                    else if (SPITsargv[i][0]=='=')
                        isopt = Zop(SPITsargv[i])?true:false;

                    if (!isopt)
                    {
                        infile.ptr = (char *) 0;
                        infile.len = 0;
                        if (OPTasis)
                        {
                            printf(SPIT_loadstr(statbuf, SPITsargv[i],OPTverbose));
                            SPIT_flush();

                            fhdl = gopen(SPITsargv[i]);
                            if (fhdl)
                            {
                                flen = (int)glen(fhdl);
                                if (flen>=0L)
                                {
                                    if (flen > ABSMAX)  /* truncate if too big */
                                        flen = ABSMAX;

                                    if (SPIT_alloc(&infile, flen+80L))
                                    {
                                        sprintf(infile.ptr,"\n$$$\n@%s\n\n", SPIT_getname( statbuf,SPITsargv[i]));
                                        namelen = (int) strlen(infile.ptr);
                                        gread(fhdl,infile.ptr+namelen, flen);
                                        strcpy((infile.ptr+namelen+flen),"\n$$$\n");
                                    }
                                }
                                gclose(fhdl);
                            }
                            else
                            {
                                if (OPTverbose)
                                    printf("abstract - FILE '%s' NOT FOUND\n", SPITsargv[i]);
                                ++errors;
                            }

                        }
                        else
                        {
                            SPIT_loadfile(&infile, SPITsargv[i]);
                        }

                        if (infile.ptr)
                        {
                            if (OPTverbose>=3)
                            {   printf("Parsing, ");
                                SPIT_flush();
                            }
                            oldabsn = absn;
                            abslen = 0L;
                            if (OPTabstype!=TYPEHTMLNOABS)
                                d = parsecomments(datebuf, SPITsargv[i], SPITdargv[i], &infile, d);
                            else
                            {
                                d = openabstract(d, infile.len, OPTverbose);           /* reserve memory */
                                memcpy(d,infile.ptr,infile.len);
                                d[infile.len] = '\0';
                                abslist[absn] = d;
                                absn = 1;
                            }
                            SPIT_free(&infile);

                            if(ABSerr==ABSERR_NOENDABS)
                            {
                                printf("\nERROR: An 'ABSTRACT' in file %s has no matching 'END ABSTRACT'!  Aborting...", SPIT_getname( statbuf,SPITsargv[i]));
                                exit(1000);
                            }

                            if (d)
                            {
                                totallen += abslen;
                                if (abslen)
                                    ++fileswithabs;

                                /* print some stats */

                                if (OPTverbose>=3)
                                {
                                    if (OPTverbose>=4)
                                    {
                                        printf("%d abstracts, ", absn-oldabsn);
                                        SPIT_percentstr(statbuf, infile.len, abslen);
                                        printf("%d->%d (%s)\n", infile.len, abslen, statbuf);
                                        SPIT_flush();
                                    }
                                    else
                                    {
                                        printf("%d->%d (%d)\n", infile.len, abslen,absn-oldabsn);
                                    }
                                }
                            }
                            else
                                i = SPITargnum;

                            /* KPW - check if catagory ended */
                            if (newcatagory==SPITYES || i>=SPITargnum-1)
                            {
                                if (OPTverbose>=6)
                                {
                                    printf("sorting category\n");
                                    SPIT_flush();
                                }
                                if(OPTabstype == TYPEHTMLINDEX || OPTabstype == TYPEHTMLINDEXTREE || OPTabstype == TYPETERSEHINDEX || OPTabstype == TYPEHHCONTENT || OPTabstype == TYPEHHCONTENTFLAT)
                                {
                                    /* let's sort abstracts within category alphabetically */
                                    if(newcatagory)
                                    {
                                        duplicates = sortcomments(absnstart,absnend-1,OPTabstype);
                                    }
                                    if(duplicates)
                                    {
                                        absn -= duplicates;
                                        oldabsn -= duplicates;
                                        absnend -= duplicates;
                                    }

                                    absnstart = absnend;    /* save position of first abstract of new category */
                                    newcatagory = SPITNO;
                                }
                            }
                        }
                    }

                }

                /* sort the last category */
                if(OPTabstype==TYPEHTMLINDEXTREE || (OPTabstype==TYPEHHCONTENT && OPTsrclanguage==LANGUAGECPP)) absnstart--;
                if(OPTabstype == TYPEHTMLINDEX || OPTabstype == TYPEHTMLINDEXTREE || OPTabstype == TYPETERSEHINDEX || OPTabstype == TYPEHHCONTENT || OPTabstype == TYPEHHCONTENTFLAT)
                {
                    duplicates = sortcomments(absnstart,absn-1,OPTabstype);
                }

                /* check if closing </UL> is needed (for TYPEHHCONTENT & TYPEHHCONTENTFLAT) */
                if(OPTabstype == TYPEHHCONTENT || OPTabstype == TYPEHHCONTENTFLAT)
                {
                    while (levelnum>0)
                    {
                        sprintf(abslist[absn-duplicates-1]+strlen(abslist[absn-duplicates-1]), "</UL>\n");
                        levelnum--;
                    }
                }

                if (d)
                {
                    if (absn && OPTwrite)
                    {
                        if (OPTabstype!=TYPEUSINDEX
                         && OPTabstype!=TYPEHTMLINDEX
                         && OPTabstype!=TYPEHTMLINDEXTREE
                         && OPTabstype!=TYPEXREF
                         && OPTabstype!=TYPETERSEHINDEX
                         && OPTabstype!=TYPEHTML
                         && OPTabstype!=TYPEHTMLNOABS
                         && OPTabstype!=TYPETICKER
                         && OPTabstype!=TYPEHHCONTENT
                         && OPTabstype!=TYPEHHINDEX
                         && OPTabstype!=TYPEHHCONTENTFLAT
                         && OPTabstype!=TYPEHHINDEXFLAT
                         && OPTabstype!=TYPEEXAMPLE)
                        {
                            if (OPTverbose>=3)
                            {   printf("Sorting, ");
                                SPIT_flush();
                            }
                            sortcomments(0,absn-1,OPTabstype);
//                            absn = i+1;  // bugzilla 1538
                        }

                        if (OPTabstype==TYPEHHINDEX || OPTabstype==TYPEHHINDEXFLAT)
                        {
                            if (OPTverbose>=3)
                            {   printf("Sorting, ");
                                SPIT_flush();
                            }
                            sortcomments(0,absn-1,OPTabstype);
                        }

                        if (OPTcrossreffile.ptr || OPTglossaryfile.ptr)
                        {
                            if (OPTabstype==TYPEHTML)
                            {
                                if (OPTverbose>=3)
                                {   printf("Cross Referencing, ");
                                    SPIT_flush();
                                }

                                crossreference(OPTcrossreffile.ptr,OPTglossaryfile.ptr);
                            }
                            else if (OPTabstype==TYPEHTMLNOABS)
                            {
                                if (OPTverbose>=3)
                                {   printf("Cross Referencing, ");
                                    SPIT_flush();
                                }

                                crossreference(OPTcrossreffile.ptr,OPTglossaryfile.ptr);
                            }
                        }

                        if (!savecomments(destname,OPTabstype))
                        {
                            if (OPTverbose>=2)
                                fprintf(OPTerrorfile, "ERROR: Could not save abstract\n");
                            ++errors;
                        }
                    }
                    if (OPTverbose>=4)
                    {
                        printf("TOTAL: %d files with abstracts, %d abstracts, %d bytes, %d lines\n", fileswithabs, absn, totallen, abslinecount);
                    }

                }

                for (i=0; i<dynan; ++i)
                    SPIT_free(&dynamem[i]);
            }
        }

        if (OPTcrossreffile.ptr)
            SPIT_free(&OPTcrossreffile);
        if (OPTglossaryfile.ptr)
            SPIT_free(&OPTglossaryfile);
        if (OPTprefixfile.ptr)
            SPIT_free(&OPTprefixfile);
        if (OPTsuffixfile.ptr)
            SPIT_free(&OPTsuffixfile);
        if (OPTcymbalfile.ptr)
            SPIT_free(&OPTcymbalfile);
        if (OPTauthorfile.ptr)
            SPIT_free(&OPTauthorfile);

    } while (more>0);

    return(errors);
}

