1 /* $Vendor-Id: out.c,v 1.23 2010/07/22 23:03:15 kristaps Exp $ */ 2 /* 3 * Copyright (c) 2009, 2010 Kristaps Dzonsons <kristaps@bsd.lv> 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 #ifdef HAVE_CONFIG_H 18 #include "config.h" 19 #endif 20 21 #include <sys/types.h> 22 23 #include <assert.h> 24 #include <ctype.h> 25 #include <stdio.h> 26 #include <stdlib.h> 27 #include <string.h> 28 #include <time.h> 29 30 #include "out.h" 31 32 /* 33 * Convert a `scaling unit' to a consistent form, or fail. Scaling 34 * units are documented in groff.7, mdoc.7, man.7. 35 */ 36 int 37 a2roffsu(const char *src, struct roffsu *dst, enum roffscale def) 38 { 39 char buf[BUFSIZ], hasd; 40 int i; 41 enum roffscale unit; 42 43 if ('\0' == *src) 44 return(0); 45 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 59 if ('\0' == *src) 60 return(0); 61 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 } 73 74 if (BUFSIZ == i || (*src && *(src + 1))) 75 return(0); 76 77 buf[i] = '\0'; 78 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'): 102 if (SCALE_MAX == def) 103 return(0); 104 unit = SCALE_BU; 105 break; 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: 116 return(0); 117 } 118 119 /* FIXME: do this in the caller. */ 120 if ((dst->scale = atof(buf)) < 0) 121 dst->scale = 0; 122 dst->unit = unit; 123 return(1); 124 } 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 168 169 int 170 a2roffdeco(enum roffdeco *d, const char **word, size_t *sz) 171 { 172 int i, j, lim; 173 char term, c; 174 const char *wp; 175 176 *d = DECO_NONE; 177 lim = i = 0; 178 term = '\0'; 179 wp = *word; 180 181 switch ((c = wp[i++])) { 182 case ('('): 183 *d = DECO_SPECIAL; 184 lim = 2; 185 break; 186 case ('F'): 187 /* FALLTHROUGH */ 188 case ('f'): 189 *d = 'F' == c ? DECO_FFONT : DECO_FONT; 190 191 switch (wp[i++]) { 192 case ('('): 193 lim = 2; 194 break; 195 case ('['): 196 term = ']'; 197 break; 198 case ('3'): 199 /* FALLTHROUGH */ 200 case ('B'): 201 *d = DECO_BOLD; 202 return(i); 203 case ('2'): 204 /* FALLTHROUGH */ 205 case ('I'): 206 *d = DECO_ITALIC; 207 return(i); 208 case ('P'): 209 *d = DECO_PREVIOUS; 210 return(i); 211 case ('1'): 212 /* FALLTHROUGH */ 213 case ('R'): 214 *d = DECO_ROMAN; 215 return(i); 216 default: 217 i--; 218 lim = 1; 219 break; 220 } 221 break; 222 case ('M'): 223 /* FALLTHROUGH */ 224 case ('m'): 225 /* FALLTHROUGH */ 226 case ('*'): 227 if ('*' == c) 228 *d = DECO_RESERVED; 229 230 switch (wp[i++]) { 231 case ('('): 232 lim = 2; 233 break; 234 case ('['): 235 term = ']'; 236 break; 237 default: 238 i--; 239 lim = 1; 240 break; 241 } 242 break; 243 case ('s'): 244 if ('+' == wp[i] || '-' == wp[i]) 245 i++; 246 247 j = ('s' != wp[i - 1]); 248 249 switch (wp[i++]) { 250 case ('('): 251 lim = 2; 252 break; 253 case ('['): 254 term = ']'; 255 break; 256 case ('\''): 257 term = '\''; 258 break; 259 case ('0'): 260 j++; 261 /* FALLTHROUGH */ 262 default: 263 i--; 264 lim = 1; 265 break; 266 } 267 268 if ('+' == wp[i] || '-' == wp[i]) { 269 if (j++) 270 return(i); 271 i++; 272 } 273 274 if (0 == j) 275 return(i); 276 break; 277 case ('['): 278 *d = DECO_SPECIAL; 279 term = ']'; 280 break; 281 case ('c'): 282 *d = DECO_NOSPACE; 283 return(i); 284 default: 285 *d = DECO_SSPECIAL; 286 i--; 287 lim = 1; 288 break; 289 } 290 291 assert(term || lim); 292 *word = &wp[i]; 293 294 if (term) { 295 j = i; 296 while (wp[i] && wp[i] != term) 297 i++; 298 if ('\0' == wp[i]) { 299 *d = DECO_NONE; 300 return(i); 301 } 302 303 assert(i >= j); 304 *sz = (size_t)(i - j); 305 306 return(i + 1); 307 } 308 309 assert(lim > 0); 310 *sz = (size_t)lim; 311 312 for (j = 0; wp[i] && j < lim; j++) 313 i++; 314 if (j < lim) 315 *d = DECO_NONE; 316 317 return(i); 318 } 319