FCONVERT.CPP
上传用户:xr_qian
上传日期:2007-01-05
资源大小:443k
文件大小:31k
源码类别:

通讯/手机编程

开发平台:

DOS

  1. // ******************************************************************** //
  2. //                                                                      //
  3. //      FCONVERT.CPP                                                    //
  4. //      Copyright (c) 1993, Michael Holmes and Bob Flanders             //
  5. //      C++ Communication Utilities                                     //
  6. //                                                                      //
  7. //      This file contains the routines for converting to and           //
  8. //      from the G3 fax format.                                         //
  9. //                                                                      //
  10. // ******************************************************************** //
  11. //
  12. //  Conversion Routine Globals
  13. //
  14. int     f_handle = -1,                      // G3 file handle
  15.         f_pgcnt,                            // maximum page count
  16.         f_write_flag,                       // write_out bit buffer flag
  17.         f_write_cnt;                        // write_out global counter
  18. char   *f_buffer,                           // work buffer
  19.        *f_ptr,                              // ..and current pointer
  20.         f_filename[MAX_PATH];               // fax filename
  21. long    f_page;                             // current G3 page size
  22. #define HDR_LEN     128                     // header length
  23. #define BUF_SIZE    256                     // buffer size
  24. /* ******************************************************************** *
  25.  *
  26.  *  f_locate() -- find a G3 formatted file and check its integrity
  27.  *
  28.  *  returns: 0 = file opened
  29.  *           1 = file not found
  30.  *
  31.  * ******************************************************************** */
  32. int     f_locate(char *s)                   // source filename
  33. {
  34. long    file_size,                          // file size
  35.         pos;                                // current file position
  36. if (f_handle != -1)                         // q. already open?
  37.     {
  38.     close(f_handle);                        // a. yes .. close file
  39.     f_handle = -1;                          // ..and clear flag
  40.     }
  41. if (NOT first_nonblank(s))                  // q. empty string?
  42.     return(1);                              // a. yes .. just return
  43. if ((f_handle = open(s,                     // q. find and open file ok?
  44.             _O_RDONLY | _O_BINARY)) == -1)
  45.     return(1);                              // a. no .. return w/error
  46. file_size = lseek(f_handle, 0L, SEEK_END);  // get file size
  47. lseek(f_handle, 0L, SEEK_SET);              // ..and back to file start
  48. if ((read(f_handle, page, 128) != 128) ||   // q. file header available
  49.         strncmp((char *) page, "G3", 2))    // ..and our format?
  50.     {
  51.     close(f_handle);                        // a. no .. just close file
  52.     f_handle = -1;                          // ..clear flag
  53.     return(1);                              // ..and return to caller
  54.     }
  55. pos = lseek(f_handle, 0L, SEEK_CUR);        // get starting position
  56. for (f_pgcnt = 0;;)                         // count available fax pages
  57.     {
  58.     if (read(f_handle, (char *) &f_page,    // q. read in enough to cover
  59.             sizeof(long)) != sizeof(long))  // ..the page length field?
  60.         break;                              // a. no .. exit loop
  61.     if ((f_page < 1) ||                     // q. page size non-positive?
  62.         ((f_page + pos + 4) > file_size))   // ..or bigger than the file?
  63.         break;                              // a. yes .. exit loop
  64.     if ((pos = lseek(f_handle, f_page,      // q. properly position to the
  65.             SEEK_CUR)) == -1L)              // ..start of the next page?
  66.         break;                              // a. no .. exit loop
  67.     f_pgcnt++;                              // count this page
  68.     }
  69. strcpy(f_filename, s);                      // save filename ..
  70. return(0);                                  // ..then return all ok
  71. }
  72. /* ******************************************************************** *
  73.  *
  74.  *  f_get_next_byte() -- get the next byte from the G3 file
  75.  *
  76.  *  returns: -1 = end of data or error
  77.  *            n = next byte
  78.  *
  79.  * ******************************************************************** */
  80. int     f_get_next_byte(void)
  81. {
  82. static
  83. int     rb;                                 // remaining buffer count
  84. if (f_ptr == 0 || rb == 0)                  // q. 1st call or out of data?
  85.     {                                       // a. yes .. get the next blk
  86.     if (f_page == 0)                        // q. out of data to read?
  87.         return(-1);                         // a. yes .. return all done
  88.     if (f_buffer == 0)                      // q. buffer allocated?
  89.         f_buffer = (char *)                 // a. no .. get a buffer
  90.                  malloc_chk(BUF_SIZE);
  91.     rb = (int)((f_page > BUF_SIZE) ?        // set count to smaller of
  92.                 BUF_SIZE : f_page);         // ..what's left or buffer size
  93.     if (read(f_handle, f_buffer, rb) != rb) // q. file read ok?
  94.         quit_with(read_error);              // a. no .. give error message
  95.     f_page -= rb;                           // deduct what was read
  96.     f_ptr = f_buffer;                       // set up character pointer
  97.     }
  98. rb--;                                       // decriment remaining count
  99. return(*(unsigned char *) f_ptr++);         // ..and return character
  100. }
  101. /* ******************************************************************** *
  102.  *
  103.  *  f_get_byte() -- get the next value from the G3 file handling DLEs
  104.  *
  105.  *  returns: -1 = end of data or error
  106.  *            n = next byte
  107.  *
  108.  * ******************************************************************** */
  109. int     f_get_byte(void)
  110. {
  111. int     v;                                  // work value
  112. while (1)
  113.     {
  114.     if ((v = f_get_next_byte()) == -1)      // q. out of data?
  115.         return(-1);                         // a. yes .. return EOF
  116.     if (v == DLE)                           // q. DLE character?
  117.         {                                   // a. yes .. get another
  118.         if ((v = f_get_next_byte()) == -1)  // q. get another char ok?
  119.             return(-1);                     // a. no .. return EOF
  120.         if (v == DLE)                       // q. another DLE?
  121.             return(v);                      // a. yes .. return the goods
  122.         }
  123.      else
  124.         return(v);                          // else .. return w/character
  125.     }
  126. }
  127. /* ******************************************************************** *
  128.  *
  129.  *  f_get_bit() -- get the next bit from the G3 file
  130.  *
  131.  *  returns: -1 = end of data or error
  132.  *            0 = zero bit found
  133.  *            1 = one bit found
  134.  *
  135.  * ******************************************************************** */
  136. int     f_get_bit(void)
  137. {
  138. static
  139. int     w,                                  // work byte
  140.         c = 0;                              // bit count
  141. w >>= 1;                                    // move next bit into place
  142. if (f_ptr == 0 || c == 0)                   // q. 1st call or out of data?
  143.     {                                       // a. yes .. get a byte
  144.     if ((w = f_get_byte()) == -1)           // q. out of data?
  145.         return(-1);                         // a. yes .. return EOF
  146.     c = 8;                                  // number of available bits
  147.     }
  148. c--;                                        // show another one used
  149. return(w & 1);                              // ..then rtn a bit to caller
  150. }
  151. /* ******************************************************************** *
  152.  *
  153.  *  f_search() -- search for a codeword match
  154.  *
  155.  *  returns: -2 = end of line or error
  156.  *           -1 = no match found
  157.  *            n = match found, n is nbr of bits in codeword
  158.  *
  159.  * ******************************************************************** */
  160. int     f_search(int type,                  // type of code
  161.                                             //  0 = white space
  162.                                             //  1 = black space
  163.                  int l,                     // length in bits
  164.                  int a)                     // accumulator
  165. {
  166. struct  code_entry *e;                      // codeword table entries
  167. if (l == 12 && a == 1)                      // q. end of line found?
  168.     return(-2);                             // a. yes .. return to caller
  169. if ((e = code_table[l - 1][type]) != 0)     // q. table entry found?
  170.     {                                       // a. yes .. check table
  171.     for (; e->code; e++)                    // scan a codeword table
  172.         if (e->code == a)                   // q. find a codeword match?
  173.             return(e->value);               // a. yes .. return
  174.     }
  175. if (l == 13)                                // q. reach max codeword size?
  176.     return(-2);                             // a. yes .. return w/error
  177.  else
  178.     return(-1);                             // else .. rtn nothing found
  179. }
  180. /* ******************************************************************** *
  181.  *
  182.  *  f_get_code() -- get the next codeword from the G3 stream
  183.  *
  184.  *  returns: 0 = converted next word ok
  185.  *           1 = error or end of line
  186.  *
  187.  * ******************************************************************** */
  188. int     f_get_code(int type,                // type of code
  189.                                             //  0 = white space
  190.                                             //  1 = black space
  191.                    int *len)                // length in bits
  192. {
  193. int     a = 0,                              // accumulator
  194.         b,                                  // one bit work area
  195.         l = 0;                              // working length
  196. while (1)
  197.     {
  198.     if ((b = f_get_bit()) == -1)            // q. get a bit successfully?
  199.         return(1);                          // a. no .. must be out of data
  200.     a = (a << 1) | b;                       // shift in a new bit
  201.     l++;                                    // ..tally up bits received
  202.     switch (*len = f_search(type, l, a))    // check for match
  203.         {
  204.         case -2:                            // end of line or error
  205.             return(1);                      // ..just return
  206.         case -1:                            // nothing found
  207.             break;                          // ..continue looping
  208.         default:                            // found codeword
  209.             return(0);                      // ..return ok
  210.         }
  211.     }
  212. return(0);                                  // make MSC C/C++ happy
  213. }
  214. /* ******************************************************************** *
  215.  *
  216.  *  f_get_pels() -- get the next group of PELS from the G3 stream
  217.  *
  218.  *  returns: 0 = converted next word ok
  219.  *           1 = error or end of line
  220.  *
  221.  * ******************************************************************** */
  222. int     f_get_pels(int type,                // type of code
  223.                                             //  0 = white space
  224.                                             //  1 = black space
  225.                    int *len)                // length in bits
  226. {
  227. int     a = 0;                              // accumulator
  228. while (1)
  229.     {
  230.     if (f_get_code(type, len))              // q. get a code word?
  231.         return(1);                          // a. no .. must be out of data
  232.     if (*len > 63)                          // q. get a makeup code?
  233.         a = *len;                           // a. yes .. save for later
  234.      else
  235.         {
  236.         *len += a;                          // else .. add in any makeups
  237.         return(0);                          // ..and return all ok
  238.         }
  239.     }
  240. }
  241. /* ******************************************************************** *
  242.  *
  243.  *  f_get_eol() -- read to end of line in current page
  244.  *
  245.  * ******************************************************************** */
  246. void    f_get_eol(void)
  247. {
  248. int     a,                                  // accumulator
  249.         b;                                  // work bit
  250. for (a = 0xfff; a != 1;)                    // try to find an EOL bit
  251.     {                                       // ..pattern of 000000000001
  252.     if ((b = f_get_bit()) == -1)            // q. get a bit successfully?
  253.         return;                             // a. no .. must be out of data
  254.     a = ((a << 1) | b) & 0xfff;             // move in new bit
  255.     }
  256. }
  257. /* ******************************************************************** *
  258.  *
  259.  *  f_read_g3() -- read a page and convert from G3 format
  260.  *
  261.  *  returns: 0 = page converted sucessfully
  262.  *           1 = page not found or error
  263.  *
  264.  * ******************************************************************** */
  265. int     f_read_g3(int n)                    // page number
  266. {
  267. int     pels,                               // pixels counter
  268.         lines,                              // lines counter
  269.         type,                               // type of codeword
  270.         codes,                              // codewords processed
  271.         eol,                                // consecutive EOLs found
  272.         l = 0;                              // work length
  273. char    huge *p;                            // bitmap line pointer
  274. lseek(f_handle, HDR_LEN, SEEK_SET);         // get to start of 1st page
  275. while(1)                                    // loop to find requested page
  276.     {
  277.     if (read(f_handle, (char *) &f_page,    // q. read in enough to cover
  278.             sizeof(long)) != sizeof(long))  // ..the page length field?
  279.         return(1);                          // a. no .. return not found
  280.     if (--n == 0)                           // q. find target page?
  281.         break;                              // a. yes .. exit loop
  282.     if (lseek(f_handle, f_page,             // q. properly position to the
  283.             SEEK_CUR) == -1L)               // ..start of the next page?
  284.         return(1);                          // a. no .. return not found
  285.     }
  286. f_ptr = 0;                                  // set global pointer
  287. f_get_eol();                                // find end of first line
  288. for (lines = 0, p = page;                   // for the whole bitmap
  289.             lines < LINES;                  // ..run through line
  290.             lines++, p += LINE)             // ..by line
  291.     memset(p, 0, LINE);                     // ..and clear white space
  292. for (lines = 0, p = page, eol = 0;          // fill in each line in the
  293.             lines < LINES;                  // ..bitmap page by processing
  294.             lines++, p += LINE)             // ..one line at a time
  295.     {
  296.     for (pels = 0, type = 0, codes = 0;     // for each bit available
  297.                 pels < PELS;                // ..in the bitmap line get
  298.                 pels += l, codes++)         // ..codewords and convert
  299.         {
  300.         if (f_get_pels(type, &l))           // q. end of line found?
  301.             break;                          // a. yes .. exit loop
  302.         if (l > (PELS - pels))              // q. too much data?
  303.             l = PELS - pels;                // a. yes .. set to max
  304.         if (type)                           // q. black bits?
  305.             set_bits(p, pels, l);           // a. yes .. set bits on
  306.         type = (type + 1) & 1;              // switch back and forth
  307.         }                                   // ..between black and white
  308.     f_get_eol();                            // find the end of this line
  309.     if (NOT codes)                          // q. empty line?
  310.         {
  311.         eol++;                              // a. yes .. tally empty lines
  312.         if (eol == 6)                       // q. find the end of page?
  313.             break;                          // a. yes .. finish looping
  314.         }
  315.      else
  316.         eol = 0;                            // else .. clear EOL counter
  317.     }
  318. return(0);                                  // finally, return ok
  319. }
  320. /* ******************************************************************** *
  321.  *
  322.  *  f_write_hdr() -- write a fax file header
  323.  *
  324.  * ******************************************************************** */
  325. void    f_write_hdr(void)
  326. {
  327. char    buf[HDR_LEN];                       // header buffer
  328. memset(buf, 0, HDR_LEN);                    // clear buffer to nulls
  329. strcpy(buf, "G3");                          // ..and put in our marker
  330. write(f_handle, buf, HDR_LEN);              // write header
  331. }
  332. /* ******************************************************************** *
  333.  *
  334.  *  f_write_out() -- write bits to output fax file
  335.  *
  336.  * ******************************************************************** */
  337. void    f_write_out(int bits,               // output bits
  338.                     int len)                // ..and number of bits
  339. {
  340. static  unsigned
  341. char    w;                                  // byte wide queue
  342. if (len > 16)                               // q. too many bits?
  343.     return;                                 // a. yes .. just return
  344. bits <<= 16 - len;                          // shift to MSB end of word
  345. while (len--)                               // while there is input
  346.     {
  347.     w >>= 1;                                // shift queue over by one
  348.     if (bits & 0x8000)                      // q. source bit on?
  349.         w |= 0x80;                          // a. yes .. turn on dest
  350.     if (++f_write_flag == 8)                // q. reach limit?
  351.         {
  352.         write(f_handle, (void *) &w, 1);    // a. yes .. write a byte
  353.         if (w == DLE)                       // q. special character?
  354.             write(f_handle, (void *) &w, 1);// a. yes .. write it again
  355.         f_write_flag = 0;                   // clear the flag
  356.         f_write_cnt++;                      // ..and tally the byte
  357.         }
  358.     bits <<= 1;                             // shift source by one bit
  359.     }
  360. }
  361. /* ******************************************************************** *
  362.  *
  363.  *  f_encode() -- encode a string of bits into G3 format
  364.  *
  365.  * ******************************************************************** */
  366. void    f_encode(int cnt,                   // number of bits from bitmap
  367.                  int type)                  // ..and bit color
  368. {
  369. struct  encode_entry *ee;                   // encode entry
  370. if (cnt > 63)                                   // q. big run of bits?
  371.     {
  372.     ee = &encode_table[(cnt / 64) + 63][type];  // a. yes .. get pointer
  373.     f_write_out(ee->code, ee->bits);            // ..write make-up code
  374.     cnt %= 64;                                  // ..and update bit count
  375.     }
  376. ee = &encode_table[cnt][type];              // get element pointer
  377. f_write_out(ee->code, ee->bits);            // write terminating code
  378. }
  379. /* ******************************************************************** *
  380.  *
  381.  *  f_scan_out() -- scan the bitmap and output a codeword
  382.  *
  383.  * ******************************************************************** */
  384. int     f_scan_out(char huge *p,            // bitmap line
  385.                    int  i,                  // starting bit offset
  386.                    int  type)               // type to search
  387. {
  388. int     cnt;                                // work counter
  389. for (cnt = 0; i < PELS; i++, cnt++)         // scan bitmap line
  390.     if (get_bit(                            // q. find a bit which is not
  391.             (unsigned char *) p, i) != type)// ..the same as type?
  392.         break;                              // a. yes .. exit loop
  393. f_encode(cnt, type);                        // build/output codeword
  394. return(cnt);                                // ..then return with count
  395. }
  396. /* ******************************************************************** *
  397.  *
  398.  *  f_write_page() -- write a fax file page
  399.  *
  400.  * ******************************************************************** */
  401. void    f_write_page(Window *w)             // window to display msgs in
  402. {
  403. int     i, j = 0,                           // loop counter
  404.         line,                               // line counter
  405.         type;                               // pixel type
  406. char    buf[60],                            // work buffer
  407.         huge *p;                            // ..and pointer
  408. long    start_pos,                          // page starting position
  409.         page_len;                           // ..and page length
  410. static
  411. long    percent,                            // percent complete
  412.         last,                               // last display time
  413.         far *timer = (long far *)           // BIOS timer tick counter
  414.                         MK_FP(0x40, 0x6c);  // ..down in low memory
  415. lseek(f_handle, 0L, SEEK_END);              // goto end of file
  416. start_pos = tell(f_handle);                 // ..and get position info
  417. memset(buf, 0, sizeof(buf));                // clear buffer to nulls
  418. write(f_handle, buf, 4);                    // write page length
  419. write(f_handle, buf, 10);                   // ..and some nulls
  420. f_write_flag = 0;                           // clear output flag
  421. f_write_out(1, 12);                         // ..and write an EOL
  422. for (p = page, line = 0; line < LINES;      // for each line in the bitmap
  423.             line++, p += LINE)              // ..encode into G3 format
  424.     {
  425.     f_write_cnt = 0;                        // clear output byte count
  426.     if ((*timer - last) > 9)                // q. has half a second past?
  427.         {
  428.         percent = (line * 100L) / LINES;    // a. yes .. get percentage
  429.         sprintf(buf, write_msg,             // build status message
  430.                 f_pgcnt, percent);          // ..into a work buffer
  431.         w->Display(buf);                    // ..display the message
  432.         last = *timer;                      // ..and pickup current time
  433.         }
  434.     if (reverse_scan((char *) p, 0, LINE))  // q. anything on line?
  435.         {                                   // a. yes .. process
  436.         for (i = type = 0; i < PELS; i += j)// scan across the bitmap line
  437.             {
  438.             j = f_scan_out(p, i, type);     // scan bitmap for pixels
  439.             type = (type + 1) & 1;          // flip-flop the type code
  440.             }
  441.         }
  442.      else
  443.         f_encode(1728, 0);                  // else .. put out blank line
  444.     if (f_write_flag)                       // q. any residual bits?
  445.         f_write_out(0, 8 - f_write_flag);   // a. yes .. put out the rest
  446.     if (i < 40)                             // q. need to pad out line?
  447.         write(f_handle, (void *) &buf,      // a. yes .. write a string
  448.                 40 - i);                    // ..of up to 40 null bytes
  449.     f_write_out(1, 12);                     // then put out an EOL
  450.     }
  451. for (i = 0; i < 5; i++)                     // at end of page
  452.     f_write_out(1, 12);                     // ..put out 5 more EOLs
  453. buf[0] = DLE;                               // set up termination
  454. buf[1] = ETX;                               // ..with DLE ETX
  455. write(f_handle, buf, 2);                    // ..then put them out
  456. page_len = tell(f_handle) - start_pos - 4;  // compute page data length
  457. lseek(f_handle, start_pos, SEEK_SET);       // position to length field
  458. write(f_handle, (void *) &page_len, 4);     // ..and update field
  459. }
  460. /* ******************************************************************** *
  461.  *
  462.  *  f_build_char() -- fill in bitmap position with a character
  463.  *
  464.  * ******************************************************************** */
  465. void    f_build_char(char cc,               // character to use
  466.                      int  c, int r)         // column and row
  467. {
  468. UINT   *ce,                                 // table entry pointer
  469.        i;                                   // loop counter
  470. char   huge *p,                             // bitmap pointer
  471.        ch1, ch2;                            // high and low bytes
  472. ce = &ascii_map[cc][0];                     // get entry in table
  473. p = &page[((r * 22L) * LINE) + (c * 2)];    // get starting point
  474. for (i = 0; i < 11; i++, ce++)              // for each of the chars rows
  475.     {
  476.     if (*ce)                                // q. anything to put in bitmap?
  477.         {                                   // a. yes .. process bits
  478.         ch1 = *ce >> 8;                     // get high order byte
  479.         ch2 = *ce & 0xff;                   // ..and low order byte
  480.         *p |= ch1;                          // "or" in each cols bits
  481.         *(p + 1) |= ch2;                    // ..for both bytes
  482.         p += LINE;                          // move to next line
  483.         *p |= ch1;                          // "or" in each cols bits
  484.         *(p + 1) |= ch2;                    // ..for both bytes
  485.         p += LINE;                          // move to next line
  486.         }
  487.      else
  488.         p += LINE * 2;                      // else .. skip two bitmap lines
  489.     }
  490. }
  491. /* ******************************************************************** *
  492.  *
  493.  *  f_build_page() -- read an ASCII text file and build a bitmap
  494.  *
  495.  *  returns: 0 = end of file reached
  496.  *           n = characters encoded
  497.  *
  498.  * ******************************************************************** */
  499. int     f_build_page(FILE *f)               // input file pointer
  500. {
  501. int     i,                                  // chars processed
  502.         lines,                              // lines counter
  503.         c, r,                               // column and row (0 based)
  504.         cc;                                 // character buffer
  505. char    huge *p;                            // bitmap line pointer
  506. for (lines = 0, p = page;                   // for the whole bitmap
  507.             lines < LINES;                  // ..run through line
  508.             lines++, p += LINE)             // ..by line
  509.     memset(p, 0, LINE);                     // ..and clear white space
  510. c = r = 0;                                  // start column & row at top
  511. for (i = 0; ; i++)                          // loop building bitmap
  512.     {
  513.     if ((cc = fgetc(f)) == EOF)             // q. get a good character?
  514.         return(i);                          // a. no .. return w/count
  515.     f_build_char(cc, c, r);                 // bld bitmap at column & row
  516.     switch (cc)                             // update column & row
  517.         {
  518.         case LF:                            // line feed
  519.             if (++r >= ROWS)                // q. reach bottom limit?
  520.                 return(i);                  // a. yes .. then page is done
  521.             break;                          // else .. get next character
  522.         case CR:                            // carriage return
  523.             c = 0;                          // start at next beginning
  524.             break;                          // ..and get next character
  525.         case 12:                            // form feed
  526.             return(++i);                    // return w/nbr chars processed
  527.         case BACKSPACE:                     // backspace
  528.             if (--c < 0)                    // q. backup too far?
  529.                 c = 0;                      // a. yes .. goto column 0
  530.             break;                          // else .. get next character
  531.         case TAB:                           // tab
  532.             c = (c & ~0x7) + 8;             // move to next tab stop
  533.             if (c >= COLUMNS)               // q. too far out?
  534.                 {
  535.                 c = 0;                      // a. yes .. just wrap around
  536.                 if (++r >= ROWS)            // q. reach bottom of page?
  537.                     return(i);              // a. yes .. stop here
  538.                 }
  539.             break;                          // else .. get next character
  540.         default:                            // everything else
  541.             if (++c >= COLUMNS)             // q. reach right margin?
  542.                 {
  543.                 c = 0;                      // a. yes .. just wrap around
  544.                 if (++r >= ROWS)            // q. reach bottom of page?
  545.                     return(i);              // a. yes .. stop here
  546.                 }
  547.         }
  548.     }
  549. return(0);                                  // make MSC C/C++ happy
  550. }
  551. /* ******************************************************************** *
  552.  *
  553.  *  f_build_fax() -- build a fax file from an ASCII text file
  554.  *
  555.  * ******************************************************************** */
  556. void    f_build_fax(char *f,                // file name
  557.                     Window *w)              // window to update
  558. {
  559. FILE   *fi;                                 // input file
  560. int     i;                                  // string index
  561. char    buf[60], buf2[60],                  // format buffers
  562.        *p;                                  // ..and pointer
  563. if (f_handle != -1)                         // q. already open?
  564.     {
  565.     close(f_handle);                        // a. yes .. close file
  566.     f_handle = -1;                          // ..and clear flag
  567.     }
  568. if ((fi = fopen(f, "rb")) == 0)             // q. open ok?
  569.     return;                                 // a. no .. just return
  570. strcpy(buf, f);                             // copy base filename
  571. if ((p = strrchr(buf, '.')) == 0)           // q. file extension found?
  572.     p = &buf[strlen(buf)];                  // a. no .. point to end
  573. strcpy(p, ".fax");                          // copy in extension
  574. if ((f_handle = open(buf,                   // q. open new file ok?
  575.             _O_BINARY | _O_TRUNC | _O_RDWR | _O_CREAT)) == -1)
  576.     return;                                 // a. no .. just return
  577. sprintf(buf2, create_msg, buf);             // build display message
  578. w->Display(buf2);                           // ..and send to user window
  579. if ((i = 34 - (strlen(f) +                  // q. able to center the
  580.         strlen(status_conv) - 2)) < 0)      // .."Converting: XXXX" msg?
  581.     i = 0;                                  // a. no .. flush left
  582. memset(buf2, ' ', sizeof(buf2));            // clear area to blanks
  583. sprintf(&buf2[i / 2], status_conv, f);      // format build information
  584. status_line(status, buf2);                  // update status line
  585. f_write_hdr();                              // write header information
  586. for (f_pgcnt = 1; ; f_pgcnt++)              // loop building and writing
  587.     {
  588.     if (f_build_page(fi) == 0)              // q. read ASCII ok?
  589.         break;                              // a. no .. end of file
  590.     f_write_page(w);                        // encode bitmap & write file
  591.     }
  592. fclose(fi);                                 // close input file
  593. close(f_handle);                            // ..and output file
  594. f_handle = -1;                              // ..and reset global
  595. f_locate(buf);                              // set up to view/print file
  596. sprintf(buf2, status_file,                  // format file information
  597.         buf, f_pgcnt);                      // ..for status line
  598. if (f_pgcnt > 1)                            // q. more than 1 page fax?
  599.     strcat(buf2, "s");                      // a. yes .. pluralize page
  600. status_line(status, buf2);                  // update status line
  601. }