home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Audio Version 4.94
/
audioversion4.94knowledgemediaresourcelibraryoctober1994.iso
/
amiga
/
utils
/
exp_iv
/
files.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-05-16
|
12KB
|
583 lines
/* files.c */
/* songs management, mainly some iterators
*/
/*
* $Author: Espie $
* $Date: 91/05/16 15:05:01 $
* $Revision: 1.8 $
* $Log: files.c,v $
* Revision 1.8 91/05/16 15:05:01 Espie
* *** empty log message ***
*
* Revision 1.7 91/05/12 19:53:05 Espie
* Corrected the non-freed icons problem.
*
* Revision 1.6 91/05/12 15:56:53 Espie
* Bugs mostly corrected.
*
* Revision 1.5 91/05/11 14:58:02 Espie
* Corrected an auto-cleanup problem.
*
* Revision 1.4 91/05/10 00:04:19 Espie
* Added albums support. Directories missing, not sure
* I will add it...
*
* Revision 1.3 91/05/09 17:35:17 Espie
* Support for appwindow, mk_wbarg optimization.
*
* Revision 1.2 91/05/08 18:33:46 Espie
* Added check_abort() for loooong runs.
* Added support for arp pattern-matching... need checking that arp is around.
* Does enter subdirectories too !
*
* Revision 1.1 91/05/08 15:50:32 Espie
* Initial revision
*
*
*/
#include <exec/types.h>
#include <dos/dos.h>
#include <exec/memory.h>
#include <workbench/startup.h>
#include <workbench/workbench.h>
#include <string.h>
#include <stddef.h>
#include <custom/cleanup.h>
#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/icon.h>
#include <stdio.h>
#include <libraries/arpbase.h>
#include <proto/arp.h>
#include "song.h"
#include "public_play.h"
void *malloc();
#include "proto.h"
LOCAL struct WBStartup *msg;
LOCAL char **tools;
/***
*
* Tooltypes management
*
***/
/* get_arg(tools, tooltype, def): reads the tooltype in the tools array,
* as a numerical argument, with def as a default value.
*/
int get_arg(char **tools, char *tooltype, int def)
{
int val;
char *string = NULL;
if (tools)
string = FindToolType(tools, tooltype);
if (string && sscanf(string, "%d", &val) == 1)
return val;
else
return def;
}
/* same thing with default tools */
int do_get_arg(char *tooltype, int def)
{
return get_arg(tools, tooltype, def);
}
/* map_arg: gives a numerical argument from a limited set
* of strings values
*/
int map_arg(char **tools, char *tooltype, char **names, int def)
{
int val;
char *string = NULL;
if (tools)
string = FindToolType(tools, tooltype);
if (string)
{
for (val = 0; names; val++, names++)
if (MatchToolValue(string, *names))
return val;
}
return def;
}
int do_map_arg(char *tooltype, char **names, int def)
{
return map_arg(tools, tooltype, names, def);
}
/* exist_tooltype(tools, tooltype): checks if tooltype exists among tools
*/
BOOL exist_tooltype(char **tools, char *tooltype)
{
if (!tools)
return NULL;
return (FindToolType(tools, tooltype) != NULL);
}
/***
*
* Iterators.
* Every argument is managed as an iterator
* you can resume later. This makes a nice
* framework for multiple arguments, pattern-matching,
* albums, directory traversal...
*
***/
enum it_tag {CLI_list, Match_list, Dir_list, WB_list, Album, Empty};
struct CLI_it
{
int number;
int index;
char **names;
};
struct WB_it
{
int number;
int index;
struct WBArg *args;
};
#define MAX_LENGTH 400
struct Album_it
{
FILE *f;
char *pbuf;
char buffer[MAX_LENGTH];
};
struct Match_it
{
struct AnchorPath anchor;
BYTE suppl_buffer[MAX_LENGTH];
};
/*
struct Dir_List
{
struct FileInfoBlock examiner;
};
*/
/* be careful of the fields you use, the FileInfoBlock/AnchorPath
* must be longword aligned !
*/
struct iterator
{
enum it_tag tag;
struct iterator *next;
CLEAN auto_clean;
BPTR save_lock;
struct DiskObject *currenticon;
BOOL cd;
BOOL ownlock;
union
{
struct CLI_it CLI;
struct WB_it WB;
struct Album_it Album;
struct Match_it Match;
} u;
};
/***
*
* Support functions
*
***/
LOCAL void free_last_icon(struct iterator *it)
{
if (it->currenticon)
FreeDiskObject(it->currenticon);
it->currenticon = NULL;
}
/* where do we get the tooltypes from anyway
*/
char **grab_tooltypes(struct iterator *it, char *arg)
{
struct DiskObject *icon;
if (icon_around())
{
icon = GetDiskObject(arg);
if (icon)
{
if (it)
{
free_last_icon(it);
it->currenticon = icon;
}
else
ToClean(FreeDiskObject, icon);
return icon->do_ToolTypes;
}
}
return NULL;
}
/* we need doFreeAnchorChain 'cause FreeAnchorChain exists only as a pragma
*/
LOCAL void doFreeAnchorChain(struct AnchorPath *ap)
{
FreeAnchorChain(ap);
}
/* getline(buffer, bufsize, f): read a line from file f into buffer,
* upto bufsize characters. Puts a \0 at the end of line in place of
* the \n. The last line may end without a \n.
* If the line is too long, remaining characters are skipped.
* returns the strlen of buffer, or -1 if the line is too long.
* A NULL f is allowed, in that case, the call will never succeed.
*
* It is the responsibility of the client to close that file.
*/
LOCAL int getline(char *buffer, int bufsize, FILE *f)
{
int i, c;
if (!f)
return 0;
for (i = 0; i < bufsize; i++)
{
c = fgetc(f);
if (c == EOF)
{
buffer[i] = '\0';
return i;
}
if (c == '\n')
{
buffer[i] = '\0';
return i;
}
buffer[i] = c;
}
while((c=fgetc(f)) != '\n' && c != EOF);
return (-1);
}
/* The iterators need to change dir in an effective way.
*/
LOCAL void un_dir(struct iterator *it)
{
if (it->cd)
{
if (it->ownlock)
UnLock(CurrentDir(it->save_lock));
else
CurrentDir(it->save_lock);
}
it->cd = FALSE;
it->ownlock = FALSE;
}
LOCAL void change_dir(struct iterator *it, BPTR new_dir)
{
un_dir(it);
it->save_lock = CurrentDir(new_dir);
it->cd = TRUE;
}
/* iterator creation. An iterator is always the son of another,
* except the root, of course. new_iterator() initializes all
* relevant fields to reasonable values.
*/
LOCAL struct iterator *new_iterator(struct iterator *father)
{
struct iterator *new;
/* this is an aligned structure */
new = AllocMem(sizeof(struct iterator), MEMF_ANY);
if (!new)
return NULL;
new->auto_clean = AllocClean(NIL);
ToClean2L(new->auto_clean, FreeMem, new, sizeof(struct iterator));
new->ownlock = FALSE;
new->cd = FALSE;
new->next = father;
new->currenticon = NULL;
ToCleanL(new->auto_clean, un_dir, new);
ToCleanL(new->auto_clean, free_last_icon, new);
return new;
}
/* insert_iterator(it): returns a new iterator inserted as a son
* of it, so executed before we resume it. Note that the address of
* it is necessary.
*/
LOCAL struct iterator *insert_iterator(struct iterator **head)
{
struct iterator *base;
base = new_iterator(*head);
*head = base;
return base;
}
/* creation of common iterator types
*/
LOCAL struct iterator *mk_CLI_iterator(struct iterator **head,
int argc, char **argv)
{
struct iterator *new;
new = insert_iterator(head);
new->tag = CLI_list;
new->u.CLI.names = argv;
new->u.CLI.number = argc;
new->u.CLI.index = 0;
return new;
}
LOCAL struct iterator *mk_WB_iterator(struct iterator **head,
int argn, struct WBArg *argarray)
{
struct iterator *new;
new = insert_iterator(head);
new->tag = WB_list;
new->u.WB.args = argarray;
new->u.WB.number = argn;
new->u.WB.index = 0;
return new;
}
/* the arp pattern matcher... */
LOCAL char *match_next(struct AnchorPath *ap)
{
int res;
forever
{
res = FindNext(ap);
if (res)
return NULL;
if (ap->ap_Info.fib_DirEntryType < 0)
return ap->ap_Buf;
if (!ap->ap_Flags & APF_DidDir)
ap->ap_Flags |= APF_DoDir;
}
}
/* ...and the start of it */
LOCAL char *match_CLI(struct iterator **head)
{
struct iterator *first, *new;
first = *head;
forever
{
if (first->u.CLI.index >= first->u.CLI.number)
return NULL;
if (requester_type() != ARP)
return first->u.CLI.names[first->u.CLI.index++];
else
{
struct AnchorPath *ap;
int res;
new = insert_iterator(head);
new->tag = Match_list;
ap = &new->u.Match.anchor;
ap->ap_BreakBits = 0;
ap->ap_Flags = APF_DoWild;
ap->ap_StrLen = MAX_LENGTH;
ToCleanL(new->auto_clean, doFreeAnchorChain, ap);
res = FindFirst(first->u.CLI.names[first->u.CLI.index++], ap);
if (!res)
{
if (ap->ap_Info.fib_DirEntryType < 0)
return ap->ap_Buf;
else
{
ap->ap_Flags |= APF_DoDir;
return match_next(ap);
}
}
}
}
}
/* how to restart an existing iterator */
LOCAL char *resume_iterator(struct iterator **head)
{
struct iterator *new, *first;
struct WBArg *temp;
first = *head;
switch(first->tag)
{
case CLI_list:
return match_CLI(head);
case WB_list:
if (first->u.WB.index >= first->u.WB.number)
return NULL;
temp = first->u.WB.args + first->u.WB.index++;
if (temp->wa_Lock)
change_dir(first, temp->wa_Lock);
return temp->wa_Name;
case Match_list:
return match_next(&first->u.Match.anchor);
case Album:
if (!getline(first->u.Album.pbuf, MAX_LENGTH, first->u.Album.f))
{
/* temporary kludge */
if (first->u.Album.f)
{
fclose(first->u.Album.f);
first->u.Album.f = NULL;
}
return NULL;
}
else
{
new = mk_CLI_iterator(head, 1, &(first->u.Album.pbuf));
return match_CLI(head);
}
}
}
LOCAL void delete_first(struct iterator **head)
{
struct iterator *next;
next = (*head)->next;
CleanUp((*head)->auto_clean);
*head = next;
}
/* basic stuff about iterators. Still needs a special test
* about albums.
*/
LOCAL char *do_next_song(struct iterator **head)
{
char *temp;
forever
{
check_abort();
if (!*head)
return NULL;
if (temp = resume_iterator(head))
return temp;
else
delete_first(head);
}
}
/* basic code to deal with albums. Once we've detected an album,
* we can insert it.
*/
LOCAL void insert_album(struct iterator **head, char *arg)
{
struct iterator *base;
base = insert_iterator(head);
base->tag = Album;
base->u.Album.pbuf = base->u.Album.buffer;
base->u.Album.f = fopen(arg, "r");
/* I can't autoclean this stuff: conflict with Lattice
ToCleanL(base->auto_clean, fclose, base->u.Album.f);
*/
}
char *next_song(struct iterator **head, BOOL req)
{
char *test;
struct iterator *new;
static struct WBArg holder;
forever
{
test = do_next_song(head);
if (test)
{
if (exist_tooltype(grab_tooltypes(*head, test), "ALBUM"))
{
insert_album(head, test);
}
else
return test;
}
else
{
if (req && query_name("Module to play", &holder))
{
new = mk_WB_iterator(head, 1, &holder);
new->ownlock = TRUE;
}
else
return NULL;
}
}
}
/* init_iterator(): builds an initial iterator from the arguments
* supplied by the user.
*/
LOCAL struct iterator *zero;
LOCAL struct iterator *init_iterator(int argc, char **argv)
{
struct iterator *base;
zero = NULL;
if (argc)
{
msg = NULL;
base = mk_CLI_iterator(&zero, argc, argv);
}
else
{
msg = (struct WBStartup *)argv;
base = mk_WB_iterator(&zero, msg->sm_NumArgs, msg->sm_ArgList);
}
return base;
}
/* insert_args: adds new songs given to the appwindow.
*/
void insert_args(struct iterator **head, struct AppMessage *msg)
{
struct iterator *new;
new = mk_WB_iterator(head, msg->am_NumArgs, msg->am_ArgList);
ToCleanL(new->auto_clean, ReplyMsg, msg);
}
/* setup_arguments: initial setup for everything
*/
struct iterator *setup_arguments(int argc, char **argv)
{
struct iterator *result;
result = init_iterator(argc, argv);
if (argc)
tools = argv; /* grab_tooltypes(NIL, next_song(&result, FALSE)); */
else
tools = grab_tooltypes(NIL, next_song(&result, FALSE));
return result;
}