/* (c) Marietta Systems, Inc 1987 All rights reserved */ /* * This program allows the viewing, amending, deleting and adding of * records to a dBase II Plus '.dbf' file. * * This program only works with files with less than 21 fields! */ #include "mtest.h" #ifndef LATTICE #define memcpy memmove #endif /* */ #define fileend (FN[fh].start + FN[fh].rec_len * FN[fh].prime) int dbf_acpt(int, int, struct DBF_DEF*, enum ATTRIB); int dbf_disp(int, int, struct DBF_DEF*, enum ATTRIB, int, int); int dbf_init(int*, struct DBF_DEF**); void dbf_mnt(int, int, struct DBF_DEF*, long*); void do_search(int, char*, long*); void mnt_scrn(int, char*); void recblank(int); int rec_acpt(int, int, struct DBF_DEF*); void rec_disp(int, int, struct DBF_DEF*); void show_nbr(int, long); int stsearch(char*, char*); /* * * Function to accept a dbase3 field * */ int dbf_acpt(fh, field, format, atb) int fh, field; struct DBF_DEF *format; enum ATTRIB atb;{ int z, basept, ret, x = _CURSOR.X, y = _CURSOR.Y; enum _JUST just; char text[255]; /* Error check */ if (fh < 5 || fh > MAXFILES || field < 0 || field > FN[fh].start/32 - 2) {disp_err("Parameter error in dbf_acpt", 1001); return -10;} /* Setup */ for (z = 0 , basept = 1 ; z < field ; basept += format[z++].dbf_len); memcpy(text, &FN[fh].record[basept], format[field].dbf_len); text[format[field].dbf_len] = 0; /* copy to entry area */ switch ((int)format[field].dbf_type){ case 'C': just = left; break; case 'L': just = left; break; case 'N': just = decimal; break; case 'D': just = date; if (text[0] == 32) {text[10] = -80; text[11] = text[12] = 0;} else {text[12] = (char)atoi(&text[6]); text[6] = 0; text[11] = (char)atoi(&text[4]); text[4] = 0; text[10] = (char)(atoi(text) - 1980);} memcpy (text, &text[10], 3); break; default: disp_err("Cannot edit memo field", 1002); return (INCHAR == ENTER ? 0 : 1); } /* perform accept */ re_enter: ret = accept(text, just, atb, format[field].dbf_dig, format[field].dbf_dec); if (ret < 0) return ret; /* Pass through error code from accept */ if (ret && INCHAR == CTL_ENT) return ret; switch ((int)format[field].dbf_type){ case 'C': break; case 'L': text[0] = toupper(text[0]); if (text[0] != 'T' && text[0] != 'F') {disp_err("Logical field type requires 'T' or 'F'", 1); set_crsr(x,y); goto re_enter;} display(text, x, y, ACC_DISP); break; case 'N': break; case 'D': memcpy(&text[10], text, 3); if (text[1] != 0) sprintf(text, "%4u%2u%2u", 1980 + text[10], (int)text[11], (int)text[12]); else strcpy(text, " "); } memcpy(&FN[fh].record[basept],text, format[field].dbf_len); return ret; } /* end of function dbf_acpt */ /* * * Function to display a dbase3 field * */ int dbf_disp(fh, field, format, atb , x, y) int fh, field, x, y; struct DBF_DEF *format; enum ATTRIB atb;{ int z, basept; char text[255]; /* Error check */ if (fh < 5 || fh > MAXFILES || field < 0 || field > FN[fh].start/32 - 2) {disp_err("Parameter error in dbf_disp", 1001); return -10;} /* Setup */ for (z = 0 , basept = 1 ; z < field ; basept += format[z++].dbf_len); memcpy(text, &FN[fh].record[basept], format[field].dbf_len); text[format[field].dbf_len] = 0; switch ((int)format[field].dbf_type){ case 'N': strcpy(&text[60], text); justify(decimal, text, &text[60], format[field].dbf_dig, format[field].dbf_dec); break; case 'D': if (text[0] == 32) /* Null date */ {text[10] = -80; text[11] = text[12] = 0;} else {text[12] = (char)atoi(&text[6]); text[6] = 0; text[11] = (char)atoi(&text[4]); text[4] = 0; text[10] = (char)(atoi(text) - 1980);} date_out(text, &text[10]); break; default: break; } /* perform display */ display(text, x, y, atb); return 0; } /* end function dbf_disp */ /* * * Function to read in file and data dictionary * */ int dbf_init(fields, format) int *fields; struct DBF_DEF **format;{ int fh, z; char name[51], text[25]; for (z = 0; z < 8 ; KEYMATCH[z++] = 0); /* suppress function keys */ disp_err("",1); /* force display of function keys */ /* test if already initialized */ strcpy(name,"dbftest.dbf"); /* obtain file name and setup format */ for (;;){ disp_msg("",0); display("Enter dBase 3+ file name ", 20, 1, high); if (accept(name, left, alt_reverse, 50, 0) < 0 || INCHAR == QUIT) goodbye(0); if ((fh = fileopen(name, dbase3, update)) < 0) continue; if (!fh) {disp_err("File not found - try again", 1); continue;} if (FN[fh].start < 65) {disp_err("Not valid dBase3+ file",1); idleloop(18);} if (FN[fh].fnext == NULL) disp_err("Could not load data dictionary",1); if (FN[fh].start < 65 || FN[fh].fnext == NULL) {fileclos(fh); continue;} break; } /* end for loop */ mk_wndw(5,15, 15,65, "Display of file header information"); display((byte*)FN[fh].fname, 1, 2, high); sprintf(text, "prime = %ld", FN[fh].prime); display(text, 2, 2, high); sprintf(text, "start = %d", FN[fh].start); display(text, 3, 2, high); sprintf(text, "rec_len= %d", FN[fh].rec_len); display(text, 4, 2, high); sprintf(text, "write = %c", FN[fh].write); display(text, 5, 2, high); sprintf(text, "ftype = %d", (int)FN[fh].ftype); display(text, 6, 2, high); if (FN[fh].fnext == NULL) display("NULL pointer value in fnext", 7, 2, high); else display("Data dictionary loaded", 7, 2, high); display("<< Press ESC key to continue >>", 9, 5, low); while (grabchar() != ESC) disp_err("Press ESC key", 1); rm_wndw(); *fields = dbf_fld(fh); *format = (struct DBF_DEF *)FN[fh].fnext; return fh; } /* end function dbf_init */ /* * * Function to initialize the screen * */ void mnt_scrn(fh, title) int fh; char *title;{ /* setup function key map */ KEYMATCH[0] = 0X428; /* PgDn, Up arrow, Ctrl+Enter */ KEYMATCH[1] = 0X104; /* PgUp, Down arrow */ KEYMATCH[2] = KEYMATCH[3] = KEYMATCH[6] = KEYMATCH[5] = 0; KEYMATCH[4] = 0XB400; /* F3, F5, F6, F8 */ KEYMATCH[7] = 0X4800; /* Ctrl+PgDn, Ctrl+PgUp */ disp_err("",1); /* force display of new function keys */ /* Create info area at top of screen */ display("\030:Prev field PgUp:Prev Record Ctrl+PgUp:1st Record ", 1, 2, low); display((byte*)FN[fh].fname, 1, 65, alt_low); display("\031:Next field PgDn:Next Record Ctrl+PgDn:Last Record", 2, 2, low); /* create edit window */ if (mk_wndw(TOP_LINE + 3, 1, SCRN_LEN, SCRN_WID, title) < 0) goodbye(10); } /* end function mnt_scrn */ /* * * Function to display a record on the screen * */ void rec_disp(fh, fields, format) int fh, fields; struct DBF_DEF *format;{ int x = 1, z, len; clr_wndw(); if (FN[fh].record[0] != IN_USE) display("Record status is deleted", x++, 5, blink); for (z = 0 ; z < fields ; z++){ display(format[z].dbf_name, x, 1, high); dbf_disp(fh, z, format, reverse, x, 12); len = (format[z].dbf_type != 'N' ? format[z].dbf_len : fld_len(decimal, format[z].dbf_dig, format[z].dbf_dec)); x += len / (SCRN_WID - 12) + 1; } } /* end function rec_disp */ /* * * Function to accept a record on the screen * */ int rec_acpt(fh, fields, format) int fh, fields; struct DBF_DEF *format;{ int x = 1, z, len, kk; if (FN[fh].record[0] != IN_USE) x++; for (z = 0 ; z < fields ; ){ set_crsr(x, 12); if (dbf_acpt(fh, z, format, alt_reverse)) kk = INCHAR; else kk = 0; switch (kk){ case 0: case ENTER: case CRS_DN: len = (format[z].dbf_type != 'N' ? format[z].dbf_len : fld_len(decimal, format[z].dbf_dig, format[z].dbf_dec)); x += len / (SCRN_WID - 12) + 1; z++; break; case CTL_ENT: case CRS_UP: if (z == 0) break; len = (format[z-1].dbf_type != 'N' ? format[z-1].dbf_len : fld_len(decimal, format[z-1].dbf_dig, format[z-1].dbf_dec)); x -= len / (SCRN_WID - 12) + 1; z--; break; default: return kk; } } return 0; } /* end function rec_acpt */ /* * * Function to show current record location on screen * (uses reserved functions 'set_clr' and 'scrn_map' */ void show_nbr(fh, rec_nbr) int fh; long rec_nbr;{ char text[16]; set_clr(99, low); /* use error status color */ sprintf(text, "%5lu of %-5lu", rec_nbr, FN[fh].prime); scrn_map(text, TOP_LINE + 2, 65); /* hairy technique */ set_clr(98, low); /* reset color */ } /* * * Function to blank out a record * */ void recblank(fh) int fh;{ memset(FN[fh].record, 32, FN[fh].rec_len); FN[fh].record[FN[fh].rec_len] = 0; FN[fh].record[0] = IN_USE; } /* * * Find if string2 is in string1 * */ int stsearch(s1, s2) char *s1, *s2;{ int len2 = strlen(s2); char *ptr; ptr = strchr(s1, s2[0]); while (ptr != NULL) { if (!strncmp(ptr, s2, len2)) return 1; /* found */ ptr = strchr(&ptr[1], s2[0]); } return 0; } /* * * Function to search for a specified string * */ void do_search(fh, text, rec_nbr) char *text; int fh; long *rec_nbr;{ int count = 0; long base = *rec_nbr; char out[15]; /* setup */ if (mk_wndw(5,7, 11,73, "File search through dbase3+ file") < 0) return; display("Remember dates are stored as yyyymmdd ('19801231' for 12/31/80)", 5, 2, low); /* obtain search text */ display("Enter search text ", 1, 1, high); if (accept(text, left, alt_reverse, 16, 0)) {disp_err("Search abandoned",1); rm_wndw(); return;} concat(text, 0); /* suppress trailing spaces */ strupr(text); /* read around through the file */ for (;;) { if (!fileread(fh, nextrec, rec_nbr)) fileread(fh, firstrec, rec_nbr); if (*rec_nbr == base) {disp_err("No matching text found", 1); warble(500); idleloop(5); rm_wndw(); warble(0); return;} if (5 == (count++)) { sprintf(out,"Record = %6lu", *rec_nbr); display(out, 2, 5, reverse); if (kbhit() && disp_qry("Do you wish to stop the search")) {rm_wndw(); return;} count = 0; } strupr(&FN[fh].record[1]); if (stsearch(&FN[fh].record[1], text)) {disp_err("Match found", 1); *rec_nbr -= 1L; rm_wndw(); return;} } } /* * * Function to perform file maintenance * */ void dbf_mnt(fh, fields, format, rec_nbr) int fh, fields; long *rec_nbr; struct DBF_DEF *format;{ int ret; byte kk = 0; char text[17]; /* setup */ mnt_scrn(fh, "Edit function for dBase3+ files"); if ((ret = fileread(fh, firstrec, rec_nbr)) < 0) goodbye(3); show_nbr(fh, *rec_nbr - 1L); text[0] = 0; if (!ret) kk = INSERT; /* Handle special case of empty file */ /* main accept loop */ for (;;){ if (!ret && !kk) recblank(fh); if (!kk) {rec_disp(fh, fields, format); scrnsave(0);} switch((kk ? kk : grabchar())){ case PGUP: case CTL_ENT: kk = 0; *rec_nbr -= 2L; if (*rec_nbr < 1L) {*rec_nbr = 1L; disp_err("Top of file",1);} break; case PGDN: case ENTER: kk = 0; if (*rec_nbr > FN[fh].prime) {*rec_nbr = FN[fh].prime; disp_err("End of file", 1);} break; case CTL_PGUP: *rec_nbr = 1L; kk = 0; break; case CTL_PGDN: *rec_nbr = FN[fh].prime; kk = 0; break; case UNDO: *rec_nbr -= 1L; if (FN[fh].record[0] != DELETED || !disp_qry("Do you want to UNDO the delete")) {kk = 0; break;} FN[fh].record[0] = IN_USE; if (filewrit(fh, rec_nbr) < 0) goodbye(6); kk = 0; *rec_nbr -= 1L; break; case SEARCH: do_search(fh, text, rec_nbr); kk = 0; break; case INSERT: fileseek(fh, fileend); *rec_nbr = FN[fh].prime + 1L; recblank(fh); rec_disp(fh, fields, format); kk = rec_acpt(fh, fields, format); if (filewrit(fh, rec_nbr) < 0) goodbye(7); if (!kk && *rec_nbr > FN[fh].prime) kk = INSERT; break; case DELETE: *rec_nbr -= 1L; kk = 0; if (!disp_qry("Do you really want to delete")) break; FN[fh].record[0] = DELETED; if (filewrit(fh, rec_nbr) < 0) goodbye(8); *rec_nbr -= 1L; break; case AMEND: *rec_nbr -= 1L; if (FN[fh].record[0] != IN_USE) {disp_err("You cannot amend a deleted record",1); kk = 0; break;} kk = rec_acpt(fh, fields, format); if (filewrit(fh, rec_nbr) < 0) goodbye(9); break; case QUIT: return; case HELP: helpscrn(NULL); default: disp_msg("",0); *rec_nbr -= 1L; kk = 0; warble(1000); idleloop(ERR_BEEP); warble(0); break; } /* end switch */ if (kk && *rec_nbr) *rec_nbr -= 1L; if ((ret = fileread(fh, relative, rec_nbr)) < 0) goodbye(5); if (!ret) {disp_err("End of file reached",1); ret = fileread(fh, lastrec, rec_nbr);} show_nbr(fh, *rec_nbr - 1L); } /* end for loop */ } /* end of dbf_mnt function */ /* * * Main program * */ void main(){ struct DBF_DEF *format; long rec_nbr = 1L; int fh, fields; clr_scrn("Test of dbf access"); if ((fh = dbf_init(&fields, &format)) < 1) goodbye(2); dbf_mnt(fh, fields, format, &rec_nbr); fileclos(fh); goodbye(0); }