summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile2
-rw-r--r--Makefile.depend1
-rw-r--r--cgi.c2
-rw-r--r--chars.c1
-rw-r--r--demandoc.c3
-rw-r--r--libmandoc.h5
-rw-r--r--main.c110
-rw-r--r--man_macro.c1
-rw-r--r--man_validate.c1
-rw-r--r--mandoc.382
-rw-r--r--mandoc.h14
-rw-r--r--mandoc_headers.315
-rw-r--r--mandoc_msg.c335
-rw-r--r--mandoc_parse.h8
-rw-r--r--mandocd.c2
-rw-r--r--mandocdb.c3
-rw-r--r--mdoc_state.c1
-rw-r--r--msec.c1
-rw-r--r--read.c308
-rw-r--r--roff_term.c2
-rw-r--r--roff_validate.c2
-rw-r--r--st.c2
-rw-r--r--tbl_data.c1
-rw-r--r--tbl_layout.c1
24 files changed, 426 insertions, 477 deletions
diff --git a/Makefile b/Makefile
index 2327e451..99e06a76 100644
--- a/Makefile
+++ b/Makefile
@@ -96,6 +96,7 @@ SRCS = att.c \
man_validate.c \
mandoc.c \
mandoc_aux.c \
+ mandoc_msg.c \
mandoc_ohash.c \
mandoc_xr.c \
mandocd.c \
@@ -237,6 +238,7 @@ LIBMANDOC_OBJS = $(LIBMAN_OBJS) \
chars.o \
mandoc.o \
mandoc_aux.o \
+ mandoc_msg.o \
mandoc_ohash.o \
mandoc_xr.o \
msec.o \
diff --git a/Makefile.depend b/Makefile.depend
index 1e989baf..827b4763 100644
--- a/Makefile.depend
+++ b/Makefile.depend
@@ -40,6 +40,7 @@ man_term.o: man_term.c config.h mandoc_aux.h roff.h man.h out.h term.h main.h
man_validate.o: man_validate.c config.h mandoc_aux.h mandoc.h roff.h man.h libmandoc.h roff_int.h libman.h
mandoc.o: mandoc.c config.h mandoc_aux.h mandoc.h roff.h libmandoc.h
mandoc_aux.o: mandoc_aux.c config.h mandoc.h mandoc_aux.h
+mandoc_msg.o: mandoc_msg.c mandoc.h
mandoc_ohash.o: mandoc_ohash.c mandoc_aux.h mandoc_ohash.h compat_ohash.h
mandoc_xr.o: mandoc_xr.c mandoc_aux.h mandoc_ohash.h compat_ohash.h mandoc_xr.h
mandocd.o: mandocd.c config.h mandoc.h roff.h mdoc.h man.h mandoc_parse.h main.h manconf.h
diff --git a/cgi.c b/cgi.c
index 47ebe454..e23e1ac9 100644
--- a/cgi.c
+++ b/cgi.c
@@ -861,7 +861,7 @@ resp_format(const struct req *req, const char *file)
mchars_alloc();
mp = mparse_alloc(MPARSE_SO | MPARSE_UTF8 | MPARSE_LATIN1,
- MANDOCERR_MAX, NULL, MANDOC_OS_OTHER, req->q.manpath);
+ MANDOC_OS_OTHER, req->q.manpath);
mparse_readfd(mp, fd, file);
close(fd);
diff --git a/chars.c b/chars.c
index ebc7cf91..581f9abc 100644
--- a/chars.c
+++ b/chars.c
@@ -23,6 +23,7 @@
#include <ctype.h>
#include <stddef.h>
#include <stdint.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
diff --git a/demandoc.c b/demandoc.c
index 96c7fd15..7ec28bf7 100644
--- a/demandoc.c
+++ b/demandoc.c
@@ -79,8 +79,7 @@ main(int argc, char *argv[])
argv += optind;
mchars_alloc();
- mp = mparse_alloc(MPARSE_SO, MANDOCERR_MAX, NULL,
- MANDOC_OS_OTHER, NULL);
+ mp = mparse_alloc(MPARSE_SO, MANDOC_OS_OTHER, NULL);
assert(mp);
if (argc < 1)
diff --git a/libmandoc.h b/libmandoc.h
index 00e707b3..cd2a1ba2 100644
--- a/libmandoc.h
+++ b/libmandoc.h
@@ -49,11 +49,6 @@ struct mparse;
struct roff;
struct roff_man;
-void mandoc_msg(enum mandocerr, struct mparse *,
- int, int, const char *);
-void mandoc_vmsg(enum mandocerr, struct mparse *,
- int, int, const char *, ...)
- __attribute__((__format__ (__printf__, 5, 6)));
char *mandoc_getarg(struct mparse *, char **, int, int *);
char *mandoc_normdate(struct roff_man *, char *, int, int);
int mandoc_eos(const char *, size_t);
diff --git a/main.c b/main.c
index d00baaa5..f74b84be 100644
--- a/main.c
+++ b/main.c
@@ -82,7 +82,6 @@ struct curparse {
void *outdata; /* data for output */
char *os_s; /* operating system for display */
int wstop; /* stop after a file with a warning */
- enum mandocerr mmin; /* ignore messages below this */
enum mandoc_os os_e; /* check base system conventions */
enum outt outtype; /* which output to use */
};
@@ -90,7 +89,7 @@ struct curparse {
int mandocdb(int, char *[]);
-static void check_xr(const char *);
+static void check_xr(void);
static int fs_lookup(const struct manpaths *,
size_t ipath, const char *,
const char *, const char *,
@@ -100,8 +99,6 @@ static int fs_search(const struct mansearch *,
struct manpage **, size_t *);
static int koptions(int *, char *);
static void moptions(int *, char *);
-static void mmsg(enum mandocerr, enum mandoclevel,
- const char *, int, int, const char *);
static void outdata_alloc(struct curparse *);
static void parse(struct curparse *, int, const char *);
static void passthrough(const char *, int, int);
@@ -113,8 +110,6 @@ static int woptions(struct curparse *, char *);
static const int sec_prios[] = {1, 4, 5, 8, 6, 3, 7, 2, 9};
static char help_arg[] = "help";
static char *help_argv[] = {help_arg, NULL};
-static enum mandoclevel rc;
-static FILE *mmsg_stream;
int
@@ -192,10 +187,8 @@ main(int argc, char *argv[])
memset(&curp, 0, sizeof(struct curparse));
curp.outtype = OUTT_LOCALE;
- curp.mmin = MANDOCERR_MAX;
curp.outopts = &conf.output;
options = MPARSE_SO | MPARSE_UTF8 | MPARSE_LATIN1;
- mmsg_stream = stderr;
use_pager = 1;
tag_files = NULL;
@@ -372,8 +365,6 @@ main(int argc, char *argv[])
#endif
}
- rc = MANDOCLEVEL_OK;
-
/* man(1), whatis(1), apropos(1) */
if (search.argmode != ARG_FILE) {
@@ -415,7 +406,7 @@ main(int argc, char *argv[])
if (sz == 0) {
if (search.argmode != ARG_NAME)
warnx("nothing appropriate");
- rc = MANDOCLEVEL_BADARG;
+ mandoc_msg_setrc(MANDOCLEVEL_BADARG);
goto out;
}
@@ -483,13 +474,15 @@ main(int argc, char *argv[])
moptions(&options, auxpaths);
mchars_alloc();
- curp.mp = mparse_alloc(options, curp.mmin, mmsg,
- curp.os_e, curp.os_s);
+ curp.mp = mparse_alloc(options, curp.os_e, curp.os_s);
if (argc < 1) {
if (use_pager)
tag_files = tag_init();
- parse(&curp, STDIN_FILENO, "<stdin>");
+ thisarg = "<stdin>";
+ mandoc_msg_setinfilename(thisarg);
+ parse(&curp, STDIN_FILENO, thisarg);
+ mandoc_msg_setinfilename(NULL);
}
/*
@@ -513,9 +506,12 @@ main(int argc, char *argv[])
(void)chdir(conf.manpath.paths[resp->ipath]);
else if (startdir != -1)
(void)fchdir(startdir);
- }
+ thisarg = resp->file;
+ } else
+ thisarg = *argv;
- fd = mparse_open(curp.mp, resp != NULL ? resp->file : *argv);
+ mandoc_msg_setinfilename(thisarg);
+ fd = mparse_open(curp.mp, thisarg);
if (fd != -1) {
if (use_pager) {
use_pager = 0;
@@ -527,10 +523,8 @@ main(int argc, char *argv[])
conf.output.tag : *argv;
}
- if (resp == NULL)
- parse(&curp, fd, *argv);
- else if (resp->form == FORM_SRC)
- parse(&curp, fd, resp->file);
+ if (resp == NULL || resp->form == FORM_SRC)
+ parse(&curp, fd, thisarg);
else
passthrough(resp->file, fd,
conf.output.synopsisonly);
@@ -542,7 +536,7 @@ main(int argc, char *argv[])
tag_files = NULL;
} else
warn("stdout");
- rc = MANDOCLEVEL_SYSERR;
+ mandoc_msg_setrc(MANDOCLEVEL_SYSERR);
break;
}
@@ -551,10 +545,10 @@ main(int argc, char *argv[])
outdata_alloc(&curp);
terminal_sepline(curp.outdata);
}
- } else if (rc < MANDOCLEVEL_ERROR)
- rc = MANDOCLEVEL_ERROR;
+ }
+ mandoc_msg_setinfilename(NULL);
- if (MANDOCLEVEL_OK != rc && curp.wstop)
+ if (curp.wstop && mandoc_msg_getrc() != MANDOCLEVEL_OK)
break;
if (resp != NULL)
@@ -645,7 +639,7 @@ out:
if (pid == -1) {
warn("wait");
- rc = MANDOCLEVEL_SYSERR;
+ mandoc_msg_setrc(MANDOCLEVEL_SYSERR);
break;
}
if (!WIFSTOPPED(status))
@@ -655,8 +649,7 @@ out:
}
tag_unlink();
}
-
- return (int)rc;
+ return (int)mandoc_msg_getrc();
}
static void
@@ -806,7 +799,6 @@ fs_search(const struct mansearch *cfg, const struct manpaths *paths,
static void
parse(struct curparse *curp, int fd, const char *file)
{
- enum mandoclevel rctmp;
struct roff_man *man;
/* Begin by parsing the file itself. */
@@ -814,18 +806,16 @@ parse(struct curparse *curp, int fd, const char *file)
assert(file);
assert(fd >= 0);
- rctmp = mparse_readfd(curp->mp, fd, file);
+ mparse_readfd(curp->mp, fd, file);
if (fd != STDIN_FILENO)
close(fd);
- if (rc < rctmp)
- rc = rctmp;
/*
* With -Wstop and warnings or errors of at least the requested
* level, do not produce output.
*/
- if (rctmp != MANDOCLEVEL_OK && curp->wstop)
+ if (curp->wstop && mandoc_msg_getrc() != MANDOCLEVEL_OK)
return;
if (curp->outdata == NULL)
@@ -889,13 +879,12 @@ parse(struct curparse *curp, int fd, const char *file)
break;
}
}
- if (curp->mmin < MANDOCERR_STYLE)
- check_xr(file);
- mparse_updaterc(curp->mp, &rc);
+ if (mandoc_msg_getmin() < MANDOCERR_STYLE)
+ check_xr();
}
static void
-check_xr(const char *file)
+check_xr(void)
{
static struct manpaths paths;
struct mansearch search;
@@ -923,8 +912,7 @@ check_xr(const char *file)
else
mandoc_asprintf(&cp, "Xr %s %s (%d times)",
xr->name, xr->sec, xr->count);
- mmsg(MANDOCERR_XR_BAD, MANDOCLEVEL_STYLE,
- file, xr->line, xr->pos + 1, cp);
+ mandoc_msg(MANDOCERR_XR_BAD, NULL, xr->line, xr->pos + 1, cp);
free(cp);
}
}
@@ -1024,8 +1012,7 @@ done:
fail:
free(line);
warn("%s: SYSERR: %s", file, syscall);
- if (rc < MANDOCLEVEL_SYSERR)
- rc = MANDOCLEVEL_SYSERR;
+ mandoc_msg_setrc(MANDOCLEVEL_SYSERR);
}
static int
@@ -1067,8 +1054,8 @@ toptions(struct curparse *curp, char *arg)
curp->outtype = OUTT_ASCII;
else if (0 == strcmp(arg, "lint")) {
curp->outtype = OUTT_LINT;
- curp->mmin = MANDOCERR_BASE;
- mmsg_stream = stdout;
+ mandoc_msg_setoutfile(stdout);
+ mandoc_msg_setmin(MANDOCERR_BASE);
} else if (0 == strcmp(arg, "tree"))
curp->outtype = OUTT_TREE;
else if (0 == strcmp(arg, "man"))
@@ -1119,29 +1106,29 @@ woptions(struct curparse *curp, char *arg)
break;
case 1:
case 2:
- curp->mmin = MANDOCERR_BASE;
+ mandoc_msg_setmin(MANDOCERR_BASE);
break;
case 3:
- curp->mmin = MANDOCERR_STYLE;
+ mandoc_msg_setmin(MANDOCERR_STYLE);
break;
case 4:
- curp->mmin = MANDOCERR_WARNING;
+ mandoc_msg_setmin(MANDOCERR_WARNING);
break;
case 5:
- curp->mmin = MANDOCERR_ERROR;
+ mandoc_msg_setmin(MANDOCERR_ERROR);
break;
case 6:
- curp->mmin = MANDOCERR_UNSUPP;
+ mandoc_msg_setmin(MANDOCERR_UNSUPP);
break;
case 7:
- curp->mmin = MANDOCERR_MAX;
+ mandoc_msg_setmin(MANDOCERR_MAX);
break;
case 8:
- curp->mmin = MANDOCERR_BASE;
+ mandoc_msg_setmin(MANDOCERR_BASE);
curp->os_e = MANDOC_OS_OPENBSD;
break;
case 9:
- curp->mmin = MANDOCERR_BASE;
+ mandoc_msg_setmin(MANDOCERR_BASE);
curp->os_e = MANDOC_OS_NETBSD;
break;
default:
@@ -1152,29 +1139,6 @@ woptions(struct curparse *curp, char *arg)
return 1;
}
-static void
-mmsg(enum mandocerr t, enum mandoclevel lvl,
- const char *file, int line, int col, const char *msg)
-{
- const char *mparse_msg;
-
- fprintf(mmsg_stream, "%s: %s:", getprogname(),
- file == NULL ? "<stdin>" : file);
-
- if (line)
- fprintf(mmsg_stream, "%d:%d:", line, col + 1);
-
- fprintf(mmsg_stream, " %s", mparse_strlevel(lvl));
-
- if ((mparse_msg = mparse_strerror(t)) != NULL)
- fprintf(mmsg_stream, ": %s", mparse_msg);
-
- if (msg)
- fprintf(mmsg_stream, ": %s", msg);
-
- fputc('\n', mmsg_stream);
-}
-
static pid_t
spawn_pager(struct tag_files *tag_files)
{
diff --git a/man_macro.c b/man_macro.c
index bc81bffb..ca481663 100644
--- a/man_macro.c
+++ b/man_macro.c
@@ -22,6 +22,7 @@
#include <assert.h>
#include <ctype.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
diff --git a/man_validate.c b/man_validate.c
index 806a6cdc..4070506d 100644
--- a/man_validate.c
+++ b/man_validate.c
@@ -24,6 +24,7 @@
#include <errno.h>
#include <limits.h>
#include <stdarg.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
diff --git a/mandoc.3 b/mandoc.3
index ea717816..93c4a1df 100644
--- a/mandoc.3
+++ b/mandoc.3
@@ -21,7 +21,6 @@
.Sh NAME
.Nm mandoc ,
.Nm deroff ,
-.Nm mandocmsg ,
.Nm man_validate ,
.Nm mdoc_validate ,
.Nm mparse_alloc ,
@@ -30,13 +29,11 @@
.Nm mparse_open ,
.Nm mparse_readfd ,
.Nm mparse_reset ,
-.Nm mparse_result ,
-.Nm mparse_strerror ,
-.Nm mparse_strlevel ,
-.Nm mparse_updaterc
+.Nm mparse_result
.Nd mandoc macro compiler library
.Sh SYNOPSIS
.In sys/types.h
+.In stdio.h
.In mandoc.h
.Pp
.Fd "#define ASCII_NBRSP"
@@ -45,21 +42,10 @@
.Ft struct mparse *
.Fo mparse_alloc
.Fa "int options"
-.Fa "enum mandocerr mmin"
-.Fa "mandocmsg mmsg"
.Fa "enum mandoc_os oe_e"
.Fa "char *os_s"
.Fc
.Ft void
-.Fo (*mandocmsg)
-.Fa "enum mandocerr errtype"
-.Fa "enum mandoclevel level"
-.Fa "const char *file"
-.Fa "int line"
-.Fa "int col"
-.Fa "const char *msg"
-.Fc
-.Ft void
.Fo mparse_free
.Fa "struct mparse *parse"
.Fc
@@ -72,7 +58,7 @@
.Fa "struct mparse *parse"
.Fa "const char *fname"
.Fc
-.Ft "enum mandoclevel"
+.Ft void
.Fo mparse_readfd
.Fa "struct mparse *parse"
.Fa "int fd"
@@ -88,19 +74,6 @@
.Fa "struct roff_man **man"
.Fa "char **sodest"
.Fc
-.Ft "const char *"
-.Fo mparse_strerror
-.Fa "enum mandocerr"
-.Fc
-.Ft "const char *"
-.Fo mparse_strlevel
-.Fa "enum mandoclevel"
-.Fc
-.Ft void
-.Fo mparse_updaterc
-.Fa "struct mparse *parse"
-.Fa "enum mandoclevel *rc"
-.Fc
.In roff.h
.Ft void
.Fo deroff
@@ -222,9 +195,6 @@ and freed with
This may be used across parsed input if
.Fn mparse_reset
is called between parses.
-.It Vt "mandocmsg"
-A prototype for a function to handle error and warning
-messages emitted by the parser.
.El
.Ss Functions
.Bl -ohang
@@ -289,24 +259,6 @@ This is for example useful in
.Xr makewhatis 8
.Fl Q
to quickly build minimal databases.
-.It Ar mmin
-Can be set to
-.Dv MANDOCERR_BASE ,
-.Dv MANDOCERR_STYLE ,
-.Dv MANDOCERR_WARNING ,
-.Dv MANDOCERR_ERROR ,
-.Dv MANDOCERR_UNSUPP ,
-or
-.Dv MANDOCERR_MAX .
-Messages below the selected level will be suppressed.
-.It Ar mmsg
-A callback function to handle errors and warnings.
-See
-.Pa main.c
-for an example.
-If printing of error messages is not desired,
-.Dv NULL
-may be passed.
.It Ar os_e
Operating system to check base system conventions for.
If
@@ -400,34 +352,6 @@ Declared in
.In mandoc.h ,
implemented in
.Pa read.c .
-.It Fn mparse_strerror
-Return a statically-allocated string representation of an error code.
-Declared in
-.In mandoc.h ,
-implemented in
-.Pa read.c .
-.It Fn mparse_strlevel
-Return a statically-allocated string representation of a level code.
-Declared in
-.In mandoc.h ,
-implemented in
-.Pa read.c .
-.It Fn mparse_updaterc
-If the highest warning or error level that occurred during the current
-.Fa parse
-is higher than
-.Pf * Fa rc ,
-update
-.Pf * Fa rc
-accordingly.
-This is useful after calling
-.Fn mdoc_validate
-or
-.Fn man_validate .
-Declared in
-.In mandoc.h ,
-implemented in
-.Pa read.c .
.El
.Ss Variables
.Bl -ohang
diff --git a/mandoc.h b/mandoc.h
index b31e70ed..60a16e97 100644
--- a/mandoc.h
+++ b/mandoc.h
@@ -265,11 +265,19 @@ enum mandoc_esc {
ESCAPE_OVERSTRIKE /* overstrike all chars in the argument */
};
-typedef void (*mandocmsg)(enum mandocerr, enum mandoclevel,
- const char *, int, int, const char *);
-
enum mandoc_esc mandoc_escape(const char **, const char **, int *);
+void mandoc_msg_setoutfile(FILE *);
+const char *mandoc_msg_getinfilename(void);
+void mandoc_msg_setinfilename(const char *);
+enum mandocerr mandoc_msg_getmin(void);
+void mandoc_msg_setmin(enum mandocerr);
+enum mandoclevel mandoc_msg_getrc(void);
+void mandoc_msg_setrc(enum mandoclevel);
+void mandoc_msg(enum mandocerr, void *, int, int, const char *);
+void mandoc_vmsg(enum mandocerr, void *, int, int,
+ const char *, ...)
+ __attribute__((__format__ (__printf__, 5, 6)));
void mchars_alloc(void);
void mchars_free(void);
int mchars_num2char(const char *, size_t);
diff --git a/mandoc_headers.3 b/mandoc_headers.3
index 29b8ab20..81fc21bb 100644
--- a/mandoc_headers.3
+++ b/mandoc_headers.3
@@ -90,18 +90,23 @@ can be used everywhere.
Requires
.In sys/types.h
for
-.Vt size_t .
+.Vt size_t
+and
+.In stdio.h
+for
+.Vt FILE .
.Pp
Provides
.Vt enum mandoc_esc ,
.Vt enum mandocerr ,
.Vt enum mandoclevel ,
-the function prototype typedef
-.Fn mandocmsg ,
the function
.Xr mandoc_escape 3 ,
-and the functions described in
-.Xr mchars_alloc 3 .
+the functions described in
+.Xr mchars_alloc 3 ,
+and the
+.Fn mandoc_msg*
+functions.
.It Qq Pa roff.h
Common data types for all syntax trees and related functions;
can be used everywhere.
diff --git a/mandoc_msg.c b/mandoc_msg.c
new file mode 100644
index 00000000..aa0cce5a
--- /dev/null
+++ b/mandoc_msg.c
@@ -0,0 +1,335 @@
+/* $OpenBSD$ */
+/*
+ * Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
+ * Copyright (c) 2014,2015,2016,2017,2018 Ingo Schwarze <schwarze@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "mandoc.h"
+
+static const enum mandocerr lowest_type[MANDOCLEVEL_MAX] = {
+ MANDOCERR_OK,
+ MANDOCERR_OK,
+ MANDOCERR_WARNING,
+ MANDOCERR_ERROR,
+ MANDOCERR_UNSUPP,
+ MANDOCERR_MAX,
+ MANDOCERR_MAX
+};
+
+static const char *const level_name[MANDOCLEVEL_MAX] = {
+ "SUCCESS",
+ "STYLE",
+ "WARNING",
+ "ERROR",
+ "UNSUPP",
+ "BADARG",
+ "SYSERR"
+};
+
+static const char *const type_message[MANDOCERR_MAX] = {
+ "ok",
+
+ "base system convention",
+
+ "Mdocdate found",
+ "Mdocdate missing",
+ "unknown architecture",
+ "operating system explicitly specified",
+ "RCS id missing",
+ "referenced manual not found",
+
+ "generic style suggestion",
+
+ "legacy man(7) date format",
+ "normalizing date format to",
+ "lower case character in document title",
+ "duplicate RCS id",
+ "possible typo in section name",
+ "unterminated quoted argument",
+ "useless macro",
+ "consider using OS macro",
+ "errnos out of order",
+ "duplicate errno",
+ "trailing delimiter",
+ "no blank before trailing delimiter",
+ "fill mode already enabled, skipping",
+ "fill mode already disabled, skipping",
+ "verbatim \"--\", maybe consider using \\(em",
+ "function name without markup",
+ "whitespace at end of input line",
+ "bad comment style",
+
+ "generic warning",
+
+ /* related to the prologue */
+ "missing manual title, using UNTITLED",
+ "missing manual title, using \"\"",
+ "missing manual section, using \"\"",
+ "unknown manual section",
+ "missing date, using today's date",
+ "cannot parse date, using it verbatim",
+ "date in the future, using it anyway",
+ "missing Os macro, using \"\"",
+ "late prologue macro",
+ "prologue macros out of order",
+
+ /* related to document structure */
+ ".so is fragile, better use ln(1)",
+ "no document body",
+ "content before first section header",
+ "first section is not \"NAME\"",
+ "NAME section without Nm before Nd",
+ "NAME section without description",
+ "description not at the end of NAME",
+ "bad NAME section content",
+ "missing comma before name",
+ "missing description line, using \"\"",
+ "description line outside NAME section",
+ "sections out of conventional order",
+ "duplicate section title",
+ "unexpected section",
+ "cross reference to self",
+ "unusual Xr order",
+ "unusual Xr punctuation",
+ "AUTHORS section without An macro",
+
+ /* related to macros and nesting */
+ "obsolete macro",
+ "macro neither callable nor escaped",
+ "skipping paragraph macro",
+ "moving paragraph macro out of list",
+ "skipping no-space macro",
+ "blocks badly nested",
+ "nested displays are not portable",
+ "moving content out of list",
+ "first macro on line",
+ "line scope broken",
+ "skipping blank line in line scope",
+
+ /* related to missing macro arguments */
+ "skipping empty request",
+ "conditional request controls empty scope",
+ "skipping empty macro",
+ "empty block",
+ "empty argument, using 0n",
+ "missing display type, using -ragged",
+ "list type is not the first argument",
+ "missing -width in -tag list, using 6n",
+ "missing utility name, using \"\"",
+ "missing function name, using \"\"",
+ "empty head in list item",
+ "empty list item",
+ "missing argument, using next line",
+ "missing font type, using \\fR",
+ "unknown font type, using \\fR",
+ "nothing follows prefix",
+ "empty reference block",
+ "missing section argument",
+ "missing -std argument, adding it",
+ "missing option string, using \"\"",
+ "missing resource identifier, using \"\"",
+ "missing eqn box, using \"\"",
+
+ /* related to bad macro arguments */
+ "duplicate argument",
+ "skipping duplicate argument",
+ "skipping duplicate display type",
+ "skipping duplicate list type",
+ "skipping -width argument",
+ "wrong number of cells",
+ "unknown AT&T UNIX version",
+ "comma in function argument",
+ "parenthesis in function name",
+ "unknown library name",
+ "invalid content in Rs block",
+ "invalid Boolean argument",
+ "argument contains two font escapes",
+ "unknown font, skipping request",
+ "odd number of characters in request",
+
+ /* related to plain text */
+ "blank line in fill mode, using .sp",
+ "tab in filled text",
+ "new sentence, new line",
+ "invalid escape sequence",
+ "undefined string, using \"\"",
+
+ /* related to tables */
+ "tbl line starts with span",
+ "tbl column starts with span",
+ "skipping vertical bar in tbl layout",
+
+ "generic error",
+
+ /* related to tables */
+ "non-alphabetic character in tbl options",
+ "skipping unknown tbl option",
+ "missing tbl option argument",
+ "wrong tbl option argument size",
+ "empty tbl layout",
+ "invalid character in tbl layout",
+ "unmatched parenthesis in tbl layout",
+ "tbl without any data cells",
+ "ignoring data in spanned tbl cell",
+ "ignoring extra tbl data cells",
+ "data block open at end of tbl",
+
+ /* related to document structure and macros */
+ NULL,
+ "duplicate prologue macro",
+ "skipping late title macro",
+ "input stack limit exceeded, infinite loop?",
+ "skipping bad character",
+ "skipping unknown macro",
+ "ignoring request outside macro",
+ "skipping insecure request",
+ "skipping item outside list",
+ "skipping column outside column list",
+ "skipping end of block that is not open",
+ "fewer RS blocks open, skipping",
+ "inserting missing end of block",
+ "appending missing end of block",
+
+ /* related to request and macro arguments */
+ "escaped character not allowed in a name",
+ "using macro argument outside macro",
+ "argument number is not numeric",
+ "NOT IMPLEMENTED: Bd -file",
+ "skipping display without arguments",
+ "missing list type, using -item",
+ "argument is not numeric, using 1",
+ "argument is not a character",
+ "missing manual name, using \"\"",
+ "uname(3) system call failed, using UNKNOWN",
+ "unknown standard specifier",
+ "skipping request without numeric argument",
+ "excessive shift",
+ "NOT IMPLEMENTED: .so with absolute path or \"..\"",
+ ".so request failed",
+ "skipping all arguments",
+ "skipping excess arguments",
+ "divide by zero",
+
+ "unsupported feature",
+ "input too large",
+ "unsupported control character",
+ "unsupported roff request",
+ "nested .while loops",
+ "end of scope with open .while loop",
+ "end of .while loop in inner scope",
+ "cannot continue this .while loop",
+ "eqn delim option in tbl",
+ "unsupported tbl layout modifier",
+ "ignoring macro in table",
+};
+
+static FILE *fileptr = stderr;
+static const char *filename = NULL;
+static enum mandocerr min_type = MANDOCERR_MAX;
+static enum mandoclevel rc = MANDOCLEVEL_OK;
+
+
+void
+mandoc_msg_setoutfile(FILE *fp)
+{
+ fileptr = fp;
+}
+
+const char *
+mandoc_msg_getinfilename(void)
+{
+ return filename;
+}
+
+void
+mandoc_msg_setinfilename(const char *fn)
+{
+ filename = fn;
+}
+
+enum mandocerr
+mandoc_msg_getmin(void)
+{
+ return min_type;
+}
+
+void
+mandoc_msg_setmin(enum mandocerr t)
+{
+ min_type = t;
+}
+
+enum mandoclevel
+mandoc_msg_getrc(void)
+{
+ return rc;
+}
+
+void
+mandoc_msg_setrc(enum mandoclevel level)
+{
+ if (rc < level)
+ rc = level;
+}
+
+void
+mandoc_vmsg(enum mandocerr t, void *dummy, int line, int col,
+ const char *fmt, ...)
+{
+ va_list ap;
+ enum mandoclevel level;
+
+ if (t < min_type && t != MANDOCERR_FILE)
+ return;
+
+ level = MANDOCLEVEL_UNSUPP;
+ while (t < lowest_type[level])
+ level--;
+ mandoc_msg_setrc(level);
+
+ if (fileptr == NULL)
+ return;
+
+ fprintf(fileptr, "%s:", getprogname());
+ if (filename != NULL)
+ fprintf(fileptr, " %s:", filename);
+
+ if (line > 0)
+ fprintf(fileptr, "%d:%d:", line, col + 1);
+
+ fprintf(fileptr, " %s", level_name[level]);
+ if (type_message[t] != NULL)
+ fprintf(fileptr, ": %s", type_message[t]);
+
+ if (fmt != NULL) {
+ fprintf(fileptr, ": ");
+ va_start(ap, fmt);
+ vfprintf(fileptr, fmt, ap);
+ va_end(ap);
+ }
+ fputc('\n', fileptr);
+}
+
+void
+mandoc_msg(enum mandocerr t, void *dummy, int line, int col, const char *msg)
+{
+ if (msg == NULL)
+ mandoc_vmsg(t, dummy, line, col, NULL);
+ else
+ mandoc_vmsg(t, dummy, line, col, "%s", msg);
+}
diff --git a/mandoc_parse.h b/mandoc_parse.h
index 05ac3cbb..130a59c6 100644
--- a/mandoc_parse.h
+++ b/mandoc_parse.h
@@ -33,17 +33,13 @@
struct mparse;
struct roff_man;
-struct mparse *mparse_alloc(int, enum mandocerr, mandocmsg,
- enum mandoc_os, const char *);
+struct mparse *mparse_alloc(int, enum mandoc_os, const char *);
void mparse_copy(const struct mparse *);
void mparse_free(struct mparse *);
int mparse_open(struct mparse *, const char *);
-enum mandoclevel mparse_readfd(struct mparse *, int, const char *);
+void mparse_readfd(struct mparse *, int, const char *);
enum mandoclevel mparse_readmem(struct mparse *, void *, size_t,
const char *);
void mparse_reset(struct mparse *);
void mparse_result(struct mparse *,
struct roff_man **, char **);
-const char *mparse_strerror(enum mandocerr);
-const char *mparse_strlevel(enum mandoclevel);
-void mparse_updaterc(struct mparse *, enum mandoclevel *);
diff --git a/mandocd.c b/mandocd.c
index b9d212f4..5e43c7a6 100644
--- a/mandocd.c
+++ b/mandocd.c
@@ -172,7 +172,7 @@ main(int argc, char *argv[])
mchars_alloc();
parser = mparse_alloc(MPARSE_SO | MPARSE_UTF8 | MPARSE_LATIN1,
- MANDOCERR_MAX, NULL, MANDOC_OS_OTHER, defos);
+ MANDOC_OS_OTHER, defos);
memset(&options, 0, sizeof(options));
switch (outtype) {
diff --git a/mandocdb.c b/mandocdb.c
index 8541bb3e..b46c94cb 100644
--- a/mandocdb.c
+++ b/mandocdb.c
@@ -422,8 +422,7 @@ mandocdb(int argc, char *argv[])
exitcode = (int)MANDOCLEVEL_OK;
mchars_alloc();
- mp = mparse_alloc(mparse_options, MANDOCERR_MAX, NULL,
- MANDOC_OS_OTHER, NULL);
+ mp = mparse_alloc(mparse_options, MANDOC_OS_OTHER, NULL);
mandoc_ohash_init(&mpages, 6, offsetof(struct mpage, inodev));
mandoc_ohash_init(&mlinks, 6, offsetof(struct mlink, file));
diff --git a/mdoc_state.c b/mdoc_state.c
index f96065ba..7b887091 100644
--- a/mdoc_state.c
+++ b/mdoc_state.c
@@ -17,6 +17,7 @@
#include <sys/types.h>
#include <assert.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
diff --git a/msec.c b/msec.c
index da0c66ba..236f5fa5 100644
--- a/msec.c
+++ b/msec.c
@@ -18,6 +18,7 @@
#include <sys/types.h>
+#include <stdio.h>
#include <string.h>
#include "mandoc.h"
diff --git a/read.c b/read.c
index 25924a3c..530a1551 100644
--- a/read.c
+++ b/read.c
@@ -48,14 +48,10 @@ struct mparse {
struct roff *roff; /* roff parser (!NULL) */
struct roff_man *man; /* man parser */
char *sodest; /* filename pointed to by .so */
- const char *file; /* filename of current input file */
struct buf *primary; /* buffer currently being parsed */
struct buf *secondary; /* copy of top level input */
struct buf *loop; /* open .while request line */
const char *os_s; /* default operating system */
- mandocmsg mmsg; /* warning/error message handler */
- enum mandoclevel file_status; /* status of current parse */
- enum mandocerr mmin; /* ignore messages below this */
int options; /* parser options */
int gzip; /* current input file is gzipped */
int filenc; /* encoding of the current file */
@@ -67,229 +63,11 @@ static void choose_parser(struct mparse *);
static void free_buf_list(struct buf *);
static void resize_buf(struct buf *, size_t);
static int mparse_buf_r(struct mparse *, struct buf, size_t, int);
-static int read_whole_file(struct mparse *, const char *, int,
- struct buf *, int *);
+static int read_whole_file(struct mparse *, int, struct buf *, int *);
static void mparse_end(struct mparse *);
static void mparse_parse_buffer(struct mparse *, struct buf,
const char *);
-static const enum mandocerr mandoclimits[MANDOCLEVEL_MAX] = {
- MANDOCERR_OK,
- MANDOCERR_OK,
- MANDOCERR_WARNING,
- MANDOCERR_ERROR,
- MANDOCERR_UNSUPP,
- MANDOCERR_MAX,
- MANDOCERR_MAX
-};
-
-static const char * const mandocerrs[MANDOCERR_MAX] = {
- "ok",
-
- "base system convention",
-
- "Mdocdate found",
- "Mdocdate missing",
- "unknown architecture",
- "operating system explicitly specified",
- "RCS id missing",
- "referenced manual not found",
-
- "generic style suggestion",
-
- "legacy man(7) date format",
- "normalizing date format to",
- "lower case character in document title",
- "duplicate RCS id",
- "possible typo in section name",
- "unterminated quoted argument",
- "useless macro",
- "consider using OS macro",
- "errnos out of order",
- "duplicate errno",
- "trailing delimiter",
- "no blank before trailing delimiter",
- "fill mode already enabled, skipping",
- "fill mode already disabled, skipping",
- "verbatim \"--\", maybe consider using \\(em",
- "function name without markup",
- "whitespace at end of input line",
- "bad comment style",
-
- "generic warning",
-
- /* related to the prologue */
- "missing manual title, using UNTITLED",
- "missing manual title, using \"\"",
- "missing manual section, using \"\"",
- "unknown manual section",
- "missing date, using today's date",
- "cannot parse date, using it verbatim",
- "date in the future, using it anyway",
- "missing Os macro, using \"\"",
- "late prologue macro",
- "prologue macros out of order",
-
- /* related to document structure */
- ".so is fragile, better use ln(1)",
- "no document body",
- "content before first section header",
- "first section is not \"NAME\"",
- "NAME section without Nm before Nd",
- "NAME section without description",
- "description not at the end of NAME",
- "bad NAME section content",
- "missing comma before name",
- "missing description line, using \"\"",
- "description line outside NAME section",
- "sections out of conventional order",
- "duplicate section title",
- "unexpected section",
- "cross reference to self",
- "unusual Xr order",
- "unusual Xr punctuation",
- "AUTHORS section without An macro",
-
- /* related to macros and nesting */
- "obsolete macro",
- "macro neither callable nor escaped",
- "skipping paragraph macro",
- "moving paragraph macro out of list",
- "skipping no-space macro",
- "blocks badly nested",
- "nested displays are not portable",
- "moving content out of list",
- "first macro on line",
- "line scope broken",
- "skipping blank line in line scope",
-
- /* related to missing macro arguments */
- "skipping empty request",
- "conditional request controls empty scope",
- "skipping empty macro",
- "empty block",
- "empty argument, using 0n",
- "missing display type, using -ragged",
- "list type is not the first argument",
- "missing -width in -tag list, using 6n",
- "missing utility name, using \"\"",
- "missing function name, using \"\"",
- "empty head in list item",
- "empty list item",
- "missing argument, using next line",
- "missing font type, using \\fR",
- "unknown font type, using \\fR",
- "nothing follows prefix",
- "empty reference block",
- "missing section argument",
- "missing -std argument, adding it",
- "missing option string, using \"\"",
- "missing resource identifier, using \"\"",
- "missing eqn box, using \"\"",
-
- /* related to bad macro arguments */
- "duplicate argument",
- "skipping duplicate argument",
- "skipping duplicate display type",
- "skipping duplicate list type",
- "skipping -width argument",
- "wrong number of cells",
- "unknown AT&T UNIX version",
- "comma in function argument",
- "parenthesis in function name",
- "unknown library name",
- "invalid content in Rs block",
- "invalid Boolean argument",
- "argument contains two font escapes",
- "unknown font, skipping request",
- "odd number of characters in request",
-
- /* related to plain text */
- "blank line in fill mode, using .sp",
- "tab in filled text",
- "new sentence, new line",
- "invalid escape sequence",
- "undefined string, using \"\"",
-
- /* related to tables */
- "tbl line starts with span",
- "tbl column starts with span",
- "skipping vertical bar in tbl layout",
-
- "generic error",
-
- /* related to tables */
- "non-alphabetic character in tbl options",
- "skipping unknown tbl option",
- "missing tbl option argument",
- "wrong tbl option argument size",
- "empty tbl layout",
- "invalid character in tbl layout",
- "unmatched parenthesis in tbl layout",
- "tbl without any data cells",
- "ignoring data in spanned tbl cell",
- "ignoring extra tbl data cells",
- "data block open at end of tbl",
-
- /* related to document structure and macros */
- NULL,
- "duplicate prologue macro",
- "skipping late title macro",
- "input stack limit exceeded, infinite loop?",
- "skipping bad character",
- "skipping unknown macro",
- "ignoring request outside macro",
- "skipping insecure request",
- "skipping item outside list",
- "skipping column outside column list",
- "skipping end of block that is not open",
- "fewer RS blocks open, skipping",
- "inserting missing end of block",
- "appending missing end of block",
-
- /* related to request and macro arguments */
- "escaped character not allowed in a name",
- "using macro argument outside macro",
- "argument number is not numeric",
- "NOT IMPLEMENTED: Bd -file",
- "skipping display without arguments",
- "missing list type, using -item",
- "argument is not numeric, using 1",
- "argument is not a character",
- "missing manual name, using \"\"",
- "uname(3) system call failed, using UNKNOWN",
- "unknown standard specifier",
- "skipping request without numeric argument",
- "excessive shift",
- "NOT IMPLEMENTED: .so with absolute path or \"..\"",
- ".so request failed",
- "skipping all arguments",
- "skipping excess arguments",
- "divide by zero",
-
- "unsupported feature",
- "input too large",
- "unsupported control character",
- "unsupported roff request",
- "nested .while loops",
- "end of scope with open .while loop",
- "end of .while loop in inner scope",
- "cannot continue this .while loop",
- "eqn delim option in tbl",
- "unsupported tbl layout modifier",
- "ignoring macro in table",
-};
-
-static const char * const mandoclevels[MANDOCLEVEL_MAX] = {
- "SUCCESS",
- "STYLE",
- "WARNING",
- "ERROR",
- "UNSUPP",
- "BADARG",
- "SYSERR"
-};
-
static void
resize_buf(struct buf *buf, size_t initial)
@@ -370,7 +148,6 @@ mparse_buf_r(struct mparse *curp, struct buf blk, size_t i, int start)
{
struct buf ln;
struct buf *firstln, *lastln, *thisln, *loop;
- const char *save_file;
char *cp;
size_t pos; /* byte number in the ln buffer */
int line_result, result;
@@ -593,13 +370,10 @@ rerun:
curp->sodest = mandoc_strdup(ln.buf + of);
goto out;
}
- save_file = curp->file;
if ((fd = mparse_open(curp, ln.buf + of)) != -1) {
mparse_readfd(curp, fd, ln.buf + of);
close(fd);
- curp->file = save_file;
} else {
- curp->file = save_file;
mandoc_vmsg(MANDOCERR_SO_FAIL,
curp, curp->line, pos,
".so %s", ln.buf + of);
@@ -648,8 +422,7 @@ out:
}
static int
-read_whole_file(struct mparse *curp, const char *file, int fd,
- struct buf *fb, int *with_mmap)
+read_whole_file(struct mparse *curp, int fd, struct buf *fb, int *with_mmap)
{
struct stat st;
gzFile gz;
@@ -779,8 +552,8 @@ mparse_parse_buffer(struct mparse *curp, struct buf blk, const char *file)
}
/* Line number is per-file. */
- svfile = curp->file;
- curp->file = file;
+ svfile = mandoc_msg_getinfilename();
+ mandoc_msg_setinfilename(file);
svprimary = curp->primary;
curp->primary = &blk;
curp->line = 1;
@@ -802,7 +575,8 @@ mparse_parse_buffer(struct mparse *curp, struct buf blk, const char *file)
mparse_end(curp);
curp->primary = svprimary;
- curp->file = svfile;
+ if (svfile != NULL)
+ mandoc_msg_setinfilename(svfile);
}
enum mandoclevel
@@ -815,21 +589,21 @@ mparse_readmem(struct mparse *curp, void *buf, size_t len,
blk.sz = len;
mparse_parse_buffer(curp, blk, file);
- return curp->file_status;
+ return mandoc_msg_getrc();
}
/*
* Read the whole file into memory and call the parsers.
* Called recursively when an .so request is encountered.
*/
-enum mandoclevel
+void
mparse_readfd(struct mparse *curp, int fd, const char *file)
{
struct buf blk;
int with_mmap;
int save_filenc;
- if (read_whole_file(curp, file, fd, &blk, &with_mmap)) {
+ if (read_whole_file(curp, fd, &blk, &with_mmap)) {
save_filenc = curp->filenc;
curp->filenc = curp->options &
(MPARSE_UTF8 | MPARSE_LATIN1);
@@ -840,7 +614,6 @@ mparse_readfd(struct mparse *curp, int fd, const char *file)
else
free(blk.buf);
}
- return curp->file_status;
}
int
@@ -849,7 +622,6 @@ mparse_open(struct mparse *curp, const char *file)
char *cp;
int fd;
- curp->file = file;
cp = strrchr(file, '.');
curp->gzip = (cp != NULL && ! strcmp(cp + 1, "gz"));
@@ -880,16 +652,13 @@ mparse_open(struct mparse *curp, const char *file)
}
struct mparse *
-mparse_alloc(int options, enum mandocerr mmin, mandocmsg mmsg,
- enum mandoc_os os_e, const char *os_s)
+mparse_alloc(int options, enum mandoc_os os_e, const char *os_s)
{
struct mparse *curp;
curp = mandoc_calloc(1, sizeof(struct mparse));
curp->options = options;
- curp->mmin = mmin;
- curp->mmsg = mmsg;
curp->os_s = os_s;
curp->roff = roff_alloc(curp, options);
@@ -916,11 +685,8 @@ mparse_reset(struct mparse *curp)
roff_man_reset(curp->man);
free_buf_list(curp->secondary);
curp->secondary = NULL;
-
free(curp->sodest);
curp->sodest = NULL;
-
- curp->file_status = MANDOCLEVEL_OK;
curp->gzip = 0;
}
@@ -950,60 +716,6 @@ mparse_result(struct mparse *curp, struct roff_man **man,
}
void
-mparse_updaterc(struct mparse *curp, enum mandoclevel *rc)
-{
- if (curp->file_status > *rc)
- *rc = curp->file_status;
-}
-
-void
-mandoc_vmsg(enum mandocerr t, struct mparse *m,
- int ln, int pos, const char *fmt, ...)
-{
- char buf[256];
- va_list ap;
-
- va_start(ap, fmt);
- (void)vsnprintf(buf, sizeof(buf), fmt, ap);
- va_end(ap);
-
- mandoc_msg(t, m, ln, pos, buf);
-}
-
-void
-mandoc_msg(enum mandocerr er, struct mparse *m,
- int ln, int col, const char *msg)
-{
- enum mandoclevel level;
-
- if (er < m->mmin && er != MANDOCERR_FILE)
- return;
-
- level = MANDOCLEVEL_UNSUPP;
- while (er < mandoclimits[level])
- level--;
-
- if (m->mmsg)
- (*m->mmsg)(er, level, m->file, ln, col, msg);
-
- if (m->file_status < level)
- m->file_status = level;
-}
-
-const char *
-mparse_strerror(enum mandocerr er)
-{
-
- return mandocerrs[er];
-}
-
-const char *
-mparse_strlevel(enum mandoclevel lvl)
-{
- return mandoclevels[lvl];
-}
-
-void
mparse_copy(const struct mparse *p)
{
struct buf *buf;
diff --git a/roff_term.c b/roff_term.c
index 5e71912f..eb566abe 100644
--- a/roff_term.c
+++ b/roff_term.c
@@ -17,7 +17,7 @@
#include <sys/types.h>
#include <assert.h>
-#include <stddef.h>
+#include <stdio.h>
#include "mandoc.h"
#include "roff.h"
diff --git a/roff_validate.c b/roff_validate.c
index 91d01767..54172391 100644
--- a/roff_validate.c
+++ b/roff_validate.c
@@ -17,7 +17,7 @@
#include <sys/types.h>
#include <assert.h>
-#include <stddef.h>
+#include <stdio.h>
#include <string.h>
#include "mandoc.h"
diff --git a/st.c b/st.c
index 5900a700..6940e17e 100644
--- a/st.c
+++ b/st.c
@@ -17,6 +17,8 @@
#include "config.h"
#include <sys/types.h>
+
+#include <stdio.h>
#include <string.h>
#include "mandoc.h"
diff --git a/tbl_data.c b/tbl_data.c
index 60bdc8df..b2d0edef 100644
--- a/tbl_data.c
+++ b/tbl_data.c
@@ -21,6 +21,7 @@
#include <assert.h>
#include <ctype.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
diff --git a/tbl_layout.c b/tbl_layout.c
index 73e6915f..11914a9f 100644
--- a/tbl_layout.c
+++ b/tbl_layout.c
@@ -21,6 +21,7 @@
#include <ctype.h>
#include <stdint.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>