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