#include <stdio.h>
#include <stdlib.h>

/**
 *
 * FOOBAR - Generates PCL barcodes; recognizes in stream indicators
 * 
 * Copyright (C) 1999 Frederik MJ Sauer
 * 
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 * You can contact the author via email:
 *     fred@allen-sauer.com
 *
 * UNIX command line example to print a 3-of-9 barcode for "123AC":
 *     echo "A pretty [FOOBAR;DATA=*123AC*] example" | foobar | lp -d myprinter
 *
 */

#define START_TAG "[FOOBAR"
#define END_TAG_CHAR ']'
#define MAX_DATA_LENGTH 100
#define MAX_TAG_LENGTH 1000
#define NARROW_BAR_DOTS "4"
#define WIDE_BAR_DOTS "10"
#define INTERCHAR_SPACING_DOTS "6"
#define HEIGHT_DOTS "100"
#define HEIGHT_DOTS_START "110" /* bars are longer at the beginning of each new character */

char data[MAX_DATA_LENGTH];
char *pattern;
int xpos=0, ypos=0, width, height;
int hrf=0; /* Human Readable Format variable */

void usage() {
  fprintf(stdout,"Sorry, wrong argument...\nUsage : foobar [-H] < datain > dataout\n");
  fprintf(stdout,"Where -H will print the code in Human ");
  fprintf(stdout,"Readable Format below the bar code.\n\n");
  exit(1);
}

void out_pattern() {
  int pos;
  for(pos=0; pos<9; pos++) {
    char *width;
    char *height;
    width=(pattern[pos]=='.')?NARROW_BAR_DOTS:WIDE_BAR_DOTS;
    /* -H specified, we start new character bar with a longer bar */
    if (hrf) height=(pos==0)?HEIGHT_DOTS_START:HEIGHT_DOTS; 
	else height=HEIGHT_DOTS;
    if (!(pos&1)) fprintf(stdout,"\033*c%sa%sb0P",width,height);
    fprintf(stdout,"\033*p+%sX",width);
  }
}

void out_char(c)
  char c;
{
  if (c>='a' && c<='z') c=c&223;
  if (c=='1') pattern="-..-....-";
  else if (c=='2') pattern="..--....-";
  else if (c=='3') pattern="-.--.....";
  else if (c=='4') pattern="...--...-";
  else if (c=='5') pattern="-..--....";
  else if (c=='6') pattern="..---....";
  else if (c=='7') pattern="...-..-.-";
  else if (c=='8') pattern="-..-..-..";
  else if (c=='9') pattern="..--..-..";
  else if (c=='0') pattern="...--.-..";
  else if (c=='A') pattern="-....-..-";
  else if (c=='B') pattern="..-..-..-";
  else if (c=='C') pattern="-.-..-...";
  else if (c=='D') pattern="....--..-";
  else if (c=='E') pattern="-...--...";
  else if (c=='F') pattern="..-.--...";
  else if (c=='G') pattern=".....--.-";
  else if (c=='H') pattern="-....--..";
  else if (c=='I') pattern="..-..--..";
  else if (c=='J') pattern="....---..";
  else if (c=='K') pattern="-......--";
  else if (c=='L') pattern="..-....--";
  else if (c=='M') pattern="-.-....-.";
  else if (c=='N') pattern="....-..--";
  else if (c=='O') pattern="-...-..-.";
  else if (c=='P') pattern="..-.-..-.";
  else if (c=='Q') pattern="......---";
  else if (c=='R') pattern="-.....--.";
  else if (c=='S') pattern="..-...--.";
  else if (c=='T') pattern="....-.--.";
  else if (c=='U') pattern="--......-";
  else if (c=='V') pattern=".--.....-";
  else if (c=='W') pattern="---......";
  else if (c=='X') pattern=".-..-...-";
  else if (c=='Y') pattern="--..-....";
  else if (c=='Z') pattern=".--.-....";
  else if (c=='-') pattern=".-....-.-";
  else if (c=='.') pattern="--....-..";
  else if (c==' ') pattern=".--...-..";
  else if (c=='*') pattern=".-..-.-..";
  else if (c=='$') pattern=".-.-.-...";
  else if (c=='/') pattern=".-.-...-.";
  else if (c=='+') pattern=".-...-.-.";
  else if (c=='%') pattern="...-.-.-.";
  else return;
  /* fprintf(stdout,"%s",pattern); */
  out_pattern();
  /* prints the current character below the bars */
  if (hrf) fprintf(stdout,"\033*p-20X\033*p+140Y%c\033*p+9X\033*p-140Y",c);
}

void out_data() {
  int pos=0;
  /* Use a small font for Human Readable code bar character */
  if (hrf) fprintf(stdout,"\033(s1p06v4s3b4102T"); 
  fprintf(stdout,"\033*p-%sY",HEIGHT_DOTS); 
  while (data[pos]!=0) {
    char c=data[pos];
    out_char(c);
    fprintf(stdout,"\033*p+" INTERCHAR_SPACING_DOTS "X");
    pos++;
  }
  fprintf(stdout,"\033*p+%sY",HEIGHT_DOTS);
}

int main(argc, argv)
  int argc;
  char *argv[];
{
  int recog_pos=0;
  int recog_len=strlen(START_TAG);
  size_t count;
  char t[MAX_TAG_LENGTH], name[MAX_DATA_LENGTH], value[MAX_DATA_LENGTH], t2[MAX_DATA_LENGTH];

  if (argc==2) {
    if (!strcmp(argv[1],"-H")) hrf=1; else usage();
  } else if (argc>2) usage();

  while (!feof(stdin) && fread(t, sizeof(char), 1, stdin)>0) {
    if (t[0]==START_TAG[recog_pos]) {
      if (fread(t+1, sizeof(char), recog_len-1, stdin)==recog_len-1) {
        if (!strncmp(t, START_TAG, recog_len)) { /* we found START_TAG */
          int tpos=recog_len;
          while (!feof(stdin) && t[tpos-1]!=END_TAG_CHAR) {
            fread(t+tpos++, sizeof(char), 1, stdin);
          }
          t[tpos]=0;
          /* fprintf(stdout," t(%s)\n",t);  */
          sscanf(t,START_TAG "%s",t2);
          /* fprintf(stdout," t2(%s)\n",t2); */
          strcpy(t,t2);
          while (t[0]!=END_TAG_CHAR && sscanf(t,";%[A-Z]=%[ A-Z0-9.*$/+%-]%s", name, value, t2)==3) {
            /* fprintf(stdout," Count(%d) Name(%s) Value(%s) t2(%s)\n",count,name,value,t2); */
            /* fprintf(stdout," Name(%s) Value(%s) t2(%s)\n",name,value,t2); */
            strcpy(t,t2);
            if (!strcmp(name,"DATA")) strcpy(data,value);
/*
            else if (!strcmp(name,"XPOS")) sscanf(value,"%i",&xpos);
            else if (!strcmp(name,"YPOS")) sscanf(value,"%i",&ypos);
            else if (!strcmp(name,"WIDTH")) sscanf(value,"%i",&width);
            else if (!strcmp(name,"HEIGHT")) sscanf(value,"%i",&height);
*/
          }
          out_data();
        }
        else { /* we did not find START_TAG */
          /* Still need to take care of "[FOO[FOOBAR...]" and stuff like that here */
          fwrite(t,sizeof(char),recog_len,stdout);
        }
      }
    }
    else {
      fwrite(t,sizeof(char),1,stdout);
    }
  }
}
