Annotation of src/usr.bin/mandoc/out.c, Revision 1.3
1.3 ! schwarze 1: /* $Id: out.c,v 1.2 2009/10/27 21:40:07 schwarze Exp $ */
1.1 schwarze 2: /*
3: * Copyright (c) 2009 Kristaps Dzonsons <kristaps@kth.se>
4: *
5: * Permission to use, copy, modify, and distribute this software for any
6: * purpose with or without fee is hereby granted, provided that the above
7: * copyright notice and this permission notice appear in all copies.
8: *
9: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16: */
17: #include <sys/types.h>
18:
1.2 schwarze 19: #include <assert.h>
1.1 schwarze 20: #include <ctype.h>
21: #include <stdio.h>
22: #include <stdlib.h>
1.2 schwarze 23: #include <string.h>
24: #include <time.h>
1.1 schwarze 25:
26: #include "out.h"
27:
1.3 ! schwarze 28: /* See a2roffdeco(). */
! 29: #define C2LIM(c, l) do { \
! 30: (l) = 1; \
! 31: if ('[' == (c) || '\'' == (c)) \
! 32: (l) = 0; \
! 33: else if ('(' == (c)) \
! 34: (l) = 2; } \
! 35: while (/* CONSTCOND */ 0)
! 36:
! 37: /* See a2roffdeco(). */
! 38: #define C2TERM(c, t) do { \
! 39: (t) = 0; \
! 40: if ('\'' == (c)) \
! 41: (t) = 1; \
! 42: else if ('[' == (c)) \
! 43: (t) = 2; \
! 44: else if ('(' == (c)) \
! 45: (t) = 3; } \
! 46: while (/* CONSTCOND */ 0)
! 47:
1.1 schwarze 48: /*
49: * Convert a `scaling unit' to a consistent form, or fail. Scaling
50: * units are documented in groff.7, mdoc.7, man.7.
51: */
52: int
53: a2roffsu(const char *src, struct roffsu *dst, enum roffscale def)
54: {
55: char buf[BUFSIZ], hasd;
56: int i;
57: enum roffscale unit;
58:
59: if ('\0' == *src)
60: return(0);
61:
62: i = hasd = 0;
63:
64: switch (*src) {
65: case ('+'):
66: src++;
67: break;
68: case ('-'):
69: buf[i++] = *src++;
70: break;
71: default:
72: break;
73: }
74:
75: if ('\0' == *src)
76: return(0);
77:
78: while (i < BUFSIZ) {
79: if ( ! isdigit((u_char)*src)) {
80: if ('.' != *src)
81: break;
82: else if (hasd)
83: break;
84: else
85: hasd = 1;
86: }
87: buf[i++] = *src++;
88: }
89:
90: if (BUFSIZ == i || (*src && *(src + 1)))
91: return(0);
92:
93: buf[i] = '\0';
94:
95: switch (*src) {
96: case ('c'):
97: unit = SCALE_CM;
98: break;
99: case ('i'):
100: unit = SCALE_IN;
101: break;
102: case ('P'):
103: unit = SCALE_PC;
104: break;
105: case ('p'):
106: unit = SCALE_PT;
107: break;
108: case ('f'):
109: unit = SCALE_FS;
110: break;
111: case ('v'):
112: unit = SCALE_VS;
113: break;
114: case ('m'):
115: unit = SCALE_EM;
116: break;
117: case ('\0'):
118: if (SCALE_MAX == def)
119: return(0);
120: unit = SCALE_BU;
121: break;
122: case ('u'):
123: unit = SCALE_BU;
124: break;
125: case ('M'):
126: unit = SCALE_MM;
127: break;
128: case ('n'):
129: unit = SCALE_EN;
130: break;
131: default:
132: return(0);
133: }
134:
135: if ((dst->scale = atof(buf)) < 0)
136: dst->scale = 0;
137: dst->unit = unit;
138: dst->pt = hasd;
139:
140: return(1);
141: }
1.2 schwarze 142:
143:
144: /*
145: * Correctly writes the time in nroff form, which differs from standard
146: * form in that a space isn't printed in lieu of the extra %e field for
147: * single-digit dates.
148: */
149: void
150: time2a(time_t t, char *dst, size_t sz)
151: {
152: struct tm tm;
153: char buf[5];
154: char *p;
155: size_t nsz;
156:
157: assert(sz > 1);
158: localtime_r(&t, &tm);
159:
160: p = dst;
161: nsz = 0;
162:
163: dst[0] = '\0';
164:
165: if (0 == (nsz = strftime(p, sz, "%B ", &tm)))
166: return;
167:
168: p += (int)nsz;
169: sz -= nsz;
170:
171: if (0 == strftime(buf, sizeof(buf), "%e, ", &tm))
172: return;
173:
174: nsz = strlcat(p, buf + (' ' == buf[0] ? 1 : 0), sz);
175:
176: if (nsz >= sz)
177: return;
178:
179: p += (int)nsz;
180: sz -= nsz;
181:
182: (void)strftime(p, sz, "%Y", &tm);
183: }
184:
1.3 ! schwarze 185:
! 186: /*
! 187: * Returns length of parsed string (the leading "\" should NOT be
! 188: * included). This can be zero if the current character is the nil
! 189: * terminator. "d" is set to the type of parsed decorator, which may
! 190: * have an adjoining "word" of size "sz" (e.g., "(ab" -> "ab", 2).
! 191: */
! 192: int
! 193: a2roffdeco(enum roffdeco *d,
! 194: const char **word, size_t *sz)
! 195: {
! 196: int j, type, term, lim;
! 197: const char *wp, *sp;
! 198:
! 199: *d = DECO_NONE;
! 200: wp = *word;
! 201: type = 1;
! 202:
! 203: switch (*wp) {
! 204: case ('\0'):
! 205: return(0);
! 206:
! 207: case ('('):
! 208: if ('\0' == *(++wp))
! 209: return(1);
! 210: if ('\0' == *(wp + 1))
! 211: return(2);
! 212:
! 213: *d = DECO_SPECIAL;
! 214: *sz = 2;
! 215: *word = wp;
! 216: return(3);
! 217:
! 218: case ('*'):
! 219: switch (*(++wp)) {
! 220: case ('\0'):
! 221: return(1);
! 222:
! 223: case ('('):
! 224: if ('\0' == *(++wp))
! 225: return(2);
! 226: if ('\0' == *(wp + 1))
! 227: return(3);
! 228:
! 229: *d = DECO_RESERVED;
! 230: *sz = 2;
! 231: *word = wp;
! 232: return(4);
! 233:
! 234: case ('['):
! 235: type = 0;
! 236: break;
! 237:
! 238: default:
! 239: *d = DECO_RESERVED;
! 240: *sz = 1;
! 241: *word = wp;
! 242: return(2);
! 243: }
! 244: break;
! 245:
! 246: case ('s'):
! 247: sp = wp;
! 248: if ('\0' == *(++wp))
! 249: return(1);
! 250:
! 251: C2LIM(*wp, lim);
! 252: C2TERM(*wp, term);
! 253:
! 254: if (term)
! 255: wp++;
! 256:
! 257: *word = wp;
! 258:
! 259: if (*wp == '+' || *wp == '-')
! 260: ++wp;
! 261:
! 262: switch (*wp) {
! 263: case ('\''):
! 264: /* FALLTHROUGH */
! 265: case ('['):
! 266: /* FALLTHROUGH */
! 267: case ('('):
! 268: if (term)
! 269: return((int)(wp - sp));
! 270:
! 271: C2LIM(*wp, lim);
! 272: C2TERM(*wp, term);
! 273: wp++;
! 274: break;
! 275: default:
! 276: break;
! 277: }
! 278:
! 279: if ( ! isdigit((u_char)*wp))
! 280: return((int)(wp - sp));
! 281:
! 282: for (j = 0; isdigit((u_char)*wp); j++) {
! 283: if (lim && j >= lim)
! 284: break;
! 285: ++wp;
! 286: }
! 287:
! 288: if (term && term < 3) {
! 289: if (1 == term && *wp != '\'')
! 290: return((int)(wp - sp));
! 291: if (2 == term && *wp != ']')
! 292: return((int)(wp - sp));
! 293: ++wp;
! 294: }
! 295:
! 296: *d = DECO_SIZE;
! 297: return((int)(wp - sp));
! 298:
! 299: case ('f'):
! 300: switch (*(++wp)) {
! 301: case ('\0'):
! 302: return(1);
! 303: case ('3'):
! 304: /* FALLTHROUGH */
! 305: case ('B'):
! 306: *d = DECO_BOLD;
! 307: break;
! 308: case ('2'):
! 309: /* FALLTHROUGH */
! 310: case ('I'):
! 311: *d = DECO_ITALIC;
! 312: break;
! 313: case ('P'):
! 314: *d = DECO_PREVIOUS;
! 315: break;
! 316: case ('1'):
! 317: /* FALLTHROUGH */
! 318: case ('R'):
! 319: *d = DECO_ROMAN;
! 320: break;
! 321: default:
! 322: break;
! 323: }
! 324:
! 325: return(2);
! 326:
! 327: case ('['):
! 328: break;
! 329:
! 330: case ('c'):
! 331: *d = DECO_NOSPACE;
! 332: *sz = 1;
! 333: return(1);
! 334:
! 335: default:
! 336: *d = DECO_SPECIAL;
! 337: *word = wp;
! 338: *sz = 1;
! 339: return(1);
! 340: }
! 341:
! 342: *word = ++wp;
! 343: for (j = 0; *wp && ']' != *wp; wp++, j++)
! 344: /* Loop... */ ;
! 345:
! 346: if ('\0' == *wp)
! 347: return(j + 1);
! 348:
! 349: *d = type ? DECO_SPECIAL : DECO_RESERVED;
! 350: *sz = (size_t)j;
! 351: return (j + 2);
! 352: }