w32tex
About: TeX Live provides a comprehensive TeX system including all the major TeX-related programs, macro packages, and fonts that are free software. Windows sources.
  Fossies Dox: w32tex-src.tar.xz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

lacheck.l
Go to the documentation of this file.
1 /* $Id: lacheck.l 51590 2019-07-09 15:26:51Z karl $
2  *
3  * lacheck.lex - A consistency checker checker for LaTeX documents
4  *
5  * Copyright (C) 1991, 1992 Kresten Krab Thorup.
6  * Copyright (C) 1993 --- 1998 Per Abrahamsen.
7  * Copyright (C) 2019 Karl Berry.
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 1, or (at your option)
12  * any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program. If not, see <https://www.gnu.org/licenses/>.
21  *
22  * original Revision: 1.26 $
23  * Author : Kresten Krab Thorup
24  * Created On : Sun May 26 18:11:58 1991
25  *
26  * HISTORY
27  * 08-Jul-2019 Karl Berry
28  * Separate patterns for \def vs. \newcommand. Report from Zayd Hammoudeh,
29  * https://tug.org/pipermail/tex-live/2019-January/043083.html.
30  * Update version number (now 1.29), contact info.
31  * 07-Mar-1998 Per Abrahamsen
32  * Added return to yywrap. Patch by Fabrice POPINEAU
33  * <popineau@esemetz.ese-metz.fr>.
34  * 14-Jan-1998 Per Abrahamsen
35  * Added GPL blurp.
36  * 27-Oct-1997 Per Abrahamsen
37  * Count newline after newenvironment and newcommand.
38  * 12-Jan-1996 Per Abrahamsen
39  * \\} used not to end a group in definitions. Reported by Piet
40  * van Oostrum <piet@cs.ruu.nl>.
41  * 03-Jan-1995 Per Abrahamsen
42  * Fix bug which prevented detection of multiple illegal characters
43  * in labels. Reported by eeide@jaguar.cs.utah.edu (Eric Eide).
44  * 30-Jul-1994 Per Abrahamsen
45  * Define dummy yywrap so we no longer depend on `libl.a'.
46  * 26-Apr-1994 Per Abrahamsen
47  * Removed a few warnings, by Richard Lloyd <R.K.Lloyd@csc.liv.ac.uk>.
48  * 23-Apr-1994 Per Abrahamsen
49  * Changed all `%i' to `%d' for VMS portability. Reported by
50  * Stephen Harker <PHS172M@vaxc.cc.monash.edu.au>.
51  * 16-Feb-1994 Per Abrahamsen
52  * Try file name with `.tex' appended before trying it bare. This
53  * will make the case where a directory and a TeX file share the
54  * same name work.
55  * 19-Jan-1994 Per Abrahamsen
56  * Comments don't imply whitespace. Pointed out by Jacco van
57  * Ossenbruggen <jrvosse@cs.vu.nl>.
58  * 14-Jan-1994 Per Abrahamsen
59  * Don't complain about \ref at the beginning of a paragraph.
60  * Suggested by Jean-Marc Lasgouttes <Jean-Marc.Lasgouttes@inria.fr>.
61  * 11-Jan-1994 Per Abrahamsen
62  * Added version string to usage message. Suggested by Uwe Bonnes
63  * <bon@LTE.E-TECHNIK.uni-erlangen.de> .
64  * 04-Jan-1994 Per Abrahamsen
65  * Warn about newlines in \verb. Suggested by Mark Burton
66  * <markb@ordern.demon.co.uk>. The LaTeX Book agrees (p. 168).
67  * 10-Sep-1993 Per Abrahamsen
68  * Removed complain about missing ~ before \cite. Requested by
69  * Nelson H. F. Beebe <beebe@math.utah.edu>. The LaTeX Book seems
70  * to agree.
71  * 03-Sep-1993 Per Abrahamsen
72  * Check for illegal characters in labels.
73  * 16-Aug-1993 Per Abrahamsen
74  * Recognize \endinput. Suggested by Stefan Farestam
75  * <Stefan.Farestam@cerfacs.fr>.
76  * 13-Aug-1993 Per Abrahamsen
77  * } was eaten after display math. Reported by Eckhard Rggeberg
78  * <eckhard@ts.go.dlr.de>.
79  * 13-Aug-1993 Per Abrahamsen
80  * Recognize \verb*. Reported by Eckhard Rggeberg
81  * <eckhard@ts.go.dlr.de>.
82  * 08-Aug-1993 Per Abrahamsen
83  * Better catch begin and end without arguments.
84  * 08-Aug-1993 Per Abrahamsen
85  * Removed free(NULL) as reported by Darrel R. Hankerson
86  * <hankedr@mail.auburn.edu>.
87  * 08-Aug-1993 Per Abrahamsen
88  * Removed declaration of realloc for some C compilers. Reported by
89  * Darrel R. Hankerson <hankedr@mail.auburn.edu>
90  * 30-Jul-1993 Per Abrahamsen
91  * Added check for italic correction after normal text.
92  * 29-Jul-1993 Per Abrahamsen
93  * Added cast for (char*) malloc as suggested by John Interrante
94  * <interran@uluru.Stanford.EDU>.
95  * 29-Jul-1993 Per Abrahamsen
96  * Added check for missing and extra italic correction.
97  * 29-Jul-1993 Per Abrahamsen
98  * Made line number counting more reliable (but it still needs a rewrite)!
99  * 28-Jul-1993 Per Abrahamsen
100  * Added check for italic correction before point or comma.
101  * 6-Jun-1992 Kresten Krab Thorup
102  * Last Modified: Sat Jun 6 16:37:44 1992 #48 (Kresten Krab Thorup)
103  * Added test for whitespace before punctuation mark
104  * 17-Dec-1991 (Last Mod: Tue Dec 17 21:01:24 1991 #41) Kresten Krab Thorup
105  * Added 'word word` and missing ~ before cite and ref
106  * 18-Jun-1991 (Last Mod: Tue Jun 18 19:20:43 1991 #17) Kresten Krab Thorup
107  * Added check (or rather management) for \newenvironment and
108  * \newcommand - as suggested by Per Abrahamsen abrham@hugin.dk
109  * 30-May-1991 (Last Mod: Thu May 30 02:22:33 1991 #15) Kresten Krab Thorup
110  * Added check for `$${punct}' and `{punct}$' constructions
111  * 30-May-1991 (Last Mod: Wed May 29 10:31:35 1991 #6) Kresten Krab Thorup
112  * Improved (dynamic) stack management from Andreas Stolcke ...
113  * <stolcke@ICSI.Berkeley.EDU>
114  * 26-May-1991 Kresten Krab Thorup
115  * Initial distribution version.
116  */
117 
118 %option never-interactive
119 
120 %{
121 
122 #include <stdio.h>
123 #include <string.h>
124 
125 /* #include <sys/param.h> */
126 
127 /* extern char *realloc(); */
128 
129 #ifdef NEED_STRSTR
130 char *strstr();
131 #endif
132 
133 #define GROUP_STACK_SIZE 10
134 #define INPUT_STACK_SIZE 10
135 
136 #define PROGNAME "LaCheck"
137 
138  /* macros */
139 
140 #define CG_NAME gstack[gstackp-1].s_name
141 #define CG_TYPE gstack[gstackp-1].s_type
142 #define CG_LINE gstack[gstackp-1].s_line
143 #define CG_ITALIC gstack[gstackp-1].italic
144 #define CG_FILE gstack[gstackp-1].s_file
145 
146 void pop(void);
147 void push(const char *p_name, int p_type, int p_line);
148 void linecount(void);
149 void g_checkend(int n);
150 void e_checkend(int n, char *name);
151 void f_checkend(char *name);
152 void input_file(char *file_nam);
153 void print_bad_match(char *end_command, int type);
154 int check_top_level_end(char *end_command, int type);
155 
156  /* global variables */
157 
158 int line_count = 1;
159 int warn_count = 0;
160 char *file_name;
161 char verb_char;
162 
163  /* the group stack */
164 
165 typedef struct tex_group
166  {
167  char *s_name;
168  int s_type;
169  int s_line;
170  int italic;
171  char *s_file;
int italic
Definition: lacheck.l:170
char * s_file
Definition: lacheck.l:171
int s_line
Definition: lacheck.l:169
int s_type
Definition: lacheck.l:166
tex_group
Definition: lacheck.l:172
173 
174 tex_group *gstack;
175 int gstack_size = GROUP_STACK_SIZE;
176 int gstackp = 0;
177 
178 typedef struct input_
179  {
181  char *name;
182  int linenum;
char * name
Definition: lacheck.l:179
int linenum
Definition: lacheck.l:182
input_
Definition: lacheck.l:183
struct stream_s stream
Definition: pts_fax.h:93
184 
185 input_ *istack;
186 int istack_size = INPUT_STACK_SIZE;
187 int istackp = 0;
188 
189 int def_count = 0;
190 
191 %}
192 
193 %x B_ENVIRONMENT E_ENVIRONMENT VERBATIM INCLUDE MATH COMMENT VERB DEF
194 %x AFTER_DISPLAY ENV_DEF ICOR GETICOR
195 
196 b_group ("{"|\\bgroup)
197 e_group ("}"|\\egroup)
198 
199 b_math \\\‍(
200 e_math \\\‍)
201 math \$
202 
203 b_display \\\[
204 e_display \\\]
205 display \$\$
206 
207 par ([ \t]*\n[ \t]*\n[ \t\n]*)
208 non_par_ws ([ \t]+\n?[ \t]*|[ \t]*\n[ \t]*|[ \t]*\n?[ \t]+)
209 
210 ws [ \n\t](%[^\n]\n)*
211 space ({ws}|\~|\\space)
212 hard_space (\~|\\space)
213 
214 u_letter [A-Z]
215 l_letter [a-z]
216 punct [\!\.\?]
217 atoz [a-zA-Z]
218 letter [A-Za-z]
219 
220 c_bin ("-"|"+"|"\\cdot"|"\\oplus"|"\\otimes"|"\\times")
221 l_bin (",")
222 
223 general_abbrev {letter}+{punct}
224 
225 non_abbrev {u_letter}{u_letter}+{punct}
226 
227 italic_spec (sl|it)
228 normal_spec normalshape
229 swap_spec em
230 font_spec (rm|bf|{italic_spec}|tt|{swap_spec}|mediumseries|{normal_spec})
231 
232 primitive \\‍(above|advance|catcode|chardef|closein|closeout|copy|count|countdef|cr|crcr|csname|delcode|dimendef|dimen|divide|expandafter|font|hskp|vskip|openout)
233 
234 symbol ("$"("\\"{atoz}+|.)"$"|"\\#"|"\\$"|"\\%"|"\\ref")
235 
236 %%
237 
238 <*>"\\\\" { ; }
239 
240 <ENV_DEF,DEF,INITIAL>"\\\%" { ; }
241 
242 <ICOR,GETICOR,ENV_DEF,DEF,INITIAL>"%"[^\n]*\n { line_count++; }
int line_count
Definition: lacheck.c:2153
243 
244 <ICOR,GETICOR,ENV_DEF,DEF,INITIAL>\n { line_count++; }
245 
246 <ENV_DEF,DEF,INITIAL>"\\\{" { ; }
247 
248 <ENV_DEF,DEF,INITIAL>"\\\}" { ; }
249 
250 "\\\$" { ; }
251 
252 <ICOR,INITIAL,GETICOR>"{"{ws} {
253  if (CG_TYPE != 4 && CG_TYPE != 5) {
254  if (!(CG_TYPE == 2 && strstr(CG_NAME, "array"))) {
255  printf( "\"%s\", line %d: possible unwanted space at \"{\"\n",
257  ++warn_count ;
258  }
259  }
260  push( "{", 0, line_count);
261  linecount();
262  }
int printf()
char * strstr()
char file_name[][1024]
Definition: cwebboot.c:318
int warn_count
Definition: lacheck.c:2154
#define CG_TYPE
void linecount(void)
Definition: lacheck.l:1132
#define CG_NAME
void push(const char *p_name, int p_type, int p_line)
Definition: lacheck.l:903
263 
264 <ICOR,INITIAL,GETICOR>{b_group} { push( "{", 0, line_count);}
265 
266 <INITIAL,GETICOR>{e_group} {
267  {
268  int italic = CG_ITALIC;
269  g_checkend(0);
270  if (italic && !CG_ITALIC)
271  BEGIN(GETICOR) ;
272  else
273  BEGIN(INITIAL);
274  }}
#define INITIAL
Definition: detex.c:1842
#define BEGIN
Definition: detex.c:205
#define GETICOR
Definition: lacheck.c:2202
void g_checkend(int n)
Definition: lacheck.l:1060
#define CG_ITALIC
275 
276 <ICOR>{e_group} { g_checkend(0); }
277 
278 <GETICOR>[A-Za-z0-9;:!()]+ {
279  {
280  if (!CG_ITALIC)
281  {
282  printf("\"%s\", line %d: you may need a \\/ before \"%s\"\n",
284  ++warn_count;
285  }
286  BEGIN(INITIAL);
287  }}
#define yytext
288 
289 <ICOR>[A-Za-z0-9;:!?()`']+ {
290  {
291  if (CG_ITALIC)
292  {
293  printf("\"%s\", line %d: \\/ not needed before italic text \"%s\"\n",
295  ++warn_count;
296  }
297  BEGIN(INITIAL);
298  }}
299 
300 ^[A-Za-z0-9;:!?()`',.]+{ws}*/\\\/ {
301  {
302  linecount();
303  if (!CG_ITALIC)
304  {
305  printf("\"%s\", line %d: \\/ not needed after non-italic text \"%s\"\n",
307  ++warn_count;
308  }
309  }}
310 
311 {ws}[A-Za-z0-9;:!?()`',.]+{ws}*/\\\/ {
312  {
313  linecount();
314  if (!CG_ITALIC)
315  {
316  printf("\"%s\", line %d: \\/ is not needed after non-italic \"%s\"\n",
318  ++warn_count;
319  }
320  }}
321 
322 <GETICOR>\\\/ { BEGIN(INITIAL); }
323 
324 <INITIAL>\\\/ { BEGIN(ICOR); }
#define ICOR
Definition: lacheck.c:2201
325 
326 <ICOR>\\\/ {
327  {
328  printf("\"%s\", line %d: double \\/ found \"%s\"\n",
330  ++warn_count;
331  BEGIN(ICOR);
332  }}
333 
334 <INITIAL,GETICOR,ICOR>\\{italic_spec}/[^a-zA-Z] { CG_ITALIC = 1; }
335 
336 <INITIAL,GETICOR>\\{normal_spec}/[^a-zA-Z] {
337  {
338  if(CG_ITALIC)
339  BEGIN(GETICOR);
340  else
341  BEGIN(INITIAL);
342  CG_ITALIC = 0;
343  }}
344 
345 <ICOR>\\{normal_spec}/[^a-zA-Z] { CG_ITALIC = 0; }
346 
347 <INITIAL,GETICOR>\\{swap_spec}/[^a-zA-Z] {
348  {
349  if(CG_ITALIC)
350  BEGIN(GETICOR);
351  else
352  BEGIN(INITIAL);
353  CG_ITALIC = !CG_ITALIC;
354  }}
355 
356 <ICOR>\\{swap_spec}/[^a-zA-Z] { CG_ITALIC = !CG_ITALIC; }
357 
358 <ICOR>[,.] {
359  {
360  printf("\"%s\", line %d: do not use \\/ before \"%s\"\n",
362  ++warn_count;
363  BEGIN(INITIAL);
364  }}
365 
366 <GETICOR,ICOR>{ws} { ; }
367 
368 <GETICOR,ICOR>~ { ; }
369 
370 <GETICOR,ICOR>[^\n] {
371  {
372  unput(yytext[0]);
373  BEGIN(INITIAL);
374  }}
#define unput(c)
Definition: detex.c:269
375 
376  /* \def can be followed by whitespace, then the \ to start the control
377  sequence, then more or less anything up to the { starting the
378  replacement text, which we assume is on the same line. (All this
379  could be changed in TeX, with catcodes etc., but we can't try to
380  handle that.) */
381 "\\"[exg]?def[ \t\n]*"\\"[^\n{]+\{ BEGIN(DEF);
@ DEF
Definition: ucnvisci.cpp:87
382 
383  /* \newcommand{\foo}{...} or \newcommand\foo{...}
384  (or \renewcommand or \providecommand).
385  To allow for arbitrary control sequence names, we match
386  the braced name as anything not containing a }.
387  To handle optional argument specifications, we assume the { is on
388  the same line as the csname.
389  We don't do anything with the definitions; the only purpose is to
390  count braces. */
391 "\\"(provide|(re)?newcommand)[ \t\n]*(\{\\[^}]+\}|\\‍)[^{]*\{ BEGIN(DEF);
392 
393  /* Pre-2019 rule was (see test-def.tex):
394  "\\"[exg]?(def|newcommand)[^\n\{]+ BEGIN(DEF);
395  */
396 
397 <DEF>{b_group} { ++def_count; }
int def_count
Definition: lacheck.c:2184
398 
399 <DEF>{e_group} { --def_count;
400  if(def_count == 0)
401  BEGIN(INITIAL); }
402 
403 <DEF>. { ; }
404 
405 "\\"newenvironment"{"[a-zA-Z]+"}"[^\n\{]+ BEGIN(ENV_DEF);
#define ENV_DEF
Definition: lacheck.c:2200
406 
407 <ENV_DEF>{b_group} { ++def_count; }
408 
409 <ENV_DEF>{e_group} { --def_count;
410  if(def_count == 0)
411  BEGIN(DEF); }
412 
413 <ENV_DEF>. { ; }
414 
415 {b_math} {
416  if(CG_TYPE == 4 || CG_TYPE == 5)
418  else
419  {
420  push( yytext, 4, line_count);
421  }}
void print_bad_match(char *end_command, int type)
Definition: lacheck.l:1100
422 
423 {e_math} { g_checkend(4); }
424 
425 {b_display} {
426  if(CG_TYPE == 4 || CG_TYPE == 5)
428  else
429  {
430  push( yytext, 5, line_count);
431  }}
432 
433 
434 {e_display} { g_checkend(5); BEGIN(AFTER_DISPLAY);}
#define AFTER_DISPLAY
Definition: lacheck.c:2199
435 
436 <AFTER_DISPLAY>{punct} {
437 
438  printf( "\"%s\", line %d: punctuation mark \"%s\" should be placed before end of displaymath\n",
440  ++warn_count ;
441 
442  BEGIN(INITIAL); }
443 
444 <AFTER_DISPLAY>(\n|.) { unput(yytext[0]); BEGIN(INITIAL); }
445 
446 <ICOR,INITIAL,GETICOR>{punct}/("\$"|"\\‍)") { if (CG_TYPE == 4)
447  {
448  printf( "\"%s\", line %d: punctuation mark \"%s\" should be placed after end of math mode\n",
450  ++warn_count ;
451  BEGIN(INITIAL);
452  }}
453 
454 {math} {
455 
456  if(CG_TYPE == 5)
458  else
459 
460  if(CG_TYPE == 4)
461  {
462  e_checkend(4, yytext);
463  }
464  else
465  {
466  push( yytext, 4, line_count);
467  }}
void e_checkend(int n, char *name)
Definition: lacheck.l:1071
468 
469 
470 {display} {
471 
472  if(CG_TYPE == 4)
474  else
475 
476  if(CG_TYPE == 5)
477  {
478  e_checkend(5, yytext);
480  }
481  else
482  {
483  push( yytext, 5, line_count);
484  }}
485 
486 \\begingroup/[^a-zA-Z] {
487  {
488  push("\\begingroup", 1, line_count);
489  }}
490 
491 
492 \\endgroup/[^a-zA-Z] {
493  {
494  g_checkend(1);
495  }}
496 
497 
498 \\begin[ \t]*"{" { BEGIN(B_ENVIRONMENT); }
#define B_ENVIRONMENT
Definition: lacheck.c:2191
499 
500 \\begin[ \t]*(%[^\n]*)?/\n {
501  {
502 
503  printf("\"%s\", line %d: {argument} missing for \\begin\n",
505  ++warn_count;
506  }}
507 
508 <B_ENVIRONMENT>[^\}\n]+ {
509  {
510  if (strcmp( yytext, "verbatim" ) == 0 )
511  {
512  input();
513  BEGIN(VERBATIM);
514  }
515  else
516  {
517  push(yytext, 2, line_count);
518 
519  if ( strcmp (yytext, "sl" ) == 0
520  || strcmp (yytext, "it" ) == 0)
521  CG_ITALIC = 1;
522  else if (strcmp (yytext, "normalshape") == 0)
523  CG_ITALIC = 0;
524  else if (strcmp (yytext, "em") == 0)
525  CG_ITALIC = !CG_ITALIC;
526 
527  input();
528  BEGIN(INITIAL);
529  }
530  }}
int strcmp()
Definition: coll.cpp:143
#define input
Definition: cpascal.h:53
#define VERBATIM
Definition: lacheck.c:2193
531 
532 <VERBATIM>\\end[ \t]*\{verbatim\} { BEGIN(INITIAL); }
533 
534 <VERBATIM>\t {
535  printf("\"%s\", line %d: TAB character in verbatim environment\n",
537  ++warn_count;
538  }
539 
540 <VERBATIM>. { ; }
541 
542 <VERBATIM>\n { ++line_count; }
543 
544 
545 <ICOR,INITIAL,GETICOR>\\verb\*?. {
546  verb_char = yytext[yyleng-1];
547  BEGIN(VERB);
548  }
#define yyleng
char verb_char
Definition: lacheck.c:2156
#define VERB
Definition: lacheck.c:2197
549 
550 <VERB>\n {
551  printf("\"%s\", line %d: \\verb should not contain end of line characters\n",
553  ++line_count;
554 }
555 
556 <VERB>. {
557  if ( *yytext == verb_char )
558  BEGIN(INITIAL);
559 }
560 
561 
562 \\end[ \t]*"{" { BEGIN(E_ENVIRONMENT); }
#define E_ENVIRONMENT
Definition: lacheck.c:2192
563 
564 \\end[ \t]*(%[^\n]*)?/\n {
565  {
566  printf("\"%s\", line %d: {argument} missing for \\end\n",
568  ++warn_count;
569  }}
570 
571 
572 <E_ENVIRONMENT>[^\}\n]+ {
573  {
574  e_checkend(2, yytext);
575  input();
576 
577  BEGIN(INITIAL);
578  }}
579 
580 
581 <ICOR,INITIAL,GETICOR>{ws}({letter}".")*{letter}*{l_letter}"."/{non_par_ws}+{l_letter} {
582  {
583  linecount();
584  printf( "\"%s\", line %d: missing `\\ ' after \"%s\"\n",
586  ++warn_count ;
587  BEGIN(INITIAL);
588  }}
589 
590 <ICOR,INITIAL,GETICOR>({l_letter}".")*{letter}*{l_letter}"."/{non_par_ws}+{l_letter} {
591  {
592  printf( "\"%s\", line %d: missing `\\ ' after \"%s\"\n",
594  ++warn_count ;
595  BEGIN(INITIAL);
596  }}
597 
598 <ICOR,INITIAL,GETICOR>{non_abbrev}/{non_par_ws}{u_letter} {
599  {
600  linecount();
601  printf("\"%s\", line %d: missing `\\@' before `.' in \"%s\"\n",
603  ++warn_count ;
604  BEGIN(INITIAL);
605  }}
606 
607 <ICOR,INITIAL,GETICOR>({hard_space}{space}|{space}{hard_space}) {
608 
609  printf("\"%s\", line %d: double space at \"%s\"\n",
611  ++warn_count;
612  linecount();
613  BEGIN(INITIAL);
614  }
615 
616 {c_bin}{ws}?(\\‍(\.|\,|\;|\:))*{ws}?\\ldots{ws}?(\\‍(\.|\,|\;|\:))*{ws}?{c_bin} {
617  printf("\"%s\", line %d: \\ldots should be \\cdots in \"%s\"\n",
619  ++warn_count;
620  linecount();
621  }
622 
623 <ICOR,INITIAL,GETICOR>[^\\]{l_bin}{ws}?(\\‍(\.|\,|\;|\:))*{ws}?\\cdots{ws}?(\\‍(\.|\,|\;|\:))*{ws}?[^\\]{l_bin} {
624  printf("\"%s\", line %d: \\cdots should be \\ldots in \"%s\"\n",
626  ++warn_count;
627  linecount();
628  BEGIN(INITIAL);
629  }
630 
631 {c_bin}{ws}?(\\‍(\.|\,|\;|\:))*{ws}?"."+{ws}?(\\‍(\.|\,|\;|\:))*{ws}?{c_bin} {
632  printf("\"%s\", line %d: Dots should be \\cdots in \"%s\"\n",
634  ++warn_count;
635  linecount();
636  }
637 
638 <ICOR,INITIAL,GETICOR>[^\\]{l_bin}{ws}?(\\‍(\.|\,|\;|\:))*{ws}?"."+{ws}?(\\‍(\.|\,|\;|\:))*{ws}?[^\\]{l_bin} {
639  printf("\"%s\", line %d: Dots should be \\ldots in \"%s\"\n",
641  ++warn_count;
642  linecount();
643  BEGIN(INITIAL);
644  }
645 
646 
647 <ICOR,INITIAL,GETICOR>\.\.\. {
648  printf("\"%s\", line %d: Dots should be ellipsis \"%s\"\n",
650  ++warn_count;
651  BEGIN(INITIAL);
652  }
653 
654 <ICOR,INITIAL,GETICOR>\\label\{[^#$%^&*+={\~"<>\n\t }]*[#$%^&*+={\~"<>\n\t ][^%}]*\} {
655  linecount();
656  printf("\"%s\", line %d: bad character in label \"%s\", see C.10.2\n",
658  }
659 
660 <ICOR,INITIAL,GETICOR>{par}"\\"ref/[^A-Za-z] {
661  linecount();
662  BEGIN(INITIAL);
663  }
664 
665 <ICOR,INITIAL,GETICOR>{ws}"\\"ref/[^A-Za-z] {
666  linecount();
667  printf("\"%s\", line %d: perhaps you should insert a `~' before \"%s\"\n",
669  BEGIN(INITIAL);
670  }
671 
672 <ICOR,INITIAL,GETICOR>{ws}"\\"footnote/[^A-Za-z] {
673  linecount();
674  printf("\"%s\", line %d: whitespace before footnote in \"%s\"\n",
676  BEGIN(INITIAL);
677  }
678 
679 
680 {primitive}/[^a-zA-Z] {
681  {
682  printf("\"%s\", line %d: Don't use \"%s\" in LaTeX documents\n",
684  ++warn_count ;
685  }}
686 
687 \\left{ws}*\\?. { linecount() ;}
688 \\right{ws}*\\?. { linecount(); }
689 
690 <ICOR,INITIAL,GETICOR>[^\{]\\{font_spec}/[ \t]*"{" {
691  {
692  linecount();
693  printf("\"%s\", line %d: Fontspecifiers don't take arguments. \"%s\"\n",
695  ++warn_count;
696  /* (void) input(); */
697  BEGIN(INITIAL);
698  }}
699 
700 \\‍([a-zA-Z\@]+\@[a-zA-Z\@]*|[a-zA-Z\@]*\@[a-zA-Z\@]+) {
701  {
702  printf("\"%s\", line %d: Do not use @ in LaTeX macro names. \"%s\"\n",
704  ++warn_count;
705  }}
706 
707 <ICOR,INITIAL,GETICOR>{ws}"'"+{letter}+ {
708  {
709  linecount();
710  printf("\"%s\", line %d: Use ` to begin quotation, not ' \"%s\"\n",
712  ++warn_count;
713  BEGIN(INITIAL);
714  }}
715 
716 <ICOR,INITIAL,GETICOR>{letter}+"`" {
717  {
718  printf("\"%s\", line %d: Use ' to end quotation, not ` \"%s\"\n",
720  ++warn_count;
721  BEGIN(INITIAL);
722  }}
723 
724 
725 <ICOR,INITIAL,GETICOR>{ws}+{punct} {
726  {
727  printf("\"%s\", line %d: Whitespace before punctation mark in \"%s\"\n",
729  ++warn_count;
730  linecount();
731  BEGIN(INITIAL);
732  }}
733 
734 "%" { BEGIN(COMMENT); }
#define COMMENT
Definition: scanst.h:29
735 
736 <COMMENT>\n { BEGIN(INITIAL); ++line_count; }
737 
738 <COMMENT>. { ; }
739 
740 
741 \\‍(input|include)([ \t]|"{") { BEGIN(INCLUDE); }
#define INCLUDE
Definition: lacheck.c:2194
742 
743 <INCLUDE>[^\}\n]+ {
744  {
745  if ( strstr(yytext,".sty") == NULL )
746  {
747  printf("** %s:\n", yytext);
749  }
750  else
751  {
752  printf("\"%s\", line %d: Style file `%s\' omitted.\n",
753  file_name,
754  line_count,
755  yytext);
756  input();
757  }
758  BEGIN(INITIAL);
759  }}
#define NULL
Definition: ftobjs.h:61
void input_file(char *file_nam)
Definition: lacheck.l:935
760 
761 \\endinput/[^A-Za-z] |
762 <<EOF>> {
763  if (--istackp < 0)
764  yyterminate();
765 
766  else
767  {
768  fclose(yyin);
771  free(file_name);
774  input();
775  BEGIN(INITIAL);
776  }
777 
778  }
#define free(a)
Definition: decNumber.cpp:310
#define yyterminate()
Definition: detex.c:2000
#define yyin
#define yy_switch_to_buffer
#define fclose
Definition: debug.h:100
int istackp
Definition: lacheck.c:2182
input_ * istack
Definition: lacheck.c:2180
void f_checkend(char *name)
Definition: lacheck.l:1084
char * name
Definition: lacheck.c:2176
int linenum
Definition: lacheck.c:2177
779 
780 
781 . { ; }
782 %%
783 static void print_version (void)
784 {
785  printf("%s (TeX Live) %s\n", PROGNAME, "1.29");
786  puts("$Id: lacheck.l 51590 2019-07-09 15:26:51Z karl $");
787  printf("License GPLv1+: GNU GPL version 1 or later");
788  puts(" <https://gnu.org/licenses/gpl.html>.");
789  puts("This is free software: you are free to change and redistribute it.");
790  puts("There is NO WARRANTY, to the extent permitted by law.");
791  puts("Written by Kresten Krab Thorup and Per Abrahamsen.");
792 }
793 
794 static void print_help (void)
795 {
796  printf("Usage: lacheck FILENAME[.tex]\n");
797  printf("A consistency checker for LaTeX documents.\n\n");
798  printf("Document context is displayed in \"double quotes\".\n");
799  printf("All messages are only warnings!\n");
800  printf("Your document may be right even though LaCheck says");
801  printf(" otherwise.\n\n");
802  print_version();
803  printf("\nEmail bug reports to tex-live@tug.org.\n");
804 }
805 
806 int main(int argc, char *argv[])
807 {
808  /* allocate initial stacks */
809  gstack = (tex_group *)malloc(gstack_size * sizeof(tex_group));
810  istack = (input_ *)malloc(istack_size * sizeof(input_));
811  if ( gstack == NULL || istack == NULL ) {
812  fprintf(stderr, "%s: not enough memory for stacks\n", PROGNAME);
813  exit(3);
814  }
815 
816  if (argc == 2)
817  {
818  if (strcmp(argv[1], "--help") == 0) {
819  print_help();
820  exit(0);
821  } else if (strcmp(argv[1], "--version") == 0) {
822  print_version();
823  exit(0);
824  }
825  if ( (file_name = (char*) malloc(strlen(argv[1]) + 5)) == NULL ) {
826  fprintf(stderr, "%s: out of memory\n", PROGNAME);
827  exit(3);
828  }
829 
830  strcpy(file_name, argv[1]);
831  strcat(file_name, ".tex" );
832 
833  if ((yyin = fopen( file_name, "r")) != NULL )
834  {
835  push(file_name, 3, 1);
836  yylex();
838  }
839  else {
840  file_name[strlen(file_name) - 4] = '\0';
841  if ((yyin = fopen( file_name, "r")) != NULL )
842  {
843  push(file_name, 3, 1);
844  yylex();
846  }
847  else
848  {
849  fprintf(stderr, "%s: Could not open ",PROGNAME);
850  perror(argv[1]);
851  exit(1);
852  }
853  }
854  /* printf("%s checked.\n", argv[1]); */
855  }
856  else
857  {
858  printf("Usage: lacheck FILENAME[.tex]\n");
859  printf("Try 'lacheck --help' for more information.\n");
860  exit(1);
861  }
862  return(0);
863 }
864 
865 int yywrap(void) { return 1; }
866 
867 #ifdef NEED_STRSTR
868 char *
869 strstr(string, substring)
870  register char *string; /* String to search. */
871  char *substring; /* Substring to try to find in string. */
872 {
873  register char *a, *b;
874 
875  /* First scan quickly through the two strings looking for a
876  * single-character match. When it's found, then compare the
877  * rest of the substring.
878  */
879 
880  b = substring;
881  if (*b == 0) {
882  return string;
883  }
884  for ( ; *string != 0; string += 1) {
885  if (*string != *b) {
886  continue;
887  }
888  a = string;
889  while (1) {
890  if (*b == 0) {
891  return string;
892  }
893  if (*a++ != *b++) {
894  break;
895  }
896  }
897  b = substring;
898  }
899  return (char *) 0;
900 }
901 #endif /* NEED_STRSTR */
902 
903 void push(const char *p_name, int p_type, int p_line)
904 {
905  if ( gstackp == gstack_size ) { /* extend stack */
906  gstack_size *= 2;
908  if ( gstack == NULL ) {
909  fprintf(stderr, "%s: stack out of memory", PROGNAME);
910  exit(3);
911  }
912  }
913 
914  if ( (gstack[gstackp].s_name =
915  (char *)malloc(strlen(p_name) + 1)) == NULL ||
916  (gstack[gstackp].s_file =
917  (char *)malloc(strlen(file_name) + 1)) == NULL ) {
918  fprintf(stderr, "%s: out of memory\n", PROGNAME);
919  exit(3);
920  }
921 
922  strcpy(gstack[gstackp].s_name, p_name);
923  gstack[gstackp].s_type = p_type;
924  gstack[gstackp].s_line = p_line;
925  gstack[gstackp].italic = ( (p_type == 4 || p_type == 5)
926  ? 1
927  : ( gstackp
928  ? gstack[gstackp - 1].italic
929  : 0));
931  ++gstackp;
932 
933 }
934 
935 void input_file(char *file_nam)
936 {
937  char *tmp_file_name;
938  FILE *tmp_yyin;
939 
940  if ( (tmp_file_name = (char*) malloc(strlen(file_nam) + 5)) == NULL ) {
941  fprintf(stderr, "%s: out of memory\n", PROGNAME);
942  exit(3);
943  }
944  strcpy(tmp_file_name,file_nam);
945 
946  if (istackp == istack_size) { /* extend stack */
947  istack_size *= 2;
948  istack = (input_ *)realloc(istack, istack_size * sizeof(input_));
949  if ( istack == NULL ) {
950  fprintf(stderr, "%s: \\input stack out of memory\n", PROGNAME);
951  exit(3);
952  }
953  }
954 
958  ++istackp;
959 
960  (void) strcat(tmp_file_name, ".tex");
961  if ((tmp_yyin = fopen( tmp_file_name, "r")) != NULL )
962  {
963  yyin = tmp_yyin;
965  file_name = tmp_file_name;
966  push(file_name, 3, 1);
967  line_count = 1;
968  }
969  else {
970  tmp_file_name[strlen(tmp_file_name) - 4] = '\0';
971  if ((tmp_yyin = fopen( tmp_file_name , "r")) != NULL )
972  {
973  yyin = tmp_yyin;
975  file_name = tmp_file_name;
976  push(file_name, 3, 1);
977  line_count = 1;
978  }
979  else
980  {
981  --istackp;
982  free(tmp_file_name);
983  printf("\"%s\", line %d: Could not open \"%s\"\n",
984  file_name,
985  line_count,
986  file_nam);
987  input();
988  }
989  }
990 }
991 
992 void pop(void)
993 {
994  if ( gstackp == 0 )
995  {
996  fprintf(stderr, "%s: Stack underflow\n", PROGNAME);
997  exit(4);
998  }
999  --gstackp;
1000 
1001  free(gstack[gstackp].s_name);
1003 }
1004 
1005 static void print_bg_command(char *name)
1006 {
1007 
1008  switch (CG_TYPE) {
1009 
1010  case 2:
1011  printf("\\begin{%s}", name);
1012  break;
1013 
1014  case 3:
1015  printf("beginning of file %s", name);
1016  break;
1017 
1018  case 4:
1019  printf("math begin %s", name);
1020  break;
1021 
1022  case 5:
1023  printf("display math begin %s", name);
1024  break;
1025 
1026  default:
1027  printf("%s", name);
1028 
1029  }
1030 }
1031 
1032 static void print_eg_command(char *name, int type)
1033 {
1034 
1035  switch (type) {
1036 
1037  case 2:
1038  printf("\\end{%s}", name);
1039  break;
1040 
1041  case 3:
1042  printf("end of file %s", name);
1043  break;
1044 
1045  case 4:
1046  printf("math end %s", name);
1047  break;
1048 
1049  case 5:
1050  printf("display math end %s", name);
1051  break;
1052 
1053  default:
1054  printf("%s", name);
1055  break;
1056  }
1057 }
1058 
1059 
1060 void g_checkend(int n)
1061 {
1062  if ( check_top_level_end(yytext,n) == 1 )
1063  {
1064  if ( CG_TYPE != n )
1066  else
1067  pop();
1068  }
1069 }
1070 
1071 void e_checkend(int n, char *name)
1072 {
1073  if ( check_top_level_end(name,n) == 1 )
1074  {
1075  if ( CG_TYPE != n || strcmp( CG_NAME, name ) != 0 )
1077 
1078  if ( CG_TYPE != 3 )
1079  pop();
1080 
1081  }
1082 }
1083 
1084 void f_checkend(char *name)
1085 {
1086  if ( check_top_level_end(name,3) == 1 )
1087  {
1088  if ( CG_TYPE != 3 || strcmp( CG_NAME, name ) != 0 )
1089 
1090  while( CG_TYPE != 3 )
1091  {
1092  print_bad_match(name,3);
1093  pop();
1094  }
1095 
1096  pop();
1097  }
1098 }
1099 
1100 void print_bad_match(char *end_command, int type)
1101 {
1102  printf("\"%s\", line %d: <- unmatched \"",
1103  file_name,
1104  line_count);
1105  print_eg_command(end_command, type);
1106  printf("\"\n");
1107 
1108  printf("\"%s\", line %d: -> unmatched \"",
1109  CG_FILE,
1110  CG_LINE);
1112  printf("\"\n");
1113  warn_count += 2;
1114 }
1115 
1116 int check_top_level_end(char *end_command, int type)
1117 {
1118  if ( gstackp == 0 )
1119  {
1120  printf("\"%s\", line %d: \"",
1121  file_name,
1122  line_count);
1123  print_eg_command(end_command, type);
1124  printf("\" found at top level\n");
1125  ++warn_count;
1126  return(0);
1127  }
1128  else
1129  return(1);
1130 }
1131 
1132 void linecount(void)
1133 {
1134  int i;
1135  for (i = 0; i < yyleng; i++)
1136  if(yytext[i] == '\n')
1137  line_count++;
1138 }
void __cdecl perror(char const *_ErrMsg)
short substring(const char *source, char *dest, unsigned long pos, long len)
Definition: Utility.c:47
#define type(a)
Definition: aptex-macros.h:171
#define n
Definition: t4ht.c:1290
#define b
Definition: jpegint.h:372
#define YY_CURRENT_BUFFER
Definition: detex.c:347
#define YY_BUF_SIZE
Definition: detex.c:227
#define fopen
Definition: xxstdio.h:21
char * strcpy()
static void
Definition: fpif.c:118
#define yy_create_buffer
#define a(n)
Definition: gpos-common.c:148
small capitals from c petite p scientific i
Definition: afcover.h:80
void exit()
#define fprintf
Definition: mendex.h:64
#define string
Definition: ctangleboot.c:111
#define malloc
Definition: alloca.c:91
tex_group * gstack
Definition: lacheck.c:2169
int istack_size
Definition: lacheck.c:2181
int gstackp
Definition: lacheck.c:2171
int gstack_size
Definition: lacheck.c:2170
int main(int argc, char *argv[])
Definition: lacheck.l:806
static void print_version(void)
Definition: lacheck.l:783
#define CG_FILE
int check_top_level_end(char *end_command, int type)
Definition: lacheck.l:1116
#define PROGNAME
int yylex(void)
Definition: lacheck.l:236
int yywrap(void)
Definition: lacheck.l:865
#define CG_LINE
static void print_eg_command(char *name, int type)
Definition: lacheck.l:1032
static void print_bg_command(char *name)
Definition: lacheck.l:1005
static void print_help(void)
Definition: lacheck.l:794
void pop(void)
Definition: lacheck.l:992
#define realloc
Definition: glob.c:206
YY_BUFFER_STATE stream
Definition: lacheck.c:2175
int s_type
Definition: lacheck.c:2163
int s_line
Definition: lacheck.c:2164
int italic
Definition: lacheck.c:2165
#define FILE
Definition: t1stdio.h:34
*job_name strlen((char *) job_name) - 4)
#define argv
Definition: xmain.c:270
#define argc
Definition: xmain.c:269