xref: /original-bsd/contrib/bib/src/locate.c (revision f1d75c93)
1 #ifndef lint
2 static char sccsid[] = "@(#)locate.c	2.7	05/27/93";
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: %s\n", keys);
86 	  allrefs = (char *) calloc(1, sizeof (char));
87 	  if (allrefs==NULL) {
88 	    fprintf(stderr,"locate: insufficient space for references\n");
89 	    exit(1);
90 	    }
91 	  *allrefs= NULL;
92 	  return(allrefs);
93 	  }
94         len= strlen(key);
95         strcat(key," ");
96         alpha_seek(index, key, i_size, 0);
97         key[len]= NULL;                     /*  strip blank off */
98 
99         refcnt= 0;
100         fscanf(index,"%s ", str);
101         if (strcmp(str,key) == 0)
102         {   str[0]= NULL;
103             while (refcnt < maxrefs && fetchref(index, str, &ref) )
104             {   refs[refcnt]= ref;
105                 refcnt++;
106             }
107         }
108 
109         if (refcnt==maxrefs)
110 	    fprintf(stderr,
111 	       "locate: first key (%s) matched too many refs\n", key);
112 
113     /*  intersect the reference sets for remaining keys with first set */
114         while (*keys!=NULL)
115         {   keys= stripkeys(keys, key, max_klen, common);
116             if (*key==NULL) continue;
117 
118             len= strlen(key);
119             strcat(key," ");
120             alpha_seek(index, key, i_size, 0);
121             key[len]= NULL;
122 
123             fscanf(index,"%s ", str);
124             if (strcmp(str,key) != 0)  refcnt= 0;   /*  no matching refs */
125 
126             copied= 0; comp= 0; more= fetchref(index, str, &ref);
127             while (comp < refcnt && more)
128             {   /*  ans= ref-refs[comp]    */
129                     ans= strcmp(ref.reffile, refs[comp].reffile);
130                     if (ans==0)     ans= ref.start-refs[comp].start;
131                     if (ans==0)     ans= ref.length-refs[comp].length;
132                 if (ans<0)  more= fetchref(index, str, &ref);
133                 if (ans==0) { refs[copied]= refs[comp]; comp++; copied++;
134                               more= fetchref(index, str, &ref);}
135                 if (ans>0)  comp++;
136             }
137 
138             refcnt= copied;
139         }
140 
141     total= 0;
142     for (i=0; i<refcnt; i++) {
143         total += refs[i].length+1;
144         if (fflag){
145 	    total += strlen(refs[i].reffile) + 1;
146         }
147     }
148 
149     allrefs= (char *) calloc(total+1, sizeof (char));
150     if (allrefs==NULL)
151     {   fprintf(stderr,"locate: insufficient space for references\n");
152 	exit(1);
153     }
154 
155     /* copy refs into allrefs */
156         next= allrefs;
157         for (i=0; i<refcnt; i++)
158         {   /*  open text */
159                 if (strcmp(oldtext,refs[i].reffile) != 0)
160                 {   strcpy(oldtext,refs[i].reffile);
161 		    if (oldtext[0]=='/')
162 		    {   /* absolute path */
163 			strcpy(str,oldtext);
164 		    } else
165 		    {   /* relative name */
166 			strncpy(str, oldname, pathlen);  str[pathlen]= NULL;
167 			strcat(str, oldtext);
168 		    }
169                     if (text) fclose(text);
170                     text= fopen(str, "r");
171                     if (text==NULL)
172                     {   fprintf(stderr,"locate: cannot open %s\n", str);
173 			strcpy(oldtext, "");
174                         return(NULL);
175                     }
176                 }
177             fseek(text, refs[i].start, 0);
178 	    if (fflag){
179 		strcat(next, refs[i].reffile);
180 		next += strlen(next);
181 		*next++ = '\n';
182 		*next = 0;
183 	    }
184             for (j=0; j<refs[i].length; j++)    *next++ = getc(text);
185             *next++ = '\n';
186         }
187         *next = NULL;
188     return(allrefs);
189 }
190 
191 
192 
193 /*  stripkeys(line,key,max_klen, common):
194         assigns to key the first key in line
195         and returns a pointer to the position following the key
196 */
197 char *stripkeys(line,key,max_klen,common)
198 char *line, *key;
199 int  max_klen;
200 char *common;
201 {   char *p;
202 
203     do
204     {   while (isspace(*line))   line++;
205 
206         p= key;
207         while (*line!=NULL && !isspace(*line))
208         {   *p++ = *line++;
209         }
210         *p= NULL;
211 
212         makekey(key, max_klen, common);
213     }   while (*key==NULL && *line!=NULL);
214     return(line);
215 }
216 
217 /*  read a reference pair from stream into *ref.  if file not given,
218     use oldfile. return 1 if pair found, 0 ow.
219 */
220 int fetchref(stream, oldfile, ref)
221 FILE *stream;
222 char *oldfile;
223 struct reftype *ref;
224 {   char cntl;
225 
226     fscanf(stream, "%c", &cntl);
227     if (cntl=='\n') {return (0);}
228     if (cntl==':')  fscanf(stream, "%s", oldfile);
229     strcpy(ref->reffile, oldfile);
230     fscanf(stream, "%D/%D", &ref->start, &ref->length);
231     return(1);
232 }
233