home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Format CD 28
/
amigaformatcd28.iso
/
-seriously_amiga-
/
archivers
/
yacoder
/
codes.c
next >
Wrap
C/C++ Source or Header
|
1998-05-09
|
5KB
|
242 lines
/*
* $Header: /usr/people/tcl/src/uutar/RCS/codes.c,v 1.1.1.4 1993/09/11 22:42:44 tcl Exp $
* Tom Lawrence
* tcl@sgi.com
*/
#include <stdio.h>
#include <stdlib.h>
#include "codes.h"
/* see codes.h */
int numchars;
struct code codes[256];
/* initialize a subset of the codes array. val and len define a variable
* length bitfield. The array elements will be set up so that any element
* of the array whose index is a left-aligned superset of this bitfield
* will contain the given output ascii character. E.g. if the bitfield is
* 10010, then all elements in the array with subscript 10010xxx for all
* xxx, will store the given ascii code, and the length of the bitfield,
* in this case 5.
*/
static void
init_encodeval(codes, val, len, ascii)
struct code *codes;
int val;
int len;
int ascii;
{
int shift, stop;
/* determine how far the code must be shifted to be
* MSB justified in the byte
*/
shift = 8 - len;
/* calculate the upper bound of indices which this bitfield
* will match
*/
stop = (val + 1) << shift;
/* shift the code over to the left edge of the byte */
val <<= shift;
/* thus, for every index in the 256 element array which has
* this code as a prefix
*/
for(; val < stop; val++) {
/* store the code length and the printable character
* it represents
*/
codes[val].len = (char)len;
codes[val].code = (char)ascii;
}
}
/* convert an ascii character code to an integer. The character code may
* be in decimal, hex or octal, or it may be an actual character escaped
* with a back-slash
*/
static int
str2val(str)
char *str;
{
int val;
char *end;
while(*str == ' ' || *str == '\t')
str++;
/* check if this is an escaped character */
if (*str == '\\') {
str++;
if (*str == 0) {
fprintf(stderr, "missing character in alphabet\n");
exit(1);
}
return((int)*str);
}
val = (int)strtol(str, &end, 0);
if (end == str) {
if (*str)
fprintf(stderr, "invalid char \'%c\' in alphabet\n", *str);
else
fprintf(stderr, "empty numerical field in alphabet\n");
exit(1);
}
return(val);
}
/* parse a range of characters for the output character set and mark each
* character as in use in the codes array. A range is either in the form
* num-num or just num
*/
static void
parse_charval_range(range)
char *range;
{
char *c, savec = 0;
int start, end, x;
for(c = range; *c && *c != '-'; c++);
savec = *c;
*c = 0;
start = str2val(range);
if (savec == '-') {
end = str2val(c + 1);
*c = savec;
for(x = start; x <= end; x++)
codes[x].inuse = 1;
}
else
codes[start].inuse = 1;
}
/* parse a list of character ranges for the output character set and then
* parse each range found. A list is of the form range,range,...
*/
void
parse_charval_list(list)
char *list;
{
char *c1, *c2, savec2;
int x;
for(x = 0; x < 256; x++)
codes[x].inuse = 0;
c1 = list;
while(*c1) {
while(*c1 == ',')
c1++;
if (*c1 == 0)
return;
for(c2 = c1; *c2 && *c2 != ','; c2++);
savec2 = *c2;
*c2 = 0;
parse_charval_range(c1);
*c2 = savec2;
c1 = c2;
}
return;
}
/* print out the character set in the form of a list of ranges, encoded
* in decimal
*/
void
print_charval_list(fp)
FILE *fp;
{
int x, usecomma;
usecomma = 0;
for(x = 0; x < 256; x++) {
if (codes[x].inuse) {
if (usecomma)
putc(',', fp);
fprintf(fp, "%d", x);
usecomma = 1;
if (x < 255 && codes[x+1].inuse) {
putc('-', fp);
while(++x < 256 && codes[x].inuse);
fprintf(fp, "%d", x-1);
}
}
}
}
/*
* Initialize the tables for encoding or decoding depending on the given
* direction.
*/
void
init_codes(direction)
int direction;
{
int x, code, numchars;
int pof2, pof2len, half, whole;
/* count how big our character set is */
numchars = 0;
for(x = 0; x < 256; x++)
if (codes[x].inuse)
numchars++;
if (numchars < 2) {
fprintf(stderr,
"uutar: alphabet doesn't contain enough characters.\n");
exit(1);
}
/* determine the lowest power of 2 that is >= numchars, and the number
* of bits needed to store that many values.
*/
for(pof2 = 2, pof2len = 1; pof2 < numchars;
pof2 <<= 1, pof2len++);
/* compute how many half codes we need */
half = pof2 - numchars;
/* compute how many whole codes we need */
whole = numchars - half;
/* create a variable length code for each valid entry */
code = 0;
x = -1;
/* create the whole codes */
while(whole--) {
/* get next slot */
do x++; while(codes[x].inuse == 0);
if (direction == DECODE) {
codes[x].code = (char)code;
codes[x].len = (char)pof2len;
}
else
init_encodeval(codes, code, pof2len, x);
code++;
}
/* chop off LSB to form the half codes */
code >>= 1;
pof2len--;
/* create the half codes */
while(half--) {
do x++; while(codes[x].inuse == 0);
if (direction == DECODE) {
codes[x].code = (char)code;
codes[x].len = (char)pof2len;
}
else
init_encodeval(codes, code, pof2len, x);
code++;
}
}