1 /* $Id: mandoc.c,v 1.36 2011/01/03 22:42:37 schwarze Exp $ */
3 * Copyright (c) 2008, 2009, 2010 Kristaps Dzonsons <kristaps@bsd.lv>
4 * Copyright (c) 2011 Ingo Schwarze <schwarze@openbsd.org>
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22 #include <sys/types.h>
32 #include "libmandoc.h"
34 static int a2time(time_t *, const char *, const char *);
38 mandoc_special(char *p)
98 if ('+' == *p || '-' == *p) {
122 if (ASCII_HYPH == *p)
124 if ('+' == *p || '-' == *p) {
130 /* Handle embedded numerical subexp or escape. */
133 while (*p && ')' != *p)
135 i = mandoc_special(--p);
145 } else if ('\\' == *p) {
146 if (0 == (i = mandoc_special(p)))
195 if (0 == (i = mandoc_special(p)))
198 return(*p ? (int)(p - sv) : 0);
216 for ( ; *p && term != *p; p++)
217 if (ASCII_HYPH == *p)
219 return(*p ? (int)(p - sv) : 0);
222 for (i = 0; *p && i < len; i++, p++)
223 if (ASCII_HYPH == *p)
225 return(i == len ? (int)(p - sv) : 0);
230 mandoc_calloc(size_t num, size_t size)
234 ptr = calloc(num, size);
237 exit((int)MANDOCLEVEL_SYSERR);
245 mandoc_malloc(size_t size)
252 exit((int)MANDOCLEVEL_SYSERR);
260 mandoc_realloc(void *ptr, size_t size)
263 ptr = realloc(ptr, size);
266 exit((int)MANDOCLEVEL_SYSERR);
274 mandoc_strdup(const char *ptr)
281 exit((int)MANDOCLEVEL_SYSERR);
288 * Parse a quoted or unquoted roff-style request or macro argument.
289 * Return a pointer to the parsed argument, which is either the original
290 * pointer or advanced by one byte in case the argument is quoted.
291 * Null-terminate the argument in place.
292 * Collapse pairs of quotes inside quoted arguments.
293 * Advance the argument pointer to the next argument,
294 * or to the null byte terminating the argument line.
297 mandoc_getarg(char **cpp, mandocmsg msg, void *data, int ln, int *pos)
300 int quoted, pairs, white;
302 /* Quoting can only start with a new word. */
312 for (cp = start; '\0' != *cp; cp++) {
313 /* Move left after quoted quotes and escaped backslashes. */
318 /* Poor man's copy mode. */
321 } else if (0 == quoted && ' ' == cp[1])
322 /* Skip escaped blanks. */
324 } else if (0 == quoted) {
326 /* Unescaped blanks end unquoted args. */
330 } else if ('"' == cp[0]) {
332 /* Quoted quotes collapse. */
336 /* Unquoted quotes end quoted args. */
343 /* Quoted argument without a closing quote. */
344 if (1 == quoted && msg)
345 (*msg)(MANDOCERR_BADQUOTE, data, ln, *pos, NULL);
347 /* Null-terminate this argument and move to the next one. */
355 *pos += (cp - start) + (quoted ? 1 : 0);
358 if ('\0' == *cp && msg && (white || ' ' == cp[-1]))
359 (*msg)(MANDOCERR_EOLNSPACE, data, ln, *pos, NULL);
366 a2time(time_t *t, const char *fmt, const char *p)
371 memset(&tm, 0, sizeof(struct tm));
373 pp = strptime(p, fmt, &tm);
374 if (NULL != pp && '\0' == *pp) {
384 * Convert from a manual date string (see mdoc(7) and man(7)) into a
385 * date according to the stipulated date type.
388 mandoc_a2time(int flags, const char *p)
392 if (MTIME_MDOCDATE & flags) {
393 if (0 == strcmp(p, "$" "Mdocdate$"))
395 if (a2time(&t, "$" "Mdocdate: %b %d %Y $", p))
399 if (MTIME_CANONICAL & flags || MTIME_REDUCED & flags)
400 if (a2time(&t, "%b %d, %Y", p))
403 if (MTIME_ISO_8601 & flags)
404 if (a2time(&t, "%Y-%m-%d", p))
407 if (MTIME_REDUCED & flags) {
408 if (a2time(&t, "%d, %Y", p))
410 if (a2time(&t, "%Y", p))
419 mandoc_eos(const char *p, size_t sz, int enclosed)
428 * End-of-sentence recognition must include situations where
429 * some symbols, such as `)', allow prior EOS punctuation to
434 for (q = p + (int)sz - 1; q >= p; q--) {
454 return(found && (!enclosed || isalnum((unsigned char)*q)));
458 return(found && !enclosed);
463 mandoc_hyph(const char *start, const char *c)
467 * Choose whether to break at a hyphenated character. We only
468 * do this if it's free-standing within a word.
471 /* Skip first/last character of buffer. */
472 if (c == start || '\0' == *(c + 1))
474 /* Skip first/last character of word. */
475 if ('\t' == *(c + 1) || '\t' == *(c - 1))
477 if (' ' == *(c + 1) || ' ' == *(c - 1))
479 /* Skip double invocations. */
480 if ('-' == *(c + 1) || '-' == *(c - 1))
483 if ('\\' == *(c - 1))