home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Club Amiga de Montreal - CAM
/
CAM_CD_1.iso
/
files
/
230.lha
/
BindNames
/
BindNames.c
< prev
next >
Wrap
C/C++ Source or Header
|
1989-04-05
|
11KB
|
364 lines
/* ====================================================================== */
/* BindNames.c by Dave Haynie
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
Where "Name" is the logical name we're assigning, "Path" is the
path name we're making equivalent.
*/
#include <exec/types.h>
#include <exec/memory.h>
#include <libraries/dos.h>
#include <libraries/dosextens.h>
#include <proto/all.h>
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
/* ====================================================================== */
/* Macros */
#define CADDR(x) ((BPTR)(((ULONG)x)>>2))
#define NAMEDIR "SYS:Names"
#define CopyStr(s) strcpy(malloc(strlen(s)+1),s)
#define FreeStr(s) free(s)
/* The "-rr" option doesn't like NewList, bit it's real simple. WHEN can
we have inline functions.... */
#define NewList(l) { (l)->lh_Head = (struct Node *)&(l)->lh_Tail; \
(l)->lh_TailPred = (struct Node *)&(l)->lh_Head; \
(l)->lh_Tail = NULL; \
}
/* ====================================================================== */
/* Global variables */
extern struct DosLibrary *DosBase = NULL;
struct DosInfo *info = NULL;
struct DeviceList *lastdev;
BPTR namelock = NULL;
BOOL verbose = FALSE;
BOOL test = FALSE;
struct FileInfoBlock *fileinfo = NULL;
/* ====================================================================== */
/* 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;
}
/* This function allocates things in a DOS friendly way. */
void *DOSAlloc(LONG size) {
LONG *ptr = AllocMem(size+4,MEMF_PUBLIC|MEMF_CLEAR);
*ptr = size+4;
return ptr+1;
}
/* This function frees memory in a DOS friendly way. */
void DOSFree(void *mem) {
LONG *ptr = (LONG *)mem;
FreeMem(ptr-1,*(ptr-1));
}
/* ====================================================================== */
/* 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. */
struct NameNode {
struct Node node;
struct NameNode *parent;
struct List children;
char *path;
};
struct List Names;
struct NameNode *lostnodes;
/* 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;
}
/* 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) {
struct NameNode *nn, *parent;
char pardev[64];
int i;
for (i = 0; path[i] != ':' && i < 63; ++i) pardev[i] = path[i];
pardev[i] = '\0';
if (!(parent = FindNode(&Names,pardev))) {
AddHead(&lostnodes->children,(struct Node *)(parent=MakeNode(pardev,NULL)));
parent->parent = lostnodes;
}
if (!(nn = FindNode(&Names,name)))
nn = MakeNode(name,path);
else {
Remove((struct Node *)nn);
if (nn->path) FreeStr(nn->path);
nn->path = CopyStr(path);
}
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;
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';
com = strtok(strupr(buf)," :\t\n");
path = strtok(NULL," \t\n");
while (com && path) {
DefNode(com,path);
com = strtok(NULL," :\t\n");
path = strtok(NULL," \t\n");
}
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",33L)))
return FALSE;
if (!(info = (struct DosInfo *)BADDR(((struct RootNode *)DosBase->dl_Root)->rn_Info)))
return FALSE;
if (!(fileinfo = AllocMem(sizeof(struct FileInfoBlock),MEMF_PUBLIC)))
return FALSE;
return TRUE;
}
/* This function cleans up after DoInits. */
void CloseUp(int code, char *str) {
if (str) printf("Error: %s\n",str);
if (fileinfo) FreeMem(fileinfo,sizeof(struct FileInfoBlock));
if (namelock) UnLock(namelock);
if (DosBase) CloseLibrary((struct Library *)DosBase);
exit(code);
}
/* ====================================================================== */
/* This function finds a directory node. It has the side effect of
setting "lastdev" to the last device in the global device list. */
struct DeviceList *AllocDirNode(char *name) {
struct DeviceList *dev, *newdev;
char *str,old[64];
/* 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)) {
lastdev = dev;
if (dev->dl_Type != DLT_DIRECTORY) continue;
b2cstr(old,dev->dl_Name);
if (!stricmp(old,name)) return dev;
}
/* Create the new name structure */
if (!(newdev=DOSAlloc(sizeof(struct DeviceList))) || !(str=DOSAlloc(32L))) {
if (newdev) DOSFree(newdev);
return NULL;
}
newdev->dl_Type = DLT_DIRECTORY;
strcpy(str+1,name);
str[0] = strlen(name);
newdev->dl_Name = CADDR(str);
return newdev;
}
/* This function does the "Assign" operation. */
BOOL Assign(char *name, char *path) {
BPTR block;
struct DeviceList *newdev;
/* Let's verify that the path object is really there. If not, try to make
the thing. */
if (!(block = Lock(path,SHARED_LOCK))) {
if (!(block = CreateDir(path))) return FALSE;
UnLock(block);
if (!(block = Lock(path,SHARED_LOCK))) return FALSE;
}
/* Get a node for this assignment. */
Forbid();
newdev = AllocDirNode(name);
/* Make the assignment */
if (newdev->dl_Lock) {
Permit();
UnLock(newdev->dl_Lock);
newdev->dl_Lock = block;
newdev->dl_Task = ((struct FileLock *)BADDR(block))->fl_Task;
return TRUE;
}
newdev->dl_Lock = block;
newdev->dl_Task = ((struct FileLock *)BADDR(block))->fl_Task;
/* Now link it into the device list. */
newdev->dl_Next = lastdev->dl_Next;
lastdev->dl_Next = CADDR(newdev);
Permit();
return TRUE;
}
/* 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, int level, BOOL inhibit) {
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) Assign(nn->node.ln_Name,nn->path);
if (verbose || inhibit)
printf("%*s%-15s%*s%s\2330m\n",level+1,"\23333m",nn->node.ln_Name,
14-level,"\23332m",nn->path);
}
if (nn->children.lh_Head->ln_Succ)
AssignList(&nn->children,level+2,inhibit);
}
}
/* ====================================================================== */
void main(int argc, char *argv[]) {
char path[256];
long i;
struct NameNode *nn;
struct DeviceList *dev;
if (!DoInits()) CloseUp(5,NULL);
/* Check the command line. */
for (i = 1; i < argc; ++i)
switch (toupper(argv[i][0])) {
case 'S':
Assign("SYS",argv[++i]);
break;
case 'V':
verbose = TRUE;
break;
case 'T':
test = TRUE;
verbose = TRUE;
break;
case '?':
printf("\2337mBindNames V1.0 by Dave Haynie\2330m\n\n");
printf("Usage: %s [VERBOSE] [TEST] [SYSTEM drive]\n",argv[0]);
CloseUp(0,NULL);
}
if (verbose) printf("\2337mBindNames V1.0 by Dave Haynie\2330m\n\n");
/* 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(strupr(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(NAMEDIR,SHARED_LOCK))) {
Examine(namelock,fileinfo);
while (ExNext(namelock,fileinfo) || IoErr() != ERROR_NO_MORE_ENTRIES) {
if (fileinfo->fib_DirEntryType > 0) continue;
strcat(strcat(strcpy(path,NAMEDIR),"/"),fileinfo->fib_FileName);
AddFIB(fileinfo,path);
}
}
/* Now I've got everything; let's see what's actually here. */
Remove((struct Node *)lostnodes);
if (verbose) printf("Assigned Names:\n");
AssignList(&Names,1,test);
if (lostnodes->children.lh_Head->ln_Succ) {
if (verbose) printf("\n");
printf("Warning: Can't Resolve Names:\n");
AssignList(&lostnodes->children,1,TRUE);
}
CloseUp(0,NULL);
}