summaryrefslogtreecommitdiff
path: root/Build/source/utils/chktex/chktex-1.6.6/FindErrs.c
diff options
context:
space:
mode:
Diffstat (limited to 'Build/source/utils/chktex/chktex-1.6.6/FindErrs.c')
-rw-r--r--Build/source/utils/chktex/chktex-1.6.6/FindErrs.c1537
1 files changed, 1537 insertions, 0 deletions
diff --git a/Build/source/utils/chktex/chktex-1.6.6/FindErrs.c b/Build/source/utils/chktex/chktex-1.6.6/FindErrs.c
new file mode 100644
index 00000000000..45a6b02bfe5
--- /dev/null
+++ b/Build/source/utils/chktex/chktex-1.6.6/FindErrs.c
@@ -0,0 +1,1537 @@
+/*
+ * ChkTeX, error searching & report routines.
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contact the author at:
+ * Jens Berger
+ * Spektrumvn. 4
+ * N-0666 Oslo
+ * Norway
+ * E-mail: <jensthi@ifi.uio.no>
+ *
+ *
+ */
+
+
+#include "ChkTeX.h"
+#include "FindErrs.h"
+#include "OpSys.h"
+#include "Utility.h"
+#include "Resource.h"
+
+/***************************** ERROR MESSAGES ***************************/
+
+#undef MSG
+#define MSG(num, type, inuse, ctxt, text) {num, type, inuse, ctxt, text},
+
+struct ErrMsg LaTeXMsgs[emMaxFault + 1] = {
+ ERRMSGS {emMaxFault, etErr, iuOK, 0, INTERNFAULT}
+};
+
+#define istex(c) (isalpha((unsigned char)c) || (AtLetter && (c == '@')))
+#define CTYPE(func) \
+static int my_##func(int c) \
+{ \
+ return(func(c)); \
+}
+
+#define INUSE(c) (LaTeXMsgs[(enum ErrNum) c].InUse == iuOK)
+
+#define PSERR2(pos,len,err,a,b) \
+ PrintError(CurStkName(&InputStack), RealBuf, pos, len, Line, err, a, b)
+
+#define PSERRA(pos,len,err,a) \
+ PrintError(CurStkName(&InputStack), RealBuf, pos, len, Line, err, a)
+
+#define HEREA(len, err, a) PSERRA(BufPtr - Buf - 1, len, err, a)
+#define PSERR(pos,len,err) PSERRA(pos,len,err,"")
+
+#define HERE(len, err) HEREA(len, err, "")
+
+#define SKIP_BACK(ptr, c, check) \
+ while((c = *ptr--)) \
+ { \
+ if (!(check)) break; \
+ } \
+ ptr++;
+
+#define SKIP_AHEAD(ptr, c, check) \
+ while((c = *ptr++)) \
+ { \
+ if (!(check)) \
+ break; \
+ } \
+ ptr--;
+
+
+/* -=><=- -=><=- -=><=- -=><=- -=><=- -=><=- -=><=- -=><=- -=><=- */
+
+/*
+ * A list of characters LaTeX considers as an end-of-sentence characters, which
+ * should be detected when whether sentence spacing is correct.
+ *
+ */
+static const char LTX_EosPunc[] = { '.', ':', '?', '!', 0 };
+
+/*
+ * General punctuation characters used on your system.
+ */
+static const char LTX_GenPunc[] = { ',', ';', 0 };
+
+/*
+ * A list of characters LaTeX considers as an small punctuation characters,
+ * which should not be preceded by a \/.
+ */
+static const char LTX_SmallPunc[] = { '.', ',', 0 };
+
+
+static unsigned long Line;
+
+static const char *RealBuf;
+static char *LineCpy;
+static char *BufPtr;
+
+static int ItFlag = efNone;
+
+NEWBUF(Buf, BUFSIZ);
+NEWBUF(CmdBuffer, BUFSIZ);
+NEWBUF(ArgBuffer, BUFSIZ);
+
+static enum ErrNum PerformCommand(const char *Cmd, char *Arg);
+
+#ifdef isdigit
+CTYPE(isdigit)
+#else
+# define my_isdigit isdigit
+#endif
+
+#ifdef isalpha
+CTYPE(isalpha)
+#else
+# define my_isalpha isalpha
+#endif
+
+/*
+ * Reads in a TeX token from Src and puts it in Dest.
+ *
+ */
+
+
+static char *GetLTXToken(char *Src, char *Dest)
+{
+ int Char;
+
+ if (Src && *Src)
+ {
+ if (*Src == '\\')
+ {
+ *Dest++ = *Src++;
+ Char = *Dest++ = *Src++;
+
+ if (istex(Char))
+ {
+ while (istex(Char))
+ Char = *Dest++ = *Src++;
+
+ Src--;
+ Dest--;
+ }
+
+ }
+ else
+ *Dest++ = *Src++;
+ *Dest = 0;
+ }
+ else
+ Src = NULL;
+
+ return (Src);
+}
+
+
+/*
+ * Scans the `SrcBuf' for a LaTeX arg, and puts that arg into `Dest'.
+ * `Until' specifies what we'll copy. Assume the text is
+ * "{foo}bar! qux} baz".
+ * GET_TOKEN => "{foo}"
+ * GET_STRIP_TOKEN => "foo"
+ * '!' => "{foo}bar!" (i.e. till the first "!")
+ * Returns NULL if we can't find the argument, ptr to the first character
+ * after the argument in other cases.
+ *
+ * If one of the tokens found is in the wl wordlist, and we're in the
+ * outer most paren, and Until isn't a single character, we'll stop.
+ * You may pass NULL as wl.
+ *
+ * We assume that you've previously skipped over leading spaces.
+ *
+ */
+
+#define GET_TOKEN 256
+#define GET_STRIP_TOKEN 257
+
+static char *GetLTXArg(char *SrcBuf, char *OrigDest, const int Until,
+ struct WordList *wl)
+{
+ char *Retval;
+ char *TmpPtr;
+ char *Dest = OrigDest;
+ unsigned long DeliCnt = 0;
+
+ *Dest = 0;
+ TmpPtr = SrcBuf;
+
+ switch (Until)
+ {
+ case GET_STRIP_TOKEN:
+ case GET_TOKEN:
+ while ((Retval = GetLTXToken(TmpPtr, Dest)))
+ {
+ switch (*Dest)
+ {
+ case '{':
+ DeliCnt++;
+ break;
+ case '}':
+ DeliCnt--;
+ }
+ Dest += Retval - TmpPtr;
+ TmpPtr = Retval;
+
+ if (!DeliCnt || ((DeliCnt == 1) && wl && HasWord(Dest, wl)))
+ break;
+ }
+
+ if (Retval && (*OrigDest == '{') && (Until == GET_STRIP_TOKEN))
+ {
+ int len = strlen(OrigDest+1);
+ memmove(OrigDest, OrigDest + 1, len + 1);
+ /* Strip the last '}' off */
+ OrigDest[len-1] = 0;
+ }
+ break;
+ default:
+ DeliCnt = TRUE;
+ while ((Retval = GetLTXArg(TmpPtr, Dest, GET_TOKEN, NULL)))
+ {
+ if (*Dest == Until)
+ DeliCnt = FALSE;
+
+ Dest += Retval - TmpPtr;
+ TmpPtr = Retval;
+
+ if (!DeliCnt)
+ break;
+ }
+ break;
+ }
+ *Dest = 0;
+
+ return (Retval);
+}
+
+
+static char *MakeCpy(void)
+{
+ if (!LineCpy)
+ LineCpy = strdup(RealBuf);
+
+ if (!LineCpy)
+ PrintPrgErr(pmStrDupErr);
+
+ return (LineCpy);
+}
+
+static char *PreProcess(void)
+{
+ /* First, kill comments. */
+
+ char *TmpPtr;
+
+ strcpy(Buf, RealBuf);
+
+ TmpPtr = Buf;
+
+ while ((TmpPtr = strchr(TmpPtr, '%')))
+ {
+ if (TmpPtr == Buf || TmpPtr[-1] != '\\')
+ {
+ PSERR(TmpPtr - Buf, 1, emComment);
+ *TmpPtr = 0;
+ break;
+ }
+ TmpPtr++;
+ }
+ return (Buf);
+}
+
+/*
+ * Interpret environments
+ */
+
+static void PerformEnv(char *Env, int Begin)
+{
+ static char VBStr[BUFSIZ] = "";
+
+ if (HasWord(Env, &MathEnvir))
+ {
+ MathMode += Begin ? 1 : -1;
+ MathMode = max(MathMode, 0);
+ }
+
+ if (Begin && HasWord(Env, &VerbEnvir))
+ {
+ VerbMode = TRUE;
+ strcpy(VBStr, "\\end{");
+ strcat(VBStr, Env);
+ strcat(VBStr, "}");
+ VerbStr = VBStr;
+ }
+}
+
+static char *SkipVerb(void)
+{
+ char *TmpPtr = BufPtr;
+ int TmpC;
+
+ if (VerbMode && BufPtr)
+ {
+ if (!(TmpPtr = strstr(BufPtr, VerbStr)))
+ BufPtr = &BufPtr[strlen(BufPtr)];
+ else
+ {
+ VerbMode = FALSE;
+ BufPtr = &TmpPtr[strlen(VerbStr)];
+ SKIP_AHEAD(BufPtr, TmpC, LATEX_SPACE(TmpC));
+ if (*BufPtr)
+ PSERR(BufPtr - Buf, strlen(BufPtr) - 2, emIgnoreText);
+ }
+ }
+ return (TmpPtr);
+}
+
+#define CHECKDOTS(wordlist, dtval) \
+for(i = 0; (i < wordlist.Stack.Used) && !(Back && Front); i++) \
+ { if(!strafter(PstPtr, wordlist.Stack.Data[i])) \
+ Back = dtval; \
+ if(!strinfront(PrePtr, wordlist.Stack.Data[i])) \
+ Front = dtval; }
+
+
+
+/*
+ * Checks that the dots are correct
+ */
+
+static enum DotLevel CheckDots(char *PrePtr, char *PstPtr)
+{
+ unsigned long i;
+ int TmpC;
+ enum DotLevel Front = dtUnknown, Back = dtUnknown;
+
+ if (MathMode)
+ {
+ PrePtr--;
+#define SKIP_EMPTIES(macro, ptr) macro(ptr, TmpC, \
+(LATEX_SPACE(TmpC) || (TmpC == '{') || (TmpC == '}')))
+
+ SKIP_EMPTIES(SKIP_BACK, PrePtr);
+ SKIP_EMPTIES(SKIP_AHEAD, PstPtr);
+
+ CHECKDOTS(CenterDots, dtCDots);
+
+ if (!(Front && Back))
+ {
+ CHECKDOTS(LowDots, dtLDots);
+ }
+ return (Front & Back);
+ }
+ else
+ return (dtLDots);
+
+}
+
+static const char *Dot2Str(enum DotLevel dl)
+{
+ const char *Retval = INTERNFAULT;
+ switch (dl)
+ {
+ case dtUnknown:
+ Retval = "\\cdots or \\ldots";
+ break;
+ case dtDots:
+ Retval = "\\dots";
+ break;
+ case dtCDots:
+ Retval = "\\cdots";
+ break;
+ case dtLDots:
+ Retval = "\\ldots";
+ break;
+ }
+ return Retval;
+}
+
+/*
+ * Wipes a command, according to the definition in WIPEARG
+ */
+
+static void WipeArgument(const char *Cmd, char *CmdPtr)
+{
+ unsigned long CmdLen = strlen(Cmd);
+ const char *Format;
+ char *TmpPtr;
+ int c, TmpC;
+
+ if (Cmd && *Cmd)
+ {
+ TmpPtr = &CmdPtr[CmdLen];
+ Format = &Cmd[CmdLen + 1];
+
+ while (TmpPtr && *TmpPtr && *Format)
+ {
+ switch (c = *Format++)
+ {
+ case '*':
+ SKIP_AHEAD(TmpPtr, TmpC, LATEX_SPACE(TmpC));
+ if (*TmpPtr == '*')
+ TmpPtr++;
+ break;
+ case '[':
+ SKIP_AHEAD(TmpPtr, TmpC, LATEX_SPACE(TmpC));
+ if (*TmpPtr == '[')
+ TmpPtr = GetLTXArg(TmpPtr, ArgBuffer, ']', NULL);
+ break;
+ case '{':
+ SKIP_AHEAD(TmpPtr, TmpC, LATEX_SPACE(TmpC));
+ TmpPtr = GetLTXArg(TmpPtr, ArgBuffer, GET_TOKEN, NULL);
+ case '}':
+ case ']':
+ break;
+ default:
+ PrintPrgErr(pmWrongWipeTemp, &Cmd[strlen(Cmd) + 1]);
+ break;
+ }
+ }
+
+ if (TmpPtr)
+ strwrite(CmdPtr, VerbClear, TmpPtr - CmdPtr);
+ else
+ strxrep(CmdPtr, "()[]{}", *VerbClear);
+ }
+}
+
+/*
+ * Checks italic.
+ *
+ */
+
+static void CheckItal(const char *Cmd)
+{
+ int TmpC;
+ char *TmpPtr;
+ if (HasWord(Cmd, &NonItalic))
+ ItState = itOff;
+ else if (HasWord(Cmd, &Italic))
+ ItState = itOn;
+ else if (HasWord(Cmd, &ItalCmd))
+ {
+ TmpPtr = BufPtr;
+ SKIP_AHEAD(TmpPtr, TmpC, LATEX_SPACE(TmpC));
+ if (*TmpPtr == '{')
+ {
+ ItFlag = ItState ? efItal : efNoItal;
+ ItState = itOn;
+ }
+ }
+}
+
+/*
+ * Interpret isolated commands.
+ *
+ */
+
+static void PerformBigCmd(char *CmdPtr)
+{
+ char *TmpPtr;
+ const char *ArgEndPtr;
+ unsigned long CmdLen = strlen(CmdBuffer);
+ int TmpC;
+ enum ErrNum ErrNum;
+ struct ErrInfo *ei;
+
+ enum DotLevel dotlev, realdl = dtUnknown;
+
+ TmpPtr = BufPtr;
+ SKIP_AHEAD(TmpPtr, TmpC, LATEX_SPACE(TmpC));
+
+ ArgEndPtr = GetLTXArg(TmpPtr, ArgBuffer, GET_STRIP_TOKEN, NULL);
+
+ /* Kill `\verb' commands */
+
+ if (WipeVerb)
+ {
+ if (!strcmp(CmdBuffer, "\\verb"))
+ {
+ if (*BufPtr && (*BufPtr != '*' || BufPtr[1]))
+ {
+ if (*BufPtr == '*')
+ TmpPtr = strchr(&BufPtr[2], BufPtr[1]);
+ else
+ TmpPtr = strchr(&BufPtr[1], *BufPtr);
+ if (TmpPtr)
+ strwrite(CmdPtr, VerbClear, (TmpPtr - CmdPtr) + 1);
+ else
+ PSERR(CmdPtr - Buf, 5, emNoArgFound);
+ }
+ }
+ }
+
+ if (HasWord(CmdBuffer, &IJAccent))
+ {
+ if (ArgEndPtr)
+ {
+ TmpPtr = ArgBuffer;
+ SKIP_AHEAD(TmpPtr, TmpC, TmpC == '{'); /* } */
+
+ if ((*TmpPtr == 'i') || (*TmpPtr == 'j'))
+ PrintError(CurStkName(&InputStack), RealBuf,
+ CmdPtr - Buf,
+ (long) strlen(CmdBuffer), Line,
+ emAccent, CmdBuffer, *TmpPtr,
+ MathMode ? "math" : "");
+ }
+ else
+ PSERR(CmdPtr - Buf, CmdLen, emNoArgFound);
+ }
+
+ if (HasWord(CmdBuffer, &NotPreSpaced) && isspace((unsigned char)CmdPtr[-1]))
+ PSERRA(CmdPtr - Buf - 1, 1, emRemPSSpace, CmdBuffer);
+
+ if ((TmpPtr = HasWord(CmdBuffer, &NoCharNext)))
+ {
+ char *BPtr = BufPtr;
+
+ TmpPtr += strlen(TmpPtr) + 1;
+ SKIP_AHEAD(BPtr, TmpC, LATEX_SPACE(TmpC));
+
+ if (strchr(TmpPtr, *BPtr))
+ {
+ PSERR2(CmdPtr - Buf, CmdLen, emNoCharMean, CmdBuffer, *BPtr);
+ }
+ }
+
+ if (!strcmp(CmdBuffer, "\\begin") || !strcmp(CmdBuffer, "\\end"))
+ {
+ if (ArgEndPtr)
+ {
+ if (!strcmp(ArgBuffer, "document"))
+ InHeader = FALSE;
+
+ if (CmdBuffer[1] == 'b')
+ {
+ if (!(PushErr(ArgBuffer, Line, CmdPtr - Buf,
+ CmdLen, MakeCpy(), &EnvStack)))
+ PrintPrgErr(pmNoStackMem);
+ }
+ else
+ {
+ if ((ei = PopErr(&EnvStack)))
+ {
+ if (strcmp(ei->Data, ArgBuffer))
+ PrintError(CurStkName(&InputStack), RealBuf,
+ CmdPtr - Buf,
+ (long) strlen(CmdBuffer),
+ Line, emExpectC, ei->Data, ArgBuffer);
+
+ FreeErrInfo(ei);
+ }
+ else
+ PrintError(CurStkName(&InputStack), RealBuf,
+ CmdPtr - Buf,
+ (long) strlen(CmdBuffer),
+ Line, emSoloC, ArgBuffer);
+ }
+
+ PerformEnv(ArgBuffer, (int) CmdBuffer[1] == 'b');
+ }
+ else
+ PSERR(CmdPtr - Buf, CmdLen, emNoArgFound);
+ }
+
+ CheckItal(CmdBuffer);
+
+ if ((ErrNum = PerformCommand(CmdBuffer, BufPtr)))
+ PSERR(CmdPtr - Buf, CmdLen, ErrNum);
+
+ if (!strcmp(CmdBuffer, "\\cdots"))
+ realdl = dtCDots;
+
+ if (!strcmp(CmdBuffer, "\\ldots"))
+ realdl = dtLDots;
+
+ if (!strcmp(CmdBuffer, "\\dots"))
+ realdl = dtLDots;
+
+ if (realdl != dtUnknown)
+ {
+ dotlev = CheckDots(CmdPtr, BufPtr);
+ if (dotlev && (dotlev != realdl))
+ {
+ const char *cTmpPtr = Dot2Str(dotlev);
+ PSERRA(CmdPtr - Buf, CmdLen, emEllipsis, cTmpPtr);
+ }
+ }
+
+ if ((TmpPtr = HasWord(CmdBuffer, &WipeArg)))
+ WipeArgument(TmpPtr, CmdPtr);
+}
+
+/*
+ * Check user abbreviations. Pass a pointer to the `.';
+ * also ensure that it's followed by spaces, etc.
+ *
+ * Note: We assume that all abbrevs have been transferred from
+ * AbbrevCase into Abbrev.
+ */
+
+static void CheckAbbrevs(const char *Buffer)
+{
+ long i;
+ char *TmpPtr;
+ const char *AbbPtr;
+
+ if (INUSE(emInterWord))
+ {
+ TmpPtr = TmpBuffer + Abbrev.MaxLen + 2;
+ *TmpPtr = 0;
+ AbbPtr = Buffer;
+
+ for (i = Abbrev.MaxLen; i >= 0; i--)
+ {
+ *--TmpPtr = *AbbPtr--;
+ if (!isalpha((unsigned char)*AbbPtr) && HasWord(TmpPtr, &Abbrev))
+ PSERR(Buffer - Buf + 1, 1, emInterWord);
+ if (!*AbbPtr)
+ break;
+ }
+ }
+}
+
+
+/*
+ * Check misc. things which can't be included in the main loop.
+ *
+ */
+
+static void CheckRest(void)
+{
+ unsigned long Count;
+ long CmdLen;
+ char *UsrPtr;
+
+ /* Search for user-specified warnings */
+
+ if (INUSE(emUserWarn))
+ {
+ strcpy(TmpBuffer, Buf);
+ FORWL(Count, UserWarn)
+ {
+ for (UsrPtr = TmpBuffer;
+ (UsrPtr = strstr(UsrPtr, UserWarn.Stack.Data[Count]));
+ UsrPtr++)
+ {
+ CmdLen = strlen(UserWarn.Stack.Data[Count]);
+ PSERR(UsrPtr - TmpBuffer, CmdLen, emUserWarn);
+ }
+ }
+
+
+ strlwr(TmpBuffer);
+
+ FORWL(Count, UserWarnCase)
+ {
+ for (UsrPtr = TmpBuffer;
+ (UsrPtr = strstr(UsrPtr, UserWarnCase.Stack.Data[Count]));
+ UsrPtr++)
+ {
+ CmdLen = strlen(UserWarnCase.Stack.Data[Count]);
+ PSERR(UsrPtr - TmpBuffer, CmdLen, emUserWarn);
+ }
+ }
+ }
+}
+
+
+/*
+ * Checks that the dash-len is correct.
+ */
+
+static void CheckDash(void)
+{
+ char *TmpPtr;
+ int TmpC;
+ long TmpCount, Len;
+ struct WordList *wl = NULL;
+ unsigned long i;
+ int Errored;
+ char *PrePtr = &BufPtr[-2];
+
+ TmpPtr = BufPtr;
+ SKIP_AHEAD(TmpPtr, TmpC, TmpC == '-');
+ TmpCount = TmpPtr - BufPtr + 1;
+
+ if (MathMode)
+ {
+ if (TmpCount > 1)
+ HERE(TmpCount, emWrongDash);
+ }
+ else
+ {
+ if (LATEX_SPACE(*PrePtr) && LATEX_SPACE(*TmpPtr))
+ wl = &WordDash;
+ if (isdigit((unsigned char)*PrePtr) && isdigit((unsigned char)*TmpPtr))
+ wl = &NumDash;
+ if (isalpha((unsigned char)*PrePtr) && isalpha((unsigned char)*TmpPtr))
+ wl = &HyphDash;
+
+ if (wl)
+ {
+ Errored = TRUE;
+ FORWL(i, *wl)
+ {
+ Len = strtol(wl->Stack.Data[i], NULL, 0);
+ if (TmpCount == Len)
+ {
+ Errored = FALSE;
+ break;
+ }
+ }
+ if (Errored)
+ HERE(TmpCount, emWrongDash);
+ }
+ }
+}
+
+/*
+ * Pushes and pops nesting characters.
+ *
+ */
+
+static void HandleBracket(int Char)
+{
+ unsigned long BrOffset; /* Offset into BrOrder array */
+ struct ErrInfo *ei;
+ int TmpC, Match;
+ char ABuf[2], BBuf[2];
+ char *TmpPtr;
+
+ AddBracket(Char);
+
+ if ((BrOffset = BrackIndex(Char)) != ~0UL)
+ {
+ if (BrOffset & 1) /* Closing bracket of some sort */
+ {
+ if ((ei = PopErr(&CharStack)))
+ {
+ Match = MatchBracket(*(ei->Data));
+ if (ei->Flags & efNoItal)
+ {
+ if (ItState == itOn)
+ {
+ TmpPtr = BufPtr;
+ SKIP_AHEAD(TmpPtr, TmpC, TmpC == '}');
+
+ if (!strchr(LTX_SmallPunc, *TmpPtr))
+ HERE(1, emNoItFound);
+ }
+
+ ItState = FALSE;
+ }
+ else if (ei->Flags & efItal)
+ ItState = TRUE;
+ FreeErrInfo(ei);
+ }
+ else
+ Match = 0;
+
+ if (Match != Char)
+ {
+ ABuf[0] = Match;
+ BBuf[0] = Char;
+ ABuf[1] = BBuf[1] = 0;
+ if (Match)
+ PrintError(CurStkName(&InputStack), RealBuf,
+ BufPtr - Buf - 1, 1, Line, emExpectC,
+ ABuf, BBuf);
+ else
+ HEREA(1, emSoloC, BBuf);
+ }
+
+ }
+ else /* Opening bracket of some sort */
+ {
+ if ((ei = PushChar(Char, Line, BufPtr - Buf - 1,
+ &CharStack, MakeCpy())))
+ {
+ if (Char == '{')
+ {
+ switch (ItFlag)
+ {
+ default:
+ ei->Flags = ItFlag;
+ ItFlag = efNone;
+ break;
+ case efNone:
+ ei->Flags |= ItState ? efItal : efNoItal;
+ }
+ }
+ }
+
+ else
+ PrintPrgErr(pmNoStackMem);
+ }
+ }
+}
+
+
+
+/*
+ * Searches the `Buf' for possible errors, and prints the errors. `Line'
+ * is supplied for error printing.
+ */
+
+int FindErr(const char *_RealBuf, const unsigned long _Line)
+{
+ char *CmdPtr; /* We'll have to copy each command out. */
+ char *PrePtr; /* Ptr to char in front of command, NULL if
+ * the cmd appears as the first character */
+ char *TmpPtr; /* Temporary pointer */
+ char *ErrPtr; /* Ptr to where an error started */
+
+ int TmpC, /* Just a temp var used throughout the proc. */
+ MatchC, Char; /* Char. currently processed */
+ unsigned long CmdLen; /* Length of misc. things */
+ int MixingQuotes;
+
+ int (*pstcb) (int c);
+
+ enum DotLevel dotlev;
+
+ LineCpy = NULL;
+
+ if (_RealBuf)
+ {
+ RealBuf = _RealBuf;
+ Line = _Line;
+
+ BufPtr = PreProcess();
+
+ BufPtr = SkipVerb();
+
+ while (BufPtr && *BufPtr)
+ {
+ PrePtr = BufPtr - 1;
+ Char = *BufPtr++;
+ if (isspace((unsigned char)Char))
+ Char = ' ';
+
+ switch (Char)
+ {
+ case '~':
+ TmpPtr = NULL;
+ if (isspace((unsigned char)*PrePtr))
+ TmpPtr = PrePtr;
+ else if (isspace((unsigned char)*BufPtr))
+ TmpPtr = BufPtr;
+
+ if (TmpPtr)
+ PSERR(TmpPtr - Buf, 1, emDblSpace);
+ break;
+
+ case 'X':
+ case 'x':
+ TmpPtr = PrePtr;
+
+ SKIP_BACK(TmpPtr, TmpC,
+ (LATEX_SPACE(TmpC) || strchr("{}$", TmpC)));
+
+ if (isdigit((unsigned char)*TmpPtr))
+ {
+ TmpPtr = BufPtr;
+
+ SKIP_AHEAD(TmpPtr, TmpC,
+ (LATEX_SPACE(TmpC) || strchr("{}$", TmpC)));
+
+ if (isdigit((unsigned char)*TmpPtr))
+ HERE(1, emUseTimes);
+ }
+ /* FALLTHRU */
+ /* CTYPE: isalpha() */
+ case 'a':
+ case 'b':
+ case 'c':
+ case 'd':
+ case 'e':
+ case 'f':
+ case 'g':
+ case 'h':
+ case 'i':
+ case 'j':
+ case 'k':
+ case 'l':
+ case 'm':
+ case 'n':
+ case 'o':
+ case 'p':
+ case 'q':
+ case 'r':
+ case 's':
+ case 't':
+ case 'u':
+ case 'v':
+ case 'w': /* case 'x': */
+ case 'y':
+ case 'z':
+
+ case 'A':
+ case 'B':
+ case 'C':
+ case 'D':
+ case 'E':
+ case 'F':
+ case 'G':
+ case 'H':
+ case 'I':
+ case 'J':
+ case 'K':
+ case 'L':
+ case 'M':
+ case 'N':
+ case 'O':
+ case 'P':
+ case 'Q':
+ case 'R':
+ case 'S':
+ case 'T':
+ case 'U':
+ case 'V':
+ case 'W': /* case 'X': */
+ case 'Y':
+ case 'Z':
+ if (!isalpha((unsigned char)*PrePtr) && (*PrePtr != '\\') && MathMode)
+ {
+ TmpPtr = BufPtr;
+ CmdPtr = CmdBuffer;
+ do
+ {
+ *CmdPtr++ = Char;
+ Char = *TmpPtr++;
+ }
+ while (isalpha((unsigned char)Char));
+
+ *CmdPtr = 0;
+
+ if (HasWord(CmdBuffer, &MathRoman))
+ HEREA(strlen(CmdBuffer), emWordCommand, CmdBuffer);
+ }
+
+ break;
+ case ' ':
+ TmpPtr = BufPtr;
+ SKIP_AHEAD(TmpPtr, TmpC, LATEX_SPACE(TmpC));
+
+ if (*TmpPtr && *PrePtr)
+ {
+ if ((TmpPtr - BufPtr) > 0)
+ {
+ HERE(TmpPtr - BufPtr + 1, emMultiSpace);
+ strwrite(BufPtr, VerbClear, TmpPtr - BufPtr - 1);
+ }
+ }
+ break;
+
+ case '.':
+ if ((Char == *BufPtr) && (Char == BufPtr[1]))
+ {
+ const char *cTmpPtr;
+ dotlev = CheckDots(&PrePtr[1], &BufPtr[2]);
+ cTmpPtr = Dot2Str(dotlev);
+ HEREA(3, emEllipsis, cTmpPtr);
+ }
+
+ /* Regexp: "([^A-Z@.])\.[.!?:;]*\s+[a-z]" */
+
+ TmpPtr = BufPtr;
+ SKIP_AHEAD(TmpPtr, TmpC, strchr(LTX_GenPunc, TmpC));
+ if (LATEX_SPACE(*TmpPtr))
+ {
+ if (!isupper((unsigned char)*PrePtr) && (*PrePtr != '@') &&
+ (*PrePtr != '.'))
+ {
+ SKIP_AHEAD(TmpPtr, TmpC, LATEX_SPACE(TmpC));
+ if (islower((unsigned char)*TmpPtr))
+ PSERR(BufPtr - Buf, 1, emInterWord);
+ else
+ CheckAbbrevs(&BufPtr[-1]);
+ }
+ }
+
+ /* FALLTHRU */
+ case ':':
+ case '?':
+ case '!':
+ case ';':
+ /* Regexp: "[A-Z][A-Z][.!?:;]\s+" */
+
+ if (isspace((unsigned char)*BufPtr) && isupper((unsigned char)*PrePtr) &&
+ (isupper((unsigned char)PrePtr[-1]) || (Char != '.')))
+ HERE(1, emInterSent);
+
+ /* FALLTHRU */
+ case ',':
+ if (isspace((unsigned char)*PrePtr) &&
+ !(isdigit((unsigned char)*BufPtr) &&
+ ((BufPtr[-1] == '.') || (BufPtr[-1] == ','))))
+ PSERR(PrePtr - Buf, 1, emSpacePunct);
+
+ if (MathMode &&
+ (((*BufPtr == '$') && (BufPtr[1] != '$')) ||
+ (!strafter(BufPtr, "\\)"))))
+ HEREA(1, emPunctMath, "outside inner");
+
+ if (!MathMode &&
+ (((*PrePtr == '$') && (PrePtr[-1] == '$')) ||
+ (!strinfront(PrePtr, "\\]"))))
+ HEREA(1, emPunctMath, "inside display");
+
+ break;
+ case '\'':
+ case '`':
+ if ((Char == *BufPtr) && (Char == BufPtr[1]))
+ {
+ PrintError(CurStkName(&InputStack), RealBuf,
+ BufPtr - Buf - 1, 3, Line,
+ emThreeQuotes,
+ Char, Char, Char, Char, Char, Char);
+ }
+
+ if (Char == '\'')
+ MatchC = '`';
+ else
+ MatchC = '\'';
+
+ TmpPtr = BufPtr;
+ SKIP_AHEAD(TmpPtr, TmpC, TmpC == Char);
+
+ MixingQuotes = FALSE;
+
+ if ((*TmpPtr == MatchC) || (*TmpPtr == '\"') ||
+ (*TmpPtr == '´'))
+ MixingQuotes = TRUE;
+
+ SKIP_AHEAD(TmpPtr, TmpC, strchr("`\'\"´", TmpC));
+
+ if (MixingQuotes)
+ HERE(TmpPtr - BufPtr + 1, emQuoteMix);
+
+ switch (Char)
+ {
+ case '\'':
+ if (isalpha((unsigned char)*TmpPtr) &&
+ (strchr(LTX_GenPunc, *PrePtr) || isspace((unsigned char)*PrePtr)))
+ HERE(TmpPtr - BufPtr + 1, emBeginQ);
+
+ /* Now check quote style */
+#define ISPUNCT(ptr) (strchr(LTX_GenPunc, *ptr) && (ptr[-1] != '\\'))
+
+ /* We ignore all single words/abbreviations in quotes */
+
+ {
+ char *WordPtr = PrePtr;
+ SKIP_BACK(WordPtr, TmpC, (isalnum((unsigned char)TmpC) ||
+ strchr(LTX_GenPunc, TmpC)));
+
+ if (*WordPtr != '`')
+ {
+ if (*PrePtr && (Quote != quTrad)
+ && ISPUNCT(PrePtr))
+ PSERRA(PrePtr - Buf, 1,
+ emQuoteStyle, "in front of");
+
+ if (*TmpPtr && (Quote != quLogic)
+ && ISPUNCT(TmpPtr))
+ PSERRA(TmpPtr - Buf, 1,
+ emQuoteStyle, "after");
+ }
+ }
+
+ break;
+ case '`':
+ if (isalpha((unsigned char)*PrePtr) &&
+ (strchr(LTX_GenPunc, *TmpPtr) || isspace((unsigned char)*TmpPtr)))
+ HERE(TmpPtr - BufPtr + 1, emEndQ);
+ break;
+ }
+ BufPtr = TmpPtr;
+ break;
+ case '"':
+ HERE(1, emUseQuoteLiga);
+ break;
+
+ /* One of these are unnecessary, but what the heck... */
+ case 180: /* ´. NOTE: '\xb4' gets converted to - something */
+ case ~(0xff & (~180)): /* This yields 0xff...fb4 in */
+ /* arbitrary precision. */
+
+ HERE(1, emUseOtherQuote);
+ break;
+
+ case '_':
+ case '^':
+ if (*PrePtr != '\\')
+ {
+ TmpPtr = PrePtr;
+ SKIP_BACK(TmpPtr, TmpC, LATEX_SPACE(TmpC));
+
+ CmdLen = 1;
+
+ switch (*TmpPtr)
+ {
+ /*{ */
+ case '}':
+ if (PrePtr[-1] != '\\')
+ break;
+
+ CmdLen++;
+ PrePtr--;
+ /* FALLTHRU */
+ /*[( */
+ case ')':
+ case ']':
+ PSERR(PrePtr - Buf, CmdLen, emEnclosePar);
+ }
+
+ TmpPtr = BufPtr;
+ SKIP_AHEAD(TmpPtr, TmpC, LATEX_SPACE(TmpC));
+
+ ErrPtr = TmpPtr;
+
+ if (isalpha((unsigned char)*TmpPtr))
+ pstcb = &my_isalpha;
+ else if (isdigit((unsigned char)*TmpPtr))
+ pstcb = &my_isdigit;
+ else
+ break;
+
+ while ((*pstcb) (*TmpPtr++))
+ ;
+ TmpPtr--;
+
+ if ((TmpPtr - ErrPtr) > 1)
+ PSERR(ErrPtr - Buf, TmpPtr - ErrPtr, emEmbrace);
+ }
+ break;
+ case '-':
+ CheckDash();
+ break;
+ case '\\': /* Command encountered */
+ BufPtr = GetLTXToken(--BufPtr, CmdBuffer);
+
+ if (LATEX_SPACE(*PrePtr))
+ {
+ if (HasWord(CmdBuffer, &Linker))
+ PSERR(PrePtr - Buf, 1, emNBSpace);
+ if (HasWord(CmdBuffer, &PostLink))
+ PSERR(PrePtr - Buf, 1, emFalsePage);
+ }
+
+ if (LATEX_SPACE(*BufPtr) && !MathMode &&
+ (!HasWord(CmdBuffer, &Silent)) &&
+ (strlen(CmdBuffer) != 2))
+ {
+ PSERR(BufPtr - Buf, 1, emSpaceTerm);
+ }
+ else if ((*BufPtr == '\\') && (!isalpha((unsigned char)BufPtr[1])) &&
+ (!LATEX_SPACE(BufPtr[1])))
+ PSERR(BufPtr - Buf, 2, emNotIntended);
+
+ PerformBigCmd(PrePtr + 1);
+ BufPtr = SkipVerb();
+
+ break;
+
+ case '(':
+ if (*PrePtr && !LATEX_SPACE(*PrePtr) && !isdigit((unsigned char)*PrePtr)
+ && !strchr("([{`~", *PrePtr))
+ {
+ if (PrePtr[-1] != '\\') /* Short cmds */
+ {
+ TmpPtr = PrePtr;
+ SKIP_BACK(TmpPtr, TmpC, istex(TmpC));
+ if (*TmpPtr != '\\') /* Long cmds */
+ PSERRA(BufPtr - Buf - 1, 1, emSpaceParen,
+ "in front of");
+ }
+ }
+ if (isspace((unsigned char)*BufPtr))
+ PSERRA(BufPtr - Buf, 1, emNoSpaceParen, "after");
+ HandleBracket(Char);
+ break;
+
+ case ')':
+ if (isspace((unsigned char)*PrePtr))
+ PSERRA(BufPtr - Buf - 1, 1, emNoSpaceParen,
+ "in front of");
+ if (isalpha((unsigned char)*BufPtr))
+ PSERRA(BufPtr - Buf, 1, emSpaceParen, "after");
+ HandleBracket(Char);
+ break;
+
+ case '}':
+ case '{':
+ case '[':
+ case ']':
+ HandleBracket(Char);
+ break;
+ case '$':
+ if (*PrePtr != '\\')
+ {
+ if (*BufPtr == '$')
+ BufPtr++;
+ MathMode ^= TRUE;
+ }
+
+ break;
+ }
+ }
+
+ if (!VerbMode)
+ {
+ CheckRest();
+ }
+ }
+
+ return (TRUE);
+}
+
+/*
+ * Tries to create plural forms for words. Put a '%s' where a
+ * suffix should be put, e.g. "warning%s". Watch your %'s!
+ */
+
+static void Transit(FILE * fh, unsigned long Cnt, const char *Str)
+{
+ switch (Cnt)
+ {
+ case 0:
+ fputs("No ", fh);
+ fprintf(fh, Str, "s");
+ break;
+ case 1:
+ fputs("One ", fh);
+ fprintf(fh, Str, "");
+ break;
+ default:
+ fprintf(fh, "%ld ", Cnt);
+ fprintf(fh, Str, "s");
+ break;
+ }
+}
+
+/*
+ * Prints the status/conclusion after doing all the testing, including
+ * bracket stack status, math mode, etc.
+ */
+
+void PrintStatus(unsigned long Lines)
+{
+ unsigned long Cnt;
+ struct ErrInfo *ei;
+
+
+ while ((ei = PopErr(&CharStack)))
+ {
+ PrintError(ei->File, ei->LineBuf, ei->Column,
+ ei->ErrLen, ei->Line, emNoMatchC, (char *) ei->Data);
+ FreeErrInfo(ei);
+ }
+
+ while ((ei = PopErr(&EnvStack)))
+ {
+ PrintError(ei->File, ei->LineBuf, ei->Column,
+ ei->ErrLen, ei->Line, emNoMatchC, (char *) ei->Data);
+ FreeErrInfo(ei);
+ }
+
+ if (MathMode)
+ {
+ PrintError(CurStkName(&InputStack), "", 0L, 0L, Lines, emMathStillOn);
+ }
+
+ for (Cnt = 0L; Cnt < (NUMBRACKETS >> 1); Cnt++)
+ {
+ if (Brackets[Cnt << 1] != Brackets[(Cnt << 1) + 1])
+ {
+ PrintError(CurStkName(&InputStack), "", 0L, 0L, Lines,
+ emNoMatchCC,
+ BrOrder[Cnt << 1], BrOrder[(Cnt << 1) + 1]);
+ }
+ }
+
+ if (!Quiet)
+ {
+ Transit(stderr, ErrPrint, "error%s printed; ");
+ Transit(stderr, WarnPrint, "warning%s printed; ");
+ Transit(stderr, UserSupp, "user suppressed warning%s printed.\n");
+ }
+}
+
+
+
+/*
+ * Uses OutputFormat. Be sure that `String'
+ * does not contain tabs, newlines, etc.
+ * Prints a formatted string. Formatting codes understood:
+ * %b - string to print Between fields (from -s option)
+ * %c - Column position of error
+ * %d - lenght of error (Digit)
+ * %f - current Filename
+ * %i - Turn on inverse printing mode.
+ * %I - Turn off inverse printing mode.
+ * %k - Kind of error (warning, error, message)
+ * %l - Line number of error
+ * %m - warning Message
+ * %n - warning Number
+ * %u - an Underlining line (like the one which appears when using -v1)
+ * %r - part of line in front of error ('S' - 1)
+ * %s - part of line which contains error (String)
+ * %t - part of line after error ('S' + 1)
+ */
+
+
+void
+PrintError(const char *File, const char *String,
+ const long Position, const long Len,
+ const long LineNo, const enum ErrNum Error, ...)
+{
+ static /* Just to reduce stack usage... */
+ char PrintBuffer[BUFSIZ];
+ va_list MsgArgs;
+
+ char *LastNorm = OutputFormat;
+ char *of;
+ int c;
+
+ enum Context Context;
+
+ if (betw(emMinFault, Error, emMaxFault))
+ {
+ switch (LaTeXMsgs[Error].InUse)
+ {
+ case iuOK:
+ do
+ {
+ Context = LaTeXMsgs[Error].Context;
+
+ if (!HeadErrOut)
+ Context |= ctOutHead;
+
+#define RGTCTXT(Ctxt, Var) if((Context & Ctxt) && !(Var)) break;
+
+ RGTCTXT(ctInMath, MathMode);
+ RGTCTXT(ctOutMath, !MathMode);
+ RGTCTXT(ctInHead, InHeader);
+ RGTCTXT(ctOutHead, !InHeader);
+
+ switch (LaTeXMsgs[Error].Type)
+ {
+ case etWarn:
+ WarnPrint++;
+ break;
+ case etErr:
+ ErrPrint++;
+ break;
+ case etMsg:
+ break;
+ }
+
+ while ((of = strchr(LastNorm, '%')))
+ {
+ c = *of;
+ *of = 0;
+
+ fputs(LastNorm, OutputFile);
+
+ *of++ = c;
+
+ switch (c = *of++)
+ {
+ case 'b':
+ fputs(Delimit, OutputFile);
+ break;
+ case 'c':
+ fprintf(OutputFile, "%ld", Position + 1);
+ break;
+ case 'd':
+ fprintf(OutputFile, "%ld", Len);
+ break;
+ case 'f':
+ fputs(File, OutputFile);
+ break;
+ case 'i':
+ fputs(ReverseOn, OutputFile);
+ break;
+ case 'I':
+ fputs(ReverseOff, OutputFile);
+ break;
+ case 'k':
+ switch (LaTeXMsgs[Error].Type)
+ {
+ case etWarn:
+ fprintf(OutputFile, "Warning");
+ break;
+ case etErr:
+ fprintf(OutputFile, "Error");
+ break;
+ case etMsg:
+ fprintf(OutputFile, "Message");
+ break;
+ }
+ break;
+ case 'l':
+ fprintf(OutputFile, "%ld", LineNo);
+ break;
+ case 'm':
+ va_start(MsgArgs, Error);
+ vfprintf(OutputFile,
+ LaTeXMsgs[Error].Message, MsgArgs);
+ va_end(MsgArgs);
+ break;
+ case 'n':
+ fprintf(OutputFile, "%d", Error);
+ break;
+ case 'u':
+ sfmemset(PrintBuffer, ' ', (long) Position);
+
+ sfmemset(&PrintBuffer[Position], '^', Len);
+ PrintBuffer[Position + Len] = 0;
+ fputs(PrintBuffer, OutputFile);
+ break;
+ case 'r':
+ substring(String, PrintBuffer, 0L, Position);
+ fputs(PrintBuffer, OutputFile);
+ break;
+ case 's':
+ substring(String, PrintBuffer, Position, Len);
+ fputs(PrintBuffer, OutputFile);
+ break;
+ case 't':
+ substring(String, PrintBuffer,
+ Position + Len, LONG_MAX);
+ fputs(PrintBuffer, OutputFile);
+ break;
+ default:
+ fputc(c, OutputFile);
+ break;
+ }
+ LastNorm = of;
+ }
+ fputs(LastNorm, OutputFile);
+ }
+ while (FALSE);
+ break;
+ case iuNotUser:
+ UserSupp++;
+ break;
+ case iuNotSys:
+ break;
+ }
+ }
+}
+
+/*
+ * All commands isolated is routed through this command, so we can
+ * update global statuses like math mode and whether @ is a letter
+ * or not.
+ */
+
+static enum ErrNum PerformCommand(const char *Cmd, char *Arg)
+{
+ const char *Argument = "";
+ enum ErrNum en = emMinFault;
+ int TmpC;
+
+ if (!strcmp(Cmd, "\\makeatletter"))
+ AtLetter = TRUE;
+ else if (!strcmp(Cmd, "\\makeatother"))
+ AtLetter = FALSE;
+ else if (InputFiles &&
+ !(strcmp(Cmd, "\\input") && strcmp(Cmd, "\\include")))
+ {
+ SKIP_AHEAD(Arg, TmpC, LATEX_SPACE(TmpC));
+ if (*Arg == '{') /* } */
+ {
+ if (GetLTXArg(Arg, TmpBuffer, GET_STRIP_TOKEN, NULL))
+ Argument = TmpBuffer;
+ }
+ else
+ Argument = strip(Arg, STRP_BTH);
+
+ if (!(Argument && PushFileName(Argument, &InputStack)))
+ en = emNoCmdExec;
+ }
+ else if (HasWord(Cmd, &Primitives))
+ en = emTeXPrim;
+ else if (*Cmd == '\\')
+ {
+ /* Quicker check of single lettered commands. */
+ switch (Cmd[1])
+ {
+ case '(':
+ case '[':
+ MathMode = TRUE;
+ break;
+ case ']':
+ case ')':
+ MathMode = FALSE;
+ break;
+ case '/':
+ switch (ItState)
+ {
+ case itOn:
+ ItState = itCorrected;
+ Argument = Arg;
+
+ SKIP_AHEAD(Argument, TmpC, TmpC == '{' || TmpC == '}');
+
+ if (strchr(".,", *Argument))
+ en = emItPunct;
+
+ break;
+ case itCorrected:
+ en = emItDup;
+ break;
+ case itOff:
+ en = emItInNoIt;
+ }
+ break;
+ }
+ }
+
+ return (en);
+}