]> git.pond.sub.org Git - empserver/blob - src/lib/commands/info.c
(info): Print the info topics found when the abbreviation is not unique. Closes ...
[empserver] / src / lib / commands / info.c
1 /*
2  *  Empire - A multi-player, client/server Internet based war game.
3  *  Copyright (C) 1986-2004, 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 #include "commands.h"
49 #include "optlist.h"
50
51 static s_char *
52 lowerit(s_char *buf, int n, s_char *orig)
53 {                               /* converts a string to lower case */
54     /* lower case output buffer */
55     /* size of output buffer */
56     /* input strig */
57     int i;
58     s_char *tmp;
59     tmp = buf;
60     memset(buf, 0, n);
61     for (i = 0; i < n && *orig; i++) {
62         *tmp++ = tolower(*orig++);
63     }
64     return buf;
65 }
66
67 #if !defined(_WIN32)
68
69 int
70 info(void)
71 {
72     s_char buf[255];
73     FILE *fp;
74     s_char *name;
75     s_char *tmp_name;
76     struct stat statb;
77     struct dirent *dp;
78     s_char filename[1024];
79     s_char last[256];
80     DIR *info_dp;
81     int nmatch = 0;
82  
83     name = player->argp[1];
84     if (name) {
85         /*
86          * don't let sneaky people go outside the info directory
87          */
88         if (NULL != (tmp_name = strrchr(name, '/')))
89             name = tmp_name + 1;
90     }
91     if (!name || !*name)
92         name = "TOP";
93  
94     snprintf(filename, sizeof(filename), "%s/%s", infodir, name);
95     fp = fopen(filename, "r");
96     if (fp == NULL) {
97         int len = strlen(name);
98         /* may be a "partial" request.  */
99         info_dp = opendir(infodir);
100         if (info_dp == 0) {
101             pr("Can't open info dir\n");
102             logerror("Can't open info dir \"%s\"\n", infodir);
103             return RET_SYS;
104         }
105
106         while ((dp = readdir(info_dp)) != 0) {
107             if (strncasecmp(name, dp->d_name, strlen(name)) != 0)
108                 continue;
109             nmatch++;
110             if (nmatch == 1) {
111                 snprintf(last, sizeof(last), "%s", dp->d_name);
112             } else {
113                 if (nmatch == 2)
114                     pr("The following info topics were found %s", last);
115                 pr(", %s", dp->d_name);
116             }
117         }
118         closedir(info_dp);
119         if (nmatch == 0) {
120             pr("Sorry, there is no info on %s\n", name);
121             return RET_FAIL;
122         } else if (nmatch > 1) {
123             pr("\n");
124             return RET_FAIL;
125         }
126         snprintf(filename, sizeof(filename), "%s/%s", infodir,
127                  last);
128         fp = fopen(filename, "r");
129         if (fp == NULL) {
130             pr("Error reading info file for %s\n", name);
131             logerror("Cannot open for \"%s\" info file (%s)",
132                 filename, strerror(errno));
133             return RET_FAIL;
134         }
135     }
136     if (fstat(fileno(fp), &statb) < 0) {
137         pr("Error reading info file for %s\n", name);
138         logerror("Cannot fstat for \"%s\" info file (%s)",
139             filename, strerror(errno));
140         fclose(fp);
141         return RET_SYS;
142     }
143     if ((statb.st_mode & S_IFREG) == 0) {
144         pr("Error reading info file for %s\n", name);
145         logerror("The info file \"%s\" is not regular file\n", filename);
146         fclose(fp);
147         return RET_SYS;
148     }
149     pr("Information on:  %s    Last modification date: %s",
150        name, ctime(&statb.st_mtime));
151     while (fgets(buf, sizeof(buf), fp) != 0)
152         pr("%s", buf);
153     (void)fclose(fp);
154     return RET_OK;
155 }
156
157 int
158 apro(void)
159 {
160     FILE *fp;
161     s_char *name, *lbp;
162     s_char *fbuf;
163     s_char *lbuf;
164     struct dirent *dp;
165     s_char filename[1024];
166     DIR *info_dp;
167     long nf, nhf, nl, nlhl, nhl, nll;
168     int alreadyhit;
169     int lhitlim;
170     struct stat statb;
171
172     if (player->argp[1] == 0 || !*player->argp[1]) {
173         pr("Apropos what?\n");
174         return RET_FAIL;
175     }
176
177     lhitlim = 100;
178     if (player->argp[2]) {
179         lhitlim = atoi(player->argp[2]);
180         if (lhitlim <= 0)
181             lhitlim = 100;
182     }
183
184     info_dp = opendir(infodir);
185     if (info_dp == NULL) {
186         pr("Can't open info dir \n");
187         logerror("Can't open info dir \"%s\"", infodir);
188         return RET_SYS;
189     }
190
191     fbuf = (s_char *)malloc(256);
192     lbuf = (s_char *)malloc(256);
193     lbp = (s_char *)malloc(256);
194
195     /*
196      *  lower case search string into lbp
197      */
198     name = player->argp[1];
199     lowerit(lbp, 256, name);
200
201     /*
202      *  search
203      */
204     nf = nhf = nl = nhl = 0;
205     while ((dp = readdir(info_dp)) != 0) {
206         snprintf(filename, sizeof(filename), "%s/%s", infodir,
207             dp->d_name);
208         fp = fopen(filename, "r");
209         alreadyhit = 0;
210         nll = nlhl = 0;
211         if (fp != NULL) {
212             if (fstat(fileno(fp), &statb) < 0) {
213                 logerror("Cannot stat for \"%s\" info file (%s)",
214                          filename, strerror(errno));
215                 fclose(fp);
216                 continue;
217             }
218             if ((statb.st_mode & S_IFREG) == 0) {
219                 logerror("The info file \"%s\" is not regular file\n",
220                          filename);
221                 fclose(fp);
222                 continue;
223             }
224             while (fgets(fbuf, 256, fp)) {
225                 lowerit(lbuf, 256, fbuf);
226                 if (strstr(lbuf, lbp)) {
227                     if (!alreadyhit) {
228                         pr("*** %s ***\n", dp->d_name);
229                         alreadyhit = 1;
230                         nhf++;
231                     }
232                     fbuf[74] = '\n';
233                     fbuf[75] = 0;
234                     pr("   %s", fbuf);
235                     nlhl++;
236                     /*
237                      * break if too many lines
238                      */
239                     if ((nhl + nlhl) > lhitlim)
240                         break;
241                 }
242                 nll++;
243             }
244             fclose(fp);
245         }
246         nhl += nlhl;
247         nl += nll;
248         nf++;
249         if (nhl > lhitlim)
250             break;
251     }
252     closedir(info_dp);
253
254     free(fbuf);
255     free(lbuf);
256     free(lbp);
257
258     if ((nhl) > lhitlim) {
259         pr("Limit of %d lines exceeded\n", lhitlim);
260     }
261     pr("Found %s in %ld of %ld files and in %ld of %ld lines\n",
262        name, nhf, nf, nhl, nl);
263     return RET_OK;
264 }
265
266 #else
267
268 int
269 info(void)
270 {
271     s_char buf[255];
272     FILE *fp;
273     s_char *name;
274     s_char *tmp_name;
275     s_char filename[1024];
276     s_char last[256];
277     int nmatch = 0;
278
279     name = player->argp[1];
280     if (name) {
281         /*
282          * don't let sneaky people go outside the info directory
283          */
284         if (NULL != (tmp_name = strrchr(name, '/')))
285             name = tmp_name + 1;
286         if (NULL != (tmp_name = strrchr(name, '\\')))
287             name = tmp_name + 1;
288         if (NULL != (tmp_name = strrchr(name, ':')))
289             name = tmp_name + 1;
290     }
291     if (!name || !*name)
292         name = "TOP";
293
294     _snprintf(filename, sizeof(filename) - 1, "%s\\%s", infodir, name);
295     fp = fopen(filename, "r");
296     if (fp == NULL) {
297         /* may be a "partial" request.  */
298         HANDLE hDir;
299         WIN32_FIND_DATA fData;
300         int len = strlen(name);
301         strcat(filename, "*");
302         hDir = FindFirstFile(filename, &fData);
303         if (hDir == INVALID_HANDLE_VALUE) {
304             switch (GetLastError()) {
305             case ERROR_FILE_NOT_FOUND:
306                 pr("Sorry, there is no info on %s\n", name);
307                 return RET_FAIL;
308                 break;
309             case ERROR_PATH_NOT_FOUND:
310                 pr("Can't open info dir\n");
311                 logerror("Can't open info dir \"%s\"", infodir);
312                 break;
313             default:
314                 pr("Error reading info dir\n");
315                 logerror("Error (%d) reading info dir(%s)\\file(%s)",
316                     infodir, filename, GetLastError());
317             }
318             return RET_SYS;
319         }
320         do {
321             if ((fData.dwFileAttributes != (DWORD)-1) &&
322                 ((fData.dwFileAttributes == FILE_ATTRIBUTE_NORMAL) ||
323                  (fData.dwFileAttributes == FILE_ATTRIBUTE_ARCHIVE) ||
324                  (fData.dwFileAttributes == FILE_ATTRIBUTE_READONLY)) &&
325                 (strncasecmp(name, fData.cFileName, strlen(name)) == 0)) {
326                 nmatch++;
327                 if (nmatch == 1) {
328                     _snprintf(last, sizeof(last), "%s", fData.cFileName);
329                 } else {
330                     if (nmatch == 2)
331                         pr("The following info topics were found %s",
332                            last);
333                     pr(", %s", fData.cFileName);
334                 }
335             }
336         } while (FindNextFile(hDir, &fData));
337         FindClose(hDir);
338         if (nmatch == 0) {
339             pr("Sorry, there is no info on %s\n", name);
340             return RET_FAIL;
341         } else if (nmatch > 1) {
342             pr("\n");
343             return RET_FAIL;
344         }
345         _snprintf(filename, sizeof(filename), "%s/%s",
346                   infodir, last);
347         fp = fopen(filename, "r");
348         if (fp == NULL) {
349             pr("Error reading info file for %s\n", name);
350             logerror("Cannot open for \"%s\" info file (%s)",
351                 filename, strerror(errno));
352             return RET_FAIL;
353         }
354     }
355     else {
356         DWORD fAttrib = GetFileAttributes(filename);
357         if ((fAttrib == (DWORD)-1) || //INVALID_FILE_ATTRIBUTES
358             (fAttrib != FILE_ATTRIBUTE_NORMAL) &&
359             (fAttrib != FILE_ATTRIBUTE_ARCHIVE) &&
360             (fAttrib != FILE_ATTRIBUTE_READONLY)) {
361             pr("Error reading info file for %s\n", name);
362             logerror("The info file \"%s\" is not regular file\n",
363                      filename);
364             fclose(fp);
365             return RET_SYS;
366         }
367     }
368
369     pr("Information on:  %s", name);
370     while (fgets(buf, sizeof(buf), fp) != 0)
371         pr("%s", buf);
372     (void)fclose(fp);
373     return RET_OK;
374 }
375
376 int
377 apro(void)
378 {
379     HANDLE hDir;
380     WIN32_FIND_DATA fData;
381     FILE *fp;
382     s_char *name, *lbp;
383     s_char *fbuf;
384     s_char *lbuf;
385     s_char filename[1024];
386     long nf, nhf, nl, nlhl, nhl, nll;
387     int alreadyhit;
388     int lhitlim;
389
390     if (player->argp[1] == 0 || !*player->argp[1]) {
391         pr("Apropos what?\n");
392         return RET_FAIL;
393     }
394
395     lhitlim = 100;
396     if (player->argp[2]) {
397         lhitlim = atoi(player->argp[2]);
398         if (lhitlim <= 0)
399             lhitlim = 100;
400     }
401
402     _snprintf(filename, sizeof(filename), "%s\\*",infodir);
403     hDir = FindFirstFile(filename, &fData);
404     if (hDir == INVALID_HANDLE_VALUE) {
405         if (GetLastError() == ERROR_PATH_NOT_FOUND) {
406             pr("Can't open info dir\n");
407             logerror("Can't open info dir \"%s\"", infodir);
408         } else {
409             pr("Error reading info dir\n");
410             logerror("Error (%d) reading info dir(%s)\\file(%s)",
411                 infodir, filename, GetLastError());
412         }
413         return RET_SYS;
414     }
415
416     fbuf = (s_char *)malloc(256);
417     lbuf = (s_char *)malloc(256);
418     lbp = (s_char *)malloc(256);
419
420     /*
421      *  lower case search string into lbp
422      */
423     name = player->argp[1];
424     lowerit(lbp, 256, name);
425
426     /*
427      *  search
428      */
429     nf = nhf = nl = nhl = 0;
430     do {
431         if ((fData.dwFileAttributes != (DWORD)-1) &&
432             ((fData.dwFileAttributes == FILE_ATTRIBUTE_NORMAL) ||
433              (fData.dwFileAttributes == FILE_ATTRIBUTE_ARCHIVE) ||
434              (fData.dwFileAttributes == FILE_ATTRIBUTE_READONLY))) {
435             _snprintf(filename, sizeof(filename), "%s\\%s", infodir,
436                       fData.cFileName);
437             fp = fopen(filename, "r");
438             alreadyhit = 0;
439             nll = nlhl = 0;
440             if (fp != NULL) {
441                 while (fgets(fbuf, 256, fp)) {
442                     lowerit(lbuf, 256, fbuf);
443                     if (strstr(lbuf, lbp)) {
444                         if (!alreadyhit) {
445                             pr("*** %s ***\n", fData.cFileName);
446                             alreadyhit = 1;
447                             nhf++;
448                         }
449                         fbuf[74] = '\n';
450                         fbuf[75] = 0;
451                         pr("   %s", fbuf);
452                         nlhl++;
453                         /*
454                          * break if too many lines
455                          */
456                         if ((nhl + nlhl) > lhitlim)
457                             break;
458                     }
459                     nll++;
460                 }
461                 fclose(fp);
462             }
463             nhl += nlhl;
464             nl += nll;
465             nf++;
466             if (nhl > lhitlim)
467                 break;
468         }
469     } while (FindNextFile(hDir, &fData));
470     FindClose(hDir);
471
472     free(fbuf);
473     free(lbuf);
474     free(lbp);
475
476     if ((nhl) > lhitlim) {
477         pr("Limit of %ld lines exceeded\n", lhitlim);
478     }
479     pr("Found %s in %ld of %ld files and in %ld of %ld lines\n",
480        name, nhf, nf, nhl, nl);
481     return RET_OK;
482 }
483
484 #endif