]> git.pond.sub.org Git - empserver/blob - src/lib/commands/info.c
errno may not be a variable; users must include errno.h instead of
[empserver] / src / lib / commands / info.c
1 /*
2  *  Empire - A multi-player, client/server Internet based war game.
3  *  Copyright (C) 1986-2000, 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 the "LEGAL", "LICENSE", "CREDITS" and "README" files for all the
23  *  related information and legal notices. It is expected that any future
24  *  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  */
36
37 #include "misc.h"
38 #include "player.h"
39 #include <errno.h>
40 #ifdef Rel4
41 #include <string.h>
42 #endif /* Rel4 */
43 #include <stdio.h>
44 #include <sys/stat.h>
45 #if !defined(_WIN32)
46 #include <dirent.h>
47 #else
48 #include <windows.h>
49 #endif
50 #ifdef solaris
51 #include <unistd.h>
52 #endif
53 #include "commands.h"
54
55 #if 0
56 static int fileselect(struct dirent *dp);
57 static int printdir(void);
58 #endif
59
60 static
61 s_char *
62 lowerit(s_char *buf, int n, s_char *orig)
63 {                               /* converts a string to lower case */
64     /* lower case output buffer */
65     /* size of output buffer */
66     /* input strig */
67     int i;
68     s_char *tmp;
69     tmp = buf;
70     memset(buf, 0, n);
71     for (i = 0; i < n && *orig; i++) {
72         *tmp++ = tolower(*orig++);
73     }
74     return buf;
75 }
76
77 static
78     int
79 strnccmp(s_char *s1, s_char *s2, int n)
80 {
81     int i;
82     char c1, c2;
83     for (i = 0; i < n && *s1 && s2; i++) {
84         c1 = tolower(*s1++);
85         c2 = tolower(*s2++);
86         if (c1 > c2)
87             return 1;
88         else if (c1 < c2)
89             return -1;
90     }
91     return 0;
92 }
93
94 #if !defined(_WIN32)
95
96 int
97 info(void)
98 {
99     extern s_char *infodir;
100 #if (!defined linux) && (!defined FBSD) && (!defined __linux__) && (!defined __ppc__)
101     extern s_char *sys_errlist[];
102 #endif
103     s_char buf[255];
104     FILE *fp;
105     s_char *bp;
106     struct stat statb;
107     struct dirent *dp;
108     s_char filename[1024];
109     DIR *info_dp;
110
111     if (player->argp[1] == 0 || !*player->argp[1])
112         bp = "TOP";
113 #if 0
114     /* Note that we generate an "all" file now, which contains
115      * this list, so we don't do printdir. */
116     else if (!strcmp(player->argp[1], "all"))
117         return printdir();
118 #endif
119     /*
120      * don't let sneaky people go outside the info directory
121      */
122     else if (NULL != (bp = rindex(player->argp[1], '/')))
123         bp++;
124     else
125         bp = player->argp[1];
126     sprintf(filename, "%s/%s", infodir, bp);
127     fp = fopen(filename, "r");
128     if (fp == NULL) {
129         int len = strlen(bp);
130         /* may be a "partial" request.  */
131         info_dp = opendir(infodir);
132         if (info_dp == 0) {
133             pr("Can't open info dir \"%s\"\n", infodir);
134             return RET_SYS;
135         }
136         rewinddir(info_dp);
137         while ((dp = readdir(info_dp)) != 0 && fp == 0) {
138             if (strnccmp(bp, dp->d_name, len) != 0)
139                 continue;
140             sprintf(filename, "%s/%s", infodir, dp->d_name);
141             fp = fopen(filename, "r");
142         }
143         closedir(info_dp);
144         if (fp == NULL) {
145             pr("Sorry, there is no info on %s\n", bp);
146             return RET_FAIL;
147         }
148     }
149     if (fstat(fileno(fp), &statb) < 0) {
150         pr("Cannot read info page for \"%s\" (%s)\n",
151            dp->d_name, sys_errlist[errno]);
152         fclose(fp);
153         return RET_SYS;
154     }
155     if ((statb.st_mode & S_IFREG) == 0) {
156         pr("There is no available information on \"%s\"\n", dp->d_name);
157         fclose(fp);
158         return RET_FAIL;
159     }
160     pr("Information on:  %s    Last modification date: %s",
161        bp, ctime(&statb.st_mtime));
162     while (fgets(buf, sizeof(buf), fp) != 0)
163         pr("%s", buf);
164     (void)fclose(fp);
165     return RET_OK;
166 }
167
168 #if 0
169 static int biggest;
170
171 static
172     int
173 fileselect(struct dirent *dp)
174 {
175     int l;
176     if (*dp->d_name == '.')
177         return 0;
178
179     if ((l = strlen(dp->d_name)) > biggest)
180         biggest = l;
181     return 1;
182 }
183
184 #ifdef solaris
185 static
186     int
187 alphasort(struct dirent *d1, struct dirent *d2)
188 {
189     return strcmp(d1->d_name, d2->d_name);
190 }
191
192 static int
193 scandir(char *dir, struct dirent ***dpp, int (*select) (), int (*sort) ())
194      /* directory to read */
195      /* directory entry pointer pointer */
196 {
197     DIR *dirp;
198     int nsize;
199     int nents;
200     struct dirent *d, *tmp;
201
202     d = (struct dirent *)malloc(sizeof(struct dirent) +
203                                 pathconf(".", _PC_NAME_MAX) + 1);
204     if ((dirp = opendir(dir)) == NULL)
205         return -1;
206     nsize = 100;
207     *dpp = (struct dirent **)malloc(nsize * sizeof(struct dirent *));
208     if ((*dpp) == NULL) {
209         closedir(dirp);
210         return -1;
211     }
212     nents = 0;
213     while ((d = readdir_r(dirp, d)) != NULL) {
214         if (select != NULL && !(*select) (d))
215             continue;
216         tmp =
217             (struct dirent *)malloc(sizeof(struct dirent) +
218                                     strlen(d->d_name) + 1);
219         if (tmp == NULL)
220             return -1;
221         tmp->d_ino = d->d_ino;
222         tmp->d_reclen = d->d_reclen;
223         strcpy(tmp->d_name, d->d_name);
224         if (nents > nsize) {
225             *dpp =
226                 (struct dirent **)realloc((char *)*dpp,
227                                           nsize * sizeof(struct dirent *));
228             if (*dpp == NULL)
229                 return -1;
230         }
231         (*dpp)[nents++] = tmp;
232     }
233     closedir(dirp);
234     if (nents > 0 && sort != NULL)
235         qsort(*dpp, nents, sizeof(struct dirent *), sort);
236     return nents;
237 }
238 #endif
239
240 static int
241 printdir(void)
242 {
243 #if !defined(solaris) && !defined(ALPHA) && !defined(__linux__)
244     extern int alphasort(const struct dirent *const *,
245                          const struct dirent *const *);
246 #endif
247     extern s_char *infodir;
248     static time_t lastmodtime;
249     static int number;
250     static struct dirent **dp;
251     struct stat st;
252     int count;
253     int i;
254     int npl;
255
256     if (stat(infodir, &st) == -1)
257         return RET_FAIL;
258     pr("Available topics are:\n");
259     if (lastmodtime < st.st_mtime) {
260         if (dp)
261             free((s_char *)dp);
262         biggest = 0;
263         number = scandir(infodir, &dp, fileselect, alphasort);
264         lastmodtime = st.st_mtime;
265     }
266     count = 79 / (biggest + 1) - 1;
267     for (i = 0, npl = 0; i < number; i++) {
268         pr("%-*.*s%c", biggest, strlen(dp[i]->d_name),
269            dp[i]->d_name, npl == count ? '\n' : ' ');
270         if (npl == count)
271             npl = 0;
272         else
273             npl++;
274     }
275     if (npl != 0)
276         pr("\n");
277     return 0;
278 }
279 #endif
280
281 int
282 apro(void)
283 {
284     extern s_char *infodir;
285     FILE *fp;
286     s_char *bp, *lbp;
287     s_char *fbuf;
288     s_char *lbuf;
289     struct dirent *dp;
290     s_char filename[1024];
291     DIR *info_dp;
292     long nf, nhf, nl, nlhl, nhl, nll;
293     int alreadyhit;
294     int lhitlim;
295
296     if (player->argp[1] == 0 || !*player->argp[1]) {
297         pr("Apropos what?\n");
298         return RET_FAIL;
299     }
300
301     lhitlim = 100;
302     if (player->argp[2]) {
303         lhitlim = atoi(player->argp[2]);
304         if (lhitlim <= 0)
305             lhitlim = 100;
306     }
307
308     info_dp = opendir(infodir);
309     if (info_dp == 0) {
310         pr("Can't open info dir \"%s\"\n", infodir);
311         return RET_SYS;
312     }
313
314     fbuf = (s_char *)malloc(256);
315     lbuf = (s_char *)malloc(256);
316     lbp = (s_char *)malloc(256);
317
318     /*
319      *  lower case search string into lbp
320      */
321     bp = player->argp[1];
322     lowerit(lbp, 256, bp);
323
324     /*
325      *  search
326      */
327     nf = nhf = nl = nhl = 0;
328     rewinddir(info_dp);
329     while ((dp = readdir(info_dp)) != 0) {
330         sprintf(filename, "%s/%s", infodir, dp->d_name);
331         fp = fopen(filename, "r");
332         alreadyhit = 0;
333         nll = nlhl = 0;
334         if (fp != NULL) {
335             while (fgets(fbuf, 256, fp)) {
336                 lowerit(lbuf, 256, fbuf);
337                 if (strstr(lbuf, lbp)) {
338                     if (!alreadyhit) {
339                         pr("*** %s ***\n", dp->d_name);
340                         alreadyhit = 1;
341                         nhf++;
342                     }
343                     fbuf[74] = '\n';
344                     fbuf[75] = 0;
345                     pr("   %s", fbuf);
346                     nlhl++;
347                     /*
348                      * break if too many lines
349                      */
350                     if ((nhl + nlhl) > lhitlim)
351                         break;
352                 }
353                 nll++;
354             }
355             fclose(fp);
356         }
357         nhl += nlhl;
358         nl += nll;
359         nf++;
360         if (nhl > lhitlim)
361             break;
362     }
363     closedir(info_dp);
364
365     free(fbuf);
366     free(lbuf);
367     free(lbp);
368
369     if ((nhl) > lhitlim) {
370         pr("Limit of %ld lines exceeded\n", lhitlim);
371     }
372     pr("Found %s in %ld of %ld files and in %ld of %ld lines\n",
373        bp, nhf, nf, nhl, nl);
374     return RET_OK;
375 }
376
377 #else
378
379 int
380 info(void)
381 {
382     extern s_char *infodir;
383     s_char buf[255];
384     FILE *fp;
385     s_char *bp;
386     s_char *bp2;
387     s_char filename[1024];
388
389     if (player->argp[1] == 0 || !*player->argp[1])
390         bp = "TOP";
391 #if 0
392     /* Note that we generate an "all" file now, which contains
393      * this list, so we don't do printdir. */
394     else if (!strcmp(player->argp[1], "all"))
395         return printdir();
396 #endif
397     else {
398         /*
399          * don't let sneaky people go outside the info directory
400          */
401         bp = player->argp[1];
402         if (NULL != (bp2 = rindex(bp, '/')))
403             bp = ++bp2;
404         if (NULL != (bp2 = rindex(bp, '\\')))
405             bp = ++bp2;
406         if (NULL != (bp2 = rindex(bp, ':')))
407             bp = ++bp2;
408         if (!*bp)
409             bp = "TOP";
410     }
411
412     strncpy(filename, infodir, sizeof(filename) - 2);
413     strcat(filename, "//");
414     strncat(filename, bp, sizeof(filename) - 1 - strlen(filename));
415     fp = fopen(filename, "r");
416     if (fp == NULL) {
417         /* may be a "partial" request.  */
418         HANDLE hDir;
419         WIN32_FIND_DATA fData;
420         int len = strlen(bp);
421         strncat(filename, "*", sizeof(filename) - 1 - strlen(filename));
422         hDir = FindFirstFile(filename, &fData);
423         if (hDir == INVALID_HANDLE_VALUE) {
424             pr("Can't open info dir \"%s\"\n", infodir);
425             return RET_SYS;
426         }
427         do {
428             if ((fData.dwFileAttributes == FILE_ATTRIBUTE_NORMAL) &&
429                 (strnccmp(bp, fData.cFileName, len) == 0)) {
430                 strncpy(filename, infodir, sizeof(filename) - 2);
431                 strcat(filename, "//");
432                 strncat(filename, fData.cFileName,
433                         sizeof(filename) - 1 - strlen(filename));
434                 fp = fopen(filename, "r");
435             }
436         } while (!fp && FindNextFile(hDir, &fData));
437         FindClose(hDir);
438         if (fp == NULL) {
439             pr("Sorry, there is no info on %s\n", bp);
440             return RET_FAIL;
441         }
442     }
443     pr("Information on:  %s", bp);
444     while (fgets(buf, sizeof(buf), fp) != 0)
445         pr("%s", buf);
446     (void)fclose(fp);
447     return RET_OK;
448 }
449
450 #if 0
451 static int
452 printdir(void)
453 {
454     extern s_char *infodir;
455     HANDLE hDir;
456     WIN32_FIND_DATA fData;
457     int count;
458     int i;
459     int npl;
460     s_char filename[1024];
461
462     strncpy(filename, infodir, sizeof(filename) - 3);
463     strcat(filename, "//*");
464
465     hDir = FindFirstFile(filename, &fData);
466     if (hDir == INVALID_HANDLE_VALUE) {
467         return RET_FAIL;
468     }
469
470     pr("Available topics are:\n");
471     do {
472         if (fData.dwFileAttributes == FILE_ATTRIBUTE_NORMAL) {
473             /* Yes, we could do multi-column work here. */
474             pr("%s\n", fData.cFileName);
475         }
476     } while (FindNextFile(hDir, &fData));
477     FindClose(hDir);
478
479     return 0;
480 }
481 #endif
482
483 int
484 apro(void)
485 {
486     extern s_char *infodir;
487     HANDLE hDir;
488     WIN32_FIND_DATA fData;
489     FILE *fp;
490     s_char *bp, *lbp;
491     s_char *fbuf;
492     s_char *lbuf;
493     s_char filename[1024];
494     long nf, nhf, nl, nlhl, nhl, nll;
495     int alreadyhit;
496     int lhitlim;
497
498     if (player->argp[1] == 0 || !*player->argp[1]) {
499         pr("Apropos what?\n");
500         return RET_FAIL;
501     }
502
503     lhitlim = 100;
504     if (player->argp[2]) {
505         lhitlim = atoi(player->argp[2]);
506         if (lhitlim <= 0)
507             lhitlim = 100;
508     }
509
510     strncpy(filename, infodir, sizeof(filename) - 3);
511     strcat(filename, "//*");
512     hDir = FindFirstFile(filename, &fData);
513     if (hDir == INVALID_HANDLE_VALUE) {
514         return RET_FAIL;
515     }
516
517     fbuf = (s_char *)malloc(256);
518     lbuf = (s_char *)malloc(256);
519     lbp = (s_char *)malloc(256);
520
521     /*
522      *  lower case search string into lbp
523      */
524     bp = player->argp[1];
525     lowerit(lbp, 256, bp);
526
527     /*
528      *  search
529      */
530     nf = nhf = nl = nhl = 0;
531     do {
532         strncpy(filename, infodir, sizeof(filename) - 3);
533         strcat(filename, "//");
534         strncat(filename, fData.cFileName,
535                 sizeof(filename) - 1 - strlen(filename));
536         fp = fopen(filename, "r");
537         alreadyhit = 0;
538         nll = nlhl = 0;
539         if (fp != NULL) {
540             while (fgets(fbuf, 256, fp)) {
541                 lowerit(lbuf, 256, fbuf);
542                 if (strstr(lbuf, lbp)) {
543                     if (!alreadyhit) {
544                         pr("*** %s ***\n", fData.cFileName);
545                         alreadyhit = 1;
546                         nhf++;
547                     }
548                     fbuf[74] = '\n';
549                     fbuf[75] = 0;
550                     pr("   %s", fbuf);
551                     nlhl++;
552                     /*
553                      * break if too many lines
554                      */
555                     if ((nhl + nlhl) > lhitlim)
556                         break;
557                 }
558                 nll++;
559             }
560             fclose(fp);
561         }
562         nhl += nlhl;
563         nl += nll;
564         nf++;
565         if (nhl > lhitlim)
566             break;
567     } while (FindNextFile(hDir, &fData));
568     FindClose(hDir);
569
570     free(fbuf);
571     free(lbuf);
572     free(lbp);
573
574     if ((nhl) > lhitlim) {
575         pr("Limit of %ld lines exceeded\n", lhitlim);
576     }
577     pr("Found %s in %ld of %ld files and in %ld of %ld lines\n",
578        bp, nhf, nf, nhl, nl);
579     return RET_OK;
580 }
581
582 #endif