]> git.pond.sub.org Git - empserver/blob - src/lib/commands/info.c
Update copyright notice
[empserver] / src / lib / commands / info.c
1 /*
2  *  Empire - A multi-player, client/server Internet based war game.
3  *  Copyright (C) 1986-2009, Dave Pare, Jeff Bailey, Thomas Ruschak,
4  *                           Ken Stevens, Steve McClure
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; either version 2 of the License, or
9  *  (at your option) any later version.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  *  ---
21  *
22  *  See files README, COPYING and CREDITS in the root of the source
23  *  tree for related information and legal notices.  It is expected
24  *  that future projects/authors will amend these files as needed.
25  *
26  *  ---
27  *
28  *  info.c: display an info page
29  *
30  *  Known contributors to this file:
31  *     Dave Pare, 1986
32  *     Mike Wise, 1997 - added apropos and case insensitivity
33  *     Doug Hay, 1998
34  *     Steve McClure, 1998-2000
35  *     Ron Koenderink, 2004
36  */
37
38 #include <config.h>
39
40 #include <ctype.h>
41 #include <errno.h>
42 #include <sys/stat.h>
43 #include <stdio.h>
44 #if !defined(_WIN32)
45 #include <dirent.h>
46 #endif
47 #include "commands.h"
48 #include "optlist.h"
49
50 static char *
51 lowerit(char *buf, int n, char *orig)
52 {                               /* converts a string to lower case */
53     /* lower case output buffer */
54     /* size of output buffer */
55     /* input strig */
56     int i;
57     for (i = 0; i < n - 1 && orig[i]; i++)
58         buf[i] = tolower(orig[i]);
59     buf[i] = 0;
60     return buf;
61 }
62
63 #if !defined(_WIN32)
64
65 int
66 info(void)
67 {
68     char buf[255];
69     FILE *fp;
70     char *name;
71     char *tmp_name;
72     struct stat statb;
73     struct dirent *dp;
74     char filename[1024];
75     char last[256];
76     DIR *info_dp;
77     int nmatch = 0;
78     int width = 0;
79     char sep;
80
81     name = player->argp[1];
82     if (name) {
83         /*
84          * don't let sneaky people go outside the info directory
85          */
86         if (NULL != (tmp_name = strrchr(name, '/')))
87             name = tmp_name + 1;
88     }
89     if (!name || !*name)
90         name = "TOP";
91
92     snprintf(filename, sizeof(filename), "%s/%s", infodir, name);
93     fp = fopen(filename, "r");
94     if (fp == NULL) {
95         /* may be a "partial" request.  */
96         info_dp = opendir(infodir);
97         if (info_dp == 0) {
98             pr("Can't open info dir\n");
99             logerror("Can't open info dir \"%s\"\n", infodir);
100             return RET_FAIL;
101         }
102
103         while ((dp = readdir(info_dp)) != 0) {
104             if (strncasecmp(name, dp->d_name, strlen(name)) != 0)
105                 continue;
106             nmatch++;
107             if (nmatch == 1) {
108                 snprintf(last, sizeof(last), "%s", dp->d_name);
109             } else {
110                 if (nmatch == 2) {
111                     pr("`%s' is ambiguous.  The following topics match:\n%s",
112                         name, last);
113                     width = strlen(last);
114                 }
115                 width += 2 + strlen(dp->d_name);
116                 sep = ' ';
117                 if (width > 75) {
118                     sep = '\n';
119                     width = strlen(dp->d_name);
120                 }
121                 pr(",%c%s", sep, dp->d_name);
122             }
123         }
124         closedir(info_dp);
125         if (nmatch == 0) {
126             pr("Sorry, there is no info on %s\n", name);
127             return RET_FAIL;
128         } else if (nmatch > 1) {
129             pr(".\n");
130             return RET_FAIL;
131         }
132         snprintf(filename, sizeof(filename), "%s/%s", infodir,
133                  last);
134         fp = fopen(filename, "r");
135         if (fp == NULL) {
136             pr("Error reading info file for %s\n", name);
137             logerror("Cannot open for \"%s\" info file (%s)",
138                      filename, strerror(errno));
139             return RET_FAIL;
140         }
141     }
142     if (fstat(fileno(fp), &statb) < 0) {
143         pr("Error reading info file for %s\n", name);
144         logerror("Cannot fstat for \"%s\" info file (%s)",
145                  filename, strerror(errno));
146         fclose(fp);
147         return RET_FAIL;
148     }
149     if ((statb.st_mode & S_IFREG) == 0) {
150         pr("Error reading info file for %s\n", name);
151         logerror("The info file \"%s\" is not regular file\n", filename);
152         fclose(fp);
153         return RET_FAIL;
154     }
155
156     while (fgets(buf, sizeof(buf), fp) != 0)
157         pr("%s", buf);
158     (void)fclose(fp);
159     return RET_OK;
160 }
161
162 int
163 apro(void)
164 {
165     FILE *fp;
166     char *name, *lbp;
167     char *fbuf;
168     char *lbuf;
169     struct dirent *dp;
170     char filename[1024];
171     DIR *info_dp;
172     long nf, nhf, nl, nlhl, nhl, nll;
173     int alreadyhit;
174     int lhitlim;
175     struct stat statb;
176
177     if (player->argp[1] == 0 || !*player->argp[1]) {
178         pr("Apropos what?\n");
179         return RET_FAIL;
180     }
181
182     lhitlim = 100;
183     if (player->argp[2]) {
184         lhitlim = atoi(player->argp[2]);
185         if (lhitlim <= 0)
186             lhitlim = 100;
187     }
188
189     info_dp = opendir(infodir);
190     if (info_dp == NULL) {
191         pr("Can't open info dir \n");
192         logerror("Can't open info dir \"%s\"", infodir);
193         return RET_FAIL;
194     }
195
196     fbuf = malloc(256);
197     lbuf = malloc(256);
198     lbp = malloc(256);
199
200     /*
201      *  lower case search string into lbp
202      */
203     name = player->argp[1];
204     lowerit(lbp, 256, name);
205
206     /*
207      *  search
208      */
209     nf = nhf = nl = nhl = 0;
210     while ((dp = readdir(info_dp)) != 0) {
211         if (dp->d_name[0] == '.')
212             continue;
213         snprintf(filename, sizeof(filename), "%s/%s", infodir,
214                  dp->d_name);
215         fp = fopen(filename, "r");
216         alreadyhit = 0;
217         nll = nlhl = 0;
218         if (fp != NULL) {
219             if (fstat(fileno(fp), &statb) < 0) {
220                 logerror("Cannot stat for \"%s\" info file (%s)",
221                          filename, strerror(errno));
222                 fclose(fp);
223                 continue;
224             }
225             if ((statb.st_mode & S_IFREG) == 0) {
226                 logerror("The info file \"%s\" is not regular file\n",
227                          filename);
228                 fclose(fp);
229                 continue;
230             }
231             while (fgets(fbuf, 256, fp)) {
232                 lowerit(lbuf, 256, fbuf);
233                 if (strstr(lbuf, lbp)) {
234                     if (!alreadyhit) {
235                         pr("*** %s ***\n", dp->d_name);
236                         alreadyhit = 1;
237                         nhf++;
238                     }
239                     fbuf[74] = '\n';
240                     fbuf[75] = 0;
241                     pr("   %s", fbuf);
242                     nlhl++;
243                     /*
244                      * break if too many lines
245                      */
246                     if ((nhl + nlhl) > lhitlim)
247                         break;
248                 }
249                 nll++;
250             }
251             fclose(fp);
252         }
253         nhl += nlhl;
254         nl += nll;
255         nf++;
256         if (nhl > lhitlim)
257             break;
258     }
259     closedir(info_dp);
260
261     free(fbuf);
262     free(lbuf);
263     free(lbp);
264
265     if ((nhl) > lhitlim) {
266         pr("Limit of %d lines exceeded\n", lhitlim);
267     }
268     pr("Found %s in %ld of %ld files and in %ld of %ld lines\n",
269        name, nhf, nf, nhl, nl);
270     return RET_OK;
271 }
272
273 #else  /* _WIN32 */
274
275 int
276 info(void)
277 {
278     char buf[255];
279     FILE *fp;
280     char *name;
281     char *tmp_name;
282     char filename[1024];
283     char last[256];
284     int nmatch = 0;
285     int width = 0;
286     char sep;
287
288     name = player->argp[1];
289     if (name) {
290         /*
291          * don't let sneaky people go outside the info directory
292          */
293         if (NULL != (tmp_name = strrchr(name, '/')))
294             name = tmp_name + 1;
295         if (NULL != (tmp_name = strrchr(name, '\\')))
296             name = tmp_name + 1;
297         if (NULL != (tmp_name = strrchr(name, ':')))
298             name = tmp_name + 1;
299     }
300     if (!name || !*name)
301         name = "TOP";
302
303     snprintf(filename, sizeof(filename) - 1, "%s\\%s", infodir, name);
304     fp = fopen(filename, "rb");
305     if (fp == NULL) {
306         /* may be a "partial" request.  */
307         HANDLE hDir;
308         WIN32_FIND_DATA fData;
309         strcat(filename, "*");
310         hDir = FindFirstFile(filename, &fData);
311         if (hDir == INVALID_HANDLE_VALUE) {
312             switch (GetLastError()) {
313             case ERROR_FILE_NOT_FOUND:
314                 pr("Sorry, there is no info on %s\n", name);
315                 break;
316             case ERROR_PATH_NOT_FOUND:
317                 pr("Can't open info dir\n");
318                 logerror("Can't open info dir \"%s\"", infodir);
319                 break;
320             default:
321                 pr("Error reading info dir\n");
322                 logerror("Error (%lu) reading info dir(%s)\\file(%s)",
323                     GetLastError(), infodir, filename);
324             }
325             return RET_FAIL;
326         }
327         do {
328             if ((fData.dwFileAttributes != (DWORD)-1) &&
329                 ((fData.dwFileAttributes == FILE_ATTRIBUTE_NORMAL) ||
330                  (fData.dwFileAttributes == FILE_ATTRIBUTE_ARCHIVE) ||
331                  (fData.dwFileAttributes == FILE_ATTRIBUTE_READONLY)) &&
332                 (strncasecmp(name, fData.cFileName, strlen(name)) == 0)) {
333                 nmatch++;
334                 if (nmatch == 1) {
335                     snprintf(last, sizeof(last), "%s", fData.cFileName);
336                 } else {
337                     if (nmatch == 2) {
338                         pr("`%s' is ambiguous.  The following topics match:\n%s",
339                             name, last);
340                         width = strlen(last);
341                     }
342                     width += 2 + strlen(fData.cFileName);
343                     sep = ' ';
344                     if (width > 75) {
345                         sep = '\n';
346                         width = strlen(fData.cFileName);
347                     }
348                     pr(",%c%s", sep, fData.cFileName);
349                 }
350             }
351         } while (FindNextFile(hDir, &fData));
352         FindClose(hDir);
353         if (nmatch == 0) {
354             pr("Sorry, there is no info on %s\n", name);
355             return RET_FAIL;
356         } else if (nmatch > 1) {
357             pr(".\n");
358             return RET_FAIL;
359         }
360         snprintf(filename, sizeof(filename), "%s/%s",
361                   infodir, last);
362         fp = fopen(filename, "rb");
363         if (fp == NULL) {
364             pr("Error reading info file for %s\n", name);
365             logerror("Cannot open for \"%s\" info file (%s)",
366                      filename, strerror(errno));
367             return RET_FAIL;
368         }
369     } else {
370         DWORD fAttrib = GetFileAttributes(filename);
371         if ((fAttrib == (DWORD)-1) || /* INVALID_FILE_ATTRIBUTES */
372             ((fAttrib != FILE_ATTRIBUTE_NORMAL) &&
373              (fAttrib != FILE_ATTRIBUTE_ARCHIVE) &&
374              (fAttrib != FILE_ATTRIBUTE_READONLY))) {
375             pr("Error reading info file for %s\n", name);
376             logerror("The info file \"%s\" is not regular file\n",
377                      filename);
378             fclose(fp);
379             return RET_FAIL;
380         }
381     }
382
383     while (fgets(buf, sizeof(buf), fp) != 0)
384         pr("%s", buf);
385     (void)fclose(fp);
386     return RET_OK;
387 }
388
389 int
390 apro(void)
391 {
392     HANDLE hDir;
393     WIN32_FIND_DATA fData;
394     FILE *fp;
395     char *name, *lbp;
396     char *fbuf;
397     char *lbuf;
398     char filename[1024];
399     long nf, nhf, nl, nlhl, nhl, nll;
400     int alreadyhit;
401     int lhitlim;
402
403     if (player->argp[1] == 0 || !*player->argp[1]) {
404         pr("Apropos what?\n");
405         return RET_FAIL;
406     }
407
408     lhitlim = 100;
409     if (player->argp[2]) {
410         lhitlim = atoi(player->argp[2]);
411         if (lhitlim <= 0)
412             lhitlim = 100;
413     }
414
415     snprintf(filename, sizeof(filename), "%s\\*",infodir);
416     hDir = FindFirstFile(filename, &fData);
417     if (hDir == INVALID_HANDLE_VALUE) {
418         if (GetLastError() == ERROR_PATH_NOT_FOUND) {
419             pr("Can't open info dir\n");
420             logerror("Can't open info dir \"%s\"", infodir);
421         } else {
422             pr("Error reading info dir\n");
423             logerror("Error (%lu) reading info dir(%s)\\file(%s)",
424                 GetLastError(), infodir, filename);
425         }
426         return RET_FAIL;
427     }
428
429     fbuf = malloc(256);
430     lbuf = malloc(256);
431     lbp = malloc(256);
432
433     /*
434      *  lower case search string into lbp
435      */
436     name = player->argp[1];
437     lowerit(lbp, 256, name);
438
439     /*
440      *  search
441      */
442     nf = nhf = nl = nhl = 0;
443     do {
444         if ((fData.dwFileAttributes != (DWORD)-1) &&
445             ((fData.dwFileAttributes == FILE_ATTRIBUTE_NORMAL) ||
446              (fData.dwFileAttributes == FILE_ATTRIBUTE_ARCHIVE) ||
447              (fData.dwFileAttributes == FILE_ATTRIBUTE_READONLY))) {
448             snprintf(filename, sizeof(filename), "%s\\%s", infodir,
449                       fData.cFileName);
450             fp = fopen(filename, "rb");
451             alreadyhit = 0;
452             nll = nlhl = 0;
453             if (fp != NULL) {
454                 while (fgets(fbuf, 256, fp)) {
455                     lowerit(lbuf, 256, fbuf);
456                     if (strstr(lbuf, lbp)) {
457                         if (!alreadyhit) {
458                             pr("*** %s ***\n", fData.cFileName);
459                             alreadyhit = 1;
460                             nhf++;
461                         }
462                         fbuf[74] = '\n';
463                         fbuf[75] = 0;
464                         pr("   %s", fbuf);
465                         nlhl++;
466                         /*
467                          * break if too many lines
468                          */
469                         if ((nhl + nlhl) > lhitlim)
470                             break;
471                     }
472                     nll++;
473                 }
474                 fclose(fp);
475             }
476             nhl += nlhl;
477             nl += nll;
478             nf++;
479             if (nhl > lhitlim)
480                 break;
481         }
482     } while (FindNextFile(hDir, &fData));
483     FindClose(hDir);
484
485     free(fbuf);
486     free(lbuf);
487     free(lbp);
488
489     if ((nhl) > lhitlim) {
490         pr("Limit of %d lines exceeded\n", lhitlim);
491     }
492     pr("Found %s in %ld of %ld files and in %ld of %ld lines\n",
493        name, nhf, nf, nhl, nl);
494     return RET_OK;
495 }
496
497 #endif  /* _WIN32 */