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

📄 linear.cc

📁 早期freebsd实现
💻 CC
字号:
// -*- 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 <string.h>#include <stdlib.h>#include <assert.h>#include <errno.h>#include "posix.h"#include "lib.h"#include "errarg.h"#include "error.h"#include "cset.h"#include "cmap.h"#include "refid.h"#include "search.h"class file_buffer {  char *buffer;  char *bufend;public:  file_buffer();  ~file_buffer();  int load(int fd, const char *filename);  const char *get_start() const;  const char *get_end() const;};typedef unsigned char uchar;static uchar map[256];static uchar inv_map[256][3];struct map_init {  map_init();};static map_init the_map_init;map_init::map_init(){  for (int i = 0; i < 256; i++)    map[i] = csalnum(i) ? cmlower(i) : '\0';  for (i = 0; i < 256; i++) {    if (cslower(i)) {      inv_map[i][0] = i;      inv_map[i][1] = cmupper(i);      inv_map[i][2] = '\0';    }    else if (csdigit(i)) {      inv_map[i][0] = i;      inv_map[i][1] = 0;    }    else      inv_map[i][0] = '\0';  }}class bmpattern {  char *pat;  int len;  int delta[256];public:  bmpattern(const char *pattern, int pattern_length);  ~bmpattern();  const char *search(const char *p, const char *end) const;  int length() const;};bmpattern::bmpattern(const char *pattern, int pattern_length): len(pattern_length){  pat = new char[len];  int i;  for (i = 0; i < len; i++)    pat[i] = map[uchar(pattern[i])];  for (i = 0; i < 256; i++)    delta[i] = len;  for (i = 0; i < len; i++)    for (const unsigned char *inv = inv_map[uchar(pat[i])]; *inv; inv++)      delta[*inv] = len - i - 1;}const char *bmpattern::search(const char *buf, const char *end) const{  int buflen = end - buf;  if (len > buflen)    return 0;  const char *strend;  if (buflen > len*4)    strend = end - len*4;  else    strend = buf;  const char *k = buf + len - 1;  const int *del = delta;  const char *pattern = pat;  for (;;) {    while (k < strend) {      int t = del[uchar(*k)];      if (!t)	break;      k += t;      k += del[uchar(*k)];      k += del[uchar(*k)];    }    while (k < end && del[uchar(*k)] != 0)      k++;    if (k == end)      break;    int j = len - 1;    const char *s = k;    for (;;) {      if (j == 0)	return s;      if (map[uchar(*--s)] != pattern[--j])	break;    }    k++;  }  return 0;}bmpattern::~bmpattern(){  a_delete pat;}inline int bmpattern::length() const{  return len;}static const char *find_end(const char *bufend, const char *p);const char *linear_searcher::search_and_check(const bmpattern *key,  const char *buf, const char *bufend, const char **start) const{  assert(buf[-1] == '\n');  assert(bufend[-1] == '\n');  const char *ptr = buf;  for (;;) {    const char *found = key->search(ptr, bufend);    if (!found)      break;    if (check_match(buf, bufend, found, key->length(), &ptr, start))      return found;  }  return 0;}static const char *skip_field(const char *end, const char *p){  for (;;)    if (*p++ == '\n') {      if (p == end || *p == '%')	break;      for (const char *q = p; *q == ' ' || *q == '\t'; q++)	;      if (*q == '\n')	break;      p = q + 1;    }  return p;}static const char *find_end(const char *bufend, const char *p){  for (;;)    if (*p++ == '\n') {      if (p == bufend)	break;      for (const char *q = p; *q == ' ' || *q == '\t'; q++)	;      if (*q == '\n')	break;      p = q + 1;    }  return p;}int linear_searcher::check_match(const char *buf, const char *bufend,				 const char *match, int matchlen,				 const char **cont, const char **start) const{  *cont = match + 1;  // The user is required to supply only the first truncate_len characters  // of the key.  If truncate_len <= 0, he must supply all the key.  if ((truncate_len <= 0 || matchlen < truncate_len)      && map[uchar(match[matchlen])] != '\0')    return 0;  // The character before the match must not be an alphanumeric  // character (unless the alphanumeric character follows one or two  // percent characters at the beginning of the line), nor must it be  // a percent character at the beginning of a line, nor a percent  // character following a percent character at the beginning of a  // line.  switch (match - buf) {  case 0:    break;  case 1:    if (match[-1] == '%' || map[uchar(match[-1])] != '\0')      return 0;    break;  case 2:    if (map[uchar(match[-1])] != '\0' && match[-2] != '%')      return 0;    if (match[-1] == '%'	&& (match[-2] == '\n' || match[-2] == '%'))      return 0;    break;  default:    if (map[uchar(match[-1])] != '\0'	&& !(match[-2] == '%'	     && (match[-3] == '\n'		 || (match[-3] == '%' && match[-4] == '\n'))))      return 0;    if (match[-1] == '%'	&& (match[-2] == '\n'	    || (match[-2] == '%' && match[-3] == '\n')))      return 0;  }      const char *p = match;  int had_percent = 0;  for (;;) {    if (*p == '\n') {      if (!had_percent && p[1] == '%') {	if (p[2] != '\0' && strchr(ignore_fields, p[2]) != 0) {	  *cont = skip_field(bufend, match + matchlen);	  return 0;	}	if (!start)	  break;	had_percent = 1;      }      if (p <= buf) {	if (start)	  *start = p + 1;	return 1;      }      for (const char *q = p - 1; *q == ' ' || *q == '\t'; q--)	;      if (*q == '\n') {	if (start)	  *start = p + 1;	break;      }      p = q;    }    p--;  }  return 1;}file_buffer::file_buffer(): buffer(0), bufend(0){}file_buffer::~file_buffer(){  a_delete buffer;}const char *file_buffer::get_start() const{  return buffer ? buffer + 4 : 0;}const char *file_buffer::get_end() const{  return bufend;}int file_buffer::load(int fd, const char *filename){  struct stat sb;  if (fstat(fd, &sb) < 0)    error("can't fstat `%1': %2", filename, strerror(errno));  else if ((sb.st_mode & S_IFMT) != S_IFREG)    error("`%1' is not a regular file", filename);  else {    // We need one character extra at the beginning for an additional newline    // used as a sentinel.  We get 4 instead so that the read buffer will be    // word-aligned.  This seems to make the read slightly faster.  We also    // need one character at the end also for an addional newline used as a    // sentinel.    int size = int(sb.st_size);    buffer = new char[size + 4 + 1];    int nread = read(fd, buffer + 4, size);    if (nread < 0)      error("error reading `%1': %2", filename, strerror(errno));    else if (nread != size)      error("size of `%1' decreased", filename);    else {      char c;      nread = read(fd, &c, 1);      if (nread != 0)	error("size of `%1' increased", filename);      else if (memchr(buffer + 4, '\0', size < 1024 ? size : 1024) != 0)	error("database `%1' is a binary file", filename);      else {	close(fd);	buffer[3] = '\n';	bufend = buffer + 4 + size;	if (bufend[-1] != '\n')	  *bufend++ = '\n';	return 1;      }    }    a_delete buffer;    buffer = 0;  }  close(fd);  return 0;}linear_searcher::linear_searcher(const char *query, int query_len,				 const char *ign, int trunc): keys(0), nkeys(0), truncate_len(trunc), ignore_fields(ign){  const char *query_end = query + query_len;  int nk = 0;  const char *p;  for (p = query; p < query_end; p++)    if (map[uchar(*p)] != '\0'	&& (p[1] == '\0' || map[uchar(p[1])] == '\0'))      nk++;  if (nk == 0)    return;  keys = new bmpattern*[nk];  p = query;  for (;;) {    while (p < query_end && map[uchar(*p)] == '\0')      p++;    if (p == query_end)      break;    const char *start = p;    while (p < query_end && map[uchar(*p)] != '\0')      p++;    keys[nkeys++] = new bmpattern(start, p - start);  }  assert(nkeys <= nk);  if (nkeys == 0) {    a_delete keys;    keys = 0;  }}linear_searcher::~linear_searcher(){  for (int i = 0; i < nkeys; i++)    delete keys[i];  a_delete keys;}int linear_searcher::search(const char *buffer, const char *bufend,			    const char **startp, int *lengthp) const{  assert(bufend - buffer > 0);  assert(buffer[-1] == '\n');  assert(bufend[-1] == '\n');  if (nkeys == 0)    return 0;  for (;;) {    const char *refstart;    const char *found = search_and_check(keys[0], buffer, bufend, &refstart);    if (!found)      break;    const char *refend = find_end(bufend, found + keys[0]->length());    for (int i = 1; i < nkeys; i++)      if (!search_and_check(keys[i], refstart, refend))	break;    if (i >= nkeys) {      *startp = refstart;      *lengthp = refend - refstart;      return 1;    }    buffer = refend;  }  return 0;}class linear_search_item : public search_item {  file_buffer fbuf;public:  linear_search_item(const char *filename, int fid);  ~linear_search_item();  int load(int fd);  search_item_iterator *make_search_item_iterator(const char *);  friend class linear_search_item_iterator;};class linear_search_item_iterator : public search_item_iterator {  linear_search_item *lsi;  int pos;public:  linear_search_item_iterator(linear_search_item *, const char *query);  ~linear_search_item_iterator();  int next(const linear_searcher &, const char **ptr, int *lenp,	   reference_id *ridp);};search_item *make_linear_search_item(int fd, const char *filename, int fid){  linear_search_item *item = new linear_search_item(filename, fid);  if (!item->load(fd)) {    delete item;    return 0;  }  else    return item;}linear_search_item::linear_search_item(const char *filename, int fid): search_item(filename, fid){}linear_search_item::~linear_search_item(){}int linear_search_item::load(int fd){  return fbuf.load(fd, name);}search_item_iterator *linear_search_item::make_search_item_iterator(  const char *query){  return new linear_search_item_iterator(this, query);}linear_search_item_iterator::linear_search_item_iterator(  linear_search_item *p, const char *): lsi(p), pos(0){}linear_search_item_iterator::~linear_search_item_iterator(){}int linear_search_item_iterator::next(const linear_searcher &searcher,				      const char **startp, int *lengthp,				      reference_id *ridp){  const char *bufstart = lsi->fbuf.get_start();  const char *bufend = lsi->fbuf.get_end();  const char *ptr = bufstart + pos;  if (ptr < bufend && searcher.search(ptr, bufend, startp, lengthp)) {    pos = *startp + *lengthp - bufstart;    if (ridp)      *ridp = reference_id(lsi->filename_id, *startp - bufstart);    return 1;  }  else    return 0;}

⌨️ 快捷键说明

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