/* * $Id: arj_file.c,v 1.10 2005/06/21 19:53:13 andrew_belov Exp $ * --------------------------------------------------------------------------- * Various archive-management functions (mostly, file-related ones) are stored * here. * */ #include "arj.h" DEBUGHDR(__FILE__) /* Debug information block */ /* Character used in counters */ #if TARGET!=UNIX #define COUNTER_CHAR 0xB2 #else #define COUNTER_CHAR '#' #endif #define UNDISP_CHAR '?' /* Replaces nonprintable characters */ /* Local variables */ static char reply_help[]="?"; /* Request for help */ #if SFX_LEVEL>=ARJ static char ext_digits[]=".%03d"; /* Pattern used to serialize extensions */ #endif /* Counter formatting sequences */ #if SFX_LEVEL>=ARJSFXV static char del_single[]="\b\b\b\b\b"; static char del_double[]="\b\b\b\b\b\b\b\b\b\b"; static char sfmt_single[]=" %s"; static char sfmt_double[]=" %s"; static char sfmt_bytes[]="%10ld%s"; static char sfmt_start_graph[]=" 0%%%s"; static char sfmt_numeric[]="%4d%%%s"; #if SFX_LEVEL>=ARJ static char sfmt_start_num[]=" %d%%"; #if TARGET!=UNIX static char sfmt_graph[]="þþþþþþþþþþ%s"; static char sfmt_mid_graph[]="þþþþþ%s"; #else static char sfmt_graph[]="..........%s"; static char sfmt_mid_graph[]=".....%s"; #endif static char sfmt_short_numeric[]="%4d%%"; #endif #else static char sfmt_sfx[]="%4d%%\b\b\b\b\b"; #endif /* Local forward-referenced functions */ static int display_block(char *str, int len); static int block_op(int action, char *block, int len); #if SFX_LEVEL>=ARJSFXV /* Closes the file given */ int file_close(FILE *stream) { if(stream!=NULL) return(fclose(stream)); else return(-1); } /* Opens a file, possibly clearing its FA_ARCH attribute (read-only modes are not affected) */ FILE *file_open_noarch(char *name, char *mode) { FILE *stream; #if TARGET!=UNIX if(clear_archive_bit&&(mode[0]=='w'||mode[0]=='a'||mode[1]=='+'||mode[2]=='+')) dos_chmod(name, STD_FATTR_NOARCH); #endif if((stream=file_open(name, mode))==NULL) error(M_CANTOPEN, name); return(stream); } #endif #if SFX_LEVEL>=ARJ /* Overwrites a file, querying user if it exists */ FILE *file_create(char *name, char *mode) { if(file_exists(name)) { if(!yes_on_all_queries&&!overwrite_existing) { msg_cprintf(0, M_EXISTS, name); if(!query_action(REPLY_YES, QUERY_OVERWRITE, M_QUERY_OVERWRITE)) error(M_CANTOPEN, name); } #if TARGET!=UNIX if(clear_archive_bit&&(mode[0]=='w'||mode[0]=='a'||mode[1]=='+'||mode[2]=='+')) dos_chmod(name, STD_FATTR_NOARCH); #endif } return(file_open(name, mode)); } #endif #ifndef REARJ /* Reads a byte from the file */ int fget_byte(FILE *stream) { int buffer; buffer=fgetc(stream); if(buffer==EOF) { if(ignore_archive_errors) { #if SFX_LEVEL>=ARJSFXV msg_cprintf(H_ERR, M_CANTREAD); #else msg_cprintf(H_ERR, M_CANTREAD); #endif return(0); } else error(M_CANTREAD); } return(buffer&0xFF); } /* Reads two bytes from the file */ unsigned int fget_word(FILE *stream) { unsigned int b0, b1; b0=fget_byte(stream); b1=fget_byte(stream); return((b1<<8)|b0); } /* Reads four bytes from the file */ unsigned long fget_longword(FILE *stream) { unsigned int w0, w1; w0=fget_word(stream); w1=fget_word(stream); return(((unsigned long)w1<<16)|(unsigned long)w0); } /* Reads a block from the file, updating CRC */ int fread_crc(char *buffer, int count, FILE *stream) { int n; n=fread(buffer, 1, count, stream); if(n>0) { origsize+=(unsigned long)n; crc_for_block((char *)buffer, n); } return(n); } #endif #if SFX_LEVEL>=ARJ /* Writes a block, updating the CRC term */ void fwrite_crc(char *buffer, int count, FILE *stream) { crc_for_block(buffer, count); if(stream!=NULL) file_write(buffer, 1, count, stream); } #endif #ifndef REARJ /* Processes the given block upon extraction. Returns a nonzero value if the extraction is to be terminated. */ int extraction_stub(char *block, int block_len, int action) { char c; char *block_ptr; int cn; #if SFX_LEVEL>=ARJ if(!debug_enabled||strchr(debug_opt, 'c')==NULL) crc_for_block(block, block_len); #else crc32_for_block(block, block_len); #endif if(!file_packing) /* Not applicable for memory data */ { if(encmem_limit=ARJ if(action==BOP_LIST||action==BOP_SEARCH||action==BOP_COMPARE||action==BOP_DISPLAY) return(block_op(action, block, block_len)); #endif if(atstream==NULL) return(0); /* Strip high bit from files created by different OS */ if(file_type==ARJT_TEXT&&host_os!=OS #if SFX_LEVEL>=ARJ &&type_override!=FT_BINARY #endif ) { block_ptr=block; while(block_len-->0) { c=*(block_ptr++); c&=0x7F; if(fputc((int)c, atstream)==EOF) error(M_DISK_FULL); } } else { /* HACK for IBM LIBC implementations under 32-bit OS/2 */ #if SFX_LEVEL>=ARJSFXV&&TARGET==OS2&&(COMPILER==ICC||defined(LIBC)) int fn=fileno(atstream); if(fn<6) { _setmode(fn, file_type?0x4000:0x8000); /* O_TEXT:O_BINARY */ cn=write(fn, block, block_len); } else cn=fwrite(block, 1, block_len, atstream); #else cn=fwrite(block, 1, block_len, atstream); #endif #if SFX_LEVEL>=ARJSFXV if(is_tty(atstream)) cn=block_len; #endif if(cn!=block_len) error(M_DISK_FULL); } return(0); } /* Executed when decoding is initialized */ void decode_start_stub() { #if SFX_LEVEL>=ARJ subbitbuf=0; #endif bitbuf=0; byte_buf=0; bitcount=0; fillbuf(CHAR_BIT*2); #if SFX_LEVEL>=ARJSFXV mem_stats(); #endif } #endif #if SFX_LEVEL>=ARJSFXV /* Executed when the decoding memory variables are released */ void decode_end_stub() { /* Currently empty, may contain debugging checks if needed. */ } #endif #if SFX_LEVEL>=ARJ /* Finds an non-existent filename that matches the given format string. The format string must contain "%d" somewhere because the names are numbered. */ char *find_tmp_filename(char *name_format) { char tmp_name[CCHMAXPATH]; int i; for(i=0; i<=99; i++) { sprintf(tmp_name, name_format, i); if(!file_exists(tmp_name)) return(strcpy(name_format, tmp_name)); } error(M_CANTOPEN, name_format); return(0); /* not reached, avoid warning */ } /* Creates an numeric extension to the name, returns -1 if failed */ int find_num_ext(char *name, int mode) { char tmp_name[CCHMAXPATHCOMP]; char tmp_ext[CCHMAXPATHCOMP]; int name_offset; char *ext_offset; int ext_num; strcpy(tmp_name, name); name_offset=split_name(tmp_name, NULL, NULL); if((ext_offset=strchr(&tmp_name[name_offset], '.'))==NULL) strcat(tmp_name, ext_digits); else { strcpy(tmp_ext, ext_offset); /* Remember the original extension */ strcpy(ext_offset, ext_digits); /* Substitute extension */ if(mode==EXT_INSERT) strcat(tmp_name, tmp_ext); /* Complete with original extension */ } for(ext_num=0; ext_num<999; ext_num++) { sprintf(name, tmp_name, ext_num); if(!file_exists(name)) return(0); } msg_cprintf(0, M_EXISTS, name); return(-1); } /* Treats filename as an ARCmail packet and finds a suitable name for it */ int find_arcmail_name(char *name) { unsigned long counter; char *nptr; char c; for(counter=0L; counter<100000000L; counter++) { if((nptr=strchr(name+1, '.'))==NULL) nptr=name+strlen(name); nptr--; do { c=*nptr; if(!isdigit(c)) c='0'; else c++; if(c>'9') { *nptr='0'; if(nptr==name) { msg_cprintf(0, M_RANGE_EXCEEDED, name); return(-1); } nptr--; } else *nptr=c; } while(c>'9'); if(!file_exists(name)) return(0); } msg_cprintf(0, M_EXISTS, name); return(-1); } #endif #if SFX_LEVEL>=ARJSFXV /* Puts the given character to the console */ static int nputc(int c) { msg_cprintf(0, (FMSG *)"%c", c); return(c); } #endif #if SFX_LEVEL>=ARJ /* Reads a command for execution from the stdin */ void query_cmd() { char cmd[CMDLINE_LENGTH]; msg_cprintf(0, M_COMMAND); read_line(cmd, sizeof(cmd)); alltrim(cmd); if(cmd[0]!='\0') exec_cmd(cmd); } #endif /* Compares the first n characters of two MSG-strings (used exclusively by query_action_proc()) */ #if SFX_LEVEL>=ARJ static int cmp_far_str(char FAR *str1, char FAR *str2, int length) { int result; char *nstr1, *nstr2; nstr1=malloc_far_str(str1); nstr2=malloc_far_str(str2); result=strncmp(nstr1, nstr2, length); free(nstr1); free(nstr2); return(result); } #define msg_strncmp(str1, str2, length) cmp_far_str((char FAR *)str1, (char FAR *)str2, length) #else #define msg_strncmp strncmp #endif /* Query routine - used exclusively by query_action() */ #if SFX_LEVEL>=ARJSFXV static int query_action_proc(int def, int qtype, char *query) { char reply_text[INPUT_LENGTH]; int sel, key, ukey; char *sel_ptr, *rt_ptr; int rt_len; if(query!=NULL) msg_cprintf(H_PROMPT, (FMSG *)strform, query); #if SFX_LEVEL>=ARJ if(qtype!=QUERY_CRITICAL&&queries_assume_no[qtype]) { msg_cprintf(H_OPER, M_NO); msg_cprintf(0, (FMSG *)lf); return(0); } if(qtype!=QUERY_CRITICAL&&queries_assume_yes[qtype]) { msg_cprintf(H_OPER, M_YES); msg_cprintf(0, (FMSG *)lf); return(1); } #endif if(kbd_cleanup_on_input) fetch_keystrokes(); #if SFX_LEVEL>=ARJ if(accept_shortcut_keys) { while(1) { do { while(1) { key=uni_getch(); /* If possible default action selected */ if(def!=0&&key==LF) { msg_cprintf(0, (FMSG *)lf); if(def==1) return(1); if(def==2) return(0); } ukey=toupper(key); far_strcpy(strcpy_buf, M_REPLIES); sel_ptr=strchr(strcpy_buf, ukey); sel=sel_ptr-strcpy_buf; if(ukey!=0&&sel_ptr!=NULL&&(qtype!=QUERY_CRITICAL||sel<=REPLY_QUIT)) break; fetch_keystrokes(); nputc(BEL); } nputc(key); msg_cprintf(0, (FMSG *)lf); } while(sel>MAX_REPLY); switch(sel) { case REPLY_YES: return(1); case REPLY_NO: return(0); case REPLY_QUIT: exit(ARJ_ERL_WARNING); case REPLY_ALL: if(qtype!=QUERY_CRITICAL) queries_assume_yes[qtype]=1; return(1); case REPLY_SKIP: if(qtype!=QUERY_CRITICAL) queries_assume_no[qtype]=1; return(0); case REPLY_GLOBAL: yes_on_all_queries=1; return(1); case REPLY_COMMAND: query_cmd(); if(query!=NULL) msg_cprintf(H_PROMPT, (FMSG *)strform, query); } } /* There is no way down here */ } #endif /* Use an editable field */ while(1) { read_line(reply_text, INPUT_LENGTH); for(rt_ptr=reply_text; rt_ptr[0]==' '; rt_ptr++); if((rt_len=strlen(rt_ptr))>0) { strupper(rt_ptr); if(!msg_strncmp(rt_ptr, reply_help, rt_len)) { far_strcpy(strcpy_buf, (qtype==QUERY_CRITICAL)?M_REPLIES_HELP:M_ALL_REPLIES_HELP); msg_cprintf(0, (FMSG *)strcpy_buf); continue; } else if(!msg_strncmp(rt_ptr, M_NO, rt_len)) return(0); else if(!msg_strncmp(rt_ptr, M_YES, rt_len)) return(1); else if(!msg_strncmp(rt_ptr, M_QUIT, rt_len)) exit(1); else if(qtype!=QUERY_CRITICAL) { #if SFX_LEVEL>=ARJ if(!msg_strncmp(rt_ptr, M_ALWAYS, rt_len)) { if(qtype!=QUERY_CRITICAL) queries_assume_yes[qtype]=1; return(1); } if(!msg_strncmp(rt_ptr, M_SKIP, rt_len)) { if(qtype!=QUERY_CRITICAL) queries_assume_no[qtype]=1; return(0); } #endif if(!msg_strncmp(rt_ptr, M_GLOBAL, rt_len)) { yes_on_all_queries=1; return(1); } #if SFX_LEVEL>=ARJ if(!msg_strncmp(rt_ptr, M_COMMAND, rt_len)) { query_cmd(); if(query!=NULL) msg_cprintf(H_PROMPT, (FMSG *)strform, query); continue; } #endif } } else { if(def==1) return(1); if(def==2) return(0); } fetch_keystrokes(); nputc(BEL); msg_cprintf(0, M_REPLIES_HELP); } } #else int query_action() { #ifndef REARJ char buf[40]; #else char buf[80]; #endif char *buf_ptr; int sl, rc; char *fmsg_ptr; while(1) { read_line(buf, sizeof(buf)); buf_ptr=buf; while(*buf_ptr==' ') buf_ptr++; if((sl=strlen(buf_ptr))!=0) { strupper(buf_ptr); fmsg_ptr=malloc_fmsg(M_NO); rc=strncmp(buf_ptr, fmsg_ptr, sl); free_fmsg(fmsg_ptr); if(!rc) return(0); fmsg_ptr=malloc_fmsg(M_YES); rc=strncmp(buf_ptr, fmsg_ptr, sl); free_fmsg(fmsg_ptr); if(!rc) return(1); #ifndef REARJ fmsg_ptr=malloc_fmsg(M_QUIT); rc=strncmp(buf_ptr, fmsg_ptr, sl); free_fmsg(fmsg_ptr); if(!rc) exit(ARJSFX_ERL_ERROR); #endif } msg_cprintf(0, M_REPLIES_HELP); } } #endif #if SFX_LEVEL>=ARJSFXV /* Standard procedure that queries user. Accepts the following parameters: - def=0 if no default action, or number of reply to be selected w/ENTER. - qtype is the standard query number to allow pre-selections. - query is the query text. */ int query_action(int def, int qtype, FMSG *query) { #if SFX_LEVEL>=ARJ char *nquery; int result; FILE *tmp_stdout; if((tmp_stdout=new_stdout)==new_stderr) new_stdout=stderr; result=query_action_proc(def, qtype, nquery=malloc_fmsg(query)); free_fmsg(nquery); new_stdout=tmp_stdout; return(result); #else return(query_action_proc(def, qtype, query)); #endif } /* Prompts the user to press ENTER */ int pause() { char *tmp_query; FILE *tmp_stdout; int rc; if((tmp_stdout=new_stdout)==new_stderr) new_stdout=stderr; tmp_query=malloc_fmsg(M_PRESS_ENTER); rc=query_action_proc(1, QUERY_PRESS_ENTER, tmp_query); new_stdout=tmp_stdout; free_fmsg(tmp_query); return(rc); } /* Puts a LF character to the stdout */ void nputlf() { msg_cprintf(0, (FMSG *)lf); } #endif #if SFX_LEVEL>=ARJ /* Deletes files specified by the given wildcard. Returns 1 if no files were found to delete. */ int delete_files(char *name) { char tmp_name[CCHMAXPATHCOMP]; struct flist_root root; FILE_COUNT curfile; flist_init(&root, FCLIM_DELETION, FL_STANDARD); if(flist_add_files(&root, NULL, name, 1, 0, FETCH_FILES, NULL)) return(1); for(curfile=0; curfile=ARJSFXV void display_comment(char FAR *cmt) #else void display_comment(char *cmt) #endif { unsigned char c; #if SFX_LEVEL>=ARJSFXV int is_ansi=0; #endif #if TARGET==OS2 USHORT af; #endif #if SFX_LEVEL>=ARJ if(new_stderr==new_stdout) return; #endif #if TARGET==OS2 fflush(stdout); VioGetAnsi(&af, 0); VioSetAnsi(ANSI_ON, 0); #endif while((c=*(cmt++))!='\0') { #if SFX_LEVEL>=ARJSFXV if(c==ANSI_ESC) is_ansi=1; #endif #if SFX_LEVEL>=ARJSFXV&&!defined(DIRECT_TO_ANSI) if(is_ansi) { display_ansi(c); if(c==LF) display_ansi(CR); } else { #endif /* Substitute non-printable control characters with "?"'s */ #ifndef DIRECT_TO_ANSI if(c<' '&&c!=TAB&&c!=LF&&c!=CR) c=UNDISP_CHAR; #endif #if SFX_LEVEL>=ARJSFXV nputc((int)c); #else fputc((int)c, stdout); #endif #if SFX_LEVEL>=ARJ if(c==LF) { lines_scrolled++; if(lines_scrolled>=lines_per_page-1) { lines_scrolled=0; if(!yes_on_all_queries&&prompt_for_more&&is_tty(stdout)) { if(!pause()) return; } } } #endif #if SFX_LEVEL>=ARJSFXV&&!defined(DIRECT_TO_ANSI) } #endif } #if SFX_LEVEL>=ARJSFXV if(is_ansi) { #ifdef DIRECT_TO_ANSI printf("\x1B[0m\n"); #else display_ansi(LF); #endif } #endif #if TARGET==OS2 VioSetAnsi(af, 0); #endif } #if SFX_LEVEL>=ARJ /* Puts repeatable character to stdout */ static char *nputnc(char *dest, int c, int count) { while(count-->0) *(dest++)=c; return(dest); } #endif /* Displays progress indicator */ void display_indicator(long bytes) { int pct; char ind[64]; char *p; /* Indicator width */ static unsigned char ind_sizes[]={5, 0, 11, 5, 8, 11, 11}; #if SFX_LEVEL>=ARJ static int prev_pct=0; #endif if(!file_packing) return; p=ind; if(arjdisp_enabled) arjdisp_scrn((unsigned long)bytes); /* Different conditions for ARJ and ARJSFX! */ #if SFX_LEVEL>=ARJ else if(indicator_style!=IND_NONE) { check_wrap(ind_sizes[indicator_style]); if(uncompsize<0L) { if(bytes==0L) p+=sprintf(p, sfmt_double, del_double); p+=sprintf(p, sfmt_bytes, bytes, del_double); } else { if(indicator_style==IND_NORMAL||indicator_style==IND_TOTAL_PCT) { if(bytes==0L) { p+=sprintf(p, sfmt_single, del_single); p+=sprintf(p, sfmt_start_graph, del_single); } else { if(total_size!=0&&display_totals&&indicator_style==IND_TOTAL_PCT) pct=calc_percentage(total_written+bytes, total_size); else pct=calc_percentage(bytes, uncompsize); if(pct==prev_pct&&CHECK_SENTRY()) return; p+=sprintf(p, sfmt_numeric, pct/10, del_single); } } else if(indicator_style==IND_GRAPH||indicator_style==IND_TOTAL_GRAPH) { if(bytes==0L) { p+=sprintf(p, sfmt_double, del_double); p+=sprintf(p, sfmt_graph, del_double); *p='\0'; p=ind; msg_cprintf(H_HL, (FMSG *)strform, ind); } else { if(total_size!=0&&display_totals&&indicator_style==IND_TOTAL_GRAPH) pct=calc_percentage(total_written+bytes, total_size); else pct=calc_percentage(bytes, uncompsize); if(pct==prev_pct&&CHECK_SENTRY()) return; p=nputnc(p, COUNTER_CHAR, pct/100); p=nputnc(p, '\b', pct/100); *p='\0'; p=ind; msg_cprintf(H_OPER, (FMSG *)strform, ind); } } else if(indicator_style==IND_PCT_GRAPH||indicator_style==IND_TOTAL_PCT_GRAPH||indicator_style==IND_TOTAL_PCT_LGRAPH) { if(total_size!=0&&display_totals&&(indicator_style==IND_TOTAL_PCT_GRAPH||indicator_style==IND_TOTAL_PCT_LGRAPH)) pct=calc_percentage(total_written+bytes, total_size); else pct=calc_percentage(bytes, uncompsize); if(bytes==0L) { p+=sprintf(p, sfmt_double, del_double); p+=sprintf(p, sfmt_start_num, pct/10); *p='\0'; p=ind; if(pct==prev_pct&&CHECK_SENTRY()) return; msg_cprintf(H_OPER, (FMSG *)strform, ind); msg_cprintf(H_HL, sfmt_mid_graph, del_double); } else { p+=sprintf(p, sfmt_short_numeric, pct/10); if(total_size!=0&&indicator_style==IND_TOTAL_PCT_GRAPH) pct=calc_percentage(total_written+bytes, total_size); else pct=calc_percentage(bytes, uncompsize); if(pct==prev_pct&&CHECK_SENTRY()) return; p=nputnc(p, COUNTER_CHAR, pct/200); p=nputnc(p, '\b', pct/200+5); } } } } *p='\0'; msg_cprintf(H_OPER, (FMSG *)strform, ind); prev_pct=pct; SET_SENTRY(); #elif SFX_LEVEL==ARJSFXV else if(indicator_style==IND_NORMAL||indicator_style==IND_GRAPH) { if(uncompsize<0L) { if(bytes==0L) p+=sprintf(p, sfmt_double, del_double); p+=sprintf(p, sfmt_bytes, bytes, del_double); } if(indicator_style==IND_NORMAL) { if(bytes==0L) { p+=sprintf(p, sfmt_single, del_single); p+=sprintf(p, sfmt_start_graph, del_single); } else { pct=calc_percentage(bytes, uncompsize); p+=sprintf(p, sfmt_numeric, pct/10, del_single); } } } *p='\0'; msg_cprintf(0, (FMSG *)strform, ind); #else else if(indicator_style==IND_NORMAL) { pct=calc_percentage(bytes, uncompsize); printf(sfmt_sfx, pct/10); } #endif } #endif #if SFX_LEVEL>=ARJ /* Puts a character to the output stream. The cursor position given is only for checking purposes. Returns the new cursor position. */ static int arj_putc(unsigned char c, int p) { unsigned char t[TAB_POS+1]; unsigned char *q; int rc=p; q=t; if(c==LF) { #if COMPILER==MSC *q++=CR; #endif *q++=c; rc=1; } else if(c==TAB) { do { if(p=' ')?c:UNDISP_CHAR; rc++; } *q='\0'; msg_cprintf(0, (FMSG *)strform, t); return(rc); } /* Prints the given text to stdout, querying for "more?" when needed. Returns 1 if the output was cancelled by the user in response to the "--More--?" prompt. */ static int list_with_more(char *str, unsigned int len) { FMSG *prompt; char *sptr; unsigned int i; int cur_pos; int cur_line; unsigned char c; int sf; #if COMPILER==MSC if(help_issued) fputc(CR, stdout); #endif sptr=str; prompt=prompt_for_more?M_QUERY_MORE:M_QUERY_SCANNED_ENOUGH; nputlf(); cur_line=2; cur_pos=1; i=1; while(i<=len) { c=*sptr++; if(verbose_display==VERBOSE_NONE&&!help_issued) c&=0x7F; /* Strip high bit from nonlocal text */ i++; if(i>len) c=LF; cur_pos=arj_putc(c, cur_pos); if(c==LF) { cur_line++; if(cur_line>=lines_per_page-2) { cur_line=0; sf=yes_on_all_queries||skip_scanned_query; if(!sf) { sf=query_action(REPLY_NO, QUERY_SCANNED_ENOUGH, prompt); if(prompt_for_more) sf=!sf; } if(sf) return(1); } } } if(help_issued) return(0); sf=yes_on_all_queries||skip_scanned_query; if(!sf) { sf=query_action(REPLY_NO, QUERY_SCANNED_ENOUGH, prompt); if(prompt_for_more) sf=!sf; } return(sf); } /* Compares the contents of the block with the input file. */ static int compare_fblock(char *block, int len) { int bytes_read; char FAR *tmp_block; if(identical_filedata) { tmp_block=farmalloc_msg((unsigned long)len); far_memmove(tmp_block, (char FAR *)block, len); if((bytes_read=fread(block, 1, len, tstream))!=len) identical_filedata=0; else { if(bytes_read>0) { if(far_memcmp((char FAR *)block, tmp_block, bytes_read)) identical_filedata=0; } } far_memmove((char FAR *)block, tmp_block, len); farfree(tmp_block); } return(0); } /* Displays the text found in a block. Returns the number of bytes displayed. */ static int display_found_text(unsigned char FAR *block, int offset, int block_len) { int remain; int d_offset; int column; unsigned int c; int i; d_offset=offset; remain=min(fdisp_lines*TXTD_LENGTH, block_len); if(remain>TXTD_LENGTH) { msg_cprintf(0, M_MARK_LLINE); d_offset=(remain/2>offset)?0:offset-remain/2; } block+=d_offset; column=0; i=0; while(i=TXTD_LENGTH) { msg_cprintf(0, lf); column=0; } c=*(block++); if(verbose_display) { if(cCON_UBOUND) c=UNDISP_CHAR; fputc(c, new_stdout); i++; d_offset++; column++; } msg_cprintf(0, lf); return(i-(offset-d_offset)); } /* Performs a search for the given pattern in memory block */ static int t_search_stub(char *pattern, char *cmpblock, char FAR *block, int skip, int block_len) { int len; int matches; int search_offset; int limit; char c; int t_offset; char *p; len=strlen(pattern); matches=0; search_offset=0; c=*pattern; limit=(len>=block_len)?0:block_len-len; t_offset=skip; p=&cmpblock[skip]; while(t_offsetsearch_offset) search_offset=t_offset+display_found_text(block, t_offset, block_len)-len; if(extm_mode!=EXTM_NONE) break; } } t_offset++; p++; } return(matches); } /* Performs a search in the block of continuous data. */ static int search_in_block(char *block, int block_len) { int tmp_len, tail_len; char *sstr_ptr; char FAR *block_ptr; char FAR *reserve_ptr; int i; block_ptr=(char FAR *)block; reserve_ptr=(char FAR *)search_reserve; if(ignore_pcase) { block_ptr=farmalloc_msg((unsigned long)block_len); far_memmove(block_ptr, (char FAR *)block, block_len); toupper_loc(block, block_len); if(reserve_size!=0) { reserve_ptr=farmalloc_msg(160L); far_memmove(reserve_ptr, (char FAR *)search_reserve, reserve_size); toupper_loc(search_reserve, reserve_size); } } for(i=0; iINPUT_LENGTH)?INPUT_LENGTH:block_len; memcpy(search_reserve+reserve_size, block, tmp_len); if(ignore_pcase) far_memmove(&reserve_ptr[reserve_size], block_ptr, tmp_len); tail_len=reserve_size-strlen(sstr_ptr)+1; search_occurences[i]+=(long)t_search_stub(sstr_ptr, search_reserve, reserve_ptr, tail_len, reserve_size+tmp_len); if(pattern_found&&extm_mode!=EXTM_NONE) break; } search_occurences[i]+=(long)t_search_stub(sstr_ptr, block, block_ptr, 0, block_len); if(pattern_found&&extm_mode!=EXTM_NONE) break; } if(ignore_pcase) { far_memmove((char FAR *)block, block_ptr, block_len); farfree(block_ptr); if(reserve_size!=0) farfree(reserve_ptr); } reserve_size=(block_len>INPUT_LENGTH)?INPUT_LENGTH:block_len; memcpy(search_reserve, block+(block_len-reserve_size), reserve_size); return(0); } /* Displays a block of text using ANSI comment display routine. */ static int display_block(char *str, int len) { if(new_stdout!=new_stderr) { while((len--)>0) { #ifndef DIRECT_TO_ANSI display_ansi(*(str++)); #else putchar(*(str++)); #endif } } return(0); } /* Performs various actions involving the given block. */ static int block_op(int action, char *block, int len) { if(action==BOP_LIST) return(list_with_more(block, len)); else if(action==BOP_DISPLAY) return(display_block(block, len)); else if(action==BOP_SEARCH) return(search_in_block(block, len)); else if(action==BOP_COMPARE) return(compare_fblock(block, len)); else return(0); } #endif #if SFX_LEVEL>=ARJ||defined(REARJ) /* Renames file and ensures that it has been successfully renamed */ #ifdef REARJ int rename_with_check(char *oldname, char *newname) { if(!no_file_activity) { if(file_rename(oldname, newname)) return(-1); if(file_exists(oldname)||!file_exists(newname)) return(-1); } return(0); } #else void rename_with_check(char *oldname, char *newname) { if(!file_test_access(oldname)) { if(!file_rename(oldname, newname)) { if(!file_exists(oldname)&&file_exists(newname)) return; } } error(M_CANTRENAME, oldname, newname); } #endif #endif /* SFX_LEVEL>=ARJ||defined(REARJ) */ #if SFX_LEVEL>=ARJ /* Returns number of occurences in the given string */ static int count_chars(char *str, char c) { int occurs=0; char *tmp_ptr; for(tmp_ptr=str; *tmp_ptr!='\0'; tmp_ptr++) if(*tmp_ptr==c) occurs++; return(occurs); } /* Deletes the processed files */ int delete_processed_files(struct flist_root *root) { char name[FILENAME_MAX]; unsigned int count; int depth, max_depth; FILE_COUNT i; FILE *t; /* If break is requested, cancel the deletion */ if(ctrlc_processing) return(0); max_depth=0; count=0; for(i=0; ifiles; i++) { if(cfa_get(i)==FLFLAG_PROCESSED) count++; } if(delete_processed==DP_STD&&!yes_on_all_queries&&!query_delete) { msg_sprintf(misc_buf, M_QUERY_DELETE_N_FILES, count); if(!query_action(REPLY_YES, QUERY_DELETE_N_FILES, (char FAR *)misc_buf)) return(0); } msg_cprintf(0, M_DELETE_COUNT, count); for(i=0; ifiles; i++) { if(cfa_get(i)==FLFLAG_PROCESSED) { flist_retrieve(name, NULL, root, i); depth=count_chars(name, PATHSEP_DEFAULT); if(depth>max_depth) max_depth=depth; if(!is_directory(name)) { /* ASR fix for 2.78-TCO */ if(delete_processed!=DP_ADD_TRUNC) { if(file_unlink(name)) { msg_cprintf(H_ERR, M_CANT_DELETE, name); nputlf(); } } else { if((t=file_open(name, m_rbp))==NULL) { msg_cprintf(H_ERR, M_CANT_TRUNCATE, name); nputlf(); } file_chsize(t, 0); fclose(t); } cfa_store(i, FLFLAG_DELETED); } } } for(depth=max_depth; depth>=0; depth--) { for(i=0; ifiles; i++) { if(cfa_get(i)==FLFLAG_PROCESSED) { flist_retrieve(name, NULL, root, i); if(count_chars(name, PATHSEP_DEFAULT)>=depth&&is_directory(name)) { if(file_rmdir(name)) { msg_cprintf(H_ERR, M_CANT_DELETE, name); nputlf(); } cfa_store(i, FLFLAG_DELETED); } } } } return(0); } /* Writes a byte to the file */ void fput_byte(int b, FILE *stream) { if(!no_file_activity) { if(fputc(b, stream)==EOF) error(M_DISK_FULL); } } /* Writes two bytes to the file */ void fput_word(unsigned int w, FILE *stream) { fput_byte(w&0xFF, stream); fput_byte(w>>8, stream); } /* Writes four bytes to the file */ void fput_dword(unsigned long l, FILE *stream) { #ifdef WORDS_BIGENDIAN fput_word((unsigned int)(l&0xFFFF), stream); fput_word((unsigned int)(l>>16), stream); #else if(!no_file_activity) { if(!fwrite(&l,4,1,stream)) error(M_DISK_FULL); } #endif } /* Writes the compressed data */ void flush_compdata() { if(out_bytes>0) { compsize+=(unsigned long)out_bytes; if(compsize>origsize&&(!garble_enabled||!file_packing)) unpackable=1; else { if(!no_file_activity) { if(garble_enabled) garble_encode_stub(out_buffer, out_bytes); if(file_packing) { file_write(out_buffer, 1, out_bytes, aostream); } else { far_memmove(packblock_ptr, (char FAR *)out_buffer, out_bytes); packblock_ptr+=out_bytes; } out_avail=PUTBIT_SIZE; } } out_bytes=0; } } /* Initializes compressed data output */ void init_putbits() { unsigned long fp; bitcount=0; byte_buf=0; bitbuf=0; out_bytes=0; if(!file_packing||no_file_activity) fp=0L; else { fp=ftell(aostream); if(fp>MAX_FILE_SIZE) error(M_FILE_IS_TOO_LARGE); } out_buffer=malloc_msg(PUTBIT_SIZE); out_avail=PUTBIT_SIZE-(fp%PUTBIT_SIZE); if(out_avail>PUTBIT_SIZE) error(M_PUTBIT_SIZE_ERROR); mem_stats(); } /* Ends the bitwise output */ void shutdown_putbits() { if(!unpackable) { putbits(CHAR_BIT-1, 0); if(out_bytes!=0) flush_compdata(); } free(out_buffer); out_bytes=0; } /* Clears the archive attribute for a set of files */ int group_clear_arch(struct flist_root *root) { char name[FILENAME_MAX]; FILE_COUNT i; if(ctrlc_processing) return(0); for(i=0; ifiles; i++) { if(cfa_get(i)==FLFLAG_PROCESSED) { flist_retrieve(name, NULL, root, i); if(dos_clear_arch_attr(name)) msg_cprintf(H_ERR, M_CANT_RESET, name); cfa_store(i, FLFLAG_DELETED); } } return(0); } #endif