xref: /original-bsd/contrib/bib/src/locate.c (revision e59fb703)
1 #ifndef lint
2 static char sccsid[] = "@(#)locate.c	2.6	03/05/87";
3 #endif not lint
4 #
5 
6 # include   "stdio.h"
7 # include   "streams.h"
8 # include   "ctype.h"
9 # define    maxrefs      1000
10 
11 struct reftype{
12     char reffile[maxstr];
13     long int start, length;
14     };
15 
16 char *calloc();
17 char *rindex();
18 char *stripkeys();
19 int   fetchref();
20 
21 /*  locate(keys, name, max_klen, common):
22         Returns a string containing all references pointed to by name
23         that contain all keys in keys.  Common is name of common word file.
24     Pointer returned comes from calloc.  Use free to return storage.
25     NB A zero length string returned if nothing is found.
26        A NULL pointer indicates an error accessing the file "name".
27 */
28 int fflag;	/* set if want the reference string to have the file name*/
29 char *locate(keys,name,max_klen,common)
30 char *keys, *name, *common;
31 int  max_klen;          /* max key length */
32 {   static  char oldname[maxstr] = "";  /* oldname is name of stream index */
33     static  FILE *index = NULL;
34     static  long int i_size;            /* size of index                   */
35     static  char oldtext[maxstr];       /* oldtext is the path to stream   */
36     static  FILE *text = NULL;		/*  text.  if it is a relative     */
37     static  int  pathlen;		/*  path, it is relative to index  */
38 					/*  directory.                     */
39 					/* oldname[0..pathlen-1] is index  */
40 					/*  directory                      */
41     int  len;
42     char key[maxstr];                   /* refs[i] is a line of index for  */
43     struct reftype  refs[maxrefs];      /* all keys up to key              */
44 
45     int  refcnt, copied, comp;          /* refcnt = # of refs               */
46                                         /* copied = # of refs copied        */
47                                         /* comp   = # of refs compared      */
48     struct reftype ref;
49     char   str[maxstr];
50     int    more;
51 
52     long int ans;
53     int i,j;
54     unsigned total;
55     char *allrefs, *next;               /* all refs (separated by null line)*/
56     char *p;
57 
58     /*  open index */
59         if  (strcmp(oldname,name)!=0)
60         {   if (index) fclose(index);
61             if (text) fclose(text);
62             strcpy(oldname,name);
63             strcpy(oldtext,"");
64             /*  determine pathlen   */
65                 p= rindex(oldname, '/');
66                 if      (p!=NULL)           pathlen= p-oldname+1;
67                 else                        pathlen= 0;
68 
69             index= fopen(oldname,"r");
70             if (index==NULL)
71             {   fprintf(stderr, "locate: cannot open %s\n", oldname);
72 		strcpy(oldname, "");
73                 return(NULL);
74             }
75             else
76             {   fseek(index,0L,2);     /*  seeks last newline      */
77                 i_size= ftell(index);
78             }
79 
80         }
81 
82     /*  load references to first key  */
83         keys= stripkeys(keys,key, max_klen, common);
84 	if (*key==NULL)
85 	{ fprintf(stderr,"locate: no keys for citation\n");
86 	  allrefs = (char *) calloc(1, sizeof (char));
87 	  if (allrefs==NULL)
88 	  {  fprintf(stderr,
89 	       "locate: insufficient space for references\n");
90 	     exit(1);
91 	  }
92 	  *allrefs= NULL;
93 	  return(allrefs);
94 	}
95         len= strlen(key);
96         strcat(key," ");
97         alpha_seek(index, key, i_size, 0);
98         key[len]= NULL;                     /*  strip blank off */
99 
100         refcnt= 0;
101         fscanf(index,"%s ", str);
102         if (strcmp(str,key) == 0)
103         {   str[0]= NULL;
104             while (refcnt < maxrefs && fetchref(index, str, &ref) )
105             {   refs[refcnt]= ref;
106                 refcnt++;
107             }
108         }
109 
110         if (refcnt==maxrefs)
111             fprintf(stderr,
112 		"locate: first key (%s) matched too many refs\n", key);
113 
114     /*  intersect the reference sets for remaining keys with first set */
115         while (*keys!=NULL)
116         {   keys= stripkeys(keys, key, max_klen, common);
117             if (*key==NULL) continue;
118 
119             len= strlen(key);
120             strcat(key," ");
121             alpha_seek(index, key, i_size, 0);
122             key[len]= NULL;
123 
124             fscanf(index,"%s ", str);
125             if (strcmp(str,key) != 0)  refcnt= 0;   /*  no matching refs */
126 
127             copied= 0; comp= 0; more= fetchref(index, str, &ref);
128             while (comp < refcnt && more)
129             {   /*  ans= ref-refs[comp]    */
130                     ans= strcmp(ref.reffile, refs[comp].reffile);
131                     if (ans==0)     ans= ref.start-refs[comp].start;
132                     if (ans==0)     ans= ref.length-refs[comp].length;
133                 if (ans<0)  more= fetchref(index, str, &ref);
134                 if (ans==0) { refs[copied]= refs[comp]; comp++; copied++;
135                               more= fetchref(index, str, &ref);}
136                 if (ans>0)  comp++;
137             }
138 
139             refcnt= copied;
140         }
141 
142     total= 0;
143     for (i=0; i<refcnt; i++) {
144         total += refs[i].length+1;
145         if (fflag){
146 	    total += strlen(refs[i].reffile) + 1;
147         }
148     }
149 
150     allrefs= (char *) calloc(total+1, sizeof (char));
151     if (allrefs==NULL)
152     {   fprintf(stderr, "locate: insufficient space for references\n");
153 	exit(1);
154     }
155 
156     /* copy refs into allrefs */
157         next= allrefs;
158         for (i=0; i<refcnt; i++)
159         {   /*  open text */
160                 if (strcmp(oldtext,refs[i].reffile) != 0)
161                 {   strcpy(oldtext,refs[i].reffile);
162 		    if (oldtext[0]=='/')
163 		    {   /* absolute path */
164 			strcpy(str,oldtext);
165 		    } else
166 		    {   /* relative name */
167 			strncpy(str, oldname, pathlen);  str[pathlen]= NULL;
168 			strcat(str, oldtext);
169 		    }
170                     if (text) fclose(text);
171                     text= fopen(str, "r");
172                     if (text==NULL)
173                     {   fprintf(stderr, "locate: cannot open %s\n", str);
174 			strcpy(oldtext, "");
175                         return(NULL);
176                     }
177                 }
178             fseek(text, refs[i].start, 0);
179 	    if (fflag){
180 		strcat(next, refs[i].reffile);
181 		next += strlen(next);
182 		*next++ = '\n';
183 		*next = 0;
184 	    }
185             for (j=0; j<refs[i].length; j++)    *next++ = getc(text);
186             *next++ = '\n';
187         }
188         *next = NULL;
189     return(allrefs);
190 }
191 
192 
193 
194 /*  stripkeys(line,key,max_klen, common):
195         assigns to key the first key in line
196         and returns a pointer to the position following the key
197 */
198 char *stripkeys(line,key,max_klen,common)
199 char *line, *key;
200 int  max_klen;
201 char *common;
202 {   char *p;
203 
204     do
205     {   while (isspace(*line))   line++;
206 
207         p= key;
208         while (*line!=NULL && !isspace(*line))
209         {   *p++ = *line++;
210         }
211         *p= NULL;
212 
213         makekey(key, max_klen, common);
214     }   while (*key==NULL && *line!=NULL);
215     return(line);
216 }
217 
218 /*  read a reference pair from stream into *ref.  if file not given,
219     use oldfile. return 1 if pair found, 0 ow.
220 */
221 int fetchref(stream, oldfile, ref)
222 FILE *stream;
223 char *oldfile;
224 struct reftype *ref;
225 {   char cntl;
226 
227     fscanf(stream, "%c", &cntl);
228     if (cntl=='\n') {return (0);}
229     if (cntl==':')  fscanf(stream, "%s", oldfile);
230     strcpy(ref->reffile, oldfile);
231     fscanf(stream, "%D/%D", &ref->start, &ref->length);
232     return(1);
233 }
234