~ubuntu-branches/ubuntu/maverick/texinfo/maverick

« back to all changes in this revision

Viewing changes to makeinfo/toc.c

  • Committer: Bazaar Package Importer
  • Author(s): Norbert Preining
  • Date: 2005-10-28 15:10:30 UTC
  • mto: (2.1.1 dapper) (3.1.4 hardy)
  • mto: This revision was merged to the branch mainline in revision 3.
  • Revision ID: james.westby@ubuntu.com-20051028151030-9nsf2s2k2z3fktjt
Tags: upstream-4.8
ImportĀ upstreamĀ versionĀ 4.8

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/* toc.c -- table of contents handling.
2
 
   $Id: toc.c,v 1.21 2002/02/23 19:12:15 karl Exp $
 
2
   $Id: toc.c,v 1.6 2004/04/11 17:56:47 karl Exp $
3
3
 
4
 
   Copyright (C) 1999, 2000, 01, 02 Free Software Foundation, Inc.
 
4
   Copyright (C) 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
5
5
 
6
6
   This program is free software; you can redistribute it and/or modify
7
7
   it under the terms of the GNU General Public License as published by
17
17
   along with this program; if not, write to the Free Software
18
18
   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19
19
 
20
 
   Written by Karl Heinz Marbaise <kama@hippo.fido.de>.  */
 
20
   Originally written by Karl Heinz Marbaise <kama@hippo.fido.de>.  */
21
21
 
22
22
#include "system.h"
23
23
#include "makeinfo.h"
30
30
#include "makeinfo.h"
31
31
#include "sectioning.h"
32
32
#include "toc.h"
33
 
 
34
 
 
35
 
 
 
33
#include "xml.h"
 
34
 
36
35
/* array of toc entries */
37
36
static TOC_ENTRY_ELT **toc_entry_alist = NULL;
38
37
 
39
38
/* toc_counter start from 0 ... n for every @chapter, @section ... */
40
39
static int toc_counter = 0;
41
 
 
42
 
/* the file where we found the @contents directive */
43
 
char *contents_filename;
44
 
 
45
 
/* the file where we found the @shortcontents directive */
46
 
char *shortcontents_filename;
47
 
 
48
 
static const char contents_placebo[] = "\n...Table of Contents...\n";
49
 
static const char shortcontents_placebo[] = "\n...Short Contents...\n";
50
 
static const char lots_of_stars[] =
51
 
"***************************************************************************";
52
 
 
53
40
 
54
41
/* Routine to add an entry to the table of contents */
55
42
int
56
 
toc_add_entry (tocname, level, node_name, anchor)
57
 
     char *tocname;
58
 
     int level;
59
 
     char *node_name;
60
 
     char *anchor;
 
43
toc_add_entry (char *tocname, int level, char *node_name, char *anchor)
61
44
{
62
 
  char *tocname_and_node, *expanded_node, *s, *d;
 
45
  char *tocname_and_node, *expanded_node, *d;
 
46
  char *s = NULL;
63
47
  char *filename = NULL;
64
48
 
65
49
  if (!node_name)
74
58
 
75
59
  if (html)
76
60
    {
77
 
      /* We need to insert the expanded node name into the TOC, so
78
 
         that when we eventually output the TOC, its <A REF= link will
79
 
         point to the <A NAME= tag created by cm_node in the navigation
 
61
      /* We need to insert the expanded node name into the toc, so
 
62
         that when we eventually output the toc, its <a ref= link will
 
63
         point to the <a name= tag created by cm_node in the navigation
80
64
         bar.  We cannot expand the containing_node member, for the
81
65
         reasons explained in the WARNING below.  We also cannot wait
82
 
         with the node name expansion until the TOC is actually output,
 
66
         with the node name expansion until the toc is actually output,
83
67
         since by that time the macro definitions may have been changed.
84
68
         So instead we store in the tocname member the expanded node
85
 
         name and the TOC name concatenated together (with the necessary
86
 
         HTML markup), since that's how they are output.  */
 
69
         name and the toc name concatenated together (with the necessary
 
70
         html markup), since that's how they are output.  */
87
71
      if (!anchor)
88
72
        s = expanded_node = expand_node_name (node_name);
89
73
      else
107
91
        {
108
92
          for (; *s; s++)
109
93
            {
110
 
              if (*s == '&')
111
 
                {
112
 
                  strcpy (d, "&amp;");
113
 
                  d += 5;
114
 
                }
 
94
              if (cr_or_whitespace (*s))
 
95
                *d++ = '-';
115
96
              else if (! URL_SAFE_CHAR (*s))
116
97
                {
117
 
                  sprintf (d, "%%%x", (unsigned char) *s);
 
98
                  sprintf (d, "_00%x", (unsigned char) *s);
118
99
                  /* do this manually since sprintf returns char * on
119
100
                     SunOS 4 and other old systems.  */
120
101
                  while (*d)
165
146
   more than a single chapter structioning command in a node,
166
147
   or if they have a node without any structuring commands.  */
167
148
char *
168
 
toc_find_section_of_node (node)
169
 
     char *node;
 
149
toc_find_section_of_node (char *node)
170
150
{
171
151
  int i;
172
152
 
181
161
 
182
162
/* free up memory used by toc entries */
183
163
void
184
 
toc_free ()
 
164
toc_free (void)
185
165
{
186
166
  int i;
187
167
 
199
179
      toc_counter = 0; /* to be absolutley sure ;-) */
200
180
    }
201
181
}
202
 
 
203
182
 
204
183
/* Print table of contents in HTML.  */
205
184
 
206
185
static void
207
 
contents_update_html (fp)
208
 
     FILE *fp;
 
186
contents_update_html (void)
209
187
{
210
188
  int i;
211
189
  int k;
216
194
      /* no, so return to sender ;-) */
217
195
      return;
218
196
 
219
 
  flush_output ();      /* in case we are writing stdout */
220
 
 
221
 
  fprintf (fp, "\n<h2>%s</h2>\n<ul>\n", _("Table of Contents"));
 
197
  add_html_block_elt_args ("\n<div class=\"contents\">\n<h2>%s</h2>\n<ul>\n", _("Table of Contents"));
222
198
 
223
199
  last_level = toc_entry_alist[0]->level;
224
200
 
230
206
             @chapter ...
231
207
             @subsubsection ...      ? */
232
208
          for (k = 0; k < (toc_entry_alist[i]->level-last_level); k++)
233
 
            fputs ("<ul>\n", fp);
 
209
            add_html_block_elt ("<ul>\n");
234
210
        }
235
211
      else if (toc_entry_alist[i]->level < last_level)
236
212
        {
237
213
          /* @subsubsection ...
238
214
             @chapter ... this IS usual.*/
239
215
          for (k = 0; k < (last_level-toc_entry_alist[i]->level); k++)
240
 
            fputs ("</ul>\n", fp);
 
216
            add_word ("</li></ul>\n");
241
217
        }
242
218
 
243
219
      /* No double entries in TOC.  */
245
221
                         toc_entry_alist[i-1]->name) == 0))
246
222
        {
247
223
          /* each toc entry is a list item.  */
248
 
          fputs ("<li>", fp);
 
224
          add_word ("<li>");
249
225
 
 
226
          /* Insert link -- to an external file if splitting, or
 
227
             within the current document if not splitting.  */
 
228
          add_word ("<a ");
250
229
          /* For chapters (only), insert an anchor that the short contents
251
230
             will link to.  */
252
231
          if (toc_entry_alist[i]->level == 0)
259
238
                 ends, and use that in toc_FOO.  */
260
239
              while (*p && *p != '"')
261
240
                p++;
262
 
              fprintf (fp, "<a name=\"toc_%.*s\"></a>\n    ",
 
241
              add_word_args ("name=\"toc_%.*s\" ",
263
242
                       p - toc_entry_alist[i]->name, toc_entry_alist[i]->name);
264
243
            }
265
 
 
266
 
          /* Insert link -- to an external file if splitting, or
267
 
             within the current document if not splitting.  */
268
 
          fprintf (fp, "<a href=\"%s#%s</a>\n",
 
244
          add_word_args ("href=\"%s#%s</a>\n",
269
245
                   splitting ? toc_entry_alist[i]->html_file : "",
270
246
                   toc_entry_alist[i]->name);
271
247
        }
276
252
  /* Go back to start level. */
277
253
  if (toc_entry_alist[0]->level < last_level)
278
254
    for (k = 0; k < (last_level-toc_entry_alist[0]->level); k++)
279
 
      fputs ("</ul>\n", fp);
 
255
      add_word ("</li></ul>\n");
280
256
 
281
 
  fputs ("</ul>\n\n", fp);
 
257
  add_word ("</li></ul>\n</div>\n\n");
282
258
}
283
259
 
284
260
/* print table of contents in ASCII (--no-headers)
285
261
   May be we should create a new command line switch --ascii ? */
286
262
static void
287
 
contents_update_info (fp)
288
 
     FILE *fp;
 
263
contents_update_info (void)
289
264
{
290
265
  int i;
291
266
  int k;
293
268
  if (!toc_counter)
294
269
      return;
295
270
 
296
 
  flush_output ();      /* in case we are writing stdout */
297
 
 
298
 
  fprintf (fp, "%s\n%.*s\n\n", _("Table of Contents"),
299
 
           (int) strlen (_("Table of Contents")), lots_of_stars);
 
271
  insert_string ((char *) _("Table of Contents"));
 
272
  insert ('\n');
 
273
  for (i = 0; i < strlen (_("Table of Contents")); i++)
 
274
    insert ('*');
 
275
  insert_string ("\n\n");
300
276
 
301
277
  for (i = 0; i < toc_counter; i++)
302
278
    {
303
279
      if (toc_entry_alist[i]->level == 0)
304
 
        fputs ("\n", fp);
 
280
        add_char ('\n');
305
281
 
306
282
      /* indention with two spaces per level, should this
307
283
         changed? */
308
284
      for (k = 0; k < toc_entry_alist[i]->level; k++)
309
 
        fputs ("  ", fp);
 
285
        insert_string ("  ");
310
286
 
311
 
      fprintf (fp, "%s\n", toc_entry_alist[i]->name);
 
287
      insert_string (toc_entry_alist[i]->name);
 
288
      insert ('\n');
312
289
    }
313
 
  fputs ("\n\n", fp);
 
290
  insert_string ("\n\n");
314
291
}
315
292
 
316
293
/* shortcontents in HTML; Should this produce a standalone file? */
317
294
static void
318
 
shortcontents_update_html (fp)
319
 
     FILE *fp;
 
295
shortcontents_update_html (char *contents_filename)
320
296
{
321
297
  int i;
322
 
  char *toc_file;
 
298
  char *toc_file = NULL;
323
299
 
324
300
  /* does exist any toc? */
325
301
  if (!toc_counter)
326
302
    return;
327
303
 
328
 
  flush_output ();      /* in case we are writing stdout */
329
 
 
330
 
  fprintf (fp, "\n<h2>%s</h2>\n<ul>\n", _("Short Contents"));
 
304
  add_html_block_elt_args ("\n<div class=\"shortcontents\">\n<h2>%s</h2>\n<ul>\n", _("Short Contents"));
331
305
 
332
306
  if (contents_filename)
333
307
    toc_file = filename_part (contents_filename);
339
313
      if (toc_entry_alist[i]->level == 0)
340
314
        {
341
315
          if (contents_filename)
342
 
            fprintf (fp, "<li><a href=\"%s#toc_%s</a>\n",
 
316
            add_word_args ("<li><a href=\"%s#toc_%s</a></li>\n",
343
317
                     splitting ? toc_file : "", name);
344
318
          else
345
 
            fprintf (fp, "<a href=\"%s#%s</a>\n",
 
319
            add_word_args ("<a href=\"%s#%s</a>\n",
346
320
                     splitting ? toc_entry_alist[i]->html_file : "", name);
347
321
        }
348
322
    }
349
 
  fputs ("</ul>\n\n", fp);
 
323
  add_word ("</ul>\n</div>\n\n");
350
324
  if (contents_filename)
351
325
    free (toc_file);
352
326
}
353
327
 
354
328
/* short contents in ASCII (--no-headers).  */
355
329
static void
356
 
shortcontents_update_info (fp)
357
 
     FILE *fp;
 
330
shortcontents_update_info (void)
358
331
{
359
332
  int i;
360
333
 
361
334
  if (!toc_counter)
362
335
      return;
363
336
 
364
 
  flush_output ();      /* in case we are writing stdout */
365
 
 
366
 
  fprintf (fp, "%s\n%.*s\n\n", _("Short Contents"),
367
 
           (int) strlen (_("Short Contents")), lots_of_stars);
 
337
  insert_string ((char *) _("Short Contents"));
 
338
  insert ('\n');
 
339
  for (i = 0; i < strlen (_("Short Contents")); i++)
 
340
    insert ('*');
 
341
  insert_string ("\n\n");
368
342
 
369
343
  for (i = 0; i < toc_counter; i++)
370
344
    {
371
345
      if (toc_entry_alist[i]->level == 0)
372
 
        fprintf (fp, "%s\n", toc_entry_alist[i]->name);
373
 
    }
374
 
  fputs ("\n\n", fp);
375
 
}
376
 
 
377
 
 
378
 
static FILE *toc_fp;
379
 
static char *toc_buf;
380
 
 
381
 
static int
382
 
rewrite_top (fname, placebo)
383
 
     const char *fname, *placebo;
384
 
{
385
 
  int idx;
386
 
 
387
 
  /* Can't rewrite standard output or the null device.  No point in
388
 
     complaining.  */
389
 
  if (STREQ (fname, "-")
390
 
      || FILENAME_CMP (fname, NULL_DEVICE) == 0
391
 
      || FILENAME_CMP (fname, ALSO_NULL_DEVICE) == 0)
392
 
    return -1;
393
 
 
394
 
  toc_buf = find_and_load (fname);
395
 
 
396
 
  if (!toc_buf)
397
 
    {
398
 
      fs_error (fname);
399
 
      return -1;
400
 
    }
401
 
 
402
 
  idx = search_forward (placebo, 0);
403
 
 
404
 
  if (idx < 0)
405
 
    {
406
 
      error (_("%s: TOC should be here, but it was not found"), fname);
407
 
      return -1;
408
 
    }
409
 
 
410
 
  toc_fp = fopen (fname, "w");
411
 
  if (!toc_fp)
412
 
    {
413
 
      fs_error (fname);
414
 
      return -1;
415
 
    }
416
 
 
417
 
  if (fwrite (toc_buf, 1, idx, toc_fp) != idx)
418
 
    {
419
 
      fs_error (fname);
420
 
      return -1;
421
 
    }
422
 
 
423
 
  return idx + strlen (placebo);
424
 
}
425
 
 
426
 
static void
427
 
contents_update ()
428
 
{
429
 
  int cont_idx = rewrite_top (contents_filename, contents_placebo);
430
 
 
431
 
  if (cont_idx < 0)
432
 
    return;
433
 
 
434
 
  if (html)
435
 
    contents_update_html (toc_fp);
436
 
  else
437
 
    contents_update_info (toc_fp);
438
 
 
439
 
  if (fwrite (toc_buf + cont_idx, 1, input_text_length - cont_idx, toc_fp)
440
 
      != input_text_length - cont_idx
441
 
      || fclose (toc_fp) != 0)
442
 
    fs_error (contents_filename);
443
 
}
444
 
 
445
 
static void
446
 
shortcontents_update ()
447
 
{
448
 
  int cont_idx = rewrite_top (shortcontents_filename, shortcontents_placebo);
449
 
 
450
 
  if (cont_idx < 0)
451
 
    return;
452
 
 
453
 
  if (html)
454
 
    shortcontents_update_html (toc_fp);
455
 
  else
456
 
    shortcontents_update_info (toc_fp);
457
 
 
458
 
  if (fwrite (toc_buf + cont_idx, 1, input_text_length - cont_idx - 1, toc_fp)
459
 
      != input_text_length - cont_idx - 1
460
 
      || fclose (toc_fp) != 0)
461
 
    fs_error (shortcontents_filename);
462
 
}
463
 
 
464
 
void
465
 
toc_update ()
466
 
{
467
 
  if (!html && !no_headers)
468
 
    return;
469
 
 
470
 
  if (contents_filename)
471
 
    contents_update ();
472
 
  if (shortcontents_filename)
473
 
    shortcontents_update ();
474
 
}
475
 
 
476
 
void
477
 
cm_contents (arg)
478
 
     int arg;
479
 
{
480
 
  if ((html || no_headers) && arg == START)
481
 
    {
482
 
      if (contents_filename)
483
 
        {
484
 
          free (contents_filename);
485
 
          contents_filename = NULL;
486
 
        }
487
 
 
488
 
      if (contents_filename && STREQ (contents_filename, "-"))
489
 
        {
490
 
          if (html)
491
 
            contents_update_html (stdout);
492
 
          else
493
 
            contents_update_info (stdout);
494
 
        }
495
 
      else
496
 
        {
497
 
          if (!executing_string && html)
498
 
            html_output_head ();
 
346
        {
 
347
          insert_string (toc_entry_alist[i]->name);
 
348
          insert ('\n');
 
349
        }
 
350
    }
 
351
  insert_string ("\n\n");
 
352
}
 
353
 
 
354
void
 
355
cm_contents (int arg)
 
356
{
 
357
  /* the file where we found the @contents directive */
 
358
  static char *contents_filename;
 
359
 
 
360
  /* No need to mess with delayed stuff for XML and Docbook.  */
 
361
  if (xml)
 
362
    {
 
363
      if (arg == START)
 
364
        {
 
365
          int elt = STREQ (command, "contents") ? CONTENTS : SHORTCONTENTS;
 
366
          xml_insert_element (elt, START);
 
367
          xml_insert_element (elt, END);
 
368
        }
 
369
    }
 
370
  else if (!handling_delayed_writes)
 
371
    {
 
372
      register_delayed_write (STREQ (command, "contents")
 
373
          ? "@contents" : "@shortcontents");
 
374
 
 
375
      if (html && STREQ (command, "contents"))
 
376
        {
 
377
          if (contents_filename)
 
378
            free (contents_filename);
499
379
          contents_filename = xstrdup (current_output_filename);
500
 
          insert_string (contents_placebo); /* just mark it, for now */
501
 
        }
502
 
    }
503
 
}
504
 
 
505
 
void
506
 
cm_shortcontents (arg)
507
 
     int arg;
508
 
{
509
 
  if ((html || no_headers) && arg == START)
510
 
    {
511
 
      if (shortcontents_filename)
512
 
        {
513
 
          free (shortcontents_filename);
514
 
          shortcontents_filename = NULL;
515
 
        }
516
 
 
517
 
      if (shortcontents_filename && STREQ (shortcontents_filename, "-"))
518
 
        {
519
 
          if (html)
520
 
            shortcontents_update_html (stdout);
521
 
          else
522
 
            shortcontents_update_info (stdout);
523
 
        }
524
 
      else
525
 
        {
526
 
          if (!executing_string && html)
527
 
            html_output_head ();
528
 
          shortcontents_filename = xstrdup (current_output_filename);
529
 
          insert_string (shortcontents_placebo); /* just mark it, for now */
530
 
        }
531
 
    }
 
380
        }
 
381
    }
 
382
  else if (html)
 
383
    STREQ (command, "contents")
 
384
      ? contents_update_html () : shortcontents_update_html (contents_filename);
 
385
  else if (no_headers)
 
386
    STREQ (command, "contents")
 
387
      ? contents_update_info () : shortcontents_update_info ();
532
388
}