~ubuntu-branches/ubuntu/vivid/mutt/vivid-updates

« back to all changes in this revision

Viewing changes to makedoc.c

Tags: 1.5.18-6
* Grab from upstream:
  + Guard idata->mailbox read in imap_mailbox_state.
    The bug happens when a user has more than a imap mailbox, when
    he/she browses through them mutt will segfault.
    (Closes: #462266, #513230, #514309. Mutt: #3057)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * Copyright (C) 1999-2000 Thomas Roessler <roessler@does-not-exist.org>
3
 
 * 
4
 
 *     This program is free software; you can redistribute it and/or modify
5
 
 *     it under the terms of the GNU General Public License as published by
6
 
 *     the Free Software Foundation; either version 2 of the License, or
7
 
 *     (at your option) any later version.
8
 
 * 
9
 
 *     This program is distributed in the hope that it will be useful,
10
 
 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 
 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
 
 *     GNU General Public License for more details.
13
 
 * 
14
 
 *     You should have received a copy of the GNU General Public License
15
 
 *     along with this program; if not, write to the Free Software
16
 
 *     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
17
 
 */ 
18
 
 
19
 
/**
20
 
 ** This program parses mutt's init.h and generates documentation in
21
 
 ** three different formats:
22
 
 **
23
 
 ** -> a commented muttrc configuration file
24
 
 ** -> nroff, suitable for inclusion in a manual page
25
 
 ** -> docbook-xml, suitable for inclusion in the 
26
 
 **    SGML-based manual
27
 
 **
28
 
 **/
29
 
 
30
 
#if HAVE_CONFIG_H
31
 
# include "config.h"
32
 
#endif
33
 
 
34
 
#include <stdio.h>
35
 
#include <stdlib.h>
36
 
#include <string.h>
37
 
#include <ctype.h>
38
 
 
39
 
#include <errno.h>
40
 
 
41
 
#ifdef HAVE_UNISTD_H
42
 
# include <unistd.h>
43
 
#endif
44
 
 
45
 
#ifdef HAVE_GETOPT_H
46
 
# include <getopt.h>
47
 
#endif
48
 
 
49
 
#ifndef HAVE_STRERROR
50
 
#ifndef STDC_HEADERS
51
 
extern int sys_nerr;
52
 
extern char *sys_errlist[];
53
 
#endif
54
 
 
55
 
#define strerror(x) ((x) > 0 && (x) < sys_nerr) ? sys_errlist[(x)] : 0
56
 
#endif /* !HAVE_STRERROR */
57
 
 
58
 
extern int optind;
59
 
 
60
 
#define BUFFSIZE 2048
61
 
 
62
 
enum output_formats_t
63
 
{
64
 
  F_CONF, F_MAN, F_SGML, F_NONE
65
 
};
66
 
 
67
 
#define D_NL            (1 << 0)
68
 
#define D_EM            (1 << 1)
69
 
#define D_BF            (1 << 2)
70
 
#define D_TAB           (1 << 3)
71
 
#define D_NP            (1 << 4)
72
 
#define D_INIT          (1 << 5)
73
 
#define D_DL            (1 << 6)
74
 
#define D_DT            (1 << 7)
75
 
#define D_DD            (1 << 8)
76
 
#define D_PA            (1 << 9)
77
 
 
78
 
enum
79
 
{
80
 
  SP_START_EM,
81
 
  SP_START_BF,
82
 
  SP_END_FT,
83
 
  SP_NEWLINE,
84
 
  SP_NEWPAR,
85
 
  SP_END_PAR,
86
 
  SP_STR,
87
 
  SP_START_TAB,
88
 
  SP_END_TAB,
89
 
  SP_START_DL,
90
 
  SP_DT,
91
 
  SP_DD,
92
 
  SP_END_DD,
93
 
  SP_END_DL,
94
 
  SP_END_SECT,
95
 
  SP_REFER
96
 
};
97
 
 
98
 
enum output_formats_t OutputFormat = F_NONE;
99
 
char *Progname;
100
 
short Debug = 0;
101
 
 
102
 
static char *get_token (char *, size_t, char *);
103
 
static char *skip_ws (char *);
104
 
static const char *type2human (int);
105
 
static int buff2type (const char *);
106
 
static int flush_doc (int, FILE *);
107
 
static int handle_docline (char *, FILE *, int);
108
 
static int print_it (int, char *, FILE *, int);
109
 
static void print_confline (const char *, int, const char *, FILE *);
110
 
static void handle_confline (char *, FILE *);
111
 
static void makedoc (FILE *, FILE *);
112
 
static void pretty_default (char *, size_t, const char *, int);
113
 
static int sgml_fputc (int, FILE *);
114
 
static int sgml_fputs (const char *, FILE *);
115
 
static int sgml_id_fputs (const char *, FILE *);
116
 
 
117
 
int main (int argc, char *argv[])
118
 
{
119
 
  int c;
120
 
  FILE *f;
121
 
 
122
 
  if ((Progname = strrchr (argv[0], '/')))
123
 
    Progname++;
124
 
  else
125
 
    Progname = argv[0];
126
 
  
127
 
  while ((c = getopt (argc, argv, "cmsd")) != EOF)
128
 
  {
129
 
    switch (c)
130
 
    {
131
 
      case 'c': OutputFormat = F_CONF; break;
132
 
      case 'm': OutputFormat = F_MAN; break;
133
 
      case 's': OutputFormat = F_SGML; break;
134
 
      case 'd': Debug++; break;
135
 
      default: 
136
 
      {
137
 
        fprintf (stderr, "%s: bad command line parameter.\n", Progname);
138
 
        exit (1);
139
 
      }
140
 
    }
141
 
  }
142
 
 
143
 
  if (optind != argc)
144
 
  {
145
 
    if ((f = fopen (argv[optind], "r")) == NULL)
146
 
    {
147
 
      fprintf (stderr, "%s: Can't open %s (%s).\n",
148
 
               Progname, argv[optind], strerror (errno));
149
 
      exit (1);
150
 
    }
151
 
  }
152
 
  else 
153
 
    f = stdin;
154
 
 
155
 
  switch (OutputFormat)
156
 
  {
157
 
    case F_CONF: 
158
 
    case F_MAN:  
159
 
    case F_SGML: makedoc (f, stdout); break;
160
 
    default:
161
 
    {
162
 
      fprintf (stderr, "%s: No output format specified.\n",
163
 
               Progname);
164
 
      exit (1);
165
 
    }
166
 
  }
167
 
  
168
 
  if (f != stdin)
169
 
    fclose (f);
170
 
  
171
 
  exit (1);
172
 
}
173
 
 
174
 
 
175
 
static void makedoc (FILE *in, FILE *out)
176
 
{
177
 
  char buffer[BUFFSIZE];
178
 
  char token[BUFFSIZE];
179
 
  char *p;
180
 
  int active = 0;
181
 
  int line = 0;
182
 
  int docstat = D_INIT;
183
 
 
184
 
  while ((fgets (buffer, sizeof (buffer), in)))
185
 
  {
186
 
    line++;
187
 
    if ((p = strchr (buffer, '\n')) == NULL)
188
 
    {
189
 
      fprintf (stderr, "%s: Line %d too long.  Ask a wizard to enlarge\n"
190
 
                       "%s: my buffer size.\n", Progname, line, Progname);
191
 
      exit (1);
192
 
    }
193
 
    else
194
 
      *p = '\0';
195
 
 
196
 
    if (!(p = get_token (token, sizeof (token), buffer)))
197
 
      continue;
198
 
 
199
 
    if (Debug)
200
 
    {
201
 
      fprintf (stderr, "%s: line %d.  first token: \"%s\".\n",
202
 
               Progname, line, token);
203
 
    }
204
 
    
205
 
    if (!strcmp (token, "/*++*/"))
206
 
      active = 1;
207
 
    else if (!strcmp (token, "/*--*/"))
208
 
    {
209
 
      docstat = flush_doc (docstat, out);
210
 
      active = 0;
211
 
    }
212
 
    else if (active && (!strcmp (token, "/**") || !strcmp (token, "**")))
213
 
      docstat = handle_docline (p, out, docstat);
214
 
    else if (active && !strcmp (token, "{"))
215
 
    {
216
 
      docstat = flush_doc (docstat, out);
217
 
      handle_confline (p, out);
218
 
    }
219
 
  }
220
 
  flush_doc (docstat, out);
221
 
  fputs ("\n", out);
222
 
}
223
 
 
224
 
/* skip whitespace */
225
 
 
226
 
static char *skip_ws (char *s)
227
 
{
228
 
  while (*s && isspace ((unsigned char) *s))
229
 
    s++;
230
 
 
231
 
  return s;
232
 
}
233
 
 
234
 
/* isolate a token */
235
 
 
236
 
static char single_char_tokens[] = "[]{},;|";
237
 
 
238
 
static char *get_token (char *d, size_t l, char *s)
239
 
{
240
 
  char *t;
241
 
  short is_quoted = 0;
242
 
  char *dd = d;
243
 
 
244
 
  if (Debug)
245
 
     fprintf (stderr, "%s: get_token called for `%s'.\n",
246
 
              Progname, s);
247
 
  
248
 
  s = skip_ws (s);
249
 
 
250
 
  if (Debug > 1)
251
 
    fprintf (stderr, "%s: argumet after skip_ws():  `%s'.\n",
252
 
             Progname, s);
253
 
 
254
 
  if (!*s)
255
 
  {
256
 
    if (Debug)
257
 
      fprintf (stderr, "%s: no more tokens on this line.\n", Progname);
258
 
    return NULL;
259
 
  }
260
 
 
261
 
  if (strchr (single_char_tokens, *s))
262
 
  {
263
 
    if (Debug)
264
 
    {
265
 
      fprintf (stderr, "%s: found single character token `%c'.\n",
266
 
               Progname, *s);
267
 
    }
268
 
    d[0] = *s++;
269
 
    d[1] = 0;
270
 
    return s;
271
 
  }
272
 
 
273
 
  if (*s == '"')
274
 
  {
275
 
    if (Debug)
276
 
    {
277
 
      fprintf (stderr, "%s: found quote character.\n", Progname);
278
 
    }
279
 
      
280
 
    s++;
281
 
    is_quoted = 1;
282
 
  }
283
 
 
284
 
  for (t = s; *t && --l > 0; t++)
285
 
  {
286
 
    if (*t == '\\' && !t[1])
287
 
      break;
288
 
 
289
 
    if (is_quoted && *t == '\\')
290
 
    {
291
 
      switch ((*d = *++t))
292
 
      {
293
 
        case 'n': *d = '\n'; break;
294
 
        case 't': *d = '\t'; break;
295
 
        case 'r': *d = '\r'; break;
296
 
        case 'a': *d = '\a'; break;
297
 
      }
298
 
 
299
 
      d++;
300
 
      continue;
301
 
    }
302
 
 
303
 
    if (is_quoted && *t == '"')
304
 
    {
305
 
      t++;
306
 
      break;
307
 
    }
308
 
    else if (!is_quoted && strchr (single_char_tokens, *t))
309
 
      break;
310
 
    else if (!is_quoted && isspace ((unsigned char) *t))
311
 
      break;
312
 
    else
313
 
      *d++ = *t;
314
 
  }
315
 
 
316
 
  *d = '\0';
317
 
 
318
 
  if (Debug)
319
 
  {
320
 
    fprintf (stderr, "%s: Got %stoken: `%s'.\n",
321
 
             Progname, is_quoted ? "quoted " : "", dd);
322
 
    fprintf (stderr, "%s: Remainder: `%s'.\n",
323
 
             Progname, t);
324
 
  }
325
 
  
326
 
  return t;
327
 
}
328
 
 
329
 
 
330
 
/**
331
 
 ** Configuration line parser
332
 
 ** 
333
 
 ** The following code parses a line from init.h which declares
334
 
 ** a configuration variable.
335
 
 **
336
 
 **/
337
 
 
338
 
/* note: the following enum must be in the same order as the
339
 
 * following string definitions!
340
 
 */
341
 
 
342
 
enum 
343
 
{
344
 
  DT_NONE = 0,
345
 
  DT_BOOL,
346
 
  DT_NUM,
347
 
  DT_STR,
348
 
  DT_PATH,
349
 
  DT_QUAD,
350
 
  DT_SORT,
351
 
  DT_RX,
352
 
  DT_MAGIC,
353
 
  DT_SYN,
354
 
  DT_ADDR
355
 
};
356
 
 
357
 
struct 
358
 
{
359
 
  char *machine;
360
 
  char *human;
361
 
}
362
 
types[] = 
363
 
{
364
 
  { "DT_NONE",  "-none-"        },
365
 
  { "DT_BOOL",  "boolean"       },
366
 
  { "DT_NUM",   "number"        },
367
 
  { "DT_STR",   "string"        },
368
 
  { "DT_PATH",  "path"          },
369
 
  { "DT_QUAD",  "quadoption"    },
370
 
  { "DT_SORT",  "sort order"    },
371
 
  { "DT_RX",    "regular expression" },
372
 
  { "DT_MAGIC", "folder magic" },
373
 
  { "DT_SYN",   NULL },
374
 
  { "DT_ADDR",  "e-mail address" },
375
 
  { NULL, NULL }
376
 
};
377
 
    
378
 
 
379
 
static int buff2type (const char *s)
380
 
{
381
 
  int type;
382
 
  
383
 
  for (type = DT_NONE; types[type].machine; type++)
384
 
    if (!strcmp (types[type].machine, s))
385
 
        return type;
386
 
  
387
 
  return DT_NONE;
388
 
}
389
 
 
390
 
static const char *type2human (int type)
391
 
{
392
 
  return types[type].human;
393
 
}
394
 
static void handle_confline (char *s, FILE *out)
395
 
{
396
 
  char varname[BUFFSIZE];
397
 
  char buff[BUFFSIZE];
398
 
  char tmp[BUFFSIZE];
399
 
  int type;
400
 
  
401
 
  char val[BUFFSIZE];
402
 
 
403
 
  /* xxx - put this into an actual state machine? */
404
 
 
405
 
  /* variable name */
406
 
  if (!(s = get_token (varname, sizeof (varname), s))) return;
407
 
  
408
 
  /* comma */
409
 
  if (!(s = get_token (buff, sizeof (buff), s))) return;
410
 
    
411
 
  /* type */
412
 
  if (!(s = get_token (buff, sizeof (buff), s))) return;
413
 
 
414
 
  type = buff2type (buff);
415
 
 
416
 
  /* possibly a "|" or comma */
417
 
  if (!(s = get_token (buff, sizeof (buff), s))) return;
418
 
 
419
 
  if (!strcmp (buff, "|"))
420
 
  {
421
 
    if (Debug) fprintf (stderr, "%s: Expecting <subtype> <comma>.\n", Progname);
422
 
    /* ignore subtype and comma */
423
 
    if (!(s = get_token (buff, sizeof (buff), s))) return;
424
 
    if (!(s = get_token (buff, sizeof (buff), s))) return;
425
 
  }
426
 
 
427
 
  /* redraw, comma */
428
 
  
429
 
  while (1)
430
 
  {
431
 
    if (!(s = get_token (buff, sizeof (buff), s))) return;
432
 
    if (!strcmp (buff, ","))
433
 
      break;
434
 
  }
435
 
 
436
 
  /* option name or UL &address */
437
 
  if (!(s = get_token (buff, sizeof (buff), s))) return;
438
 
  if (!strcmp (buff, "UL"))
439
 
    if (!(s = get_token (buff, sizeof (buff), s))) return;
440
 
 
441
 
  /* comma */
442
 
  if (!(s = get_token (buff, sizeof (buff), s))) return;
443
 
 
444
 
  if (Debug) fprintf (stderr, "%s: Expecting default value.\n", Progname);
445
 
  
446
 
  /* <default value> or UL <default value> */
447
 
  if (!(s = get_token (buff, sizeof (buff), s))) return;
448
 
  if (!strcmp (buff, "UL"))
449
 
  {
450
 
    if (Debug) fprintf (stderr, "%s: Skipping UL.\n", Progname);
451
 
    if (!(s = get_token (buff, sizeof (buff), s))) return;
452
 
  }
453
 
 
454
 
  memset (tmp, 0, sizeof (tmp));
455
 
 
456
 
  do 
457
 
  {
458
 
    if (!strcmp (buff, "}"))
459
 
      break;
460
 
 
461
 
    strncpy (tmp + strlen (tmp), buff, sizeof (tmp) - strlen (tmp));
462
 
  }
463
 
  while ((s = get_token (buff, sizeof (buff), s)));
464
 
 
465
 
  pretty_default (val, sizeof (val), tmp, type);
466
 
  print_confline (varname, type, val, out);
467
 
}
468
 
 
469
 
static void pretty_default (char *t, size_t l, const char *s, int type)
470
 
{
471
 
  memset (t, 0, l);
472
 
  l--;
473
 
 
474
 
  switch (type)
475
 
  {
476
 
    case DT_QUAD:
477
 
    {    
478
 
      if (!strcasecmp (s, "M_YES")) strncpy (t, "yes", l);
479
 
      else if (!strcasecmp (s, "M_NO")) strncpy (t, "no", l);
480
 
      else if (!strcasecmp (s, "M_ASKYES")) strncpy (t, "ask-yes", l);
481
 
      else if (!strcasecmp (s, "M_ASKNO")) strncpy (t, "ask-no", l);
482
 
      break;
483
 
    }
484
 
    case DT_BOOL:
485
 
    {
486
 
      if (atoi (s))
487
 
        strncpy (t, "yes", l);
488
 
      else
489
 
        strncpy (t, "no", l);
490
 
      break;
491
 
    }
492
 
    case DT_SORT:
493
 
    {
494
 
      /* heuristic! */
495
 
      strncpy (t, s + 5, l);
496
 
      for (; *t; t++) *t = tolower ((unsigned char) *t);
497
 
      break;
498
 
    }
499
 
    case DT_MAGIC:
500
 
    {
501
 
      /* heuristic! */
502
 
      strncpy (t, s + 2, l);
503
 
      for (; *t; t++) *t = tolower ((unsigned char) *t);
504
 
      break;
505
 
    }
506
 
    case DT_STR:
507
 
    case DT_RX:
508
 
    case DT_ADDR:
509
 
    case DT_PATH:
510
 
    {
511
 
      if (!strcmp (s, "0"))
512
 
        break;
513
 
      /* fallthrough */
514
 
    }
515
 
    default:
516
 
    {
517
 
      strncpy (t, s, l);
518
 
      break;
519
 
    }
520
 
  }
521
 
}
522
 
 
523
 
static void char_to_escape (char *dest, unsigned int c)
524
 
{
525
 
  switch (c)
526
 
  {
527
 
    case '\r': strcpy (dest, "\\r"); break;     /* __STRCPY_CHECKED__ */
528
 
    case '\n': strcpy (dest, "\\n"); break;     /* __STRCPY_CHECKED__ */
529
 
    case '\t': strcpy (dest, "\\t"); break;     /* __STRCPY_CHECKED__ */
530
 
    case '\f': strcpy (dest, "\\f"); break;     /* __STRCPY_CHECKED__ */
531
 
    default: sprintf (dest, "\\%03o", c); break;
532
 
  }
533
 
}
534
 
static void conf_char_to_escape (unsigned int c , FILE *out)
535
 
{
536
 
  char buff[16];
537
 
  char_to_escape (buff, c);
538
 
  fputs (buff, out);
539
 
}
540
 
 
541
 
static void conf_print_strval (const char *v, FILE *out)
542
 
{
543
 
  for (; *v; v++)
544
 
  {
545
 
    if (*v < ' ' || *v & 0x80)
546
 
    {
547
 
      conf_char_to_escape ((unsigned int) *v, out);
548
 
      continue;
549
 
    }
550
 
 
551
 
    if (*v == '"'  || *v == '\\')
552
 
      fputc ('\\', out);
553
 
    fputc (*v, out);
554
 
  }
555
 
}
556
 
 
557
 
static void man_print_strval (const char *v, FILE *out)
558
 
{
559
 
  for (; *v; v++)
560
 
  {
561
 
    if (*v < ' ' || *v & 0x80)
562
 
    {
563
 
      fputc ('\\', out);
564
 
      conf_char_to_escape ((unsigned int) *v, out);
565
 
      continue;
566
 
    }
567
 
    
568
 
    if (*v == '"')
569
 
      fputs ("\\(rq", out);
570
 
    else if (*v == '\\')
571
 
      fputs ("\\\\", out);
572
 
    else
573
 
      fputc (*v, out);
574
 
  }
575
 
}
576
 
 
577
 
static void sgml_print_strval (const char *v, FILE *out)
578
 
{
579
 
  char buff[16];
580
 
  for (; *v; v++)
581
 
  {
582
 
    if (*v <  ' ' || *v & 0x80)
583
 
    {
584
 
      char_to_escape (buff, (unsigned int) *v);
585
 
      sgml_fputs (buff, out);
586
 
      continue;
587
 
    }
588
 
    sgml_fputc ((unsigned int) *v, out);
589
 
  }
590
 
}
591
 
 
592
 
static int sgml_fputc (int c, FILE *out)
593
 
{
594
 
  switch (c)
595
 
  {
596
 
    case '<': return fputs ("&lt;", out);
597
 
    case '>': return fputs ("&gt;", out);
598
 
    case '$': return fputs ("&dollar;", out);
599
 
    case '_': return fputs ("&lowbar;", out);
600
 
    case '%': return fputs ("&percnt;", out);
601
 
    case '&': return fputs ("&amp;", out);
602
 
    case '\\': return fputs ("&bsol;", out);
603
 
    case '"': return fputs ("&quot;", out);
604
 
    case '[': return fputs ("&lsqb;", out);
605
 
    case ']': return fputs ("&rsqb;", out);
606
 
    case '~': return fputs ("&tilde;", out);
607
 
    default:  return fputc (c, out);
608
 
  }
609
 
}
610
 
 
611
 
static int sgml_fputs (const char *s, FILE *out)
612
 
{
613
 
  for (; *s; s++)
614
 
    if (sgml_fputc ((unsigned int) *s, out) == EOF)
615
 
      return EOF;
616
 
  
617
 
  return 0;
618
 
}
619
 
 
620
 
/* reduce CDATA to ID */
621
 
static int sgml_id_fputs (const char *s, FILE* out)
622
 
{
623
 
  char id;
624
 
 
625
 
  for (; *s; s++)
626
 
  {
627
 
    if (*s == '_')
628
 
      id = '-';
629
 
    else
630
 
      id = *s;
631
 
 
632
 
    if (fputc ((unsigned int) id, out) == EOF)
633
 
      return EOF;
634
 
  }
635
 
 
636
 
  return 0;
637
 
}
638
 
 
639
 
static void print_confline (const char *varname, int type, const char *val, FILE *out)
640
 
{
641
 
  if (type == DT_SYN) return;
642
 
  
643
 
  switch (OutputFormat)
644
 
  {
645
 
    /* configuration file */
646
 
    case F_CONF:
647
 
    {
648
 
      if (type == DT_STR || type == DT_RX || type == DT_ADDR || type == DT_PATH)
649
 
      {
650
 
        fprintf (out, "\n# set %s=\"", varname);
651
 
        conf_print_strval (val, out);
652
 
        fputs ("\"", out);
653
 
      }
654
 
      else if (type != DT_SYN)
655
 
        fprintf (out, "\n# set %s=%s", varname, val);
656
 
      
657
 
      fprintf (out, "\n#\n# Name: %s", varname);
658
 
      fprintf (out, "\n# Type: %s", type2human (type));
659
 
      if (type == DT_STR || type == DT_RX || type == DT_ADDR || type == DT_PATH)
660
 
      {
661
 
        fputs ("\n# Default: \"", out);
662
 
        conf_print_strval (val, out);
663
 
        fputs ("\"", out);
664
 
      }
665
 
      else
666
 
        fprintf (out, "\n# Default: %s", val);
667
 
 
668
 
      fputs ("\n# ", out);
669
 
      break;
670
 
    }
671
 
 
672
 
    /* manual page */
673
 
    case F_MAN:
674
 
    {
675
 
      fprintf (out, "\n.TP\n.B %s\n", varname);
676
 
      fputs (".nf\n", out);
677
 
      fprintf (out, "Type: %s\n", type2human (type));
678
 
      if (type == DT_STR || type == DT_RX || type == DT_ADDR || type == DT_PATH)
679
 
      {
680
 
        fputs ("Default: \\(lq", out);
681
 
        man_print_strval (val, out);
682
 
        fputs ("\\(rq\n", out);
683
 
      }
684
 
      else
685
 
        fprintf (out, "Default: %s\n", val);
686
 
 
687
 
      fputs (".fi", out);
688
 
 
689
 
      break;
690
 
    }
691
 
    
692
 
    /* SGML based manual */
693
 
    case F_SGML:
694
 
    {
695
 
      fputs ("\n<sect2 id=\"", out);
696
 
      sgml_id_fputs(varname, out);
697
 
      fputs ("\">\n<title>", out);
698
 
      sgml_fputs (varname, out);
699
 
      fprintf (out, "</title>\n<literallayout>Type: %s", type2human (type));
700
 
      
701
 
      if (type == DT_STR || type == DT_RX || type == DT_ADDR || type == DT_PATH)
702
 
      {
703
 
        fputs ("\nDefault: &quot;", out);
704
 
        sgml_print_strval (val, out);
705
 
        fputs ("&quot;</literallayout>\n", out);
706
 
      }
707
 
      else
708
 
        fprintf (out, "\nDefault: %s</literallayout>\n", val);
709
 
      break;
710
 
    }
711
 
    /* make gcc happy */
712
 
    default:
713
 
      break;
714
 
  }
715
 
}
716
 
 
717
 
/**
718
 
 ** Documentation line parser
719
 
 **
720
 
 ** The following code parses specially formatted documentation 
721
 
 ** comments in init.h.
722
 
 **
723
 
 ** The format is very remotely inspired by nroff. Most important, it's
724
 
 ** easy to parse and convert, and it was easy to generate from the SGML 
725
 
 ** source of mutt's original manual.
726
 
 **
727
 
 ** - \fI switches to italics
728
 
 ** - \fB switches to boldface
729
 
 ** - \fP switches to normal display
730
 
 ** - .dl on a line starts a definition list (name taken taken from HTML).
731
 
 ** - .dt starts a term in a definition list.
732
 
 ** - .dd starts a definition in a definition list.
733
 
 ** - .de on a line finishes a definition list.
734
 
 ** - .ts on a line starts a "tscreen" environment (name taken from SGML).
735
 
 ** - .te on a line finishes this environment.
736
 
 ** - .pp on a line starts a paragraph.
737
 
 ** - \$word will be converted to a reference to word, where appropriate.
738
 
 **   Note that \$$word is possible as well.
739
 
 ** - '. ' in the beginning of a line expands to two space characters.
740
 
 **   This is used to protect indentations in tables.
741
 
 **/
742
 
 
743
 
/* close eventually-open environments. */
744
 
 
745
 
static int fd_recurse = 0;
746
 
 
747
 
static int flush_doc (int docstat, FILE *out)
748
 
{
749
 
  if (docstat & D_INIT)
750
 
    return D_INIT;
751
 
 
752
 
  if (fd_recurse++)
753
 
  {
754
 
    fprintf (stderr, "%s: Internal error, recursion in flush_doc()!\n", Progname);
755
 
    exit (1);
756
 
  }
757
 
 
758
 
  if (docstat & (D_PA))
759
 
    docstat = print_it (SP_END_PAR, NULL, out, docstat);
760
 
 
761
 
  if (docstat & (D_TAB))
762
 
    docstat = print_it (SP_END_TAB, NULL, out, docstat);
763
 
 
764
 
  if (docstat & (D_DL))
765
 
    docstat = print_it (SP_END_DL, NULL, out, docstat);
766
 
 
767
 
  if (docstat & (D_EM | D_BF))
768
 
    docstat = print_it (SP_END_FT, NULL, out, docstat);
769
 
 
770
 
  docstat = print_it (SP_END_SECT, NULL, out, docstat);
771
 
 
772
 
  docstat = print_it (SP_NEWLINE, NULL, out, 0);
773
 
 
774
 
  fd_recurse--;
775
 
  return D_INIT;
776
 
}
777
 
 
778
 
/* print something. */
779
 
 
780
 
static int print_it (int special, char *str, FILE *out, int docstat)
781
 
{
782
 
  int onl = docstat & (D_NL|D_NP);
783
 
  
784
 
  docstat &= ~(D_NL|D_NP|D_INIT);
785
 
 
786
 
  switch (OutputFormat)
787
 
  {
788
 
    /* configuration file */
789
 
    case F_CONF:
790
 
    {
791
 
      switch (special)
792
 
      {
793
 
        static int Continuation = 0;
794
 
 
795
 
        case SP_END_FT: docstat &= ~(D_EM|D_BF); break;
796
 
        case SP_START_BF: docstat |= D_BF; break;
797
 
        case SP_START_EM: docstat |= D_EM; break;
798
 
        case SP_NEWLINE: 
799
 
        {
800
 
          if (onl)
801
 
            docstat |= onl;
802
 
          else
803
 
          {
804
 
            fputs ("\n# ", out);
805
 
            docstat |= D_NL;
806
 
          }
807
 
          if (docstat & D_DL)
808
 
            ++ Continuation;
809
 
          break;
810
 
        }
811
 
        case SP_NEWPAR:
812
 
        {
813
 
          if (onl & D_NP)
814
 
          {
815
 
            docstat |= onl;
816
 
            break;
817
 
          }
818
 
 
819
 
          if (!(onl & D_NL))
820
 
            fputs ("\n# ", out);
821
 
          fputs ("\n# ", out);
822
 
          docstat |= D_NP;
823
 
          break;
824
 
        }
825
 
        case SP_START_TAB: 
826
 
        {
827
 
          if (!onl) 
828
 
            fputs ("\n# ", out);
829
 
          docstat |= D_TAB;
830
 
          break;
831
 
        }
832
 
        case SP_END_TAB:
833
 
        {
834
 
          docstat &= ~D_TAB;
835
 
          docstat |= D_NL;
836
 
          break;
837
 
        }
838
 
        case SP_START_DL:
839
 
        {
840
 
          docstat |= D_DL;
841
 
          break;
842
 
        }
843
 
        case SP_DT:
844
 
        {
845
 
          Continuation = 0;
846
 
          docstat |= D_DT;
847
 
          break;
848
 
        }
849
 
        case SP_DD:
850
 
        {
851
 
          Continuation = 0;
852
 
          break;
853
 
        }
854
 
        case SP_END_DL:
855
 
        {
856
 
          Continuation = 0;
857
 
          docstat &= ~D_DL;
858
 
          break;
859
 
        }
860
 
        case SP_STR:
861
 
        {
862
 
          if (Continuation)
863
 
          {
864
 
            Continuation = 0;
865
 
            fputs ("        ", out);
866
 
          }
867
 
          fputs (str, out);
868
 
          if (docstat & D_DT)
869
 
          { 
870
 
            int i;
871
 
 
872
 
            for (i = strlen (str) ; i < 8 ; i++)
873
 
              putc (' ', out);
874
 
            docstat &= ~D_DT;
875
 
            docstat |= D_NL;
876
 
          }
877
 
          break;
878
 
        }
879
 
      }
880
 
      break;
881
 
    }
882
 
 
883
 
    /* manual page */
884
 
    case F_MAN:
885
 
    {
886
 
      switch (special)
887
 
      {
888
 
        case SP_END_FT: 
889
 
        {
890
 
          fputs ("\\fP", out);
891
 
          docstat &= ~(D_EM|D_BF);
892
 
          break;
893
 
        }
894
 
        case SP_START_BF: 
895
 
        {
896
 
          fputs ("\\fB", out);
897
 
          docstat |= D_BF;
898
 
          docstat &= ~D_EM;
899
 
          break;
900
 
        }
901
 
        case SP_START_EM:
902
 
        {
903
 
          fputs ("\\fI", out);
904
 
          docstat |= D_EM;
905
 
          docstat &= ~D_BF;
906
 
          break;
907
 
        }
908
 
        case SP_NEWLINE:
909
 
        {
910
 
          if (onl)
911
 
            docstat |= onl;
912
 
          else
913
 
          {
914
 
            fputc ('\n', out);
915
 
            docstat |= D_NL;
916
 
          }
917
 
          break;
918
 
        }
919
 
        case SP_NEWPAR:
920
 
        {
921
 
          if (onl & D_NP)
922
 
          {
923
 
            docstat |= onl;
924
 
            break;
925
 
          }
926
 
 
927
 
          if (!(onl & D_NL))
928
 
            fputc ('\n', out);
929
 
          fputs (".IP\n", out);
930
 
 
931
 
          docstat |= D_NP;
932
 
          break;
933
 
        }
934
 
        case SP_START_TAB:
935
 
        {
936
 
          fputs ("\n.IP\n.DS\n.sp\n.ft CR\n.nf\n", out);
937
 
          docstat |= D_TAB | D_NL;
938
 
          break;
939
 
        }
940
 
        case SP_END_TAB:
941
 
        {
942
 
          fputs ("\n.fi\n.ec\n.ft P\n.sp\n", out);
943
 
          docstat &= ~D_TAB;
944
 
          docstat |= D_NL;
945
 
          break;
946
 
        }
947
 
        case SP_START_DL:
948
 
        {
949
 
          fputs ("\n.RS", out);
950
 
          docstat |= D_DL;
951
 
          break;
952
 
        }
953
 
        case SP_DT:
954
 
        {
955
 
          fputs ("\n.IP ", out);
956
 
          break;
957
 
        }
958
 
        case SP_DD:
959
 
        {
960
 
          fputs ("\n", out);
961
 
          break;
962
 
        }
963
 
        case SP_END_DL:
964
 
        {
965
 
          fputs ("\n.RE", out);
966
 
          docstat &= ~D_DL;
967
 
          break;
968
 
        }
969
 
        case SP_STR:
970
 
        {
971
 
          while (*str)
972
 
          {
973
 
            for (; *str; str++)
974
 
            {
975
 
              if (*str == '"')
976
 
                fputs ("\\(rq", out);
977
 
              else if (*str == '\\')
978
 
                fputs ("\\\\", out);
979
 
              else if (!strncmp (str, "``", 2))
980
 
              {
981
 
                fputs ("\\(lq", out);
982
 
                str++;
983
 
              }
984
 
              else if (!strncmp (str, "''", 2))
985
 
              {
986
 
                fputs ("\\(rq", out);
987
 
                str++;
988
 
              }
989
 
              else
990
 
                fputc (*str, out);
991
 
            }
992
 
          }
993
 
          break;
994
 
        }
995
 
      }
996
 
      break;
997
 
    }
998
 
 
999
 
    /* SGML based manual */
1000
 
    case F_SGML:
1001
 
    {
1002
 
      switch (special)
1003
 
      {
1004
 
        case SP_END_FT: 
1005
 
        {
1006
 
          if (docstat & D_EM) fputs ("</emphasis>", out);
1007
 
          if (docstat & D_BF) fputs ("</emphasis>", out);
1008
 
          docstat &= ~(D_EM|D_BF);
1009
 
          break;
1010
 
        }
1011
 
        case SP_START_BF: 
1012
 
        {
1013
 
          fputs ("<emphasis role=\"bold\">", out);
1014
 
          docstat |= D_BF;
1015
 
          docstat &= ~D_EM;
1016
 
          break;
1017
 
        }
1018
 
        case SP_START_EM:
1019
 
        {
1020
 
          fputs ("<emphasis>", out);
1021
 
          docstat |= D_EM;
1022
 
          docstat &= ~D_BF;
1023
 
          break;
1024
 
        }
1025
 
        case SP_NEWLINE:
1026
 
        {
1027
 
          if (onl)
1028
 
            docstat |= onl;
1029
 
          else
1030
 
          {
1031
 
            fputc ('\n', out);
1032
 
            docstat |= D_NL;
1033
 
          }
1034
 
          break;
1035
 
        }
1036
 
        case SP_NEWPAR:
1037
 
        {
1038
 
          if (onl & D_NP)
1039
 
          {
1040
 
            docstat |= onl;
1041
 
            break;
1042
 
          }
1043
 
 
1044
 
          if (!(onl & D_NL))
1045
 
            fputc ('\n', out);
1046
 
          if (docstat & D_PA)
1047
 
            fputs("</para>\n", out);
1048
 
          fputs ("<para>\n", out);
1049
 
 
1050
 
          docstat |= D_NP;
1051
 
          docstat |= D_PA;
1052
 
 
1053
 
          break;
1054
 
        }
1055
 
        case SP_END_PAR:
1056
 
        {
1057
 
          fputs ("</para>\n", out);
1058
 
          docstat &= ~D_PA;
1059
 
          break;
1060
 
        }
1061
 
        case SP_START_TAB:
1062
 
        {
1063
 
          fputs ("\n<screen>\n", out);
1064
 
          docstat |= D_TAB | D_NL;
1065
 
          break;
1066
 
        }
1067
 
        case SP_END_TAB:
1068
 
        {
1069
 
          fputs ("\n</screen>", out);
1070
 
          docstat &= ~D_TAB;
1071
 
          docstat |= D_NL;
1072
 
          break;
1073
 
        }
1074
 
        case SP_START_DL:
1075
 
        {
1076
 
          fputs ("\n<variablelist>\n", out);
1077
 
          docstat |= D_DL;
1078
 
          break;
1079
 
        }
1080
 
        case SP_DT:
1081
 
        {
1082
 
          fputs ("<varlistentry><term>", out);
1083
 
          break;
1084
 
        }
1085
 
        case SP_DD:
1086
 
        {
1087
 
          docstat |= D_DD;
1088
 
          fputs ("</term>\n<listitem><para>", out);
1089
 
          break;
1090
 
        }
1091
 
        case SP_END_DD:
1092
 
        {
1093
 
          docstat &= ~D_DD;
1094
 
          fputs ("</para></listitem></varlistentry>\n", out);
1095
 
          break;
1096
 
        }
1097
 
        case SP_END_DL:
1098
 
        {
1099
 
          fputs ("</para></listitem></varlistentry></variablelist>\n", out);
1100
 
          docstat &= ~(D_DD|D_DL);
1101
 
          break;
1102
 
        }
1103
 
        case SP_END_SECT:
1104
 
        {
1105
 
          fputs ("</sect2>", out);
1106
 
          break;
1107
 
        }
1108
 
        case SP_STR:
1109
 
        {
1110
 
          if (docstat & D_TAB)
1111
 
            fputs (str, out);
1112
 
          else
1113
 
            sgml_fputs (str, out);
1114
 
          break;
1115
 
        }
1116
 
      }
1117
 
      break;
1118
 
    }
1119
 
    /* make gcc happy (unreached) */
1120
 
    default:
1121
 
      break;
1122
 
  }
1123
 
 
1124
 
  return docstat;
1125
 
}
1126
 
 
1127
 
void print_ref (FILE *out, int output_dollar, const char *ref)
1128
 
{
1129
 
  switch (OutputFormat)
1130
 
  {
1131
 
  case F_CONF:
1132
 
  case F_MAN:
1133
 
    if (output_dollar)
1134
 
      putc ('$', out);
1135
 
    fputs (ref, out);
1136
 
    break;
1137
 
 
1138
 
  case F_SGML:
1139
 
    fputs ("<link linkend=\"", out);
1140
 
    sgml_id_fputs (ref, out);
1141
 
    fputs ("\">", out);
1142
 
    if (output_dollar)
1143
 
      fputs ("&dollar;", out);
1144
 
    sgml_fputs (ref, out);
1145
 
    fputs ("</link>", out);
1146
 
    break;
1147
 
 
1148
 
  default:
1149
 
    break;
1150
 
  }
1151
 
}
1152
 
 
1153
 
static int commit_buff (char *buff, char **d, FILE *out, int docstat)
1154
 
{
1155
 
  if (*d > buff)
1156
 
  {
1157
 
    **d = '\0';
1158
 
    docstat = print_it (SP_STR, buff, out, docstat);
1159
 
    *d = buff;
1160
 
  }
1161
 
 
1162
 
  return docstat;
1163
 
}
1164
 
 
1165
 
static int handle_docline (char *l, FILE *out, int docstat)
1166
 
{
1167
 
  char buff[BUFFSIZE];
1168
 
  char *s, *d;
1169
 
  l = skip_ws (l);
1170
 
 
1171
 
  if (Debug)
1172
 
    fprintf (stderr, "%s: handle_docline `%s'\n", Progname, l);
1173
 
  
1174
 
  if (!strncmp (l, ".pp", 3))
1175
 
    return print_it (SP_NEWPAR, NULL, out, docstat);
1176
 
  else if (!strncmp (l, ".ts", 3))
1177
 
    return print_it (SP_START_TAB, NULL, out, docstat);
1178
 
  else if (!strncmp (l, ".te", 3))
1179
 
    return print_it (SP_END_TAB, NULL, out, docstat);
1180
 
  else if (!strncmp (l, ".dl", 3))
1181
 
    return print_it (SP_START_DL, NULL, out, docstat);
1182
 
  else if (!strncmp (l, ".de", 3))
1183
 
    return print_it (SP_END_DL, NULL, out, docstat);
1184
 
  else if (!strncmp (l, ". ", 2))
1185
 
    *l = ' ';
1186
 
 
1187
 
  for (s = l, d = buff; *s; s++)
1188
 
  {
1189
 
    if (!strncmp (s, "\\(as", 4))
1190
 
    {
1191
 
      *d++ = '*';
1192
 
      s += 3;
1193
 
    }
1194
 
    else if (!strncmp (s, "\\(rs", 4))
1195
 
    {
1196
 
      *d++ = '\\';
1197
 
      s += 3;
1198
 
    }
1199
 
    else if (!strncmp (s, "\\fI", 3))
1200
 
    {
1201
 
      docstat = commit_buff (buff, &d, out, docstat);
1202
 
      docstat = print_it (SP_START_EM, NULL, out, docstat);
1203
 
      s += 2;
1204
 
    }
1205
 
    else if (!strncmp (s, "\\fB", 3))
1206
 
    {
1207
 
      docstat = commit_buff (buff, &d, out, docstat);
1208
 
      docstat = print_it (SP_START_BF, NULL, out, docstat);
1209
 
      s += 2;
1210
 
    }
1211
 
    else if (!strncmp (s, "\\fP", 3))
1212
 
    {
1213
 
      docstat = commit_buff (buff, &d, out, docstat);
1214
 
      docstat = print_it (SP_END_FT, NULL, out, docstat);
1215
 
      s += 2;
1216
 
    }
1217
 
    else if (!strncmp (s, ".dt", 3))
1218
 
    {
1219
 
      if (docstat & D_DD)
1220
 
      {
1221
 
        docstat = commit_buff (buff, &d, out, docstat);
1222
 
        docstat = print_it (SP_END_DD, NULL, out, docstat);
1223
 
      }
1224
 
      docstat = commit_buff (buff, &d, out, docstat);
1225
 
      docstat = print_it (SP_DT, NULL, out, docstat);
1226
 
      s += 3;
1227
 
    }
1228
 
    else if (!strncmp (s, ".dd", 3))
1229
 
    {
1230
 
      docstat = commit_buff (buff, &d, out, docstat);
1231
 
      docstat = print_it (SP_DD, NULL, out, docstat);
1232
 
      s += 3;
1233
 
    }
1234
 
    else if (*s == '$')
1235
 
    {
1236
 
      int output_dollar = 0;
1237
 
      char *ref;
1238
 
      char save;
1239
 
 
1240
 
      ++s;
1241
 
      if (*s == '$')
1242
 
      {
1243
 
        output_dollar = 1;
1244
 
        ++s;
1245
 
      }
1246
 
      if (*s == '$')
1247
 
      {
1248
 
        *d++ = '$';
1249
 
      }
1250
 
      else
1251
 
      {
1252
 
        ref = s;
1253
 
        while (isalnum ((unsigned char) *s) || *s == '-' || *s == '_')
1254
 
          ++s;
1255
 
 
1256
 
        docstat = commit_buff (buff, &d, out, docstat);
1257
 
        save = *s;
1258
 
        *s = 0;
1259
 
        print_ref (out, output_dollar, ref);
1260
 
        *s = save;
1261
 
        --s;
1262
 
      }
1263
 
    }
1264
 
    else
1265
 
      *d++ = *s;
1266
 
  }
1267
 
 
1268
 
  docstat = commit_buff (buff, &d, out, docstat);
1269
 
  return print_it (SP_NEWLINE, NULL, out, docstat);
1270
 
}