Annotation of mandoc/out.c, Revision 1.25
1.25 ! kristaps 1: /* $Id: out.c,v 1.24 2010/08/16 09:37:58 kristaps Exp $ */
1.1 kristaps 2: /*
1.18 kristaps 3: * Copyright (c) 2009, 2010 Kristaps Dzonsons <kristaps@bsd.lv>
1.1 kristaps 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: */
1.12 kristaps 17: #ifdef HAVE_CONFIG_H
18: #include "config.h"
19: #endif
20:
1.1 kristaps 21: #include <sys/types.h>
22:
1.6 kristaps 23: #include <assert.h>
1.1 kristaps 24: #include <ctype.h>
1.3 kristaps 25: #include <stdio.h>
1.1 kristaps 26: #include <stdlib.h>
1.6 kristaps 27: #include <string.h>
1.7 kristaps 28: #include <time.h>
1.1 kristaps 29:
30: #include "out.h"
31:
1.3 kristaps 32: /*
33: * Convert a `scaling unit' to a consistent form, or fail. Scaling
1.5 kristaps 34: * units are documented in groff.7, mdoc.7, man.7.
1.3 kristaps 35: */
1.1 kristaps 36: int
1.5 kristaps 37: a2roffsu(const char *src, struct roffsu *dst, enum roffscale def)
1.1 kristaps 38: {
1.4 kristaps 39: char buf[BUFSIZ], hasd;
1.1 kristaps 40: int i;
1.3 kristaps 41: enum roffscale unit;
1.1 kristaps 42:
1.5 kristaps 43: if ('\0' == *src)
44: return(0);
45:
1.4 kristaps 46: i = hasd = 0;
47:
48: switch (*src) {
49: case ('+'):
50: src++;
51: break;
52: case ('-'):
53: buf[i++] = *src++;
54: break;
55: default:
56: break;
57: }
58:
1.5 kristaps 59: if ('\0' == *src)
60: return(0);
61:
1.4 kristaps 62: while (i < BUFSIZ) {
63: if ( ! isdigit((u_char)*src)) {
64: if ('.' != *src)
65: break;
66: else if (hasd)
67: break;
68: else
69: hasd = 1;
70: }
71: buf[i++] = *src++;
72: }
1.1 kristaps 73:
1.3 kristaps 74: if (BUFSIZ == i || (*src && *(src + 1)))
1.1 kristaps 75: return(0);
76:
1.4 kristaps 77: buf[i] = '\0';
1.1 kristaps 78:
1.3 kristaps 79: switch (*src) {
80: case ('c'):
81: unit = SCALE_CM;
82: break;
83: case ('i'):
84: unit = SCALE_IN;
85: break;
86: case ('P'):
87: unit = SCALE_PC;
88: break;
89: case ('p'):
90: unit = SCALE_PT;
91: break;
92: case ('f'):
93: unit = SCALE_FS;
94: break;
95: case ('v'):
96: unit = SCALE_VS;
97: break;
98: case ('m'):
99: unit = SCALE_EM;
100: break;
101: case ('\0'):
1.5 kristaps 102: if (SCALE_MAX == def)
103: return(0);
104: unit = SCALE_BU;
105: break;
1.3 kristaps 106: case ('u'):
107: unit = SCALE_BU;
108: break;
109: case ('M'):
110: unit = SCALE_MM;
111: break;
112: case ('n'):
113: unit = SCALE_EN;
114: break;
115: default:
1.1 kristaps 116: return(0);
1.3 kristaps 117: }
1.1 kristaps 118:
1.23 kristaps 119: /* FIXME: do this in the caller. */
1.4 kristaps 120: if ((dst->scale = atof(buf)) < 0)
1.3 kristaps 121: dst->scale = 0;
122: dst->unit = unit;
123: return(1);
1.1 kristaps 124: }
1.6 kristaps 125:
126:
127: /*
128: * Correctly writes the time in nroff form, which differs from standard
129: * form in that a space isn't printed in lieu of the extra %e field for
130: * single-digit dates.
131: */
132: void
133: time2a(time_t t, char *dst, size_t sz)
134: {
135: struct tm tm;
136: char buf[5];
137: char *p;
138: size_t nsz;
139:
140: assert(sz > 1);
141: localtime_r(&t, &tm);
142:
143: p = dst;
144: nsz = 0;
145:
146: dst[0] = '\0';
147:
148: if (0 == (nsz = strftime(p, sz, "%B ", &tm)))
149: return;
150:
151: p += (int)nsz;
152: sz -= nsz;
153:
154: if (0 == strftime(buf, sizeof(buf), "%e, ", &tm))
155: return;
156:
157: nsz = strlcat(p, buf + (' ' == buf[0] ? 1 : 0), sz);
158:
159: if (nsz >= sz)
160: return;
161:
162: p += (int)nsz;
163: sz -= nsz;
164:
165: (void)strftime(p, sz, "%Y", &tm);
166: }
167:
1.8 kristaps 168:
169: int
1.18 kristaps 170: a2roffdeco(enum roffdeco *d, const char **word, size_t *sz)
1.8 kristaps 171: {
1.18 kristaps 172: int i, j, lim;
173: char term, c;
174: const char *wp;
1.25 ! kristaps 175: enum roffdeco dd;
1.8 kristaps 176:
177: *d = DECO_NONE;
1.18 kristaps 178: lim = i = 0;
179: term = '\0';
1.8 kristaps 180: wp = *word;
181:
1.18 kristaps 182: switch ((c = wp[i++])) {
1.8 kristaps 183: case ('('):
184: *d = DECO_SPECIAL;
1.18 kristaps 185: lim = 2;
186: break;
1.14 kristaps 187: case ('F'):
188: /* FALLTHROUGH */
189: case ('f'):
1.18 kristaps 190: *d = 'F' == c ? DECO_FFONT : DECO_FONT;
191:
192: switch (wp[i++]) {
193: case ('('):
194: lim = 2;
195: break;
196: case ('['):
197: term = ']';
198: break;
1.14 kristaps 199: case ('3'):
200: /* FALLTHROUGH */
201: case ('B'):
202: *d = DECO_BOLD;
1.18 kristaps 203: return(i);
1.14 kristaps 204: case ('2'):
205: /* FALLTHROUGH */
206: case ('I'):
207: *d = DECO_ITALIC;
1.18 kristaps 208: return(i);
1.14 kristaps 209: case ('P'):
210: *d = DECO_PREVIOUS;
1.18 kristaps 211: return(i);
1.14 kristaps 212: case ('1'):
213: /* FALLTHROUGH */
214: case ('R'):
215: *d = DECO_ROMAN;
1.18 kristaps 216: return(i);
1.14 kristaps 217: default:
1.18 kristaps 218: i--;
219: lim = 1;
1.14 kristaps 220: break;
221: }
1.18 kristaps 222: break;
1.19 kristaps 223: case ('M'):
224: /* FALLTHROUGH */
225: case ('m'):
1.20 kristaps 226: /* FALLTHROUGH */
227: case ('*'):
228: if ('*' == c)
229: *d = DECO_RESERVED;
230:
1.18 kristaps 231: switch (wp[i++]) {
1.8 kristaps 232: case ('('):
1.18 kristaps 233: lim = 2;
234: break;
1.8 kristaps 235: case ('['):
1.18 kristaps 236: term = ']';
237: break;
1.8 kristaps 238: default:
1.18 kristaps 239: i--;
240: lim = 1;
1.14 kristaps 241: break;
1.8 kristaps 242: }
1.18 kristaps 243: break;
1.24 kristaps 244: case ('h'):
245: /* FALLTHROUGH */
246: case ('v'):
247: /* FALLTHROUGH */
1.8 kristaps 248: case ('s'):
1.24 kristaps 249: j = 0;
250: if ('+' == wp[i] || '-' == wp[i]) {
1.18 kristaps 251: i++;
1.24 kristaps 252: j = 1;
253: }
1.8 kristaps 254:
1.18 kristaps 255: switch (wp[i++]) {
256: case ('('):
257: lim = 2;
258: break;
259: case ('['):
260: term = ']';
261: break;
1.10 kristaps 262: case ('\''):
1.18 kristaps 263: term = '\'';
1.10 kristaps 264: break;
1.22 kristaps 265: case ('0'):
1.24 kristaps 266: j = 1;
1.22 kristaps 267: /* FALLTHROUGH */
1.10 kristaps 268: default:
1.18 kristaps 269: i--;
270: lim = 1;
1.10 kristaps 271: break;
1.8 kristaps 272: }
273:
1.18 kristaps 274: if ('+' == wp[i] || '-' == wp[i]) {
1.24 kristaps 275: if (j)
1.18 kristaps 276: return(i);
277: i++;
278: }
1.25 ! kristaps 279:
1.18 kristaps 280: break;
281: case ('['):
282: *d = DECO_SPECIAL;
283: term = ']';
284: break;
285: case ('c'):
286: *d = DECO_NOSPACE;
287: return(i);
1.25 ! kristaps 288: case ('z'):
! 289: *d = DECO_NONE;
! 290: if ('\\' == wp[i]) {
! 291: *word = &wp[++i];
! 292: return(i + a2roffdeco(&dd, word, sz));
! 293: } else
! 294: lim = 1;
! 295: break;
1.18 kristaps 296: default:
1.21 kristaps 297: *d = DECO_SSPECIAL;
1.18 kristaps 298: i--;
299: lim = 1;
300: break;
301: }
1.8 kristaps 302:
1.18 kristaps 303: assert(term || lim);
304: *word = &wp[i];
1.8 kristaps 305:
1.18 kristaps 306: if (term) {
307: j = i;
308: while (wp[i] && wp[i] != term)
309: i++;
310: if ('\0' == wp[i]) {
311: *d = DECO_NONE;
312: return(i);
1.8 kristaps 313: }
1.10 kristaps 314:
1.18 kristaps 315: assert(i >= j);
316: *sz = (size_t)(i - j);
1.8 kristaps 317:
1.18 kristaps 318: return(i + 1);
319: }
1.8 kristaps 320:
1.18 kristaps 321: assert(lim > 0);
322: *sz = (size_t)lim;
1.11 kristaps 323:
1.18 kristaps 324: for (j = 0; wp[i] && j < lim; j++)
325: i++;
326: if (j < lim)
327: *d = DECO_NONE;
1.8 kristaps 328:
1.18 kristaps 329: return(i);
1.8 kristaps 330: }
CVSweb