📄 refer.cc
字号:
int handle_pending(int c);public: label_processing_state(reference **, int, FILE *); ~label_processing_state(); void process(int c);};static void output_pending_line(){ if (label_in_text && !accumulate && ncitations > 0) { label_processing_state state(citation, ncitations, outfp); int len = pending_line.length(); for (int i = 0; i < len; i++) state.process((unsigned char)(pending_line[i])); } else put_string(pending_line, outfp); pending_line.clear(); if (pending_lf_lines.length() > 0) { put_string(pending_lf_lines, outfp); pending_lf_lines.clear(); } if (!accumulate) immediately_output_references(); if (need_syncing) { fprintf(outfp, ".lf %d %s\n", current_lineno, current_filename); need_syncing = 0; }}static void split_punct(string &line, string &punct){ const char *start = line.contents(); const char *end = start + line.length(); const char *ptr = start; const char *last_token_start = 0; for (;;) { if (ptr >= end) break; last_token_start = ptr; if (*ptr == PRE_LABEL_MARKER || *ptr == POST_LABEL_MARKER || (*ptr >= LABEL_MARKER && *ptr < LABEL_MARKER + N_LABEL_TYPES)) ptr++; else if (!get_token(&ptr, end)) break; } if (last_token_start) { const token_info *ti = lookup_token(last_token_start, end); if (ti->is_punct()) { punct.append(last_token_start, end - last_token_start); line.set_length(last_token_start - start); } }}static void divert_to_temporary_file(){ outfp = xtmpfile();}static void store_citation(reference *ref){ if (ncitations >= citation_max) { if (citation == 0) citation = new reference*[citation_max = 100]; else { reference **old_citation = citation; citation_max *= 2; citation = new reference *[citation_max]; memcpy(citation, old_citation, ncitations*sizeof(reference *)); a_delete old_citation; } } citation[ncitations++] = ref;}static unsigned store_reference(const string &str){ if (reference_hash_table == 0) { reference_hash_table = new reference *[17]; hash_table_size = 17; for (int i = 0; i < hash_table_size; i++) reference_hash_table[i] = 0; } unsigned flags; reference *ref = make_reference(str, &flags); ref->compute_hash_code(); unsigned h = ref->hash(); for (reference **ptr = reference_hash_table + (h % hash_table_size); *ptr != 0; ((ptr == reference_hash_table) ? (ptr = reference_hash_table + hash_table_size - 1) : --ptr)) if (same_reference(**ptr, *ref)) break; if (*ptr != 0) { if (ref->is_merged()) warning("fields ignored because reference already used"); delete ref; ref = *ptr; } else { *ptr = ref; ref->set_number(nreferences); nreferences++; ref->pre_compute_label(); ref->compute_sort_key(); if (nreferences*2 >= hash_table_size) { // Rehash it. reference **old_table = reference_hash_table; int old_size = hash_table_size; hash_table_size = next_size(hash_table_size); reference_hash_table = new reference*[hash_table_size]; int i; for (i = 0; i < hash_table_size; i++) reference_hash_table[i] = 0; for (i = 0; i < old_size; i++) if (old_table[i]) { for (reference **p = (reference_hash_table + (old_table[i]->hash() % hash_table_size)); *p; ((p == reference_hash_table) ? (p = reference_hash_table + hash_table_size - 1) : --p)) ; *p = old_table[i]; } a_delete old_table; } } if (label_in_text) store_citation(ref); return flags;}unsigned immediately_handle_reference(const string &str){ unsigned flags; reference *ref = make_reference(str, &flags); ref->set_number(nreferences); if (label_in_text || label_in_reference) { ref->pre_compute_label(); ref->immediate_compute_label(); } nreferences++; store_citation(ref); return flags;}static void immediately_output_references(){ for (int i = 0; i < ncitations; i++) { reference *ref = citation[i]; if (label_in_reference) { fputs(".ds [F ", outfp); const string &label = ref->get_label(NORMAL_LABEL); if (label.length() > 0 && (label[0] == ' ' || label[0] == '\\' || label[0] == '"')) putc('"', outfp); put_string(label, outfp); putc('\n', outfp); } ref->output(outfp); delete ref; } ncitations = 0;}static void output_citation_group(reference **v, int n, label_type type, FILE *fp){ if (sort_adjacent_labels) { // Do an insertion sort. Usually n will be very small. for (int i = 1; i < n; i++) { int num = v[i]->get_number(); reference *temp = v[i]; for (int j = i - 1; j >= 0 && v[j]->get_number() > num; j--) v[j + 1] = v[j]; v[j + 1] = temp; } } // This messes up if !accumulate. if (accumulate && n > 1) { // remove duplicates int j = 1; for (int i = 1; i < n; i++) if (v[i]->get_label(type) != v[i - 1]->get_label(type)) v[j++] = v[i]; n = j; } string merged_label; for (int i = 0; i < n; i++) { int nmerged = v[i]->merge_labels(v + i + 1, n - i - 1, type, merged_label); if (nmerged > 0) { put_string(merged_label, fp); i += nmerged; } else put_string(v[i]->get_label(type), fp); if (i < n - 1) put_string(sep_label, fp); }}label_processing_state::label_processing_state(reference **p, int n, FILE *f): state(NORMAL), count(0), rptr(p), rcount(n), fp(f){}label_processing_state::~label_processing_state(){ int handled = handle_pending(EOF); assert(!handled); assert(rcount == 0);}int label_processing_state::handle_pending(int c){ switch (state) { case NORMAL: break; case PENDING_LABEL: if (c == POST_LABEL_MARKER) { state = PENDING_LABEL_POST; return 1; } else { output_citation_group(rptr, count, type, fp); rptr += count ; rcount -= count; state = NORMAL; } break; case PENDING_LABEL_POST: if (c == PRE_LABEL_MARKER) { state = PENDING_LABEL_POST_PRE; return 1; } else { output_citation_group(rptr, count, type, fp); rptr += count; rcount -= count; put_string(post_label, fp); state = NORMAL; } break; case PENDING_LABEL_POST_PRE: if (c >= LABEL_MARKER && c < LABEL_MARKER + N_LABEL_TYPES && c - LABEL_MARKER == type) { count += 1; state = PENDING_LABEL; return 1; } else { output_citation_group(rptr, count, type, fp); rptr += count; rcount -= count; put_string(sep_label, fp); state = NORMAL; } break; case PENDING_POST: if (c == PRE_LABEL_MARKER) { put_string(sep_label, fp); state = NORMAL; return 1; } else { put_string(post_label, fp); state = NORMAL; } break; } return 0;}void label_processing_state::process(int c){ if (handle_pending(c)) return; assert(state == NORMAL); switch (c) { case PRE_LABEL_MARKER: put_string(pre_label, fp); state = NORMAL; break; case POST_LABEL_MARKER: state = PENDING_POST; break; case LABEL_MARKER: case LABEL_MARKER + 1: count = 1; state = PENDING_LABEL; type = label_type(c - LABEL_MARKER); break; default: state = NORMAL; putc(c, fp); break; }}extern "C" {static int rcompare(const void *p1, const void *p2){ return compare_reference(**(reference **)p1, **(reference **)p2);}}void output_references(){ assert(accumulate); if (nreferences > 0) { int j = 0; int i; for (i = 0; i < hash_table_size; i++) if (reference_hash_table[i] != 0) reference_hash_table[j++] = reference_hash_table[i]; assert(j == nreferences); for (; j < hash_table_size; j++) reference_hash_table[j] = 0; qsort(reference_hash_table, nreferences, sizeof(reference*), rcompare); for (i = 0; i < nreferences; i++) reference_hash_table[i]->set_number(i); compute_labels(reference_hash_table, nreferences); } if (outfp != stdout) { rewind(outfp); { label_processing_state state(citation, ncitations, stdout); int c; while ((c = getc(outfp)) != EOF) state.process(c); } ncitations = 0; fclose(outfp); outfp = stdout; } if (nreferences > 0) { fputs(".]<\n", outfp); for (int i = 0; i < nreferences; i++) { if (sort_fields.length() > 0) reference_hash_table[i]->print_sort_key_comment(outfp); if (label_in_reference) { fputs(".ds [F ", outfp); const string &label = reference_hash_table[i]->get_label(NORMAL_LABEL); if (label.length() > 0 && (label[0] == ' ' || label[0] == '\\' || label[0] == '"')) putc('"', outfp); put_string(label, outfp); putc('\n', outfp); } reference_hash_table[i]->output(outfp); delete reference_hash_table[i]; reference_hash_table[i] = 0; } fputs(".]>\n", outfp); nreferences = 0; } clear_labels();}static reference *find_reference(const char *query, int query_len){ // This is so that error messages look better. while (query_len > 0 && csspace(query[query_len - 1])) query_len--; string str; for (int i = 0; i < query_len; i++) str += query[i] == '\n' ? ' ' : query[i]; str += '\0'; possibly_load_default_database(); search_list_iterator iter(&database_list, str.contents()); reference_id rid; const char *start; int len; if (!iter.next(&start, &len, &rid)) { error("no matches for `%1'", str.contents()); return 0; } const char *end = start + len; while (start < end) { if (*start == '%') break; while (start < end && *start++ != '\n') ; } if (start >= end) { error("found a reference for `%1' but it didn't contain any fields", str.contents()); return 0; } reference *result = new reference(start, end - start, &rid); if (iter.next(&start, &len, &rid)) warning("multiple matches for `%1'", str.contents()); return result;}static reference *make_reference(const string &str, unsigned *flagsp){ const char *start = str.contents(); const char *end = start + str.length(); const char *ptr = start; while (ptr < end) { if (*ptr == '%') break; while (ptr < end && *ptr++ != '\n') ; } *flagsp = 0; for (; start < ptr; start++) { if (*start == '#') *flagsp = (SHORT_LABEL | (*flagsp & (FORCE_RIGHT_BRACKET | FORCE_LEFT_BRACKET))); else if (*start == '[') *flagsp |= FORCE_LEFT_BRACKET; else if (*start == ']') *flagsp |= FORCE_RIGHT_BRACKET; else if (!csspace(*start)) break; } if (start >= end) { error("empty reference"); return new reference; } reference *database_ref = 0; if (start < ptr) database_ref = find_reference(start, ptr - start); reference *inline_ref = 0; if (ptr < end) inline_ref = new reference(ptr, end - ptr); if (inline_ref) { if (database_ref) { database_ref->merge(*inline_ref); delete inline_ref; return database_ref; } else return inline_ref; } else if (database_ref) return database_ref; else return new reference;}static void do_ref(const string &str){ if (accumulate) (void)store_reference(str); else { (void)immediately_handle_reference(str); immediately_output_references(); }}static void trim_blanks(string &str){ const char *start = str.contents(); const char *end = start + str.length(); while (end > start && end[-1] != '\n' && csspace(end[-1])) --end; str.set_length(end - start);}void do_bib(const char *filename){ FILE *fp; if (strcmp(filename, "-") == 0) fp = stdin; else { errno = 0; fp = fopen(filename, "r"); if (fp == 0) { error("can't open `%1': %2", filename, strerror(errno)); return; } current_filename = filename; } enum { START, MIDDLE, BODY, BODY_START, BODY_BLANK, BODY_DOT } state = START; string body; for (;;) { int c = getc(fp); if (c == EOF) break; if (illegal_input_char(c)) { error("illegal input character code %1", c); continue; } switch (state) { case START: if (c == '%') { body = c; state = BODY; } else if (c != '\n') state = MIDDLE; break; case MIDDLE: if (c == '\n') state = START; break; case BODY: body += c; if (c == '\n') state = BODY_START; break; case BODY_START: if (c == '\n') { do_ref(body); state = START; } else if (c == '.') state = BODY_DOT; else if (csspace(c)) { state = BODY_BLANK; body += c; } else { body += c; state = BODY; } break; case BODY_BLANK: if (c == '\n') { trim_blanks(body); do_ref(body); state = START; } else if (csspace(c)) body += c; else { body += c; state = BODY; } break; case BODY_DOT: if (c == ']') { do_ref(body); state = MIDDLE; } else { body += '.'; body += c; state = c == '\n' ? BODY_START : BODY; } break; default: assert(0); } if (c == '\n') current_lineno++; } switch (state) { case START: case MIDDLE: break; case BODY: body += '\n'; do_ref(body); break; case BODY_DOT: case BODY_START: do_ref(body); break; case BODY_BLANK: trim_blanks(body); do_ref(body); break; } fclose(fp);}// from the Dragon Bookunsigned hash_string(const char *s, int len){ const char *end = s + len; unsigned h = 0, g; while (s < end) { h <<= 4; h += *s++; if ((g = h & 0xf0000000) != 0) { h ^= g >> 24; h ^= g; } } return h;}int next_size(int n){ static const int table_sizes[] = { 101, 503, 1009, 2003, 3001, 4001, 5003, 10007, 20011, 40009, 80021, 160001, 500009, 1000003, 2000003, 4000037, 8000009, 16000057, 32000011, 64000031, 128000003, 0 }; for (const int *p = table_sizes; *p <= n && *p != 0; p++) ; assert(*p != 0); return *p;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -