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 >
Wrap
C/C++ Source or Header
|
1993-05-27
|
28KB
|
1,222 lines
// -*- C++ -*-
/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
Written by James Clark (jjc@jclark.com)
This file is part of groff.
groff is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 2, or (at your option) any later
version.
groff is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License along
with groff; see the file COPYING. If not, write to the Free Software
Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "refer.h"
#include "refid.h"
#include "ref.h"
#include "token.h"
#include "search.h"
#include "command.h"
const char PRE_LABEL_MARKER = '\013';
const char POST_LABEL_MARKER = '\014';
const char LABEL_MARKER = '\015'; // label_type is added on
#define FORCE_LEFT_BRACKET 04
#define FORCE_RIGHT_BRACKET 010
static FILE *outfp = stdout;
string capitalize_fields;
string reverse_fields;
string abbreviate_fields;
string period_before_last_name = ". ";
string period_before_initial = ".";
string period_before_hyphen = "";
string period_before_other = ". ";
string sort_fields;
int annotation_field = -1;
string annotation_macro;
string discard_fields = "XYZ";
string pre_label = "\\*([.";
string post_label = "\\*(.]";
string sep_label = ", ";
int accumulate = 0;
int move_punctuation = 0;
int abbreviate_label_ranges = 0;
string label_range_indicator;
int label_in_text = 1;
int label_in_reference = 1;
int date_as_label = 0;
int sort_adjacent_labels = 0;
// Join exactly two authors with this.
string join_authors_exactly_two = " and ";
// When there are more than two authors join the last two with this.
string join_authors_last_two = ", and ";
// Otherwise join authors with this.
string join_authors_default = ", ";
string separate_label_second_parts = ", ";
// Use this string to represent that there are other authors.
string et_al = " et al";
// Use et al only if it can replace at least this many authors.
int et_al_min_elide = 2;
// Use et al only if the total number of authors is at least this.
int et_al_min_total = 3;
int compatible_flag = 0;
int short_label_flag = 0;
static int recognize_R1_R2 = 1;
search_list database_list;
int search_default = 1;
static int default_database_loaded = 0;
static reference **citation = 0;
static int ncitations = 0;
static int citation_max = 0;
static reference **reference_hash_table = 0;
static int hash_table_size;
static int nreferences = 0;
static int need_syncing = 0;
string pending_line;
string pending_lf_lines;
static void output_pending_line();
static unsigned immediately_handle_reference(const string &);
static void immediately_output_references();
static unsigned store_reference(const string &);
static void divert_to_temporary_file();
static reference *make_reference(const string &, unsigned *);
static void usage();
static void do_file(const char *);
static void split_punct(string &line, string &punct);
static void output_citation_group(reference **v, int n, label_type, FILE *fp);
static void possibly_load_default_database();
int main(int argc, char **argv)
{
program_name = argv[0];
static char stderr_buf[BUFSIZ];
setbuf(stderr, stderr_buf);
outfp = stdout;
int finished_options = 0;
int bib_flag = 0;
int done_spec = 0;
for (--argc, ++argv;
!finished_options && argc > 0 && argv[0][0] == '-'
&& argv[0][1] != '\0';
argv++, argc--) {
const char *opt = argv[0] + 1;
while (opt != 0 && *opt != '\0') {
switch (*opt) {
case 'C':
compatible_flag = 1;
opt++;
break;
case 'B':
bib_flag = 1;
label_in_reference = 0;
label_in_text = 0;
++opt;
if (*opt == '\0') {
annotation_field = 'X';
annotation_macro = "AP";
}
else if (csalnum(opt[0]) && opt[1] == '.' && opt[2] != '\0') {
annotation_field = opt[0];
annotation_macro = opt + 2;
}
opt = 0;
break;
case 'P':
move_punctuation = 1;
opt++;
break;
case 'R':
recognize_R1_R2 = 0;
opt++;
break;
case 'S':
// Not a very useful spec.
set_label_spec("(A.n|Q)', '(D.y|D)");
done_spec = 1;
pre_label = " (";
post_label = ")";
sep_label = "; ";
opt++;
break;
case 'V':
verify_flag = 1;
opt++;
break;
case 'f':
{
const char *num = 0;
if (*++opt == '\0') {
if (argc > 1) {
num = *++argv;
--argc;
}
else {
error("option `f' requires an argument");
usage();
}
}
else {
num = opt;
opt = 0;
}
for (const char *ptr = num; *ptr; ptr++)
if (!csdigit(*ptr)) {
error("bad character `%1' in argument to -f option", *ptr);
break;
}
if (*ptr == '\0') {
string spec;
spec = '%';
spec += num;
spec += '\0';
set_label_spec(spec.contents());
done_spec = 1;
}
break;
}
case 'b':
label_in_text = 0;
label_in_reference = 0;
opt++;
break;
case 'e':
accumulate = 1;
opt++;
break;
case 'c':
capitalize_fields = ++opt;
opt = 0;
break;
case 'k':
{
char buf[5];
if (csalpha(*++opt))
buf[0] = *opt++;
else {
if (*opt != '\0')
error("bad field name `%1'", *opt++);
buf[0] = 'L';
}
buf[1] = '~';
buf[2] = '%';
buf[3] = 'a';
buf[4] = '\0';
set_label_spec(buf);
done_spec = 1;
}
break;
case 'a':
{
for (const char *ptr = ++opt; *ptr; ptr++)
if (!csdigit(*ptr)) {
error("argument to `a' option not a number");
break;
}
if (*ptr == '\0') {
reverse_fields = 'A';
reverse_fields += opt;
}
opt = 0;
}
break;
case 'i':
linear_ignore_fields = ++opt;
opt = 0;
break;
case 'l':
{
char buf[INT_DIGITS*2 + 11]; // A.n+2D.y-3%a
strcpy(buf, "A.n");
if (*++opt != '\0' && *opt != ',') {
char *ptr;
long n = strtol(opt, &ptr, 10);
if (n == 0 && ptr == opt) {
error("bad integer `%1' in `l' option", opt);
opt = 0;
break;
}
if (n < 0)
n = 0;
opt = ptr;
sprintf(strchr(buf, '\0'), "+%ld", n);
}
strcat(buf, "D.y");
if (*opt == ',')
opt++;
if (*opt != '\0') {
char *ptr;
long n = strtol(opt, &ptr, 10);
if (n == 0 && ptr == opt) {
error("bad integer `%1' in `l' option", opt);
opt = 0;
break;
}
if (n < 0)
n = 0;
sprintf(strchr(buf, '\0'), "-%ld", n);
opt = ptr;
if (*opt != '\0')
error("argument to `l' option not of form `m,n'");
}
strcat(buf, "%a");
if (!set_label_spec(buf))
assert(0);
done_spec = 1;
}
break;
case 'n':
search_default = 0;
opt++;
break;
case 'p':
{
const char *filename = 0;
if (*++opt == '\0') {
if (argc > 1) {
filename = *++argv;
argc--;
}
else {
error("option `p' requires an argument");
usage();
}
}
else {
filename = opt;
opt = 0;
}
database_list.add_file(filename);
}
break;
case 's':
if (*++opt == '\0')
sort_fields = "AD";
else {
sort_fields = opt;
opt = 0;
}
accumulate = 1;
break;
case 't':
{
char *ptr;
long n = strtol(opt, &ptr, 10);
if (n == 0 && ptr == opt) {
error("bad integer `%1' in `t' option", opt);
opt = 0;
break;
}
if (n < 1)
n = 1;
linear_truncate_len = int(n);
opt = ptr;
break;
}
case 'v':
{
extern const char *version_string;
fprintf(stderr, "GNU refer version %s\n", version_string);
fflush(stderr);
opt++;
break;
}
case '-':
if (opt[1] == '\0') {
finished_options = 1;
opt++;
break;
}
// fall through
default:
error("unrecognized option `%1'", *opt);
usage();
break;
}
}
}
if (!done_spec)
set_label_spec("%1");
if (argc <= 0) {
if (bib_flag)
do_bib("-");
else
do_file("-");
}
else {
for (int i = 0; i < argc; i++) {
if (bib_flag)
do_bib(argv[i]);
else
do_file