⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ref.cc

📁 早期freebsd实现
💻 CC
📖 第 1 页 / 共 2 页
字号:
// -*- 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 underthe terms of the GNU General Public License as published by the FreeSoftware Foundation; either version 2, or (at your option) any laterversion.groff is distributed in the hope that it will be useful, but WITHOUT ANYWARRANTY; without even the implied warranty of MERCHANTABILITY orFITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public Licensefor more details.You should have received a copy of the GNU General Public License alongwith groff; see the file COPYING.  If not, write to the Free SoftwareFoundation, 675 Mass Ave, Cambridge, MA 02139, USA. */     #include "refer.h"#include "refid.h"#include "ref.h"#include "token.h"static const char *find_day(const char *, const char *, const char **);static int find_month(const char *start, const char *end);static void abbreviate_names(string &);#define DEFAULT_ARTICLES "the\000a\000an"     string articles(DEFAULT_ARTICLES, sizeof(DEFAULT_ARTICLES));// Multiple occurrences of fields are separated by FIELD_SEPARATOR.const char FIELD_SEPARATOR = '\0';const char MULTI_FIELD_NAMES[] = "AE";const char *AUTHOR_FIELDS = "AQ";enum { OTHER, JOURNAL_ARTICLE, BOOK, ARTICLE_IN_BOOK, TECH_REPORT, BELL_TM };const char *reference_types[] = {  "other",  "journal-article",  "book",  "article-in-book",  "tech-report",  "bell-tm",};static string temp_fields[256];reference::reference(const char *start, int len, reference_id *ridp): no(-1), field(0), nfields(0), h(0), merged(0), label_ptr(0),  computed_authors(0), last_needed_author(-1), nauthors(-1){  for (int i = 0; i < 256; i++)    field_index[i] = NULL_FIELD_INDEX;  if (ridp)    rid = *ridp;  if (start == 0)    return;  if (len <= 0)    return;  const char *end = start + len;  const char *ptr = start;  assert(*ptr == '%');  while (ptr < end) {    if (ptr + 1 < end && ptr[1] != '\0'	&& ((ptr[1] != '%' && ptr[1] == annotation_field)	    || (ptr + 2 < end && ptr[1] == '%' && ptr[2] != '\0'		&& discard_fields.search(ptr[2]) < 0))) {      if (ptr[1] == '%')	ptr++;      string &f = temp_fields[(unsigned char)ptr[1]];      ptr += 2;      while (ptr < end && csspace(*ptr))	ptr++;      for (;;) {	for (;;) {	  if (ptr >= end) {	    f += '\n';	    break;	  }	  f += *ptr;	  if (*ptr++ == '\n')	    break;	}	if (ptr >= end || *ptr == '%')	  break;      }    }    else if (ptr + 1 < end && ptr[1] != '\0' && ptr[1] != '%'	     && discard_fields.search(ptr[1]) < 0) {      string &f = temp_fields[(unsigned char)ptr[1]];      if (f.length() > 0) {	if (strchr(MULTI_FIELD_NAMES, ptr[1]) != 0)	  f += FIELD_SEPARATOR;	else	  f.clear();      }      ptr += 2;      if (ptr < end) {	if (*ptr == ' ')	  ptr++;	for (;;) {	  const char *p = ptr;	  while (ptr < end && *ptr != '\n')	    ptr++;	  // strip trailing white space	  const char *q = ptr;	  while (q > p && q[-1] != '\n' && csspace(q[-1]))	    q--;	  while (p < q)	    f += *p++;	  if (ptr >= end)	    break;	  ptr++;	  if (ptr >= end)	    break;	  if (*ptr == '%')	    break;	  f += ' ';	}      }    }    else {      // skip this field      for (;;) {	while (ptr < end && *ptr++ != '\n')	  ;	if (ptr >= end || *ptr == '%')	  break;      }    }  }  for (i = 0; i < 256; i++)    if (temp_fields[i].length() > 0)      nfields++;  field = new string[nfields];  int j = 0;  for (i = 0; i < 256; i++)    if (temp_fields[i].length() > 0) {      field[j].move(temp_fields[i]);      if (abbreviate_fields.search(i) >= 0)	abbreviate_names(field[j]);      field_index[i] = j;      j++;    }}reference::~reference(){  if (nfields > 0)    ad_delete(nfields) field;}// ref is the inline, this is the database refvoid reference::merge(reference &ref){  int i;  for (i = 0; i < 256; i++)    if (field_index[i] != NULL_FIELD_INDEX)      temp_fields[i].move(field[field_index[i]]);  for (i = 0; i < 256; i++)    if (ref.field_index[i] != NULL_FIELD_INDEX)      temp_fields[i].move(ref.field[ref.field_index[i]]);  for (i = 0; i < 256; i++)    field_index[i] = NULL_FIELD_INDEX;  int old_nfields = nfields;  nfields = 0;  for (i = 0; i < 256; i++)    if (temp_fields[i].length() > 0)      nfields++;  if (nfields != old_nfields) {    if (old_nfields > 0)      ad_delete(old_nfields) field;    field = new string[nfields];  }  int j = 0;  for (i = 0; i < 256; i++)    if (temp_fields[i].length() > 0) {      field[j].move(temp_fields[i]);      field_index[i] = j;      j++;    }  merged = 1;}void reference::insert_field(unsigned char c, string &s){  assert(s.length() > 0);  if (field_index[c] != NULL_FIELD_INDEX) {    field[field_index[c]].move(s);    return;  }  assert(field_index[c] == NULL_FIELD_INDEX);  string *old_field = field;  field = new string[nfields + 1];  int pos = 0;  for (int i = 0; i < int(c); i++)    if (field_index[i] != NULL_FIELD_INDEX)      pos++;  for (i = 0; i < pos; i++)    field[i].move(old_field[i]);  field[pos].move(s);  for (i = pos; i < nfields; i++)    field[i + 1].move(old_field[i]);  if (nfields > 0)    ad_delete(nfields) old_field;  nfields++;  field_index[c] = pos;  for (i = c + 1; i < 256; i++)    if (field_index[i] != NULL_FIELD_INDEX)      field_index[i] += 1;}void reference::delete_field(unsigned char c){  if (field_index[c] == NULL_FIELD_INDEX)    return;  string *old_field = field;  field = new string[nfields - 1];  for (int i = 0; i < int(field_index[c]); i++)    field[i].move(old_field[i]);  for (i = field_index[c]; i < nfields - 1; i++)    field[i].move(old_field[i + 1]);  if (nfields > 0)    ad_delete(nfields) old_field;  nfields--;  field_index[c] = NULL_FIELD_INDEX;  for (i = c + 1; i < 256; i++)    if (field_index[i] != NULL_FIELD_INDEX)      field_index[i] -= 1;}    void reference::compute_hash_code(){  if (!rid.is_null())    h = rid.hash();  else {    h = 0;    for (int i = 0; i < nfields; i++)      if (field[i].length() > 0) {	h <<= 4;	h ^= hash_string(field[i].contents(), field[i].length());      }  }}void reference::set_number(int n){  no = n;}const char SORT_SEP = '\001';const char SORT_SUB_SEP = '\002';const char SORT_SUB_SUB_SEP = '\003';// sep specifies additional word separatorsvoid sortify_words(const char *s, const char *end, const char *sep,		   string &result){  int non_empty = 0;  int need_separator = 0;  for (;;) {    const char *token_start = s;    if (!get_token(&s, end))      break;    if ((s - token_start == 1	 && (*token_start == ' '	     || *token_start == '\n'	     || (sep && *token_start != '\0'		 && strchr(sep, *token_start) != 0)))	|| (s - token_start == 2	    && token_start[0] == '\\' && token_start[1] == ' ')) {      if (non_empty)	need_separator = 1;    }    else {      const token_info *ti = lookup_token(token_start, s);      if (ti->sortify_non_empty(token_start, s)) {	if (need_separator) {	  result += ' ';	  need_separator = 0;	}	ti->sortify(token_start, s, result);	non_empty = 1;      }    }  }}void sortify_word(const char *s, const char *end, string &result){  for (;;) {    const char *token_start = s;    if (!get_token(&s, end))      break;    const token_info *ti = lookup_token(token_start, s);    ti->sortify(token_start, s, result);  }}void sortify_other(const char *s, int len, string &key){  sortify_words(s, s + len, 0, key);}void sortify_title(const char *s, int len, string &key){  const char *end = s + len;  for (; s < end && (*s == ' ' || *s == '\n'); s++)     ;  const char *ptr = s;  for (;;) {    const char *token_start = ptr;    if (!get_token(&ptr, end))      break;    if (ptr - token_start == 1	&& (*token_start == ' ' || *token_start == '\n'))      break;  }  if (ptr < end) {    int first_word_len = ptr - s - 1;    const char *ae = articles.contents() + articles.length();    for (const char *a = articles.contents();	 a < ae;	 a = strchr(a, '\0') + 1)      if (first_word_len == strlen(a)) {	for (int j = 0; j < first_word_len; j++)	  if (a[j] != cmlower(s[j]))	    break;	if (j >= first_word_len) {	  s = ptr;	  for (; s < end && (*s == ' ' || *s == '\n'); s++)	    ;	  break;	}      }  }  sortify_words(s, end, 0, key);}void sortify_name(const char *s, int len, string &key){  const char *last_name_end;  const char *last_name = find_last_name(s, s + len, &last_name_end);  sortify_word(last_name, last_name_end, key);  key += SORT_SUB_SUB_SEP;  if (last_name > s)    sortify_words(s, last_name, ".", key);  key += SORT_SUB_SUB_SEP;  if (last_name_end < s + len)    sortify_words(last_name_end, s + len, ".,", key);}void sortify_date(const char *s, int len, string &key){  const char *year_end;  const char *year_start = find_year(s, s + len, &year_end);  if (!year_start) {    // Things without years are often `forthcoming', so it makes sense    // that they sort after things with explicit years.    key += 'A';    sortify_words(s, s + len, 0, key);    return;  }  int n = year_end - year_start;  while (n < 4) {    key += '0';    n++;  }  while (year_start < year_end)    key += *year_start++;  int m = find_month(s, s + len);  if (m < 0)    return;  key += 'A' + m;  const char *day_end;  const char *day_start = find_day(s, s + len, &day_end);  if (!day_start)    return;  if (day_end - day_start == 1)    key += '0';  while (day_start < day_end)    key += *day_start++;}// SORT_{SUB,SUB_SUB}_SEP can creep in from use of @ in label specification.void sortify_label(const char *s, int len, string &key){  const char *end = s + len;  for (;;) {    for (const char *ptr = s;	 ptr < end && *ptr != SORT_SUB_SEP && *ptr != SORT_SUB_SUB_SEP;	 ptr++)      ;    if (ptr > s)      sortify_words(s, ptr, 0, key);    s = ptr;    if (s >= end)      break;    key += *s++;  }}void reference::compute_sort_key(){  if (sort_fields.length() == 0)    return;  sort_fields += '\0';  const char *sf = sort_fields.contents();  while (*sf != '\0') {    if (sf > sort_fields)      sort_key += SORT_SEP;    char f = *sf++;    int n = 1;    if (*sf == '+') {      n = INT_MAX;      sf++;    }    else if (csdigit(*sf)) {      char *ptr;      long l = strtol(sf, &ptr, 10);      if (l == 0 && ptr == sf)	;      else {	sf = ptr;	if (l < 0) {	  n = 1;	}	else {	  n = int(l);	}      }    }    if (f == '.')      sortify_label(label.contents(), label.length(), sort_key);    else if (f == AUTHOR_FIELDS[0])      sortify_authors(n, sort_key);    else      sortify_field(f, n, sort_key);  }  sort_fields.set_length(sort_fields.length() - 1);}void reference::sortify_authors(int n, string &result) const{  for (const char *p = AUTHOR_FIELDS; *p != '\0'; p++)    if (contains_field(*p)) {      sortify_field(*p, n, result);      return;    }  sortify_field(AUTHOR_FIELDS[0], n, result);}void reference::canonicalize_authors(string &result) const{  int len = result.length();  sortify_authors(INT_MAX, result);  if (result.length() > len)    result += SORT_SUB_SEP;}void reference::sortify_field(unsigned char f, int n, string &result) const{  typedef void (*sortify_t)(const char *, int, string &);  sortify_t sortifier = sortify_other;  switch (f) {  case 'A':  case 'E':    sortifier = sortify_name;    break;  case 'D':    sortifier = sortify_date;    break;  case 'B':  case 'J':  case 'T':    sortifier = sortify_title;    break;  }  int fi = field_index[(unsigned char)f];  if (fi != NULL_FIELD_INDEX) {    string &str = field[fi];    const char *start = str.contents();    const char *end = start + str.length();    for (int i = 0; i < n && start < end; i++) {      const char *p = start;      while (start < end && *start != FIELD_SEPARATOR)	start++;      if (i > 0)	result += SORT_SUB_SEP;      (*sortifier)(p, start - p, result);      if (start < end)	start++;    }  }}int compare_reference(const reference &r1, const reference &r2){  assert(r1.no >= 0);  assert(r2.no >= 0);  const char *s1 = r1.sort_key.contents();  int n1 = r1.sort_key.length();  const char *s2 = r2.sort_key.contents();  int n2 = r2.sort_key.length();  for (; n1 > 0 && n2 > 0; --n1, --n2, ++s1, ++s2)    if (*s1 != *s2)      return (int)(unsigned char)*s1 - (int)(unsigned char)*s2;  if (n2 > 0)    return -1;  if (n1 > 0)    return 1;  return r1.no - r2.no;}int same_reference(const reference &r1, const reference &r2){  if (!r1.rid.is_null() && r1.rid == r2.rid)    return 1;  if (r1.h != r2.h)    return 0;  if (r1.nfields != r2.nfields)    return 0;  int i = 0;   for (i = 0; i < 256; i++)    if (r1.field_index != r2.field_index)      return 0;  for (i = 0; i < r1.nfields; i++)    if (r1.field[i] != r2.field[i])      return 0;  return 1;}const char *find_last_name(const char *start, const char *end,			   const char **endp){  const char *ptr = start;  const char *last_word = start;  for (;;) {    const char *token_start = ptr;    if (!get_token(&ptr, end))      break;    if (ptr - token_start == 1) {      if (*token_start == ',') {	*endp = token_start;	return last_word;      }      else if (*token_start == ' ' || *token_start == '\n') {	if (ptr < end && *ptr != ' ' && *ptr != '\n')	  last_word = ptr;      }    }  }  *endp = end;  return last_word;}void abbreviate_name(const char *ptr, const char *end, string &result){  const char *last_name_end;  const char *last_name_start = find_last_name(ptr, end, &last_name_end);  int need_period = 0;  for (;;) {    const char *token_start = ptr;    if (!get_token(&ptr, last_name_start))      break;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -