www.pudn.com > commutil.zip > UTILITY.CPP
// ******************************************************************** //
// //
// UTILITY.CPP //
// Copyright (c) 1993, Michael Holmes and Bob Flanders //
// C++ Communication Utilities //
// //
// Chapter 7: Receiving a FAX //
// Last changed in chapter 7 //
// //
// This file contains the following miscellaneous routines. //
// status_line() update the status line //
// build_comm() build comm instance //
// terminal_handler() handle special terminal keys //
// terminal_display() display comm input stream //
// first_nonblank() find first non-blank character //
// ascii_encode() encode string w/control characters //
// quit_with() give an error message, then rtn to DOS //
// get_time() retrieve time of day in ticks //
// elapsed_time() calculate elapsed time in ticks //
// time_out() check for a timeout situation //
// wait() wait for a given number timer ticks //
// wait_ms() wait in milliseconds //
// malloc_chk() allocate memory with error checks //
// field_edit() edit a field in a window //
// delete_file() delete file any way possible //
// pad() pad a string to a length //
// touppers() translate string to uppercase //
// control_break() control break intercept routine //
// critical_rtn() DOS critical error handler //
// //
// ******************************************************************** //
#define TICKS_DAY 1573040L // number of ticks per day
/* ******************************************************************** *
*
* status_line() -- update the status line
*
* ******************************************************************** */
void status_line(void)
{
char msr; // modem status register
window(1, 25, 80, 25); // set up status window
_wscroll = 0; // disable scrolling
textcolor(FG(stat_cn)); // set up foreground
textbackground(BG(stat_cn)); // ..and background colors
msr = comm->Modem(); // get modem status register
cprintf(stat_format, // write current status line
com_ports[comport].name, // ..including selected port
line[SPEED].lp->parm, // ..selected baud rate
line[DATA].lp->parm, // ..data bits
line[PARITY].lp->parm, // ..parity
line[STOP].lp->parm, // ..and stop bits
msr & MSR_CD ? "CD" : " ", // ..carrier detect
msr & MSR_CTS ? "CTS" : " ", // ..clear to send
comm->IFlow() ? " " : "RTS"); // ..request to send
last_window = 0; // clear last window accessed
window(1, 1, 80, 25); // ..and reset for full screen
}
/* ******************************************************************** *
*
* build_comm() -- build comm instance with current parameters
*
* ******************************************************************** */
void build_comm()
{
if (comm) // q. using a port already?
comm->~Comm(); // a. yes .. close it down
comm = new Comm( // build a Comm instance
com_ports[comport].port, // ..with base port address
com_ports[comport].irq, // ..and interrupt number
line[SPEED].lp->value, // ..baud rate divisor
line[PARITY].lp->value | // ..line control values
line[DATA].lp->value | // ..including parity,
line[STOP].lp->value, // ..data and stop bits
flowctl, 4096, 512); // ..and flow control flag
comm->Write(CMD_EXECUTE); // execute previous command
wait_ms(250); // .. let it execute
comm->Write(CMD_EXECUTE); // .. and.. kill it.
comm->Write(CMD_INIT); // send modem init string
comm->Write(CMD_EXECUTE); // .. execute init command
}
/* ******************************************************************** *
*
* terminal_handler() -- handle terminal input
*
* ******************************************************************** */
void terminal_handler(void)
{
int key; // extended keyboard character
if (comm->ModemChanged()) // q. time to update status?
{
status_line(); // a. yes .. do a status update
term->MakeCurrent(); // ..and reposition cursor
}
if ((key = get_key(ALLOW_ALT)) == 0) // q. get a valid key?
return; // a. no .. just return
if (key >= 0x100) // q. alt or function key?
{ // a. yes .. check validity
if (main_menu.ValidateKey(key)) // q. valid for main menu?
{
main_menu.Display(key); // a. yes .. display menu
term->MakeCurrent(); // reposition cursor
return; // ..then return to caller
}
}
switch (key) // handle special keys
{
case F1: // clear screen request
term->Clear(); // clear terminal window
break; // ..and continue
default:
if (key >= 0x100) // q. special key?
{
printf(BELL); // a. yes .. give error beep
break; // ..and continue
}
comm->Write(key); // else .. send out com port
}
}
/* ******************************************************************** *
*
* terminal_display() -- display comm input stream
*
* ******************************************************************** */
void terminal_display(void)
{
int i; // loop counter
char c, // input character
msr, // modem status register
lsr, // line status register
buf[40]; // work buffer
if ((i = comm->Read(&c, &msr, &lsr)) == -1) // q. get a comm character?
return; // a. no .. just return
if (i) // q. buffer overflow?
{
sprintf(buf, overflow_msg, i); // a. yes .. prepare msg
term->DisplayReverse(buf); // ..and give to user
return; // ..then return to caller
}
if ((lsr &= LSR_ERROR) != 0) // q. any errors?
for (i = 0, lsr >>= 1; lsr; // a. yes .. loop thru and
i++, lsr >>= 1) // ..display error messages
if (lsr & 1) // q. recognize this error?
term->DisplayReverse( // a. yes .. display error msg
line_error[i]); // ..from message table
if (c) // q. null character?
term->Display(c); // a. no .. display character
}
/* ******************************************************************** *
*
* first_nonblank() -- find first non-blank character
*
* ******************************************************************** */
char *first_nonblank(char *s) // string to look through
{
for (; *s; s++) // loop thru string
if (NOT isspace(*s)) // q. find a non-blank char?
return(s); // a. yes .. return w/address
return(0); // else .. string is blank
}
/* ******************************************************************** *
*
* ascii_encode() -- encode string w/control characters
*
* ******************************************************************** */
char *ascii_encode(char *s) // string to encode
{
char *p, *q; // work pointers
for (p = q = s; // work across input string
*s == ' ' || *s == '='; s++) // ..skipping leading blanks
; // ..and delimiting equals
for (; *s; s++) // work across rest of the
{ // ..input string
if (*s == ';') // q. hit start of comment?
break; // a. yes .. exit loop
if (*s != '^') // q. control character?
{
*p++ = *s; // a. no .. just copy
continue; // ..and process next one
}
s++; // move on to next input char
if (*s == '^' || *s == ';') // q. special characters?
{
*p++ = *s; // a. yes .. just copy
continue; // ..and process next one
}
*p++ = *s & 0x1f; // make into control char
}
*p = '\0'; // terminate encoded string
return(q); // ..and return string addr
}
/* ******************************************************************** *
*
* quit_with() -- give an error message, then return to DOS
*
* ******************************************************************** */
void quit_with(char *msg, ...) // quit with an error message
{
va_list list; // variable list
if (full_screen) // q. in full screen mode?
{
term->Close(); // a. yes .. close term window
window(1, 1, 80, max_lines); // set up termination screen
textcolor(FG(mono_1)); // ..with foreground
textbackground(BG(mono_1)); // ..and background colors
clrscr(); // ..and clear screen
CURSOR(); // ..and set cursor to normal
printf(copyright); // display program banner
}
if (comm) // q. comm object created?
comm->~Comm(); // a. yes .. call destructor
_dos_setvect(0x1b, old_break); // restore old ^break handler
va_start(list, msg); // set up variable list
vprintf(msg, list); // give error message ..
exit(rc); // ..and then quit
}
/* ******************************************************************** *
*
* time_out() -- check for a timeout event
*
* ******************************************************************** */
int time_out(long *n) // time to wait in ticks
{
static unsigned
long far *timer = (unsigned long far *) // BIOS timer tick counter
MK_FP(0x40, 0x6c), // ..down in low memory
last, // last accessed time
work; // work variable
work = *timer; // get current time
if (*n > 0) // q. first time call?
{
*n = -*n; // a. yes .. change sign
last = work; // ..and initialize counters
}
if (work != last) // q. time pass?
{ // a. yes .. see how much
if (work <= last) // q. clock go past midnite?
(*n)++; // a. yes .. count as 1 tick
else
*n += (UINT)(work - last); // else .. count everything
last = work; // start again w/curr time
}
return(*n >= 0L); // return TRUE at timeout time
}
/* ******************************************************************** *
*
* get_time() -- retrieve the time in ticks
*
* ******************************************************************** */
ULONG get_time(void) // retrieve time in ticks
{
static
ULONG far *timer = (unsigned long far *) // BIOS timer tick counter
MK_FP(0x40, 0x6c); // ..down in low memory
return(*timer); // return current value
}
/* ******************************************************************** *
*
* elapsed_time() -- return elapsed time in ticks
*
* ******************************************************************** */
ULONG elapsed_time(ULONG st) // start time in ticks
{
static
ULONG far *timer = (unsigned long far *) // BIOS timer tick counter
MK_FP(0x40, 0x6c); // ..down in low memory
if (st > *timer) // q. start time greater?
return((TICKS_DAY - st) + *timer); // a. yes .. add in rollover;
else
return(*timer - st); // return elapsed ticks
}
/* ******************************************************************** *
*
* wait() -- wait for a given number of timer ticks
*
* ******************************************************************** */
void wait(long n) // time to wait in ticks
{
long far *timer = (long far *) // BIOS timer tick counter
MK_FP(0x40, 0x6c), // ..down in low memory
start, work; // start tick count
start = *timer; // get current time
while (n > 0) // loop 'til n ticks past
{
if ((work = *timer) != start) // q. time pass?
{ // a. yes .. see how much
if (work < start) // q. clock go past midnite?
n--; // a. yes .. count as 1 tick
else
n -= (UINT)(work - start); // else .. count everything
start = work; // start again w/curr time
}
else
kbhit(); // else .. check keyboard
}
}
/* ******************************************************************** *
*
* wait_ms() -- wait in milliseconds
*
* ******************************************************************** */
void wait_ms(long ms) // milliseconds to wait
{
wait((ms + 54) / 55); // convert then wait in ticks
}
/* ******************************************************************** *
*
* malloc_chk() -- allocate memory with error processing
*
* ******************************************************************** */
void *malloc_chk(int s) // size to allocate
{
void *p; // work pointer
if ((p = malloc(s)) == 0) // q. out of memory?
quit_with(no_memory, s); // a. yes .. give error msg
return(p); // finally rtn with pointer
}
/* ******************************************************************** *
*
* field_edit() -- edit a string field in a window
*
* ******************************************************************** */
int field_edit(Window *win, // window to work in
int c, int r, // initial column and row
char **s, // initial field data
int m) // maximum field length
{
int i, // string index
k, // keyboard input
x, // current column
ins; // insert flag
char *org, // original string pointer
*w, // work string pointer
b[80]; // work buffer
org = *s; // get initial field data
w = (char *) malloc_chk(m + 1); // allocate work string
memset(w, ' ', m); // clear to blanks
w[m] = 0; // ..and make a string
ins = 0; // clear insert flag
if (org) // q. orig data available?
strncpy(w, org, strlen(org)); // a. yes .. copy to work
CURSOR(); // turn cursor on
win->AtSayReverse(c, r, w); // ..display field
win->GotoXY(x = c, r); // locate start of field
for(;;) // loop till user quits
{
while (NOT (k = get_key(NO_ALT))) // wait for a key
; // ..before continuing
switch (k) // handle user's input
{
case LEFT: // left key
if (--x < c) // q. past left margin?
x = c; // a. yes .. reset
break; // ..then get next key
case RIGHT: // right key
if (++x >= (m + c - 1)) // q. past right margin?
x = m + c - 1; // a. yes .. reset
break; // ..then get next key
case BACKSPACE: // backspace
if (x == c) // q. at top of window?
{
printf(BELL); // a. yes .. give warning
break; // ..and wait for another..
}
x--; // move left one character
// ..and fall into delete key
case DELETE: // delete key
i = x - c; // set up string index
strcpy(&w[i], &w[i + 1]); // simulate delete
w[m - 1] = ' '; // ..and put a blank at end
sprintf(b, "%s", &w[i]); // make into string
win->AtSayReverse(x, r, b); // ..display remainder
break; // ..and wait for next key
case HOME: // home key
x = c; // reset pointer to start
break; // ..and wait for next key
case END: // end key
x = c + m - 1; // reset pointer to end
break; // ..and wait for next key
case CR: // carriage return
case UP: // up arrow key
case DOWN: // down arrow key
NOCURSOR(); // turn cursor off
free(org); // release original data
*s = w; // store addr of new data
win->AtSay(c, r, w); // ..display field normally
return(DOWN); // ..then return to caller
case ESC: // escape key
NOCURSOR(); // turn cursor off
win->AtSay(c, r, w); // ..display field normally
free(w); // release work copy
return(0); // ..then return to caller
case INSERT: // insert toggle
if (ins) // q. insert mode active?
{
ins = 0; // a. yes .. turn it off
CURSOR(); // ..and use proper cursor
}
else
{
ins = 1; // else .. set on insert
BIGCURSOR(); // ..and show insert cursor
}
break; // then wait for next key
default: // error case
if (k & 0xff00 || // q. function key..
k < ' ') // ..or less than a blank?
{
printf(BELL); // a. yes .. ring the bell
break; // ..and wait for next key
}
i = x - c; // get string index
if (ins) // q. insert mode active?
{
memmove(&w[i + 1], &w[i], // a. yes .. move everything
m - i); // ..for the remainder over
w[m] = 0; // ..and overlay the overflow
w[i] = (char) k; // put new char its place
sprintf(b, "%s", &w[i]); // make into a displayable
}
else
{
w[i] = (char) k; // save character in string
sprintf(b, "%c", k); // make into a string
}
win->AtSayReverse(x, r, b); // display new char/string
if (i < (m - 1)) // q. up to right margin?
x++; // a. no .. advance one
break; // ..then get next key
}
win->GotoXY(x, r); // ..then go there
}
}
/* ******************************************************************** *
*
* delete_file() -- delete file any way necessary
*
* ******************************************************************** */
int delete_file(char *s) // filename to delete
{
int rc; // return code, 0=ok
if ((rc = unlink(s)) != 0) // q. regular unlink work?
{ // a. no .. change attributes
if (NOT (rc = chmod(s, S_IWRITE))) // q. change work?
rc = unlink(s); // a. yes .. try delete again
}
return(rc); // return with final status
}
/* ******************************************************************** *
*
* pad() -- pad a string to a length
*
* ******************************************************************** */
void pad(char *s, // target string
int len) // final length
{
int i; // calculated pad length
i = strlen(s); // get current length
if (i < len) // q. need padding?
{
len -= i; // a. yes .. get pad length
memset(&s[i], ' ', len); // ..blank out rest
}
s[len] = 0; // ..and terminate string
}
/* ******************************************************************** *
*
* touppers() -- translate all characters to uppercase
*
* ******************************************************************** */
void touppers(char *s) // string to translate
{
while (*s) // for each char in string
{
*s = toupper(*s); // .. translate to uppercase
s++; // .. and go to next char
}
}
/* ******************************************************************** *
*
* control_break() -- control break intercept routine
*
* ******************************************************************** */
#pragma option -O2-b-e // no global reg allocation
// ..or dead code elimination
void interrupt control_break(...)
{
asm mov al, 20 // al = end of interrupt cmd
asm out 20, al // clear kb interrupt on 8259
}
/* ******************************************************************** *
*
* critical_rtn() -- DOS critical error handler
*
* ******************************************************************** */
#pragma option -O2-b-e // no global reg allocation
// ..or dead code elimination
void interrupt critical_routine(...)
{
if (_AX & 0x800) // q. fail allowed?
_AX = (_AX & 0xff00) | 3; // a. yes .. show failed
else
_AX = (_AX & 0xff00) | 2; // else .. abort
}