/* * ______ ____ ______ _____ ______ * | ____| | _ \| ____| / / _ \| ____| * | |__ _ __ ___ ___| |_) | |__ / / |_| | |__ * | __| '__/ _ \/ _ \ _ <| __| / /| _ | __| * | | | | | __/ __/ |_) | |____ / / | | | | | * |_| |_| \___|\___|____/|______/_/ |_| |_|_| * * * Installation utility. * * See freebe.txt for copyright information. */ #include #include #include #include #include #include #include #include #include #include #include #include "vbeaf.h" #define VBEAF_FILENAME "c:\\vbeaf.drv" #define ever \ ; \ ; /* info about one of the VBE/AF drivers */ typedef struct DRIVER_INFO { char name[80]; AF_DRIVER *driver; int driver_size; char *notes; int notes_size; int present; int accel; int config; } DRIVER_INFO; #define MAX_DRIVERS 256 DRIVER_INFO driver_info[MAX_DRIVERS]; int num_drivers = 0; char current_driver_name[80]; char current_driver_copyright[80]; /* graphics characters */ #define TL_CHAR 0xDA #define TOP_CHAR 0xC4 #define TR_CHAR 0xBF #define SIDE_CHAR 0xB3 #define BL_CHAR 0xC0 #define BR_CHAR 0xD9 #define SHADOW_CHAR 0xDB /* drawing state variables */ int _text_color = 0; int _text_x = 0; int _text_y = 0; int screen_h; /* mouse driver state variables */ int m_state; int m_x = 0; int m_y = 0; int m_b = 0; /* sets up the mouse driver */ void mouse_init( ) { __dpmi_regs reg; reg.x.ax = 0; __dpmi_int(0x33, ®); m_state = reg.x.ax; if (m_state) { reg.x.ax = 10; reg.x.bx = 0; reg.x.cx = 0xffff; reg.x.dx = 0x7700; __dpmi_int(0x33, ®); } } /* displays the mouse pointer */ void mouse_on( ) { __dpmi_regs reg; if (m_state) { reg.x.ax = 1; __dpmi_int(0x33, ®); } } /* hides the mouse pointer */ void mouse_off( ) { __dpmi_regs reg; if (m_state) { reg.x.ax = 2; __dpmi_int(0x33, ®); } } /* reads the mouse state */ void mouse_read( ) { __dpmi_regs reg; if (m_state) { reg.x.ax = 3; __dpmi_int(0x33, ®); m_x = reg.x.cx / 8; m_y = reg.x.dx / 8; m_b = reg.x.bx; } } /* sets the mouse position */ void mouse_move(int x, int y) { __dpmi_regs reg; if (m_state) { reg.x.ax = 4; reg.x.cx = x * 8; reg.x.dx = y * 8; __dpmi_int(0x33, ®); m_x = x; m_y = y; } } /* waits for a keypress or mouse button click */ void input_pause( ) { mouse_on( ); while (m_b) mouse_read( ); for (ever) { if (keypressed( )) { readkey( ); break; } mouse_read( ); if (m_b) break; } mouse_off( ); } /* sets the drawing color */ void text_color(int c) { _text_color = c; } /* sets the drawing position */ void text_pos(int x, int y) { _text_x = x - 1; _text_y = y - 1; } /* prints a character */ void text_c(int c) { if (_text_x < 80) _farpokew(_dos_ds, 0xB8000 + _text_x * 2 + _text_y * 160, c | (_text_color << 8)); _text_x++; } /* prints a string */ void text_str(char *s) { while (*s) { text_c((unsigned char)*s); s++; } } /* prints the first part of a string */ void text_clamp(char *s, int max) { int i; if ((int)strlen(s) <= max) { text_str(s); } else { for (i = 0; i < max; i++) text_c((unsigned char)s[i]); text_str("..."); } } /* clears to the end of the current line */ void text_clear_eol( ) { while (_text_x < 80) text_c(' '); } /* helper for drawing a box onto the screen */ void draw_box(int w, int h) { static char url[] = "http://www.talula.demon.co.uk/freebe/"; int x, y, e; /* status text */ text_color(0x07); text_pos(1, 1); text_str("FreeBE/AF " FREEBE_VERSION); while (_text_x < 80 - (int)strlen(url)) text_c(' '); text_str(url); text_pos(1, screen_h - 2); text_str("Currently installed driver:"); text_clear_eol( ); text_pos(1, screen_h - 1); text_str(current_driver_name); text_clear_eol( ); text_pos(1, screen_h); text_str(current_driver_copyright); text_clear_eol( ); text_color(0x74); /* top border */ text_pos(40 - w / 2 - 1, screen_h / 2 - h / 2 - 1); text_c(TL_CHAR); for (x = 0; x < w; x++) text_c(TOP_CHAR); text_c(TR_CHAR); /* box body */ for (y = 0; y < h; y++) { text_pos(40 - w / 2 - 1, screen_h / 2 - h / 2 + y); text_c(SIDE_CHAR); for (x = 0; x < w; x++) text_c(' '); text_c(SIDE_CHAR); } /* bottom border */ text_pos(40 - w / 2 - 1, screen_h / 2 + (h + 1) / 2); text_c(BL_CHAR); for (x = 0; x < w; x++) text_c(TOP_CHAR); text_c(BR_CHAR); /* shadow */ text_color(0x08); for (y = 0; y <= h; y++) { text_pos(41 + w / 2, screen_h / 2 - h / 2 + y); text_c(SHADOW_CHAR); } text_pos(40 - w / 2, screen_h / 2 + (h + 1) / 2 + 1); for (x = 0; x <= w + 1; x++) text_c(SHADOW_CHAR); /* clear the rest of the screen */ text_color(0); for (y = 2; y < screen_h / 2 - h / 2 - 1; y++) { text_pos(1, y); for (x = 0; x < 80; x++) text_c(' '); } for (y = screen_h / 2 + (h + 1) / 2 + 2; y < screen_h - 2; y++) { text_pos(1, y); for (x = 0; x < 80; x++) text_c(' '); } for (y = screen_h / 2 - h / 2 - 1; y < screen_h / 2 + (h + 1) / 2 + 2; y++) { e = (y == screen_h / 2 + (h + 1) / 2 + 1) ? 1 : 0; text_pos(1, y); for (x = 1; x < 40 - w / 2 - 1 + e; x++) text_c(' '); e = (y == screen_h / 2 - h / 2 - 1) ? 1 : 0; text_pos(42 + w / 2 - e, y); for (x = 42 + w / 2 - e; x <= 80; x++) text_c(' '); } text_color(0x71); } /* main menu interface function */ int get_selection(char **str, int sel, int num, int y, int samescroll) { static int oldscroll = 0; int scroll; long start, sstart; int redraw; int count, len; int i, j, c, x; int ox, oy; int ob = 0; count = 0; len = 0; while (str[count]) { if (*str[count] <= '\002') i = 6 + strlen(str[count] + 1); else i = strlen(str[count]); if (len < i) len = i; count++; } if (count > num) { y++; num -= 2; } if (samescroll) scroll = oldscroll; else scroll = MID(0, sel - num / 2, count - num); len += 8; x = 40 - len / 2; sstart = clock( ); for (ever) { /* draw the menu */ for (i = 0; i < num; i++) { if (i + scroll == sel) text_color(0x07); else text_color(0x70); text_pos(x, y + i + 1); text_str(" "); if (*str[i + scroll] <= '\002') { if (*str[i + scroll] == '\001') { if (i + scroll == sel) text_color(0x02); else text_color(0x72); text_str("ON -- "); } else { if (i + scroll == sel) text_color(0x04); else text_color(0x74); text_str("OFF - "); } if (i + scroll == sel) text_color(0x07); else text_color(0x70); text_str(str[i + scroll] + 1); for (j = strlen(str[i + scroll] + 1) + 10; j < len; j++) text_c(' '); } else { text_str(str[i + scroll]); for (j = strlen(str[i + scroll]) + 4; j < len; j++) text_c(' '); } } if (count > num) { text_color(0x78); text_pos(x + 4, y); if (scroll > 0) text_str("--- more ---"); else text_str(" "); text_pos(x + 4, y + num + 1); if (scroll < count - num) text_str("--- more ---"); else text_str(" "); } mouse_on( ); while ((m_b) && (!ob)) mouse_read( ); redraw = FALSE; while (!redraw) { if (keypressed( )) { /* deal with keyboard input */ c = readkey( ); switch (c >> 8) { case KEY_UP: if (sel > 0) { sel--; if (sel < scroll) scroll = sel; redraw = TRUE; } break; case KEY_DOWN: if (sel < count - 1) { sel++; if (sel >= scroll + num) scroll = sel - num + 1; redraw = TRUE; } break; case KEY_PGUP: if (sel > scroll) { sel = scroll; } else { sel = scroll = MAX(sel - num + 1, 0); } redraw = TRUE; break; case KEY_PGDN: if (sel < scroll + num - 1) { sel = scroll + num - 1; } else { sel = MIN(sel + num - 1, count - 1); scroll = sel - num + 1; } redraw = TRUE; break; case KEY_HOME: sel = scroll = 0; redraw = TRUE; break; case KEY_END: sel = count - 1; scroll = count - num; redraw = TRUE; break; case KEY_ENTER: case KEY_SPACE: mouse_off( ); oldscroll = scroll; return sel; case KEY_ESC: mouse_off( ); oldscroll = scroll; return -1; } } else { /* deal with mouse input */ mouse_read( ); if (m_b & 2) { /* right button cancels */ mouse_off( ); oldscroll = scroll; return -1; } if (m_b & 1) { if ((m_x >= x - 1) && (m_x < x + len - 1) && (m_y >= y) && (m_y < y + num)) { if (sel == m_y - y + scroll) { /* double click detection */ start = clock( ); ox = m_x; oy = m_y; /* check for release */ while (((clock( ) - start) < CLOCKS_PER_SEC / 4) && (ox == m_x) && (oy == m_y) && (m_b & 1)) mouse_read( ); if (!(m_b & 1)) { start = clock( ); ox = m_x; oy = m_y; /* check for second click */ while ( ((clock( ) - start) < CLOCKS_PER_SEC / 4) && (ox == m_x) && (oy == m_y) && (!(m_b & 1))) mouse_read( ); if (m_b & 1) { /* yeah! dclick... */ mouse_off( ); oldscroll = scroll; return sel; } } } else { /* left button selects */ sel = m_y - y + scroll; redraw = TRUE; } } else if ((m_x >= x - 1) && (m_x < x + len - 1) && (m_y < y) && (scroll > 0) && (clock( ) > sstart + CLOCKS_PER_SEC / 24)) { /* upward mouse scrolling */ scroll--; sel = scroll; redraw = TRUE; sstart = clock( ); } else if ((m_x >= x - 1) && (m_x < x + len - 1) && (m_y >= y + num) && (scroll < count - num) && (clock( ) > sstart + CLOCKS_PER_SEC / 24)) { /* downward mouse scrolling */ scroll++; sel = scroll + num - 1; redraw = TRUE; sstart = clock( ); } } ob = m_b; } } mouse_off( ); } } /* helper to remove a string from within another string */ void strip_text(char *str, char *kill) { char *s = strstr(str, kill); if (s) { if ((s > str) && (s[-1] == ' ')) strcpy(s - 1, s + strlen(kill)); else if (s[strlen(kill)] == ' ') strcpy(s, s + strlen(kill) + 1); else strcpy(s, s + strlen(kill)); } } /* qsort() callback for sorting the driver list */ int driver_cmp(const void *q1, const void *q2) { DRIVER_INFO *d1 = (DRIVER_INFO *)q1; DRIVER_INFO *d2 = (DRIVER_INFO *)q2; return strcmp(d1->name, d2->name); } /* read the appended driver data */ int read_driver_data( ) { typedef unsigned long (*EXT_INIT_FUNC)(AF_DRIVER * af, unsigned long id); EXT_INIT_FUNC ext_init; FAF_CONFIG_DATA *cfg; AF_DRIVER *af; DRIVER_INFO *info; PACKFILE *f; char name[80]; unsigned long magic; int type, size, ret; f = pack_fopen("#", F_READ_PACKED); if (!f) return 1; pack_mgetl(f); pack_mgetl(f); while (!pack_feof(f)) { type = pack_mgetl(f); if (type == DAT_FILE) { f = pack_fopen_chunk(f, FALSE); pack_mgetl(f); info = &driver_info[num_drivers]; info->driver = NULL; info->notes = NULL; name[0] = 0; while (!pack_feof(f)) { type = pack_mgetl(f); if (type == DAT_PROPERTY) { type = pack_mgetl(f); size = pack_mgetl(f); if (type == DAT_NAME) { pack_fread(name, size, f); name[size] = 0; } else pack_fseek(f, size); } else { f = pack_fopen_chunk(f, FALSE); if (strcmp(name, "VBEAF_DRV") == 0) { info->driver_size = f->todo; info->driver = malloc(info->driver_size); pack_fread(info->driver, info->driver_size, f); } else if (strcmp(name, "NOTES_TXT") == 0) { info->notes_size = f->todo; info->notes = malloc(info->notes_size); pack_fread(info->notes, info->notes_size, f); } f = pack_fclose_chunk(f); } } if ((info->driver) && (info->notes)) { strcpy(info->name, info->driver->OemVendorName); strip_text(info->name, "FreeBE/AF"); strip_text(info->name, "driver"); strip_text(info->name, FREEBE_VERSION); info->present = FALSE; info->accel = FALSE; info->config = 0; af = malloc(info->driver_size); if (af) { memcpy(af, info->driver, info->driver_size); if (af->OemExt) { ext_init = (EXT_INIT_FUNC)((long)af + (long)af->OemExt); magic = ext_init(af, FAFEXT_INIT); if (((magic & 0xFFFF0000) == FAFEXT_MAGIC) && (isdigit((magic >> 8) & 0xFF)) && (isdigit(magic & 0xFF))) { cfg = af->OemExt(af, FAFEXT_CONFIG); if (cfg) { while (cfg->id) { if (cfg->id == FAF_CFG_FEATURES) { info->config = (unsigned long)&cfg->value - (unsigned long)af; break; } cfg++; } } } } asm(" call *%2 " : "=&a"(ret) : "b"(af), "rm"(((long)af + (long)af->PlugAndPlayInit)) : "memory"); if (ret == 0) { info->present = TRUE; info->accel = ((af->Attributes & afHaveAccel2D) != 0); } free(af); } num_drivers++; } f = pack_fclose_chunk(f); } else if (type == DAT_PROPERTY) { pack_mgetl(f); size = pack_mgetl(f); pack_fseek(f, size); } else { size = pack_mgetl(f); pack_fseek(f, size + 4); } } pack_fclose(f); if (num_drivers > 1) qsort(driver_info, num_drivers, sizeof(DRIVER_INFO), driver_cmp); return 0; } /* detects what VBE/AF driver is currently installed */ int check_current_driver( ) { static char *options[] = { "Overwrite existing driver", "Backup c:\\vbeaf.drv to c:\\vbeaf.old", "Abort installation", NULL }; AF_DRIVER driver; PACKFILE *f; f = pack_fopen(VBEAF_FILENAME, F_READ); if (!f) { strcpy(current_driver_name, "{none}"); strcpy(current_driver_copyright, ""); return 0; } pack_fread(&driver, sizeof(driver), f); pack_fclose(f); strcpy(current_driver_name, driver.OemVendorName); strcpy(current_driver_copyright, driver.OemCopyright); if (strstr(current_driver_name, "FreeBE/AF")) return 0; draw_box(60, 16); text_pos(12, screen_h / 2 - 6); text_str("Existing VBE/AF driver detected:"); text_color(0x74); text_pos(16, screen_h / 2 - 4); text_clamp(current_driver_name, 48); text_pos(16, screen_h / 2 - 3); text_clamp(current_driver_copyright, 48); text_color(0x71); text_pos(12, screen_h / 2 - 1); text_str("If this is one of the SciTech Display Doctor drivers,"); text_pos(12, screen_h / 2); text_str("it will be regenerated whenever you load UniVBE. You"); text_pos(12, screen_h / 2 + 1); text_str("will need to uninstall SDD before using FreeBE/AF."); switch (get_selection(options, 0, 3, screen_h / 2 + 3, FALSE)) { case 0: /* overwrite */ return 0; case 1: /* backup */ remove("c:\\vbeaf.old"); rename(VBEAF_FILENAME, "c:\\vbeaf.old"); strcpy(current_driver_name, "{none}"); strcpy(current_driver_copyright, ""); return 0; default: /* abort */ return 1; } } /* displays the readme information */ void text_viewer(char *text, int len) { char buf[256]; int redraw; int total, pos; int line; int c, i, l, p; int oy; total = 1; pos = 0; /* count number of lines */ for (i = 0; i < len; i++) { if ((text[i] == '\r') || (text[i] == '\n')) { total++; if ((i < len - 1) && (text[i] == '\r') && (text[i + 1] == '\n')) i++; } } mouse_move(40, screen_h / 2); for (ever) { text_color(0x70); p = 0; /* skip lines that we have scrolled past */ for (i = 0; i < pos; i++) { while ((p < len) && (text[p] != '\r') && (text[p] != '\n')) p++; if ((p < len) && (text[p] == '\r')) p++; if ((p < len) && (text[p] == '\n')) p++; } /* redraw the screen */ for (line = 1; line <= screen_h; line++) { text_pos(1, line); l = 0; while ((p < len) && (l < 255) && (text[p] != '\r') && (text[p] != '\n')) { buf[l] = text[p]; if (buf[l] == '\t') { for (i = 0; (i < 8) && (i + l < 255); i++) buf[l + i] = ' '; l += 7; } l++; p++; } buf[l] = 0; if ((p < len) && (text[p] == '\r')) p++; if ((p < len) && (text[p] == '\n')) p++; text_str(buf); text_clear_eol( ); } while (m_b) mouse_read( ); redraw = FALSE; while (!redraw) { if (keypressed( )) { /* process keyboard input */ c = readkey( ); switch (c >> 8) { case KEY_UP: if (pos > 0) pos--; redraw = TRUE; break; case KEY_DOWN: if (pos < total - screen_h) pos++; redraw = TRUE; break; case KEY_HOME: pos = 0; redraw = TRUE; break; case KEY_END: pos = total - screen_h; if (pos < 0) pos = 0; redraw = TRUE; break; case KEY_PGUP: pos -= screen_h - 1; if (pos < 0) pos = 0; redraw = TRUE; break; case KEY_PGDN: pos += screen_h - 1; if (pos > total - screen_h) pos = total - screen_h; if (pos < 0) pos = 0; redraw = TRUE; break; case KEY_ESC: case KEY_ENTER: case KEY_SPACE: return; } } else { /* process mouse input */ oy = m_y; mouse_read( ); if (m_b) return; if (m_y != oy) { pos += m_y - oy; if (pos > total - screen_h) pos = total - screen_h; if (pos < 0) pos = 0; mouse_move(40, screen_h / 2); redraw = TRUE; } } } } } /* allows the user to edit the driver configuration */ void edit_config(unsigned long *features, unsigned long orig_features) { static char *flist[] = { "*Linear Framebuffer", "*Banked Framebuffer", "*Hardware Cursor", "*DrawScan()", "*DrawPattScan()", "*DrawColorPattScan()", "*DrawScanList()", "*DrawPattScanList()", "*DrawColorPattScanList()", "*DrawRect()", "*DrawPattRect()", "*DrawColorPattRect()", "*DrawLine()", "*DrawStippleLine()", "*DrawTrap()", "*DrawTri()", "*DrawQuad()", "*PutMonoImage()", "*PutMonoImageLin()", "*PutMonoImageBM()", "*BitBlt()", "*BitBltSys()", "*BitBltLin()", "*BitBltBM()", "*SrcTransBlt()", "*SrcTransBltSys()", "*SrcTransBltLin()", "*SrcTransBltBM()", "Go Back", NULL }; static int sel = 0; int virgin = TRUE; char *list[34]; int index[32]; int num_options, n, i; num_options = 0; for (n = 0; n < (int)(sizeof(flist) / sizeof(char *) - 2); n++) { if (orig_features & (1 << n)) { list[num_options] = flist[n]; index[num_options] = n; num_options++; if (*features & (1 << n)) *flist[n] = '\001'; else *flist[n] = '\002'; } } list[num_options++] = flist[n]; list[num_options] = NULL; if (sel >= num_options) sel = 0; n = MIN(num_options, screen_h * 4 / 7); draw_box(40, n + 2); for (ever) { i = get_selection(list, sel, n, screen_h / 2 - n / 2 - 1, !virgin); if (i >= 0) sel = i; if ((i >= 0) && (i < num_options - 1)) { *features ^= (1 << index[i]); if (*features & (1 << index[i])) *list[i] = '\001'; else *list[i] = '\002'; } else return; virgin = FALSE; } } /* writes vbeaf.drv to c:\ */ int install_driver(DRIVER_INFO *info, unsigned long features, unsigned long orig_features) { PACKFILE *f; f = pack_fopen(VBEAF_FILENAME, F_WRITE); if (!f) { draw_box(60, 3); text_pos(16, screen_h / 2); text_str("Error installing driver!"); input_pause( ); return FALSE; } if (info->config) *((unsigned long *)((unsigned long)info->driver + info->config)) = features; pack_fwrite(info->driver, info->driver_size, f); pack_fclose(f); if (info->config) *((unsigned long *)((unsigned long)info->driver + info->config)) = orig_features; return TRUE; } /* installs a new driver */ int got_card(DRIVER_INFO *info) { static char *options[] = { "View implementation notes", "Configure", "Go Back", "Quit", NULL }; int sel = 0; unsigned long features = 0; unsigned long orig_features = 0; strcpy(current_driver_name, info->driver->OemVendorName); strcpy(current_driver_copyright, info->driver->OemCopyright); if (info->config) { features = *((unsigned long *)((unsigned long)info->driver + info->config)); orig_features = features; } if (!install_driver(info, features, orig_features)) return FALSE; for (ever) { draw_box(60, 11); text_pos(16, screen_h / 2 - 3); text_clamp(info->driver->OemVendorName, 48); text_pos(16, screen_h / 2 - 2); text_str("has been installed onto your system."); sel = get_selection(options, sel, 4, screen_h / 2, FALSE); switch (sel) { case 0: /* view notes */ text_viewer(info->notes, info->notes_size); break; case 1: /* configure */ if (info->config) { edit_config(&features, orig_features); install_driver(info, features, orig_features); } else { draw_box(60, 4); text_pos(16, screen_h / 2 - 1); text_str("Sorry, this driver does not support the"); text_pos(16, screen_h / 2); text_str("FreeBE/AF configuration mechanism!"); input_pause( ); } break; case 3: /* quit */ return TRUE; default: /* back */ return FALSE; } } } /* allows the user to select a driver */ int choose_card( ) { static int sel = 0; char *options[MAX_DRIVERS + 1]; int i, n; for (i = 0; i < num_drivers; i++) options[i] = driver_info[i].name; options[i] = NULL; n = MIN(num_drivers, screen_h * 4 / 7); draw_box(40, n + 2); i = get_selection(options, sel, n, screen_h / 2 - n / 2 - 1, FALSE); if (i >= 0) { sel = i; return got_card(&driver_info[sel]); } return FALSE; } /* displays the main selection menu */ void main_menu( ) { static char *options[] = { "Autodetect graphics hardware", "Manually select a driver", "Remove FreeBE/AF", "Quit", NULL }; char old_name[80]; int sel = 0; int i; for (ever) { draw_box(40, 8); sel = get_selection(options, sel, 4, screen_h / 2 - 3, FALSE); switch (sel) { case 0: /* autodetect */ for (i = 0; i < num_drivers; i++) { if ((!strstr(driver_info[i].name, "stub implementation")) && (driver_info[i].present) && (driver_info[i].accel)) { if (got_card(&driver_info[i])) return; break; } } if (i >= num_drivers) { for (i = 0; i < num_drivers; i++) { if ((!strstr(driver_info[i].name, "stub implementation")) && (driver_info[i].present) && (!driver_info[i].accel)) { if (got_card(&driver_info[i])) return; break; } } if (i >= num_drivers) { draw_box(60, 3); text_pos(16, screen_h / 2); text_str( "Error: unable to detect any supported hardware."); input_pause( ); } } break; case 1: /* manual selection */ if (choose_card( )) return; break; case 2: /* uninstall */ if (strstr(current_driver_name, "FreeBE/AF")) { remove(VBEAF_FILENAME); strcpy(old_name, current_driver_name); strcpy(current_driver_name, "{none}"); strcpy(current_driver_copyright, ""); draw_box(60, 4); text_pos(16, screen_h / 2 - 1); text_clamp(old_name, 48); text_pos(16, screen_h / 2); text_str("has been removed from your system."); input_pause( ); } else { draw_box(60, 4); text_pos(16, screen_h / 2 - 1); text_str("Error removing driver:"); text_pos(16, screen_h / 2); text_str("No FreeBE/AF driver is currently installed!"); input_pause( ); } break; default: /* quit */ return; } } } /* main program */ int main( ) { struct text_info info; allegro_init( ); install_keyboard( ); if (read_driver_data( ) != 0) { printf("Fatal error: driver data not present!\n"); return 1; } __djgpp_set_ctrl_c(0); setcbrk(0); gettextinfo(&info); screen_h = info.screenheight; _setcursortype(_NOCURSOR); mouse_init( ); if (check_current_driver( ) == 0) main_menu( ); clrscr( ); _setcursortype(_NORMALCURSOR); if (strcmp(current_driver_name, "{none}") == 0) { textattr(0x04); cputs("No VBE/AF driver is installed on your machine."); } else { textattr(0x07); cputs("Installed driver:\r\n\r\n"); textattr(0x02); cputs(current_driver_name); cputs("\r\n"); cputs(current_driver_copyright); } textattr(0x07); cputs("\r\n\r\n"); return 0; }