]> git.pond.sub.org Git - empserver/blob - src/lib/commands/info.c
Break inclusion cycle: prototypes.h and commands.h included each
[empserver] / src / lib / commands / info.c
1 /*
2  *  Empire - A multi-player, client/server Internet based war game.
3  *  Copyright (C) 1986-2006, 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 #if !defined(_WIN32)
44 #include <dirent.h>
45 #else
46 #include <windows.h>
47 #endif
48 #include "commands.h"
49 #include "optlist.h"
50
51 static char *
52 lowerit(char *buf, int n, char *orig)
53 {                               /* converts a string to lower case */
54     /* lower case output buffer */
55     /* size of output buffer */
56     /* input strig */
57     int i;
58     for (i = 0; i < n - 1 && orig[i]; i++)
59         buf[i] = tolower(orig[i]);
60     buf[i] = 0;
61     return buf;
62 }
63
64 #if !defined(_WIN32)
65
66 int
67 info(void)
68 {
69     char buf[255];
70     FILE *fp;
71     char *name;
72     char *tmp_name;
73     struct stat statb;
74     struct dirent *dp;
75     char filename[1024];
76     char last[256];
77     DIR *info_dp;
78     int nmatch = 0;
79     int width = 0;
80     char sep;
81  
82     name = player->argp[1];
83     if (name) {
84         /*
85          * don't let sneaky people go outside the info directory
86          */
87         if (NULL != (tmp_name = strrchr(name, '/')))
88             name = tmp_name + 1;
89     }
90     if (!name || !*name)
91         name = "TOP";
92  
93     snprintf(filename, sizeof(filename), "%s/%s", infodir, name);
94     fp = fopen(filename, "r");
95     if (fp == NULL) {
96         /* may be a "partial" request.  */
97         info_dp = opendir(infodir);
98         if (info_dp == 0) {
99             pr("Can't open info dir\n");
100             logerror("Can't open info dir \"%s\"\n", infodir);
101             return RET_SYS;
102         }
103
104         while ((dp = readdir(info_dp)) != 0) {
105             if (strncasecmp(name, dp->d_name, strlen(name)) != 0)
106                 continue;
107             nmatch++;
108             if (nmatch == 1) {
109                 snprintf(last, sizeof(last), "%s", dp->d_name);
110             } else {
111                 if (nmatch == 2) {
112                     pr("`%s' is ambiguous.  The following topics match:\n%s",
113                         name, last);
114                     width = strlen(last);
115                 }
116                 width += 2 + strlen(dp->d_name);
117                 sep = ' ';
118                 if (width > 75) {
119                     sep = '\n';
120                     width = strlen(dp->d_name);
121                 }
122                 pr(",%c%s", sep, dp->d_name);
123             }
124         }
125         closedir(info_dp);
126         if (nmatch == 0) {
127             pr("Sorry, there is no info on %s\n", name);
128             return RET_FAIL;
129         } else if (nmatch > 1) {
130             pr(".\n");
131             return RET_FAIL;
132         }
133         snprintf(filename, sizeof(filename), "%s/%s", infodir,
134                  last);
135         fp = fopen(filename, "r");
136         if (fp == NULL) {
137             pr("Error reading info file for %s\n", name);
138             logerror("Cannot open for \"%s\" info file (%s)",
139                      filename, strerror(errno));
140             return RET_FAIL;
141         }
142     }
143     if (fstat(fileno(fp), &statb) < 0) {
144         pr("Error reading info file for %s\n", name);
145         logerror("Cannot fstat for \"%s\" info file (%s)",
146                  filename, strerror(errno));
147         fclose(fp);
148         return RET_SYS;
149     }
150     if ((statb.st_mode & S_IFREG) == 0) {
151         pr("Error reading info file for %s\n", name);
152         logerror("The info file \"%s\" is not regular file\n", filename);
153         fclose(fp);
154         return RET_SYS;
155     }
156     pr("Information on:  %s    Last modification date: %s",
157        name, ctime(&statb.st_mtime));
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_SYS;
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         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                 return RET_FAIL;
316                 break;
317             case ERROR_PATH_NOT_FOUND:
318                 pr("Can't open info dir\n");
319                 logerror("Can't open info dir \"%s\"", infodir);
320                 break;
321             default:
322                 pr("Error reading info dir\n");
323                 logerror("Error (%lu) reading info dir(%s)\\file(%s)",
324                     GetLastError(), infodir, filename);
325             }
326             return RET_SYS;
327         }
328         do {
329             if ((fData.dwFileAttributes != (DWORD)-1) &&
330                 ((fData.dwFileAttributes == FILE_ATTRIBUTE_NORMAL) ||
331                  (fData.dwFileAttributes == FILE_ATTRIBUTE_ARCHIVE) ||
332                  (fData.dwFileAttributes == FILE_ATTRIBUTE_READONLY)) &&
333                 (strncasecmp(name, fData.cFileName, strlen(name)) == 0)) {
334                 nmatch++;
335                 if (nmatch == 1) {
336                     snprintf(last, sizeof(last), "%s", fData.cFileName);
337                 } else {
338                     if (nmatch == 2) {
339                         pr("`%s' is ambiguous.  The following topics match:\n%s",
340                             name, last);
341                         width = strlen(last);
342                     }
343                     width += 2 + strlen(fData.cFileName);
344                     sep = ' ';
345                     if (width > 75) {
346                         sep = '\n';
347                         width = strlen(fData.cFileName);
348                     }
349                     pr(",%c%s", sep, fData.cFileName);
350                 }
351             }
352         } while (FindNextFile(hDir, &fData));
353         FindClose(hDir);
354         if (nmatch == 0) {
355             pr("Sorry, there is no info on %s\n", name);
356             return RET_FAIL;
357         } else if (nmatch > 1) {
358             pr(".\n");
359             return RET_FAIL;
360         }
361         snprintf(filename, sizeof(filename), "%s/%s",
362                   infodir, last);
363         fp = fopen(filename, "rb");
364         if (fp == NULL) {
365             pr("Error reading info file for %s\n", name);
366             logerror("Cannot open for \"%s\" info file (%s)",
367                      filename, strerror(errno));
368             return RET_FAIL;
369         }
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_SYS;
382         }
383     }
384
385     pr("Information on:  %s", name);
386     while (fgets(buf, sizeof(buf), fp) != 0)
387         pr("%s", buf);
388     (void)fclose(fp);
389     return RET_OK;
390 }
391
392 int
393 apro(void)
394 {
395     HANDLE hDir;
396     WIN32_FIND_DATA fData;
397     FILE *fp;
398     char *name, *lbp;
399     char *fbuf;
400     char *lbuf;
401     char filename[1024];
402     long nf, nhf, nl, nlhl, nhl, nll;
403     int alreadyhit;
404     int lhitlim;
405
406     if (player->argp[1] == 0 || !*player->argp[1]) {
407         pr("Apropos what?\n");
408         return RET_FAIL;
409     }
410
411     lhitlim = 100;
412     if (player->argp[2]) {
413         lhitlim = atoi(player->argp[2]);
414         if (lhitlim <= 0)
415             lhitlim = 100;
416     }
417
418     snprintf(filename, sizeof(filename), "%s\\*",infodir);
419     hDir = FindFirstFile(filename, &fData);
420     if (hDir == INVALID_HANDLE_VALUE) {
421         if (GetLastError() == ERROR_PATH_NOT_FOUND) {
422             pr("Can't open info dir\n");
423             logerror("Can't open info dir \"%s\"", infodir);
424         } else {
425             pr("Error reading info dir\n");
426             logerror("Error (%lu) reading info dir(%s)\\file(%s)",
427                 GetLastError(), infodir, filename);
428         }
429         return RET_SYS;
430     }
431
432     fbuf = malloc(256);
433     lbuf = malloc(256);
434     lbp = malloc(256);
435
436     /*
437      *  lower case search string into lbp
438      */
439     name = player->argp[1];
440     lowerit(lbp, 256, name);
441
442     /*
443      *  search
444      */
445     nf = nhf = nl = nhl = 0;
446     do {
447         if ((fData.dwFileAttributes != (DWORD)-1) &&
448             ((fData.dwFileAttributes == FILE_ATTRIBUTE_NORMAL) ||
449              (fData.dwFileAttributes == FILE_ATTRIBUTE_ARCHIVE) ||
450              (fData.dwFileAttributes == FILE_ATTRIBUTE_READONLY))) {
451             snprintf(filename, sizeof(filename), "%s\\%s", infodir,
452                       fData.cFileName);
453             fp = fopen(filename, "rb");
454             alreadyhit = 0;
455             nll = nlhl = 0;
456             if (fp != NULL) {
457                 while (fgets(fbuf, 256, fp)) {
458                     lowerit(lbuf, 256, fbuf);
459                     if (strstr(lbuf, lbp)) {
460                         if (!alreadyhit) {
461                             pr("*** %s ***\n", fData.cFileName);
462                             alreadyhit = 1;
463                             nhf++;
464                         }
465                         fbuf[74] = '\n';
466                         fbuf[75] = 0;
467                         pr("   %s", fbuf);
468                         nlhl++;
469                         /*
470                          * break if too many lines
471                          */
472                         if ((nhl + nlhl) > lhitlim)
473                             break;
474                     }
475                     nll++;
476                 }
477                 fclose(fp);
478             }
479             nhl += nlhl;
480             nl += nll;
481             nf++;
482             if (nhl > lhitlim)
483                 break;
484         }
485     } while (FindNextFile(hDir, &fData));
486     FindClose(hDir);
487
488     free(fbuf);
489     free(lbuf);
490     free(lbp);
491
492     if ((nhl) > lhitlim) {
493         pr("Limit of %d lines exceeded\n", lhitlim);
494     }
495     pr("Found %s in %ld of %ld files and in %ld of %ld lines\n",
496        name, nhf, nf, nhl, nl);
497     return RET_OK;
498 }
499
500 #endif  /* _WIN32 */