git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/branches/WX_2_2_BRANCH@7117 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
		
			
				
	
	
		
			585 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			585 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /* ------------------------------------------------------------------------ */
 | |
| /*                                                                          */
 | |
| /*      Main file of public UNACE.                                          */
 | |
| /*                                                                          */
 | |
| /* ------------------------------------------------------------------------ */
 | |
| 
 | |
| 
 | |
| //--------------- include general files ------------------------------------//
 | |
| #include <ctype.h>      // tolower()
 | |
| #include <fcntl.h>      // open()
 | |
| #include <stdio.h>      // printf() sprintf() remove()
 | |
| #include <stdlib.h>     // malloc()
 | |
| #include <string.h>     // str*()
 | |
| #include <sys/types.h>
 | |
| #include <sys/stat.h>   // S_I*  AMIGA: fstat()
 | |
| 
 | |
| #define DIRSEP	'\\'
 | |
| 
 | |
| #if (!defined(__EMX__) && !defined(__OS2__) && !defined(WINNT) && !defined(WIN32)) ||  defined(__CYGWIN__)
 | |
| #include <sys/errno.h>
 | |
| #endif
 | |
| 
 | |
| 
 | |
| //--------------- include unace specific header files ----------------------//
 | |
| #include "os.h"
 | |
| 
 | |
| #include "globals.h"
 | |
| #include "portable.h"
 | |
| #include "uac_comm.h"
 | |
| #include "uac_crc.h"
 | |
| #include "uac_crt.h"
 | |
| #include "uac_dcpr.h"
 | |
| #include "uac_sys.h"
 | |
| 
 | |
| #ifdef CRYPT
 | |
|  #include "unace_ps.h"
 | |
| #endif /* CRYPT */
 | |
| int files=0;
 | |
| 
 | |
| //--------------- BEGIN OF UNACE ROUTINES ----------------------------------//
 | |
| 
 | |
| int pipeit(char *format, ...) {
 | |
| 	/* Do nothing ... perhaps pipe this somewhere in the future */
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| void init_unace(void)           // initializes unace
 | |
| {
 | |
| 	buf_rd =malloc(size_rdb * sizeof(ULONG));  // Allocate buffers: increase
 | |
| 	buf    =malloc(size_buf);                  // sizes when possible to speed
 | |
| 	buf_wr =malloc(size_wrb);                  // up the program
 | |
| 	readbuf=malloc(size_headrdb);
 | |
| 
 | |
| 	if (buf_rd ==NULL ||
 | |
| 		buf    ==NULL ||
 | |
| 		buf_wr ==NULL ||
 | |
| 		readbuf==NULL )
 | |
| 		f_err = ERR_MEM;
 | |
| 
 | |
| 	make_crctable();             // initialize CRC table
 | |
| 	dcpr_init();                 // initialize decompression
 | |
| 
 | |
| 	set_handler();               // ctrl+break etc.
 | |
| }
 | |
| 
 | |
| void done_unace(void)
 | |
| {
 | |
| 	if (buf_rd   ) free(buf_rd   );
 | |
| 	if (buf      ) free(buf      );
 | |
| 	if (buf_wr   ) free(buf_wr   );
 | |
| 	if (readbuf  ) free(readbuf  );
 | |
| 	if (dcpr_text) free(dcpr_text);
 | |
| }
 | |
| 
 | |
| INT  read_header(INT print_err)         // reads any header from archive
 | |
| {
 | |
| 	USHORT rd,
 | |
| 	head_size,
 | |
| 	crc_ok;
 | |
| 	LONG crc;
 | |
| 	UCHAR *tp=readbuf;
 | |
| 
 | |
| 	lseek(archan, skipsize, SEEK_CUR);   // skip ADDSIZE block
 | |
| 
 | |
| 	if (read(archan, &head, 4)<4)
 | |
| 		return (0);                       // read CRC and header size
 | |
| 
 | |
| #ifdef HI_LO_BYTE_ORDER
 | |
| 	WORDswap(&head.HEAD_CRC);
 | |
| 	WORDswap(&head.HEAD_SIZE);
 | |
| #endif
 | |
| 	// read size_headrdb bytes into
 | |
| 	head_size = head.HEAD_SIZE;          // header structure
 | |
| 	rd = (head_size > size_headrdb) ? size_headrdb : head_size;
 | |
| 	if (read(archan, readbuf, rd) < rd)
 | |
| 		return (0);
 | |
| 	head_size -= rd;
 | |
| 	crc = getcrc(CRC_MASK, readbuf, rd);
 | |
| 
 | |
| 	while (head_size)                    // skip rest of header
 | |
| 	{
 | |
| 		rd = (head_size > size_buf) ? size_buf : head_size;
 | |
| 		if (read(archan, buf, rd) < rd)
 | |
| 			return (0);
 | |
| 		head_size -= rd;
 | |
| 		crc = getcrc(crc, (UCHAR *)buf, rd);
 | |
| 	}
 | |
| 
 | |
| 	head.HEAD_TYPE =*tp++;               // generic buffer to head conversion
 | |
| 	head.HEAD_FLAGS=BUFP2WORD(tp);
 | |
| 
 | |
| 	if (head.HEAD_FLAGS & ACE_ADDSIZE)
 | |
| 		skipsize = head.ADDSIZE = BUF2LONG(tp);   // get ADDSIZE
 | |
| 	else
 | |
| 		skipsize = 0;
 | |
| 
 | |
| 	// check header CRC
 | |
| 	if (!(crc_ok = head.HEAD_CRC == (crc & 0xffff)) && print_err)
 | |
| 		pipeit("\nError: archive is broken\n");
 | |
| 	else
 | |
| 		switch (head.HEAD_TYPE)              // specific buffer to head conversion
 | |
| 		{
 | |
| 		case MAIN_BLK:
 | |
| 			memcpy(mhead.ACESIGN, tp, acesign_len); tp+=acesign_len;
 | |
| 			mhead.VER_MOD=*tp++;
 | |
| 			mhead.VER_CR =*tp++;
 | |
| 			mhead.HOST_CR=*tp++;
 | |
| 			mhead.VOL_NUM=*tp++;
 | |
| 			mhead.TIME_CR=BUFP2LONG(tp);
 | |
| 			mhead.RES1   =BUFP2WORD(tp);
 | |
| 			mhead.RES2   =BUFP2WORD(tp);
 | |
| 			mhead.RES    =BUFP2LONG(tp);
 | |
| 			mhead.AV_SIZE=*tp++;
 | |
| 			memcpy(mhead.AV, tp, rd-(USHORT)(tp-readbuf));
 | |
| 			break;
 | |
| 		case FILE_BLK:
 | |
| 			fhead.PSIZE     =BUFP2LONG(tp);
 | |
| 			fhead.SIZE      =BUFP2LONG(tp);
 | |
| 			fhead.FTIME     =BUFP2LONG(tp);
 | |
| 			fhead.ATTR      =BUFP2LONG(tp);
 | |
| 			fhead.CRC32     =BUFP2LONG(tp);
 | |
| 			fhead.TECH.TYPE =*tp++;
 | |
| 			fhead.TECH.QUAL =*tp++;
 | |
| 			fhead.TECH.PARM =BUFP2WORD(tp);
 | |
| 			fhead.RESERVED  =BUFP2WORD(tp);
 | |
| 			fhead.FNAME_SIZE=BUFP2WORD(tp);
 | |
| 			memcpy(fhead.FNAME, tp, rd-(USHORT)(tp-readbuf));
 | |
| 			break;
 | |
| 			//    default: (REC_BLK and future things):
 | |
| 			//              do nothing 'cause isn't needed for extraction
 | |
| 		}
 | |
| 
 | |
| 	return (crc_ok);
 | |
| }
 | |
| // maximum SFX module size
 | |
| #define max_sfx_size 65536      // (needed by read_arc_head)
 | |
| 
 | |
| INT read_arc_head(void)         // searches for the archive header and reads it
 | |
| {
 | |
| 	INT  i,
 | |
| 	flags,
 | |
| 	buf_pos = 0;
 | |
| 	LONG arc_head_pos,
 | |
| 		old_fpos,
 | |
| 	fpos = 0;
 | |
| 	struct stat st;
 | |
| 
 | |
| 	fstat(archan, &st);
 | |
| 
 | |
| 	memset(buf, 0, size_buf);
 | |
| 
 | |
| #if !defined(__EMX__) && !defined(__OS2__)
 | |
| 	while (ftell(farchan)<st.st_size && fpos < max_sfx_size)
 | |
| #else
 | |
| 		while (tell(archan)<st.st_size && fpos < max_sfx_size)
 | |
| #endif
 | |
| 		{
 | |
| 			old_fpos = fpos;
 | |
| 			fpos += read(archan, &buf[buf_pos], size_buf - buf_pos);
 | |
| 
 | |
| 			for (i = 0; i < size_buf; i++)    // look for the acesign
 | |
| 			{
 | |
| 				if (!memcmp(acesign, &buf[i], acesign_len))
 | |
| 				{
 | |
| 					// seek to the probable begin
 | |
| 					// of the archive
 | |
| 					arc_head_pos = old_fpos + i - buf_pos -  bytes_before_acesign;
 | |
| 					lseek(archan, arc_head_pos, SEEK_SET);
 | |
| 					if (read_header(0))         // try to read archive header
 | |
| 					{
 | |
| 						flags = mhead.HEAD_FLAGS;
 | |
| 						adat.sol     = (flags & ACE_SOLID) > 0;
 | |
| 						adat.vol     = (flags & ACE_MULT_VOL) > 0;
 | |
| 						adat.vol_num = mhead.VOL_NUM;
 | |
| 						adat.time_cr = mhead.TIME_CR;
 | |
| 						return (1);
 | |
| 					}
 | |
| 				}
 | |
| 			}
 | |
| 			// was no archive header,
 | |
| 			// continue search
 | |
| 			lseek(archan, fpos, SEEK_SET);
 | |
| 			memcpy(buf, &buf[size_buf - 512], 512);
 | |
| 			buf_pos = 512;                    // keep 512 old bytes
 | |
| 		}
 | |
| 	return (0);
 | |
| }
 | |
| 
 | |
| INT  open_archive(INT print_err)        // opens archive (or volume)
 | |
| {
 | |
| 	CHAR av_str[80];
 | |
| 
 | |
| 
 | |
| #if defined(__OS2_) || defined(__EMX__) || defined(WIN32)
 | |
| 	archan = open(aname, O_RDONLY | O_BINARY);   // open file
 | |
| #else
 | |
| 	archan = open(aname, O_RDONLY);   // open file
 | |
| #endif
 | |
| #if !defined(__EMX__) && !defined(__OS2__)
 | |
| 	farchan = fdopen(archan, "rb");
 | |
| #endif
 | |
| 	if (archan == -1)
 | |
| 	{
 | |
| 		pipeit("\nError opening file %s", aname);
 | |
| 		return (0);
 | |
| 	}
 | |
| 	if (!read_arc_head())                        // read archive header
 | |
| 	{
 | |
| 		if (print_err)
 | |
| 			pipeit("\nInvalid archive file: %s\n", aname);
 | |
| #if !defined(__EMX__) && !defined(__OS2__)
 | |
| 		fclose(farchan);
 | |
| #endif
 | |
| 		close(archan);
 | |
| 		return (0);
 | |
| 	}
 | |
| 
 | |
| 	pipeit("\nProcessing archive: %s\n\n", aname);
 | |
| 	if (head.HEAD_FLAGS & ACE_AV)
 | |
| 	{
 | |
| 	   pipeit("Authenticity Verification:");   // print the AV
 | |
| 	   sprintf(av_str, "\ncreated on %d.%d.%d by ",
 | |
| 			   ts_day(adat.time_cr), ts_month(adat.time_cr), ts_year(adat.time_cr));
 | |
| 	   pipeit(av_str);
 | |
| 	   strncpy(av_str, (char *)mhead.AV, mhead.AV_SIZE);
 | |
| 	   av_str[mhead.AV_SIZE] = 0;
 | |
| 	   pipeit("%s\n\n", av_str);
 | |
| 	}
 | |
| 	comment_out("Main comment:");        // print main comment
 | |
| 	return (1);
 | |
| }
 | |
| 
 | |
| void get_next_volname(void)             // get file name of next volume
 | |
| {
 | |
| 	CHAR *cp;
 | |
| 	INT  num;
 | |
| 
 | |
| 	if ((cp = (CHAR *) strrchr(aname, '.')) == NULL || !*(cp + 1))
 | |
| 		num = -1;
 | |
| 	else
 | |
| 	{
 | |
| 		cp++;
 | |
| 		num = (*(cp + 1) - '0') * 10 + *(cp + 2) - '0';
 | |
| 		if (!in(num, 0, 99))
 | |
| 			num = -1;
 | |
| 		if (in(*cp, '0', '9'))
 | |
| 			num += (*cp - '0') * 100;
 | |
| 	}
 | |
| 	num++;
 | |
| 
 | |
| 	if (num < 100)
 | |
| 		*cp = 'C';
 | |
| 	else
 | |
| 		*cp = num / 100 + '0';
 | |
| 	*(cp + 1) = (num / 10) % 10 + '0';
 | |
| 	*(cp + 2) = num % 10 + '0';
 | |
| }
 | |
| 
 | |
| INT  proc_vol(void)                     // opens volume
 | |
| {
 | |
| 	INT  i;
 | |
| 	CHAR s[80];
 | |
| 
 | |
| 	if (!fileexists(aname) || !f_allvol_pr)
 | |
| 	{
 | |
| 		do
 | |
| 		{
 | |
| 			sprintf(s, "Ready to process %s?", aname);
 | |
| #if !defined(__MINGW32__)
 | |
| 			beep();
 | |
| #else
 | |
| 			beep(500,500);
 | |
| #endif
 | |
| 			i = wrask(s);                  // ask whether ready or not
 | |
| 			f_allvol_pr = (i == 1);        // "Always" --> process all volumes
 | |
| 			if (i >= 2)
 | |
| 			{
 | |
| 				f_err = ERR_FOUND;
 | |
| 				return (0);
 | |
| 			}
 | |
| 		}
 | |
| 		while (!fileexists(aname));
 | |
| 	}
 | |
| 
 | |
| 	if (!open_archive(1))                // open volume
 | |
| 	{
 | |
| 		pipeit("\nError while opening archive. File not found or archive broken.\n");
 | |
| 		f_err = ERR_OPEN;
 | |
| 		return (0);
 | |
| 	}
 | |
| 
 | |
| 	return (1);
 | |
| }
 | |
| 
 | |
| INT  proc_next_vol(void)        // opens next volume to process
 | |
| {
 | |
| #if !defined(__EMX__) && !defined(__OS2__)
 | |
| 	fclose(farchan);
 | |
| #endif
 | |
| 	close(archan);               // close handle
 | |
| 	get_next_volname();          // get file name of next volume
 | |
| 
 | |
| 	if (!proc_vol())             // try to open volume, read archive header
 | |
| 		return 0;
 | |
| 	if (!read_header(1))         // read 2nd header
 | |
| 	{
 | |
| 		f_err=ERR_READ;
 | |
| 		return 0;
 | |
| 	}
 | |
| 	return 1;
 | |
| }
 | |
| 
 | |
| INT  read_adds_blk(CHAR * buffer, INT len)      // reads part of ADD_SIZE block
 | |
| {
 | |
| 	INT  rd = 0,
 | |
| 	l = len;
 | |
| 	LONG i;
 | |
| 
 | |
| #ifdef CRYPT
 | |
| 	char *cbuffer=buffer;
 | |
| 
 | |
| 	if (head.HEAD_TYPE == FILE_BLK && (head.HEAD_FLAGS & ACE_PASSW))
 | |
| 		len = crypt_len(len);
 | |
| #endif /* CRYPT */
 | |
| 	while (!f_err && len && skipsize)
 | |
| 	{
 | |
| 		i = (skipsize > len) ? len : skipsize;
 | |
| 		skipsize -= i;
 | |
| 
 | |
| 		/* How do I check error condition when comping -mno-cygwin? */
 | |
| #if !defined(__MINGW32__)
 | |
| 		errno = 0;
 | |
| #endif
 | |
| 		rd += read(archan, buffer, i);
 | |
| #if !defined(__MINGW32__)
 | |
| 		if (errno)
 | |
| 		{
 | |
| 			pipeit("\nRead error\n");
 | |
| 			f_err = ERR_READ;
 | |
| 		}
 | |
| #endif
 | |
| 
 | |
| 		buffer += i;
 | |
| 		len -= i;
 | |
| 
 | |
| 		if (!skipsize)            // if block is continued on next volume
 | |
| 			if (head.HEAD_FLAGS & ACE_SP_AFTER && !proc_next_vol())
 | |
| 				break;
 | |
| 	}
 | |
| #ifdef CRYPT
 | |
| 	if (head.HEAD_TYPE == FILE_BLK && (head.HEAD_FLAGS & ACE_PASSW))
 | |
| 		decrypt(cbuffer, rd);
 | |
| #endif /* CRYPT */
 | |
| 
 | |
| 	return (rd > l ? l : rd);
 | |
| }
 | |
| 
 | |
| void crc_print(void)            // checks CRC, prints message
 | |
| {
 | |
| 	INT  crc_not_ok = rd_crc != fhead.CRC32;  /* check CRC of file */
 | |
| 
 | |
| 	if (!f_err)                  // print message
 | |
| 	{
 | |
| 		pipeit(crc_not_ok ? "          CRC-check error" : "          CRC OK");
 | |
| 		flush;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| void analyze_file(void)         // analyzes one file (for solid archives)
 | |
| {
 | |
| 	pipeit("\n Analyzing");
 | |
| 	flush;
 | |
| 	while (!cancel() && (dcpr_adds_blk(buf_wr, size_wrb))) // decompress only
 | |
| 		;
 | |
| 	crc_print();
 | |
| }
 | |
| 
 | |
| void extract_file(void)         // extracts one file
 | |
| {
 | |
| 	INT  rd;
 | |
| 
 | |
| 	pipeit("\n Extracting");
 | |
| 	flush;                       // decompress block
 | |
| 	while (!cancel() && (rd = dcpr_adds_blk(buf_wr, size_wrb)))
 | |
| 	{
 | |
| 		if (write(wrhan, buf_wr, rd) != rd)       // write block
 | |
| 		{
 | |
| 			pipeit("\nWrite error\n");
 | |
| 			f_err = ERR_WRITE;
 | |
| 		}
 | |
| 	}
 | |
| 	crc_print();
 | |
| }
 | |
| 
 | |
| /* extracts or tests all files of the archive
 | |
|  */
 | |
| void extract_files(int nopath, int test)
 | |
| {
 | |
| 	CHAR file[PATH_MAX];
 | |
| 
 | |
| 	while (!cancel() && read_header(1))
 | |
| 	{
 | |
| 		if (head.HEAD_TYPE == FILE_BLK)
 | |
| 		{
 | |
| 			comment_out("File comment:");   // show file comment
 | |
| 			ace_fname(file, &head, nopath); // get file name
 | |
| 			pipeit("\n%s", file);
 | |
| 			flush;
 | |
| 			dcpr_init_file();               // initialize decompression of file
 | |
| 			if (!f_err)
 | |
| 			{
 | |
| 				if (test ||
 | |
| 					(wrhan = create_dest_file(file, (INT) fhead.ATTR))<0)
 | |
| 				{
 | |
| 					if (test || adat.sol)
 | |
| 						analyze_file();        // analyze file
 | |
| 				}
 | |
| 				else
 | |
| 				{
 | |
| 					extract_file();           // extract it
 | |
| #ifdef DOS                               // set file time
 | |
| 					_dos_setftime(wrhan, (USHORT) (fhead.FTIME >> 16), (USHORT) fhead.FTIME);
 | |
| #endif
 | |
| 					close(wrhan);
 | |
| #ifdef DOS                               // set file attributes
 | |
| 					_dos_setfileattr(file, (UINT) fhead.ATTR);
 | |
| #endif
 | |
| #ifdef AMIGA
 | |
| 					{                         // set file date and time
 | |
| 						struct DateTime dt;
 | |
| 						char Date[9], Time[9];
 | |
| 						ULONG tstamp=fhead.FTIME;
 | |
| 
 | |
| 						sprintf(Date, "%02d-%02d-%02d", ts_year(tstamp)-1900, ts_month(tstamp), ts_day(tstamp));
 | |
| 						sprintf(Time, "%02d:%02d:%02d", ts_hour(tstamp), ts_min(tstamp), ts_sec(tstamp));
 | |
| 
 | |
| 						dt.dat_Format = FORMAT_INT;
 | |
| 						dt.dat_Flags  = 0;
 | |
| 						dt.dat_StrDate= Date;
 | |
| 						dt.dat_StrTime= Time;
 | |
| 
 | |
| 						if (StrToDate(&dt))
 | |
| 							SetFileDate(file, &dt.dat_Stamp);
 | |
| 					}
 | |
| #endif
 | |
| 					if (f_err)
 | |
| 						remove(file);
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| unsigned percentage(ULONG p, ULONG d)
 | |
| {
 | |
| 	return (unsigned)( d ? (d/2+p*100)/d : 100 );
 | |
| }
 | |
| 
 | |
| void list_files(int verbose)
 | |
| {
 | |
| 	ULONG    size =0,
 | |
| 	psize=0,
 | |
| 	tpsize;
 | |
| 	CHAR     file[PATH_MAX];
 | |
| 
 | |
| 	pipeit("Date    |Time |Packed     |Size     |Ratio|File\n");
 | |
| 
 | |
| 	while (!cancel() && read_header(1))
 | |
| 	{
 | |
| 		if (head.HEAD_TYPE == FILE_BLK)
 | |
| 		{
 | |
| 			ULONG ti=fhead.FTIME;
 | |
| 			ace_fname(file, &head, verbose ? 0 : 1); // get file name
 | |
| 
 | |
| 			size  += fhead.SIZE;
 | |
| 			psize +=
 | |
| 				tpsize = fhead.PSIZE;
 | |
| 			files++;
 | |
| 
 | |
| 			while (head.HEAD_FLAGS & ACE_SP_AFTER)
 | |
| 			{
 | |
| 				skipsize=0;
 | |
| 				if (!proc_next_vol())
 | |
| 					break;
 | |
| 				psize += fhead.PSIZE;
 | |
| 				tpsize+= fhead.PSIZE;
 | |
| 			}
 | |
| 			if (!f_err)
 | |
| 				pipeit("%02u.%02u.%02u|%02u:%02u|%c%c%9lu|%9lu|%4u%%|%c%s\n",
 | |
| 					   ts_day (ti), ts_month(ti), ts_year(ti)%100,
 | |
| 					   ts_hour(ti), ts_min  (ti),
 | |
| 					   fhead.HEAD_FLAGS & ACE_SP_BEF   ? '<' : ' ',
 | |
| 					   fhead.HEAD_FLAGS & ACE_SP_AFTER ? '>' : ' ',
 | |
| 					   tpsize, fhead.SIZE, percentage(tpsize, fhead.SIZE),
 | |
| 					   fhead.HEAD_FLAGS & ACE_PASSW    ? '*'    : ' ',
 | |
| 					   file
 | |
| 					  );
 | |
| 		}
 | |
| 	}
 | |
| 	if (!f_err)
 | |
| 	{
 | |
| 		pipeit("\n                 %9lu|%9lu|%4u%%| %u file%s",
 | |
| 			   psize,
 | |
| 			   size,
 | |
| 			   percentage(psize, size),
 | |
| 			   files,
 | |
| 			   (char*)(files == 1 ? "" : "s")
 | |
| 			  );
 | |
| 	}
 | |
| }
 | |
| 
 | |
| void showhelp(void)
 | |
| {
 | |
| 	pipeit("\n"
 | |
| 		   "Usage: UNACE <command> <archive[.ace]>\n"
 | |
| 		   "\n"
 | |
| 		   "Where <command> is one of:\n"
 | |
| 		   "\n"
 | |
| 		   "  e   Extract files\n"
 | |
| 		   "  l   List archive\n"
 | |
| 		   "  t   Test archive integrity\n"
 | |
| 		   "  v   List archive (verbose)\n"
 | |
| 		   "  x   Extract files with full path"
 | |
| 		  );
 | |
| }
 | |
| 
 | |
| int include_unpack(char *bleah)              // processes the archive
 | |
| {
 | |
| 	CHAR *s;
 | |
| 
 | |
| 	strcpy(aname, bleah);
 | |
| 
 | |
| 	init_unace();                              // initialize unace
 | |
| 
 | |
| 	if (!(s = (CHAR *) strrchr(aname, DIRSEP)))
 | |
| 		s = aname;
 | |
| 	if (!strrchr(s, '.'))
 | |
| 		strcat(aname, ".ACE");
 | |
| 
 | |
| 	if (open_archive(1))                       // open archive to process
 | |
| 	{
 | |
| 		if (adat.vol_num)
 | |
| 			pipeit("\nFirst volume of archive required!\n");
 | |
| 		else
 | |
| 			list_files   (0   );
 | |
| 
 | |
| #if !defined(__EMX__) && !defined(__OS2__)
 | |
| 		fclose(farchan);
 | |
| #endif
 | |
| 		close(archan);
 | |
| 		if (f_err)
 | |
| 		{
 | |
| 			pipeit("\nError occurred\n");
 | |
| 			if (f_criterr)
 | |
| 				pipeit("Critical error on drive %c\n", f_criterr);
 | |
| 		}
 | |
| 	}
 | |
| 	else
 | |
| 		f_err = ERR_CLINE;
 | |
| 
 | |
| 	done_unace();
 | |
| 	return (f_err);
 | |
| }
 | |
| 
 |