=================================================================== RCS file: /cvs/docbook2mdoc/macro.c,v retrieving revision 1.12 retrieving revision 1.21 diff -u -p -r1.12 -r1.21 --- docbook2mdoc/macro.c 2019/04/14 12:59:15 1.12 +++ docbook2mdoc/macro.c 2019/05/20 20:08:26 1.21 @@ -1,4 +1,4 @@ -/* $Id: macro.c,v 1.12 2019/04/14 12:59:15 schwarze Exp $ */ +/* $Id: macro.c,v 1.21 2019/05/20 20:08:26 schwarze Exp $ */ /* * Copyright (c) 2019 Ingo Schwarze * @@ -28,20 +28,36 @@ */ void +para_check(struct format *f) +{ + if (f->parastate != PARA_WANT) + return; + if (f->linestate != LINE_NEW) { + putchar('\n'); + f->linestate = LINE_NEW; + } + puts(".Pp"); + f->parastate = PARA_HAVE; +} + +void macro_open(struct format *f, const char *name) { + para_check(f); switch (f->linestate) { case LINE_MACRO: if (f->flags & FMT_NOSPC) { fputs(" Ns ", stdout); break; } - if (f->flags & (FMT_CHILD | FMT_IMPL)) { + if (f->nofill || f->flags & (FMT_CHILD | FMT_IMPL)) { putchar(' '); break; } /* FALLTHROUGH */ case LINE_TEXT: + if (f->nofill && f->linestate == LINE_TEXT) + fputs(" \\c", stdout); putchar('\n'); /* FALLTHROUGH */ case LINE_NEW: @@ -53,6 +69,7 @@ macro_open(struct format *f, const char *name) fputs(name, stdout); f->flags &= FMT_IMPL; f->flags |= FMT_ARG; + f->parastate = PARA_MID; } void @@ -79,11 +96,13 @@ void macro_addarg(struct format *f, const char *arg, int flags) { const char *cp; + int quote_now; assert(f->linestate == LINE_MACRO); /* Quote if requested and necessary. */ + quote_now = 0; if ((flags & (ARG_SINGLE | ARG_QUOTED)) == ARG_SINGLE) { for (cp = arg; *cp != '\0'; cp++) if (isspace((unsigned char)*cp)) @@ -95,6 +114,7 @@ macro_addarg(struct format *f, const char *arg, int fl } putchar('"'); flags = ARG_QUOTED; + quote_now = 1; } } @@ -110,6 +130,13 @@ macro_addarg(struct format *f, const char *arg, int fl flags &= ~ ARG_SPACE; } + /* For XML entities, skip escaping. */ + + if (flags & ARG_RAW) { + fputs(arg, stdout); + break; + } + /* Escape us if we look like a macro. */ if ((flags & (ARG_QUOTED | ARG_UPPER)) == 0 && @@ -133,6 +160,9 @@ macro_addarg(struct format *f, const char *arg, int fl if (*cp == '\\') putchar('e'); } + if (quote_now) + putchar('"'); + f->parastate = PARA_MID; } void @@ -150,7 +180,7 @@ void macro_addnode(struct format *f, struct pnode *n, int flags) { struct pnode *nc; - int quote_now; + int is_text, quote_now; assert(f->linestate == LINE_MACRO); @@ -163,9 +193,16 @@ macro_addnode(struct format *f, struct pnode *n, int f TAILQ_NEXT(nc, child) == NULL) n = nc; - if (n->node == NODE_TEXT || n->node == NODE_ESCAPE) { + switch (n->node) { + case NODE_ESCAPE: + flags |= ARG_RAW; + /* FALLTHROUGH */ + case NODE_TEXT: macro_addarg(f, n->b, flags); + f->parastate = PARA_MID; return; + default: + break; } /* @@ -194,11 +231,18 @@ macro_addnode(struct format *f, struct pnode *n, int f while (nc != NULL) { macro_addnode(f, nc, flags); + is_text = pnode_class(nc->node) == CLASS_TEXT; nc = TAILQ_NEXT(nc, child); - flags |= ARG_SPACE; + if (nc == NULL || pnode_class(nc->node) != CLASS_TEXT) + is_text = 0; + if (is_text && (nc->flags & NFLAG_SPC) == 0) + flags &= ~ARG_SPACE; + else + flags |= ARG_SPACE; } if (quote_now) putchar('"'); + f->parastate = PARA_MID; } void @@ -217,6 +261,9 @@ macro_nodeline(struct format *f, const char *name, str void print_text(struct format *f, const char *word, int flags) { + int ateos, inword; + + para_check(f); switch (f->linestate) { case LINE_NEW: break; @@ -230,12 +277,59 @@ print_text(struct format *f, const char *word, int fla } if (f->linestate == LINE_NEW && (*word == '.' || *word == '\'')) fputs("\\&", stdout); + ateos = inword = 0; while (*word != '\0') { + if (f->nofill == 0) { + switch (*word) { + case ' ': + if (ateos == 0) { + inword = 0; + break; + } + ateos = inword = 0; + /* Handle the end of a sentence. */ + while (*word == ' ') + word++; + switch (*word) { + case '\0': + break; + case '\'': + case '.': + fputs("\n\\&", stdout); + break; + default: + putchar('\n'); + break; + } + continue; + /* Detect the end of a sentence. */ + case '!': + case '.': + case '?': + if (inword > 1 && + (word[-2] != 'n' || word[-1] != 'c') && + (word[-2] != 'v' || word[-1] != 's')) + ateos = 1; + /* FALLTHROUGH */ + case '"': + case '\'': + case ')': + case ']': + inword = 0; + break; + default: + if (isalnum((unsigned char)*word)) + inword++; + ateos = 0; + break; + } + } putchar(*word); if (*word++ == '\\') putchar('e'); } f->linestate = LINE_TEXT; + f->parastate = PARA_MID; f->flags = 0; }