/* numbers.h -- Copyright 1989, 1993, 1994, 1995 Liam R. E. Quin. * All Rights Reserved. * This code is NOT in the public domain. * See the file COPYRIGHT for full details. * * LQT_sReadNumber and LQT_sWriteNumber take/return a long, * using a simple compression algorithm to reduce the amount of data taken. * * A 1 in the top bit means another byte follows, hence fitting * 7 bits into each bytes. * Speed is very important. These functions are the backbone of lq-text. * * If you don't have inline functions, these functions are defined in * numbers.c instead. * * There used to be FILE ** versions, but I never used them. * * $Id: numbers.h,v 1.12 1996/08/14 16:51:03 lee Exp $ * */ #ifndef LQ_NUMBERS_H # define LQ_NUMBERS_H 1 #ifdef HAVE_INLINE #define PutC(ch, Sp, Base, Maxlen) \ ((((*(Sp)) - (Base)) >= Maxlen) ? -1 : ( (*((*(Sp))++) = (unsigned char) (ch)), 0)) /* * LQT_sWriteNumber * Database/Physical * * Writes a compressed binary representation of the given Number into * the given string. The pointer pointed to by Sp is advanced to point * to the first unwritten byte of the buffer. * *
  • -1 if the string doesn't fit; in this case, the pointer * referred to by Sp will have been advanced by the amount of the number * that fitted; *
  • Zero is returned if the number was written successfully.
  • *
    * *

    This function and the companion LQT_sReadNumber are central to the * operation of the lq-text database package. If it were not for the * use of compressed numbers, the index would be too large to be useful. *

    *

    The function is designed to work best with small numbers; a number * less than 127 is written out in a single byte, for example, and a * number less than 16383 is written in two bytes. For this reason, * LQT_sWriteNumber is most effectively used when writing a sorted * sequence of numbers, as then you can write only the difference between * successive values, saving space. This form of delta coding is used * extensively by lq-text. * * LQT_sReadNumber * */ INLINE int LQT_sWriteNumber(Sp, Number, Base, Maxlen) unsigned char **Sp; unsigned long Number; unsigned char *Base; unsigned int Maxlen; { /* Compressed numbers: * 7 bit numbers --> single byte; * 8...14 bits --> 2 bytes * 15...21 bits --> 3 bytes * 22..28 bits --> 4 bytes * 29..32 bits --> 5 bytes */ while (Number > 0177) { /* the 0200 means more data follows... */ if (PutC((Number & 0177) | 0200, Sp, Base, Maxlen) < 0) { return -1; } Number >>= 7; } if (PutC(Number & 0177, Sp, Base, Maxlen) < 0) { return -1; } return 0; } #define GetC(S) \ ( (unsigned int) * (unsigned char *) ((* (unsigned char **)S)++) ) /* * LQT_sReadNumber * Database/Physical * *

    Reads a number from its compressed binary representation stored * the given string. The pointer pointed to by Sp is advanced to point * to the first unread byte of the buffer. * The retrieved number is stored in the variable pointed to by * the given Resultp argument.

    * *
  • -1 if the entire number was not read, because it wasn't all * included in the given string; in this case, the pointer * referred to by Sp will have been advanced by the number of bytes * read, but the return value is useless. *
  • Zero is returned if the number was read successfully.
  • *
    * * LQT_sWriteNumber *
    */ INLINE int LQT_sReadNumber(Sp, Resultp, StartOfBuffer, LengthOfBuffer) unsigned char **Sp; unsigned long *Resultp; unsigned char *StartOfBuffer; unsigned int LengthOfBuffer; { int ThereIsMore; int Shift = 0; *Resultp = 0L; /* Read a number, 7 bits at a time, lsb first, until there is * a byte without the top bit set -- that's the most significant * byte, and there is no more of this number. */ do { if (*Sp - StartOfBuffer >= LengthOfBuffer) { return -1; } *Resultp |= ((ThereIsMore = GetC(Sp)) & 0177) << Shift; ThereIsMore &= 0200; Shift += 7; } while (ThereIsMore); return 0; } #endif /* HAVE_INLINE */ # endif /* LQ_NUMBERS_H */