home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Club Amiga de Montreal - CAM
/
CAM_CD_1.iso
/
files
/
522.lha
/
ccd_v2.0
/
ccd.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-06-09
|
22KB
|
857 lines
#include <stdio.h>
#include <assert.h>
#include <proto/dos.h>
#include <proto/intuition.h>
#include <libraries/dos.h>
#include <libraries/dosextens.h>
#include <exec/memory.h>
#include <exec/types.h>
#include <intuition/intuition.h>
#include "ccd.h"
#include "win.h"
#define GRAPHICS
#define VERSION "2"
#define WINDOWTITLE "ccd v2.0, beta version by Cédric BEUST"
#define CCDCONFIGFILE "ccd:.ccdconfig"
#define WIDTH 640 /* width of the display */
#define HEIGHT 200 /* its height */
#define DELTAX 80 /* # of pixels between two entries */
#define DELTAY 10 /* vertical step */
#define UPPERX 25 /* upper corner where we start to write */
#define UPPERY 7 /* ditto */
#define LINESPERWINDOW 18 /* # of lines displayed */
#define BETWEEN_GADGETS 10 /* # of vert pixels between gadgets */
#define min(a,b) (a < b ? a : b)
#define NEW(v, t) v = (t *) malloc(sizeof(*v))
static char actualdir[128];
struct Window *mainwindow;
struct Screen *mainscreen;
long IntuitionBase;
long GfxBase;
int configlines = 0; /* # of lines in ccdconfig */
int actualline = 1;
int nbvolumes = 0; /* # of volumes found */
int volumesid = 0; /* id of the first Volume gadgets */
USHORT *chippointer = NULL, *chippointer2 = NULL;
struct Tree_t {
struct Tree_t *brother;
struct Tree_t *son; /* could be sister and daughter... */
char name[128];
char fullname[128];
int x;
int line;
} *the_tree = NULL;
int show_ambiguities = 0;
int update_list = 0;
int no_expand = 0;
BPTR locklist[128];
int lockpt = 0;
BPTR
get_a_lock(char *name, long code)
{
locklist[lockpt] = Lock(name, code);
if (locklist[lockpt])
return locklist[lockpt++];
else
return 0;
}
void
unlock(BPTR lock)
{
/*
UnLock(lock);
*/
}
void
free_all_locks()
{
int i;
for (i = 0; i < lockpt; i++)
UnLock(locklist[i]);
}
void
myputs(char *s)
{
Write(Output(), s, strlen(s));
}
void
Read_Dirs(char *dir, FILE *f)
{
BPTR lock;
struct FileInfoBlock info, *fib;
lock = Lock(dir, ACCESS_READ);
if (lock == 0) {
fprintf(stderr,"*** Yup! Couldn't lock %s\n", dir);
return;
}
fib = (struct FileInfoBlock *) Examine(lock, &info);
fib = &info;
while (1) {
if (ExNext(lock, fib) == 0) break;
if (fib -> fib_DirEntryType > 0) {
char t[50],c;
strcpy(t, dir);
if ((c = t[strlen(t) - 1]) != ':' && c != '/')
strcat(t,"/");
strcat(t, fib -> fib_FileName);
fprintf(f, "%s\n", t);
Read_Dirs(t,f);
}
}
unlock(lock);
}
void
Update(char **dirname, int ndirs)
/* Update the config file with the list of dirs (dirname) of length ndirs */
{
FILE *f = fopen(CCDCONFIGFILE,"w");
int i;
if (f == NULL) {
fprintf(stderr, "*** Couldn't open '%s', maybe an assign is missing?\n", CCDCONFIGFILE);
return(0);
}
Put_Version(f);
printf("Updating %s with", CCDCONFIGFILE);
for (i = 0; i < ndirs; i++) {
printf(" %s", *dirname);
fflush(stdout);
fprintf(f, "%s\n", *dirname);
Read_Dirs(*dirname++, f);
}
printf(" -- done!\n");
fclose(f);
}
int
mystricmp(char *bigdir, char *shortdir)
/* Check if shortdir is part of the path bigdir, return 0 if it is */
{
char t[50], *pt = t, *ps;
int end = 0;
int i = 0;
while (*bigdir) {
while (*bigdir && *bigdir != ':' && *bigdir != '/' && *bigdir != '\n')
*pt++ = *bigdir++;
if (*bigdir) bigdir++;
*pt++ = '\0';
pt = t;
}
/* Now, we must see if shortdir is included in t */
for (i = 0; i <= strlen(t) - strlen(shortdir); i++) {
pt = &t[i]; ps = shortdir;
while (*pt && *ps && (*pt | 0x20) == (*ps | 0x20)) {
ps++; pt++;
};
if (*pt == 0 || *ps == 0) return(0); /* match! */
}
return(1);
}
void
Update_Prompt(char *currentdir)
/* Update the concerned field with the new current dir */
/* This routine is for users of wshell or such, thar display this name */
/* as the shell prompt. */
/* This trick was previously pointed to me by Henry J. Cobb on Usenet */
/* for my 'find' program (another great utility of mine :-)). */
/* Let him be thanked again! */
{
struct Process *pr = (struct Process *) FindTask(0L);
struct CommandLineInterface *cli =
(struct CommandLineInterface *) (pr -> pr_CLI) << 2;
char *p = (char *) (cli -> cli_SetName) << 2;
*p++ = strlen(currentdir); /* it is a BSTR, so length first */
while (*currentdir) *p++ = *currentdir++; /* don't add '\0' */
}
int
Check_Version(FILE *f)
{
char v[100];
fscanf(f, "%s\n", v);
if (! isdigit(v[0]) || atoi(v) < atoi(VERSION)) {
printf("*** config file is obsolete for this version, run ccd -u\n");
fclose(f);
exit(0);
}
}
int
Put_Version(FILE *f)
{
fprintf(f, "%s\n", VERSION);
}
char *
locate_dir(char *dir, FILE *f)
/* Return the complete path for the fragment given, if any, in file *f */
{
int match = 0;
static char onedir[100];
while (! feof(f) && ! match) {
int i;
fgets(onedir, 100, f);
i = strlen(onedir) - 1;
if (onedir[i] == '\n')
onedir[i] = '\0'; /* strip trailing \n */
if (mystricmp(onedir, dir) == 0) {
match = 1;
break;
}
}
if (match) return(onedir);
else return(NULL);
}
char *
reverse(char *s)
/* Return the string s backwards (modify s)*/
{
register char c;
char *result = s + strlen(s) - 1, *r2 = s;
while (result > s) {
c = *result;
*result = *s;
*s = c;
s++; result--;
}
return(r2);
}
void
Get_Real_Name(BPTR lock, char *result)
/* This is a very useful function! Put in result path of lock */
/* Assume lock is not null */
/* Result always device:dir/dir/... */
{
char *p = result;
struct FileInfoBlock ib;
assert(lock);
if (no_expand) return;
Examine(lock, &ib);
strcpy(result, reverse(ib.fib_FileName));
strcat(result, "/");
while (lock) {
lock = ParentDir(lock);
if (lock) {
Examine(lock, &ib);
strcat(result, reverse(ib.fib_FileName));
strcat(result,"/");
unlock(lock);
}
}
p = &p[strlen(p) - 1];
*p-- = '\0';
while (*p != '/') p--;
*p = ':';
reverse(result);
}
void
Call_CurrentDir(char *actualdir)
{
BPTR lock;
if (actualdir[0]) {
lock = Lock(actualdir, ACCESS_READ);
if (lock == 0) {
fprintf(stderr,
"*** Couldn't cd to %s, '%s' probably outdated (re-run ccd -u)\n",
actualdir, CCDCONFIGFILE);
exit(0);
}
CurrentDir(lock);
Get_Real_Name(lock, actualdir);
printf("Current directory is now %s\n", actualdir);
Update_Prompt(actualdir);
unlock(lock);
}
else
printf("%s: no such dir\n", actualdir);
}
void
Change_Dir(char *dir, int occ)
/* The main function to change to the fragment of dir given, */
/* to the occ'th occurence found in the config file */
/* New 1.3: first, try to cd right into 'dir' */
{
char cmd[50];
FILE *f = fopen(CCDCONFIGFILE,"r");
int match = 0;
BPTR lock;
Check_Version(f);
strcpy(actualdir, dir);
if ((lock = Lock(actualdir, ACCESS_READ))) { /* can we cd directly? */
BPTR old;
Get_Real_Name(lock, actualdir);
lock = get_a_lock(actualdir, ACCESS_READ);
printf("Current directory is now %s\n", actualdir);
Update_Prompt(actualdir);
old = CurrentDir(lock); /* yes! Do it and end */
/*
UnLock(lock);
UnLock(old);
*/
return;
}
/* no, dir is a path fragment */
if (f == NULL) {
fprintf(stderr,
"*** Couldn't open '%s'; run ccd -u first, will you?\n", CCDCONFIGFILE);
exit(0);
};
while (occ--) {
strcpy(actualdir, locate_dir(dir, f));
}
Call_CurrentDir(actualdir);
fclose(f);
}
void
Show_Ambiguities(char *dir)
{
char *onedir = NULL;
char cmd[50];
FILE *f = fopen(CCDCONFIGFILE,"r");
int match = 0;
if (f == NULL) {
fprintf(stderr,
"*** Couldn't open '%s'; run ccd -u first, will you?\n", CCDCONFIGFILE);
exit(0);
};
Check_Version(f);
while ((onedir = locate_dir(dir, f))) {
myputs(onedir);
myputs("\n");
}
fclose(f);
}
void
Usage()
{
myputs("\nccd v2.0, by
Cedric Beust
(C) 1991\n\n");
myputs("
Usage
:\n");
myputs(" ccd Brings up the graphics display\n");
myputs(" or ccd -u <dir> <dir> ... Rebuild dir list with dirs\n");
myputs(" or ccd -a <partial dir> Show ambiguities\n");
myputs(" or ccd [opt] <partial dir> [n] Change to this dir, nth occurence\n");
myputs(" where opt is one of\n");
myputs(" -n No path expansion\n\n");
exit(0);
}
void
get_vol(char *path, char *vol)
/* String is a line of the .ccdconfig (volume:a/b/c) */
/* Return volume in the variable vol */
{
char *p = path;
while (*p && *p != ':') *vol++ = *p++;
*vol++ = '\0';
}
int
numberofdirs(char *path)
/* path is 'vol:a/b/c' */
/* Return number of dirs in it (3 here), actually = number of '/' + 1 */
{
int result = 0;
while (*path) {
while (*path && *path != '/') path++;
if (*path == '/') {
result++;
path++;
}
}
return(++result);
}
void
nthdir(char *dir, char *path, int n)
/* Path is 'volume:a/b/c' */
/* Return in dir the nth dir in it (e.g. with n=2, it's b) */
{
char *dirhead = dir;
while (*path && *path != ':') path++;
if (*path == ':') {
path++;
while (*path) {
while (*path && *path != '/') {
*dir++ = *path++;
}
if (*(dir - 1) == '\n') dir--;
*dir++ = '\0';
if (*path == '/') path++;
if (n == 1) return;
else {
n--; dir = dirhead;
}
}
}
else {
printf("nthdir: problem\n");
exit(0);
}
}
struct Tree_t *
new_node(char *s, int line, int x, char *fullname)
{
struct Tree_t *newnode;
NEW(newnode, struct Tree_t);
if (s[strlen(s) - 1] == '\n')
s[strlen(s) - 1] = '\0';
strcpy(newnode -> name, s);
strcpy(newnode -> fullname, fullname);
newnode -> brother = NULL;
newnode -> son = NULL;
newnode -> line = line;
newnode -> x = x;
return(newnode);
}
struct Tree_t *
get_line(struct Tree_t *root, int line)
/* Return the struct for line line, searching from root */
{
/*
printf("get_line with %s, %d\n", root->name, line);
*/
if (root) {
if (root -> line == line) return root;
else if (root -> brother) {
if (root -> brother -> line <= line)
return get_line(root -> brother, line);
else
return get_line(root -> son, line);
}
else
return get_line(root -> son, line);
}
return NULL;
}
void
add_node(char *s, struct Tree_t *root, int line)
/* Add the appropriate node to the tree */
/* Assert root != NULL */
/*
dh0: -> dh1: -> dh2:
|
Anews
|
New
*/
{
char vol[30];
char dir[30];
struct Tree_t *newnode;
int i;
int x = UPPERX - DELTAX;
get_vol(s, vol);
assert(root);
while (root -> brother && stricmp(root -> name, vol))
root = root -> brother;
if (strcmp(root -> name, vol)) { /* new vol, must create a new node */
root -> brother = new_node(vol, line, x + DELTAX, s);
newnode = root -> brother;
}
else {
struct Tree_t *t = root;
newnode = root;
}
assert(newnode);
assert(stricmp(newnode -> name, vol) == 0);
/* Now, newnode is a node that contains the volume. Create the path */
for (i = 1; i <= numberofdirs(s); i++) {
x = newnode -> x;
nthdir(dir, s, i);
if (newnode -> son) {
root = newnode -> son; /* get down one level */
/* Search amid the brothers if we have a matching name */
while (root -> brother && stricmp(dir, root -> name)) {
root = root -> brother;
}
if (stricmp(root -> name, dir)) { /* new dir, create new node */
newnode = root -> brother = new_node(dir, line, x + DELTAX, s);
}
else {
newnode = root;
}
}
else { /* no son yet, have to create one */
newnode -> son = new_node(dir, line, x + DELTAX, s);
newnode = newnode -> son;
}
/* Now, newnode is a node that contains how far we've got in the path */
/* Let's go on */
root = newnode;
}
}
struct Tree_t *
Build_Tree()
{
FILE *f;
char string[128];
char currentvol[30];
struct Tree_t *result;
f = fopen(CCDCONFIGFILE, "r");
if (f == NULL) {
fprintf(stderr,
"*** Couldn't open '%s'; run ccd -u first, will you?\n", CCDCONFIGFILE);
exit(0);
};
Check_Version(f);
NEW(result, struct Tree_t);
strcpy(result -> name, "Root");
result -> brother = NULL;
result -> son = NULL;
result -> line = -1;
while (! feof(f)) {
configlines++;
fgets(string, 128, f);
if (string[strlen(string) - 1] == '\n')
string[strlen(string) - 1] = '\0';
add_node(string, result, configlines);
}
return result;
}
void
Find_Dir_Coo(int x, int y, int line)
{
struct Tree_t *root;
root = get_line(the_tree, line + (y / DELTAY) - 1);
Call_CurrentDir(root -> fullname);
}
int
Display_Tree(struct Tree_t *root, int line, int x, int y)
/* Graphically display the tree for the volume 'vol', from the line */
/* line in the ccdconfig file, at coordinates x and y */
/* Return the y coordinate at the end */
{
int len, i;
struct RastPort *rp = mainwindow -> RPort;
int xinit = x;
root = get_line(the_tree, line);
/*
printf("For line %d, found %s\n", line, root -> name);
*/
while (root && y < 200) {
y += 10;
#ifdef GRAPHICS
assert(rp);
Move(rp, root -> x, y);
Text(rp, root -> name, strlen(root -> name));
#endif
y = Display_Tree(root -> son, line + 1, x, y);
root = root -> brother;
}
return y;
}
int
Create_Gadgets()
/* Create the Volumes gadgets. Return the id of the first one */
{
struct Tree_t *t;
struct Gadget *gad = mainwindow -> FirstGadget, *lastgadget = NULL;
struct IntuiText *tex;
int id = 1, result;
int gady = w1Gadget2.TopEdge;
/* First, transfer the gadget imageries into chip ram */
chippointer = (USHORT *)
AllocMem(sizeof(w1ImageData1), MEMF_PUBLIC | MEMF_CHIP);
if (chippointer == 0) {
printf("*** Couldn't allocate in chip mem...\n");
exit(0);
}
memcpy(chippointer, w1ImageData1, sizeof(w1ImageData1));
w1Image1.ImageData = chippointer;
chippointer2 = (USHORT *)
AllocMem(sizeof(w1ImageData2), MEMF_PUBLIC | MEMF_CHIP);
if (chippointer2 == 0) {
printf("*** Couldn't allocate in chip mem...\n");
exit(0);
}
memcpy(chippointer2, w1ImageData2, sizeof(w1ImageData2));
w1Image2.ImageData = chippointer2;
while (gad -> NextGadget) {
gad = gad -> NextGadget;
}
lastgadget = gad;
result = lastgadget -> GadgetID + 1;
id = result;
t = the_tree -> brother;
while (t) {
/* Dynamically create the gadget, using w1Gadget2 as template */
gad = (struct Gadget *) malloc(sizeof(*gad));
memcpy(gad, & w1Gadget2, sizeof(*gad));
gad -> TopEdge = gady;
gady += BETWEEN_GADGETS + w1Gadget2.Height;
gad -> GadgetID = id++;
/* Link the previous gadget to the one we're building up */
if (lastgadget) lastgadget -> NextGadget = gad;
lastgadget = gad;
gad -> NextGadget = NULL;
/* And now create its IntuiText structure, using w1IText1 */
tex = (struct IntuiText *) malloc(sizeof(*tex));
memcpy(tex, & w1IText1, sizeof(*tex));
tex -> IText = (char *) malloc(sizeof(t -> name) + 1);
strcpy(tex -> IText, t -> name);
/* Link the text to the gadget */
gad -> GadgetText = tex;
nbvolumes++;
t = t -> brother;
}
return result;
}
void
Display_Dir(int line)
/* Display the directory of the volume in the window, starting at the */
/* line in the config file */
{
struct Tree_t *t;
char dir[128];
struct Window *w = mainwindow;
struct Gadget *gad = NULL, *lastgadget;
struct IntuiText *tex = NULL;
int gady = w1Gadget2.TopEdge;
int id = 2;
assert(mainwindow);
/* Warning!!! Here, I assume the 1st gadget is the scrollbar, so I */
/* start from the second... */
lastgadget = w -> FirstGadget;
if (! the_tree) the_tree = Build_Tree();
dir[0] = '\0';
actualline = 1;
SetAPen(w -> RPort, 0);
RectFill(w -> RPort, UPPERX, UPPERY + 4, WIDTH - 4, HEIGHT - 2);
SetAPen(w -> RPort, 2);
(void) Display_Tree(the_tree -> brother, line, UPPERX + DELTAX, UPPERY);
}
int
Locate_Vol(char *vol)
/* Return first line where vol (dh0:, dh1:, ...) appears */
{
struct Tree_t *t = the_tree -> brother;
while (t && stricmp(vol, t -> name)) {
t = t -> brother;
}
if (t) return t -> line;
else assert(0);
}
void
Display_Window()
/* Main routine for the graphic display */
{
struct IntuiMessage *message;
long class, code;
int i, fin = 0;
int firstline = 1, previousline = 1;
struct Gadget *g;
struct PropInfo *info;
struct Tree_t *highlight;
IntuitionBase = OpenLibrary("intuition.library", 0);
GfxBase = OpenLibrary("graphics.library", 0);
#ifdef GRAPHICS
mainscreen = OpenScreen(& NewScreenStructure);
LoadRGB4(&mainscreen -> ViewPort, Palette, PaletteColorCount);
w1NewWindowStructure1.Screen = mainscreen;
w1NewWindowStructure1.Title = (char *) malloc(sizeof(WINDOWTITLE));
strcpy(w1NewWindowStructure1.Title, WINDOWTITLE);
w1Gadget1.NextGadget = NULL;
mainwindow = OpenWindow(& w1NewWindowStructure1);
#endif
Display_Dir(1);
#ifdef GRAPHICS
volumesid = Create_Gadgets();
info = (struct PropInfo *) w1Gadget1.SpecialInfo;
info -> VertBody = (0xffff * LINESPERWINDOW) / configlines;
RefreshGadgets(mainwindow -> FirstGadget, mainwindow, NULL);
while (! fin) {
while ((message = (struct IntuiMessage *)
GetMsg(mainwindow -> UserPort))) {
class = message -> Class;
code = message -> Code;
ReplyMsg(message);
switch(class) {
case CLOSEWINDOW:
fin = 1;
break;
case GADGETUP:
g = (struct Gadget *) message -> IAddress;
if (g -> GadgetID >= volumesid) {
firstline = Locate_Vol(g -> GadgetText -> IText);
w1w1Gadget1SInfo.VertPot = (firstline * 0xffff) / configlines;
}
else
firstline = (configlines * w1w1Gadget1SInfo.VertPot) / 0xffff;
/* Take care of trunc problems */
if (firstline == previousline + LINESPERWINDOW + 1 ||
firstline == previousline + LINESPERWINDOW - 1)
firstline = previousline + LINESPERWINDOW;
else
if (firstline == previousline - LINESPERWINDOW + 1 ||
firstline == previousline - LINESPERWINDOW - 1)
firstline = previousline - LINESPERWINDOW;
if (firstline == 0) firstline = 1;
if (firstline > configlines - LINESPERWINDOW - 1)
firstline = configlines - LINESPERWINDOW - 1;
Display_Dir(firstline);
RefreshGadgets(mainwindow -> FirstGadget, mainwindow, NULL);
break;
case GADGETDOWN:
printf("Gadgetdown, class=%d, code=%d\n", class, code);
g = (struct Gadget *) message -> IAddress;
printf("Gadgetdown, gadget id: %d\n", g -> GadgetID);
break;
case MOUSEBUTTONS:
if (message -> MouseX >= UPPERX && message -> MouseY>=UPPERY
&& code == SELECTDOWN) {
Find_Dir_Coo(message -> MouseX, message -> MouseY, firstline);
fin = 1;
}
break;
case MOUSEMOVE:
printf("Mousemove\n");
highlight = get_line(the_tree, firstline + (message -> MouseY / DELTAY) - 1);
SetAPen(mainwindow -> RPort, 1);
Move(mainwindow -> RPort, highlight -> x, message -> MouseY);
Text(mainwindow -> RPort, highlight -> name, strlen(highlight -> name));
break;
default:
printf("Class=%d, Code = %d\n", class, code);
break;
} /* switch class */
} /* while message */
}
if (mainwindow) CloseWindow(mainwindow);
if (mainscreen) CloseScreen(mainscreen);
#endif
}
int
main(int argc, char **argv)
{
int i = 1;
if (argc == 1) {
Display_Window();
exit(0);
}
while (argv[i][0] == '-') {
switch(argv[i][1]) {
case 'u' : /* update config file */
if (argc == i + 1) Usage();
update_list = 1;
break;
case 'a' : /* show ambiguities */
if (argc == i) Usage();
show_ambiguities = 1;
break;
case 'n' :
if (argc == i) Usage();
no_expand = 1;
break;
default :
Usage();
} /* switch */
i++;
} /* while */
if (update_list)
Update(&argv[i], argc - 2);
else if (show_ambiguities) {
printf("Ambiguities for %s\n", argv[i]);
Show_Ambiguities(argv[i]);
}
else
Change_Dir(argv[i], (argc == i + 2 ? atoi(argv[i+1]) : 1));
/*
free_all_locks();
*/
if (chippointer) FreeMem(chippointer, sizeof(w1ImageData1));
if (chippointer2) FreeMem(chippointer2, sizeof(w1ImageData2));
exit(0);
}