]> 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-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_SYS;
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_SYS;
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_SYS;
156     }
157     pr("Information on:  %s    Last modification date: %s",
158        name, ctime(&statb.st_mtime));
159     while (fgets(buf, sizeof(buf), fp) != 0)
160         pr("%s", buf);
161     (void)fclose(fp);
162     return RET_OK;
163 }
164
165 int
166 apro(void)
167 {
168     FILE *fp;
169     char *name, *lbp;
170     char *fbuf;
171     char *lbuf;
172     struct dirent *dp;
173     char filename[1024];
174     DIR *info_dp;
175     long nf, nhf, nl, nlhl, nhl, nll;
176     int alreadyhit;
177     int lhitlim;
178     struct stat statb;
179
180     if (player->argp[1] == 0 || !*player->argp[1]) {
181         pr("Apropos what?\n");
182         return RET_FAIL;
183     }
184
185     lhitlim = 100;
186     if (player->argp[2]) {
187         lhitlim = atoi(player->argp[2]);
188         if (lhitlim <= 0)
189             lhitlim = 100;
190     }
191
192     info_dp = opendir(infodir);
193     if (info_dp == NULL) {
194         pr("Can't open info dir \n");
195         logerror("Can't open info dir \"%s\"", infodir);
196         return RET_SYS;
197     }
198
199     fbuf = malloc(256);
200     lbuf = malloc(256);
201     lbp = malloc(256);
202
203     /*
204      *  lower case search string into lbp
205      */
206     name = player->argp[1];
207     lowerit(lbp, 256, name);
208
209     /*
210      *  search
211      */
212     nf = nhf = nl = nhl = 0;
213     while ((dp = readdir(info_dp)) != 0) {
214         if (dp->d_name[0] == '.')
215             continue;
216         snprintf(filename, sizeof(filename), "%s/%s", infodir,
217                  dp->d_name);
218         fp = fopen(filename, "r");
219         alreadyhit = 0;
220         nll = nlhl = 0;
221         if (fp != NULL) {
222             if (fstat(fileno(fp), &statb) < 0) {
223                 logerror("Cannot stat for \"%s\" info file (%s)",
224                          filename, strerror(errno));
225                 fclose(fp);
226                 continue;
227             }
228             if ((statb.st_mode & S_IFREG) == 0) {
229                 logerror("The info file \"%s\" is not regular file\n",
230                          filename);
231                 fclose(fp);
232                 continue;
233             }
234             while (fgets(fbuf, 256, fp)) {
235                 lowerit(lbuf, 256, fbuf);
236                 if (strstr(lbuf, lbp)) {
237                     if (!alreadyhit) {
238                         pr("*** %s ***\n", dp->d_name);
239                         alreadyhit = 1;
240                         nhf++;
241                     }
242                     fbuf[74] = '\n';
243                     fbuf[75] = 0;
244                     pr("   %s", fbuf);
245                     nlhl++;
246                     /*
247                      * break if too many lines
248                      */
249                     if ((nhl + nlhl) > lhitlim)
250                         break;
251                 }
252                 nll++;
253             }
254             fclose(fp);
255         }
256         nhl += nlhl;
257         nl += nll;
258         nf++;
259         if (nhl > lhitlim)
260             break;
261     }
262     closedir(info_dp);
263
264     free(fbuf);
265     free(lbuf);
266     free(lbp);
267
268     if ((nhl) > lhitlim) {
269         pr("Limit of %d lines exceeded\n", lhitlim);
270     }
271     pr("Found %s in %ld of %ld files and in %ld of %ld lines\n",
272        name, nhf, nf, nhl, nl);
273     return RET_OK;
274 }
275
276 #else  /* _WIN32 */
277
278 int
279 info(void)
280 {
281     char buf[255];
282     FILE *fp;
283     char *name;
284     char *tmp_name;
285     char filename[1024];
286     char last[256];
287     int nmatch = 0;
288     int width = 0;
289     char sep;
290
291     name = player->argp[1];
292     if (name) {
293         /*
294          * don't let sneaky people go outside the info directory
295          */
296         if (NULL != (tmp_name = strrchr(name, '/')))
297             name = tmp_name + 1;
298         if (NULL != (tmp_name = strrchr(name, '\\')))
299             name = tmp_name + 1;
300         if (NULL != (tmp_name = strrchr(name, ':')))
301             name = tmp_name + 1;
302     }
303     if (!name || !*name)
304         name = "TOP";
305
306     snprintf(filename, sizeof(filename) - 1, "%s\\%s", infodir, name);
307     fp = fopen(filename, "rb");
308     if (fp == NULL) {
309         /* may be a "partial" request.  */
310         HANDLE hDir;
311         WIN32_FIND_DATA fData;
312         strcat(filename, "*");
313         hDir = FindFirstFile(filename, &fData);
314         if (hDir == INVALID_HANDLE_VALUE) {
315             switch (GetLastError()) {
316             case ERROR_FILE_NOT_FOUND:
317                 pr("Sorry, there is no info on %s\n", name);
318                 return RET_FAIL;
319                 break;
320             case ERROR_PATH_NOT_FOUND:
321                 pr("Can't open info dir\n");
322                 logerror("Can't open info dir \"%s\"", infodir);
323                 break;
324             default:
325                 pr("Error reading info dir\n");
326                 logerror("Error (%lu) reading info dir(%s)\\file(%s)",
327                     GetLastError(), infodir, filename);
328             }
329             return RET_SYS;
330         }
331         do {
332             if ((fData.dwFileAttributes != (DWORD)-1) &&
333                 ((fData.dwFileAttributes == FILE_ATTRIBUTE_NORMAL) ||
334                  (fData.dwFileAttributes == FILE_ATTRIBUTE_ARCHIVE) ||
335                  (fData.dwFileAttributes == FILE_ATTRIBUTE_READONLY)) &&
336                 (strncasecmp(name, fData.cFileName, strlen(name)) == 0)) {
337                 nmatch++;
338                 if (nmatch == 1) {
339                     snprintf(last, sizeof(last), "%s", fData.cFileName);
340                 } else {
341                     if (nmatch == 2) {
342                         pr("`%s' is ambiguous.  The following topics match:\n%s",
343                             name, last);
344                         width = strlen(last);
345                     }
346                     width += 2 + strlen(fData.cFileName);
347                     sep = ' ';
348                     if (width > 75) {
349                         sep = '\n';
350                         width = strlen(fData.cFileName);
351                     }
352                     pr(",%c%s", sep, fData.cFileName);
353                 }
354             }
355         } while (FindNextFile(hDir, &fData));
356         FindClose(hDir);
357         if (nmatch == 0) {
358             pr("Sorry, there is no info on %s\n", name);
359             return RET_FAIL;
360         } else if (nmatch > 1) {
361             pr(".\n");
362             return RET_FAIL;
363         }
364         snprintf(filename, sizeof(filename), "%s/%s",
365                   infodir, last);
366         fp = fopen(filename, "rb");
367         if (fp == NULL) {
368             pr("Error reading info file for %s\n", name);
369             logerror("Cannot open for \"%s\" info file (%s)",
370                      filename, strerror(errno));
371             return RET_FAIL;
372         }
373     }
374     else {
375         DWORD fAttrib = GetFileAttributes(filename);
376         if ((fAttrib == (DWORD)-1) || /* INVALID_FILE_ATTRIBUTES */
377             ((fAttrib != FILE_ATTRIBUTE_NORMAL) &&
378              (fAttrib != FILE_ATTRIBUTE_ARCHIVE) &&
379              (fAttrib != FILE_ATTRIBUTE_READONLY))) {
380             pr("Error reading info file for %s\n", name);
381             logerror("The info file \"%s\" is not regular file\n",
382                      filename);
383             fclose(fp);
384             return RET_SYS;
385         }
386     }
387
388     pr("Information on:  %s", name);
389     while (fgets(buf, sizeof(buf), fp) != 0)
390         pr("%s", buf);
391     (void)fclose(fp);
392     return RET_OK;
393 }
394
395 int
396 apro(void)
397 {
398     HANDLE hDir;
399     WIN32_FIND_DATA fData;
400     FILE *fp;
401     char *name, *lbp;
402     char *fbuf;
403     char *lbuf;
404     char filename[1024];
405     long nf, nhf, nl, nlhl, nhl, nll;
406     int alreadyhit;
407     int lhitlim;
408
409     if (player->argp[1] == 0 || !*player->argp[1]) {
410         pr("Apropos what?\n");
411         return RET_FAIL;
412     }
413
414     lhitlim = 100;
415     if (player->argp[2]) {
416         lhitlim = atoi(player->argp[2]);
417         if (lhitlim <= 0)
418             lhitlim = 100;
419     }
420
421     snprintf(filename, sizeof(filename), "%s\\*",infodir);
422     hDir = FindFirstFile(filename, &fData);
423     if (hDir == INVALID_HANDLE_VALUE) {
424         if (GetLastError() == ERROR_PATH_NOT_FOUND) {
425             pr("Can't open info dir\n");
426             logerror("Can't open info dir \"%s\"", infodir);
427         } else {
428             pr("Error reading info dir\n");
429             logerror("Error (%lu) reading info dir(%s)\\file(%s)",
430                 GetLastError(), infodir, filename);
431         }
432         return RET_SYS;
433     }
434
435     fbuf = malloc(256);
436     lbuf = malloc(256);
437     lbp = malloc(256);
438
439     /*
440      *  lower case search string into lbp
441      */
442     name = player->argp[1];
443     lowerit(lbp, 256, name);
444
445     /*
446      *  search
447      */
448     nf = nhf = nl = nhl = 0;
449     do {
450         if ((fData.dwFileAttributes != (DWORD)-1) &&
451             ((fData.dwFileAttributes == FILE_ATTRIBUTE_NORMAL) ||
452              (fData.dwFileAttributes == FILE_ATTRIBUTE_ARCHIVE) ||
453              (fData.dwFileAttributes == FILE_ATTRIBUTE_READONLY))) {
454             snprintf(filename, sizeof(filename), "%s\\%s", infodir,
455                       fData.cFileName);
456             fp = fopen(filename, "rb");
457             alreadyhit = 0;
458             nll = nlhl = 0;
459             if (fp != NULL) {
460                 while (fgets(fbuf, 256, fp)) {
461                     lowerit(lbuf, 256, fbuf);
462                     if (strstr(lbuf, lbp)) {
463                         if (!alreadyhit) {
464                             pr("*** %s ***\n", fData.cFileName);
465                             alreadyhit = 1;
466                             nhf++;
467                         }
468                         fbuf[74] = '\n';
469                         fbuf[75] = 0;
470                         pr("   %s", fbuf);
471                         nlhl++;
472                         /*
473                          * break if too many lines
474                          */
475                         if ((nhl + nlhl) > lhitlim)
476                             break;
477                     }
478                     nll++;
479                 }
480                 fclose(fp);
481             }
482             nhl += nlhl;
483             nl += nll;
484             nf++;
485             if (nhl > lhitlim)
486                 break;
487         }
488     } while (FindNextFile(hDir, &fData));
489     FindClose(hDir);
490
491     free(fbuf);
492     free(lbuf);
493     free(lbp);
494
495     if ((nhl) > lhitlim) {
496         pr("Limit of %d lines exceeded\n", lhitlim);
497     }
498     pr("Found %s in %ld of %ld files and in %ld of %ld lines\n",
499        name, nhf, nf, nhl, nl);
500     return RET_OK;
501 }
502
503 #endif  /* _WIN32 */