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