1 /* $NetBSD: label.y,v 1.1.1.4 2006/02/06 18:14:37 wiz Exp $ */
4 Copyright (C) 1989, 1990, 1991, 1992, 2000, 2004
5 Free Software Foundation, Inc.
6 Written by James Clark (jjc@jclark.com)
8 This file is part of groff.
10 groff is free software; you can redistribute it and/or modify it under
11 the terms of the GNU General Public License as published by the Free
12 Software Foundation; either version 2, or (at your option) any later
15 groff is distributed in the hope that it will be useful, but WITHOUT ANY
16 WARRANTY; without even the implied warranty of MERCHANTABILITY or
17 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
20 You should have received a copy of the GNU General Public License along
21 with groff; see the file COPYING. If not, write to the Free Software
22 Foundation, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, USA. */
32 void yyerror(const char *);
35 static const char *format_serial
(char c
, int n
);
42 label_info
(const string &);
45 label_info
*lookup_label
(const string &label
);
49 // Does the tentative label depend on the reference?
50 CONTAINS_VARIABLE
= 01,
55 virtual ~expression
() { }
56 virtual
void evaluate
(int, const reference
&, string &,
57 substring_position
&) = 0;
58 virtual
unsigned analyze
() { return
0; }
61 class at_expr
: public expression
{
64 void evaluate
(int, const reference
&, string &, substring_position
&);
65 unsigned analyze
() { return CONTAINS_VARIABLE|CONTAINS_AT
; }
68 class format_expr
: public expression
{
73 format_expr
(char c
, int w
= 0, int f
= 1)
74 : type
(c
), width
(w
), first_number
(f
) { }
75 void evaluate
(int, const reference
&, string &, substring_position
&);
76 unsigned analyze
() { return CONTAINS_FORMAT
; }
79 class field_expr
: public expression
{
83 field_expr
(char nm
, int num
) : number
(num
), name
(nm
) { }
84 void evaluate
(int, const reference
&, string &, substring_position
&);
85 unsigned analyze
() { return CONTAINS_VARIABLE
; }
88 class literal_expr
: public expression
{
91 literal_expr
(const char *ptr
, int len
) : s
(ptr
, len
) { }
92 void evaluate
(int, const reference
&, string &, substring_position
&);
95 class unary_expr
: public expression
{
99 unary_expr
(expression
*e
) : expr
(e
) { }
100 ~unary_expr
() { delete expr
; }
101 void evaluate
(int, const reference
&, string &, substring_position
&) = 0;
102 unsigned analyze
() { return expr ? expr
->analyze
() : 0; }
105 // This caches the analysis of an expression.
107 class analyzed_expr
: public unary_expr
{
110 analyzed_expr
(expression
*);
111 void evaluate
(int, const reference
&, string &, substring_position
&);
112 unsigned analyze
() { return flags
; }
115 class star_expr
: public unary_expr
{
117 star_expr
(expression
*e
) : unary_expr
(e
) { }
118 void evaluate
(int, const reference
&, string &, substring_position
&);
120 return
((expr ?
(expr
->analyze
() & ~CONTAINS_VARIABLE
) : 0)
125 typedef
void map_func
(const char *, const char *, string &);
127 class map_expr
: public unary_expr
{
130 map_expr
(expression
*e
, map_func
*f
) : unary_expr
(e
), func
(f
) { }
131 void evaluate
(int, const reference
&, string &, substring_position
&);
134 typedef
const char *extractor_func
(const char *, const char *, const char **);
136 class extractor_expr
: public unary_expr
{
138 extractor_func
*func
;
140 enum { BEFORE
= +1, MATCH
= 0, AFTER
= -1 };
141 extractor_expr
(expression
*e
, extractor_func
*f
, int pt
)
142 : unary_expr
(e
), part
(pt
), func
(f
) { }
143 void evaluate
(int, const reference
&, string &, substring_position
&);
146 class truncate_expr
: public unary_expr
{
149 truncate_expr
(expression
*e
, int i
) : unary_expr
(e
), n
(i
) { }
150 void evaluate
(int, const reference
&, string &, substring_position
&);
153 class separator_expr
: public unary_expr
{
155 separator_expr
(expression
*e
) : unary_expr
(e
) { }
156 void evaluate
(int, const reference
&, string &, substring_position
&);
159 class binary_expr
: public expression
{
164 binary_expr
(expression
*e1
, expression
*e2
) : expr1
(e1
), expr2
(e2
) { }
165 ~binary_expr
() { delete expr1
; delete expr2
; }
166 void evaluate
(int, const reference
&, string &, substring_position
&) = 0;
168 return
(expr1 ? expr1
->analyze
() : 0) |
(expr2 ? expr2
->analyze
() : 0);
172 class alternative_expr
: public binary_expr
{
174 alternative_expr
(expression
*e1
, expression
*e2
) : binary_expr
(e1
, e2
) { }
175 void evaluate
(int, const reference
&, string &, substring_position
&);
178 class list_expr
: public binary_expr
{
180 list_expr
(expression
*e1
, expression
*e2
) : binary_expr
(e1
, e2
) { }
181 void evaluate
(int, const reference
&, string &, substring_position
&);
184 class substitute_expr
: public binary_expr
{
186 substitute_expr
(expression
*e1
, expression
*e2
) : binary_expr
(e1
, e2
) { }
187 void evaluate
(int, const reference
&, string &, substring_position
&);
190 class ternary_expr
: public expression
{
196 ternary_expr
(expression
*e1
, expression
*e2
, expression
*e3
)
197 : expr1
(e1
), expr2
(e2
), expr3
(e3
) { }
198 ~ternary_expr
() { delete expr1
; delete expr2
; delete expr3
; }
199 void evaluate
(int, const reference
&, string &, substring_position
&) = 0;
201 return
((expr1 ? expr1
->analyze
() : 0)
202 |
(expr2 ? expr2
->analyze
() : 0)
203 |
(expr3 ? expr3
->analyze
() : 0));
207 class conditional_expr
: public ternary_expr
{
209 conditional_expr
(expression
*e1
, expression
*e2
, expression
*e3
)
210 : ternary_expr
(e1
, e2
, e3
) { }
211 void evaluate
(int, const reference
&, string &, substring_position
&);
214 static expression
*parsed_label
= 0;
215 static expression
*parsed_date_label
= 0;
216 static expression
*parsed_short_label
= 0;
218 static expression
*parse_result
;
227 struct { int ndigits
; int val
; } dig
;
228 struct { int start
; int len
; } str
;
231 /* uppercase or lowercase letter */
232 %token
<num
> TOKEN_LETTER
233 /* literal characters */
234 %token
<str
> TOKEN_LITERAL
236 %token
<num
> TOKEN_DIGIT
238 %type
<expr
> conditional
239 %type
<expr
> alternative
242 %type
<expr
> substitute
243 %type
<expr
> optional_conditional
246 %type
<num
> optional_number
253 { parse_result
= ($1 ? new analyzed_expr
($1) : 0); }
259 | alternative
'?' optional_conditional
':' conditional
260 { $$
= new conditional_expr
($1, $3, $5); }
263 optional_conditional:
273 | alternative
'|' list
274 { $$
= new alternative_expr
($1, $3); }
275 | alternative
'&' list
276 { $$
= new conditional_expr
($1, $3, 0); }
283 { $$
= new list_expr
($1, $2); }
289 | substitute
'~' string
290 { $$
= new substitute_expr
($1, $3); }
295 { $$
= new at_expr
; }
298 $$
= new literal_expr
(literals.contents
() + $1.start
,
302 { $$
= new field_expr
($1, 0); }
303 | TOKEN_LETTER number
304 { $$
= new field_expr
($1, $2 - 1); }
312 $$
= new format_expr
($2);
315 command_error
("unrecognized format `%1'", char($2));
316 $$
= new format_expr
('a');
323 $$
= new format_expr
('0', $2.ndigits
, $2.val
);
325 |
string '.' flag TOKEN_LETTER optional_number
329 $$
= new map_expr
($1, lowercase
);
332 $$
= new map_expr
($1, uppercase
);
335 $$
= new map_expr
($1, capitalize
);
338 $$
= new map_expr
($1, reverse_name
);
341 $$
= new map_expr
($1, abbreviate_name
);
344 $$
= new extractor_expr
($1, find_year
, $3);
347 $$
= new extractor_expr
($1, find_last_name
, $3);
351 command_error
("unknown function `%1'", char($4));
357 { $$
= new truncate_expr
($1, $3); }
359 { $$
= new truncate_expr
($1, -$3); }
361 { $$
= new star_expr
($1); }
362 |
'(' optional_conditional
')'
364 |
'<' optional_conditional
'>'
365 { $$
= new separator_expr
($2); }
384 { $$.ndigits
= 1; $$.val
= $1; }
386 { $$.ndigits
= $1.ndigits
+ 1; $$.val
= $1.val
*10 + $2; }
401 /* bison defines const to be empty unless __STDC__ is defined, which it
402 isn't under cfront */
408 const char *spec_ptr
;
409 const char *spec_end
;
410 const char *spec_cur
;
412 static char uppercase_array
[] = {
413 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
414 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
415 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
419 static char lowercase_array
[] = {
420 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
421 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p',
422 'q', 'r', 's', 't', 'u', 'v', 'w', 'x',
428 while
(spec_ptr
< spec_end
&& csspace
(*spec_ptr
))
431 if
(spec_ptr
>= spec_end
)
433 unsigned char c
= *spec_ptr
++;
439 yylval.num
= c
- '0';
443 yylval.str.start
= literals.length
();
444 for
(; spec_ptr
< spec_end
; spec_ptr
++) {
445 if
(*spec_ptr
== '\'') {
446 if
(++spec_ptr
< spec_end
&& *spec_ptr
== '\'')
449 yylval.str.len
= literals.length
() - yylval.str.start
;
450 return TOKEN_LITERAL
;
454 literals
+= *spec_ptr
;
456 yylval.str.len
= literals.length
() - yylval.str.start
;
457 return TOKEN_LITERAL
;
462 int set_label_spec
(const char *label_spec
)
464 spec_cur
= spec_ptr
= label_spec
;
465 spec_end
= strchr
(label_spec
, '\0');
470 parsed_label
= parse_result
;
474 int set_date_label_spec
(const char *label_spec
)
476 spec_cur
= spec_ptr
= label_spec
;
477 spec_end
= strchr
(label_spec
, '\0');
481 delete parsed_date_label
;
482 parsed_date_label
= parse_result
;
486 int set_short_label_spec
(const char *label_spec
)
488 spec_cur
= spec_ptr
= label_spec
;
489 spec_end
= strchr
(label_spec
, '\0');
493 delete parsed_short_label
;
494 parsed_short_label
= parse_result
;
498 void yyerror(const char *message
)
500 if
(spec_cur
< spec_end
)
501 command_error
("label specification %1 before `%2'", message
, spec_cur
);
503 command_error
("label specification %1 at end of string",
507 void at_expr
::evaluate
(int tentative
, const reference
&ref
,
508 string &result
, substring_position
&)
511 ref.canonicalize_authors
(result
);
513 const char *end
, *start
= ref.get_authors
(&end
);
515 result.append
(start
, end
- start
);
519 void format_expr
::evaluate
(int tentative
, const reference
&ref
,
520 string &result
, substring_position
&)
524 const label_info
*lp
= ref.get_label_ptr
();
525 int num
= lp
== 0 ? ref.get_number
() : lp
->count
;
527 result
+= format_serial
(type
, num
+ 1);
529 const char *ptr
= i_to_a
(num
+ first_number
);
530 int pad
= width
- strlen
(ptr
);
537 static const char *format_serial
(char c
, int n
)
540 static char buf
[128]; // more than enough.
546 // troff uses z and w to represent 10000 and 5000 in Roman
547 // numerals; I can find no historical basis for this usage
548 const char *s
= c
== 'i' ?
"zwmdclxvi" : "ZWMDCLXVI";
555 for
(int i
= 1000; i
> 0; i
/= 10, s
+= 2) {
602 // this is derived from troff/reg.c
609 *p
++ = c
== 'a' ? lowercase_array
[d
- 1] :
610 uppercase_array
[d
- 1];
630 void field_expr
::evaluate
(int, const reference
&ref
,
631 string &result
, substring_position
&)
634 const char *start
= ref.get_field
(name
, &end
);
636 start
= nth_field
(number
, start
, &end
);
638 result.append
(start
, end
- start
);
642 void literal_expr
::evaluate
(int, const reference
&,
643 string &result
, substring_position
&)
648 analyzed_expr::analyzed_expr
(expression
*e
)
649 : unary_expr
(e
), flags
(e ? e
->analyze
() : 0)
653 void analyzed_expr
::evaluate
(int tentative
, const reference
&ref
,
654 string &result
, substring_position
&pos
)
657 expr
->evaluate
(tentative
, ref
, result
, pos
);
660 void star_expr
::evaluate
(int tentative
, const reference
&ref
,
661 string &result
, substring_position
&pos
)
663 const label_info
*lp
= ref.get_label_ptr
();
665 && (lp
== 0 || lp
->total
> 1)
667 expr
->evaluate
(tentative
, ref
, result
, pos
);
670 void separator_expr
::evaluate
(int tentative
, const reference
&ref
,
671 string &result
, substring_position
&pos
)
673 int start_length
= result.length
();
674 int is_first
= pos.start
< 0;
676 expr
->evaluate
(tentative
, ref
, result
, pos
);
678 pos.start
= start_length
;
679 pos.length
= result.length
() - start_length
;
683 void map_expr
::evaluate
(int tentative
, const reference
&ref
,
684 string &result
, substring_position
&)
688 substring_position temp_pos
;
689 expr
->evaluate
(tentative
, ref
, temp
, temp_pos
);
690 (*func
)(temp.contents
(), temp.contents
() + temp.length
(), result
);
694 void extractor_expr
::evaluate
(int tentative
, const reference
&ref
,
695 string &result
, substring_position
&)
699 substring_position temp_pos
;
700 expr
->evaluate
(tentative
, ref
, temp
, temp_pos
);
701 const char *end
, *start
= (*func
)(temp.contents
(),
702 temp.contents
() + temp.length
(),
707 result.append
(temp.contents
(), start
- temp.contents
());
713 result.append
(start
, end
- start
);
717 result.append
(end
, temp.contents
() + temp.length
() - end
);
725 static void first_part
(int len
, const char *ptr
, const char *end
,
729 const char *token_start
= ptr
;
730 if
(!get_token
(&ptr
, end
))
732 const token_info
*ti
= lookup_token
(token_start
, ptr
);
733 int counts
= ti
->sortify_non_empty
(token_start
, ptr
);
734 if
(counts
&& --len
< 0)
736 if
(counts || ti
->is_accent
())
737 result.append
(token_start
, ptr
- token_start
);
741 static void last_part
(int len
, const char *ptr
, const char *end
,
744 const char *start
= ptr
;
747 const char *token_start
= ptr
;
748 if
(!get_token
(&ptr
, end
))
750 const token_info
*ti
= lookup_token
(token_start
, ptr
);
751 if
(ti
->sortify_non_empty
(token_start
, ptr
))
755 int skip
= count
- len
;
758 const char *token_start
= ptr
;
759 if
(!get_token
(&ptr
, end
))
761 const token_info
*ti
= lookup_token
(token_start
, ptr
);
762 if
(ti
->sortify_non_empty
(token_start
, ptr
) && --skip
< 0) {
768 first_part
(len
, ptr
, end
, result
);
771 void truncate_expr
::evaluate
(int tentative
, const reference
&ref
,
772 string &result
, substring_position
&)
776 substring_position temp_pos
;
777 expr
->evaluate
(tentative
, ref
, temp
, temp_pos
);
778 const char *start
= temp.contents
();
779 const char *end
= start
+ temp.length
();
781 first_part
(n
, start
, end
, result
);
783 last_part
(-n
, start
, end
, result
);
787 void alternative_expr
::evaluate
(int tentative
, const reference
&ref
,
788 string &result
, substring_position
&pos
)
790 int start_length
= result.length
();
792 expr1
->evaluate
(tentative
, ref
, result
, pos
);
793 if
(result.length
() == start_length
&& expr2
)
794 expr2
->evaluate
(tentative
, ref
, result
, pos
);
797 void list_expr
::evaluate
(int tentative
, const reference
&ref
,
798 string &result
, substring_position
&pos
)
801 expr1
->evaluate
(tentative
, ref
, result
, pos
);
803 expr2
->evaluate
(tentative
, ref
, result
, pos
);
806 void substitute_expr
::evaluate
(int tentative
, const reference
&ref
,
807 string &result
, substring_position
&pos
)
809 int start_length
= result.length
();
811 expr1
->evaluate
(tentative
, ref
, result
, pos
);
812 if
(result.length
() > start_length
&& result
[result.length
() - 1] == '-') {
813 // ought to see if pos covers the -
814 result.set_length
(result.length
() - 1);
816 expr2
->evaluate
(tentative
, ref
, result
, pos
);
820 void conditional_expr
::evaluate
(int tentative
, const reference
&ref
,
821 string &result
, substring_position
&pos
)
824 substring_position temp_pos
;
826 expr1
->evaluate
(tentative
, ref
, temp
, temp_pos
);
827 if
(temp.length
() > 0) {
829 expr2
->evaluate
(tentative
, ref
, result
, pos
);
833 expr3
->evaluate
(tentative
, ref
, result
, pos
);
837 void reference
::pre_compute_label
()
839 if
(parsed_label
!= 0
840 && (parsed_label
->analyze
() & expression
::CONTAINS_VARIABLE
)) {
842 substring_position temp_pos
;
843 parsed_label
->evaluate
(1, *this
, label
, temp_pos
);
844 label_ptr
= lookup_label
(label
);
848 void reference
::compute_label
()
852 parsed_label
->evaluate
(0, *this
, label
, separator_pos
);
853 if
(short_label_flag
&& parsed_short_label
)
854 parsed_short_label
->evaluate
(0, *this
, short_label
, short_separator_pos
);
857 if
(parsed_date_label
) {
858 substring_position temp_pos
;
859 parsed_date_label
->evaluate
(0, *this
, new_date
, temp_pos
);
864 label_ptr
->count
+= 1;
867 void reference
::immediate_compute_label
()
870 label_ptr
->total
= 2; // force use of disambiguator
874 int reference
::merge_labels
(reference
**v
, int n
, label_type type
,
877 if
(abbreviate_label_ranges
)
878 return merge_labels_by_number
(v
, n
, type
, result
);
880 return merge_labels_by_parts
(v
, n
, type
, result
);
883 int reference
::merge_labels_by_number
(reference
**v
, int n
, label_type type
,
888 int num
= get_number
();
889 // Only merge three or more labels.
890 if
(v
[0]->get_number
() != num
+ 1
891 || v
[1]->get_number
() != num
+ 2)
894 for
(i
= 2; i
< n
; i
++)
895 if
(v
[i
]->get_number
() != num
+ i
+ 1)
897 result
= get_label
(type
);
898 result
+= label_range_indicator
;
899 result
+= v
[i
- 1]->get_label
(type
);
903 const substring_position
&reference
::get_separator_pos
(label_type type
) const
905 if
(type
== SHORT_LABEL
&& short_label_flag
)
906 return short_separator_pos
;
908 return separator_pos
;
911 const string &reference
::get_label
(label_type type
) const
913 if
(type
== SHORT_LABEL
&& short_label_flag
)
919 int reference
::merge_labels_by_parts
(reference
**v
, int n
, label_type type
,
924 const string &lb
= get_label
(type
);
925 const substring_position
&sp
= get_separator_pos
(type
);
927 || sp.start
!= v
[0]->get_separator_pos
(type
).start
928 || memcmp
(lb.contents
(), v
[0]->get_label
(type
).contents
(),
934 result
+= separate_label_second_parts
;
935 const substring_position
&s
= v
[i
]->get_separator_pos
(type
);
936 int sep_end_pos
= s.start
+ s.length
;
937 result.append
(v
[i
]->get_label
(type
).contents
() + sep_end_pos
,
938 v
[i
]->get_label
(type
).length
() - sep_end_pos
);
940 && sp.start
== v
[i
]->get_separator_pos
(type
).start
941 && memcmp
(lb.contents
(), v
[i
]->get_label
(type
).contents
(),
948 label_info::label_info
(const string &s
)
949 : start
(label_pool.length
()), length
(s.length
()), count
(0), total
(1)
954 static label_info
**label_table
= 0;
955 static int label_table_size
= 0;
956 static int label_table_used
= 0;
958 label_info
*lookup_label
(const string &label
)
960 if
(label_table
== 0) {
961 label_table
= new label_info
*[17];
962 label_table_size
= 17;
963 for
(int i
= 0; i
< 17; i
++)
966 unsigned h
= hash_string
(label.contents
(), label.length
()) % label_table_size
;
968 for
(ptr
= label_table
+ h
;
971 ?
(ptr
= label_table
+ label_table_size
- 1)
973 if
((*ptr
)->length
== label.length
()
974 && memcmp
(label_pool.contents
() + (*ptr
)->start
, label.contents
(),
975 label.length
()) == 0) {
979 label_info
*result
= *ptr
= new label_info
(label
);
980 if
(++label_table_used
* 2 > label_table_size
) {
982 label_info
**old_table
= label_table
;
983 int old_size
= label_table_size
;
984 label_table_size
= next_size
(label_table_size
);
985 label_table
= new label_info
*[label_table_size
];
987 for
(i
= 0; i
< label_table_size
; i
++)
989 for
(i
= 0; i
< old_size
; i
++)
991 h
= hash_string
(label_pool.contents
() + old_table
[i
]->start
,
992 old_table
[i
]->length
);
994 for
(p
= label_table
+ (h % label_table_size
);
997 ?
(p
= label_table
+ label_table_size
- 1)
1009 for
(int i
= 0; i
< label_table_size
; i
++) {
1010 delete label_table
[i
];
1013 label_table_used
= 0;
1017 static void consider_authors
(reference
**start
, reference
**end
, int i
);
1019 void compute_labels
(reference
**v
, int n
)
1022 && (parsed_label
->analyze
() & expression
::CONTAINS_AT
)
1023 && sort_fields.length
() >= 2
1024 && sort_fields
[0] == 'A'
1025 && sort_fields
[1] == '+')
1026 consider_authors
(v
, v
+ n
, 0);
1027 for
(int i
= 0; i
< n
; i
++)
1028 v
[i
]->compute_label
();
1032 /* A reference with a list of authors <A0,A1,...,AN> _needs_ author i
1033 where 0 <= i <= N if there exists a reference with a list of authors
1034 <B0,B1,...,BM> such that <A0,A1,...,AN> != <B0,B1,...,BM> and M >= i
1035 and Aj = Bj for 0 <= j < i. In this case if we can't say ``A0,
1036 A1,...,A(i-1) et al'' because this would match both <A0,A1,...,AN> and
1037 <B0,B1,...,BM>. If a reference needs author i we only have to call
1038 need_author(j) for some j >= i such that the reference also needs
1041 /* This function handles 2 tasks:
1042 determine which authors are needed (cannot be elided with et al.);
1043 determine which authors can have only last names in the labels.
1045 References >= start and < end have the same first i author names.
1046 Also they're sorted by A+. */
1048 static void consider_authors
(reference
**start
, reference
**end
, int i
)
1052 reference
**p
= start
;
1053 if
(i
>= (*p
)->get_nauthors
()) {
1054 for
(++p
; p
< end
&& i
>= (*p
)->get_nauthors
(); p
++)
1056 if
(p
< end
&& i
> 0) {
1057 // If we have an author list <A B C> and an author list <A B C D>,
1058 // then both lists need C.
1059 for
(reference
**q
= start
; q
< end
; q
++)
1060 (*q
)->need_author
(i
- 1);
1065 reference
**last_name_start
= p
;
1066 reference
**name_start
= p
;
1068 p
< end
&& i
< (*p
)->get_nauthors
()
1069 && same_author_last_name
(**last_name_start
, **p
, i
);
1071 if
(!same_author_name
(**name_start
, **p
, i
)) {
1072 consider_authors
(name_start
, p
, i
+ 1);
1076 consider_authors
(name_start
, p
, i
+ 1);
1077 if
(last_name_start
== name_start
) {
1078 for
(reference
**q
= last_name_start
; q
< p
; q
++)
1079 (*q
)->set_last_name_unambiguous
(i
);
1081 // If we have an author list <A B C D> and <A B C E>, then the lists
1082 // need author D and E respectively.
1083 if
(name_start
> start || p
< end
) {
1084 for
(reference
**q
= last_name_start
; q
< p
; q
++)
1085 (*q
)->need_author
(i
);
1090 int same_author_last_name
(const reference
&r1
, const reference
&r2
, int n
)
1093 const char *as1
= r1.get_sort_field
(0, n
, 0, &ae1
);
1095 const char *as2
= r2.get_sort_field
(0, n
, 0, &ae2
);
1096 if
(!as1
&& !as2
) return
1; // they are the same
1097 if
(!as1 ||
!as2
) return
0;
1098 return ae1
- as1
== ae2
- as2
&& memcmp
(as1
, as2
, ae1
- as1
) == 0;
1101 int same_author_name
(const reference
&r1
, const reference
&r2
, int n
)
1104 const char *as1
= r1.get_sort_field
(0, n
, -1, &ae1
);
1106 const char *as2
= r2.get_sort_field
(0, n
, -1, &ae2
);
1107 if
(!as1
&& !as2
) return
1; // they are the same
1108 if
(!as1 ||
!as2
) return
0;
1109 return ae1
- as1
== ae2
- as2
&& memcmp
(as1
, as2
, ae1
- as1
) == 0;
1113 void int_set
::set
(int i
)
1117 if
(bytei
>= v.length
()) {
1118 int old_length
= v.length
();
1119 v.set_length
(bytei
+ 1);
1120 for
(int j
= old_length
; j
<= bytei
; j
++)
1123 v
[bytei
] |
= 1 << (i
& 7);
1126 int int_set
::get
(int i
) const
1130 return bytei
>= v.length
() ?
0 : (v
[bytei
] & (1 << (i
& 7))) != 0;
1133 void reference
::set_last_name_unambiguous
(int i
)
1135 last_name_unambiguous.set
(i
);
1138 void reference
::need_author
(int n
)
1140 if
(n
> last_needed_author
)
1141 last_needed_author
= n
;
1144 const char *reference
::get_authors
(const char **end
) const
1146 if
(!computed_authors
) {
1147 ((reference
*)this
)->computed_authors
= 1;
1148 string &result
= ((reference
*)this
)->authors
;
1149 int na
= get_nauthors
();
1151 for
(int i
= 0; i
< na
; i
++) {
1152 if
(last_name_unambiguous.get
(i
)) {
1153 const char *e
, *start
= get_author_last_name
(i
, &e
);
1155 result.append
(start
, e
- start
);
1158 const char *e
, *start
= get_author
(i
, &e
);
1160 result.append
(start
, e
- start
);
1162 if
(i
== last_needed_author
1163 && et_al.length
() > 0
1164 && et_al_min_elide
> 0
1165 && last_needed_author
+ et_al_min_elide
< na
1166 && na
>= et_al_min_total
) {
1172 result
+= join_authors_exactly_two
;
1173 else if
(i
< na
- 2)
1174 result
+= join_authors_default
;
1176 result
+= join_authors_last_two
;
1180 const char *start
= authors.contents
();
1181 *end
= start
+ authors.length
();
1185 int reference
::get_nauthors
() const
1190 for
(na
= 0; get_author
(na
, &dummy
) != 0; na
++)
1192 ((reference
*)this
)->nauthors
= na
;