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