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