Created
December 31, 2013 12:34
-
-
Save codemonkey-uk/8196109 to your computer and use it in GitHub Desktop.
TCD is a directory tree browser for DOS PC's, that I wrote as a learning exercise, circa 1994. It was not released at the time, but was used as part of a successful job application. I have made the "TCD" source code public here as a curiosity only. http://thad.frogley.info/portfolio/tcd.html
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* TCD directory tree program T.Frogley '94 */ | |
#include <stdlib.h> | |
#include <string.h> | |
#include <stdio.h> | |
#include <conio.h> | |
#include <dir.h> | |
#include <dos.h> | |
#include <memory.h> | |
/* My defines */ | |
#define arrow_up 72 | |
#define arrow_down 80 | |
#define arrow_left 75 | |
#define arrow_right 77 | |
#define escape 27 | |
#define start_message "TCD [<DRIVE>]\n(c) T.Frogley 1994\n" | |
#define error_message1 "Invalid command line!" | |
#define dot_dot ".." | |
#define controle_msg "KEYS : eXpand, Collapse, arrow keys, Exit, Quit, Search & Remove" | |
#define teststr1 "*A?*B?C" | |
#define teststr2 "DAABCC" | |
char check_arg(int arg_count,char *arg_st); | |
char get_drive(void); | |
void store_crt(void); | |
void restore_crt(void); | |
void loadtree(char *directory,int deepness); | |
void draw_window(int x1,int y1,int x2,int y2); | |
void drawscreen(void); | |
void drawtree(int scroll_pos); | |
void plottree(struct directory_tree *topofscreen); | |
void move_about(struct directory_tree *user_position); | |
void buildpath(char *buffer,struct directory_tree *current_dirpos); | |
struct directory_tree *direcsearch(int scroll_pos); | |
struct directory_tree *findadirectory(char *searchstr,int scroll_pos); | |
struct directory_tree *recursivesearch(struct directory_tree *passedpointer); | |
struct directory_tree *gotodirectory(char *serchstr,int scroll_pos); | |
int intelicomp(char *searchstr,char *teststr); | |
/* Alocate enough memory for if it's a silly video mode */ | |
char video_buffer[80*50]; | |
char current_directory[MAXPATH]; | |
struct text_info ti; | |
int spos,tempint; | |
char buffer[80],stickyoutbit[80],string_store[80]; | |
struct directory_tree | |
{ | |
char directory_name[MAXFILE+MAXEXT]; | |
int open,selected,depth,screen_thingy; | |
struct directory_tree *brother,*sister,*son,*parent; | |
} top_block, *current_dirpos, *temp_dirpointer, *bloody_blood; | |
// An for my next trick, a simple one way linked list of pointers to strings | |
struct strlst | |
{ | |
char *thestring; | |
struct strlst *next; | |
}; | |
void main(int arg_count,char *arg_lst[]) | |
{ | |
/* My variables and procedures and functions */ | |
char v_start_message[] = start_message; | |
char drive,str1[50],str2[50]; | |
/* Title message */ | |
printf("%s",v_start_message); | |
drive=(arg_count==1) ? get_drive() : check_arg(arg_count,arg_lst[1]); | |
if (drive) | |
{ | |
store_crt(); | |
clrscr(); | |
sprintf(top_block.directory_name,"%c:",drive); | |
getcurdir(0,current_directory); | |
printf("%s%s\n",top_block.directory_name,current_directory); | |
current_dirpos=&top_block; | |
printf("Loading directory structure into memory, please wait."); | |
chdir("\\"); | |
loadtree(top_block.directory_name,0); | |
top_block.selected=1; | |
top_block.open=1; | |
drawscreen(); | |
move_about(gotodirectory(current_directory,10)); | |
restore_crt(); | |
} | |
else | |
puts(error_message1); | |
} | |
/* Function returns commandline drive in ASCII, if there was a CL error | |
return a 0 */ | |
char check_arg(int arg_count,char *arg_st) | |
{ | |
int c; | |
c=((strlen(arg_st)==1 || strlen(arg_st)==2) && (arg_count==2)) ? *arg_st : 0; | |
return(c); | |
} | |
/* converts drive from number to letter */ | |
char get_drive() | |
{ | |
register char c; | |
c=getdisk(); | |
c+=65; | |
return(c); | |
} | |
/* Video store and restore */ | |
void store_crt() | |
{ | |
gettextinfo(&ti); | |
gettext(ti.winleft,ti.wintop,ti.winright,ti.winbottom,video_buffer); | |
} | |
void restore_crt() | |
{ | |
puttext(ti.winleft,ti.wintop,ti.winright,ti.winbottom,video_buffer); | |
gotoxy(ti.curx,ti.cury); | |
} | |
/* Load the directory struct into memory */ | |
void loadtree(char *directory,int deepness) | |
{ | |
struct ffblk ffblk; | |
int done; | |
struct directory_tree *temp_parent; | |
current_dirpos->son=(struct directory_tree*)malloc( | |
sizeof(struct directory_tree) | |
); | |
if (current_dirpos->son==NULL) | |
{ | |
printf("No enough memory to read directory structure"); | |
exit(1); | |
} | |
deepness++; | |
temp_parent=current_dirpos; | |
current_dirpos=current_dirpos->son; | |
current_dirpos->parent=temp_parent; | |
current_dirpos->son=NULL; | |
current_dirpos->sister=NULL; | |
current_dirpos->brother=NULL; | |
current_dirpos->open=0; | |
current_dirpos->selected=0; | |
current_dirpos->depth=deepness; | |
strcpy(current_dirpos->directory_name,dot_dot); | |
chdir(directory); | |
done = findfirst("*.*",&ffblk,FA_DIREC); | |
while (!done) | |
{ | |
/* OK! big if statement - it evaluates true when - | |
The file IS a directory | |
and NOT .. OR . | |
clear as mud? */ | |
if ((ffblk.ff_attrib==FA_DIREC) && | |
!((!strcmp(ffblk.ff_name,"..")) || (!strcmp(ffblk.ff_name,".")))) | |
{ | |
current_dirpos->sister=(struct directory_tree*)malloc( | |
sizeof(struct directory_tree) | |
); | |
if (current_dirpos->sister==NULL) | |
{ | |
printf("No enough memory to read directory structure"); | |
exit(1); | |
} | |
temp_dirpointer=current_dirpos; | |
current_dirpos=current_dirpos->sister; | |
current_dirpos->brother=temp_dirpointer; | |
current_dirpos->parent=temp_parent; | |
current_dirpos->sister=NULL; | |
current_dirpos->son=NULL; | |
current_dirpos->open=0; | |
current_dirpos->selected=0; | |
current_dirpos->depth=deepness; | |
strcpy(current_dirpos->directory_name,ffblk.ff_name); | |
} | |
done = findnext(&ffblk); | |
} | |
current_dirpos=current_dirpos->parent; | |
current_dirpos=current_dirpos->son; | |
while (current_dirpos->sister!=NULL) | |
{ | |
current_dirpos=current_dirpos->sister; | |
loadtree(current_dirpos->directory_name,current_dirpos->depth); | |
} | |
chdir(dot_dot); | |
current_dirpos=current_dirpos->parent; | |
} | |
void draw_window(int x1,int y1,int x2,int y2) | |
{ | |
register int x,y; | |
if (x1>x2) | |
{ | |
x=x1; | |
x1=x2; | |
x2=x; | |
} | |
if (y1>y2) | |
{ | |
y=y1; | |
y1=y2; | |
y2=y; | |
} | |
gotoxy(x1,y1); | |
putch(218); | |
gotoxy(x2,y2); | |
putch(217); | |
gotoxy(x2,y1); | |
putch(191); | |
gotoxy(x1,y2); | |
putch(192); | |
for (x=x1+1;x!=x2;x++) | |
{ | |
gotoxy(x,y1); | |
putch(196); | |
gotoxy(x,y2); | |
putch(196); | |
} | |
for (y=y1+1;y!=y2;y++) | |
{ | |
gotoxy(x1,y); | |
putch(179); | |
gotoxy(x2,y); | |
putch(179); | |
} | |
} | |
void drawscreen() | |
{ | |
clrscr(); | |
draw_window(1,1,80,21); | |
draw_window(1,22,80,24); | |
gotoxy((80-strlen(controle_msg)) / 2,23); | |
printf(controle_msg); | |
draw_window(1,22,80,24); | |
gotoxy((80-strlen(controle_msg)) / 2,23); | |
printf(controle_msg); | |
} | |
void drawtree(int scroll_pos) | |
{ | |
int i; | |
stickyoutbit[0]=0; | |
buffer[0]=0; | |
spos=scroll_pos; | |
for (i=2;i<spos;i++) | |
{ | |
gotoxy(2,i); | |
clreol(); | |
gotoxy(80,i); | |
putch('�'); | |
} | |
plottree(&top_block); | |
for (i=spos;i<21;i++) | |
{ | |
gotoxy(2,i); | |
clreol(); | |
gotoxy(80,i); | |
putch('�'); | |
} | |
if (scroll_pos<2) | |
{ | |
gotoxy(1,1); | |
puts("�More�������������������������������������������������������������������������Ŀ"); | |
} | |
else | |
{ | |
gotoxy(2,scroll_pos-1); | |
textbackground(0); | |
cputs(" "); | |
gotoxy(1,1); | |
puts("������������������������������������������������������������������������������Ŀ"); | |
} | |
} | |
void plottree(struct directory_tree *topofscreen) | |
{ | |
if ((spos>1) && (spos<21)) | |
{ | |
gotoxy(2,spos); | |
clreol(); | |
if (current_dirpos->depth>0) | |
{ | |
printf(stickyoutbit); | |
if (current_dirpos->sister==NULL) | |
putch(192); | |
else | |
putch(195); | |
if (current_dirpos->selected) | |
textbackground(1); | |
cprintf("��Ŀ%s\n",current_dirpos->directory_name); | |
textbackground(0); | |
gotoxy(80,spos); | |
putch('�'); | |
} | |
else | |
{ | |
if (current_dirpos->selected) | |
textbackground(1); | |
cprintf("%s\n",current_dirpos->directory_name); | |
textbackground(0); | |
gotoxy(80,spos); | |
putch('�'); | |
} | |
} | |
if (current_dirpos->depth>0) | |
if (current_dirpos->sister==NULL) | |
sprintf(buffer,"%s ",stickyoutbit); | |
else | |
sprintf(buffer,"%s� ",stickyoutbit); | |
strcpy(stickyoutbit,buffer); | |
current_dirpos->screen_thingy=spos++; | |
current_dirpos=topofscreen->son; | |
while (current_dirpos->sister!=NULL) | |
{ | |
current_dirpos=current_dirpos->sister; | |
if ((current_dirpos->son->sister!=NULL) && (current_dirpos->open)) | |
plottree(current_dirpos); | |
else | |
{ | |
if ((spos>1) && (spos<21)) | |
{ | |
gotoxy(2,spos); | |
clreol(); | |
printf(stickyoutbit); | |
if (current_dirpos->sister==NULL) | |
putch(192); | |
else | |
putch(195); | |
if (current_dirpos->selected) | |
textbackground(1); | |
if (current_dirpos->son->sister!=NULL) | |
cprintf("���>%s\n",current_dirpos->directory_name); | |
else | |
cprintf("����%s\n",current_dirpos->directory_name); | |
textbackground(0); | |
gotoxy(80,spos); | |
putch('�'); | |
} | |
current_dirpos->screen_thingy=spos++; | |
} | |
} | |
if (spos>20) | |
{ | |
gotoxy(2,21); | |
puts("More�������"); | |
} | |
else | |
{ | |
gotoxy(2,21); | |
puts("End of tree"); | |
gotoxy(2,spos); | |
clreol(); | |
gotoxy(80,spos); | |
putch('�'); | |
} | |
current_dirpos=current_dirpos->parent; | |
if (strlen(stickyoutbit)>3) | |
stickyoutbit[strlen(stickyoutbit)-4]=0; | |
} | |
void move_about(struct directory_tree *user_position) | |
{ | |
char strbuff[MAXPATH]; | |
int key_pressed=1; | |
int scroll_pos=tempint; | |
while (key_pressed!=escape) | |
{ | |
key_pressed=getch(); | |
if (!key_pressed) | |
switch (getch()) | |
{ | |
case arrow_left: | |
if (user_position!=&top_block) | |
{ | |
scroll_pos=scroll_pos+(user_position->screen_thingy); | |
user_position->selected=0; | |
user_position=user_position->parent; | |
scroll_pos=scroll_pos-(user_position->screen_thingy); | |
user_position->selected=1; | |
drawtree(scroll_pos); | |
} | |
break; | |
case arrow_right: | |
if ((user_position->son->sister!=NULL) && (user_position->open)) | |
{ | |
scroll_pos=scroll_pos+(user_position->screen_thingy); | |
user_position->selected=0; | |
user_position=user_position->son; | |
user_position=user_position->sister; | |
scroll_pos=scroll_pos-(user_position->screen_thingy); | |
user_position->selected=1; | |
drawtree(scroll_pos); | |
} | |
break; | |
case arrow_down: | |
if (user_position->sister!=NULL) | |
{ | |
scroll_pos=scroll_pos+(user_position->screen_thingy); | |
user_position->selected=0; | |
user_position=user_position->sister; | |
scroll_pos=scroll_pos-(user_position->screen_thingy); | |
user_position->selected=1; | |
drawtree(scroll_pos); | |
} | |
break; | |
case arrow_up: | |
if ((user_position->brother->brother!=NULL) && (user_position!=&top_block)) | |
{ | |
scroll_pos=scroll_pos+(user_position->screen_thingy); | |
user_position->selected=0; | |
user_position=user_position->brother; | |
scroll_pos=scroll_pos-(user_position->screen_thingy); | |
user_position->selected=1; | |
drawtree(scroll_pos); | |
} | |
break; | |
default:; | |
} | |
else | |
switch (key_pressed) | |
{ | |
case 'e': | |
case 'E': | |
{ | |
buildpath(strbuff,user_position); | |
chdir(strbuff); | |
key_pressed=escape; | |
break; | |
} | |
case 'q': | |
case 'Q': | |
{ | |
chdir(current_directory); | |
key_pressed=escape; | |
break; | |
} | |
case 'c': | |
case 'C': | |
{ | |
user_position->open=0; | |
drawtree(scroll_pos); | |
break; | |
} | |
case 'x': | |
case 'X': | |
{ | |
user_position->open=1; | |
drawtree(scroll_pos); | |
break; | |
} | |
case 's': | |
case 'S': | |
{ | |
user_position->selected=0; | |
user_position=direcsearch(scroll_pos); | |
top_block.open=1; | |
scroll_pos=tempint; | |
user_position->selected=1; | |
drawscreen(); | |
drawtree(scroll_pos); | |
break; | |
} | |
case 'r': | |
case 'R': | |
{ | |
buildpath(strbuff,user_position->parent); | |
chdir(strbuff); | |
if (rmdir(user_position->directory_name)) | |
{ | |
draw_window(10,9,70,11); | |
gotoxy(11,10); | |
textbackground(0); | |
puts("Directory is write protected, or not empty, press any key."); | |
getch(); | |
drawtree(scroll_pos); | |
} | |
else | |
{ | |
scroll_pos=scroll_pos+(user_position->screen_thingy); | |
user_position->sister->brother=user_position->brother; | |
user_position->brother->sister=user_position->sister; | |
temp_dirpointer=user_position->parent; | |
free(user_position); | |
user_position=temp_dirpointer; | |
scroll_pos=scroll_pos-(user_position->screen_thingy); | |
user_position->selected=1; | |
drawtree(scroll_pos); | |
} | |
chdir("\\"); | |
break; | |
} | |
default:; | |
} | |
} | |
} | |
void buildpath(char *buffer,struct directory_tree *current_dirpos) | |
{ | |
char tempstr[MAXPATH]="",buff[MAXPATH]=""; | |
while((current_dirpos!=&top_block)) | |
{ | |
strcpy(buff,current_dirpos->directory_name); | |
strcat(tempstr,strrev(buff)); | |
strcat(tempstr,"\\"); | |
current_dirpos=current_dirpos->parent; | |
} | |
strcpy(buffer,top_block.directory_name); | |
strcat(buffer,strrev(tempstr)); | |
} | |
struct directory_tree *direcsearch(int scroll_pos) | |
{ | |
char searchpath[MAXPATH]; | |
char key_pressed=0; | |
struct directory_tree *tempointer; | |
draw_window(10,9,70,11); | |
gotoxy(11,10); | |
textbackground(0); | |
puts("Enter path :"); | |
gotoxy(25,10); | |
scanf("%66s",searchpath); | |
strupr(searchpath); | |
gotoxy(11,10); | |
puts(" Press (P) for a path search, of (G) for a general search "); | |
while (key_pressed!='P' && key_pressed!='G') | |
{ | |
key_pressed=getch(); | |
if (key_pressed=='p') | |
key_pressed='P'; | |
if (key_pressed=='g') | |
key_pressed='G'; | |
} | |
if (key_pressed=='P') | |
{ | |
gotoxy(11,10); | |
puts(" Performing path search, as requested "); | |
tempointer=gotodirectory(searchpath,10); | |
} | |
else | |
{ | |
tempointer=findadirectory(searchpath,scroll_pos); | |
} | |
return(tempointer); | |
} | |
char *wstr,gotkey; | |
struct strlst topoflist,*stringlist; | |
int result_scroll=10,done=0,scrolpos,cont=1; | |
struct directory_tree *user_position,*resultstore; | |
struct directory_tree *findadirectory(char *searchstr,int scroll_pos) | |
{ | |
result_scroll=10; | |
done=0; | |
cont=1; | |
scrolpos=10; | |
resultstore=user_position=&top_block; | |
user_position=user_position->son; | |
user_position=user_position->sister; | |
drawtree(scrolpos); | |
strcpy(string_store,searchstr); | |
tempint=scroll_pos; | |
recursivesearch(&top_block); | |
tempint=scrolpos; | |
drawtree(scrolpos); | |
return(user_position); | |
} | |
struct directory_tree *recursivesearch(struct directory_tree *passedpointer) | |
{ | |
if (cont) | |
{ | |
passedpointer->open=1; | |
drawtree(scrolpos); | |
current_dirpos=passedpointer->son; | |
while (current_dirpos->sister!=NULL) | |
{ | |
current_dirpos=current_dirpos->sister; | |
if (intelicomp(string_store,current_dirpos->directory_name)) | |
{ | |
if (done) | |
{ | |
draw_window(10,7,70,9); | |
gotoxy(11,8); | |
textbackground(0); | |
puts("There is more than one matching directory, Stop/Continue ."); | |
gotkey=' '; | |
while (gotkey!='C' && gotkey!='c' && gotkey!='S' && gotkey!='s') | |
gotkey=getch(); | |
if (gotkey=='C' || gotkey=='c') | |
{ | |
scrolpos=scrolpos+(user_position->screen_thingy); | |
user_position=current_dirpos; | |
user_position->selected=1; | |
scrolpos=scrolpos-(user_position->screen_thingy); | |
} | |
else | |
{ | |
cont=0; | |
} | |
} | |
else | |
{ | |
scrolpos=scrolpos+(user_position->screen_thingy); | |
user_position=current_dirpos; | |
user_position->selected=1; | |
scrolpos=scrolpos-(user_position->screen_thingy); | |
done=1; | |
} | |
} | |
if (current_dirpos->son->sister!=NULL) | |
recursivesearch(current_dirpos); | |
} | |
} | |
current_dirpos=current_dirpos->parent; | |
return(current_dirpos); | |
} | |
struct directory_tree *gotodirectory(char *serchstr,int scroll_pos) | |
{ | |
char *wstr; | |
struct strlst topoflist,*stringlist; | |
int result_scroll=10; | |
struct directory_tree *user_position,*resultstore; | |
resultstore=user_position=&top_block; | |
user_position=user_position->son; | |
user_position=user_position->sister; | |
/* The first part will be to strip the drive and colon ect */ | |
if (strchr(serchstr,':')!=NULL) | |
{ | |
wstr=strchr(serchstr,':'); | |
wstr++; | |
} | |
else | |
{ | |
wstr=serchstr; | |
} | |
if (*wstr=='\\') | |
wstr++; | |
/* Then I have to split the string into it's individual directorys */ | |
topoflist.thestring=wstr; | |
topoflist.next=NULL; | |
stringlist=&topoflist; | |
while (*wstr!=NULL) | |
{ | |
while (*wstr!=NULL && *wstr!='\\') | |
wstr++; | |
if (*wstr=='\\') | |
{ | |
*wstr=NULL; | |
wstr++; | |
stringlist->next=(struct strlst*)malloc( | |
sizeof(struct strlst)); | |
stringlist=stringlist->next; | |
stringlist->thestring=wstr; | |
stringlist->next=NULL; | |
} | |
} | |
stringlist=&topoflist; | |
if (*(stringlist->thestring)) | |
{ | |
while (stringlist!=NULL) | |
{ | |
gotoxy(1,1); | |
printf("Searching for %s",stringlist->thestring); | |
if (intelicomp(stringlist->thestring,user_position->directory_name)) | |
{ | |
resultstore->selected=0; | |
resultstore=user_position; | |
result_scroll=scroll_pos; | |
user_position->open=1; | |
stringlist=stringlist->next; | |
drawtree(scroll_pos); | |
if (user_position->son->sister!=NULL) | |
{ | |
scroll_pos=scroll_pos+(user_position->screen_thingy); | |
user_position=user_position->son; | |
user_position=user_position->sister; | |
scroll_pos=scroll_pos-(user_position->screen_thingy); | |
drawtree(scroll_pos); | |
} | |
} | |
else | |
{ | |
user_position->selected=0; | |
if (user_position->sister!=NULL) | |
{ | |
user_position=user_position->sister; | |
scroll_pos--; | |
} | |
else | |
stringlist=stringlist->next; | |
user_position->selected=1; | |
drawtree(scroll_pos); | |
} | |
} | |
user_position->selected=0; | |
resultstore->selected=1; | |
resultstore->open=0; | |
} | |
drawtree(result_scroll); | |
tempint=result_scroll; | |
return(resultstore); | |
} | |
int intelicomp(char *searchstr,char *teststr) | |
{ | |
char *laststar=NULL; | |
char *lastthing=NULL; | |
int notfinished=1,itsallalright=1; | |
/* Compaire the to using the * and ? markers by ... */ | |
while (notfinished && itsallalright) | |
{ | |
if (*searchstr==*teststr) | |
{ | |
searchstr++; | |
teststr++; | |
} | |
if (*searchstr!='?') | |
{ | |
if (*searchstr=='*') | |
{ | |
lastthing=teststr; | |
searchstr++; | |
laststar=searchstr; | |
} | |
if (*searchstr!=*teststr) | |
{ | |
if (laststar!=NULL) | |
{ | |
searchstr=laststar; | |
lastthing++; | |
teststr=lastthing; | |
} | |
else | |
itsallalright=0; | |
} | |
} | |
else | |
{ | |
searchstr++; | |
teststr++; | |
} | |
notfinished=(*teststr && *searchstr); | |
} | |
if (*searchstr==NULL && *teststr!=NULL) | |
if (*(searchstr-1)!='*') | |
itsallalright=0; | |
if (*searchstr!=NULL && *teststr==NULL) | |
itsallalright=0; | |
return(itsallalright); /* 0 = fail, 1 = match */ | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment