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