Skip to content

Instantly share code, notes, and snippets.

@codemonkey-uk
Created December 31, 2013 12:34
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save codemonkey-uk/8196109 to your computer and use it in GitHub Desktop.
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
/* 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