home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 10
/
aminetcdnumber101996.iso
/
Aminet
/
util
/
batch
/
BindNames36_19.lha
/
BindNames.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-11-05
|
16KB
|
845 lines
/* File : BindNames.c
*
* $Project:
*
* $Description:
*
* This is a simple utility to remove some of the drudgery of program
* installation. Instead of having to edit a Startup-Sequence for
* every logical name that must be used by a new program, this lets
* names be block-allocated. The BindNames program looks for files
* in the SYS:Names directory. Each of these files contains any number
* of lines of the form:
*
* <Name>: <Path> [ADD|DEFER|PATH]
*
* Where "Name" is the logical name we're assigning, "Path" is the
* path name we're making equivalent. Refer the AmigaDOS manual under
* the Assign command for a full description of the ADD, DEFER and
* PATH keywords.
*
* $Module Id:
* $Original Author: Dave Haynie
* $Date Started: ??? ?? 1989
*
* $Header: sqa:BobsStuff/BindNames/BindNames.c-v 1.1 1995/08/08 02:26:45 Bob Exp $
*
* $Revision: 1.1 $
*
* $State: Exp $
*
* $Locker: $
*
* $Log: BindNames.c-v $
* Revision 1.1 1995/08/08 02:26:45 Bob
* Initial revision
*
*
*
* $History:
* {ver} {initial} {date} {description of change}
*
* 1.0 DH ??? ?? 1989 Initial rev
* 2.1 RWH Apr 16 1994 Modified to handle new
* V36 Assign arguments DEFER,
* PATH and ADD. Also excluded
* SYS:Names/*.bak from assign
* files.
* 2.1a RWH Sun Aug 7 1994 Added NAMES, FILE and REMOVE
* keywords and associated
* functionality.
*/
/* ====================================================================== */
#include <exec/memory.h>
#include <libraries/dos.h>
#include <libraries/dosextens.h>
#include <exec/types.h>
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <dos.h>
#include <dos/dosextens.h>
#include <proto/all.h>
#include "BindNames.h"
#include "BindNames_rev.h"
static char *BN_Version =
VERSTAG" by Dave Haynie (modified for V36+ By Robert Hardy)";
/* ====================================================================== */
struct List Names;
struct NameNode *lostnodes;
struct DosLibrary *DosBase;
struct DosInfo *info;
/* ====================================================================== */
/* Sorry Dave, SAS 6.51 gacked on the original macro */
char *CopyStr(char *s)
{
char *string;
size_t len = strlen(s) + 1;
string = malloc(len);
if (string)
strcpy(string, s);
return string;
}
/* This function makes a BCPL string into a C style string. */
char *b2cstr(char *cstr, BPTR bptr)
{
char *ptr = (char *) BADDR(bptr);
strncpy(cstr, ptr + 1, *ptr);
cstr[*ptr] = '\0';
return cstr;
}
/* ====================================================================== */
/* Here we manage name trees. Name nodes are built from the device list
first. All primary nodes based on the device list have NULL paths,
indicating that they are primary and thus, don't need to be recreated.
Subsequent nodes are added to the node that they depend on. If a node
is encountered that doesn't have a parent listed yet, it will be place
on a temporary node list. */
/* This function creates a name node, allocating whatever memory is
needed. */
struct NameNode *MakeNode(char *name, char *path)
{
struct NameNode *nn;
if (!(nn = calloc(1, sizeof(struct NameNode))))
return NULL;
if (name)
nn->node.ln_Name = CopyStr(name);
NewList(&nn->children);
if (path)
nn->path = CopyStr(path);
return nn;
}
/* This function finds a particular name in the Names data base, via a
depth-first search. If it finds the name, it returns that node,
otherwise, it returns NULL. */
struct NameNode *FindNode(struct List * lst, char *name)
{
struct Node *n;
struct NameNode *nn;
for (n = lst->lh_Head; n->ln_Succ; n = n->ln_Succ)
{
if (!(stricmp(name, n->ln_Name)))
return (struct NameNode *) n;
if (nn = FindNode(&((struct NameNode *) n)->children, name))
return nn;
}
return NULL;
}
/* Ya, this Token stuff is probably overkill. I'm used to
* using it and I was in a hurry. RWH
*/
typedef USHORT PARSE_TOKEN;
typedef struct Token_Rec
{
char *Key;
short Len;
PARSE_TOKEN Token;
void *User_Data;
} TOKEN_REC;
char * Find_String_Token(TOKEN_REC *keys, PARSE_TOKEN token)
{
char *result = NULL;
while (!result && keys->Key)
{
if (keys->Token == token)
{
result = keys->Key;
}
++keys;
}
return result;
}
PARSE_TOKEN Find_Token_String(TOKEN_REC *key, char *name)
{
PARSE_TOKEN result = 0;
while (!result && key->Key)
{
if (strnicmp(key->Key, name, key->Len) == EQUAL)
{
result = key->Token;
}
++key;
}
return result;
}
private TOKEN_REC Assign_Tokens[] =
{
{
"DEFER", 5, AO_DEFER, NIL
},
{
"ADD", 3, AO_ADD, NIL
},
{
"PATH", 4, AO_PATH, NIL
},
{
NIL, 0, 0, NIL
}
};
/* This is the node assignment routine. It accepts a node name and a path
for assignment. It handles all the proper node creations to add that
information to the node data base. */
void DefNode(char *name, char *path, char *opts)
{
struct NameNode *nn, *parent, *a_node = NIL;
char pardev[100];
short i;
ASSIGN_OPTION ass_opt;
if (opts)
{
ass_opt = Find_Token_String(Assign_Tokens, opts);
}
else
ass_opt = AO_NORMAL;
for (i = 0; path[i] != ':' && i < 99; ++i)
pardev[i] = path[i];
pardev[i] = '\0';
if (!(parent = FindNode(&Names, pardev)))
{
parent = MakeNode(pardev, NULL);
AddHead(&lostnodes->children, (struct Node *) parent );
parent->parent = lostnodes;
}
if (!(nn = FindNode(&Names, name)))
nn = MakeNode(name, path);
else if (ass_opt == AO_ADD)
{
a_node = nn;
nn = MakeNode(name, path);
}
else
{
Remove((struct Node *) nn);
if (nn->path)
FreeStr(nn->path);
nn->path = CopyStr(path);
}
if (nn)
{
nn->Option = ass_opt;
if (ass_opt == AO_ADD && a_node)
Insert(&parent->children, (struct Node *) nn, (struct Node *) a_node);
else
AddHead(&parent->children, (struct Node *) nn);
}
}
/* This function reads in the individual file's data and builds entries
in the name list based on that data. */
void AddFIB(struct FileInfoBlock * fib, char *name)
{
BPTR file;
char *buf, *com, *path, *ptr, *args;
if ( stricmp(&name[strlen(name) - 4], ".bak") == 0 )
return;
if (buf = AllocMem(fib->fib_Size + 1, 0L))
{
if (file = Open(name, MODE_OLDFILE))
{
Read(file, buf, fib->fib_Size);
buf[fib->fib_Size] = '\0';
ptr = buf;
while (*ptr)
{
ptr = stpblk(ptr);
args = NIL;
if (*ptr == '#' || *ptr == '!' || *ptr == ';')
{
ptr = strchr(ptr, '\n');
if (*ptr)
*ptr++;
continue;
}
com = ptr;
while (*ptr && *ptr != ':')
++ptr;
if (*ptr)
*ptr++ = 0;
ptr = stpblk(ptr);
if (*ptr)
{
path = ptr;
while (*ptr > ' ')
++ptr;
if (*ptr == '\n')
{
*ptr++ = 0;
}
else if (*ptr)
{
*ptr++ = 0;
while (*ptr && *ptr <= ' ' && *ptr != '\n')
++ptr;
if (*ptr && *ptr != '\n')
{
ptr = stpblk(ptr);
args = ptr;
while (*ptr > ' ')
++ptr;
if (*ptr)
{
*ptr++ = 0;
}
}
else if (*ptr == '\n')
++ptr;
}
DefNode(com, path, args);
}
if (*ptr == '\n')
++ptr;
}
Close(file);
}
FreeMem(buf, fib->fib_Size + 1);
}
}
/* ====================================================================== */
/* This function opens up the stuff we need. */
BOOL DoInits(void)
{
if (!(DosBase = (struct DosLibrary *) OpenLibrary("dos.library", 36L)))
{
printf("Requires AmigaDOS Version 36 or greater\n");
return FALSE;
}
if (!(info = (struct DosInfo *) BADDR(((struct RootNode *) ((struct DosLibrary *)DosBase)->dl_Root)->rn_Info)))
return FALSE;
return TRUE;
}
/* This function cleans up after DoInits. */
short CloseUp(short code, char *str)
{
if (str)
printf("Error: %s\n", str);
Icon_Finish();
if (DosBase)
{
CloseLibrary((struct Library *) DosBase);
DosBase = NIL;
}
return (code);
}
BOOL Rem_Assign(struct NameNode *nn)
{
BOOL result = FALSE;
struct DeviceList *dev, *lastdev = NIL;
Forbid();
{
/* Let's see if the assignment has already been made... */
for (dev = (struct DeviceList *) BADDR(info->di_DevInfo); dev != NULL;
dev = (struct DeviceList *) BADDR(dev->dl_Next))
{
if (dev->dl_Type != DLT_DIRECTORY
&& dev->dl_Type != DLT_LATE
&& dev->dl_Type != DLT_NONBINDING
)
continue;
if (!strnicmp(nn->node.ln_Name, (char *)BADDR(dev->dl_Name) + 1,
(size_t)*(char *)BADDR(nn->node.ln_Name)))
break;
lastdev = dev;
}
if (dev)
{
/* Remove it from the list */
if (lastdev)
lastdev->dl_Next = dev->dl_Next;
else
info->di_DevInfo = dev->dl_Next;
if (dev->dl_Lock)
{
UnLock(dev->dl_Lock);
dev->dl_Lock = NULL;
}
FreeVec(BADDR(dev->dl_Name));
FreeVec(dev);
}
}
Permit();
return result;
}
BPTR get_lock(char *path)
{
BPTR lock;
lock = Lock(path, (long)SHARED_LOCK);
if (!lock)
{
lock = CreateDir(path);
if (lock)
{
UnLock(lock);
lock = Lock(path, (long)SHARED_LOCK);
}
}
return lock;
}
/* ====================================================================== */
/* This function does the "Assign" operation. */
BOOL Assign(struct NameNode *nn, short flags)
{
BPTR lock;
BOOL result = FALSE;
if (flags & BNF_REMOVE)
{
if (nn->Option == AO_ADD)
{
lock = Lock(nn->path, (long)SHARED_LOCK);
result = RemAssignList(nn->node.ln_Name, lock);
UnLock(lock);
}
else
{
result = Rem_Assign(nn);
}
}
else
{
switch (nn->Option)
{
case AO_NORMAL :
{
lock = get_lock(nn->path);
if (lock)
{
if ( !( result = AssignLock(nn->node.ln_Name, lock) ) )
UnLock(lock);
}
break;
}
case AO_ADD :
{
lock = get_lock(nn->path);
if (lock)
{
if ( !( result = AssignAdd(nn->node.ln_Name, lock) ) )
UnLock(lock);
}
break;
}
case AO_DEFER :
{
result = AssignLate(nn->node.ln_Name, nn->path);
break;
}
case AO_PATH :
{
result = AssignPath(nn->node.ln_Name, nn->path);
break;
}
}
}
return result;
}
/* This list takes in a node list, and performs assignments for all non-primary
nodes in the list, as long as "inhibit" is FALSE. */
void AssignList(struct List * lst, short level, BOOL inhibit, short flags)
{
struct Node *n;
struct NameNode *nn;
for (n = lst->lh_Head; n->ln_Succ; n = n->ln_Succ)
{
nn = (struct NameNode *) n;
if (nn->path)
{
if (!inhibit || (nn->Option == AO_DEFER) )
{
Assign(nn, flags);
}
if ((flags & BNF_VERBOSE) || (inhibit && nn->Option != AO_DEFER ) )
{
char *ptr = Find_String_Token(Assign_Tokens, nn->Option);
if (!ptr)
ptr = "NORMAL";
printf("%*s%-*s %-5s\t%s%s\2330m\n",
level + 1, "\23333m", 20 - level + 1, nn->node.ln_Name,
ptr,
/*14 - level,*/ "\23332m", nn->path);
}
}
if (nn->children.lh_Head->ln_Succ)
AssignList(&nn->children, level + 2, inhibit, flags);
}
}
/* ====================================================================== */
#define PATH_SEPARATOR '/'
char * make_path(char *dest, char *path, char *name)
{
int len;
strcpy (dest, path);
len = strlen(dest)-1;
if (*dest && dest[len] != ':' && dest[len] != PATH_SEPARATOR)
{
dest[len + 1] = PATH_SEPARATOR;
dest[len + 2] = 0;
}
strcat (dest, name);
return dest;
}
/*
* Disable SAS/C CTRL/C handling
*/
private int Break_Func(void)
{
return 0;
}
void _CXBRK(void)
{
}
private short set_sys_node(char *dir)
{
struct NameNode nnode;
short result;
nnode.node.ln_Name = "SYS";
nnode.path = dir;
nnode.Option = AO_NORMAL;
if ( !( result = Assign(&nnode, FALSE) ) )
printf("Can't assign Sys: to `%s'\n", dir);
return result;
}
#define FILE_ARG 0
#define NAMES_ARG 1
#define SYSTEM_ARG 2
#define VERBOSE_ARG 3
#define REMOVE_ARG 4
#define TEST_ARG 5
private ARG_LIST BN_Args[] =
{
{
"FILE", NIL
},
{
"NAMES", NIL
},
{
"SYSTEM", NIL
},
{
"VERBOSE", NIL
},
{
"REMOVE", NIL
},
{
"TEST", NIL
},
{
NIL, NIL /* Null termination */
},
};
int main(int argc, char **argv)
{
static char Names_Path[200] = NAMEDIR;
static char path[256];
short i, flags = 0;
struct NameNode *nn;
struct DeviceList *dev;
BPTR namelock;
onbreak(Break_Func); /* Disable CTRL_x checking */
if (!DoInits())
return CloseUp(5, NULL);
if (argc == 0)
{
if (Icon_Launch(argc, argv, BN_Args, 1))
{
if (BN_Args[FILE_ARG].arg_value)
{
flags |= BNF_ONEFILE;
strcpy(Names_Path, BN_Args[FILE_ARG].arg_value);
}
else if (BN_Args[NAMES_ARG].arg_value)
strcpy(Names_Path, BN_Args[NAMES_ARG].arg_value);
if (BN_Args[SYSTEM_ARG].arg_value)
{
if (!set_sys_node(BN_Args[SYSTEM_ARG].arg_value))
return CloseUp(0, NULL);
}
if (BN_Args[REMOVE_ARG].arg_value)
flags |= BNF_REMOVE;
if (BN_Args[TEST_ARG].arg_value)
flags |= BNF_TEST;
if (BN_Args[VERBOSE_ARG].arg_value)
flags |= BNF_VERBOSE;
}
}
else
{
/* Check the command line. */
for (i = 1; i < argc; ++i)
{
switch (toupper(argv[i][0]))
{
case 'R':
{
flags |= BNF_REMOVE;
break;
}
case 'F':
{
flags |= BNF_ONEFILE;
/**** Fall through to copy name ****/
}
case 'N':
{
strcpy(Names_Path, argv[++i]);
break;
}
case 'S':
{
if (!set_sys_node(argv[++i]))
return CloseUp(0, NULL);
break;
}
case 'T':
{
flags |= BNF_TEST;
/**** Fall through to set verbose mode ****/
}
case 'V':
{
flags |= BNF_VERBOSE;
break;
}
case '?':
{
printf("\n
%s
\n\n", BN_Version + 7);
printf("Usage: %s [F=FILE <name>] [N=NAMES <path>] [S=SYSTEM <path>] [V=VERBOSE] [R=REMOVE] [T=TEST]\n\n", argv[0]);
return CloseUp(0, NULL);
}
}
}
}
if (flags & BNF_VERBOSE)
printf("\n
%s
\n\n", BN_Version + 7);
/*
* Let's build the internal device list. We know this list is going
* to be a flat list; everything is primary, and thus hung from the
* root list.
*/
NewList(&Names);
Forbid();
for (dev = (struct DeviceList *) BADDR(info->di_DevInfo); dev != NULL;
dev = (struct DeviceList *) BADDR(dev->dl_Next))
{
if (!(nn = MakeNode(b2cstr(path, dev->dl_Name), NULL)))
continue;
AddHead(&Names, (struct Node *) nn);
}
Permit();
/*
* I need to build the "lostnodes" node. In order to avoid name
* collisions, I make the name of this node '\0'. We never need to
* search for it by name...
*/
AddTail(&Names, (struct Node *) (lostnodes = MakeNode("\0", NULL)));
/*
* Here I build the list of required assignments by walking through
* the SYS:Names directory, and reading each file.
*/
if ((namelock = Lock(Names_Path, SHARED_LOCK)))
{
struct FileInfoBlock *fileinfo;
if ((fileinfo = AllocMem(sizeof(struct FileInfoBlock), MEMF_PUBLIC)))
{
Examine(namelock, fileinfo);
if (flags & BNF_ONEFILE)
{
AddFIB(fileinfo, Names_Path);
}
else
{
while (ExNext(namelock, fileinfo)
|| IoErr() != ERROR_NO_MORE_ENTRIES)
{
if (fileinfo->fib_DirEntryType > 0)
continue;
make_path(path, Names_Path, fileinfo->fib_FileName);
AddFIB(fileinfo, path);
}
}
FreeMem(fileinfo, sizeof(struct FileInfoBlock));
}
UnLock(namelock);
}
/* Now I've got everything; let's see what's actually here. */
Remove((struct Node *) lostnodes);
if (flags & BNF_VERBOSE)
printf("%s Names:\n", (flags & BNF_REMOVE) ? "Removed" : "Assigned");
AssignList(&Names, 1, flags & BNF_TEST, flags);
if (lostnodes->children.lh_Head->ln_Succ)
{
if (flags & BNF_VERBOSE)
printf("\nWarning: Can't Resolve Names:\n");
AssignList(&lostnodes->children, 1, TRUE, flags);
}
return CloseUp(0, NULL);
}