]> git.pond.sub.org Git - empserver/blob - src/lib/commands/info.c
Add some missing declarations to headers. Remove some redundant
[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     static time_t lastmodtime;
239     static int number;
240     static struct dirent **dp;
241     struct stat st;
242     int count;
243     int i;
244     int npl;
245
246     if (stat(infodir, &st) == -1)
247         return RET_FAIL;
248     pr("Available topics are:\n");
249     if (lastmodtime < st.st_mtime) {
250         if (dp)
251             free((s_char *)dp);
252         biggest = 0;
253         number = scandir(infodir, &dp, fileselect, alphasort);
254         lastmodtime = st.st_mtime;
255     }
256     count = 79 / (biggest + 1) - 1;
257     for (i = 0, npl = 0; i < number; i++) {
258         pr("%-*.*s%c", biggest, strlen(dp[i]->d_name),
259            dp[i]->d_name, npl == count ? '\n' : ' ');
260         if (npl == count)
261             npl = 0;
262         else
263             npl++;
264     }
265     if (npl != 0)
266         pr("\n");
267     return 0;
268 }
269 #endif
270
271 int
272 apro(void)
273 {
274     FILE *fp;
275     s_char *bp, *lbp;
276     s_char *fbuf;
277     s_char *lbuf;
278     struct dirent *dp;
279     s_char filename[1024];
280     DIR *info_dp;
281     long nf, nhf, nl, nlhl, nhl, nll;
282     int alreadyhit;
283     int lhitlim;
284
285     if (player->argp[1] == 0 || !*player->argp[1]) {
286         pr("Apropos what?\n");
287         return RET_FAIL;
288     }
289
290     lhitlim = 100;
291     if (player->argp[2]) {
292         lhitlim = atoi(player->argp[2]);
293         if (lhitlim <= 0)
294             lhitlim = 100;
295     }
296
297     info_dp = opendir(infodir);
298     if (info_dp == 0) {
299         pr("Can't open info dir \"%s\"\n", infodir);
300         return RET_SYS;
301     }
302
303     fbuf = (s_char *)malloc(256);
304     lbuf = (s_char *)malloc(256);
305     lbp = (s_char *)malloc(256);
306
307     /*
308      *  lower case search string into lbp
309      */
310     bp = player->argp[1];
311     lowerit(lbp, 256, bp);
312
313     /*
314      *  search
315      */
316     nf = nhf = nl = nhl = 0;
317     rewinddir(info_dp);
318     while ((dp = readdir(info_dp)) != 0) {
319         sprintf(filename, "%s/%s", infodir, dp->d_name);
320         fp = fopen(filename, "r");
321         alreadyhit = 0;
322         nll = nlhl = 0;
323         if (fp != NULL) {
324             while (fgets(fbuf, 256, fp)) {
325                 lowerit(lbuf, 256, fbuf);
326                 if (strstr(lbuf, lbp)) {
327                     if (!alreadyhit) {
328                         pr("*** %s ***\n", dp->d_name);
329                         alreadyhit = 1;
330                         nhf++;
331                     }
332                     fbuf[74] = '\n';
333                     fbuf[75] = 0;
334                     pr("   %s", fbuf);
335                     nlhl++;
336                     /*
337                      * break if too many lines
338                      */
339                     if ((nhl + nlhl) > lhitlim)
340                         break;
341                 }
342                 nll++;
343             }
344             fclose(fp);
345         }
346         nhl += nlhl;
347         nl += nll;
348         nf++;
349         if (nhl > lhitlim)
350             break;
351     }
352     closedir(info_dp);
353
354     free(fbuf);
355     free(lbuf);
356     free(lbp);
357
358     if ((nhl) > lhitlim) {
359         pr("Limit of %ld lines exceeded\n", lhitlim);
360     }
361     pr("Found %s in %ld of %ld files and in %ld of %ld lines\n",
362        bp, nhf, nf, nhl, nl);
363     return RET_OK;
364 }
365
366 #else
367
368 int
369 info(void)
370 {
371     s_char buf[255];
372     FILE *fp;
373     s_char *bp;
374     s_char *bp2;
375     s_char filename[1024];
376
377     if (player->argp[1] == 0 || !*player->argp[1])
378         bp = "TOP";
379 #if 0
380     /* Note that we generate an "all" file now, which contains
381      * this list, so we don't do printdir. */
382     else if (!strcmp(player->argp[1], "all"))
383         return printdir();
384 #endif
385     else {
386         /*
387          * don't let sneaky people go outside the info directory
388          */
389         bp = player->argp[1];
390         if (NULL != (bp2 = strrchr(bp, '/')))
391             bp = ++bp2;
392         if (NULL != (bp2 = strrchr(bp, '\\')))
393             bp = ++bp2;
394         if (NULL != (bp2 = strrchr(bp, ':')))
395             bp = ++bp2;
396         if (!*bp)
397             bp = "TOP";
398     }
399
400     strncpy(filename, infodir, sizeof(filename) - 2);
401     strcat(filename, "//");
402     strncat(filename, bp, sizeof(filename) - 1 - strlen(filename));
403     fp = fopen(filename, "r");
404     if (fp == NULL) {
405         /* may be a "partial" request.  */
406         HANDLE hDir;
407         WIN32_FIND_DATA fData;
408         int len = strlen(bp);
409         strncat(filename, "*", sizeof(filename) - 1 - strlen(filename));
410         hDir = FindFirstFile(filename, &fData);
411         if (hDir == INVALID_HANDLE_VALUE) {
412             pr("Can't open info dir \"%s\"\n", infodir);
413             return RET_SYS;
414         }
415         do {
416             if ((fData.dwFileAttributes == FILE_ATTRIBUTE_NORMAL) &&
417                 (strnccmp(bp, fData.cFileName, len) == 0)) {
418                 strncpy(filename, infodir, sizeof(filename) - 2);
419                 strcat(filename, "//");
420                 strncat(filename, fData.cFileName,
421                         sizeof(filename) - 1 - strlen(filename));
422                 fp = fopen(filename, "r");
423             }
424         } while (!fp && FindNextFile(hDir, &fData));
425         FindClose(hDir);
426         if (fp == NULL) {
427             pr("Sorry, there is no info on %s\n", bp);
428             return RET_FAIL;
429         }
430     }
431     pr("Information on:  %s", bp);
432     while (fgets(buf, sizeof(buf), fp) != 0)
433         pr("%s", buf);
434     (void)fclose(fp);
435     return RET_OK;
436 }
437
438 #if 0
439 static int
440 printdir(void)
441 {
442     HANDLE hDir;
443     WIN32_FIND_DATA fData;
444     int count;
445     int i;
446     int npl;
447     s_char filename[1024];
448
449     strncpy(filename, infodir, sizeof(filename) - 3);
450     strcat(filename, "//*");
451
452     hDir = FindFirstFile(filename, &fData);
453     if (hDir == INVALID_HANDLE_VALUE) {
454         return RET_FAIL;
455     }
456
457     pr("Available topics are:\n");
458     do {
459         if (fData.dwFileAttributes == FILE_ATTRIBUTE_NORMAL) {
460             /* Yes, we could do multi-column work here. */
461             pr("%s\n", fData.cFileName);
462         }
463     } while (FindNextFile(hDir, &fData));
464     FindClose(hDir);
465
466     return 0;
467 }
468 #endif
469
470 int
471 apro(void)
472 {
473     HANDLE hDir;
474     WIN32_FIND_DATA fData;
475     FILE *fp;
476     s_char *bp, *lbp;
477     s_char *fbuf;
478     s_char *lbuf;
479     s_char filename[1024];
480     long nf, nhf, nl, nlhl, nhl, nll;
481     int alreadyhit;
482     int lhitlim;
483
484     if (player->argp[1] == 0 || !*player->argp[1]) {
485         pr("Apropos what?\n");
486         return RET_FAIL;
487     }
488
489     lhitlim = 100;
490     if (player->argp[2]) {
491         lhitlim = atoi(player->argp[2]);
492         if (lhitlim <= 0)
493             lhitlim = 100;
494     }
495
496     strncpy(filename, infodir, sizeof(filename) - 3);
497     strcat(filename, "//*");
498     hDir = FindFirstFile(filename, &fData);
499     if (hDir == INVALID_HANDLE_VALUE) {
500         return RET_FAIL;
501     }
502
503     fbuf = (s_char *)malloc(256);
504     lbuf = (s_char *)malloc(256);
505     lbp = (s_char *)malloc(256);
506
507     /*
508      *  lower case search string into lbp
509      */
510     bp = player->argp[1];
511     lowerit(lbp, 256, bp);
512
513     /*
514      *  search
515      */
516     nf = nhf = nl = nhl = 0;
517     do {
518         strncpy(filename, infodir, sizeof(filename) - 3);
519         strcat(filename, "//");
520         strncat(filename, fData.cFileName,
521                 sizeof(filename) - 1 - strlen(filename));
522         fp = fopen(filename, "r");
523         alreadyhit = 0;
524         nll = nlhl = 0;
525         if (fp != NULL) {
526             while (fgets(fbuf, 256, fp)) {
527                 lowerit(lbuf, 256, fbuf);
528                 if (strstr(lbuf, lbp)) {
529                     if (!alreadyhit) {
530                         pr("*** %s ***\n", fData.cFileName);
531                         alreadyhit = 1;
532                         nhf++;
533                     }
534                     fbuf[74] = '\n';
535                     fbuf[75] = 0;
536                     pr("   %s", fbuf);
537                     nlhl++;
538                     /*
539                      * break if too many lines
540                      */
541                     if ((nhl + nlhl) > lhitlim)
542                         break;
543                 }
544                 nll++;
545             }
546             fclose(fp);
547         }
548         nhl += nlhl;
549         nl += nll;
550         nf++;
551         if (nhl > lhitlim)
552             break;
553     } while (FindNextFile(hDir, &fData));
554     FindClose(hDir);
555
556     free(fbuf);
557     free(lbuf);
558     free(lbp);
559
560     if ((nhl) > lhitlim) {
561         pr("Limit of %ld lines exceeded\n", lhitlim);
562     }
563     pr("Found %s in %ld of %ld files and in %ld of %ld lines\n",
564        bp, nhf, nf, nhl, nl);
565     return RET_OK;
566 }
567
568 #endif