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

« back to all changes in this revision

Viewing changes to makeinfo/node.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
/* node.c -- nodes for Texinfo.
2
 
   $Id: node.c,v 1.31 2002/02/23 19:12:15 karl Exp $
 
2
   $Id: node.c,v 1.27 2004/12/20 23:56:07 karl Exp $
3
3
 
4
 
   Copyright (C) 1998, 99, 2000, 01, 02 Free Software Foundation, Inc.
 
4
   Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software
 
5
   Foundation, Inc.
5
6
 
6
7
   This program is free software; you can redistribute it and/or modify
7
8
   it under the terms of the GNU General Public License as published by
20
21
#include "system.h"
21
22
#include "cmds.h"
22
23
#include "files.h"
 
24
#include "float.h"
23
25
#include "footnote.h"
24
26
#include "macro.h"
25
27
#include "makeinfo.h"
29
31
#include "insertion.h"
30
32
#include "xml.h"
31
33
 
32
 
 
33
34
/* See comments in node.h.  */
34
35
NODE_REF *node_references = NULL;
35
36
NODE_REF *node_node_references = NULL;
36
37
TAG_ENTRY *tag_table = NULL;
37
38
int node_number = -1;
 
39
int node_order = 0;
38
40
int current_section = 0;
39
41
int outstanding_node = 0;
40
42
 
42
44
 
43
45
/* Start a new tag table. */
44
46
void
45
 
init_tag_table ()
 
47
init_tag_table (void)
46
48
{
47
49
  while (tag_table)
48
50
    {
60
62
   INDIRECT_P says how to format the output (it depends on whether the
61
63
   table is direct or indirect).  */
62
64
static void
63
 
write_tag_table_internal (indirect_p)
64
 
     int indirect_p;
 
65
write_tag_table_internal (int indirect_p)
65
66
{
66
67
  TAG_ENTRY *node;
67
68
  int old_indent = no_indent;
111
112
}
112
113
 
113
114
void
114
 
write_tag_table ()
 
115
write_tag_table (char *filename)
115
116
{
 
117
  output_stream = fopen (filename, "a");
 
118
  if (!output_stream)
 
119
    {
 
120
      fs_error (filename);
 
121
      return;
 
122
    }
 
123
 
116
124
  write_tag_table_internal (0); /* Not indirect. */
 
125
 
 
126
  if (fclose (output_stream) != 0)
 
127
    fs_error (filename);
117
128
}
118
129
 
119
 
void
120
 
write_tag_table_indirect ()
 
130
static void
 
131
write_tag_table_indirect (void)
121
132
{
122
133
  write_tag_table_internal (1);
123
134
}
124
135
 
125
136
/* Convert "top" and friends into "Top". */
126
137
static void
127
 
normalize_node_name (string)
128
 
     char *string;
 
138
normalize_node_name (char *string)
129
139
{
130
140
  if (strcasecmp (string, "Top") == 0)
131
141
    strcpy (string, "Top");
132
142
}
133
143
 
134
 
char *
135
 
get_node_token (expand)
136
 
      int expand;
 
144
static char *
 
145
get_node_token (int expand)
137
146
{
138
147
  char *string;
139
148
 
153
162
/* Expand any macros and other directives in a node name, and
154
163
   return the expanded name as an malloc'ed string.  */
155
164
char *
156
 
expand_node_name (node)
157
 
     char *node;
 
165
expand_node_name (char *node)
158
166
{
159
167
  char *result = node;
160
168
 
174
182
/* Look up NAME in the tag table, and return the associated
175
183
   tag_entry.  If the node is not in the table return NULL. */
176
184
TAG_ENTRY *
177
 
find_node (name)
178
 
     char *name;
 
185
find_node (char *name)
179
186
{
180
187
  TAG_ENTRY *tag = tag_table;
181
188
  char *expanded_name;
222
229
/* Look in the tag table for a node whose file name is FNAME, and
223
230
   return the associated tag_entry.  If there's no such node in the
224
231
   table, return NULL. */
225
 
TAG_ENTRY *
226
 
find_node_by_fname (fname)
227
 
     char *fname;
 
232
static TAG_ENTRY *
 
233
find_node_by_fname (char *fname)
228
234
{
229
235
  TAG_ENTRY *tag = tag_table;
230
236
  while (tag)
240
246
/* Remember next, prev, etc. references in a @node command, where we
241
247
   don't care about most of the entries. */
242
248
static void
243
 
remember_node_node_reference (node)
244
 
     char *node;
 
249
remember_node_node_reference (char *node)
245
250
{
246
251
  NODE_REF *temp = xmalloc (sizeof (NODE_REF));
247
252
  int number;
262
267
}
263
268
 
264
269
/* Remember NODE and associates. */
265
 
void
266
 
remember_node (node, prev, next, up, position, line_no, fname, flags)
267
 
     char *node, *prev, *next, *up, *fname;
268
 
     int position, line_no, flags;
 
270
static void
 
271
remember_node (char *node, char *prev, char *next, char *up,
 
272
    int position, int line_no, char *fname, int flags)
269
273
{
270
274
  /* Check for existence of this tag already. */
271
275
  if (validating)
306
310
        node_number++;
307
311
        new->number = node_number;
308
312
      }
309
 
    new->html_fname = fname;
 
313
    if (fname)
 
314
      new->html_fname = fname;
 
315
    else
 
316
      /* This happens for Top node under split-HTML, for example.  */
 
317
      new->html_fname
 
318
        = normalize_filename (filename_part (current_output_filename));
310
319
    new->next_ent = tag_table;
 
320
 
 
321
    /* Increment the order counter, and save it.  */
 
322
    node_order++;
 
323
    new->order = node_order;
 
324
 
311
325
    tag_table = new;
312
326
  }
313
327
 
324
338
   output file has been written, if validation is on, then we use the
325
339
   contents of `node_references' as a list of nodes to validate.  */
326
340
void
327
 
remember_node_reference (node, line, type)
328
 
     char *node;
329
 
     int line;
330
 
     enum reftype type;
 
341
remember_node_reference (char *node, int line, enum reftype type)
331
342
{
332
343
  NODE_REF *temp = xmalloc (sizeof (NODE_REF));
333
344
  int number = number_of_node (node);
351
362
}
352
363
 
353
364
static void
354
 
isolate_nodename (nodename)
355
 
     char *nodename;
 
365
isolate_nodename (char *nodename)
356
366
{
357
367
  int i, c;
358
368
  int paren_seen, paren;
411
421
   just before the menu line.  If REMEMBER_REF is zero, REF_TYPE is unused.  */
412
422
#define MENU_STARTER "* "
413
423
char *
414
 
glean_node_from_menu (remember_ref, ref_type)
415
 
     int remember_ref;
416
 
     enum reftype ref_type;
 
424
glean_node_from_menu (int remember_ref, enum reftype ref_type)
417
425
{
418
426
  int i, orig_offset = input_text_offset;
419
427
  char *nodename;
467
475
 
468
476
/* Set the name of the current output file.  */
469
477
void
470
 
set_current_output_filename (fname)
471
 
     const char *fname;
 
478
set_current_output_filename (const char *fname)
472
479
{
473
480
  if (current_output_filename)
474
481
    free (current_output_filename);
475
482
  current_output_filename = xstrdup (fname);
476
483
}
477
484
 
 
485
 
 
486
/* Output the <a name="..."></a> constructs for NODE.  We output both
 
487
   the new-style conversion and the old-style, if they are different.
 
488
   See comments at `add_escaped_anchor_name' in html.c.  */
 
489
 
 
490
static void
 
491
add_html_names (char *node)
 
492
{
 
493
  char *tem = expand_node_name (node);
 
494
  char *otem = xstrdup (tem);
 
495
 
 
496
  /* Determine if the old and new schemes come up with different names;
 
497
     only output the old scheme if that is so.  We don't want to output
 
498
     the same name twice.  */
 
499
  canon_white (otem);
 
500
  {
 
501
    char *optr = otem;
 
502
    int need_old = 0;
 
503
    
 
504
    for (; *optr; optr++)
 
505
      {
 
506
        if (!cr_or_whitespace (*optr) && !URL_SAFE_CHAR (*optr))
 
507
          {
 
508
            need_old = 1;
 
509
            break;
 
510
          }
 
511
      }
 
512
    
 
513
    if (need_old)
 
514
      {
 
515
        add_word ("<a name=\"");
 
516
        add_anchor_name (otem, -1);  /* old anchor name conversion */
 
517
        add_word ("\"></a>\n");
 
518
      }
 
519
    free (otem);
 
520
  }
 
521
 
 
522
  /* Always output the new scheme.  */
 
523
  canon_white (tem);
 
524
  add_word ("<a name=\"");
 
525
  add_anchor_name (tem, 0);
 
526
  add_word ("\"></a>\n");
 
527
 
 
528
  free (tem);
 
529
}
 
530
 
 
531
 
478
532
/* The order is: nodename, nextnode, prevnode, upnode.
479
533
   If all of the NEXT, PREV, and UP fields are empty, they are defaulted.
480
534
   You must follow a node command which has those fields defaulted
481
 
   with a sectioning command (e.g. @chapter) giving the "level" of that node.
 
535
   with a sectioning command (e.g., @chapter) giving the "level" of that node.
482
536
   It is an error not to do so.
483
537
   The defaults come from the menu in this node's parent. */
484
538
void
485
 
cm_node ()
 
539
cm_node (void)
486
540
{
487
541
  static long epilogue_len = 0L;
488
542
  char *node, *prev, *next, *up;
504
558
 
505
559
  if (!html && !already_outputting_pending_notes)
506
560
    {
507
 
      if (!xml)
508
561
      close_paragraph ();
509
562
      output_pending_notes ();
510
563
    }
580
633
                epilogue_len = ftell (output_stream) - pos1;
581
634
              fclose (output_stream);
582
635
              output_stream = NULL;
 
636
              output_position = 0;
583
637
              tag = find_node_by_fname (fname_for_this_node);
584
638
            }
585
639
          free (fname_for_prev_node);
589
643
  filling_enabled = indented_fill = 0;
590
644
  if (!html || (html && splitting))
591
645
    current_footnote_number = 1;
592
 
  
 
646
 
593
647
  if (verbose_mode)
594
648
    printf (_("Formatting node %s...\n"), node);
595
649
 
596
650
  if (macro_expansion_output_stream && !executing_string)
597
651
    remember_itext (input_text, input_text_offset);
598
652
 
 
653
  /* Reset the line number in each node for Info output, so that
 
654
     index entries will save the line numbers of parent node.  */
 
655
  node_line_number = 0;
 
656
 
599
657
  no_indent = 1;
600
658
  if (xml)
601
659
    {
602
 
      xml_begin_document ();
 
660
      xml_begin_document (current_output_filename);
603
661
      xml_begin_node ();
604
662
      if (!docbook)
605
663
        {
606
 
          xml_insert_element (NODENAME, START);      
 
664
          xml_insert_element (NODENAME, START);
607
665
          if (macro_expansion_output_stream && !executing_string)
608
666
            me_execute_string (node);
609
667
          else
615
673
    }
616
674
  else if (!no_headers && !html)
617
675
    {
 
676
      /* Emacs Info reader cannot grok indented escape sequence.  */
 
677
      kill_self_indent (-1);
 
678
 
618
679
      add_word_args ("\037\nFile: %s,  Node: ", pretty_output_filename);
619
680
 
620
681
      if (macro_expansion_output_stream && !executing_string)
627
688
  /* Check for defaulting of this node's next, prev, and up fields. */
628
689
  defaulting = (*next == 0 && *prev == 0 && *up == 0);
629
690
 
630
 
  this_section = what_section (input_text + input_text_offset);
 
691
  this_section = what_section (input_text + input_text_offset, NULL);
631
692
 
632
693
  /* If we are defaulting, then look at the immediately following
633
694
     sectioning command (error if none) to determine the node's
652
713
              }
653
714
 
654
715
          line_error
655
 
            (_("Node `%s' requires a sectioning command (e.g. %c%s)"),
 
716
            (_("Node `%s' requires a sectioning command (e.g., %c%s)"),
656
717
             node, COMMAND_PREFIX, polite_section_name);
657
718
        }
658
719
      else
673
734
 
674
735
              int orig_offset, orig_size;
675
736
 
 
737
              int bye_offset = search_forward ("\n@bye", input_text_offset);
 
738
 
676
739
              /* No matter what, make this file point back at `(dir)'. */
677
740
              free (up);
678
741
              up = xstrdup ("(dir)"); /* html fixxme */
688
751
 
689
752
                  input_text_offset = search_forward ("\n@menu", orig_offset);
690
753
                  if (input_text_offset > -1
 
754
                      && (bye_offset > -1 && input_text_offset < bye_offset)
691
755
                      && cr_or_whitespace (input_text[input_text_offset + 6]))
692
756
                    {
693
757
                      char *nodename_from_menu = NULL;
905
969
        }
906
970
 
907
971
      if (!splitting && no_headers)
908
 
        { /* cross refs need a name="#anchor" even if we're not writing headers*/
909
 
          add_word ("<a name=\"");
910
 
          tem = expand_node_name (node);
911
 
          add_anchor_name (tem, 0);
912
 
          add_word ("\"></a>");
913
 
          free (tem);
 
972
        { /* cross refs need a name="#anchor" even if not writing headers */ 
 
973
          add_html_names (node);
914
974
        }
915
975
 
916
976
      if (splitting || !no_headers)
917
 
        { /* Navigation bar.   The <p> avoids the links area running
918
 
             on with old Lynxen.  */
 
977
        { /* Navigation bar. */
 
978
          add_html_block_elt ("<div class=\"node\">\n");
 
979
          /* The <p> avoids the links area running on with old Lynxen. */
919
980
          add_word_args ("<p>%s\n", splitting ? "" : "<hr>");
920
 
          add_word_args ("%s<a name=\"", _("Node:"));
921
 
          tem = expand_node_name (node);
922
 
          add_anchor_name (tem, 0);
923
 
          add_word_args ("\">%s</a>", tem);
924
 
          free (tem);
 
981
 
 
982
          /* In the split HTML case, the filename is wrong for the 
 
983
             old-style converted names, but we'll add them anyway, for
 
984
             consistency.  (And we need them in the normal (not
 
985
             no_headers) nonsplit case.)  */
 
986
          add_html_names (node);
925
987
 
926
988
          if (next)
927
989
            {
928
990
              tem = expansion (next, 0);
929
 
              add_word (",\n");
930
 
              add_word (_("Next:"));
931
 
              add_word ("<a rel=next href=\"");
 
991
              add_word ((char *) _("Next:"));
 
992
              add_word ("&nbsp;");
 
993
              
 
994
              add_word ("<a rel=\"next\" accesskey=\"n\" href=\"");
932
995
              add_anchor_name (tem, 1);
 
996
              tem = escape_string (tem);
933
997
              add_word_args ("\">%s</a>", tem);
 
998
              
934
999
              free (tem);
 
1000
 
 
1001
              if (prev || up)
 
1002
                add_word (",\n");
935
1003
            }
936
1004
          if (prev)
937
1005
            {
938
1006
              tem = expansion (prev, 0);
939
 
              add_word (",\n");
940
 
              add_word (_("Previous:"));
941
 
              add_word ("<a rel=previous href=\"");
 
1007
              add_word ((char *) _("Previous:"));
 
1008
              add_word ("&nbsp;");
 
1009
              add_word ("<a rel=\"previous\" accesskey=\"p\" href=\"");
942
1010
              add_anchor_name (tem, 1);
 
1011
              tem = escape_string (tem);
943
1012
              add_word_args ("\">%s</a>", tem);
944
1013
              free (tem);
 
1014
 
 
1015
              if (up)
 
1016
                add_word (",\n");
945
1017
            }
946
1018
          if (up)
947
1019
            {
948
1020
              tem = expansion (up, 0);
949
 
              add_word (",\n");
950
 
              add_word (_("Up:"));
951
 
              add_word ("<a rel=up href=\"");
 
1021
              add_word ((char *) _("Up:"));
 
1022
              add_word ("&nbsp;");
 
1023
              add_word ("<a rel=\"up\" accesskey=\"u\" href=\"");
952
1024
              add_anchor_name (tem, 1);
 
1025
              tem = escape_string (tem);
953
1026
              add_word_args ("\">%s</a>", tem);
954
1027
              free (tem);
955
1028
            }
956
1029
          /* html fixxme: we want a `top' or `contents' link here.  */
957
1030
 
958
 
          add_word_args ("\n%s<br>\n", splitting ? "<hr>" : "");
 
1031
          add_word_args ("\n%s\n", splitting ? "<hr>" : "");
 
1032
          add_word ("</div>\n");
959
1033
        }
960
1034
    }
961
1035
  else if (docbook)
971
1045
      if (prev)
972
1046
        {
973
1047
          xml_insert_element (NODEPREV, START);
974
 
          execute_string ("%s", prev);      
 
1048
          execute_string ("%s", prev);
975
1049
          xml_insert_element (NODEPREV, END);
976
1050
        }
977
1051
      if (up)
1022
1096
 
1023
1097
/* Cross-reference target at an arbitrary spot.  */
1024
1098
void
1025
 
cm_anchor (arg)
1026
 
     int arg;
 
1099
cm_anchor (int arg)
1027
1100
{
1028
1101
  char *anchor;
1029
1102
  char *fname_for_anchor = NULL;
1034
1107
  /* Parse the anchor text.  */
1035
1108
  anchor = get_xref_token (1);
1036
1109
 
 
1110
  /* Force all versions of "top" to be "Top". */
 
1111
  normalize_node_name (anchor);
 
1112
 
1037
1113
  /* In HTML mode, need to actually produce some output.  */
1038
1114
  if (html)
1039
1115
    {
1149
1225
      xml_insert_element (ANCHOR, END);
1150
1226
    }
1151
1227
  /* Save it in the tag table.  */
1152
 
  remember_node (anchor, NULL, NULL, NULL, output_position + output_column,
 
1228
  remember_node (anchor, NULL, NULL, NULL,
 
1229
                 output_position + output_paragraph_offset,
1153
1230
                 line_number, fname_for_anchor, TAG_FLAG_ANCHOR);
1154
1231
}
1155
1232
 
1156
1233
/* Find NODE in REF_LIST. */
1157
1234
static NODE_REF *
1158
 
find_node_reference (node, ref_list)
1159
 
     char *node;
1160
 
     NODE_REF *ref_list;
 
1235
find_node_reference (char *node, NODE_REF *ref_list)
1161
1236
{
1162
1237
  NODE_REF *orig_ref_list = ref_list;
1163
1238
  char *expanded_node;
1195
1270
}
1196
1271
 
1197
1272
void
1198
 
free_node_references ()
 
1273
free_node_references (void)
1199
1274
{
1200
1275
  NODE_REF *list, *temp;
1201
1276
 
1213
1288
}
1214
1289
 
1215
1290
void
1216
 
free_node_node_references ()
 
1291
free_node_node_references (void)
1217
1292
{
1218
1293
  NODE_REF *list, *temp;
1219
1294
 
1232
1307
/* Return the number assigned to a named node in either the tag_table
1233
1308
   or node_references list or zero if no number has been assigned. */
1234
1309
int
1235
 
number_of_node (node)
1236
 
     char *node;
 
1310
number_of_node (char *node)
1237
1311
{
1238
1312
  NODE_REF *temp_ref;
1239
1313
  TAG_ENTRY *temp_node = find_node (node);
1255
1329
   Menu, Cross, Next, etc.  */
1256
1330
 
1257
1331
static int
1258
 
validate (tag, line, label)
1259
 
     char *tag;
1260
 
     int line;
1261
 
     char *label;
 
1332
validate (char *tag, int line, const char *label)
1262
1333
{
1263
1334
  TAG_ENTRY *result;
1264
1335
 
1273
1344
  if (!result)
1274
1345
    {
1275
1346
      line_number = line;
1276
 
      line_error (_("%s reference to nonexistent node `%s'"), label, tag);
 
1347
      line_error (_("%s reference to nonexistent node `%s' (perhaps incorrect sectioning?)"), label, tag);
1277
1348
      return 0;
1278
1349
    }
1279
1350
  result->touched++;
1283
1354
/* The strings here are followed in the message by `reference to...' in
1284
1355
   the `validate' routine.  They are only used in messages, thus are
1285
1356
   translated.  */
1286
 
static char *
1287
 
reftype_type_string (type)
1288
 
     enum reftype type;
 
1357
static const char *
 
1358
reftype_type_string (enum reftype type)
1289
1359
{
1290
1360
  switch (type)
1291
1361
    {
1299
1369
}
1300
1370
 
1301
1371
static void
1302
 
validate_other_references (ref_list)
1303
 
     NODE_REF *ref_list;
 
1372
validate_other_references (NODE_REF *ref_list)
1304
1373
{
1305
1374
  char *old_input_filename = input_filename;
1306
1375
 
1329
1398
   If the Next is different from the Next of the Up,
1330
1399
   then the Next node must have a Prev pointing at this node. */
1331
1400
void
1332
 
validate_file (tag_table)
1333
 
     TAG_ENTRY *tag_table;
 
1401
validate_file (TAG_ENTRY *tag_table)
1334
1402
{
1335
1403
  char *old_input_filename = input_filename;
1336
1404
  TAG_ENTRY *tags = tag_table;
1369
1437
                  tem1 = expand_node_name (prev);
1370
1438
                  tem2 = expand_node_name (tags->node);
1371
1439
 
1372
 
                  if (STREQ (tem1, tem2))
 
1440
                  if (tem1 && tem2 && STREQ (tem1, tem2))
1373
1441
                    you_lose = 0;
1374
1442
                  free (tem1);
1375
1443
                  free (tem2);
1376
1444
                }
1377
1445
              if (you_lose)
1378
1446
                {
1379
 
                  line_error (_("Next field of node `%s' not pointed to"),
 
1447
                  line_error (_("Next field of node `%s' not pointed to (perhaps incorrect sectioning?)"),
1380
1448
                              tags->node);
1381
1449
                  file_line_error (temp_tag->filename, temp_tag->line_no,
1382
1450
                                   _("This node (%s) has the bad Prev"),
1450
1518
      if (!tags->up
1451
1519
          && !(tags->flags & TAG_FLAG_ANCHOR)
1452
1520
          && strcasecmp (tags->node, "Top") != 0)
1453
 
        line_error (_("`%s' has no Up field"), tags->node);
 
1521
        line_error (_("`%s' has no Up field (perhaps incorrect sectioning?)"), tags->node);
1454
1522
      else if (tags->up)
1455
1523
        {
1456
1524
          int valid_p = validate (tags->up, tags->line_no, _("Up"));
1575
1643
   This means only anchors follow.  */
1576
1644
 
1577
1645
static int
1578
 
last_node_p (tags)
1579
 
     TAG_ENTRY *tags;
 
1646
last_node_p (TAG_ENTRY *tags)
1580
1647
{
1581
1648
  int last = 1;
1582
1649
  while (tags->next_ent) {
1589
1656
        break;
1590
1657
      }
1591
1658
  }
1592
 
  
 
1659
 
1593
1660
  return last;
1594
1661
}
1595
1662
 
1596
1663
 
 
1664
static char *
 
1665
enumerate_filename (char *pathname, char *basename, int number)
 
1666
{
 
1667
  /* Do we need to generate names of subfiles which don't exceed 8+3 limits? */
 
1668
  const int dos_file_names = !HAVE_LONG_FILENAMES (pathname ? pathname : ".");
 
1669
  unsigned name_len = strlen (basename);
 
1670
  char *filename = xmalloc (10 + strlen (pathname) + name_len);
 
1671
  char *base_filename = xmalloc (10 + name_len);
 
1672
 
 
1673
  sprintf (base_filename, "%s-%d", basename, number);
 
1674
 
 
1675
  if (dos_file_names)
 
1676
    {
 
1677
      char *dot = strchr (base_filename, '.');
 
1678
      unsigned base_len = strlen (base_filename);
 
1679
 
 
1680
      if (dot)
 
1681
        { /* Make foobar.i1, .., foobar.i99, foobar.100, ... */
 
1682
          dot[1] = 'i';
 
1683
          memmove (number <= 99 ? dot + 2 : dot + 1,
 
1684
              base_filename + name_len + 1,
 
1685
              strlen (base_filename + name_len + 1) + 1);
 
1686
        }
 
1687
      else if (base_len > 8)
 
1688
        {
 
1689
          /* Make foobar-1, .., fooba-10, .., foob-100, ... */
 
1690
          unsigned numlen = base_len - name_len;
 
1691
 
 
1692
          memmove (base_filename + 8 - numlen, base_filename + name_len, numlen + 1);
 
1693
        }
 
1694
    }
 
1695
 
 
1696
  sprintf (filename, "%s%s", pathname, base_filename);
 
1697
 
 
1698
  return filename;
 
1699
}
 
1700
 
 
1701
/* Remove previously split files, to avoid
 
1702
   lingering parts of shrinked documents.  */
 
1703
void
 
1704
clean_old_split_files (char *filename)
 
1705
{
 
1706
  char *root_filename = filename_part (filename);
 
1707
  char *root_pathname = pathname_part (filename);
 
1708
  int i;
 
1709
 
 
1710
  /* We break as soon as we hit an inexistent file,
 
1711
     so looping until large numbers is harmless.  */
 
1712
  for (i = 1; i < 1000; i++)
 
1713
    {
 
1714
      struct stat st;
 
1715
      char *check_file = enumerate_filename (root_pathname, root_filename, i);
 
1716
 
 
1717
      if (stat (check_file, &st) != 0)
 
1718
        break;
 
1719
      else if (!S_ISDIR (st.st_mode))
 
1720
        {
 
1721
          /* Give feedback if requested, removing a file is important.  */
 
1722
          if (verbose_mode)
 
1723
            printf (_("Removing %s\n"), check_file);
 
1724
 
 
1725
          /* Warn user that we cannot remove the file.  */
 
1726
          if (unlink (check_file) != 0)
 
1727
            warning (_("Can't remove file `%s': %s"), check_file, strerror (errno));
 
1728
        }
 
1729
 
 
1730
      free (check_file);
 
1731
    }
 
1732
}
 
1733
 
 
1734
 
1597
1735
/* Split large output files into a series of smaller files.  Each file
1598
1736
   is pointed to in the tag table, which then gets written out as the
1599
1737
   original file.  The new files have the same name as the original file
1600
1738
   with a "-num" attached.  SIZE is the largest number of bytes to allow
1601
1739
   in any single split file. */
1602
1740
void
1603
 
split_file (filename, size)
1604
 
     char *filename;
1605
 
     int size;
 
1741
split_file (char *filename, int size)
1606
1742
{
1607
1743
  char *root_filename, *root_pathname;
1608
 
  char *the_file, *filename_part ();
 
1744
  char *the_file;
1609
1745
  struct stat fileinfo;
1610
1746
  long file_size;
1611
1747
  char *the_header;
1612
1748
  int header_size;
1613
 
  int dos_file_names = 0;       /* if nonzero, don't exceed 8+3 limits */
1614
1749
 
1615
1750
  /* Can only do this to files with tag tables. */
1616
1751
  if (!tag_table)
1619
1754
  if (size == 0)
1620
1755
    size = DEFAULT_SPLIT_SIZE;
1621
1756
 
1622
 
  if ((stat (filename, &fileinfo) != 0) ||
1623
 
      (((long) fileinfo.st_size) < SPLIT_SIZE_THRESHOLD))
 
1757
  if ((stat (filename, &fileinfo) != 0)
 
1758
      || (((long) fileinfo.st_size) < size))
1624
1759
    return;
1625
1760
  file_size = (long) fileinfo.st_size;
1626
1761
 
1627
 
  the_file = find_and_load (filename);
 
1762
  the_file = find_and_load (filename, 0);
1628
1763
  if (!the_file)
1629
1764
    return;
1630
1765
 
1631
1766
  root_filename = filename_part (filename);
1632
1767
  root_pathname = pathname_part (filename);
1633
1768
 
1634
 
  /* Do we need to generate names of subfiles which don't exceed 8+3 limits? */
1635
 
  dos_file_names = !HAVE_LONG_FILENAMES (root_pathname ? root_pathname : ".");
1636
 
 
1637
1769
  if (!root_pathname)
1638
1770
    root_pathname = xstrdup ("");
1639
1771
 
1647
1779
    TAG_ENTRY *tags = tag_table;
1648
1780
    char *indirect_info = NULL;
1649
1781
 
 
1782
    /* Maybe we want a Local Variables section.  */
 
1783
    char *trailer = info_trailer ();
 
1784
    int trailer_len = trailer ? strlen (trailer) : 0;
 
1785
 
1650
1786
    /* Remember the `header' of this file.  The first tag in the file is
1651
1787
       the bottom of the header; the top of the file is the start. */
1652
1788
    the_header = xmalloc (1 + (header_size = tags->position));
1732
1868
              write_region:
1733
1869
                {
1734
1870
                  int fd;
1735
 
                  char *split_filename, *split_basename;
1736
 
                  unsigned root_len = strlen (root_filename);
1737
 
 
1738
 
                  split_filename = xmalloc (10 + strlen (root_pathname)
1739
 
                                            + root_len);
1740
 
                  split_basename = xmalloc (10 + root_len);
1741
 
                  sprintf (split_basename, "%s-%d", root_filename, which_file);
1742
 
                  if (dos_file_names)
1743
 
                    {
1744
 
                      char *dot = strchr (split_basename, '.');
1745
 
                      unsigned base_len = strlen (split_basename);
1746
 
 
1747
 
                      if (dot)
1748
 
                        { /* Make foobar.i1, .., foobar.i99, foobar.100, ... */
1749
 
                          dot[1] = 'i';
1750
 
                          memmove (which_file <= 99 ? dot + 2 : dot + 1,
1751
 
                                   split_basename + root_len + 1,
1752
 
                                   strlen (split_basename + root_len + 1) + 1);
1753
 
                        }
1754
 
                      else if (base_len > 8)
1755
 
                        {
1756
 
                          /* Make foobar-1, .., fooba-10, .., foob-100, ... */
1757
 
                          unsigned numlen = base_len - root_len;
1758
 
 
1759
 
                          memmove (split_basename + 8 - numlen,
1760
 
                                   split_basename + root_len, numlen + 1);
1761
 
                        }
1762
 
                    }
1763
 
                  sprintf (split_filename, "%s%s", root_pathname,
1764
 
                           split_basename);
 
1871
                  char *split_filename = enumerate_filename (root_pathname,
 
1872
                      root_filename, which_file);
 
1873
                  char *split_basename = filename_part (split_filename);
1765
1874
 
1766
1875
                  fd = open (split_filename, O_WRONLY|O_TRUNC|O_CREAT, 0666);
1767
1876
                  if (fd < 0
1768
1877
                      || write (fd, the_header, header_size) != header_size
1769
1878
                      || write (fd, the_file + file_top, file_bot - file_top)
1770
1879
                         != (file_bot - file_top)
1771
 
                      || (close (fd)) < 0)
 
1880
                      || (trailer_len
 
1881
                          && write (fd, trailer, trailer_len) != trailer_len)
 
1882
                      || close (fd) < 0)
1772
1883
                    {
1773
1884
                      perror (split_filename);
1774
1885
                      if (fd != -1)
1813
1924
      /* Inhibit newlines. */
1814
1925
      paragraph_is_open = 0;
1815
1926
 
 
1927
      /* Write the indirect tag table.  */
1816
1928
      write_tag_table_indirect ();
 
1929
 
 
1930
      /* preserve local variables in info output.  */
 
1931
      if (trailer)
 
1932
        {
 
1933
          fwrite (trailer, 1, trailer_len, output_stream);
 
1934
          free (trailer);
 
1935
        }
 
1936
 
1817
1937
      fclose (output_stream);
1818
1938
      free (the_header);
1819
1939
      free (the_file);