/***************************************************************************
 *                                                                         *
 *   GALTTF.C                                                              *
 *                                                                         *
 *   Copyright (c) 1992-1996 Galacticomm, Inc.    All Rights Reserved.     *
 *                                                                         *
 *   This is the offline utility to convert text files to fax files.       *
 *                                                                         *
 *                               - C. Robert and B. Stephens  12/15/92     *
 *                                                                         *
 ***************************************************************************/

#include "gcomm.h"
#include "excphand.h"
#include "majorbbs.h"
#include "galfax.h"

#define FILREV "$Revision: 1.4 $"

#define   OFNSIZ    29             /* our file name size                   */

extern CHAR scntbl[][GVIDSCNSIZ];  /* array of screens (c/o MAKESCNS)      */

static CHAR dosscn[GVIDSCNSIZ];    /* saved DOS screen image               */

CHAR txtfil[GCMAXPTH],             /* text file name (file to convert)     */
     faxfil[GCMAXPTH];             /* fax file name (file to convert to)   */

FILE *infp,                        /* text file pointer                    */
     *outfp;                       /* fax file pointer                     */

struct ttofax *txt2fx;             /* text to fax convert structure        */

INT vrtres=VRTRES;                 /* vertical resolution variable         */

INT numpps=1;                      /* number of pages in the fax           */
INT numlin=0;                      /* number of lines so far on page       */

CHAR *bigfnt,                      /* "big chars" in-memory font chars     */
     *smlfnt;                      /* "small chars" in-memory font chars   */

static USHORT eolpat=0x0001;

static CHAR revtbl[]={
       0,128, 64,192, 32,160, 96,224, 16,144, 80,208, 48,176,112,240,
       8,136, 72,200, 40,168,104,232, 24,152, 88,216, 56,184,120,248,
       4,132, 68,196, 36,164,100,228, 20,148, 84,212, 52,180,116,244,
      12,140, 76,204, 44,172,108,236, 28,156, 92,220, 60,188,124,252,
       2,130, 66,194, 34,162, 98,226, 18,146, 82,210, 50,178,114,242,
      10,138, 74,202, 42,170,106,234, 26,154, 90,218, 58,186,122,250,
       6,134, 70,198, 38,166,102,230, 22,150, 86,214, 54,182,118,246,
      14,142, 78,206, 46,174,110,238, 30,158, 94,222, 62,190,126,254,
       1,129, 65,193, 33,161, 97,225, 17,145, 81,209, 49,177,113,241,
       9,137, 73,201, 41,169,105,233, 25,153, 89,217, 57,185,121,249,
       5,133, 69,197, 37,165,101,229, 21,149, 85,213, 53,181,117,245,
      13,141, 77,205, 45,173,109,237, 29,157, 93,221, 61,189,125,253,
       3,131, 67,195, 35,163, 99,227, 19,147, 83,211, 51,179,115,243,
      11,139, 75,203, 43,171,107,235, 27,155, 91,219, 59,187,123,251,
       7,135, 71,199, 39,167,103,231, 23,151, 87,215, 55,183,119,247,
      15,143, 79,207, 47,175,111,239, 31,159, 95,223, 63,191,127,255
};
static USHORT whtmak[]={
     0xD800, 5,0x9000, 5,0x5C00, 6,0x6E00, 7,0x3600, 8,0x3700, 8,0x6400, 8,
     0x6500, 8,0x6800, 8,0x6700, 8,0x6600, 9,0x6680, 9,0x6900, 9,0x6980, 9,
     0x6A00, 9,0x6A80, 9,0x6B00, 9,0x6B80, 9,0x6C00, 9,0x6C80, 9,0x6D00, 9,
     0x6D80, 9,0x4C00, 9,0x4C80, 9,0x4D00, 9,0x6000, 6,0x4D80, 9
};
static USHORT blkmak[]={
     0x03C0,10,0x0C80,12,0x0C90,12,0x05B0,12,0x0330,12,0x0340,12,0x0350,12,
     0x0360,13,0x0368,13,0x0250,13,0x0258,13,0x0260,13,0x0268,13,0x0390,13,
     0x0398,13,0x03A0,13,0x03A8,13,0x03B0,13,0x03B8,13,0x0290,13,0x0298,13,
     0x02A0,13,0x02A8,13,0x02D0,13,0x02D8,13,0x0320,13,0x0328,13
};
static USHORT whttrm[]={
     0x3500, 8,0x1C00, 6,0x7000, 4,0x8000, 4,0xB000, 4,0xC000, 4,0xE000, 4,
     0xF000, 4,0x9800, 5,0xA000, 5,0x3800, 5,0x4000, 5,0x2000, 6,0x0C00, 6,
     0xD000, 6,0xD400, 6,0xA800, 6,0xAC00, 6,0x4E00, 7,0x1800, 7,0x1000, 7,
     0x2E00, 7,0x0600, 7,0x0800, 7,0x5000, 7,0x5600, 7,0x2600, 7,0x4800, 7,
     0x3000, 7,0x0200, 8,0x0300, 8,0x1A00, 8,0x1B00, 8,0x1200, 8,0x1300, 8,
     0x1400, 8,0x1500, 8,0x1600, 8,0x1700, 8,0x2800, 8,0x2900, 8,0x2A00, 8,
     0x2B00, 8,0x2C00, 8,0x2D00, 8,0x0400, 8,0x0500, 8,0x0A00, 8,0x0B00, 8,
     0x5200, 8,0x5300, 8,0x5400, 8,0x5500, 8,0x2400, 8,0x2500, 8,0x5800, 8,
     0x5900, 8,0x5A00, 8,0x5B00, 8,0x4A00, 8,0x4B00, 8,0x3200, 8,0x3300, 8,
     0x3400, 8
};
static USHORT blktrm[]={
     0x0DC0,10,0x4000, 3,0xC000, 2,0x8000, 2,0x6000, 3,0x3000, 4,0x2000, 4,
     0x1800, 5,0x1400, 6,0x1000, 6,0x0800, 7,0x0A00, 7,0x0E00, 7,0x0400, 8,
     0x0700, 8,0x0C00, 9,0x05C0,10,0x0600,10,0x0200,10,0x0CE0,11,0x0D00,11,
     0x0D80,11,0x06E0,11,0x0500,11,0x02E0,11,0x0300,11,0x0CA0,12,0x0CB0,12,
     0x0CC0,12,0x0CD0,12,0x0680,12,0x0690,12,0x06A0,12,0x06B0,12,0x0D20,12,
     0x0D30,12,0x0D40,12,0x0D50,12,0x0D60,12,0x0D70,12,0x06C0,12,0x06D0,12,
     0x0DA0,12,0x0DB0,12,0x0540,12,0x0550,12,0x0560,12,0x0570,12,0x0640,12,
     0x0650,12,0x0520,12,0x0530,12,0x0240,12,0x0370,12,0x0380,12,0x0270,12,
     0x0280,12,0x0580,12,0x0590,12,0x02B0,12,0x02C0,12,0x05A0,12,0x0660,12,
     0x0670,12
};

static VOID ldfont(VOID);
static VOID convert(VOID);
static VOID explin(CHAR *line,INT maxlen);
static CHAR *ffgets(CHAR *buf,INT size,FILE *fp);
static VOID dofeed(VOID);
static VOID cnvlin(CHAR *line,GBOOL big);
static VOID wrtbuf(VOID);
static VOID adblnk(GBOOL big);
static VOID addeol(VOID);
static VOID runlen(INT color,INT length);
static VOID adbits(USHORT pattern,INT nbits);
static GBOOL valfln(INT c,CHAR *stg);
static VOID wrapup(VOID);

INT
main(                              /* main program loop                    */
INT argc,
CHAR *argv[])
{
TRY
     initvid();
     txt2fx=(struct ttofax *)alcmem(sizeof(struct ttofax));
     ldfont();
     if (argc == 3) {
          stlcpy(txtfil,argv[1],GCMAXPTH);
          stlcpy(faxfil,argv[2],GCMAXPTH);
          convert();
          clsvid();
          return(0);
     }
     monorcol();
     cvtscn(scntbl[0]);
     scn2mem(dosscn,0,GVIDSCNSIZ);
     explode(scntbl[0],17,11,62,22);
     cursiz(GVIDLILCURS);
     do {
          if (!edtval(32,16,OFNSIZ,txtfil,valfln,ALLCAPS)) {
               wrapup();
               return(0);
          }
     } while (txtfil[0] == '\0' && printf("\7"));
     locate(32,16);
     setatr(0x30);
     printf("%-*.*s",OFNSIZ-1,OFNSIZ-1,txtfil);
     do {
          if (!edtval(32,17,OFNSIZ,faxfil,valfln,ALLCAPS)) {
               wrapup();
               return(0);
          }
     } while (faxfil[0] == '\0' && printf("\7"));
     locate(32,17);
     setatr(0x30);
     printf("%-*.*s",OFNSIZ-1,OFNSIZ-1,faxfil);
     locate(18,20);
     printf("<Press any key to confirm, or ESC to cancel>");
     cursiz(GVIDNOCURS);
     if (getchc() != ESC) {
          setatr(0xB0);
          locate(18,20);
          printf("        (Please wait.  Converting...)       ");
          convert();
     }
     wrapup();
EXCEPT
     return(0);
}

static VOID
ldfont(VOID)                       /* load up the font arrays (big and sml)*/
{
     FILE *fp;

     bigfnt=alcmem(BFNSIZ);
     smlfnt=alcmem(SFNSIZ);
     if ((fp=fopen("GALFAX.FNT",FOPRB)) == NULL) {
          catastro("Unable to open \"GALFAX.FNT\" for input!");
     }
     if (fread(bigfnt,1,BFNSIZ,fp) != BFNSIZ ||
         fread(smlfnt,1,SFNSIZ,fp) != SFNSIZ) {
          catastro("Bad \"GALFAX.FNT\" file!");
     }
     fclose(fp);
}

static VOID
convert(VOID)                      /* convert text txtfil -> a fax faxfil  */
{
     if ((infp=fopen(txtfil,FOPRB)) == NULL) {
          catastro("Unable to open %s for input!",txtfil);
     }
     if ((outfp=fopen(faxfil,FOPWB)) == NULL) {
          catastro("Unable to open %s for output!",faxfil);
     }
     fwrite("  ",1,2,outfp);
     while (TRUE) {
          setmem(txt2fx,sizeof(struct ttofax),0);
          if (ffgets(txt2fx->line,CPERLN+1,infp) == NULL) {
               rewind(outfp);
               fwrite((CHAR *)&numpps,1,2,outfp);
               fclose(outfp);
               fclose(infp);
               break;
          }
          if (txt2fx->line[0] == FORMFD) {
               dofeed();
          }
          else {
               explin(txt2fx->line,CPERLN);
               cnvlin(txt2fx->line,TRUE);
               wrtbuf();
          }
     }
}

static VOID
explin(                            /* expand TABs in a line (in place)     */
CHAR *line,                        /*   pointer to line to expand          */
INT maxlen)                        /*   maximum length of line             */
{
     INT len;
     CHAR *ptr;

     ptr=line;
     while (*ptr != '\0') {
          if (*ptr++ == TAB) {
               len=min(TABLEN-1,maxlen-strlen(line));
               movmem(ptr,ptr+len,strlen(ptr)+1);
               setmem(ptr-1,len+1,' ');
          }
     }
}

static CHAR *
ffgets(                            /* fax flavr of fgets() (handles FORMFD)*/
CHAR *buf,                         /*   buffer to store line in            */
INT size,                          /*   size of buffer (just in case)      */
FILE *fp)                          /*   file pointer                       */
{
     INT i,c;

     for (i=0 ; i < size-1 ; i++) {
          switch (c=fgetc(fp)) {
          case '\r':
               i--;
               break;
          case FORMFD:
               if (i == 0) {
                    buf[i++]=FORMFD;
               }
               else {
                    ungetc(c,fp);
               }
          case '\n':
               buf[i]='\0';
               return(buf);
          case EOF:
               if (i == 0) {
                    return(NULL);
               }
               else if (buf[i-1] == 26) {
                    buf[i-1]='\0';
               }
               else {
                    buf[i]='\0';
               }
               return(buf);
          default:
               buf[i]=c;
          }
     }
     buf[i]='\0';
     return(buf);
}

static VOID
dofeed(VOID)                       /* x-late text form feed -> fax image   */
{
     while (numlin < LPERPG) {
          adblnk(1);
          wrtbuf();
          setmem(txt2fx,sizeof(struct ttofax),0);
          numlin++;
     }
}

static VOID
cnvlin(                            /* convert line of text -> fax image    */
CHAR *line,                        /*   pointer to line of text            */
GBOOL big)                         /*   big (TRUE) or small text?          */
{
     CHAR curbyte;
     INT i,itimes,j,k,h,color=0,sofar=INDENT,totfar=0;

     if (big && numlin++ == LPERPG) {
          numpps++;
          fwrite(EOPSTG,1,strlen(EOPSTG),outfp);
          numlin=1;
     }
     if (line[0] == '\0') {
          adblnk(big);
     }
     else {
          itimes=(big ? 16 : 8);
          for (i=0 ; i < itimes ; i++) {
               for (h=0 ; h < vrtres ; h++) {
                    for (j=0 ; j < strlen(line) ; j++) {
                         curbyte=(big ? bigfnt[line[j]*16+i]
                                       : smlfnt[line[j]*8+i]);
                         for (k=0 ; k < 8 ; k++) {
                              if (((curbyte<<k)&0x80) == color*0x80) {
                                   sofar++;
                              }
                              else {
                                   runlen(color,sofar*HORRES);
                                   totfar+=sofar*HORRES;
                                   sofar=1;
                                   color^=1;
                              }
                         }
                    }
                    if (color != 0) {
                         runlen(1,sofar*HORRES);
                         runlen(0,1728-(totfar+(sofar*HORRES)));
                    }
                    else {
                         runlen(0,1728-totfar);
                    }
                    addeol();
                    sofar=INDENT;
                    totfar=color=0;
               }
          }
     }
}

static VOID
wrtbuf(VOID)                       /* write fax image bit array            */
{
     CHAR c,*wrtptr;
     UINT i,j,totsiz;

     wrtptr=(CHAR *)txt2fx->bitary;
     totsiz=(txt2fx->bsofar/8);
     for (i=0 ; i < totsiz+1 ; i+=2) {
          c=revtbl[wrtptr[i]];
          wrtptr[i]=revtbl[wrtptr[i+1]];
          wrtptr[i+1]=c;
          for (j=0 ; j < 2 ; j++) {
               if (wrtptr[i+j] == FAXDLE) {
                    movmem(&wrtptr[i+j+1],&wrtptr[i+j+2],totsiz-i-j-1);
                    wrtptr[i+j+1]=FAXDLE;
                    i++;
                    totsiz++;
               }
          }
     }
     fwrite(wrtptr,totsiz,1,outfp);
}

static VOID
adblnk(                            /* add a blank line to the fax bit array*/
GBOOL big)                         /*   big (TRUE) or small text line?     */
{
     INT i;

     for (i=0 ; i < (big ? 16 : 8)*vrtres ; i++) {
          runlen(0,1728);
          addeol();
     }
}

static VOID
addeol(VOID)                       /* add an EOL to the fax image bit array*/
{
     if (txt2fx->bsofar%16 != 0) {
          txt2fx->bsofar+=(16-(txt2fx->bsofar%16));
     }
     adbits(eolpat,16);
}

static VOID
runlen(                            /* add this run length to fax bit array */
INT color,                         /*   run length is:  1=black 0=white    */
INT length)                        /*   length of run (in PELs)            */
{
     INT big,sml;

     if (color != 0) {
          if (length < 64) {
               adbits(blktrm[length*2],blktrm[length*2+1]);
          }
          else {
               big=(length-64)/64;
               sml=length-(big+1)*64;
               adbits(blkmak[big*2],blkmak[big*2+1]);
               adbits(blktrm[sml*2],blktrm[sml*2+1]);
          }
     }
     else {
          if (length < 64) {
               adbits(whttrm[length*2],whttrm[length*2+1]);
          }
          else {
               big=(length-64)/64;
               sml=length-(big+1)*64;
               adbits(whtmak[big*2],whtmak[big*2+1]);
               adbits(whttrm[sml*2],whttrm[sml*2+1]);
          }

     }
}

static VOID
adbits(                            /* add string of bits to fax image */
USHORT pattern,                    /*   the pattern of bits to add    */
INT nbits)                         /*   # of bits to use in pattern   */
{
     INT lword,bitpos,freebits;

     lword=txt2fx->bsofar/16;
     bitpos=txt2fx->bsofar%16;
     freebits=16-bitpos;
     txt2fx->bitary[lword]|=(pattern>>bitpos);
     if (nbits > freebits) {
          txt2fx->bitary[++lword]|=(pattern<<freebits);
     }
     txt2fx->bsofar+=nbits;
}

static GBOOL
valfln(                            /* is this a valid file name char?      */
INT c,                             /*   character just entered             */
CHAR *stg)                         /*   complete string so far             */
{
     (VOID)c;
     (VOID)stg;
     return(TRUE);
}

static VOID
wrapup(VOID)                       /* wrap things up before exiting        */
{
     setatr(0x07);
     printf(" ");
     locate(0,24);
     mem2scn(dosscn,0,GVIDSCNSIZ);
     cursiz(GVIDLILCURS);
     clsvid();
}
