Annotation of mandoc/mlg.c, Revision 1.1
1.1 ! kristaps 1: /* $Id: ml.c,v 1.1 2008/12/02 18:26:57 kristaps Exp $ */
! 2: /*
! 3: * Copyright (c) 2008 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
! 7: * above copyright notice and this permission notice appear in all
! 8: * copies.
! 9: *
! 10: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
! 11: * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
! 12: * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
! 13: * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
! 14: * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
! 15: * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
! 16: * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
! 17: * PERFORMANCE OF THIS SOFTWARE.
! 18: */
! 19: #include <assert.h>
! 20: #include <ctype.h>
! 21: #include <err.h>
! 22: #include <stdlib.h>
! 23: #include <stdio.h>
! 24: #include <string.h>
! 25:
! 26: #include "libmdocml.h"
! 27: #include "private.h"
! 28: #include "ml.h"
! 29:
! 30: /* TODO: literal tokens. */
! 31:
! 32: #define COLUMNS 72
! 33: #define INDENT 4
! 34: #define MAXINDENT 8
! 35:
! 36: enum md_tok {
! 37: MD_TEXT,
! 38: MD_INLINE_IN,
! 39: MD_INLINE_OUT,
! 40: MD_BLK_IN,
! 41: MD_BLK_OUT,
! 42: };
! 43:
! 44: struct md_mlg {
! 45: const struct md_args *args;
! 46: const struct md_rbuf *rbuf;
! 47:
! 48: struct md_mbuf *mbuf;
! 49: struct rofftree *tree;
! 50: size_t indent;
! 51: size_t pos;
! 52: enum md_tok last;
! 53: void *arg;
! 54: ml_begintag begintag;
! 55: ml_endtag endtag;
! 56: int flags;
! 57: #define ML_OVERRIDE_ONE (1 << 0)
! 58: #define ML_OVERRIDE_ALL (1 << 1)
! 59: };
! 60:
! 61:
! 62: static void mlg_roffmsg(void *arg, enum roffmsg,
! 63: const char *, const char *, char *);
! 64: static int mlg_roffhead(void *);
! 65: static int mlg_rofftail(void *);
! 66: static int mlg_roffin(void *, int, int *, char **);
! 67: static int mlg_roffdata(void *, int, char *);
! 68: static int mlg_roffout(void *, int);
! 69: static int mlg_roffblkin(void *, int, int *, char **);
! 70: static int mlg_roffblkout(void *, int);
! 71: static int mlg_roffspecial(void *, int, int *, char **, char **);
! 72: static int mlg_begintag(struct md_mlg *, enum md_ns,
! 73: int, int *, char **);
! 74: static int mlg_endtag(struct md_mlg *, enum md_ns, int);
! 75: static int mlg_indent(struct md_mlg *);
! 76: static int mlg_newline(struct md_mlg *);
! 77: static void mlg_mode(struct md_mlg *, enum md_tok);
! 78: static int mlg_data(struct md_mlg *, int, char *);
! 79:
! 80: #ifdef __linux__
! 81: extern size_t strlcat(char *, const char *, size_t);
! 82: extern size_t strlcpy(char *, const char *, size_t);
! 83: #endif
! 84:
! 85:
! 86: static int
! 87: mlg_begintag(struct md_mlg *p, enum md_ns ns, int tok,
! 88: int *argc, char **argv)
! 89: {
! 90: ssize_t res;
! 91:
! 92: /* TODO: extra rules for block/inline. */
! 93:
! 94: if ( ! ml_nputs(p->mbuf, "<", 1, &p->pos))
! 95: return(0);
! 96:
! 97: res = (*p->begintag)(p->mbuf, p->args, ns, tok,
! 98: argc, (const char **)argv);
! 99: if (-1 == res)
! 100: return(0);
! 101:
! 102: assert(res >= 0);
! 103: p->pos += (size_t)res;
! 104:
! 105: /* TODO: extra rules for block/inline. */
! 106:
! 107: return(ml_nputs(p->mbuf, ">", 1, &p->pos));
! 108: }
! 109:
! 110:
! 111: static int
! 112: mlg_endtag(struct md_mlg *p, enum md_ns ns, int tok)
! 113: {
! 114: ssize_t res;
! 115:
! 116: /* TODO: extra rules for block/inline. */
! 117:
! 118: if ( ! ml_nputs(p->mbuf, "</", 2, &p->pos))
! 119: return(0);
! 120:
! 121: res = (*p->endtag)(p->mbuf, p->args, ns, tok);
! 122: if (-1 == res)
! 123: return(0);
! 124:
! 125: assert(res >= 0);
! 126: p->pos += (size_t)res;
! 127:
! 128: /* TODO: extra rules for block/inline. */
! 129:
! 130: return(ml_nputs(p->mbuf, ">", 1, &p->pos));
! 131: }
! 132:
! 133:
! 134: static int
! 135: mlg_indent(struct md_mlg *p)
! 136: {
! 137: size_t count;
! 138:
! 139: count = p->indent > MAXINDENT ? MAXINDENT : p->indent;
! 140: count *= INDENT;
! 141:
! 142: assert(0 == p->pos);
! 143: return(ml_putchars(p->mbuf, ' ', count, &p->pos));
! 144: }
! 145:
! 146:
! 147: static int
! 148: mlg_newline(struct md_mlg *p)
! 149: {
! 150: size_t dummy;
! 151:
! 152: if ( ! ml_nputs(p->mbuf, "\n", 1, &dummy))
! 153: return(0);
! 154: p->pos = 0;
! 155: return(1);
! 156: }
! 157:
! 158:
! 159: static void
! 160: mlg_mode(struct md_mlg *p, enum md_tok ns)
! 161: {
! 162: p->flags &= ~ML_OVERRIDE_ONE;
! 163: p->last = ns;
! 164: }
! 165:
! 166:
! 167: static int
! 168: mlg_data(struct md_mlg *p, int space, char *buf)
! 169: {
! 170: size_t sz;
! 171: char *bufp;
! 172:
! 173: assert(p->mbuf);
! 174: assert(0 != p->indent);
! 175:
! 176: if (ML_OVERRIDE_ONE & p->flags ||
! 177: ML_OVERRIDE_ALL & p->flags)
! 178: space = 0;
! 179:
! 180: while (*buf) {
! 181: while (*buf && isspace(*buf))
! 182: buf++;
! 183:
! 184: if (0 == *buf)
! 185: break;
! 186:
! 187: bufp = buf;
! 188: while (*buf && ! isspace(*buf))
! 189: buf++;
! 190:
! 191: if (0 != *buf)
! 192: *buf++ = 0;
! 193:
! 194: sz = strlen(bufp);
! 195:
! 196: if (0 == p->pos) {
! 197: if ( ! mlg_indent(p))
! 198: return(0);
! 199: if ( ! ml_nputstring(p->mbuf, bufp,
! 200: sz, &p->pos))
! 201: return(0);
! 202: if (p->indent * MAXINDENT + sz >= COLUMNS)
! 203: if ( ! mlg_newline(p))
! 204: return(0);
! 205: if ( ! (ML_OVERRIDE_ALL & p->flags))
! 206: space = 1;
! 207: continue;
! 208: }
! 209:
! 210: if (space && sz + p->pos >= COLUMNS) {
! 211: if ( ! mlg_newline(p))
! 212: return(0);
! 213: if ( ! mlg_indent(p))
! 214: return(0);
! 215: } else if (space) {
! 216: if ( ! ml_nputs(p->mbuf, " ", 1, &p->pos))
! 217: return(0);
! 218: }
! 219:
! 220: if ( ! ml_nputstring(p->mbuf, bufp, sz, &p->pos))
! 221: return(0);
! 222:
! 223: if ( ! (ML_OVERRIDE_ALL & p->flags))
! 224: space = 1;
! 225: }
! 226:
! 227: return(1);
! 228: }
! 229:
! 230:
! 231: int
! 232: mlg_line(struct md_mlg *p, char *buf)
! 233: {
! 234:
! 235: return(roff_engine(p->tree, buf));
! 236: }
! 237:
! 238:
! 239: int
! 240: mlg_exit(struct md_mlg *p, int flush)
! 241: {
! 242: int c;
! 243:
! 244: c = roff_free(p->tree, flush);
! 245: free(p);
! 246: return(c);
! 247: }
! 248:
! 249:
! 250: struct md_mlg *
! 251: mlg_alloc(const struct md_args *args,
! 252: const struct md_rbuf *rbuf,
! 253: struct md_mbuf *mbuf,
! 254: ml_begintag begintag, ml_endtag endtag)
! 255: {
! 256: struct roffcb cb;
! 257: struct md_mlg *p;
! 258:
! 259: cb.roffhead = mlg_roffhead;
! 260: cb.rofftail = mlg_rofftail;
! 261: cb.roffin = mlg_roffin;
! 262: cb.roffout = mlg_roffout;
! 263: cb.roffblkin = mlg_roffblkin;
! 264: cb.roffblkout = mlg_roffblkout;
! 265: cb.roffspecial = mlg_roffspecial;
! 266: cb.roffmsg = mlg_roffmsg;
! 267: cb.roffdata = mlg_roffdata;
! 268:
! 269: if (NULL == (p = calloc(1, sizeof(struct md_mlg))))
! 270: err(1, "calloc");
! 271:
! 272: p->args = args;
! 273: p->mbuf = mbuf;
! 274: p->rbuf = rbuf;
! 275: p->begintag = begintag;
! 276: p->endtag = endtag;
! 277:
! 278: if (NULL == (p->tree = roff_alloc(&cb, p))) {
! 279: free(p);
! 280: return(NULL);
! 281: }
! 282:
! 283: return(p);
! 284: }
! 285:
! 286:
! 287: static int
! 288: mlg_roffhead(void *arg)
! 289: {
! 290: struct md_mlg *p;
! 291:
! 292: assert(arg);
! 293: p = (struct md_mlg *)arg;
! 294:
! 295: mlg_mode(p, MD_BLK_IN);
! 296: if ( ! mlg_begintag(p, MD_NS_DEFAULT, -1, NULL, NULL))
! 297: return(0);
! 298:
! 299: p->indent++;
! 300: return(mlg_newline(p));
! 301: }
! 302:
! 303:
! 304: static int
! 305: mlg_rofftail(void *arg)
! 306: {
! 307: struct md_mlg *p;
! 308:
! 309: assert(arg);
! 310: p = (struct md_mlg *)arg;
! 311:
! 312: if (0 != p->pos && ! mlg_newline(p))
! 313: return(0);
! 314:
! 315: mlg_mode(p, MD_BLK_OUT);
! 316: if ( ! mlg_endtag(p, -1, MD_NS_DEFAULT))
! 317: return(0);
! 318:
! 319: return(mlg_newline(p));
! 320: }
! 321:
! 322:
! 323: /* ARGSUSED */
! 324: static int
! 325: mlg_roffspecial(void *arg, int tok, int *argc, char **argv, char **more)
! 326: {
! 327: struct md_mlg *p;
! 328:
! 329: assert(arg);
! 330: p = (struct md_mlg *)arg;
! 331:
! 332: switch (tok) {
! 333: case (ROFF_Ns):
! 334: p->flags |= ML_OVERRIDE_ONE;
! 335: break;
! 336: case (ROFF_Sm):
! 337: assert(*more);
! 338: if (0 == strcmp(*more, "on"))
! 339: p->flags |= ML_OVERRIDE_ALL;
! 340: else
! 341: p->flags &= ~ML_OVERRIDE_ALL;
! 342: break;
! 343: default:
! 344: break;
! 345: }
! 346:
! 347: return(1);
! 348: }
! 349:
! 350:
! 351: static int
! 352: mlg_roffblkin(void *arg, int tok, int *argc, char **argv)
! 353: {
! 354: struct md_mlg *p;
! 355:
! 356: assert(arg);
! 357: p = (struct md_mlg *)arg;
! 358:
! 359: if (0 != p->pos) {
! 360: if ( ! mlg_newline(p))
! 361: return(0);
! 362: if ( ! mlg_indent(p))
! 363: return(0);
! 364: } else if ( ! mlg_indent(p))
! 365: return(0);
! 366:
! 367: p->indent++;
! 368: mlg_mode(p, MD_BLK_IN);
! 369:
! 370: if ( ! mlg_begintag(p, MD_NS_BLOCK, tok, argc, argv))
! 371: return(0);
! 372: return(mlg_newline(p));
! 373: }
! 374:
! 375:
! 376: static int
! 377: mlg_roffblkout(void *arg, int tok)
! 378: {
! 379: struct md_mlg *p;
! 380:
! 381: assert(arg);
! 382: p = (struct md_mlg *)arg;
! 383:
! 384: p->indent--;
! 385:
! 386: if (0 != p->pos) {
! 387: if ( ! mlg_newline(p))
! 388: return(0);
! 389: if ( ! mlg_indent(p))
! 390: return(0);
! 391: } else if ( ! mlg_indent(p))
! 392: return(0);
! 393:
! 394: mlg_mode(p, MD_BLK_OUT);
! 395: if ( ! mlg_endtag(p, MD_NS_BLOCK, tok))
! 396: return(0);
! 397: return(mlg_newline(p));
! 398: }
! 399:
! 400:
! 401: static int
! 402: mlg_roffin(void *arg, int tok, int *argc, char **argv)
! 403: {
! 404: struct md_mlg *p;
! 405:
! 406: assert(arg);
! 407: p = (struct md_mlg *)arg;
! 408:
! 409: /* FIXME: this part. */
! 410:
! 411: if ( ! (ML_OVERRIDE_ONE & p->flags) &&
! 412: ! (ML_OVERRIDE_ALL & p->flags) &&
! 413: p->pos + 11 > COLUMNS)
! 414: if ( ! mlg_newline(p))
! 415: return(0);
! 416:
! 417: if (0 != p->pos && (MD_TEXT == p->last ||
! 418: MD_INLINE_OUT == p->last)
! 419: && ! (ML_OVERRIDE_ONE & p->flags)
! 420: && ! (ML_OVERRIDE_ALL & p->flags))
! 421: if ( ! ml_nputs(p->mbuf, " ", 1, &p->pos))
! 422: return(0);
! 423:
! 424: if (0 == p->pos && ! mlg_indent(p))
! 425: return(0);
! 426:
! 427: mlg_mode(p, MD_INLINE_IN);
! 428: return(mlg_begintag(p, MD_NS_INLINE, tok, argc, argv));
! 429: }
! 430:
! 431:
! 432: static int
! 433: mlg_roffout(void *arg, int tok)
! 434: {
! 435: struct md_mlg *p;
! 436:
! 437: assert(arg);
! 438: p = (struct md_mlg *)arg;
! 439:
! 440: if (0 == p->pos && ! mlg_indent(p))
! 441: return(0);
! 442:
! 443: mlg_mode(p, MD_INLINE_OUT);
! 444: return(mlg_endtag(p, MD_NS_INLINE, tok));
! 445: }
! 446:
! 447:
! 448: static void
! 449: mlg_roffmsg(void *arg, enum roffmsg lvl,
! 450: const char *buf, const char *pos, char *msg)
! 451: {
! 452: char *level;
! 453: struct md_mlg *p;
! 454:
! 455: assert(arg);
! 456: p = (struct md_mlg *)arg;
! 457:
! 458: switch (lvl) {
! 459: case (ROFF_WARN):
! 460: if ( ! (MD_WARN_ALL & p->args->warnings))
! 461: return;
! 462: level = "warning";
! 463: break;
! 464: case (ROFF_ERROR):
! 465: level = "error";
! 466: break;
! 467: default:
! 468: abort();
! 469: }
! 470:
! 471: if (pos)
! 472: (void)fprintf(stderr, "%s:%zu: %s: %s (column %zu)\n",
! 473: p->rbuf->name, p->rbuf->line, level,
! 474: msg, pos - buf);
! 475: else
! 476: (void)fprintf(stderr, "%s: %s: %s\n",
! 477: p->rbuf->name, level, msg);
! 478:
! 479: }
! 480:
! 481:
! 482: static int
! 483: mlg_roffdata(void *arg, int space, char *buf)
! 484: {
! 485: struct md_mlg *p;
! 486:
! 487: assert(arg);
! 488: p = (struct md_mlg *)arg;
! 489:
! 490: if ( ! mlg_data(p, space, buf))
! 491: return(0);
! 492:
! 493: mlg_mode(p, MD_TEXT);
! 494: return(1);
! 495: }
! 496:
CVSweb