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