=================================================================== RCS file: /cvs/pod2mdoc/pod2mdoc.c,v retrieving revision 1.16 retrieving revision 1.20 diff -u -p -r1.16 -r1.20 --- pod2mdoc/pod2mdoc.c 2014/04/02 16:41:02 1.16 +++ pod2mdoc/pod2mdoc.c 2014/04/03 11:34:30 1.20 @@ -1,4 +1,4 @@ -/* $Id: pod2mdoc.c,v 1.16 2014/04/02 16:41:02 kristaps Exp $ */ +/* $Id: pod2mdoc.c,v 1.20 2014/04/03 11:34:30 kristaps Exp $ */ /* * Copyright (c) 2014 Kristaps Dzonsons * @@ -27,7 +27,9 @@ #include /* - * In what section can we find Perl manuals? + * In what section can we find Perl module manuals? + * Sometimes (Mac OS X) it's 3pm, sometimes (OpenBSD, etc.) 3p. + * XXX IF YOU CHANGE THIS, CHANGE POD2MDOC.1 AS WELL. */ #define PERL_SECTION "3p" @@ -170,72 +172,128 @@ formatescape(const char *buf, size_t *start, size_t en /* * Run some heuristics to intuit a link format. - * I recognise L as a Perl manpage, printing it in section 3p; - * or a general UNIX foo(5) manpage. - * If I recognise one, I set "start" to be the end of the sequence so + * I set "start" to be the end of the sequence (last right-carrot) so * that the caller can safely just continue processing. - * Otherwise, I don't touch "start". + * If this is just an empty tag, I'll return 0. */ static int trylink(const char *buf, size_t *start, size_t end, size_t dsz) { - size_t sv, nstart, nend, i, j; - int hasdouble; + size_t linkstart, realend, linkend, i, j, textsz; + const char *text; /* * Scan to the start of the terminus. * This function is more or less replicated in the formatcode() * for null or index formatting codes. */ - hasdouble = 0; - for (sv = nstart = *start; nstart < end; nstart++) { - /* Do we have a double-colon? */ - if (':' == buf[nstart] && - nstart > sv && - ':' == buf[nstart - 1]) - hasdouble = 1; - if ('>' != buf[nstart]) + for (linkstart = realend = *start; realend < end; realend++) { + if ('>' != buf[realend]) continue; else if (dsz == 1) break; - assert(nstart > 0); - if (' ' != buf[nstart - 1]) + assert(realend > 0); + if (' ' != buf[realend - 1]) continue; - i = nstart; - for (j = 0; i < end && j < dsz; j++) + for (i = realend, j = 0; i < end && j < dsz; j++) if ('>' != buf[i++]) break; if (dsz == j) break; } - - /* We don't care about stubs. */ - if (nstart == end || nstart == *start) + + /* Ignore stubs. */ + if (realend == end || realend == *start) return(0); - /* Set nend to the end of content. */ - nend = nstart; - if (dsz > 1) - nend--; + /* Set linkend to the end of content. */ + linkend = dsz > 1 ? realend - 1 : realend; - /* - * Provide for some common invocations of the link primitive. - * First, allow us to link to other Perl manuals. - */ - if (hasdouble) + /* Re-scan to see if we have a title or section. */ + text = &buf[*start]; + for (textsz = *start; textsz < linkend; textsz++) + if ('|' == buf[textsz] || '/' == buf[textsz]) + break; + + if (textsz < linkend && '|' == buf[textsz]) { + /* With title: set start, then end at section. */ + linkstart = textsz + 1; + textsz = textsz - *start; + for (i = linkstart; i < linkend; i++) + if ('/' == buf[i]) + break; + if (i < linkend) + linkend = i; + } else if (textsz < linkend && '/' == buf[textsz]) { + /* With section: set end at section. */ + linkend = textsz; + textsz = 0; + } else + /* No title, no section. */ + textsz = 0; + + *start = realend; + j = linkend - linkstart; + + /* Do we have only subsection material? */ + if (0 == j && '/' == buf[linkend]) { + linkstart = linkend + 1; + linkend = dsz > 1 ? realend - 1 : realend; + if (0 == (j = linkend - linkstart)) + return(0); + printf("Sx %.*s", (int)j, &buf[linkstart]); + return(1); + } else if (0 == j) + return(0); + + /* See if we qualify as being a link or not. */ + if ((j > 4 && 0 == memcmp("http:", &buf[linkstart], j)) || + (j > 5 && 0 == memcmp("https:", &buf[linkstart], j)) || + (j > 3 && 0 == memcmp("ftp:", &buf[linkstart], j)) || + (j > 4 && 0 == memcmp("sftp:", &buf[linkstart], j)) || + (j > 3 && 0 == memcmp("smb:", &buf[linkstart], j)) || + (j > 3 && 0 == memcmp("afs:", &buf[linkstart], j))) { + /* Gross. */ + printf("Lk %.*s", (int)((dsz > 1 ? realend - 1 : + realend) - linkstart), &buf[linkstart]); + return(1); + } + + /* See if we qualify as a mailto. */ + if (j > 6 && 0 == memcmp("mailto:", &buf[linkstart], j)) { + printf("Mt %.*s", (int)j, &buf[linkstart]); + return(1); + } + + /* See if we're a foo(5), foo(5x), or foo(5xx) manpage. */ + if ((j > 3 && ')' == buf[linkend - 1]) && + ('(' == buf[linkend - 3])) { + printf("Xr %.*s %c", (int)(j - 3), + &buf[linkstart], buf[linkend - 2]); + return(1); + } else if ((j > 4 && ')' == buf[linkend - 1]) && + ('(' == buf[linkend - 4])) { + printf("Xr %.*s %.*s", (int)(j - 4), + &buf[linkstart], 2, &buf[linkend - 3]); + return(1); + } else if ((j > 5 && ')' == buf[linkend - 1]) && + ('(' == buf[linkend - 5])) { + printf("Xr %.*s %.*s", (int)(j - 5), + &buf[linkstart], 3, &buf[linkend - 4]); + return(1); + } + + /* Last try: do we have a double-colon? */ + for (i = linkstart + 1; i < linkend; i++) + if (':' == buf[i] && ':' == buf[i - 1]) + break; + + if (i < linkend) printf("Xr %.*s " PERL_SECTION, - (int)(nend - sv), &buf[sv]); - else if (nend - sv > 3 && isalnum(buf[sv]) && - ')' == buf[nend - 1] && - isdigit((int)buf[nend - 2]) && - '(' == buf[nend - 3]) - printf("Xr %.*s %c", - (int)(nend - 3 - sv), - &buf[sv], buf[nend - 2]); + (int)j, &buf[linkstart]); else - return(0); + printf("Xr %.*s 1", (int)j, &buf[linkstart]); - *start = nstart; return(1); } @@ -444,6 +502,7 @@ formatcode(struct state *st, const char *buf, size_t * printf("Qo Li "); break; case (FMT_LINK): + /* Try to link; use "No" if it's empty. */ if ( ! trylink(buf, start, end, dsz)) printf("No "); break; @@ -866,6 +925,40 @@ dosynopsisop(const char *buf, int *last, } /* + * Format multiple "Nm" manpage names in the NAME section. + */ +static void +donamenm(struct state *st, const char *buf, size_t *start, size_t end) +{ + size_t word; + + while (*start < end && ' ' == buf[*start]) + (*start)++; + + if (end == *start) { + puts(".Nm unknown"); + return; + } + + while (*start < end) { + fputs(".Nm ", stdout); + for (word = *start; word < end; word++) + if (',' == buf[word]) + break; + formatcodeln(st, buf, start, word, 1); + if (*start == end) { + putchar('\n'); + continue; + } + assert(',' == buf[*start]); + puts(" ,"); + (*start)++; + while (*start < end && ' ' == buf[*start]) + (*start)++; + } +} + +/* * Ordinary paragraph. * Well, this is really the hardest--POD seems to assume that, for * example, a leading space implies a newline, and so on. @@ -898,10 +991,10 @@ ordinary(struct state *st, const char *buf, size_t sta for ( ; i > start; i--) if ('-' != buf[i]) break; - fputs(".Nm ", stdout); - formatcodeln(st, buf, &start, i + 1, 1); - putchar('\n'); + donamenm(st, buf, &start, i + 1); start = j + 1; + while (start < end && ' ' == buf[start]) + start++; fputs(".Nd ", stdout); formatcodeln(st, buf, &start, end, 1); putchar('\n');