]> git.pond.sub.org Git - empserver/blob - src/lib/commands/info.c
Change info not to prepend a header line to the info page
[empserver] / src / lib / commands / info.c
1 /*
2  *  Empire - A multi-player, client/server Internet based war game.
3  *  Copyright (C) 1986-2008, 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 #else
47 #include <windows.h>
48 #endif
49 #include "commands.h"
50 #include "optlist.h"
51
52 static char *
53 lowerit(char *buf, int n, char *orig)
54 {                               /* converts a string to lower case */
55     /* lower case output buffer */
56     /* size of output buffer */
57     /* input strig */
58     int i;
59     for (i = 0; i < n - 1 && orig[i]; i++)
60         buf[i] = tolower(orig[i]);
61     buf[i] = 0;
62     return buf;
63 }
64
65 #if !defined(_WIN32)
66
67 int
68 info(void)
69 {
70     char buf[255];
71     FILE *fp;
72     char *name;
73     char *tmp_name;
74     struct stat statb;
75     struct dirent *dp;
76     char filename[1024];
77     char last[256];
78     DIR *info_dp;
79     int nmatch = 0;
80     int width = 0;
81     char sep;
82
83     name = player->argp[1];
84     if (name) {
85         /*
86          * don't let sneaky people go outside the info directory
87          */
88         if (NULL != (tmp_name = strrchr(name, '/')))
89             name = tmp_name + 1;
90     }
91     if (!name || !*name)
92         name = "TOP";
93
94     snprintf(filename, sizeof(filename), "%s/%s", infodir, name);
95     fp = fopen(filename, "r");
96     if (fp == NULL) {
97         /* may be a "partial" request.  */
98         info_dp = opendir(infodir);
99         if (info_dp == 0) {
100             pr("Can't open info dir\n");
101             logerror("Can't open info dir \"%s\"\n", infodir);
102             return RET_FAIL;
103         }
104
105         while ((dp = readdir(info_dp)) != 0) {
106             if (strncasecmp(name, dp->d_name, strlen(name)) != 0)
107                 continue;
108             nmatch++;
109             if (nmatch == 1) {
110                 snprintf(last, sizeof(last), "%s", dp->d_name);
111             } else {
112                 if (nmatch == 2) {
113                     pr("`%s' is ambiguous.  The following topics match:\n%s",
114                         name, last);
115                     width = strlen(last);
116                 }
117                 width += 2 + strlen(dp->d_name);
118                 sep = ' ';
119                 if (width > 75) {
120                     sep = '\n';
121                     width = strlen(dp->d_name);
122                 }
123                 pr(",%c%s", sep, dp->d_name);
124             }
125         }
126         closedir(info_dp);
127         if (nmatch == 0) {
128             pr("Sorry, there is no info on %s\n", name);
129             return RET_FAIL;
130         } else if (nmatch > 1) {
131             pr(".\n");
132             return RET_FAIL;
133         }
134         snprintf(filename, sizeof(filename), "%s/%s", infodir,
135                  last);
136         fp = fopen(filename, "r");
137         if (fp == NULL) {
138             pr("Error reading info file for %s\n", name);
139             logerror("Cannot open for \"%s\" info file (%s)",
140                      filename, strerror(errno));
141             return RET_FAIL;
142         }
143     }
144     if (fstat(fileno(fp), &statb) < 0) {
145         pr("Error reading info file for %s\n", name);
146         logerror("Cannot fstat for \"%s\" info file (%s)",
147                  filename, strerror(errno));
148         fclose(fp);
149         return RET_FAIL;
150     }
151     if ((statb.st_mode & S_IFREG) == 0) {
152         pr("Error reading info file for %s\n", name);
153         logerror("The info file \"%s\" is not regular file\n", filename);
154         fclose(fp);
155         return RET_FAIL;
156     }
157
158     while (fgets(buf, sizeof(buf), fp) != 0)
159         pr("%s", buf);
160     (void)fclose(fp);
161     return RET_OK;
162 }
163
164 int
165 apro(void)
166 {
167     FILE *fp;
168     char *name, *lbp;
169     char *fbuf;
170     char *lbuf;
171     struct dirent *dp;
172     char filename[1024];
173     DIR *info_dp;
174     long nf, nhf, nl, nlhl, nhl, nll;
175     int alreadyhit;
176     int lhitlim;
177     struct stat statb;
178
179     if (player->argp[1] == 0 || !*player->argp[1]) {
180         pr("Apropos what?\n");
181         return RET_FAIL;
182     }
183
184     lhitlim = 100;
185     if (player->argp[2]) {
186         lhitlim = atoi(player->argp[2]);
187         if (lhitlim <= 0)
188             lhitlim = 100;
189     }
190
191     info_dp = opendir(infodir);
192     if (info_dp == NULL) {
193         pr("Can't open info dir \n");
194         logerror("Can't open info dir \"%s\"", infodir);
195         return RET_FAIL;
196     }
197
198     fbuf = malloc(256);
199     lbuf = malloc(256);
200     lbp = malloc(256);
201
202     /*
203      *  lower case search string into lbp
204      */
205     name = player->argp[1];
206     lowerit(lbp, 256, name);
207
208     /*
209      *  search
210      */
211     nf = nhf = nl = nhl = 0;
212     while ((dp = readdir(info_dp)) != 0) {
213         if (dp->d_name[0] == '.')
214             continue;
215         snprintf(filename, sizeof(filename), "%s/%s", infodir,
216                  dp->d_name);
217         fp = fopen(filename, "r");
218         alreadyhit = 0;
219         nll = nlhl = 0;
220         if (fp != NULL) {
221             if (fstat(fileno(fp), &statb) < 0) {
222                 logerror("Cannot stat for \"%s\" info file (%s)",
223                          filename, strerror(errno));
224                 fclose(fp);
225                 continue;
226             }
227             if ((statb.st_mode & S_IFREG) == 0) {
228                 logerror("The info file \"%s\" is not regular file\n",
229                          filename);
230                 fclose(fp);
231                 continue;
232             }
233             while (fgets(fbuf, 256, fp)) {
234                 lowerit(lbuf, 256, fbuf);
235                 if (strstr(lbuf, lbp)) {
236                     if (!alreadyhit) {
237                         pr("*** %s ***\n", dp->d_name);
238                         alreadyhit = 1;
239                         nhf++;
240                     }
241                     fbuf[74] = '\n';
242                     fbuf[75] = 0;
243                     pr("   %s", fbuf);
244                     nlhl++;
245                     /*
246                      * break if too many lines
247                      */
248                     if ((nhl + nlhl) > lhitlim)
249                         break;
250                 }
251                 nll++;
252             }
253             fclose(fp);
254         }
255         nhl += nlhl;
256         nl += nll;
257         nf++;
258         if (nhl > lhitlim)
259             break;
260     }
261     closedir(info_dp);
262
263     free(fbuf);
264     free(lbuf);
265     free(lbp);
266
267     if ((nhl) > lhitlim) {
268         pr("Limit of %d lines exceeded\n", lhitlim);
269     }
270     pr("Found %s in %ld of %ld files and in %ld of %ld lines\n",
271        name, nhf, nf, nhl, nl);
272     return RET_OK;
273 }
274
275 #else  /* _WIN32 */
276
277 int
278 info(void)
279 {
280     char buf[255];
281     FILE *fp;
282     char *name;
283     char *tmp_name;
284     char filename[1024];
285     char last[256];
286     int nmatch = 0;
287     int width = 0;
288     char sep;
289
290     name = player->argp[1];
291     if (name) {
292         /*
293          * don't let sneaky people go outside the info directory
294          */
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         if (NULL != (tmp_name = strrchr(name, ':')))
300             name = tmp_name + 1;
301     }
302     if (!name || !*name)
303         name = "TOP";
304
305     snprintf(filename, sizeof(filename) - 1, "%s\\%s", infodir, name);
306     fp = fopen(filename, "rb");
307     if (fp == NULL) {
308         /* may be a "partial" request.  */
309         HANDLE hDir;
310         WIN32_FIND_DATA fData;
311         strcat(filename, "*");
312         hDir = FindFirstFile(filename, &fData);
313         if (hDir == INVALID_HANDLE_VALUE) {
314             switch (GetLastError()) {
315             case ERROR_FILE_NOT_FOUND:
316                 pr("Sorry, there is no info on %s\n", name);
317                 break;
318             case ERROR_PATH_NOT_FOUND:
319                 pr("Can't open info dir\n");
320                 logerror("Can't open info dir \"%s\"", infodir);
321                 break;
322             default:
323                 pr("Error reading info dir\n");
324                 logerror("Error (%lu) reading info dir(%s)\\file(%s)",
325                     GetLastError(), infodir, filename);
326             }
327             return RET_FAIL;
328         }
329         do {
330             if ((fData.dwFileAttributes != (DWORD)-1) &&
331                 ((fData.dwFileAttributes == FILE_ATTRIBUTE_NORMAL) ||
332                  (fData.dwFileAttributes == FILE_ATTRIBUTE_ARCHIVE) ||
333                  (fData.dwFileAttributes == FILE_ATTRIBUTE_READONLY)) &&
334                 (strncasecmp(name, fData.cFileName, strlen(name)) == 0)) {
335                 nmatch++;
336                 if (nmatch == 1) {
337                     snprintf(last, sizeof(last), "%s", fData.cFileName);
338                 } else {
339                     if (nmatch == 2) {
340                         pr("`%s' is ambiguous.  The following topics match:\n%s",
341                             name, last);
342                         width = strlen(last);
343                     }
344                     width += 2 + strlen(fData.cFileName);
345                     sep = ' ';
346                     if (width > 75) {
347                         sep = '\n';
348                         width = strlen(fData.cFileName);
349                     }
350                     pr(",%c%s", sep, fData.cFileName);
351                 }
352             }
353         } while (FindNextFile(hDir, &fData));
354         FindClose(hDir);
355         if (nmatch == 0) {
356             pr("Sorry, there is no info on %s\n", name);
357             return RET_FAIL;
358         } else if (nmatch > 1) {
359             pr(".\n");
360             return RET_FAIL;
361         }
362         snprintf(filename, sizeof(filename), "%s/%s",
363                   infodir, last);
364         fp = fopen(filename, "rb");
365         if (fp == NULL) {
366             pr("Error reading info file for %s\n", name);
367             logerror("Cannot open for \"%s\" info file (%s)",
368                      filename, strerror(errno));
369             return RET_FAIL;
370         }
371     } else {
372         DWORD fAttrib = GetFileAttributes(filename);
373         if ((fAttrib == (DWORD)-1) || /* INVALID_FILE_ATTRIBUTES */
374             ((fAttrib != FILE_ATTRIBUTE_NORMAL) &&
375              (fAttrib != FILE_ATTRIBUTE_ARCHIVE) &&
376              (fAttrib != FILE_ATTRIBUTE_READONLY))) {
377             pr("Error reading info file for %s\n", name);
378             logerror("The info file \"%s\" is not regular file\n",
379                      filename);
380             fclose(fp);
381             return RET_FAIL;
382         }
383     }
384
385     while (fgets(buf, sizeof(buf), fp) != 0)
386         pr("%s", buf);
387     (void)fclose(fp);
388     return RET_OK;
389 }
390
391 int
392 apro(void)
393 {
394     HANDLE hDir;
395     WIN32_FIND_DATA fData;
396     FILE *fp;
397     char *name, *lbp;
398     char *fbuf;
399     char *lbuf;
400     char filename[1024];
401     long nf, nhf, nl, nlhl, nhl, nll;
402     int alreadyhit;
403     int lhitlim;
404
405     if (player->argp[1] == 0 || !*player->argp[1]) {
406         pr("Apropos what?\n");
407         return RET_FAIL;
408     }
409
410     lhitlim = 100;
411     if (player->argp[2]) {
412         lhitlim = atoi(player->argp[2]);
413         if (lhitlim <= 0)
414             lhitlim = 100;
415     }
416
417     snprintf(filename, sizeof(filename), "%s\\*",infodir);
418     hDir = FindFirstFile(filename, &fData);
419     if (hDir == INVALID_HANDLE_VALUE) {
420         if (GetLastError() == ERROR_PATH_NOT_FOUND) {
421             pr("Can't open info dir\n");
422             logerror("Can't open info dir \"%s\"", infodir);
423         } else {
424             pr("Error reading info dir\n");
425             logerror("Error (%lu) reading info dir(%s)\\file(%s)",
426                 GetLastError(), infodir, filename);
427         }
428         return RET_FAIL;
429     }
430
431     fbuf = malloc(256);
432     lbuf = malloc(256);
433     lbp = malloc(256);
434
435     /*
436      *  lower case search string into lbp
437      */
438     name = player->argp[1];
439     lowerit(lbp, 256, name);
440
441     /*
442      *  search
443      */
444     nf = nhf = nl = nhl = 0;
445     do {
446         if ((fData.dwFileAttributes != (DWORD)-1) &&
447             ((fData.dwFileAttributes == FILE_ATTRIBUTE_NORMAL) ||
448              (fData.dwFileAttributes == FILE_ATTRIBUTE_ARCHIVE) ||
449              (fData.dwFileAttributes == FILE_ATTRIBUTE_READONLY))) {
450             snprintf(filename, sizeof(filename), "%s\\%s", infodir,
451                       fData.cFileName);
452             fp = fopen(filename, "rb");
453             alreadyhit = 0;
454             nll = nlhl = 0;
455             if (fp != NULL) {
456                 while (fgets(fbuf, 256, fp)) {
457                     lowerit(lbuf, 256, fbuf);
458                     if (strstr(lbuf, lbp)) {
459                         if (!alreadyhit) {
460                             pr("*** %s ***\n", fData.cFileName);
461                             alreadyhit = 1;
462                             nhf++;
463                         }
464                         fbuf[74] = '\n';
465                         fbuf[75] = 0;
466                         pr("   %s", fbuf);
467                         nlhl++;
468                         /*
469                          * break if too many lines
470                          */
471                         if ((nhl + nlhl) > lhitlim)
472                             break;
473                     }
474                     nll++;
475                 }
476                 fclose(fp);
477             }
478             nhl += nlhl;
479             nl += nll;
480             nf++;
481             if (nhl > lhitlim)
482                 break;
483         }
484     } while (FindNextFile(hDir, &fData));
485     FindClose(hDir);
486
487     free(fbuf);
488     free(lbuf);
489     free(lbp);
490
491     if ((nhl) > lhitlim) {
492         pr("Limit of %d lines exceeded\n", lhitlim);
493     }
494     pr("Found %s in %ld of %ld files and in %ld of %ld lines\n",
495        name, nhf, nf, nhl, nl);
496     return RET_OK;
497 }
498
499 #endif  /* _WIN32 */