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