home *** CD-ROM | disk | FTP | other *** search
/ Fresh Fish 4 / FreshFish_May-June1994.bin / bbs / gnu / groff-1.09-src.lha / src / amiga / groff-1.09 / refer / refer.cc < prev    next >
C/C++ Source or Header  |  1993-05-27  |  28KB  |  1,222 lines

  1. // -*- C++ -*-
  2. /* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
  3.      Written by James Clark (jjc@jclark.com)
  4.  
  5. This file is part of groff.
  6.  
  7. groff is free software; you can redistribute it and/or modify it under
  8. the terms of the GNU General Public License as published by the Free
  9. Software Foundation; either version 2, or (at your option) any later
  10. version.
  11.  
  12. groff is distributed in the hope that it will be useful, but WITHOUT ANY
  13. WARRANTY; without even the implied warranty of MERCHANTABILITY or
  14. FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  15. for more details.
  16.  
  17. You should have received a copy of the GNU General Public License along
  18. with groff; see the file COPYING.  If not, write to the Free Software
  19. Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
  20.  
  21. #include "refer.h"
  22. #include "refid.h"
  23. #include "ref.h"
  24. #include "token.h"
  25. #include "search.h"
  26. #include "command.h"
  27.  
  28. const char PRE_LABEL_MARKER = '\013';
  29. const char POST_LABEL_MARKER = '\014';
  30. const char LABEL_MARKER = '\015'; // label_type is added on
  31.  
  32. #define FORCE_LEFT_BRACKET 04
  33. #define FORCE_RIGHT_BRACKET 010
  34.  
  35. static FILE *outfp = stdout;
  36.  
  37. string capitalize_fields;
  38. string reverse_fields;
  39. string abbreviate_fields;
  40. string period_before_last_name = ". ";
  41. string period_before_initial = ".";
  42. string period_before_hyphen = "";
  43. string period_before_other = ". ";
  44. string sort_fields;
  45. int annotation_field = -1;
  46. string annotation_macro;
  47. string discard_fields = "XYZ";
  48. string pre_label = "\\*([.";
  49. string post_label = "\\*(.]";
  50. string sep_label = ", ";
  51. int accumulate = 0;
  52. int move_punctuation = 0;
  53. int abbreviate_label_ranges = 0;
  54. string label_range_indicator;
  55. int label_in_text = 1;
  56. int label_in_reference = 1;
  57. int date_as_label = 0;
  58. int sort_adjacent_labels = 0;
  59. // Join exactly two authors with this.
  60. string join_authors_exactly_two = " and ";
  61. // When there are more than two authors join the last two with this.
  62. string join_authors_last_two = ", and ";
  63. // Otherwise join authors with this.
  64. string join_authors_default = ", ";
  65. string separate_label_second_parts = ", ";
  66. // Use this string to represent that there are other authors.
  67. string et_al = " et al";
  68. // Use et al only if it can replace at least this many authors.
  69. int et_al_min_elide = 2;
  70. // Use et al only if the total number of authors is at least this.
  71. int et_al_min_total = 3;
  72.  
  73.  
  74. int compatible_flag = 0;
  75.  
  76. int short_label_flag = 0;
  77.  
  78. static int recognize_R1_R2 = 1;
  79.  
  80. search_list database_list;
  81. int search_default = 1;
  82. static int default_database_loaded = 0;
  83.  
  84. static reference **citation = 0;
  85. static int ncitations = 0;
  86. static int citation_max = 0;
  87.  
  88. static reference **reference_hash_table = 0;
  89. static int hash_table_size;
  90. static int nreferences = 0;
  91.  
  92. static int need_syncing = 0;
  93. string pending_line;
  94. string pending_lf_lines;
  95.  
  96. static void output_pending_line();
  97. static unsigned immediately_handle_reference(const string &);
  98. static void immediately_output_references();
  99. static unsigned store_reference(const string &);
  100. static void divert_to_temporary_file();
  101. static reference *make_reference(const string &, unsigned *);
  102. static void usage();
  103. static void do_file(const char *);
  104. static void split_punct(string &line, string &punct);
  105. static void output_citation_group(reference **v, int n, label_type, FILE *fp);
  106. static void possibly_load_default_database();
  107.  
  108. int main(int argc, char **argv)
  109. {
  110.   program_name = argv[0];
  111.   static char stderr_buf[BUFSIZ];
  112.   setbuf(stderr, stderr_buf);
  113.   outfp = stdout;
  114.   int finished_options = 0;
  115.   int bib_flag = 0;
  116.   int done_spec = 0;
  117.  
  118.   for (--argc, ++argv;
  119.        !finished_options && argc > 0 && argv[0][0] == '-'
  120.        && argv[0][1] != '\0';
  121.        argv++, argc--) {
  122.     const char *opt = argv[0] + 1; 
  123.     while (opt != 0 && *opt != '\0') {
  124.       switch (*opt) {
  125.       case 'C':
  126.     compatible_flag = 1;
  127.     opt++;
  128.     break;
  129.       case 'B':
  130.     bib_flag = 1;
  131.     label_in_reference = 0;
  132.     label_in_text = 0;
  133.     ++opt;
  134.     if (*opt == '\0') {
  135.       annotation_field = 'X';
  136.       annotation_macro = "AP";
  137.     }
  138.     else if (csalnum(opt[0]) && opt[1] == '.' && opt[2] != '\0') {
  139.       annotation_field = opt[0];
  140.       annotation_macro = opt + 2;
  141.     }
  142.     opt = 0;
  143.     break;
  144.       case 'P':
  145.     move_punctuation = 1;
  146.     opt++;
  147.     break;
  148.       case 'R':
  149.     recognize_R1_R2 = 0;
  150.     opt++;
  151.     break;
  152.       case 'S':
  153.     // Not a very useful spec.
  154.     set_label_spec("(A.n|Q)', '(D.y|D)");
  155.     done_spec = 1;
  156.     pre_label = " (";
  157.     post_label = ")";
  158.     sep_label = "; ";
  159.     opt++;
  160.     break;
  161.       case 'V':
  162.     verify_flag = 1;
  163.     opt++;
  164.     break;
  165.       case 'f':
  166.     {
  167.       const char *num = 0;
  168.       if (*++opt == '\0') {
  169.         if (argc > 1) {
  170.           num = *++argv;
  171.           --argc;
  172.         }
  173.         else {
  174.           error("option `f' requires an argument");
  175.           usage();
  176.         }
  177.       }
  178.       else {
  179.         num = opt;
  180.         opt = 0;
  181.       }
  182.       for (const char *ptr = num; *ptr; ptr++)
  183.         if (!csdigit(*ptr)) {
  184.           error("bad character `%1' in argument to -f option", *ptr);
  185.           break;
  186.         }
  187.       if (*ptr == '\0') {
  188.         string spec;
  189.         spec = '%';
  190.         spec += num;
  191.         spec += '\0';
  192.         set_label_spec(spec.contents());
  193.         done_spec = 1;
  194.       }
  195.       break;
  196.     }
  197.       case 'b':
  198.     label_in_text = 0;
  199.     label_in_reference = 0;
  200.     opt++;
  201.     break;
  202.       case 'e':
  203.     accumulate = 1;
  204.     opt++;
  205.     break;
  206.       case 'c':
  207.     capitalize_fields = ++opt;
  208.     opt = 0;
  209.     break;
  210.       case 'k':
  211.     {
  212.       char buf[5];
  213.       if (csalpha(*++opt))
  214.         buf[0] = *opt++;
  215.       else {
  216.         if (*opt != '\0')
  217.           error("bad field name `%1'", *opt++);
  218.         buf[0] = 'L';
  219.       }
  220.       buf[1] = '~';
  221.       buf[2] = '%';
  222.       buf[3] = 'a';
  223.       buf[4] = '\0';
  224.       set_label_spec(buf);
  225.       done_spec = 1;
  226.     }
  227.     break;
  228.       case 'a':
  229.     {
  230.       for (const char *ptr = ++opt; *ptr; ptr++)
  231.         if (!csdigit(*ptr)) {
  232.           error("argument to `a' option not a number");
  233.           break;
  234.         }
  235.       if (*ptr == '\0') {
  236.         reverse_fields = 'A';
  237.         reverse_fields += opt;
  238.       }
  239.       opt = 0;
  240.     }
  241.     break;
  242.       case 'i':
  243.     linear_ignore_fields = ++opt;
  244.     opt = 0;
  245.     break;
  246.       case 'l':
  247.     {
  248.       char buf[INT_DIGITS*2 + 11]; // A.n+2D.y-3%a
  249.       strcpy(buf, "A.n");
  250.       if (*++opt != '\0' && *opt != ',') {
  251.         char *ptr;
  252.         long n = strtol(opt, &ptr, 10);
  253.         if (n == 0 && ptr == opt) {
  254.           error("bad integer `%1' in `l' option", opt);
  255.           opt = 0;
  256.           break;
  257.         }
  258.         if (n < 0)
  259.           n = 0;
  260.         opt = ptr;
  261.         sprintf(strchr(buf, '\0'), "+%ld", n);
  262.       }
  263.       strcat(buf, "D.y");
  264.       if (*opt == ',')
  265.         opt++;
  266.       if (*opt != '\0') {
  267.         char *ptr;
  268.         long n = strtol(opt, &ptr, 10);
  269.         if (n == 0 && ptr == opt) {
  270.           error("bad integer `%1' in `l' option", opt);
  271.           opt = 0;
  272.           break;
  273.         }
  274.         if (n < 0)
  275.           n = 0;
  276.         sprintf(strchr(buf, '\0'), "-%ld", n);
  277.         opt = ptr;
  278.         if (*opt != '\0')
  279.           error("argument to `l' option not of form `m,n'");
  280.       }
  281.       strcat(buf, "%a");
  282.       if (!set_label_spec(buf))
  283.         assert(0);
  284.       done_spec = 1;
  285.     }
  286.     break;
  287.       case 'n':
  288.     search_default = 0;
  289.     opt++;
  290.     break;
  291.       case 'p':
  292.     {
  293.       const char *filename = 0;
  294.       if (*++opt == '\0') {
  295.         if (argc > 1) {
  296.           filename = *++argv;
  297.           argc--;
  298.         }
  299.         else {
  300.           error("option `p' requires an argument");
  301.           usage();
  302.         }
  303.       }
  304.       else {
  305.         filename = opt;
  306.         opt = 0;
  307.       }
  308.       database_list.add_file(filename);
  309.     }
  310.     break;
  311.       case 's':
  312.     if (*++opt == '\0')
  313.       sort_fields = "AD";
  314.     else {
  315.       sort_fields = opt;
  316.       opt = 0;
  317.     }
  318.     accumulate = 1;
  319.     break;
  320.       case 't':
  321.     {
  322.       char *ptr;
  323.       long n = strtol(opt, &ptr, 10);
  324.       if (n == 0 && ptr == opt) {
  325.         error("bad integer `%1' in `t' option", opt);
  326.         opt = 0;
  327.         break;
  328.       }
  329.       if (n < 1)
  330.         n = 1;
  331.       linear_truncate_len = int(n);
  332.       opt = ptr;
  333.       break;
  334.     }
  335.       case 'v':
  336.     {
  337.       extern const char *version_string;
  338.       fprintf(stderr, "GNU refer version %s\n", version_string);
  339.       fflush(stderr);
  340.       opt++;
  341.       break;
  342.     }
  343.       case '-':
  344.     if (opt[1] == '\0') {
  345.       finished_options = 1;
  346.       opt++;
  347.       break;
  348.     }
  349.     // fall through
  350.       default:
  351.     error("unrecognized option `%1'", *opt);
  352.     usage();
  353.     break;
  354.       }
  355.     }
  356.   }
  357.   if (!done_spec)
  358.     set_label_spec("%1");
  359.   if (argc <= 0) {
  360.     if (bib_flag)
  361.       do_bib("-");
  362.     else
  363.       do_file("-");
  364.   }
  365.   else {
  366.     for (int i = 0; i < argc; i++) {
  367.       if (bib_flag)
  368.     do_bib(argv[i]);
  369.       else
  370.     do_file