/*
 *  ChkTeX v1.4, header file for main program.
 *  Copyright (C) 1995-96 Jens T. Berger Thielemann
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 *  Contact the author at:
 *              Jens Berger
 *              Spektrumvn. 4
 *              N-0666 Oslo
 *              Norway
 *              E-mail: <jensthi@ifi.uio.no>
 *
 *
 */

/********************************************************************/
/**************** START OF USER SETTABLE PREFERENCES ****************/

/*
 * Note: This file contains most defines you'll wish to change if you
 * wish to adopt ChkTeX to a new system. It is, as you might notice,
 * heavily documented. If you wish to get into the internals of ChkTeX,
 * the interesting stuff is at the bottom of this file, and in the .c
 * files. However, you should also take a look at the "config.h.in" file 
 * in this directory if you haven't got a shell able to run the "configure"
 * script.
 * 
 * This program relies heavily on that the system which
 * automagically free()'s all malloc()'ed memory, works. The program
 * itself does not call free() very much. This is because we're doing
 * lots of tiny allocations, and a properly designed pooling system will
 * hopefully do a quicker job than we'll be able to do. So there.
 *
 * To keep things simple, we trust that the fclose()'ing of fopen()'ed
 * also happens automagically.
 *
 * Please use the getopt included, as we will modify optarg during
 * command processing.
 *
 * You may wish to modify the SetupVars() (OpSys.c) to better suit your
 * preferences. In any case, it should put the filename (and full path)
 * of the `.chktexrc' file into the ConfigFile array. The array is sized
 * BUFSIZ bytes.
 *
 * The program does also assume that AMIGA is defined if the source
 * compiled on an Amiga machine, and that __unix__ is defined if the
 * source is compiled on a UNIX machine.
 *
 */


/*  -=><=- -=><=- -=><=- -=><=- -=><=- -=><=- -=><=- -=><=- -=><=-  */

/*
 * Here you should define what codes which should be returned to the
 * shell upon success/failure.
 *
 */

#ifndef EXIT_FAILURE
#   ifdef  AMIGA
#       define  EXIT_FAILURE    20
#   else
#       define  EXIT_FAILURE    1
#   endif
#endif

#ifndef EXIT_SUCCESS
#   define  EXIT_SUCCESS    0
#endif

/*  -=><=- -=><=- -=><=- -=><=- -=><=- -=><=- -=><=- -=><=- -=><=-  */

/*
 * SLASH should be defined to the character your computer uses to
 * separate files/directories. Most systems use '/', messydos uses
 * '\'.
 *
 * DIRCHARS should be defined to the characters a directory entry
 * may end on. On Amigas, this is ":/" (either "FOO:BAR/" or "FOO:"),
 * Unix uses only "/", while messydos uses ":\\".
 *
 * This data will be used to automatically concatenate a directory
 * path and a filename.
 *
 * Adjust both to suit your needs.
 */


#if defined(__unix__) || defined(AMIGA)
#   define  SLASH           '/'
#elif defined(__MSDOS__)
#   define SLASH '\\'
#endif

#if defined(__unix__)
#   define DIRCHARS "/"
#elif defined(AMIGA)
#   define DIRCHARS ":/"
#elif defined(__MSDOS__)
#   define DIRCHARS ":\\"
#endif

/*  -=><=- -=><=- -=><=- -=><=- -=><=- -=><=- -=><=- -=><=- -=><=-  */

/*
 * Here, define what key-combination which is used to abort stdin
 * keyboard input. It should be a string, as we we'll type it out as
 * information to the user.
 */

#ifdef AMIGA
#    define STDIN_BREAK "Ctrl-\\"
#elif defined(__unix__)
#    define STDIN_BREAK "Ctrl-D"
#elif defined(__MSDOS__)
#    define STDIN_BREAK "Ctrl-Z + Enter"
#else
#    define STDIN_BREAK "stdin break combination"
#endif

/*  -=><=- -=><=- -=><=- -=><=- -=><=- -=><=- -=><=- -=><=- -=><=-  */

/*
 * For fancy printing of commands, we'll use these strings to turn
 * on/off the error indication. The codes listed here are ANSI
 * compatible; if you don't have that type of terminal, you may wish
 * to adjust this. Use "chktex -v2 Test.tex" to check the effects of
 * these macros. Note: These strings will be printf()'ed, so watch your
 * %'s.
 *
 * On VT10[02] terminals, these values will be ignored; we'll use
 * the sequence "_\b%c" for each character instead.
 *
 * PRE_ERROR_STR is of course printed in front of each location we
 * wish to show as an error, and POST_ERROR_STR after each location.
 *
 * The codes #defined here, will switch back- and foreground colours.
 * We're using '\033[' as escape character, some terminals may like
 * '\233' better.
 *
 */

#define PRE_ERROR_STR   "\033[7m"
#define POST_ERROR_STR  "\033[0m"

/*  -=><=- -=><=- -=><=- -=><=- -=><=- -=><=- -=><=- -=><=- -=><=-  */

/*
 * The next macro should contain a list of characters LaTeX (and you?)
 * considers as an end-of-sentence characters, which should be
 * detected when whether sentence spacing is correct.
 *
 */

#define LATEX_PUNCT             ".:?!"


/*  -=><=- -=><=- -=><=- -=><=- -=><=- -=><=- -=><=- -=><=- -=><=-  */

/*
 * The next macro should contain a list of characters LaTeX (and you?)
 * considers as an small punctuation characters, which should not be
 * preceded by a \/.
 */

#define SMALL_PUNCT             ".,"



/*  -=><=- -=><=- -=><=- -=><=- -=><=- -=><=- -=><=- -=><=- -=><=-  */

/*
 * NOTE: All macros below should return FALSE (0) if the input
 * character is 0.
 *
 * The next macro should return TRUE if the character should be
 * stripped from a string, e.g. if it is a space, tab, control
 * character or any other `invisible' character.
 *
 */

#define SKIP_STRIP(c)   (c > 0 && c <= ' ')

/*  -=><=- -=><=- -=><=- -=><=- -=><=- -=><=- -=><=- -=><=- -=><=-  */

/*
 * The next macro should return TRUE if LaTeX (and you?) considers
 * the character `c' as a space, which should be detected when
 * we're checking whether commands are terminated by spaces.
 *
 */

#define LATEX_SPACE(c)  (c > 0 && c <= ' ')


/***************** END OF USER SETTABLE PREFERENCES *****************/
/********************************************************************/

#if defined(HAVE_CONFIG_H) || defined(CONFIG_H_NAME)
#   ifndef CONFIG_H_NAME
#       define  CONFIG_H_NAME   "config.h"
#   endif
#   include CONFIG_H_NAME
#   ifndef HAVE_VPRINTF
#       error "Sorry, I need the vprintf function...please send info on doprnt"
#   endif
#endif

#include <ctype.h>
#include <math.h>
#include <stdio.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdlib.h>

#ifdef HAVE_UNISTD_H
#   include <unistd.h>
#endif

#ifdef HAVE_LIMITS_H
#    include <limits.h>
#else
#    define LONG_MAX (0x7fffffff)
#endif

#include <string.h>

#ifdef AMIGA
#   include <exec/execbase.h>
#   include "WB2Argv.h"
#endif

#include "exec/types.h"
#include "getopt.h"

#ifndef __NOPROTO
#   ifndef __PROTO
#       define __PROTO(a) a
#   endif
#else
#   ifndef __PROTO
#       define __PROTO(a) ()
#   endif
#endif


/*
 * How many indexes we'll allocate first time
 */
#define MINPUDDLE       256


/*
 * How many bytes we want in front/end of each UBYTE buffer.
 */

#define WALLBYTES       2

#define betw(a,b,c)             ((a < b) && (b < c))
#define within(a,b,c)   ((a <= b) && (b <= c))
#define elif                    else if

#ifndef NOT
#   define NOT(a)                   (!(a))
#endif
#define ifn(a)                  if(NOT(a))

#ifndef min
#   define min(a,b) ((a)<=(b)?(a):(b))
#endif

#ifndef max
#   define max(a,b) ((a)>(b)?(a):(b))
#endif

#ifndef abs
#   define abs(a) (a>=0?a:(-a))
#endif

#define QUOTE   '\"'	/* Char used to quote text containing blanks	*/
#define ESCAPE  '!'     /* Char used to access special characters       */
#define CMNT    '#'     /* Char used as comment                         */


#define STRP_LFT                        1
#define STRP_RGT                        2
#define STRP_BTH                        (STRP_LFT|STRP_RGT)

#define NUMBRACKETS             6

#define NEWBUF(name,len) \
static \
UBYTE   _##name         [len  + (WALLBYTES<<1)] = {0};  \
const STRPTR    name =          &_##name[WALLBYTES]


enum ErrNum
{
  emMinFault = 0,
  emSpaceTerm, emNBSpace, emEnclosePar, emItInNoIt,
  emItDup,  emNoItFound, emAccent,  emWrongDash,
  emExpectC,  emSoloC,  emEllipsis,  emInterWord,
  emInterSent, emNoArgFound, emNoMatchC,  emMathStillOn,
  emNoMatchCC, emUseQuoteLiga, emUseOtherQuote,emUserWarn,
  emNotIntended, emComment,  emThreeQuotes, emFalsePage,
  emEmbrace,  emSpacePunct, emNoCmdExec, emItPunct,
  emUseTimes, emMultiSpace, emIgnoreText, emBeginQ,
  emEndQ, emQuoteMix, emWordCommand,
  emMaxFault
};

enum PrgErrNum {
  pmMinFault = 0,

  pmUnknownTerm, pmNoFileMatch, pmNoTeXOpen, pmRename,
  pmRenameErr, pmOutOpen,  pmOutTwice,  pmStrDupErr,
  pmWordListErr, pmNoStackMem, pmWarnNumErr, pmVerbLevErr,
  pmNotPSDigit, pmEscCode,  pmKeyWord,  pmFaultFmt,
  pmRsrcOpen, pmSlowAbbr, pmEmptyToken, pmAssert,
  pmNoRsrc,

  pmMaxFault,
};

enum Context {
    ctNone    = 0x00,
    ctInMath  = 0x01,
    ctOutMath = 0x02,
    ctInHead  = 0x04,
    ctOutHead = 0x08
};

struct  ErrMsg {
    enum ErrNum   Number;
    enum {
        etMsg,
        etWarn,
        etErr
    }             Type;

    BOOL  InUse;
    /* Requirements posed upon environment */
    enum Context Context;

    STRPTR        Message;
};

struct Stack {
  APTR  *Data;
  ULONG Size, Used;
};

struct WordList {
    struct Stack  Stack;
    BOOL          Sorted;
};

struct ErrInfo {
  STRPTR
        Data,
        LineBuf,
        File;
  ULONG Line,
  Column,
  ErrLen;
};

enum ItState {
  itOff,
  itOn,
  itCorrected
};

enum DotLevel {
  dtUnknown = 0x0,
  dtCDots = 0x1,
  dtLDots = 0x2,
  dtDots = 0x4
};

struct FileNode {
  STRPTR        Name;
  FILE  *fh;
  ULONG Line;
};

extern const STRPTR
    ReadBuffer,
    CmdBuffer,
    TmpBuffer;

extern BOOL
        AtLetter,  /* Whether `@' is a letter or not. */
        InHeader,  /* Whether we're in the header */
        VerbMode;  /* Whether we're in complete ignore-mode */

extern LONG
        MathMode;  /* Whether we're in math mode or not	*/


extern UBYTE   ConfigFile[BUFSIZ];

extern struct WordList
        Silent, Abbrev, SlowAbbrev, Linker, IJAccent, Italic,
        ItalCmd, UserWarn, CmdLine, PostLink, WipeArg, VerbEnvir,
        MathEnvir, MathRoman, TeXInputs, HyphDash, NumDash, WordDash,
        CenterDots, LowDots, OutFormat;

extern STRPTR VerbClear, PrgName;

extern
struct Stack
CharStack,
InputStack,
EnvStack;

extern struct ErrMsg
    LaTeXMsgs [emMaxFault + 1],
	PrgMsgs [pmMaxFault + 1];

extern const
    UBYTE BrOrder[NUMBRACKETS + 1];

extern
    ULONG Brackets  [NUMBRACKETS];

extern enum TermType TermType;

extern
  ULONG ErrPrint,  /* # errors printed */
        WarnPrint, /* # warnings printed */
        UserSupp;  /* # user suppressed warnings */

extern
enum ItState
ItState;

extern FILE *OutputFile, *InputFile;

extern STRPTR
        OutputName,
        PseudoInName,
        Delimit;

extern
    BOOL GlobalRC, WipeVerb, TicToc, BackupOut,
         Quiet, LicenseOnly, UsingStdIn, InputFiles,
         HeadErrOut;

extern
    STRPTR
        OutputFormat;


void    AddBracket      __PROTO((UBYTE const));
LONG    BrackIndex      __PROTO((UBYTE const));

FILE *  CurStkFile      __PROTO((struct Stack *));
STRPTR  CurStkName      __PROTO((struct Stack *));
ULONG   CurStkLine      __PROTO((struct Stack *));

BOOL    fexists         __PROTO((STRPTR Filename));
STRPTR  FGetsStk        __PROTO((STRPTR Dest, ULONG len, struct Stack *stack));
BOOL    FindErr         __PROTO((STRPTR const, ULONG const));
void    FreeErrInfo     __PROTO((struct ErrInfo* ei));

STRPTR  GetLTXArg       __PROTO((STRPTR, STRPTR, const UBYTE));

BOOL    HasWord         __PROTO((STRPTR const, struct WordList *));

BOOL    InsertWord      __PROTO((STRPTR const, struct WordList *));

int     main            __PROTO((int argc, char **argv));
UBYTE   MapChars        __PROTO((STRPTR *));
UBYTE   MatchBracket    __PROTO((UBYTE const));
STRPTR  MatchFileName   __PROTO((STRPTR String));

BOOL    OpenOut         __PROTO((void));

int     ParseArgs       __PROTO((int argc, char **argv));
int     ParseBoolArg    __PROTO((BOOL *, STRPTR *));
int     ParseNumArg     __PROTO((LONG *, LONG, STRPTR *));
enum ErrNum
        PerformCommand  __PROTO((STRPTR const, STRPTR));
struct ErrInfo *
        PopErr          __PROTO((struct Stack *Stack));
void    PrintError      __PROTO((const  STRPTR,
                                const STRPTR, const LONG, const LONG,
                                const LONG, const enum ErrNum, ...));
void    PrintPrgErr     __PROTO((enum PrgErrNum , ...));
void    PrintStatus     __PROTO((ULONG));
BOOL    PushChar        __PROTO((const UBYTE c, const ULONG Line,
                                const ULONG Column, struct Stack *Stk,
                                const STRPTR LineCpy));
BOOL    PushErr         __PROTO((const STRPTR Data, const ULONG Line,
                                const ULONG Column, const ULONG ErrLen,
                                const STRPTR LineCpy, struct Stack *Stk));
BOOL    PushFile        __PROTO((STRPTR, FILE *, struct Stack *));
BOOL    PushFileName    __PROTO((STRPTR Name, struct Stack *stack));

void *  saferealloc     __PROTO((void *, size_t));
void    strwrite        __PROTO((STRPTR To, STRPTR From, ULONG Len));
BOOL    ReadRC          __PROTO((STRPTR const));

void    SetupVars       __PROTO((void));
APTR    sfmemset        __PROTO((APTR to, int c, LONG n));
int     ShiftArg        __PROTO((STRPTR *Argument));
void    ShowIntStatus   __PROTO((void));
APTR    StkPop          __PROTO((struct Stack *));
BOOL    StkPush         __PROTO((const APTR, struct Stack *));
APTR    StkTop          __PROTO((struct Stack *));

int     strafter        __PROTO((STRPTR Str, STRPTR Cmp));
int     strinfront      __PROTO((STRPTR Str, STRPTR Cmp));
STRPTR  strip           __PROTO((STRPTR, WORDBITS const));
void    strrep          __PROTO((STRPTR, UBYTE const, UBYTE const));
int     str_cmp         __PROTO((void const *, void const *));

void    tackon          __PROTO((STRPTR, const STRPTR));
void    tictoc          __PROTO((void));
struct ErrInfo *
        TopChar         __PROTO((struct Stack *));
struct ErrInfo *
        TopErr          __PROTO((struct Stack *Stack));



#ifndef HAVE_STRMID
#   define  strmid  mystrmid

WORD    mystrmid          __PROTO((const STRPTR source, STRPTR dest,
                                ULONG pos, LONG len));
#endif

#ifndef  HAVE_STRUPR
#   define  strupr  mystrupr

STRPTR  mystrupr          __PROTO((STRPTR));
#endif

#ifndef  HAVE_STRDUP
#   define  strdup  mystrdup

STRPTR  mystrdup          __PROTO((STRPTR const));
#endif

#ifndef HAVE_STRCASECMP
int strcasecmp(char* a, char* b);
#endif


