1 /*        $NetBSD: getNAME.c,v 1.27 2011/08/29 20:41:06 joerg Exp $   */
2 
3 /*-
4  * Copyright (c) 1997, Christos Zoulas.  All rights reserved.
5  * Copyright (c) 1980, 1993
6  *        The Regents of the University of California.  All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. Neither the name of the University nor the names of its contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  */
32 
33 #include <sys/cdefs.h>
34 #ifndef lint
35 __COPYRIGHT("@(#) Copyright (c) 1980, 1993\
36  The Regents of the University of California.  All rights reserved.");
37 #if 0
38 static char sccsid[] = "@(#)getNAME.c   8.1 (Berkeley) 6/30/93";
39 #else
40 __RCSID("$NetBSD: getNAME.c,v 1.27 2011/08/29 20:41:06 joerg Exp $");
41 #endif
42 #endif /* not lint */
43 
44 /*
45  * Get name sections from manual pages.
46  *        -t        for building toc
47  *        -i        for building intro entries
48  *        -w        for querying type of manual source
49  *        -v        verbose
50  *        other     apropos database
51  */
52 #include <err.h>
53 #include <ctype.h>
54 #include <stdio.h>
55 #include <stdlib.h>
56 #include <string.h>
57 #include <unistd.h>
58 
59 static int tocrc;
60 static int intro;
61 static int typeflag;
62 static int verbose;
63 
64 #define SLOP 10     /* strlen(" () - ") < 10 */
65 
66 static char *linebuf = NULL;
67 static size_t maxlen = 0;
68 
69 
70 static void doname(char *);
71 static void dorefname(char *);
72 static void getfrom(char *);
73 static void oldman(char *, char *);
74 static void newman(char *, char *);
75 static void remcomma(char *, size_t *);
76 static void remquote(char *, size_t *);
77 static void fixxref(char *, size_t *);
78 static void split(char *, char *);
79 __dead static void usage(void);
80 
81 int main(int, char *[]);
82 
83 /* The .SH NAMEs that are allowed. */
84 static const char *names[] = { "name", "namn", 0 };
85 
86 int
main(int argc,char * argv[])87 main(int argc, char *argv[])
88 {
89           int ch;
90 
91           while ((ch = getopt(argc, argv, "itvw")) != -1)
92                     switch (ch) {
93                     case 'i':
94                               intro = 1;
95                               break;
96                     case 't':
97                               tocrc = 1;
98                               break;
99                     case 'v':
100                               verbose = 1;
101                               break;
102                     case 'w':
103                               typeflag = 1;
104                               break;
105                     case '?':
106                     default:
107                               usage();
108                     }
109           argc -= optind;
110           argv += optind;
111 
112           if (!*argv)
113                     usage();
114 
115           for (; *argv; ++argv)
116                     getfrom(*argv);
117           return 0;
118 }
119 
120 static void
getfrom(char * pathname)121 getfrom(char *pathname)
122 {
123           char *name;
124           char *line;
125           size_t len;
126 
127           if (freopen(pathname, "r", stdin) == 0) {
128                     warn("Cannot open `%s'", pathname);
129                     return;
130           }
131           if ((name = strrchr(pathname, '/')) != NULL)
132                     name++;
133           else
134                     name = pathname;
135           for (;;) {
136                     if ((line = fgetln(stdin, &len)) == NULL) {
137                               if (typeflag)
138                                         (void)printf("%-60s\tUNKNOWN\n", pathname);
139                               if (verbose)
140                                         warnx("missing .TH or .Dt section in `%s'",
141                                             pathname);
142                               return;
143                     }
144                     if (len < 3)
145                               continue;
146                     if (line[0] != '.')
147                               continue;
148                     if ((line[1] == 'T' && line[2] == 'H') ||
149                         (line[1] == 't' && line[2] == 'h')) {
150                               oldman(pathname, name);
151                               return;
152                     }
153                     if (line[1] == 'D' && line[2] == 't') {
154                               newman(pathname, name);
155                               return;
156                     }
157           }
158 }
159 
160 static void
oldman(char * pathname,char * name)161 oldman(char *pathname, char *name)
162 {
163           char *line, *ext, *s, *newlinebuf;
164           size_t len, i, extlen;
165           size_t curlen = 0;
166           size_t newmaxlen;
167           size_t ocurlen = -1;
168 
169           if (typeflag) {
170                     (void)printf("%-60s\tOLD\n", pathname);
171                     return;
172           }
173           for (;;) {
174                     if ((line = fgetln(stdin, &len)) == NULL) {
175                               if (verbose)
176                                         warnx("missing .SH section in `%s'", pathname);
177                               return;
178                     }
179                     if (len < 4)
180                               continue;
181                     if (line[0] != '.')
182                               continue;
183                     if (line[1] == 'S' && line[2] == 'H')
184                               break;
185                     if (line[1] == 's' && line[2] == 'h')
186                               break;
187           }
188 
189           for (s = &line[3]; s < &line[len] &&
190               (isspace((unsigned char) *s) || *s == '"' || *s == '\''); s++)
191                     continue;
192           if (s == &line[len]) {
193                     warnx("missing argument to .SH in `%s'", pathname);
194                     return;
195           }
196           for (i = 0; names[i]; i++)
197                     if (strncasecmp(s, names[i], strlen(names[i])) == 0)
198                               break;
199           if (names[i] == NULL) {
200                     warnx("first .SH section is not \"NAME\" in `%s'", pathname);
201                     return;
202           }
203 
204  again:
205           if (tocrc)
206                     doname(name);
207 
208           for (i = 0;; i++) {
209                     if ((line = fgetln(stdin, &len)) == NULL)
210                               break;
211                     if (line[0] == '.') {
212                               if (line[1] == '\\' && line[2] == '"')
213                                         continue; /* [nt]roff comment */
214                               if (line[1] == 'S' && line[2] == 'H')
215                                         break;
216                               if (line[1] == 's' && line[2] == 'h')
217                                         break;
218                               if (line[1] == 'P' && line[2] == 'P')
219                                         break;
220                               if (line[1] == 'b' && line[2] == 'r') {
221                                         if (intro)
222                                                   split(linebuf, name);
223                                         else
224                                                   (void)printf("%s\n", linebuf);
225                                         curlen = ocurlen;
226                                         goto again;
227                               }
228                     }
229                     if (line[len - 1] == '\n') {
230                               line[len - 1] = '\0';
231                               len--;
232                     }
233                     if ((ext = strrchr(name, '.')) != NULL) {
234                               ext++;
235                               extlen = strlen(ext);
236                     }
237                     else
238                               extlen = 0;
239 
240                     if (maxlen + extlen < curlen + len + SLOP) {
241                               newmaxlen = 2 * (curlen + len) + SLOP + extlen;
242                               if ((newlinebuf = realloc(linebuf, newmaxlen)) == NULL)
243                                         err(1, NULL);
244                               linebuf = newlinebuf;
245                               maxlen = newmaxlen;
246                     }
247                     if (i != 0)
248                               linebuf[curlen++] = ' ';
249                     (void)memcpy(&linebuf[curlen], line, len);
250                     ocurlen = curlen;
251                     curlen += len;
252                     linebuf[curlen] = '\0';
253 
254                     if(!tocrc && !intro) {
255                               /* change the \- into (N) - */
256                               if ((s = strstr(linebuf, "\\-")) != NULL) {
257                                         (void)memmove(s + extlen + 3, s + 1,
258                                                         curlen - (s + 1 - linebuf));
259                                         curlen--;
260                                         if (extlen) {
261                                                   *s++ = '(';
262                                                   while (*ext)
263                                                             *s++ = *ext++;
264                                                   *s++ = ')';
265                                                   *s++ = ' ';
266                                                   curlen += extlen + 3;
267                                         }
268                                         linebuf[curlen] = '\0';
269                               }
270                     }
271           }
272 
273           if (intro)
274                     split(linebuf, name);
275           else
276                     (void)printf("%s\n", linebuf);
277           return;
278 }
279 
280 static void
newman(char * pathname,char * name)281 newman(char *pathname, char *name)
282 {
283           char *line, *ext, *s, *newlinebuf;
284           size_t len, i, extlen;
285           size_t curlen = 0;
286           size_t newmaxlen;
287 
288           if (typeflag) {
289                     (void)printf("%-60s\tNEW\n", pathname);
290                     return;
291           }
292           for (;;) {
293                     if ((line = fgetln(stdin, &len)) == NULL) {
294                               if (verbose)
295                                         warnx("missing .Sh section in `%s'", pathname);
296                               return;
297                     }
298                     if (line[0] != '.')
299                               continue;
300                     if (line[1] == 'S' && line[2] == 'h')
301                               break;
302           }
303 
304           for (s = &line[3]; s < &line[len] && isspace((unsigned char) *s); s++)
305                     continue;
306           if (s == &line[len]) {
307                     warnx("missing argument to .Sh in `%s'", pathname);
308                     return;
309           }
310           for (i = 0; names[i]; i++)
311                     if (strncasecmp(s, names[i], strlen(names[i])) == 0)
312                               break;
313           if (names[i] == NULL) {
314                     warnx("first .SH section is not \"NAME\" in `%s'", pathname);
315                     return;
316           }
317 
318           if (tocrc)
319                     doname(name);
320 
321           for (i = 0;; i++) {
322                     if ((line = fgetln(stdin, &len)) == NULL)
323                               break;
324 
325                     if (line[0] == '.') {
326                               if (line[1] == '\\' && line[2] == '"')
327                                         continue; /* [nt]roff comment */
328                               if (line[1] == 'S' && line[2] == 'h')
329                                         break;
330                     }
331 
332                     if (line[len - 1] == '\n') {
333                               line[len - 1] = '\0';
334                               len--;
335                     }
336 
337                     if ((ext = strrchr(name, '.')) != NULL) {
338                               ext++;
339                               extlen = strlen(ext);
340                     }
341                     else
342                               extlen = 0;
343 
344                     if (maxlen + extlen < curlen + len + SLOP) {
345                               newmaxlen = 2 * (curlen + len) + SLOP + extlen;
346                               if ((newlinebuf = realloc(linebuf, newmaxlen)) == NULL)
347                                         err(1, NULL);
348                               linebuf = newlinebuf;
349                               maxlen = newmaxlen;
350                     }
351 
352                     if (i != 0)
353                               linebuf[curlen++] = ' ';
354 
355                     remcomma(line, &len);
356 
357                     if (line[0] != '.') {
358                               (void)memcpy(&linebuf[curlen], line, len);
359                               curlen += len;
360                     }
361                     else {
362                               remquote(line, &len);
363                               fixxref(line, &len);
364 
365                               /*
366                                * Put section and dash between names and description.
367                                */
368                               if (line[1] == 'N' && line[2] == 'd') {
369                                         if(!tocrc && !intro) {
370                                                   if (extlen) {
371                                                             linebuf[curlen++] = '(';
372                                                             while (*ext)
373                                                                       linebuf[curlen++] = *ext++;
374                                                             linebuf[curlen++] = ')';
375                                                             linebuf[curlen++] = ' ';
376                                                   }
377                                         }
378                                         linebuf[curlen++] = '-';
379                                         linebuf[curlen++] = ' ';
380                               }
381                               /*
382                                * Skip over macro names.
383                                */
384                               if (len <= 4)
385                                         continue;
386                               (void)memcpy(&linebuf[curlen], &line[4], len - 4);
387                               curlen += len - 4;
388                     }
389           }
390           linebuf[curlen] = '\0';
391           if (intro)
392                     split(linebuf, name);
393           else
394                     (void)printf("%s\n", linebuf);
395 }
396 
397 /*
398  * convert " ," -> " "
399  */
400 static void
remcomma(char * line,size_t * len)401 remcomma(char *line, size_t *len)
402 {
403           char *pline = line, *loc;
404           size_t plen = *len;
405 
406           while ((loc = memchr(pline, ' ', plen)) != NULL) {
407                     plen -= loc - pline + 1;
408                     pline = loc;
409                     if (loc[1] == ',') {
410                               (void)memcpy(loc, &loc[1], plen);
411                               (*len)--;
412                     }
413                     else
414                               pline++;
415           }
416 }
417 
418 /*
419  * Get rid of quotes in macros.
420  */
421 static void
remquote(char * line,size_t * len)422 remquote(char *line, size_t *len)
423 {
424           char *loc;
425           char *pline = &line[4];
426           size_t plen = *len - 4;
427 
428           if (*len < 4)
429                     return;
430 
431           while ((loc = memchr(pline, '"', plen)) != NULL) {
432                     plen -= loc - pline + 1;
433                     pline = loc;
434                     (void)memcpy(loc, &loc[1], plen);
435                     (*len)--;
436           }
437 }
438 
439 /*
440  * Handle cross references
441  */
442 static void
fixxref(char * line,size_t * len)443 fixxref(char *line, size_t *len)
444 {
445           char *loc;
446           char *pline = &line[4];
447           size_t plen = *len - 4;
448 
449           if (*len < 4)
450                     return;
451 
452           if (line[1] == 'X' && line[2] == 'r') {
453                     if ((loc = memchr(pline, ' ', plen)) != NULL) {
454                               *loc++ = '(';
455                               loc++;
456                               *loc++ = ')';
457                               *len = loc - line;
458                     }
459           }
460 }
461 
462 static void
doname(char * name)463 doname(char *name)
464 {
465           char *dp = name, *ep;
466 
467 again:
468           while (*dp && *dp != '.')
469                     (void)putchar(*dp++);
470           if (*dp)
471                     for (ep = dp+1; *ep; ep++)
472                               if (*ep == '.') {
473                                         (void)putchar(*dp++);
474                                         goto again;
475                               }
476           (void)putchar('(');
477           if (*dp)
478                     dp++;
479           while (*dp)
480                     (void)putchar(*dp++);
481           (void)putchar(')');
482           (void)putchar(' ');
483 }
484 
485 static void
split(char * line,char * name)486 split(char *line, char *name)
487 {
488           char *cp, *dp;
489           char *sp;
490           const char *sep;
491 
492           cp = strchr(line, '-');
493           if (cp == 0)
494                     return;
495           sp = cp + 1;
496           for (--cp; *cp == ' ' || *cp == '\t' || *cp == '\\'; cp--)
497                     ;
498           *++cp = '\0';
499           while (*sp && (*sp == ' ' || *sp == '\t'))
500                     sp++;
501           for (sep = "", dp = line; dp && *dp; dp = cp, sep = "\n") {
502                     cp = strchr(dp, ',');
503                     if (cp) {
504                               char *tp;
505 
506                               for (tp = cp - 1; *tp == ' ' || *tp == '\t'; tp--)
507                                         ;
508                               *++tp = '\0';
509                               for (++cp; *cp == ' ' || *cp == '\t'; cp++)
510                                         ;
511                     }
512                     (void)printf("%s%s\t", sep, dp);
513                     dorefname(name);
514                     (void)printf("\t- %s", sp);
515           }
516           (void)putchar('\n');
517 }
518 
519 static void
dorefname(char * name)520 dorefname(char *name)
521 {
522           char *dp = name, *ep;
523 
524 again:
525           while (*dp && *dp != '.')
526                     (void)putchar(*dp++);
527           if (*dp)
528                     for (ep = dp+1; *ep; ep++)
529                               if (*ep == '.') {
530                                         (void)putchar(*dp++);
531                                         goto again;
532                               }
533           (void)putchar('.');
534           if (*dp)
535                     dp++;
536           while (*dp)
537                     (void)putchar(*dp++);
538 }
539 
540 static void
usage(void)541 usage(void)
542 {
543 
544           (void)fprintf(stderr, "Usage: %s [-itw] file ...\n", getprogname());
545           exit(1);
546 }
547