flamer@argent.UUCP (04/02/87)
/*
* Program: zbc.c ZIP Bar Code
* Author: Jim Trethewey
* Intel OMS BITBUS Engineering.
* Version: V1.0.
* Date: 02-Apr-1987.
* Language: Microsoft C 286.
* Ppn: ..!argent!mithril!flamer [or] flamer@mithril.hf.intel.COM
*
* Description:
*
* This program will provide you interest for about two minutes.
* It was an exercise in reverse engineering the little bar codes
* that the U.S. Postal Service puts at the bottom of envelopes,
* and this program was written primarily for hack value.
*
* This program takes one of four options, summarized as follows:
*
* 1. Encode in Bar Code the given ZIP.
* zbc -e <zip>
* zbc -e <zip+4>
* 2. Encode in Bar Code the given ZIP, and be verbose about it.
* zbc -ev <zip>
* zbc -ev <zip+4>
* 3. Decode the given Bar Code to ZIP.
* zbc -d "<barcode>"
* 4. Decode the given Bar Code to ZIP, and be verbose about it.
* zbc -dv "<barcode>"
*
* Because the two functions are inverses, you can do neat things like:
*
* zbc -d "`zbc -e 94601`"
*
* Modification History:
*
* M000 02-Apr-1987 flamer Original issue.
*
*/
#include <stdio.h>
#include <ctype.h>
#ifdef UCB
#define strchr index
#endif
extern char *strchr ();
/*
* The definitions for ZERO and ONE indicate which characters are
* used and accepted for the bar code bits. They can be anything
* you want so long as they're different. Depending upon your
* CRT or printer, '.' is best for ZERO and '|' for ONE.
*/
#ifdef LASERJET
#define ZERO ','
#define ONE '|'
#else
#define ZERO '.'
#define ONE '|'
#endif
#define FALSE 0
#define TRUE !FALSE
#define SAME 0
char zbc [10][6] = {
{ ONE, ONE, ZERO, ZERO, ZERO, 0 }, /* 0 = "||..." */
{ ZERO, ZERO, ZERO, ONE, ONE, 0 }, /* 1 = "...||" */
{ ZERO, ZERO, ONE, ZERO, ONE, 0 }, /* 2 = "..|.|" */
{ ZERO, ZERO, ONE, ONE, ZERO, 0 }, /* 3 = "..||." */
{ ZERO, ONE, ZERO, ZERO, ONE, 0 }, /* 4 = ".|..|" */
{ ZERO, ONE, ZERO, ONE, ZERO, 0 }, /* 5 = ".|.|." */
{ ZERO, ONE, ONE, ZERO, ZERO, 0 }, /* 6 = ".||.." */
{ ONE, ZERO, ZERO, ZERO, ONE, 0 }, /* 7 = "|...|" */
{ ONE, ZERO, ZERO, ONE, ZERO, 0 }, /* 8 = "|..|." */
{ ONE, ZERO, ONE, ZERO, ZERO, 0 } /* 9 = "|.|.." */
};
int encode_flag, decode_flag, verbose_flag;
int valid_flag;
value_of (bit)
char bit;
{
if (bit == ZERO)
{
return (0);
}
else if (bit == ONE)
{
return (1);
}
else
{
return (-1);
}
}
put_start_bit (position)
char *position;
{
*position = (ONE);
}
put_stop_bit (position)
char *position;
{
*position = (ONE);
}
char *ztob (zipcode)
char *zipcode;
{
static char barcode [100];
char *ch_p;
char *out_p;
int checksum;
int i, j;
checksum = 0;
out_p = &barcode [0];
put_start_bit (out_p++);
for (ch_p = zipcode, i = 0; ch_p && *ch_p; ch_p++, i++)
{
if (isdigit (*ch_p))
{
strcpy (out_p, zbc [*ch_p - '0']);
out_p += 5;
checksum += (*ch_p - '0');
}
}
checksum = 10 - checksum % 10;
strcpy (out_p, zbc [checksum]);
out_p += 5;
put_stop_bit (out_p++);
*out_p = '\0';
return (barcode);
}
char *btoz (barcode)
char *barcode;
{
static char zipcode [100];
char *ch_p;
char *out_p;
int i, j;
int checksum;
int expected_checksum;
int parity;
int found;
int digits_seen;
int digit_length;
int checksum_flag;
int error_flag;
int new_digit;
error_flag = FALSE;
checksum = 0;
expected_checksum = -1;
out_p = &zipcode [0];
digits_seen = 0;
digit_length = (strlen (barcode) - 2) / 5;
for (ch_p = barcode, i = 0; ch_p && *ch_p; ch_p++, i++)
{
if (ch_p == barcode) /* at the start bit */
{
if (*ch_p != ONE)
{
fprintf (stderr, "Invalid start bit.\n");
}
else if (verbose_flag)
{
*out_p++ = ('_');
}
}
else if (*(ch_p + 1) == 0) /* at the stop bit */
{
if (checksum % 10 != 0)
{
fprintf (stderr,
"Checksum error (actual = %d, expected = %d).\n",
checksum % 10, expected_checksum);
if (error_flag == 0)
{
fprintf (stderr, "Too many bit errors to fix.\n");
fprintf (stderr, "Can't find position of error,");
fprintf (stderr, " bad ZIP code returned.\n");
}
}
if (*ch_p != ONE)
{
fprintf (stderr, "Invalid stop bit.\n");
}
else
{
if (verbose_flag)
{
*out_p++ = ('_');
}
}
if (error_flag > 1)
{
fprintf (stderr, "Too many bit errors to fix.\n");
}
else if (error_flag == 1)
{
new_digit = (10 - checksum % 10) % 10;
fprintf (stderr, "Correcting digit to a \"%d\".\n",
new_digit);
if (!checksum_flag || verbose_flag)
{
*strchr (zipcode, '?') = new_digit + '0';
}
else
{
*strchr (zipcode, '?') = '\0';
}
}
}
else /* in the middle somewhere */
{
checksum_flag = (digits_seen == digit_length - 1);
if ((digits_seen == 5) && !checksum_flag)
{
*out_p++ = ('-');
}
found = FALSE;
for (j = 0; j < 10; j++)
{
if (strncmp (ch_p, zbc [j], 5) == SAME)
{
found = TRUE;
if (checksum_flag && verbose_flag)
{
*out_p++ = ('[');
}
if (!checksum_flag || verbose_flag)
{
*out_p++ = (j + '0');
}
if (checksum_flag)
{
expected_checksum = j;
}
if (checksum_flag && verbose_flag)
{
*out_p++ = (']');
}
break;
}
}
if (!found)
{
/*
* Check parity.
*/
parity = value_of (*ch_p)
+ value_of (*(ch_p + 1))
+ value_of (*(ch_p + 2))
+ value_of (*(ch_p + 3))
+ value_of (*(ch_p + 4));
if (parity != 2)
{
error_flag++;
fprintf (stderr,
"Parity error (actual = %d, expected = 2) in \"%5.5s\" at position %d.\n",
parity, ch_p, digits_seen + 1);
if (checksum_flag && verbose_flag)
{
*out_p++ = ('[');
}
*out_p++ = '?';
if (checksum_flag && verbose_flag)
{
*out_p++ = (']');
}
}
}
else
{
checksum += j;
}
digits_seen++;
ch_p += 4;
}
}
*out_p = '\0';
return (zipcode);
}
main (argc, argv)
int argc;
char *argv [];
{
/*
* Check out the command line arguments.
*/
valid_flag = FALSE;
encode_flag = FALSE;
decode_flag = FALSE;
verbose_flag = FALSE;
if (argc != 3)
{
valid_flag = FALSE;
}
else if (strncmp (argv [1], "-e", 2) == SAME)
{
valid_flag++;
encode_flag++;
if (argv [1][2] == 'v')
{
verbose_flag++;
}
}
else if (strncmp (argv [1], "-d", 2) == SAME)
{
valid_flag++;
decode_flag++;
if (argv [1][2] == 'v')
{
verbose_flag++;
}
}
if (!valid_flag)
{
fprintf (stderr,
"Usage: %s -e <zipcode> Encode ZIPcode in bar code.\n",
argv [0]);
fprintf (stderr,
" %s -ev <zipcode> Encode ZIPcode in bar code verbosely.\n",
argv [0]);
fprintf (stderr,
" %s -d \"<barcode>\" Decode bar code to ZIPcode.\n",
argv [0]);
fprintf (stderr,
" %s -dv \"<barcode>\" Decode bar code to ZIPcode verbosely.\n",
argv [0]);
exit (1);
}
/*
* Do the requested conversion.
*/
if (encode_flag)
{
printf ("%s\n", ztob (argv [2]));
}
else if (decode_flag)
{
printf ("%s\n", btoz (argv [2]));
}
}