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 
 
}