/**************************************************************** * Author: Steven Stewart * * Name: qprint * * Synopsis: Prints a database or a query to an HP LaserJet * * III (or PCL5 emulating) printer in 16.67 cpi * * line printer font, 78 lines per column, two * * columns per page, in landscape orientation. * ****************************************************************/ /* declare global variables */ int EOF, ESC, CR, LP, LCNT, PCNT, PG1FLG; text RECHEAD, PGHEAD, DELIM1, DELIM2, RESET; text BoldOn = chr(27)+"&dD"; text BoldOff = chr(27)+"&d@"; main() { int key, i, j, db; text codes, line1, line2; char string[80]; char fields[256]; /* Abort if no open database */ if (len(db.database) == 0) { messageBox("You need to open a database to run this printing program.", program(), MB_OK | MB_ICONEXCLAMATION); return(0); } /* Initialize screen and global variables; */ initialize(); /* Should we print every field, or only selected fields? */ i = messageBox("Would you like to print every field in the database?", program(), MB_ICONQUESTION | MB_YESNO); if (i == IDYES) { for(i = 1; i <= db.fields; i = i + 1) fields[i] = i; } else { for(i = 1; i <= db.fields; i = i + 1) fields[i] = db.order[i]; markfields(db, fields,"Select the Fields",15,'E'); } /* If active query > 0 ask user to input a string */ /* to print in the header as a decription of query */ /* If active query = 0 then supply description as */ /* "ALL RECORDS" */ if (db.activequery == 0) string = ""; else { key = 0; string[0] = 0; while((key <> CR) and (key <> ESC)) { puts(13, 15, "Enter description of query for header:", RGB(255, 255, 255), RGB(160,160,160)); key = getline(14, 15, 30, string, MenuColor_); if (key == ESC) return(0); } } /* build string for header from database name */ /* and query string, page no. appended later */ i = 1; PGHEAD = db.database; /* Strip drive & path from database name */ while ((match(PGHEAD, "\", (len(PGHEAD) - i), 1) == 0)) i = i + 1; PGHEAD = substr(PGHEAD, (len(PGHEAD) - i + 1)); PGHEAD = pad(PGHEAD + ": Query=" + chr(34)+trim(string)+chr(34), "C", 52); puts(13, 15, "Header:" + rep(" ", 40), RGB(0, 0, 0), RGB(160,160,160)); puts(14, 15, rep(" ", 40), RGB(0, 0, 0), RGB(160,160,160)); puts(14, 15, trim(PGHEAD), RGB(0, 0, 0), RGB(160,160,160)); /* Add date and 'Page ' for header to print */ PGHEAD = dtoc(today()) + PGHEAD + "Page "; /************************ MAIN LOOP ********************/ /* initialize screen and local variables for main loop */ key = 0; box(15, 24, 19, 57, '3D', RGB(120, 120, 120), RGB(160,160,160)); puts(18, 28, "Esc to cancel printing", RGB(0, 0, 0), RGB(160,160,160)); puts(16, 25, "Now processing", RGB(0, 0, 0), RGB(160,160,160)); /* Open, reset and initialize printer */ LP = open("PRN", "w"); string = RESET + chr(ESC) + "&l1h2a1o0E" + chr(ESC) + "(s016.66H" + chr(ESC) + "(10U"; write(LP, string, len(string)); /* process the current query until last */ /* record, or user hits the ESC key. */ for (j = first(db); j > 0; j = next(db)) { if (key == ESC) { /* Reset and close printer */ write(LP, RESET, 2); close(LP); return(0); } /* display document no. in process */ puts(16, 40, "document: ", RGB(0, 0, 0), RGB(160,160,160)); puts(16, 50, str(docno(db), 5, 0, ','), RGB(0, 0, 0), RGB(160,160,160)); cursor(24, 80); /* Print document number heading for this record */ /* skip last line in column if starting new doc */ if ((LCNT == 75) or (LCNT == 151)) lincnt(db); else { /* skip a line if in middle of page */ if ((LCNT <> 3) and (LCNT <> 79) and (LCNT <> 152)) lincnt(db); } /* increment line counter and build document header */ lincnt(db); codes = esccodes(0); line1 = DELIM1 + trim(str(docno(db), 6, 0, ',')); line2 = codes + pad((line1 + DELIM2), 'c', 70); write(LP, line2, len(line2)); /* Loop through each field for this record */ /* set up variables for field processing loop */ i = 1; RECHEAD = pad((line1 + " (cont.)" + DELIM2), 'c', 70); while((i <= db.fields) and (key <> ESC)) { if (fields[i]) { puts(17, 43, "field: ", RGB(0, 0, 0), RGB(160,160,160)); puts(17, 50, str(i, 5, 0, ','), RGB(0, 0, 0), RGB(160,160,160)); /* function printfield() processes line items. */ wrap(db->i, 80); printfield(db, i, LP); } /* Increment for the next field. */ i = i + 1; /* trap for Esc key pressed */ if (keypress()) key = getkey(); } /* all fields processed for this record; */ /* suppress continued message */ RECHEAD = ""; } /* all records processed for this query; */ /* Reset and close printer */ write(LP, RESET, 2); close(LP); } /* main() */ /**************************************************************** * Name: printfield * * Synopsis: print a field to file, each field type is * * handled separately. The data base "ftype" * * variable tells which type of field it is. * * Process text and paragraph fields line by line. * * Ignore empty fields, only process fields with * * data. Start by printing the field's name * * followed by a colon and a space, then print the * * rest of the field. * ****************************************************************/ printfield(int db, field, LP) { int offset, length, i, tloop; text line, codes, fieldText; switch(db.type[field]) { case 'P': case 'T': /* Handle fixed length Text and */ /* free text Paragraph fields here. */ if (len(db->field)) { lincnt(db); /* increment line counter */ codes = esccodes(0); line = codes + db.name[field] + ": "; write(LP, line, len(line)); fieldText = markhits(db->field,BoldOn,BoldOff); offset = findline(fieldText, 1, length); /* This while loop prints the contents */ /* of a fixed length or free text field. */ /* Variable tloop prevents the first pass */ /* through from incremeting line counter */ /* and setting new escape codes in order */ /* to append line to field label. */ tloop = 0; while(offset) { if (tloop == EOF) { lincnt(db); /* increment line counter */ codes = esccodes(265); } else { tloop = EOF; codes = ""; } write(LP,codes+addr(fieldText,offset),len(codes)+length); offset = findnline(fieldText, offset, length); } } case 'D': /* Handle date fields here. */ /* increment line counter */ lincnt(db); codes = esccodes(0); line = codes + db.name[field] + ": " + dtoc(db->field); write(LP, line, len(line)); case 'N': /* Handle numeric fields here. */ /* increment line counter */ lincnt(db); codes = esccodes(0); line = codes + db.name[field] + ": " + str(db->field, 6, 0); write(LP, line, len(line)); } } /* printfield() */ /**************************************************************** * Name: initialize * * Synopsis: Set global variables to initial values * * Action: Global variables are set for system calls; * * Initial screen drawn * ****************************************************************/ initialize() { int db; EOF = -1; ESC = 27; CR = 13; PG1FLG = EOF; LCNT = 152; PCNT = 0; RESET = chr(ESC) + "E"; RECHEAD = ""; DELIM1 = "*** Document "; DELIM2 = " ***"; messageBox("Compressed Query Print" + newline() + "by Steven Stewart" + newline() + "Database: "+db.database + newline() + "Printing Query No.: " + str(db.activequery) + newline() + "No. of Docs: " + str(count(db)), program(), MB_OK | MB_ICONINFORMATION); cursor(0,0); box(4, 10, 21, 70, "3U", RGB(120,120,120), RGB(160,160,160)); puts(6, 15, "Compressed Query Print", RGB(0, 0, 0), RGB(160,160,160)); puts(6, 38, "by Steven Stewart", RGB(0, 0, 0), RGB(160,160,160)); puts(8, 15, "Database:", RGB(0, 0, 0), RGB(160,160,160)); puts(9, 15, db.database, RGB(0, 0, 0), RGB(160,160,160)); puts(11, 15, "Printing Query No.:", RGB(0, 0, 0), RGB(160,160,160)); puts(11, 35, str(db.activequery, 3, 0, ','), RGB(0, 0, 0), RGB(160,160,160)); puts(11, 45, "No. of Docs:", RGB(0, 0, 0), RGB(160,160,160)); puts(11, 58, str(count(db), 5, 0, ','), RGB(0, 0, 0), RGB(160,160,160)); puts(19, 34, "Esc to cancel", RGB(0, 0, 0), RGB(160,160,160)); } /* initialize() */ /**************************************************************** * Name: esccodes * * Synopsis: Set escape codes to position line on page. * * Action: Builds string of escape codes for vertical * * and horizontal motion to position each line. * ****************************************************************/ esccodes(int indent) { int lcount, row, col; text outstr; lcount = LCNT; /* Set horizontal position: */ /* Switch between column 1 and 2 */ /* if line counter > 76 set column 2 */ if (lcount > 76) { col = 4000; lcount = lcount - 76; } else col = 150; /* vertical movement follows line counter */ row = ((76 * lcount) + 100); /* indent pushes horizontal position approx. 1/4" right */ outstr = chr(27) + "&a" + str(col + indent) + "h" + str(row) + "V"; return(outstr); } /* esccodes() */ /**************************************************************** * Name: lincnt * * Synopsis: Increment line counter and page counter * ****************************************************************/ lincnt(int db) { text codes, hdr; LCNT = LCNT + 1; if ((LCNT == 153) or (LCNT == 77)) { /* Send form feed if returning to first column, */ /* i.e., beginning odd page > 1 */ if (LCNT == 153) { if (PG1FLG == EOF) PG1FLG = 0; /* Set Page 1 flag off */ else write(LP, chr(12), 1); /* send form feed */ LCNT = 1; /* reset line counter */ } /* set up and print new page header */ PCNT = PCNT + 1; codes = esccodes(0); hdr = header(); write(LP, codes+hdr, len(codes)+len(hdr)); LCNT = LCNT + 2; if (RECHEAD <> "") { codes = esccodes(0); write(LP, codes+RECHEAD, len(codes)+len(RECHEAD)); LCNT = LCNT + 1; } } } /* lincnt() */ /**************************************************************** * Name: header * * Synopsis: Add page numbering to header string * ****************************************************************/ header() { text outstr; outstr = PGHEAD + trim(str(PCNT,4,0,',')); return(outstr); } /* header() */ char TRUE, FALSE; char NUMBER_COLUMN; char NAME_COLUMN; char TYPE_COLUMN; short LEFT, RIGHT, UP, DOWN, PGUP, PGDN, HOME, END, ALTS, ALTC; /************************************************************************ * name markfields() * * synopsis Mark or unmark fields as selected. * * description Fields are displayed and marked as selected or not * * selected. Display begins on row parameter, mode is * * display only if editmode parameter is not 'E'. * ************************************************************************/ markfields(int db; /* Handle to data base. */ char order[]; /* Array with order of selected fields. */ text prompt; /* Prompt displayed on top of screen. */ int minrow, /* Used with Display mode, shows fields.*/ editmode) /* Edits if 'E', displays if not 'E'. */ { int i, j; /* Misc. loop variables. */ int row; /* Row on screen being edited. */ int key; /* Key stroke pressed with each loop iteration. */ int field; /* Tracks which element of fs[] array is edited.*/ float fnumber; /* Only used for user's entry of numeric order. */ char fs[101]; /* Array used internally to edit field order. */ text screen; /* Saves calling function's screen. */ if (ver() >= 5.08) debug(-1); if ((db.documents < 0) and editmode) Message("Please open a data base first."); /* Initialize local global variables. */ screen = save(0,0,MaxRow_,79); NUMBER_COLUMN = 2; NAME_COLUMN = 10; TYPE_COLUMN = 27; ESC = 27; CR = 13; UP = 18432; LEFT = 19200; RIGHT = 19712; TRUE = 1; DOWN = 20480; PGUP = 18688; PGDN = 20736; HOME = 18176; END = 20224; ALTS = 7936; ALTC = 11776; /* Use the fs[] array to track the "fields selected". */ cursoroff(); if (editmode = (upper(chr(editmode)) == "E")) minrow = 2; for(i = 1; i <= db.fields; i = i + 1) fs[i] = order[i]; if (editmode) { cls(); puts(0,0,pad(prompt,'L',80),MenuColor_); } scroll(minrow + 1, 1, MaxRow_ - 1, 36, 0, 0, MenuBackground_); box(minrow, 0, MaxRow_, 37, "3D", MenuColor_, MenuBackground_); puts(minrow+1,1," Order Field Name Type ", MenuColor_, MenuBackground_); /* puts(minrow+2,1," ", MenuColor_, MenuBackground_); for (i = minrow + 3; i < MaxRow_; i = i + 1) puts(i,1," ", MenuColor_, MenuBackground_); puts(MaxRow_,1," ", MenuColor_, MenuBackground_); */ row = minrow+3; field = 1; update(db,field,row,fs,minrow); if (editmode and (db.documents >= 0)) { /* Print the instructions. */ box(2,43,10,77,'3D',TextColor_); puts( 3,53,"Selected Fields",TextHighlight_); puts( 4,45,"Select fields and their order"); puts( 5,45,"by marking them with [+] and [-]"); puts( 6,45,"keys. Unselected fields are not"); puts( 7,45,"used in functions which allow"); puts( 8,45,"field selection, such as print."); puts( 9,45,"You must select at least one."); box(12,43,22,77,'3D', TextColor_); puts(13,50,"How to Select Fields",TextHighlight_); puts(14,45,"Select a field [+]"); puts(15,45,"Deselect a field [-]"); puts(16,45,"Toggle field [Spacebar]"); puts(17,45,"Previous field [Up]"); puts(18,45,"Next field [Down]"); puts(19,45,"First field [Home]"); puts(20,45,"Clear all fields [C]"); puts(21,45,"Select all fields [S]"); puts(23,43,"Press [Enter] when you are finished.",TextHighlight_); key = 0; while ((key <> ESC) and (key <> CR)) { dpf(db,field,row,TextHighlight_[0],fs); if ((key = getkey()) == ' ') key = fs[field] ? '-' : '+'; switch(key) { case '+':/* User selected this field. ** Add it in if it isn't already. */ if (fs[field] == 0) { /* Scan for the highest number assigned. */ j = 0; for(i = 1; i <= db.fields; i = i + 1) if (j < fs[i]) j = fs[i]; /* Assign the next highest number to this field. */ fs[field] = j + 1; } break; case '-': j = fs[field]; fs[field] = 0; if (j) { for(i = 1; i <= db.fields; i = i + 1) if (fs[i] > j) fs[i] = fs[i] - 1; NewNumbers(db, field, row, fs, minrow, j); } default: break; } switch(key) { case '+': case '-': case DOWN: if (field < db.fields) { dpf(db,field,row,TextColor_[0],fs); field = field + 1; if (row < (MaxRow_ - 1)) row = row + 1; else scroll(minrow+3,1,MaxRow_ - 1,42,1,'U'); /* scroll page up */ } break; case UP: if (field > 1) { dpf(db,field,row,TextColor_[0],fs); field = field - 1; if (row > minrow+3) row = row - 1; else scroll(minrow+3,1,MaxRow_ - 1,42,1,'D'); /* Scroll page down. */ } break; case PGDN: for(i = minrow + 3; i < (MaxRow_ - 1); i = i + 1) if (field <> db.fields) field = field + 1; update(db,field,row,fs,minrow); break; case PGUP: for(i = minrow + 3; i < (MaxRow_ - 1); i = i + 1) if (field > 1) field = field - 1; if ((row - (minrow + 3) + 1) > field) field = (row - (minrow + 3)) + 1; update(db,field,row,fs,minrow); break; case HOME: field = 1; row = minrow+3; update(db,field,row,fs,minrow); break; case END: field = db.fields; row = minrow+3; update(db,field,row,fs,minrow); break; case 'S': case 's': for(i = 1; i <= db.fields; i = i + 1) fs[i] = i; update(db,field,row,fs,minrow); break; case 'c': case 'C': for(i = 1; i <= db.fields; i = i + 1) fs[i] = 0; update(db,field,row,fs,minrow); break; case ESC: case CR: break; default: key = key & 255; if (isdigit(key)) { /* Find the maximum number in the list. */ j = 0; for(i = 0; i <= db.fields; i = i + 1) if (j < fs[i] + 1) j = fs[i] + 1; if (j > db.fields) j = db.fields; if (j == 0) j = 1; fnumber = key - '0'; cursoron(); key = 0; while((key <> ESC) and (key <> CR)) key = getnumber(row,NUMBER_COLUMN,fnumber,0.0,j,5,0); cursoroff(); if (key <> ESC) { /* Remove the current number from the list if non-zero. */ if (j = fs[field]) { fs[field] = 0; for(i = 1; i <= db.fields; i = i + 1) if ((fs[i] >= j) and (fs[i] > 0)) fs[i] = fs[i] - 1; } /* Make room for the new number if non-zero. */ if (j = fnumber) for(i = 0; i <= db.fields; i = i + 1) if ((fs[i] >= j) and (fs[i] > 0)) fs[i] = fs[i] + 1; /* Store the new number and display changes. */ fs[field] = fnumber; update(db,field,row,fs,minrow); } key = 0; } break; } } /* while ((key <> ESC) and (key <> CR)) */ /* Copy the selected field orders to the calling ** function's array if the user pressed [Enter] ** to accept their changes. [Esc] ignores any ** changes. */ if (key == CR) for(i = 1; i <= db.fields; i = i + 1) order[i] = fs[i]; cls(); cursoron(); restore(0,0,screen); } return(key); } /* markfields() */ /************************************************************************ * name FieldType * * synopsis Return a text string describing the field's type. * ************************************************************************/ FieldType(int db, field) { switch(db.type[field]) { case 'T': return("Text"); break; case 'D': return("Date"); break; case 'N': return("Numeric"); break; case 'P': return("Paragraph"); break; default : return(""); break; } } /* FieldType() */ /************************************************************************ * name NewNumbers * * synopsis Helper function for markfields() * ************************************************************************/ NewNumbers(int db, field, row; char fs[]; int minrow, number) { int i; int fcode; fcode = field; for(i = row; i >= minrow + 3; i = i - 1) { if (fs[fcode] >= number) puts(i, NUMBER_COLUMN, fs[fcode] ? str(fs[fcode],4) : " "); fcode = fcode - 1; } fcode = field + 1; for(i = row + 1; i <= (MaxRow_ - 1); i = i + 1) { if (fs[fcode] >= number) puts(i, NUMBER_COLUMN, fs[fcode] ? str(fs[fcode],4) : " "); fcode = fcode + 1; } } /* NewNumbers() */ /************************************************************************ * name dpf * * synopsis Display print field, field and width option displayed. * * description Field definition pointed to by field is displayed on * * the screen row passed. If the field is invalid then * * the row is cleared. * ************************************************************************/ dpf(int db, field, row, color; char fs[]) { puts(row,1," ", color, MenuBackground_); if ((field <= db.fields) and (field > 0)) { puts(row,NUMBER_COLUMN, fs[field] ? str(fs[field],4) : " ", color, MenuBackground_); puts(row,NAME_COLUMN, pad(db.name[field],'L',14), color, MenuBackground_); puts(row,TYPE_COLUMN, pad(FieldType(db,field),'L',9), color, MenuBackground_); if (color == TextHighlight_[0]) puts(row,NUMBER_COLUMN, ">", color, MenuBackground_); } } /* dpf() */ /************************************************************************ * name update() * * description Helper function for markfields() * ************************************************************************/ update(int db, field, row; char fs[]; int minrow) { int i; int fcode; fcode = field; i = row; while(i >= minrow + 3) { dpf(db,fcode,i,TextColor_[0],fs); i = i - 1; fcode = fcode - 1; } fcode = field + 1; i = row + 1; while(i <= (MaxRow_ - 1)) { dpf(db,fcode,i,TextColor_[0],fs); i = i + 1; fcode = fcode + 1; } } /* update() */ RGB(char red, grn, blu) { return(((blu & 255) * 65536) | ((grn & 255) * 256) | (red & 255)); } /**************************************************************** * Name: Message * * Synopsis: Displays error message and waits for key. * ****************************************************************/ Message(text message) { text screen; int key; cursoroff(); screen = save(5,13,8,69); box(5,13,8,69,"DS", MenuColor_); puts(6,14,pad(message,'C',53),MenuColor_); key = getkey(); restore(5,13,screen); return(asc(upper(chr(key)))); } /* Message() */ /**************************************************************** * Global Variable Declarations and Initialization * ****************************************************************/ /* findfirst() file attributes. */ int A_NORMAL = 00; /* Normal file - No read/write restrictions */ int A_RDONLY = 01; /* Read only file */ int A_HIDDEN = 02; /* Hidden file */ int A_SYSTEM = 04; /* System file */ int A_VOLID = 08; /* Volume ID file */ int A_SUBDIR = 16; /* Subdirectory */ int A_ARCH = 32; /* Archive file */ /* edit() mode attributes. A // Alpha only mode. U // Upper case conversion. N // Numeric only mode. Y // Y mode for dates. M // M mode for dates. D // D mode for dates. C // Cut and paste mode. S // Scroll field left and right, no wordwrapping. E // Return on [Enter], no CR in data. T // Always edit from the top. B // Always edit from the bottom. @ // Display only this field. ! // Return when this field is entered, don't edit. N:99.99 */ int CTRLPGUP = 33792, F11 = 34048, F12 = 34304, EOF = -1; short LEFT = 19200, RIGHT = 19712, UP = 18432, DOWN = 20480, HOME = 18176, END = 20224, PGUP = 18688, PGDN = 20736, CTRLPGDN = 30208, F1 = 15104, F2 = 15360, F3 = 15616, F4 = 15872, F5 = 16128, F6 = 16384, F7 = 16640, F8 = 16896, F9 = 17152, F10 = 17408; char ESC = 27, CTRLP = 16, FALSE = 0, TRUE = 1, TAB = 9, CR = 13, LF = 10, FF = 12; /* Standard dialog button return values. */ int IDOK = 1; int IDCANCEL = 2; int IDABORT = 3; int IDRETRY = 4; int IDIGNORE = 5; int IDYES = 6; int IDNO = 7; /* MessageBox() display options. */ int MB_OK = 0; int MB_OKCANCEL = 1; int MB_ABORTRETRYIGNORE = 2; int MB_YESNOCANCEL = 3; int MB_YESNO = 4; int MB_RETRYCANCEL = 5; int MB_ICONHAND = 16; int MB_ICONQUESTION = 32; int MB_ICONEXCLAMATION = 48; int MB_ICONASTERISK = 64; int MB_ICONINFORMATION = MB_ICONASTERISK; int MB_ICONSTOP = MB_ICONHAND; int MB_DEFBUTTON1 = 0; int MB_DEFBUTTON2 = 256; int MB_DEFBUTTON3 = 512; int MB_APPLMODAL = 0; int MB_SYSTEMMODAL = 4096; int MB_TASKMODAL = 8192; int MB_NOFOCUS = 32768; /**********************************************************/ /* The first byte of every entry in the database.TRK file */ /* indicates the type of log entry and the type of event. */ /**********************************************************/ int LOGDELETION = 'D'; int LOGDELETION_OLD = 1 ; int LOGFIELDEDITED = 2 ; int LOGTAGADDED = 4 ; int LOGTAGDELETED = 8 ; int LOGEVENTSDELETED = 'P'; int LOGREINDEX = 'R'; int LOGSECURITYDELETION = 'S'; /********************************************************/ /* Definitions for the shellExecute() command. */ /********************************************************/ int SW_HIDE = 0; int SW_MINIMIZE = 6; int SW_RESTORE = 9; int SW_SHOW = 5; int SW_SHOWMAXIMIZED = 3; int SW_SHOWMINIMIZED = 2; int SW_SHOWMINNOACTIVE = 7; int SW_SHOWNA = 8; int SW_SHOWNOACTIVATE = 4; int SW_SHOWNORMAL = 1;