English Amiga Board


Go Back   English Amiga Board > Coders > Coders. Language > Coders. C/C++

 
 
Thread Tools
Old 30 May 2015, 06:23   #1
tygre
Returning fan!

tygre's Avatar
 
Join Date: Jan 2011
Location: Montréal, QC, Canada
Posts: 769
UnArchiving LHA Files Programmatically: Confused about XPK, XAD, XFD

Hi all!

I am trying to simply extract one (or all) files from a LHA archive programmatically and I am confused: should I use XPK, XAD, or XFD?

Reading the docs and Web sites, it sems that XAD is the way to go but then I look at the code examples and see that, for example, xadUnFile.c is a thousand lines of code! I was naively thinking that calling the xadmaster.library in few lines of code would be sufficient

Am I missing something or is there really no free lunch?
Thanks!
tygre is offline  
Old 30 May 2015, 14:01   #2
BigFan
Registered User

BigFan's Avatar
 
Join Date: Feb 2014
Location: Germany
Posts: 261
xadunfile does more than just unpacking one file. it parses lots of arguments and options, has pattern matching, error handling, and code is prepared for use multiple files as input.

what should xadmaster do if your uncompressed file already exists? it is not part of the unpacking libs to handle these scenarios. that's the code you have to provide.

no, there is no free lunch

code block will be much smaller without that many options, see start() section
BigFan is offline  
Old 04 June 2015, 17:51   #3
tygre
Returning fan!

tygre's Avatar
 
Join Date: Jan 2011
Location: Montréal, QC, Canada
Posts: 769
Hi BigFan!

Thanks a lot! You are right: the source code of the xadUnFile and its start() function is very helpful... I am stating from there and already got something compiling and working so-so...

Cheers!

Last edited by tygre; 04 June 2015 at 19:15. Reason: Wrong tool name!
tygre is offline  
Old 08 June 2015, 04:51   #4
tygre
Returning fan!

tygre's Avatar
 
Join Date: Jan 2011
Location: Montréal, QC, Canada
Posts: 769
@BigFan and all!

For the record, here is a minimal use of the xadmasterl.library to unarchive some archive, XAD is very neat!

Code:
int extract_archive(
	const char *archive_path,
	const char *destination_path)
{
	struct xadMasterBase  *xadmasterbase;
	struct xadArchiveInfo *ai;
	struct xadFileInfo    *fi;
	LONG                   e;
	UBYTE                  destination_name[NAMEBUFSIZE];

	if((xadmasterbase = (struct xadMasterBase *)OpenLibrary("xadmaster.library", 11)))
	{
		xadMasterBase = xadmasterbase;

		if((ai = (struct xadArchiveInfo *)xadAllocObjectA(XADOBJ_ARCHIVEINFO, 0)))
		{
			e = xadGetInfo(
				ai,
				XAD_INFILENAME, "RAM:Slurp10.lha",
				TAG_DONE);
			if(DEBUG)
			{
				printf("xc_ArchiverName = %s\n", ai->xai_Client->xc_ArchiverName);
			}
			if(!e)
			{
				fi = ai->xai_FileInfo;
				while(fi)
				{
					if(!(fi->xfi_Flags & XADFIF_LINK || fi->xfi_Flags & XADFIF_DIRECTORY))
					{
						CopyMem("RAM:", destination_name, strlen("RAM:") + 1);
						AddPart(destination_name, FilePart(fi->xfi_FileName), NAMEBUFSIZE);
						e = xadFileUnArc(
							ai,
							XAD_OUTFILENAME, destination_name,
							XAD_ENTRYNUMBER, fi->xfi_EntryNumber,
							TAG_DONE);
						if(DEBUG)
						{
							printf("e = %lu\n", e);
						}
					}
					else if(DEBUG)
					{
						printf("\tSkipped link or directory\n");
					}
					fi = fi->xfi_Next;
				}
				goto _RETURN_OK;
			}
			else
			{
				perror("Error in extract_archive(...), call to xadGetInfo(...) failed");
				goto _RETURN_ERROR;
			}
		}
		else
		{
			perror("Error in extract_archive(...), cannot allocate struct xadArchiveInfo");
			goto _RETURN_ERROR;
		}
	}
	else
	{
		perror("Error in  extract_archive(...), cannot open xadmaster.library");
		goto _RETURN_ERROR;
	}

	goto _RETURN_OK;
	_RETURN_OK:
		xadFreeInfo(ai);
		xadFreeObjectA(ai, 0);
		CloseLibrary((struct Library *)xadmasterbase);
		return OK;

	_RETURN_ERROR:
		if(ai)
		{
			xadFreeInfo(ai);
			xadFreeObjectA(ai, 0);
		}
		if(xadmasterbase)
		{
			CloseLibrary((struct Library *)xadmasterbase);
		}
		return ERROR;
}
Cheers!

PS. Being a newbie in Amiga programming, any advice is welcome to improve my code!
tygre is offline  
Old 08 June 2015, 06:09   #5
Thorham
Computer Nerd

Thorham's Avatar
 
Join Date: Sep 2007
Location: Rotterdam/Netherlands
Age: 44
Posts: 3,092
Quote:
Originally Posted by tygre View Post
Being a newbie in Amiga programming, any advice is welcome to improve my code!
You can avoid those indentation levels:

Code:
int bla(void)
{
    struct foo *a;
    struct bar *b;
    int c;
    
    a = function1("abcdef");
    if (a == NULL)
    {
        printError("Some error.");
        goto error1;
    }

    b = function2(12345);
    if (b == NULL)
    {
        printError("Some other error.");
        goto error2;
    }

    c = funtion3(a, b);
    
    cleanup2(b);
    cleanup1(a);
    return c;

error2:
    cleanup1(a);
error1:
    return -1;
}
Nothing wrong with goto, of course, and don't let anyone tell you any different.
Thorham is offline  
Old 08 June 2015, 12:22   #6
BigFan
Registered User

BigFan's Avatar
 
Join Date: Feb 2014
Location: Germany
Posts: 261
I disagree.

Goto is useless in this case. But first: Check your code for redundancy.
Doing so you'll notice, that goto is repeated and the code under both _RETURN_xx labels is identical.

My suggestion:
set an integer variable named rc (as returncode)
replace goto with rc=OK; or rc=ERROR; appropriatly.

delete labels

set cleanup code as if there is an error:

if(ai)
{
xadFreeInfo(ai);
xadFreeObjectA(ai, 0);
}
if(xadmasterbase)
{
CloseLibrary((struct Library *)xadmasterbase);
}
return rc;

this way your are always fine (on success and failure).

else {} conditions will be executed only when if() returns false, that is :
if inner loop succeeded , all if() succeeded before and none of the else{} will be executed.
if not then code will jump to the end of (un)conditioned {} , say it skips all else{} statements prior to the one that fails or can't be checked or do not need to be checked.

your goto doesn't do anything usefull. i think you used this to distuingish between success and failure.

be careful: any statement that is not part of else{} will be executed always as regular.

the exzessive use of goto is a sign of bad code. use goto wisely, e.g.
your code is recursive and the only way to exit on failure or infinite loop is a goto.

me too, i hate doctrines and religious talk about the use of goto, but in your case it leads to weird code quickly.
BigFan is offline  
Old 08 June 2015, 16:00   #7
tygre
Returning fan!

tygre's Avatar
 
Join Date: Jan 2011
Location: Montréal, QC, Canada
Posts: 769
@Thorham and @BigFan

Thanks for reading and commenting my code! My use of gotos was my (poor) attempt to mimic throws/catches in C . I'll revise my code based on your suggestions...

Would you have any comment on my (mis)use/lack-of-use of AmigaOS functions?

Thanks!
tygre is offline  
Old 08 June 2015, 16:48   #8
BigFan
Registered User

BigFan's Avatar
 
Join Date: Feb 2014
Location: Germany
Posts: 261
Path "RAM:" is hardcoded, CopyMem() is not necessary if you initialize with
Code:
ubyte destination_name[NAMEBUFFER]={'R','A','M',':',0};
Would be better to handle this with variables (values for testing can be macro), as it will ease the extension of the code with a file requester. Maybe in a later version or project.


What abuse of AOS functions? There aren't many.

Last edited by BigFan; 08 June 2015 at 17:25. Reason: stumbled over *xadmasterbase , text deleted
BigFan is offline  
Old 08 June 2015, 18:02   #9
Thorham
Computer Nerd

Thorham's Avatar
 
Join Date: Sep 2007
Location: Rotterdam/Netherlands
Age: 44
Posts: 3,092
Quote:
Originally Posted by BigFan View Post
Goto is useless in this case.
No, it's not, because it can get rid of the deep indentation and the else blocks, making the code shorter and easier to follow. You can see this in my example.

Quote:
Originally Posted by BigFan View Post
Doing so you'll notice, that goto is repeated and the code under both
A few lines of identical code isn't a problem in this case, because having to set a return value variable really only adds more code back in.

Another point is that you may want to do a little more than just cleanup in the case of an error. Or just something different. My example shows the latter (only one cleanup function is called, because the first failed).

If you have to duplicate a large amount of code, then it's probably a good idea to use a return variable.

Here's an example of how I actually use goto:
Code:
static int monitor_readFile(lua_State *L)
{
   struct FileInfoBlock *finfo;
   BPTR fhandle;
   APTR fmem;
   char *fname = (char *)luaL_checkstring(L, 1);
   long ret;

   finfo = AllocDosObject(DOS_FIB, fibTags);
   if (finfo == NULL) goto error1;

   fhandle = Open(fname, MODE_OLDFILE);
   if (fhandle == NULL) goto error2;

   if (ExamineFH(fhandle, finfo) == 0) goto error3;

   fmem = malloc(finfo->fib_Size);
   if (fmem == NULL) goto error3;

   ret = Read(fhandle, fmem, finfo->fib_Size);
   Close(fhandle);
   FreeDosObject(DOS_FIB, finfo);

   lua_pushunsigned(L, (unsigned long)fmem);
   lua_pushinteger(L, finfo->fib_Size); // stupid bug here
   lua_pushinteger(L, ret);
   return 3;

error3:
   Close(fhandle);

error2:
   FreeDosObject(DOS_FIB, finfo);

error1:
   lua_pushnil(L);
   return 1;
}

Last edited by Thorham; 09 June 2015 at 09:02.
Thorham is offline  
Old 08 June 2015, 19:02   #10
tygre
Returning fan!

tygre's Avatar
 
Join Date: Jan 2011
Location: Montréal, QC, Canada
Posts: 769
Thanks BigFan and Thorham, I'm going to update my code to make it more lean and mean!

Last edited by tygre; 08 June 2015 at 19:10.
tygre is offline  
Old 09 June 2015, 07:31   #11
Leffmann
 
Join Date: Jul 2008
Location: Sweden
Posts: 2,265
Quote:
Originally Posted by Thorham View Post
Here's an example of how I actually use goto:
That's spaghetti-code Four levels of indentation isn't really bad, but if you want to get rid of them, then initializing each pointer and structure on the condition that the previous one succeeded is a lot cleaner and easier to follow than a bunch of gotos.

You also have a bug in there: accessing the data in finfo after having called FreeDosObject on it.
Leffmann is offline  
Old 09 June 2015, 08:57   #12
Thorham
Computer Nerd

Thorham's Avatar
 
Join Date: Sep 2007
Location: Rotterdam/Netherlands
Age: 44
Posts: 3,092
Quote:
Originally Posted by Leffmann View Post
That's spaghetti-code
I don't agree.

Quote:
Originally Posted by Leffmann View Post
Four levels of indentation isn't really bad


Quote:
Originally Posted by Leffmann View Post
but if you want to get rid of them, then initializing each pointer and structure on the condition that the previous one succeeded is a lot cleaner and easier to follow than a bunch of gotos.
That code is perfectly readable, and I'm certainly not restructuring it to get rid of those gotos.

Quote:
Originally Posted by Leffmann View Post
You also have a bug in there: accessing the data in finfo after having called FreeDosObject on it.
Missed that one, thanks
Thorham is offline  
Old 09 June 2015, 09:34   #13
Leffmann
 
Join Date: Jul 2008
Location: Sweden
Posts: 2,265
Quote:
Originally Posted by Thorham View Post
That code is perfectly readable, and I'm certainly not restructuring it to get rid of those gotos.
I think it's always a good idea to get rid of gotos if you can, and if you can make the program flow cleaner and getting rid of duplicate code at the same time, just the better. I would suggest this:
Code:
static int monitor_readFile(lua_State *L) {
  struct FileInfoBlock* finfo;
  char* fname;
  BPTR fhandle = 0;
  APTR fmem = NULL;
  BOOL exres = FALSE;
  int retval;

  fname = (char*)luaL_checkstring(L, 1);
  finfo = AllocDosObject(DOS_FIB, fibTags);

  if (finfo)    fhandle = Open(fname, MODE_OLDFILE);
  if (fhandle)  exres = ExamineFH(fhandle, finfo);
  if (exres)    fmem = malloc(finfo->fib_Size);

  if (fmem) {
    long ret = Read(fhandle, fmem, finfo->fib_Size);
    lua_pushunsigned(L, (unsigned long)fmem);
    lua_pushinteger(L, finfo->fib_Size);
    lua_pushinteger(L, ret);
    retval = 3;
  } else {
    lua_pushnil(L);
    retval = 1;
  }

  if (fhandle)  Close(fhandle);
  if (finfo)    FreeDosObject(DOS_FIB, finfo);

  return retval;
}

Last edited by Leffmann; 09 June 2015 at 16:18.
Leffmann is offline  
Old 09 June 2015, 13:16   #14
BigFan
Registered User

BigFan's Avatar
 
Join Date: Feb 2014
Location: Germany
Posts: 261
@Thorham
My posting about 'goto' addresses Tygre, not you.
Mentioned '_Return_' code section is definitly not yours, so stop taking things personally.
And i'm not willing to use @ periodically and rewrite every posting to avoid users getting pissed when misinterpreting my posts.


And i agree with Leffmann, redundant code and usage of 'goto' is the path to the dark side of the force. Once you get used to it, you'll hardly find a way back into the 'light'.
It looks like someone has ported BASIC to C. Whenever a user is posting spaghetti code, he'll be confronted with harsh criticism in any advanded users forum.
No need to encourage the usage of 'goto', except you can fundamentally argue for it because of its advantage in a very special case.
BigFan is offline  
Old 09 June 2015, 15:32   #15
tygre
Returning fan!

tygre's Avatar
 
Join Date: Jan 2011
Location: Montréal, QC, Canada
Posts: 769
@thread

Thank you all for your comments, I really appreciate your suggestions and will revise my code accordingly .

You all make good points pros and cons using gotos .

My using gotos was my (poor) attempt to simulate throws/catches but also to have "single exit points", actually two: one exit point for "normal returns" and one for "error returns". Please feel free to give more advices on my code!

Let's not argue whether this is spaghetti code or not... we are still far from Toyota's code and their 10,000 global variables .

Cheers!

Last edited by tygre; 09 June 2015 at 15:33. Reason: Minor plead
tygre is offline  
Old 09 June 2015, 17:39   #16
Thorham
Computer Nerd

Thorham's Avatar
 
Join Date: Sep 2007
Location: Rotterdam/Netherlands
Age: 44
Posts: 3,092
Quote:
Originally Posted by Leffmann View Post
I think it's always a good idea to get rid of gotos if you can, and if you can make the program flow cleaner and getting rid of duplicate code at the same time, just the better.
Nothing wrong with the code you posted, but the reason I'm using goto in my code is to get the program flow out of the main part of the the code block. The duplicate code is only there because it's just two short lines.

Quote:
Originally Posted by BigFan View Post
My posting about 'goto' addresses Tygre, not you.
That's what I was actually referring to. Goto isn't useless in that code if used properly.

Quote:
Originally Posted by BigFan View Post
Mentioned '_Return_' code section is definitly not yours, so stop taking things personally.
My comment was a general comment.

Quote:
Originally Posted by tygre View Post
That's just totally insane
Thorham is offline  
Old 15 June 2015, 20:05   #17
tygre
Returning fan!

tygre's Avatar
 
Join Date: Jan 2011
Location: Montréal, QC, Canada
Posts: 769
Hi all!

For the record, here is the (minimum?) code needed to use the xadmaster.library to unarchive an archive file (no subfolders or links, no checking whether the destination exists... really the bare minimum), thanks a lot for your help and suggestions!

The rest of the code is available here and I welcome all your comments/suggestions to improve it!

Cheers!
Tygre

Code:
/*
	AmiModRadio
	All of Aminet modules at your fingertips



	Copyright 2015 Tygre <tygre@chingu.asia>

	This file is part of AmiModRadio.

	AmiModRadio is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	AmiModRadio is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with AmiModRadio. If not, see <http://www.gnu.org/licenses/>.



	Entirely developed on an Amiga!
	(Except for source code versioning...)
	tygre@chingu.asia
*/



#include "xad.h"
#include "fortify.h"
#include "utils.h"

#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <proto/xadmaster.h>
#include <proto/exec.h>
#include <proto/dos.h>



#define DEBUG         0
#define DEBUG_VERBOSE 0

#define MAX_SIZE_LIST 512
#define MAX_SIZE_NAME 512



struct xadMasterBase *xadMasterBase = NULL;



int extract_archive(
	IN  char  *archive_path,
	IN  char  *destination_path,
	OUT char **list)
{
	struct xadMasterBase  *xadmasterbase           = NULL;
	struct xadArchiveInfo *ai                      = NULL;
	struct xadFileInfo    *fi                      = NULL;
	LONG                   e                       = 0;
	char                  *list_temp               = NULL;
	char                  *list_temp_for_realloc   = NULL;
	int                    number_of_chars         = 0;
	int                    maximum_number_of_chars = 0;
	UBYTE                  destination_name[MAX_SIZE_NAME];

	maximum_number_of_chars = MAX_SIZE_LIST;
	list_temp = calloc(maximum_number_of_chars, sizeof(char));
	if(list_temp == NULL)
	{
		perror("Error in  extract_archive(...), cannot allocate memory");
		goto _RETURN_ERROR;
	}

	if(!(xadmasterbase = (struct xadMasterBase *)OpenLibrary("xadmaster.library", 11)))
	{
		perror("Error in  extract_archive(...), cannot open xadmaster.library");
		goto _RETURN_ERROR;
	}
	xadMasterBase = xadmasterbase;

	if(!(ai = (struct xadArchiveInfo *)xadAllocObjectA(XADOBJ_ARCHIVEINFO, 0)))
	{
		perror("Error in extract_archive(...), cannot allocate struct xadArchiveInfo");
		goto _RETURN_ERROR;
	}

	e = xadGetInfo(
		ai,
		XAD_INFILENAME, archive_path,
		TAG_DONE);
	if(e)
	{
		perror("Error in extract_archive(...), call to xadGetInfo(...) failed");
		goto _RETURN_ERROR;
	}

	if(DEBUG)
	{
		printf("xc_ArchiverName = %s\n", ai->xai_Client->xc_ArchiverName);
	}

	// Everything is set, let's extract the content of the archive :-)
	// This loop ignores links and directories. It only extracts files in the archive root.
	fi = ai->xai_FileInfo;
	while(fi)
	{
		if(!(fi->xfi_Flags & XADFIF_LINK || fi->xfi_Flags & XADFIF_DIRECTORY))
		{
			CopyMem(destination_path, destination_name, strlen(destination_path) + 1);
			AddPart(destination_name, FilePart(fi->xfi_FileName), MAX_SIZE_NAME);
			e = xadFileUnArc(
				ai,
				XAD_OUTFILENAME, destination_name,
				XAD_ENTRYNUMBER, fi->xfi_EntryNumber,
				TAG_DONE);
			if(e)
			{
				printf("Error in extract_archive(...), call to xadFileUnArc(...) failed\n");
				printf("\te = %ld for file = %s\n", e, destination_name);
			}
			else
			{
				number_of_chars += strlen(destination_name) + 2;
				if(number_of_chars >= maximum_number_of_chars)
				{
					maximum_number_of_chars += MAX_SIZE_LIST;
					list_temp_for_realloc = realloc(list_temp, maximum_number_of_chars);
					if(list_temp_for_realloc == NULL)
					{
						perror("Error in  extract_archive(...), cannot reallocate memory");
						goto _RETURN_ERROR;
					}
					list_temp = list_temp_for_realloc;
				}
				strcat(list_temp, destination_name);
				strcat(list_temp, "\n");
			}
		}
		else if(DEBUG)
		{
			printf("\tSkipped link or directory\n");
		}
		fi = fi->xfi_Next;
	}

	goto _RETURN_OK;
	_RETURN_OK:
		xadFreeInfo(ai);
		xadFreeObjectA(ai, 0);
		CloseLibrary((struct Library *)xadmasterbase);
		if(string_fit(&*list, list_temp) == ERROR)
		{
			perror("Error in  extract_archive(...), cannot trim list");
			goto _RETURN_ERROR;
		}
		free(list_temp);
		return OK;

	goto _RETURN_ERROR;
	_RETURN_ERROR:
		if(ai)
		{
			xadFreeInfo(ai);
			xadFreeObjectA(ai, 0);
		}
		if(xadmasterbase)
		{
			CloseLibrary((struct Library *)xadmasterbase);
		}
		if(list_temp != NULL)
		{
			free(list_temp);
		}
		return ERROR;
}
tygre is offline  
Old 16 June 2015, 22:57   #18
BigFan
Registered User

BigFan's Avatar
 
Join Date: Feb 2014
Location: Germany
Posts: 261
My suggestions:

Use either c or aos functions. this code is not portable and i suggest you to replace c functions, especially when it comes to memory allocation.

Sometimes perror and printf is used. Why?

Do not use goto like you did in the past. Your code is f*cking weird spaghetti
code. Your code gets unreadible, instead use modular and structured code.

Split functions. Keep them small and simple.

If **list is for viewing/printing only, then write dest_names to file open in T:
This saves you from reallocation and the possible failure of it. Thats another reason to split up your functions. AddtoList can be file open/write instead of realloc() without interefering with existing code blocks.
I hope you get the point

I have not compiled this. Take it with a grain of salt.

Code:
#include "xad.h"
#include "fortify.h"
#include "utils.h"

#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <proto/xadmaster.h>
#include <proto/exec.h>
#include <proto/dos.h>



#define DEBUG         0
#define DEBUG_VERBOSE 0

#define MAX_SIZE_LIST 512
#define MAX_SIZE_NAME 512

// Error messages used in extract_archive()
// message text takes less memory now

#define ERRMSG_100 "Error in  extract_archive(), "
#define ERRMSG_101 "cannot allocate memory!"
#define ERRMSG_102 "cannot open xadmaster.library!"
#define ERRMSG_103 "call to xadFileUnArc(...) failed!"
#define ERRMSG_104 "cannot reallocate memory!"
#define ERRMSG_104 "cannot trim list!"
//char * errmsg_105 = ;
//char * errmsg_106 = ;

struct xadMasterBase * xadMasterBase = NULL;
// list entry management is new function
// keep function bodies lean and clean, do not overload with different purposes
// do not overload with features
int AddtoList(char *, char *);

int extract_archive(
	IN  char  *archive_path,
	IN  char  *destination_path,
	OUT char **list)
{
	struct xadMasterBase  *xadmasterbase           = NULL;
	struct xadArchiveInfo *ai                      = NULL;
	struct xadFileInfo    *fi                      = NULL;
	char                  *list_temp               = NULL;
	char                  *list_temp_for_realloc   = NULL;
	long                   e                       ;
	int 				   rc 					   = OK;
	UBYTE                  destination_name[MAX_SIZE_NAME];

	if ((list_temp = calloc(MAX_SIZE_LIST, sizeof(char))) == NULL);
	{
		// compiler concatenates subsequent strings automatically
		perror(ERRMSG_100 ERRMSG_101);
		// there is not much to clean up at this point, so just quit this funtion block
		return ERROR;
	}

	if((xadmasterbase = (struct xadMasterBase *)OpenLibrary("xadmaster.library", 11)) == NULL)
	{
		perror(ERRMSG_100 ERRMSG_102);
		return ERROR;
	}
	
	xadMasterBase = xadmasterbase;

	if(ai = (struct xadArchiveInfo *)xadAllocObjectA(XADOBJ_ARCHIVEINFO, 0))
	{
		if(e = xadGetInfo(ai, XAD_INFILENAME, archive_path,	TAG_DONE))
		{
			// Everything is set, let's extract the content of the archive :-)
			// This loop ignores links and directories. It only extracts files in the archive root.
			fi = ai->xai_FileInfo;
			while(fi)
			{
				if(!(fi->xfi_Flags & XADFIF_LINK || fi->xfi_Flags & XADFIF_DIRECTORY))
				{
					CopyMem(destination_path, destination_name, strlen(destination_path) + 1);
					
					AddPart(destination_name, FilePart(fi->xfi_FileName), MAX_SIZE_NAME);
					
					if (e = xadFileUnArc(ai, XAD_OUTFILENAME, destination_name,
									 XAD_ENTRYNUMBER, fi->xfi_EntryNumber, TAG_DONE))
					{
						printf(ERRMSG_100 ERRMSG_103);
						printf("\te = %ld for file = %s\n", e, destination_name);
					}
					else
					{
						//quit while-loop on error (realloc failed)
						if(AddtoList(list_temp, destination_name)) 
                                                {
                                                      rc = ERROR;             
                                                      break;
                                                 }
					}
				}
				fi = fi->xfi_Next;
			}
		}
		else
		{
			rc = ERROR;
		}
	}
	else
	{
		rc = ERROR;
	}
// clean up section

		if(ai)
		{
			xadFreeInfo(ai);
			xadFreeObjectA(ai, 0);
		}
		if(xadmasterbase)
		{
			CloseLibrary((struct Library *)xadmasterbase);
		}
		if(string_fit(&*list, list_temp) == ERROR)
		{
			perror("Error in  extract_archive(...), cannot trim list");
		}
		if(list_temp)
		{
			free(list_temp);
		}
		return rc;
}

int AddtoList(char * list_temp, char * destination_name)
{
	static int num_chars = 0;
	static int listsize = MAX_SIZE_LIST;

	num_chars += strlen(destination_name) + 2;
	
	if(number_of_chars >= MAX_SIZE_LIST)
	{
		int * list_temp_for_realloc = realloc(list_temp, (listsize += MAX_SIZE_LIST));
		if(list_temp_for_realloc != NULL)
		{
			list_temp = list_temp_for_realloc;
		}
		else 
		{
			perror(ERRMSG_100 ERRMSG_104);
			return 20; // or set return code to ERROR
		}
	}
	strcat(list_temp, destination_name);
	strcat(list_temp, "\n");
	return 0;
}

Last edited by BigFan; 16 June 2015 at 23:02.
BigFan is offline  
Old 17 June 2015, 00:26   #19
tygre
Returning fan!

tygre's Avatar
 
Join Date: Jan 2011
Location: Montréal, QC, Canada
Posts: 769
Hi BigFan!

Quote:
Originally Posted by BigFan View Post
Use either c or aos functions. this code is not portable and i suggest you to replace c functions, especially when it comes to memory allocation.
I agree but as a newbie, I am confused about C vs. AmigaOS functions: is there anyway to have a tool warn me about using C functions instead of the proper AmigaOS functions? I am using Cubic IDE and vbcc.


Quote:
Originally Posted by BigFan View Post
Sometimes perror and printf is used. Why?
No good reason, my bad Actually, could you suggest me the related AmigaOS function? I saw PrintFault but it seems to require always at least one parameter?

Quote:
Originally Posted by BigFan View Post
Do not use goto like you did in the past. Your code is f*cking weird spaghetti
code. Your code gets unreadible, instead use modular and structured code.
Split functions. Keep them small and simple.
Okay!

Quote:
Originally Posted by BigFan View Post
If **list is for viewing/printing only, then write dest_names to file open in T:. This saves you from reallocation and the possible failure of it. Thats another reason to split up your functions. AddtoList can be file open/write instead of realloc() without interefering with existing code blocks. I hope you get the point
Hum, not quite but I am going to think about it

Quote:
Originally Posted by BigFan View Post
I have not compiled this. Take it with a grain of salt.

Code:
#include "xad.h"
#include "fortify.h"
#include "utils.h"

#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <proto/xadmaster.h>
#include <proto/exec.h>
#include <proto/dos.h>



#define DEBUG         0
#define DEBUG_VERBOSE 0

#define MAX_SIZE_LIST 512
#define MAX_SIZE_NAME 512

// Error messages used in extract_archive()
// message text takes less memory now

#define ERRMSG_100 "Error in  extract_archive(), "
#define ERRMSG_101 "cannot allocate memory!"
#define ERRMSG_102 "cannot open xadmaster.library!"
#define ERRMSG_103 "call to xadFileUnArc(...) failed!"
#define ERRMSG_104 "cannot reallocate memory!"
#define ERRMSG_104 "cannot trim list!"
//char * errmsg_105 = ;
//char * errmsg_106 = ;

struct xadMasterBase * xadMasterBase = NULL;
// list entry management is new function
// keep function bodies lean and clean, do not overload with different purposes
// do not overload with features
int AddtoList(char *, char *);

int extract_archive(
    IN  char  *archive_path,
    IN  char  *destination_path,
    OUT char **list)
{
    struct xadMasterBase  *xadmasterbase           = NULL;
    struct xadArchiveInfo *ai                      = NULL;
    struct xadFileInfo    *fi                      = NULL;
    char                  *list_temp               = NULL;
    char                  *list_temp_for_realloc   = NULL;
    long                   e                       ;
    int                    rc                        = OK;
    UBYTE                  destination_name[MAX_SIZE_NAME];

    if ((list_temp = calloc(MAX_SIZE_LIST, sizeof(char))) == NULL);
    {
        // compiler concatenates subsequent strings automatically
        perror(ERRMSG_100 ERRMSG_101);
        // there is not much to clean up at this point, so just quit this funtion block
        return ERROR;
    }

    if((xadmasterbase = (struct xadMasterBase *)OpenLibrary("xadmaster.library", 11)) == NULL)
    {
        perror(ERRMSG_100 ERRMSG_102);
        return ERROR;
    }
    
    xadMasterBase = xadmasterbase;

    if(ai = (struct xadArchiveInfo *)xadAllocObjectA(XADOBJ_ARCHIVEINFO, 0))
    {
        if(e = xadGetInfo(ai, XAD_INFILENAME, archive_path,    TAG_DONE))
        {
            // Everything is set, let's extract the content of the archive :-)
            // This loop ignores links and directories. It only extracts files in the archive root.
            fi = ai->xai_FileInfo;
            while(fi)
            {
                if(!(fi->xfi_Flags & XADFIF_LINK || fi->xfi_Flags & XADFIF_DIRECTORY))
                {
                    CopyMem(destination_path, destination_name, strlen(destination_path) + 1);
                    
                    AddPart(destination_name, FilePart(fi->xfi_FileName), MAX_SIZE_NAME);
                    
                    if (e = xadFileUnArc(ai, XAD_OUTFILENAME, destination_name,
                                     XAD_ENTRYNUMBER, fi->xfi_EntryNumber, TAG_DONE))
                    {
                        printf(ERRMSG_100 ERRMSG_103);
                        printf("\te = %ld for file = %s\n", e, destination_name);
                    }
                    else
                    {
                        //quit while-loop on error (realloc failed)
                        if(AddtoList(list_temp, destination_name)) 
                                                {
                                                      rc = ERROR;             
                                                      break;
                                                 }
                    }
                }
                fi = fi->xfi_Next;
            }
        }
        else
        {
            rc = ERROR;
        }
    }
    else
    {
        rc = ERROR;
    }
// clean up section

        if(ai)
        {
            xadFreeInfo(ai);
            xadFreeObjectA(ai, 0);
        }
        if(xadmasterbase)
        {
            CloseLibrary((struct Library *)xadmasterbase);
        }
        if(string_fit(&*list, list_temp) == ERROR)
        {
            perror("Error in  extract_archive(...), cannot trim list");
        }
        if(list_temp)
        {
            free(list_temp);
        }
        return rc;
}

int AddtoList(char * list_temp, char * destination_name)
{
    static int num_chars = 0;
    static int listsize = MAX_SIZE_LIST;

    num_chars += strlen(destination_name) + 2;
    
    if(number_of_chars >= MAX_SIZE_LIST)
    {
        int * list_temp_for_realloc = realloc(list_temp, (listsize += MAX_SIZE_LIST));
        if(list_temp_for_realloc != NULL)
        {
            list_temp = list_temp_for_realloc;
        }
        else 
        {
            perror(ERRMSG_100 ERRMSG_104);
            return 20; // or set return code to ERROR
        }
    }
    strcat(list_temp, destination_name);
    strcat(list_temp, "\n");
    return 0;
}
Thanks a lot! Excellent ideas

Cheers!

Last edited by tygre; 17 June 2015 at 03:21. Reason: Forgot to say that I am using Cubic IDE and vbcc.
tygre is offline  
 


Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
 
Thread Tools

Similar Threads
Thread Thread Starter Forum Replies Last Post
Unarchiving LHA & LZX files on Windows XP amigauser Amiga scene 58 28 September 2017 23:36
Fixed XAD for lha (OS3.9) ancalimon request.Apps 1 27 July 2014 17:39
Amateur requires help with LHA files..... THEGMAN support.WinUAE 3 27 September 2010 11:27
lha files read by UAE? dionisis New to Emulation or Amiga scene 3 09 April 2007 11:55
How to use LHA files (WinUAE) Jacko New to Emulation or Amiga scene 4 14 January 2007 11:46

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT +2. The time now is 17:43.


Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2020, vBulletin Solutions Inc.
Page generated in 0.10776 seconds with 13 queries