1 /*****************************************************************************/
2 /* */
3 /* (C) Copyright 1992-1996 Alberto Pasquale */
4 /* Portions (C) Copyright 1999 Per Lundberg */
5 /* */
6 /* A L L R I G H T S R E S E R V E D */
7 /* */
8 /*****************************************************************************/
9 /* */
10 /* This source code is NOT in the public domain and it CANNOT be used or */
11 /* distributed without written permission from the author. */
12 /* */
13 /*****************************************************************************/
14 /* */
15 /* How to contact the author: Alberto Pasquale of 2:332/504@fidonet */
16 /* Viale Verdi 106 */
17 /* 41100 Modena */
18 /* Italy */
19 /* */
20 /*****************************************************************************/
21
22 // ComprCfg.Cpp
23
24 #ifdef __OS2__
25 #define INCL_DOS
26 #include <os2.h>
27 #endif
28 #include "bbsgenlb.hpp"
29 #include "apgenlib.hpp"
30 #include <string.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <stdarg.h>
34
35
36
37 #define IDENTBUFSIZE 64
38 #define CFGLINESIZE 256
39
40
41 #define InString 1 // for CleanLine status
42 #define OutString 2
43 #define LineEnd 3
44
45
46 AH_VShow AH_ComprCfg::outf;
47
48
CleanLine(char * line)49 static void CleanLine (char *line) // Get rid of tabs, comments, newline.
50 { // Preserve ';' if enclosed in string.
51 int status = OutString; // Remove trailing space.
52 char *c = line;
53
54 while (status != LineEnd) {
55 switch (*c) {
56 case '\t': // convert tab to blank
57 *c = ' ';
58 break;
59
60 case '\n':
61 case '\0':
62 status = LineEnd;
63 continue;
64
65 case '\"':
66 if (status == InString) {
67 if (*(c+1) == '\"')
68 c++;
69 else
70 status = OutString;
71 } else
72 status = InString;
73 break;
74
75 case ';' :
76 if (status == OutString) {
77 status = LineEnd;
78 continue;
79 }
80 }
81 c++;
82 }
83
84 while (c > line) // remove trailing space
85 if (*(c-1) == ' ')
86 c--;
87 else
88 break;
89
90 *c = '\0';
91 }
92
93
fgetln(FILE * f,char * lbuff,const char * & tkp)94 static char *fgetln (FILE *f, char *lbuff, const char *&tkp)
95 {
96 char *tok = NULL;
97
98 while ((_fgets (lbuff, CFGLINESIZE, f)) != NULL) {
99 CleanLine (lbuff); /* get rid of tabs, comments and newline */
100 tkp = lbuff;
101 tok = GetStatName (tkp);
102 if (tok != NULL) /* if keyword ok, return */
103 break;
104 }
105 return tok;
106 }
107
108
RcShow(int code,...)109 void AH_ComprCfg::RcShow (int code, ...)
110 {
111 if (!outf)
112 return;
113 va_list args;
114 va_start (args, code);
115 switch (code) {
116 case RC_DOING:
117 outf (AH_MT_Action, "Executing \"%s\"\n", va_arg (args, char *));
118 break;
119 case RC_EXIT:
120 outf (AH_MT_Info, "Exit code: %d\n", va_arg (args, int));
121 break;
122 case RC_EMPTY:
123 outf (AH_MT_Error, "Error: Empty external command !\n");
124 break;
125 }
126 va_end (args);
127 }
128
129
AH_Archiver(const AH_Archiver * aptr)130 AH_Archiver::AH_Archiver (const AH_Archiver *aptr) // constructor
131 {
132 memset (this, 0, sizeof (*this)); // clear all fields
133 prev = aptr;
134 }
135
136
AH_ComprCfg(const char * cfgfile,AH_VShow outf)137 AH_ComprCfg::AH_ComprCfg (const char *cfgfile, AH_VShow outf) // constructor
138 {
139 FILE *f;
140 const char *tok, *tkp;
141
142 AH_ComprCfg::outf = outf;
143
144 lastarc = NULL;
145
146 f = fopen (cfgfile, "rt");
147 if (!f) {
148 if (outf)
149 outf (AH_MT_Error, "Error: cannot open \"%s\"\n", cfgfile);
150 return;
151 }
152
153 if (outf)
154 outf (AH_MT_Info, "Including Compress Definition \"%s\"\n", cfgfile);
155
156 BOOL InArchive = FALSE;
157
158 char lbuff[CFGLINESIZE];
159
160 while ((tok = fgetln (f, lbuff, tkp)) != NULL) {
161
162 #ifdef __OS2__
163 if (stricmp (tok, "DOS") == 0) // ignore DOS lines
164 continue;
165
166 if (stricmp (tok, "OS2") == 0) { // skip OS2 prefix
167 if ((tok = GetStatName (tkp)) == NULL)
168 continue;
169 }
170 #else // DOS
171 if (stricmp (tok, "OS2") == 0) // ignore OS2 lines
172 continue;
173
174 if (stricmp (tok, "DOS") == 0) { // skip DOS prefix
175 if ((tok = GetStatName (tkp)) == NULL)
176 continue;
177 }
178 #endif
179
180 if (!InArchive) {
181 if (stricmp (tok, "Archiver") == 0) {
182 if ((tok = GetStatName (tkp)) == NULL)
183 continue;
184 InArchive = TRUE;
185 lastarc = new AH_Archiver (lastarc);
186 lastarc->name = newcpy (tok);
187 continue;
188 }
189 } else { // Inside Archiver definition
190 if (stricmp (tok, "End") == 0) {
191 InArchive = FALSE;
192 continue;
193 }
194
195 if (stricmp (tok, "View") == 0) // ignore View command
196 continue;
197
198 if (stricmp (tok, "Extension") == 0) {
199 if ((tok = GetStatName (tkp)) == NULL)
200 continue;
201 lastarc->ext = newcpy (tok);
202 continue;
203 }
204
205 if (stricmp (tok, "Ident") == 0) {
206 if ((tok = GetStatName (tkp)) == NULL)
207 continue;
208 ScanIdent (tok);
209 continue;
210 }
211
212 if (stricmp (tok, "Add") == 0) {
213 if (*tkp == '\0')
214 continue;
215 lastarc->addcmd = GetAllocLn (tkp, GL_Empty);
216 continue;
217 }
218
219 if (stricmp (tok, "Extract") == 0) {
220 if (*tkp == '\0')
221 continue;
222 lastarc->extcmd = GetAllocLn (tkp, GL_Empty);
223 continue;
224 }
225 }
226
227 if (outf)
228 outf (AH_MT_Error, "\nUnknown or out of sequence ComprCfg line:\n%s\n\n", lbuff);
229 }
230
231 fclose (f);
232
233 if (outf)
234 outf (AH_MT_Info, "Finished Compress Definition \"%s\"\n", cfgfile);
235 }
236
237
ScanIdent(const char * tok)238 void AH_ComprCfg::ScanIdent (const char *tok)
239 {
240 char hexfig[3] = "00"; // initialized to set hexfig[2] = '\0';
241 byte identbuf[IDENTBUFSIZE];
242 int identlen = 0;
243
244 #ifndef __QNX__
245 char *p = strchr (tok, ',');
246 #else
247 char *p = strchr ((char *)tok, ',');
248 #endif // __QNX__
249
250 if (!p)
251 return;
252
253 p++; // points to first hex figure
254
255 while (*p) {
256 *hexfig = *(p++);
257 if (*p == '\0')
258 return;
259 *(hexfig+1) = *(p++);
260 identbuf[identlen++] = (byte) strtol (hexfig, NULL, 16);
261 }
262
263 lastarc->identofs = atoi (tok);
264
265 lastarc->identlen = identlen;
266
267 lastarc->identstr = new byte[identlen];
268 memcpy (lastarc->identstr, identbuf, identlen);
269 }
270
271
272 typedef enum { St_Start, // Look for 1st byte of ID
273 St_StrChk // Looking for next byte
274 } State;
275
276 struct _Status {
277 State state;
278 const AH_Archiver *CurArc; // current arc type in evaluation
279 ulong idofs; // current ofs in ID
280 };
281
282
ArcGood(const AH_Archiver * a)283 BOOL AH_ComprCfg::ArcGood (const AH_Archiver *a)
284 {
285 return ((a->identlen > 1) && (a->extcmd != NULL));
286 }
287
288
SfxNext(const AH_Archiver * a)289 const AH_Archiver *AH_ComprCfg::SfxNext (const AH_Archiver *a)
290 {
291 if (!a) {
292 a = lastarc;
293 if (!a)
294 return NULL;
295 if (ArcGood (a))
296 return a;
297 }
298
299 do {
300 a = a->prev;
301 if (!a)
302 return NULL;
303 } while (!ArcGood (a));
304
305 return a;
306 }
307
308
ChkSfx(const char * filename)309 const AH_Archiver *AH_ComprCfg::ChkSfx (const char *filename)
310 {
311 int namelen = strlen (filename);
312 if (namelen < 5)
313 return NULL;
314 if (stricmp (filename + namelen - 4, ".exe") != 0)
315 return NULL;
316
317
318 FILE *f = fopen (filename, "rb");
319 if (!f)
320 return NULL;
321 setvbuf (f, NULL, _IOFBF, 8192);
322
323 int ch;
324 _Status Status = { St_Start, SfxNext (NULL), 0 };
325 if (!Status.CurArc)
326 return NULL;
327 BOOL afound = FALSE;
328
329 while ((ch = fgetc (f)) != EOF) {
330 switch (Status.state) {
331
332 case St_Start: // looking for 1st byte of ID
333 if (!Status.CurArc)
334 Status.CurArc = SfxNext (NULL);
335 while (Status.CurArc) {
336 if (ch == Status.CurArc->identstr[0]) {
337 Status.state = St_StrChk;
338 Status.idofs = 1;
339 break;
340 }
341 Status.CurArc = SfxNext (Status.CurArc);
342 }
343 break;
344
345 case St_StrChk:
346 if (ch == Status.CurArc->identstr[Status.idofs++]) {
347 if (Status.CurArc->identlen == (long)Status.idofs)
348 afound = TRUE;
349 } else {
350 long nback = Status.idofs;
351 Status.state = St_Start;
352 Status.CurArc = SfxNext (Status.CurArc);
353 if (!Status.CurArc)
354 nback --;
355 fseek (f, -nback, SEEK_CUR);
356 }
357 break;
358 }
359
360 if (afound)
361 break;
362 }
363
364 fclose (f);
365
366 if (!afound)
367 return NULL;
368
369 return Status.CurArc;
370 }
371
372
UnArc(const char * filename,const char * extract)373 int AH_ComprCfg::UnArc (const char *filename, const char *extract)
374 { // Unarcs extract from filename
375 FILE *f; // returns errorlevel
376 const AH_Archiver *a; // returns -1 if cannot execute
377 int res; // returns -2 on unknown type
378 BOOL afound; // Archive type found // returns -3 on file not found
379 char buf[PATH_MAX], buf2[PATH_MAX];
380
381
382 f = fopen (filename, "rb");
383 if (!f) {
384 if (outf)
385 outf (AH_MT_Error, "Error: cannot open \"%s\"\n", filename);
386 return -3; // cannot open
387 }
388
389 afound = FALSE;
390 a = lastarc;
391 while (a) {
392 if ((a->identlen > 0) && (a->extcmd != NULL)) {
393 if (a->identofs >= 0)
394 res = fseek (f, a->identofs, SEEK_SET);
395 else
396 res = fseek (f, a->identofs, SEEK_END);
397 if (res == 0) { // seek successful
398 afound = TRUE;
399 for (int i = 0; i < a->identlen; i ++) {
400 res = fgetc (f);
401 if (res != a->identstr[i]) { // incl. EOF
402 afound = FALSE;
403 break;
404 }
405 }
406 if (afound)
407 break;
408 }
409 }
410 a = a->prev;
411 }
412
413 fclose (f);
414
415 if (!afound) {
416 a = ChkSfx (filename);
417 afound = (a != NULL);
418 }
419
420 if (!afound) {
421 if (outf)
422 outf (AH_MT_Error, "Error: unknown archive for \"%s\"\n", filename);
423 return -2; // Archive type not identified
424 }
425
426 /* Note from Gerrit (2:2411/12):
427 The following code tries two types to unarc commands:
428 1. extcmd filename "extract"
429 2. (if 1. has failed)
430 extcmd "filename extract"
431 The whole thing is about jokers (???) being present in extract. A shell
432 (e.g. under *ix) must be prevented to expand them - extract has to be given
433 to extcmd as is. However, sometimes (namely with arc under *ix) this seems
434 to fail and the 2nd form of command is tried (my arc sometimes works with
435 the first version, sometimes with the second - I really don't know why!).*/
436
437 sprintf(buf2,"%s",filename);
438 sprintf(buf,"\"%s\"",extract);
439 res = RunCmd (a->extcmd, RcShow, "af", buf2, buf);
440 if (res) {
441 outf (AH_MT_Error, "Warning: unable to extract from \"%s\"\n", filename);
442 outf (AH_MT_Error, "Warning: trying alternate extract command composition\n");
443 sprintf(buf2,"\"%s",filename);
444 sprintf(buf,"%s\"",extract);
445 res = RunCmd (a->extcmd, RcShow, "af", buf2, buf);
446 }
447 if (res) {
448 outf (AH_MT_Error, "Error: unable to extract from \"%s\"\n", filename);
449 outf (AH_MT_Error, "Error: giving up\n");
450 }
451 return res;
452 }
453
454
Arc(const AH_Archiver * a,const char * filename,const char * add)455 int AH_ComprCfg::Arc (const AH_Archiver *a, const char *filename, const char *add)
456 { // Adds add to filename using archiver
457 return RunCmd (a->addcmd, RcShow, "af", filename, add);
458 }
459
460
AddDefined(const char * method)461 const AH_Archiver *AH_ComprCfg::AddDefined (const char *method) // is method defined in cfg ?
462 { // return pointer
463 const AH_Archiver *a = lastarc;
464 while (a) {
465 if (stricmp (a->name, method) == 0) {
466 if ((a->addcmd != NULL) && (a->ext != NULL))
467 return a;
468 else
469 return NULL;
470 }
471 a = a->prev;
472 }
473 return NULL;
474 }
475
476
ExtDefined(const char * ext)477 const AH_Archiver *AH_ComprCfg::ExtDefined (const char *ext) // is extension defined in compress.cfg ?
478 {
479 const AH_Archiver *a = lastarc;
480 while (a) {
481 if (stricmp (a->ext, ext) == 0)
482 return a;
483 a = a->prev;
484 }
485 return NULL;
486 }
487