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