1 /*
2 * $Id: fardata.c,v 1.6 2004/04/17 11:39:43 andrew_belov Exp $
3 * ---------------------------------------------------------------------------
4 * This file contains routines dealing with far data segment and CRC.
5 *
6 */
7
8 #include "arj.h"
9 #ifdef TILED
10 #include <dos.h> /* Weird, eh? */
11 #endif
12
13 /* ASR fix 02/05/2003: need that regardless of COLOR_OUTPUT to support -jp
14 correctly */
15 #if SFX_LEVEL>=ARJ
16 #define CUSTOM_PRINTF
17 #define CHUNK_SIZE 512 /* Size of the output block */
18 #define CHUNK_THRESHOLD (CHUNK_SIZE-256) /* Safety bound */
19 #endif
20
21 DEBUGHDR(__FILE__) /* Debug information block */
22
23 #ifdef CUSTOM_PRINTF
24
25 /* Forward Declaration */
26
27 int vcprintf(int ccode, FMSG *fmt, va_list args);
28
29 #endif
30
31 #if SFX_LEVEL>=ARJ
32
33 /* Checks if the error can have an error code or not */
34
is_std_error(FMSG * errmsg)35 static int is_std_error(FMSG *errmsg)
36 {
37 return(errmsg==M_DISK_FULL||errmsg==M_CANT_DELETE||errmsg==M_CANTOPEN||
38 errmsg==M_CANTRENAME||errmsg==M_CANTREAD||errmsg==M_CANT_DELETE||
39 errmsg==M_CANT_COPY_TEMP)?1:0;
40 }
41
42 #endif
43
44 /* Makes various cleanup depending on the error message received and quits. */
45
error_proc(FMSG * errmsg,...)46 int error_proc(FMSG *errmsg, ...)
47 {
48 char *tmp_errmsg;
49 va_list marker;
50
51 #if SFX_LEVEL>=ARJ
52 /* Check if the message could have a standard error code */
53 if(errno!=0&&is_std_error(errmsg))
54 {
55 msg_cprintf(0, "\n");
56 error_report();
57 }
58 #endif
59 #if SFX_LEVEL>=ARJSFXV
60 if(quiet_mode==ARJ_SILENT)
61 freopen(dev_con, m_w, stdout);
62 #endif
63 #if SFX_LEVEL>=ARJ
64 file_settype(stdout, ARJT_TEXT);
65 #endif
66 /* For SFX archives, don't forget to display our logo */
67 #if SFX_LEVEL==ARJSFXV
68 show_sfx_logo();
69 #elif SFX_LEVEL==ARJSFX
70 if(!logo_shown)
71 {
72 msg_cprintf(0, M_ARJSFX_BANNER, exe_name);
73 msg_cprintf(0, M_PROCESSING_ARCHIVE, archive_name);
74 }
75 #endif
76 #if SFX_LEVEL>=ARJ
77 nputlf();
78 #elif SFX_LEVEL>=ARJSFXV
79 fputc(LF, new_stdout);
80 #else
81 fputc(LF, stdout);
82 #endif
83 /* Format and print the error message */
84 va_start(marker, errmsg);
85 #ifdef CUSTOM_PRINTF
86 vcprintf(H_ERR, errmsg, marker);
87 #else
88 tmp_errmsg=malloc_fmsg(errmsg);
89 #if SFX_LEVEL>=ARJSFXV
90 vfprintf(new_stdout, (FMSG *)tmp_errmsg, marker);
91 #else
92 vprintf(tmp_errmsg, marker);
93 #endif
94 free_fmsg(tmp_errmsg);
95 #endif
96 va_end(marker);
97 #if SFX_LEVEL>=ARJ
98 nputlf();
99 #elif SFX_LEVEL>=ARJSFXV
100 fputc(LF, new_stdout);
101 #else
102 fputc(LF, stdout);
103 #endif
104 /* Terminate the execution with a specific errorlevel */
105 #if SFX_LEVEL>=ARJSFXV
106 /* If there's no errorlevel yet, select errorlevel by message class */
107 if(errorlevel==0)
108 errorlevel=subclass_errors(errmsg);
109 /* If the error was the lack of memory, display final memory statistics to
110 find memory leaks */
111 #if SFX_LEVEL>=ARJ
112 if(errorlevel==ARJ_ERL_NO_MEMORY)
113 mem_stats();
114 #endif
115 error_occured=1;
116 exit(errorlevel);
117 #elif defined(REARJ)
118 exit(REARJ_ERL_WARNING);
119 #elif defined(REGISTER)
120 exit(REGISTER_ERL_ERROR);
121 #elif SFX_LEVEL>=ARJSFX
122 exit(ARJSFX_ERL_ERROR);
123 #else
124 exit(1);
125 #endif
126 return(0);
127 }
128
129 #ifdef FMSG_ST
130
131 /* A printf() function for far strings */
132
msg_printf(FMSG * fmt,...)133 int msg_printf(FMSG *fmt, ...)
134 {
135 va_list marker;
136 char *storage;
137 int result;
138
139 storage=malloc_far_str(fmt);
140 va_start(marker, fmt);
141 result=vfprintf(new_stdout, (FMSG *)storage, marker);
142 va_end(marker);
143 free(storage);
144 return(result);
145 }
146
147 /* A fprintf() function for far strings */
148
msg_fprintf(FILE * stream,FMSG * fmt,...)149 int msg_fprintf(FILE *stream, FMSG *fmt, ...)
150 {
151 va_list marker;
152 char *storage;
153 int result;
154
155 storage=malloc_far_str(fmt);
156 va_start(marker, fmt);
157 result=vfprintf(stream, storage, marker);
158 va_end(marker);
159 free(storage);
160 return(result);
161 }
162
163 /* A sprintf() function for far strings */
164
msg_sprintf(char * str,FMSG * fmt,...)165 int msg_sprintf(char *str, FMSG *fmt, ...)
166 {
167 va_list marker;
168 char *storage;
169 int result;
170
171 storage=malloc_far_str(fmt);
172 va_start(marker, fmt);
173 result=vsprintf(str, storage, marker);
174 va_end(marker);
175 free(storage);
176 return(result);
177 }
178
179 #endif
180
181 #ifdef CUSTOM_PRINTF
182
183 /*
184 * A Q&D custom printf() implementation. Derived from:
185 *
186 * vsprintf.c -- Lars Wirzenius & Linus Torvalds.
187 * Wirzenius wrote this portably, Torvalds f*cked it up :-)
188 *
189 */
190
191 /* Length-limited strlen() */
192
193 #ifndef HAVE_STRNLEN
strnlen(const char FAR * s,int count)194 static int strnlen(const char FAR *s, int count)
195 {
196 const char FAR *sc;
197
198 for(sc=s; *sc!='\0'&&count--; ++sc)
199 ;
200 return(sc-s);
201 }
202 #endif
203
204 /* Hex representation of digits */
205
adigit(unsigned long n,int is_uc)206 static char adigit(unsigned long n, int is_uc)
207 {
208 if(n<10)
209 return('0'+n);
210 n-=10;
211 return((is_uc?'A':'a')+n);
212 }
213
214 /* Q'n'D strtoul() implementation */
215
simple_strtoul(const FMSG * cp,FMSG ** endp,unsigned int base)216 unsigned long simple_strtoul(const FMSG *cp, FMSG **endp, unsigned int base)
217 {
218 unsigned long result=0, value;
219
220 if(!base)
221 {
222 base=10;
223 if(*cp=='0')
224 {
225 base=8;
226 cp++;
227 if((*cp=='x')&&isxdigit(cp[1]))
228 {
229 cp++;
230 base=16;
231 }
232 }
233 }
234 while(isxdigit(*cp)&&(value=isdigit(*cp)?
235 *cp-'0':
236 (islower(*cp)?toupper(*cp):*cp)-'A'+10)<base)
237 {
238 result=result*base+value;
239 cp++;
240 }
241 if(endp)
242 *endp=(FMSG *)cp;
243 return(result);
244 }
245
246 /* Convert digits and skip over them */
247
skip_atoi(FMSG ** s)248 static int skip_atoi(FMSG **s)
249 {
250 int i=0;
251
252 while(isdigit(**s))
253 i=i*10+*((*s)++)-'0';
254 return(i);
255 }
256
257 #define ZEROPAD 1 /* pad with zero */
258 #define SIGN 2 /* unsigned/signed long */
259 #define PLUS 4 /* show plus */
260 #define SPACE 8 /* space if plus */
261 #define LEFT 16 /* left justified */
262 #define SPECIAL 32 /* 0x */
263 #define LARGE 64 /* use 'ABCDEF' instead of 'abcdef' */
264 #define FAR_STR 128 /* Far strings (Fs) */
265
266 /* Number representation routine */
267
number(char * istr,long num,int base,int size,int precision,int type)268 static int number(char *istr, long num, int base, int size, int precision, int type)
269 {
270 char c, sign, tmp[66];
271 int i;
272 int ucase_dig=0;
273 char *str;
274
275 str=istr;
276 if(type&LARGE)
277 ucase_dig=1;
278 if(type&LEFT)
279 type&=~ZEROPAD;
280 if(base<2||base>36)
281 return(0);
282 c=(type&ZEROPAD)?'0':' ';
283 sign=0;
284 if(type&SIGN)
285 {
286 if(num<0)
287 {
288 sign='-';
289 num=-num;
290 size--;
291 }
292 else if(type&PLUS)
293 {
294 sign='+';
295 size--;
296 }
297 else if(type&SPACE)
298 {
299 sign=' ';
300 size--;
301 }
302 }
303 if(type&SPECIAL)
304 {
305 if(base==16)
306 size-=2;
307 else if(base==8)
308 size--;
309 }
310 i=0;
311 if(num==0)
312 tmp[i++]='0';
313 else while (num!=0)
314 {
315 unsigned long __res;
316
317 __res=((unsigned long)num)%(unsigned long)base;
318 num=((unsigned long)num)/(unsigned long)base;
319 tmp[i++]=adigit(__res, ucase_dig);
320 }
321 if(i>precision)
322 precision=i;
323 size-=precision;
324 if(!(type&(ZEROPAD+LEFT)))
325 {
326 while(size-->0)
327 *str++=' ';
328 }
329 if(sign)
330 *str++=sign;
331 if(type&SPECIAL)
332 {
333 if(base==8)
334 *str++='0';
335 else if(base==16)
336 {
337 *str++='0';
338 *str++=ucase_dig?'X':'x';
339 }
340 }
341 if(!(type&LEFT))
342 {
343 while(size-->0)
344 *str++=c;
345 }
346 while(i<precision--)
347 *str++='0';
348 while(i-->0)
349 *str++=tmp[i];
350 while(size-->0)
351 *str++=' ';
352 return(str-istr);
353 }
354
355 /* Flushes the output buffer downstream. The buffer gets clobbered. */
356
flush_cbuf(int ccode,char * text)357 static void flush_cbuf(int ccode, char *text)
358 {
359 char *n_text, *t_text;
360 int need_pause, rc;
361 char c;
362
363 if(quiet_mode==ARJ_SILENT||(quiet_mode==ARJ_QUIET&&!(ccode&H_FORCE)))
364 return;
365 CLOBBER_SENTRY();
366 need_pause=(prompt_for_more&&!yes_on_all_queries&&!print_with_more);
367 n_text=t_text=text;
368 #ifdef COLOR_OUTPUT
369 if(!redirected&&!no_colors)
370 textcolor(color_table[ccode&H_COLORMASK].color);
371 #endif
372 while((c=*t_text)!='\0')
373 {
374 if(c==LF)
375 {
376 *t_text='\0';
377 #ifdef COLOR_OUTPUT
378 if(redirected)
379 {
380 #if SFX_LEVEL>=ARJSFXV
381 fprintf(new_stdout, strform, n_text);
382 fprintf(new_stdout, "\n");
383 #else
384 printf(strform, n_text);
385 printf("\n");
386 #endif
387 }
388 else
389 {
390 scr_out(n_text);
391 if(!no_colors)
392 textcolor(7);
393 #ifdef NEED_CRLF
394 scr_out("\r");
395 #endif
396 scr_out("\n");
397 }
398 if(!no_colors)
399 textcolor(color_table[ccode&H_COLORMASK].color);
400 #else
401 printf(strform, n_text);
402 printf("\n");
403 #endif
404 n_text=t_text+1;
405 #if SFX_LEVEL>=ARJ
406 lines_scrolled++;
407 if(lines_scrolled>=lines_per_page-1)
408 {
409 lines_scrolled=0;
410 if(need_pause)
411 {
412 rc=pause();
413 #ifdef COLOR_OUTPUT
414 /* Restore the color after implicit recursion to msg_cprintf() */
415 if(!no_colors)
416 textcolor(color_table[ccode&H_COLORMASK].color);
417 #endif
418 if(!rc&&(ccode&H_WEAK))
419 longjmp(main_proc, 1);
420 }
421 }
422 #endif
423 }
424 t_text++;
425 }
426 #ifdef COLOR_OUTPUT
427 if(redirected)
428 #if SFX_LEVEL>=ARJSFXV
429 fprintf(new_stdout, strform, n_text);
430 #else
431 printf(strform, n_text);
432 #endif
433 else
434 scr_out(n_text);
435 #else
436 printf(strform, n_text);
437 #endif
438 }
439
440 /* vcprintf() implementation */
441
vcprintf(int ccode,FMSG * fmt,va_list args)442 int vcprintf(int ccode, FMSG *fmt, va_list args)
443 {
444 int len;
445 unsigned long num;
446 int i, base;
447 char FAR *s;
448 int flags; /* flags to number() */
449 int field_width; /* width of output field */
450 int precision; /* min. # of digits for integers; max
451 number of chars for from string */
452 int qualifier; /* 'h', 'l', or 'L' for integer
453 fields */
454 int far_str; /* Far string qualifier */
455 char buf[CHUNK_SIZE]; /* Output buffer */
456 int p_buf;
457 int rc=0;
458 int ocode; /* Output color code for formatted
459 fields (that's what the whole
460 routine is about!) */
461 long *ipl;
462 int *ipi;
463 int last_fmt=0;
464
465 ocode=(ccode&H_NFMT)?H_STD:ccode;
466 for(p_buf=0; *fmt; ++fmt)
467 {
468 if(last_fmt&&ccode&H_NFMT)
469 {
470 last_fmt=0;
471 buf[p_buf]='\0';
472 rc+=p_buf;
473 p_buf=0;
474 flush_cbuf(ocode, buf);
475 }
476 if(*fmt!='%'||*(fmt+1)=='%')
477 {
478 if(p_buf>=CHUNK_SIZE-1)
479 {
480 buf[p_buf]='\0';
481 rc+=p_buf;
482 p_buf=0;
483 flush_cbuf(ccode, buf);
484 }
485 buf[p_buf++]=*fmt;
486 if(*fmt=='%')
487 ++fmt; /* Skip over the 2nd percent - we've handled
488 it here */
489 continue;
490 }
491 /* A format symbol is found - flush the buffer if:
492 1. It's H_NFMT, so we need to change the brush, OR
493 2. CHUNK_THRESHOLD has been exceeded (for numeric) */
494 if(ccode&H_NFMT||p_buf>=CHUNK_THRESHOLD)
495 {
496 buf[p_buf]='\0';
497 rc+=p_buf;
498 p_buf=0;
499 flush_cbuf(ccode, buf);
500 }
501 last_fmt=1;
502 /* Process flags */
503 flags=0;
504 repeat:
505 ++fmt; /* This also skips first '%' */
506 switch(*fmt)
507 {
508 case '-': flags|=LEFT; goto repeat;
509 case '+': flags|=PLUS; goto repeat;
510 case ' ': flags|=SPACE; goto repeat;
511 case '#': flags|=SPECIAL; goto repeat;
512 case '0': flags|=ZEROPAD; goto repeat;
513 case 'F': flags|=FAR_STR; goto repeat;
514 }
515 /* Get field width */
516 field_width=-1;
517 if(isdigit(*fmt))
518 field_width=skip_atoi((FMSG **)&fmt);
519 else if(*fmt=='*')
520 {
521 ++fmt;
522 /* It's the next argument */
523 field_width=va_arg(args, int);
524 if(field_width<0)
525 {
526 field_width=-field_width;
527 flags|=LEFT;
528 }
529 }
530 /* Get the precision */
531 precision=-1;
532 if(*fmt=='.')
533 {
534 ++fmt;
535 if(isdigit(*fmt))
536 precision=skip_atoi((FMSG **)&fmt);
537 else if(*fmt=='*')
538 {
539 ++fmt;
540 /* It's the next argument */
541 precision=va_arg(args, int);
542 }
543 if(precision<0)
544 precision=0;
545 }
546 /* Get the conversion qualifier */
547 qualifier=-1;
548 if(*fmt=='h'||*fmt=='l'||*fmt=='L')
549 {
550 qualifier=*fmt;
551 ++fmt;
552 }
553 /* Default base */
554 base=10;
555 switch(*fmt)
556 {
557 case 'c':
558 if(!(flags&LEFT))
559 while(--field_width>0)
560 buf[p_buf++]=' ';
561 buf[p_buf++]=(unsigned char)va_arg(args, int);
562 while(--field_width>0)
563 buf[p_buf++]=' ';
564 continue;
565 case 's':
566 if(!(flags&FAR_STR))
567 s=(char FAR *)va_arg(args, char NEAR *);
568 else
569 s=va_arg(args, char FAR *);
570 #ifdef DEBUG
571 if(!s)
572 s="(null)";
573 #endif
574 len=strnlen(s, precision);
575 if(!(flags&LEFT))
576 {
577 while(len<field_width--)
578 {
579 if(p_buf>=CHUNK_SIZE-1)
580 {
581 buf[p_buf]='\0';
582 rc+=p_buf;
583 p_buf=0;
584 flush_cbuf(ocode, buf);
585 }
586 buf[p_buf++]=' ';
587 }
588 }
589 for(i=0; i<len; ++i)
590 {
591 if(p_buf>=CHUNK_SIZE-1)
592 {
593 buf[p_buf]='\0';
594 rc+=p_buf;
595 p_buf=0;
596 flush_cbuf(ocode, buf);
597 }
598 buf[p_buf++]=*s++;
599 }
600 while(len<field_width--)
601 {
602 if(p_buf>=CHUNK_SIZE-1)
603 {
604 buf[p_buf]='\0';
605 rc+=p_buf;
606 p_buf=0;
607 flush_cbuf(ocode, buf);
608 }
609 buf[p_buf++]=' ';
610 }
611 continue;
612 case 'p':
613 if(field_width==-1)
614 {
615 field_width=2*sizeof(void *);
616 flags|=ZEROPAD;
617 }
618 p_buf+=number(buf+p_buf, (unsigned long)va_arg(args, void *), 16,
619 field_width, precision, flags);
620 continue;
621 case 'n':
622 if(qualifier=='l')
623 {
624 ipl=va_arg(args, long *);
625 *ipl=p_buf;
626 }
627 else
628 {
629 ipi=va_arg(args, int *);
630 *ipi=p_buf;
631 }
632 continue;
633 /* Integer number formats - set up the flags and "break" */
634 case 'o':
635 base=8;
636 break;
637 case 'X':
638 flags|=LARGE;
639 case 'x':
640 base=16;
641 break;
642 case 'd':
643 case 'i':
644 flags|=SIGN;
645 case 'u':
646 break;
647 default:
648 if(*fmt!='%')
649 buf[p_buf++]='%';
650 if(*fmt)
651 buf[p_buf++]=*fmt;
652 else
653 --fmt;
654 continue;
655 }
656 if(qualifier=='l')
657 num=va_arg(args, unsigned long);
658 else if(qualifier=='h')
659 {
660 #ifdef __linux__
661 if (flags&SIGN)
662 num=va_arg(args, int); /* num=va_arg(args, short); */
663 else
664 num=va_arg(args, int); /* num=va_arg(args, unsigned short);*/
665 #else
666 if(flags&SIGN)
667 num=va_arg(args, short);
668 else
669 num=va_arg(args, unsigned short);
670 #endif
671 }
672 else if(flags&SIGN)
673 num=va_arg(args, int);
674 else
675 num=va_arg(args, unsigned int);
676 p_buf+=number(buf+p_buf, num, base, field_width, precision, flags);
677 }
678 if(p_buf>0)
679 {
680 buf[p_buf]='\0';
681 rc+=p_buf;
682 flush_cbuf(last_fmt?ocode:ccode, buf);
683 }
684 return(rc);
685 }
686
687 #endif /* CUSTOM_PRINTF */
688
689 #if SFX_LEVEL>=ARJSFX||defined(REARJ)
690
691 /* Helper routine for scrprintf() */
692
msg_cprintf(int ccode,FMSG * fmt,...)693 int msg_cprintf(int ccode, FMSG *fmt, ...)
694 {
695 #ifndef CUSTOM_PRINTF
696 char *storage;
697 #endif
698 va_list marker;
699 int result;
700
701 #ifndef CUSTOM_PRINTF
702 #ifdef FMSG_ST
703 storage=malloc_far_str(fmt);
704 #else
705 storage=fmt;
706 #endif
707 #endif
708 va_start(marker, fmt);
709 #if defined(CUSTOM_PRINTF)
710 result=vcprintf(ccode, fmt, marker);
711 #elif SFX_LEVEL>=ARJSFXV
712 result=vfprintf(new_stdout, (FMSG *)storage, marker);
713 #else
714 result=vprintf(storage, marker);
715 #endif
716 va_end(marker);
717 #if defined(FMSG_ST)&&!defined(CUSTOM_PRINTF)
718 free(storage);
719 #endif
720 return(result);
721 }
722
723 #endif
724
725 #if SFX_LEVEL>=ARJSFX&&defined(TILED)
726
727 /* A model-independent movedata() function (it must go to ENVIRON.C) */
728
far_memmove(char FAR * dest,char FAR * src,int length)729 void far_memmove(char FAR *dest, char FAR *src, int length)
730 {
731 movedata(FP_SEG(src), FP_OFF(src), FP_SEG(dest), FP_OFF(dest), length);
732 }
733
734 #endif
735
736 #if SFX_LEVEL>=ARJ
737
738 /* Initializes CRC32 subsystem (only used by main()) */
739
init_crc()740 void init_crc()
741 {
742 build_crc32_table();
743 }
744
745 /* Returns CRC32 for the given block */
746
crc_for_block(char * block,unsigned int length)747 void crc_for_block(char *block, unsigned int length)
748 {
749 crc32_for_block(block, length);
750 }
751
752 /* Returns CRC32 for the given string */
753
crc_for_string(char * str)754 void crc_for_string(char *str)
755 {
756 crc32_for_string(str);
757 }
758
759 #endif
760
761 #ifdef COLOR_OUTPUT
762
763 /* Parse the color table */
764
parse_colors(char * opt)765 int parse_colors(char *opt)
766 {
767 int i, c;
768 char *p;
769 int rc=0;
770
771 if(*opt=='\0')
772 {
773 no_colors=1;
774 textcolor(7); /* HACK */
775 return(0);
776 }
777 while(*opt!='\0')
778 {
779 for(p=opt; !isdigit(*p); p++)
780 {
781 if(*p=='\0')
782 {
783 opt=p;
784 goto next_opt;
785 }
786 }
787 c=atoi(p);
788 if(c>=32)
789 rc++;
790 else
791 {
792 for(i=0; color_table[i].arg!='\0'||!(++rc); i++)
793 {
794 if(color_table[i].arg==tolower(*opt))
795 {
796 color_table[i].color=(char)c;
797 break;
798 }
799 }
800 }
801 next_opt:
802 while(*opt!='\0'&&!isdigit(*opt))
803 opt++;
804 while(*opt!='\0'&&(isdigit(*opt)||!isalpha(*opt)))
805 opt++;
806 }
807 return(rc);
808 }
809
810 #endif
811