Category : C Source Code
Archive   : TC-MENU.ZIP
Filename : TC-MENU.C

 
Output of file : TC-MENU.C contained in archive : TC-MENU.ZIP
/*
** TC-MENU.C
**
** Turbo C version of James Pinson's Lattice C program PULLDOWN.C
**
** I edited his program to suit my indentation style, cleaned up the
** code in a few places, and made adjustments for Turbo C.
**
** Compile with tcc -K tc-menu
** or in TC with O/C/C/Default char type...Unsigned
** Ignore the three compiler warnings.
**
** If you get snow on your monitor, type in tc-menu s to prevent
** the program from using direct screen writes.
**
** -- Scott Houck
*/

#include
#include
#include
#include
#include

#define BLACK 0 /* These are for color cards */
#define BLUE 1
#define GREEN 2
#define CYAN 3
#define RED 4
#define MAGENTA 5
#define BROWN 6
#define WHITE 7
#define L_BLUE 9 /* Light-blue foreground only */
#define L_GREEN 10 /* Light-green foreground only */
#define YELLOW 14
#define IWHITE 15 /* Intense-white foreground only */

#define UNDERLINE 1 /* These are for monochrome cards */
#define NORMAL 7
#define HI_INTEN 15
#define REVERSE 112

#define TRUE 1
#define FALSE 0

unsigned int page; /* extern decl. for functions */
unsigned int attribute;
unsigned int mon_type;
char wrt_meth = 'f';

#define NU_MAIN 5 /* number of main menu options */
#define NU_SUB 5 /* number of sub menu options */

int menu();
int pull_down();
void make_help();
void make_inst();
void mono_help();
void demo();
void help();
void gotoxy();
int wherexy();
void d_page();
void win_save();
int set_color();
void clear_window();
void box();
int what_mon();
void cls();
void make_window();
int cursor();
void print();
void dos_prt();
void fast_write();
int get_key();


struct menu_str /* change this if you need more options */
{
char *head;
char *body[NU_SUB];
void (*fun1)();
void (*fun2)();
void (*fun3)();
void (*fun4)();
void (*fun5)();
};


/*-----------*/
/* M A I N */
/*-----------*/

main(argc, argv)
int argc;
char **argv;
{
extern unsigned int page;
extern unsigned int attribute;
extern unsigned int mon_type;

int hi_attr, nor_attr;

static struct menu_str m_menu[NU_MAIN] =
{
" File ", /* The first menu option */
" Dir ", /* Menu sub options */
" Load ",
" Save ",
" dElete ",
" Path ",
demo, /* The functions each sub-option call */
demo,
demo, /* these all call the same fake function */
demo,
demo,

" fiNd ", /* The second menu option */
" All-words ",
" First-word ",
"\0",
"\0", /* space filler for unused option names */
"\0",
demo,
demo,
0, /* unused function pointer */
0,
0,

" Configure ", /* The third option */
" Modem ",
" Screen ",
" Printer ",
"\0",
"\0",
demo,
demo,
demo,
0,
0,

" Output ", /* The fourth menu option */
" Screen ",
" Printer ",
" Disk ",
" Modem ",
"\0",
demo,
demo,
demo,
demo,
0,


" Help ", /* The fifth option */
" Instant help (really works) ",
"\0",
"\0",
"\0",
"\0",
help,
0,
0,
0,
0,
};


/* was a slow write requested? */
if (tolower(*argv[1]) == 's')
wrt_meth = 's';

page = 0;
mon_type = what_mon();

if (mon_type == 1) /* Find out if you have a color card */
{
hi_attr = set_color(BLACK, CYAN); /* and set attributes accordingly */
nor_attr = set_color(WHITE, BLACK);
}
else
{
hi_attr = REVERSE;
nor_attr = NORMAL;
}

attribute = nor_attr;
cursor(0); /* hide cursor */
win_save('s');
cls();

if (mon_type == 1)
make_help();

make_inst(); /* Show instructions */

menu(m_menu, NU_MAIN, NU_SUB, hi_attr, nor_attr);

win_save('r'); /* restore text display*/
cursor(1); /* restore cursor */
}


/*-----------*/
/* M E N U */
/*-----------*/

int menu(m_menu, nu_main, nu_sub, hi_attr, nor_attr)
struct menu_str m_menu[];
int nu_main, nu_sub, hi_attr, nor_attr;
{
extern unsigned int page;
extern unsigned int attribute;
extern unsigned int mon_type;

int i, j, cur_x, cur_y, cur_opt, found, expert = 1;
char ch, ext, ltr;

ch = ' ';
ext = ' ';
cur_opt = 0;
found = 0;

if (mon_type == 1)
attribute = set_color(YELLOW, BLACK);
else
attribute = nor_attr;

make_window(1, 1, 78, 1, 1);

for (;;) /* endless loop */
{
for (i = 0; i < nu_main; i++)
{
j = 0;
while (ltr = m_menu[i].head[j++])
{
if (ch == ltr && ch != ' ')
{
found = TRUE;
cur_opt = i;
}
}
}
if (ch == 13)
{
found = TRUE;
expert = FALSE;
}

ch = ' ';
cur_x = 2;
cur_y = 2;

for (i = 0; i < nu_main; i++)
{
if (i == cur_opt)
attribute = hi_attr;
else
attribute= nor_attr;
print(cur_x, cur_y, m_menu[i].head);
cur_x += strlen(m_menu[i].head) + 3;
}

if (!expert)
found = TRUE;

if (found)
{
ext = pull_down(m_menu, nu_sub, cur_opt); /* pull-down options */
if (ext == 27)
expert = TRUE;
if (ext == 'r' || ext == 'l')
expert = FALSE;
if (ext == 'r')
++cur_opt;
if (ext == 'l')
--cur_opt;
ch = ' ';
ext = ' ';
}

if (!found)
{
ch = ' ';
get_key(&ch, &ext);
ch = toupper(ch);
}

if (ch == 27)
return;

if (ext == 'r' || ext == 'l')
expert = 0;
if (ext == 'r')
++cur_opt;
if (ext == 'l')
--cur_opt;
if (cur_opt >= nu_main)
cur_opt = 0;
if (cur_opt < 0)
cur_opt = nu_main - 1;
ext = ' ';
found = 0;

} /* end for (;;) */
}



/*---------------------*/
/* P U L L _ D O W N */
/*---------------------*/

int pull_down(m_menu, nu_sub, position)
struct menu_str m_menu[];
int position;
{
extern unsigned int page;
extern unsigned int attribute;
char ch = ' ', ltr;
int ext = ' ', hi_attr, nor_attr;
int i, j, tx, ty, start, width, nu_opt, cur_opt = 0, found = FALSE;

nu_opt = nu_sub;

/* nu_sub = number of possible pull-down options */
/* find out how many are in use */

for (i = 0; i < nu_opt; i++)
{
if (m_menu[position].body[i][0] == '\0')
{
nu_opt = i;
break;
}
}

if (mon_type == 1)
{
hi_attr = set_color(BLACK, CYAN);
nor_attr = set_color(WHITE, BLACK);
}
else
{
hi_attr = REVERSE;
nor_attr = NORMAL;
}

attribute = nor_attr;

start = 2; /* Figure where to draw pull-down box */
/* 2 is column to start 1st box */
/* Add up length of menu heads */

for (i = 0; i < position; i++)
start += strlen(m_menu[i].head) + 3;

width = 0; /* figure max length of window */

for (i = 0; i < nu_opt; i++)
if (strlen(m_menu[position].body[i]) > width)
width = strlen(m_menu[position].body[i]);

/* move box to left if it will spill off right side */

if (start + width + 1 > 80)
start = 80 - width - 2;

win_save('s');

if (mon_type == 1)
attribute = set_color(YELLOW, BLACK);

make_window(start++, 3, width, nu_opt, 0); /*make a window */
attribute = nor_attr;

tx = start; /* reposition for writing */
ty = 4;

for (;;)
{
for (i = 0; i < nu_opt; i++)
{
if (i == cur_opt)
attribute = hi_attr;
else
attribute = nor_attr;
print(tx, ty++, m_menu[position].body[i]);
}

attribute = nor_attr;

if (found)
{
win_save('r'); /* remove box */

/* If you want more than 5 menu options */
/* change this next switch statement */

switch(cur_opt) /* call function */
{
case 0: (*m_menu[position].fun1)(); break;
case 1: (*m_menu[position].fun2)(); break;
case 2: (*m_menu[position].fun3)(); break;
case 3: (*m_menu[position].fun4)(); break;
case 4: (*m_menu[position].fun5)(); break;
}

/* found = FALSE; */
if (kbhit())
getch(); /* make sure keyboard buffer is clear */
return(' ');
}

tx = start;
ty = 4;
get_key(&ch, &ext); /* get a character */
ch = toupper(ch);
if (ext == 'd')
++cur_opt;
if (ext == 'u')
--cur_opt;
if (cur_opt >= nu_opt)
cur_opt = 0;
if (cur_opt < 0)
cur_opt = nu_opt - 1;

if (ch == 13)
found = TRUE;

for (i = 0; i < nu_opt; i++) /* does it match an option? */
{
j = 0;
while (ltr = m_menu[position].body[i][j++])
{
if (ch == ltr)
{
cur_opt = i;
found = TRUE;
}
}
}

if (ext == 'l'|| ext == 'r')
break;

if (ch == 27) /* EXIT IF ESCAPE KEY */
{
ext = ch;
break;
}

ext = ' ';
ch = ' ';

} /* end for (;;) */

win_save('r');
return (ext);
}


/*---------------------*/
/* M A K E _ H E L P */
/*---------------------*/

void make_help()
{
extern unsigned int page, attribute;

page = 1;

print( 1, 1, "Hello - This is a sample of an instant help screen.");
print(10, 5, "This screen was printed to the second page of graphics");
print(10, 7, "while you were looking at the main menu.");
print(10, 9, "This help screen can be left undisturbed");
print(10, 11, "and redisplayed at any time.");
print( 1, 20, "Please touch any key to return to the main menu.");

page = 0;
}


/*---------------------*/
/* M A K E _ I N S T */
/*---------------------*/

void make_inst()
{
extern unsigned int attribute;

if (mon_type == 1)
attribute = set_color(GREEN, BLACK);
else
attribute = NORMAL;

print( 1, 4, "INSTRUCTIONS:");
print( 1, 6, "EXPERT MODE: Select by touching the key which represents each option.");
print(15, 7, "(the capital letter)");

print( 1, 10, "ASSIST MODE: Pull-down menu by touching 'enter' or a cursor key.");
print(14, 11, "Select by highlighting with cursor keys- then touch return");
print(14, 13, "Return to Expert mode by touching 'escape'");

print( 1, 15, "EXIT: Touch 'Escape' while in expert mode.");
}


/*---------------------*/
/* M O N O _ H E L P */
/*---------------------*/

void mono_help()
{
attribute = NORMAL;
win_save('s');

clear_window(1, 4, 80, 21);
print(1, 7, "This is a demonstration of a help screen.");
print(1, 9, "This text was written by means of direct memory address.");
print(1, 10, "The original screen has been saved and will be restored ");
print(1, 11, "when you exit this 'help' screen.");
print(1, 14, "Please touch any key to continue.");

getch();
win_save('r');
}


/*-----------*/
/* D E M O */
/*-----------*/

void demo()
{
win_save('s');
make_window(20, 10, 40, 5, 1);

print(21, 11, "Put your favorite routine here ");
print(21, 14, "touch any key to return to menu");
getch();

win_save('r');
}


/*-----------*/
/* H E L P */
/*-----------*/

void help()
{
if (mon_type == 1) /* If color card flip page to */
{
page = 1; /* Show text else write to current screen */
d_page();
getch();
page = 0;
d_page();
}
else
mono_help();
}


/* Screen Function Library */

/*
** Declare the extern variables page, attribute, and
** mon_type (monitor type) in your main program.
*/


/*---------------*/
/* G O T O X Y */
/*---------------*/

void gotoxy(x, y) /* Puts cursor at x,y position on selected page */
unsigned int x, y; /* 1,1 is upper left corner */
{
extern unsigned int page;
union REGS regist;

if (x < 1 || x > 80)
return;
if (y < 1 || y > 25)
return;
--x;
--y; /* BIOS starts coordinates at 0,0 */

regist.h.ah = 0x02;
regist.x.dx = (y << 8) | x;
regist.h.bh = page;
int86(0x10, ®ist, ®ist);
}


/*-----------------*/
/* W H E R E X Y */
/*-----------------*/

int wherexy(x, y) /* Returns the x,y position of cursor */
int *x, *y;
{
extern unsigned int page;
union REGS regist;

regist.h.ah = 0x03;
regist.h.bh = page;
int86(0x10, ®ist, ®ist);
*x = regist.h.dl + 1;
*y = regist.h.dh + 1;
}


/*---------------*/
/* D _ P A G E */
/*---------------*/

/* Displays the page indicated by extern var page */
/* Use only with color card */

void d_page()
{
extern unsigned int page;
union REGS regist;

regist.h.ah = 0x05;
regist.h.al = page;
int86(0x10, ®ist,®ist);
}


/*-------------------*/
/* W I N _ S A V E */
/*-------------------*/

void win_save(action) /* Saves or restores primary */
int action; /* display screen. */
{ /* (page 0 for color display) */
extern unsigned int page; /* 's' = save */
extern unsigned int mon_type; /* 'r' = restore */
int position; /* Saves cursor position too */
static int ptr; /* May make snow on CGA */

static struct
{
int x;
int y;
unsigned int buffer[4000];
}
window[2];


if (mon_type == 1)
position = 0xB800; /* Color card */
else
position = 0xB000; /* Monochrome */

if (action == 's') /* save */
{
if (ptr > 1)
{
ptr = 2;
return;
}

/*
** Note: I used movedata because the peek function is specific
** to Lattice C.
**
** peek(position, 0x00, &window[ptr].buffer, 4000);
**
** Also see poke below.
*/

/* save screen */
movedata(position, 0, _DS, (int)&window[ptr].buffer, 4000);

/* save cursor location */
wherexy(&window[ptr].x, &window[ptr].y);
ptr++;
}

if (action == 'r') /* restore */
{
if (ptr < 1)
{
ptr = 0;
return;
}
--ptr;

/* poke(position, 0, &window[ptr].buffer, 4000); */

/* restore screen */
movedata(_DS, (int)&window[ptr].buffer, position, 0, 4000);

/* restore cursor location */
gotoxy(window[ptr].x, window[ptr].y);
}
}



/*---------------------*/
/* S E T _ C O L O R */
/*---------------------*/

/* Call with foreground and background colors. Returns attribute. */

int set_color(foreground, background)
int foreground,background;
{
return (background << 4 | foreground);
}



/*---------------------------*/
/* C L E A R _ W I N D O W */
/*---------------------------*/

void clear_window(x, y, width, height) /* Call with x,y of upper left */
unsigned int x, y, width, height; /* corner of window area. */
{ /* Clears down and to right */
extern unsigned int page; /* for width and height. */
extern unsigned int attribute; /* Cleared with active attribute */
union REGS regist; /* Use on displayed page only! */

regist.x.ax = 0x0600;
regist.h.ch = --y;
regist.h.cl = --x;
regist.x.dx = (y + height - 1) << 8 | x + width - 1;
regist.h.bh = attribute;
int86(0x10, ®ist, ®ist);
}


/*---------*/
/* B O X */
/*---------*/

void box(x, y, width, height, type) /* type 0 = pull-down box */
int x, y, width, height, type; /* type 1 = regular box */
{
int i, u_right, u_left;
char string[82];

if (type == 0) /* following sets corners */
{
u_left = '\xC2';
u_right = '\xC2';
}
else if (type == 1)
{
u_left = '\xDA';
u_right = '\xBF';
}

string[0] = u_left;
for (i = 1; i <= width; string[i++] = '\xC4');
string[i++] = u_right;
string[i] = '\0';
print(x, y++, string);

for (i = 0; i < height; i++)
{
print(x, y, "\xB3");
print(x + width + 1, y++, "\xB3");
}

string[0]='\xC0';
for(i = 1; i <= width; string[i++] = '\xC4');
string[i++] = '\xD9';
string[i] = '\0';
print(x, y++, string);
}


/*-------------------*/
/* W H A T _ M O N */
/*-------------------*/

int what_mon() /* Returns a 1 if color card present, 0 if monochrome */
{
return (peekb(0x0040, 0x0049) != 7);
}


/*---------*/
/* C L S */
/*---------*/

void cls() /* Same as DOS cls */
{
clear_window(1, 1, 80, 25);
gotoxy(1, 1);
}


/*-------------------------*/
/* M A K E _ W I N D O W */
/*-------------------------*/

void make_window(x, y, width, height, type) /* Draws and clears a box */
unsigned int x, y, width, height, type;
{
box(x++, y++, width, height, type); /* Draw box */
clear_window(x, y, width, height); /* Clear interior */
}


/*---------------*/
/* C U R S O R */
/*---------------*/

int cursor(size) /* Sets cursor size */
int size; /* 0 = no cursor, 1 = normal, 2 = big cursor */
{
union REGS regist;

regist.h.ah = 0x01;

if (mon_type == 1 ) /* color */
{
if (size == 0)
regist.x.cx = 0x0F0F;
else if (size == 1)
regist.x.cx = 0x0607;
else if (size == 2)
regist.x.cx = 0x0107;
}
else /* monochrome */
{
if (size == 0)
regist.x.cx = 0x0F0F;
else if (size == 1)
regist.x.cx = 0x0C0D;
else if (size == 2)
regist.x.cx = 0x010D;
}

int86(0x10, ®ist, ®ist);
}


/*-------------*/
/* P R I N T */
/*-------------*/

void print(x, y, str) /* A switcher - routes to fast_write */
unsigned int x, y; /* or to dos_prt depending on argv */
char *str; /* passed to program and stored in */
{ /* extern char wr_meth */
extern char wrt_meth;

if (wrt_meth == 'f') /* Fast (direct poking) */
fast_write(x, y, str);
else if (wrt_meth == 's') /* Slow (DOS method) */
{
gotoxy(x, y);
dos_prt(str);
}
}


/*-----------------*/ /* Asks DOS to write a string with attribute */
/* D O S _ P R T */ /* defined. an alternative to fast write in */
/*-----------------*/ /* that it is "well behaved" (goes through DOS) */
/* Specify page and set cursor position before */
void dos_prt(str) /* calling */
char *str;
{
extern unsigned int page, attribute;
unsigned int x, y;
union REGS regist;

wherexy(&x, &y);
while (*str)
{
if (x > 80)
{
x = 1;
++y;
}
if (y > 25)
break;
gotoxy(x++, y);
regist.x.bx = (page << 8 | attribute);
regist.x.cx = 1;
regist.x.ax = 0x0900 | *str++;
int86(0x10, ®ist, ®ist);
}
gotoxy(x, y); /* put cursor at end of string */
}


/*-----------------------*/
/* F A S T _ W R I T E */
/*-----------------------*/

void fast_write(x, y, string) /* Directly pokes string at x,y position */
int x, y; /* Uses attribute and page. */
char *string; /* May cause snow on some graphic cards */
{
extern unsigned int page;
extern unsigned int attribute;
extern unsigned int mon_type; /* Monitor type */
int position, offset, orig;

if (page <= 3 && page >= 0)
offset = 4000 * page + 96 * page;
orig = offset;
offset += (y-1) * 160 + 2 * (x-1);
if (mon_type == 0)
position = 0xB000;
else
position = 0xB800;

while (*string)
{
pokeb(position, offset, *string++); /* Poke character */
pokeb(position, offset+1, (char)attribute); /* Poke attribute */
offset += 2;
}
offset -= orig; /* Figure where I am */
x = (offset % 160) / 2 + 1;
y = offset / 160 + 1; /* and move cursor */
gotoxy(x, y);
}


/*-----------------*/
/* G E T _ K E Y */
/*-----------------*/

int get_key(ch, ext) /* Read a char */
char *ch; /* Return character in ch */
int *ext; /* If it is a function key */
{ /* return following in ext */
*ch = getch(); /* up-arrow = 'u' */
if (!*ch) /* down-arrow = 'd' */
{ /* right-arrow = 'r' */
*ext = getch(); /* left-arrow = 'l' */
switch (*ext)
{
case 'H': *ext = 'u'; break; /* up */
case 'P': *ext = 'd'; break; /* down */
case 'M': *ext = 'r'; break; /* right */
case 'K': *ext = 'l'; break; /* left */
case 'G': *ext = 'h'; break; /* home */
case 'O': *ext = 'e'; break; /* end */
case 'R': *ext = 'I'; break; /* insert */
case 'S': *ext = 'D'; break; /* delete */
}
}
}


  3 Responses to “Category : C Source Code
Archive   : TC-MENU.ZIP
Filename : TC-MENU.C

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/