Algorithmic Encryption Without Math

by Dale Thorn

Algorithmic encryption, as I envision it, uses an executable program, a plaintext file, and a password or passwords to change the plaintext file to a ciphertext file.  PGP, as I understand it, is an algorithmic encryption program, as compared to programs that use One-Time Pads (OTP), for example.

An algorithmic program will generally use advanced mathematics such as large prime numbers, elliptic curves, discrete logarithms, and so on to generate ostensibly random bit-streams which, when XOR'd with the plaintext, produces the unreadable ciphertext.

Encryption without math has a distant similarity to the OTP method, in that a fixed lookup table of numbers is used as part of the process to generate the pseudo-random values used in the encryption.

I have to interject here that the program I'm about to describe has withstood several plaintext attacks where the attacker sends me tens of thousands of plaintext or binary files and I encrypt them with the same passwords and program that encrypted the secret contest file.  When I return the encrypted files to the attacker, if they can deduce the pattern or sequence of the encryption and thus decrypt the secret file, they win thousands of dollars as the contest prize.

The lookup table I currently use was generated from a simple pseudo-random number generator, which is more than sufficient for my purposes.  The quality of randomness is not important for the lookup table.  The program is usually run with several password numbers, and the complete file is encrypted once for each number entered.  Each password number pulls numbers from the lookup table beginning at that value in the lookup table and proceeding through the table sequentially until the end, where it wraps around to the first number.

A group of lookup table numbers are placed into an array (array "A"), and an equivalent number of sequential values (from zero to "n") are placed into a same-sized array (array "B").

Array "A" is then sorted and the values in array "B" are swapped the same way as the values in array "A".

Array "A", containing the sorted lookup table numbers, is then discarded.

Array "B", containing numbers which are now in an apparent random order, are used to reposition (or shuffle) the bits in the plaintext file.

For example, the two arrays might start off as follows:

Index  Sequential Array  Random Array
0      0                 5743
1      1                 13496
2      2                 17729
3      3                 8933
4      4                 10150
5      5                 14584
6      6                 22362
7      7                 31955
8      8                 2867
9      9                 16383

After sorting by the values in the random number array:

Index  Sequential Array  Random Array
0      8                 2867
1      0                 5743
2      3                 8933
3      4                 10150
4      1                 13496
5      5                 14584
6      9                 16383
7      2                 17729
8      6                 22362
9      7                 31955

In the second example, after sorting you will see that the sequential number array is now in a more or less random order and the originally random array is fully sorted.  We now discard the random number array and move the bits from their original sequential positions (the "index" column) to the random positions shown in the "Sequential Array" column.

The good news about using array "B" to shuffle bits in the plaintext is the fact that there are no duplicate values in array "B" and no missing numbers either.  Therefore we don't need a "hash" or other math-oriented technique to calculate the move-to bit positions.  Another bit of good news is that since we're not using the lookup table numbers directly to calculate the move-to positions, we don't have to worry about weaknesses in the encryption due to the low quality "randomness" of the values in the lookup table.

Another major factor in randomizing the ciphertext output is the fact that I use several password numbers to encrypt, with each password adding about 20 bits of security as it's commonly referred to in the crypto business.  The real trick here is that since each password number is different, the additional crypto layers after the first one use different segments of the lookup table, layered over top of each other.

And unlike conventional codes that can decrypt multiple XOR'd layers in any sequence, the code described here requires all layers to be decrypted in the exact reverse order of the encryption, else the plaintext cannot be recovered.

Another factor in randomizing the output is the use of random-sized groups of bits when shuffling the bits.  One lookup table value provides the group size ("n"), then the next "n" lookup values are used to fill the "A" array as described above.  A fourth factor in preventing plaintext and ciphertext attacks from being successful - by analyzing thousands of files with just a single "1" bit in each file to see where the bit moved to after encryption - is to use the filename, or add a serial number to each file and use that name or number to further iterate the password so that each encryption is different for each file.

Lastly, the filenames or serial numbers are themselves randomized in a way that disallows an attacker to control the names or numbers to make their contribution predictable.  Given all of the above, and with a simple lookup table of 220 values, it may still be possible to crack the encryption in a plaintext or ciphertext attack if considerably more than a million files are submitted for the chosen attack.  I would guess that this code is very secure for all individual encryptions performed by an individual manually during their lifetime, even using the same set of password numbers during that entire time, but for use in a typical encryption server that processes thousands to millions of transactions per day, you would want to change the passwords each day.

In the process of developing this code, I read the very lengthy FAQs on the sci.crypt website, I read several versions of the famous "snake oil" FAQ, I read several papers on differential analysis, and I participated in the Cypherpunks forum for about seven months.  I also corresponded with a few of the well known crypto experts, but I have to say that the near universal opinion of the experts is that you cannot have a secure algorithmic crypto program that doesn't use the high-level mathematics as described above.

Or, if all you need to create is a private-key program such as mine, you would still have to generate a random bit-stream and XOR those bits against the plaintext file to get a secure encryption.  Crypto experts just don't trust bit-shuffling techniques, albeit that in the real world the best randomness is usually obtained by shuffling, as in playing cards or lottery tumblers.

One of the fascinating things about current cryptography is the discussion of quantum computers and the assumed fact that all password-encrypted files now archived by various agencies will be easily decrypted by the quantum computers when those computers are fully functional.  It suggests to me that the assumed level of security of conventional cryptography may be a false hope, especially if people have sent PGP messages that they can't afford to have read by the wrong people.  One possible positive point with this code is that:

1.)  Due to the design, the number of encryption layers per file is not limited.

2.)  The design requires physical multi-layer reshuffling rather than single pass XOR'ing, which tends to defeat the shortcut mathematical wizardry of quantum decryption.  Time will tell.

The following C code is DOS-based and I also have Visual BASIC 5 and DOS BASIC versions.  The DOS BASIC code, predictably, runs several times as slow as the DOS C code, however the VB5 code is twice as fast as the DOS C code.  This C code will compile O.K. using the Microsoft QuickC compiler circa 1991, but I've also specified typedefs so that the variables used in the program can be resized for different platforms.  If any of the variables are resized, you may have to resize one or more of the malloc() allocations in the ifn_cryp routine.

This program is called from a command line for encryption as follows:

C:\> CCRP filename /e passwordno1 passwordno2 passwordno3 ...

Decryption is called as follows:

C:\> CCRP filename /d passwordno1 passwordno2 passwordno3 ...

Version 3.1

ccrp.h:

/* CCRP.H  28.10.1996 */

typedef char C;                 /* char (strings, null-terminated) */
typedef double D;               /* double float (double precision) */
typedef float F;                /* float (single precision) */
typedef int I;                  /* short integer (signed) */
typedef long L;                 /* long integer (signed) */
typedef unsigned int U;         /* short integer (unsigned) */
typedef unsigned char UC;       /* unsigned character */
typedef void V;                 /* void data type */

I bitget(C * cstr, I ibit);
V bitput(C * cstr, I ibit, I iput);
V ifn_cryp(I * int1, I * int2, I * istk, C * cbuf, C * ctmp, I ibit, I ilen,
           I iopr);
V ifn_msgs(C * cmsg, I iofs, I irow, I icol, I ibrp, I iext);
V ifn_pack(C * cbuf, L llof, U ibuf, I iopr, struct _iobuf *ebuf);
V ifn_read(C * cbuf, L lbyt, U ibuf, struct _iobuf *ebuf);
V ifn_sort(I * int1, I * int2, I * istk, I imax);
V ifn_write(C * cbuf, L lbyt, U ibuf, struct _iobuf *ebuf);
U io_vadr(I inop);
V io_vcls(I iclr);
V io_vcsr(I irow, I icol, I icsr);
V io_vdsp(C * cdat, I irow, I icol, I iclr);

union REGS rg;                  /* DOS registers declaration (video) */
U _far *uvadr = 0;              /* video display pointer */

ccrp.c:

/* CCRP.C  Encrypt/Decrypt a DOS file */
/*         By: Dale Thorn             */
/*         Version 3.1                */
/*         Rev. 29.10.1996            */

#include "stdlib.h"
#include "string.h"
#include "stdio.h"
#include "dos.h"
#include "io.h"
#include "ccrp.h"

V main(I argc, C ** argv)
{                               /* command-line arguments (input file/offset) */
  C cmsg[23];                   /* initialize the User message string */
  U ibit = 0;                   /* initialize the bit offset in cbuf */
  U ibuf = 2048;                /* set maximum file buffer length */
  U idot;                       /* initialize the filename extension separator */
  I ieof = 0;                   /* initialize the EOF flag */
  U ilen;                       /* initialize a temporary length variable */
  U indx;                       /* initialize a temporary loop variable */
  I iopr;                       /* initialize the operation code */
  U irnd = 0;                   /* initialize the randomizer seed */
  L lbyt;                       /* initialize the file pointer variable */
  L llof;                       /* initialize the file length variable */
  L lrnd = 0;                   /* initialize the randomizer accumulator */
  U _far *uvadr = 0;            /* video display pointer */
  struct _iobuf *ebuf;          /* source file access structure */

  C *cbuf = (C *) malloc(2048); /* initialize the file buffer */
  C *ctmp = (C *) malloc(2048); /* initialize the temp buffer */
  I *int1 = (I *) malloc(3074); /* allocate the sort index array */
  I *int2 = (I *) malloc(3074); /* allocate the sort random number array */
  I *istk = (I *) malloc(3074); /* allocate the sort stack array */

  if (argc == 1) {              /* a command line was not supplied */
    ifn_msgs("Usage:  CCRP(v3.1)  filename  [/e /d /p /u]  [key]", 4, 24, 79, 0, 1);    /* display usage message [above] and exit */
  }
  if (argc < 3 || argc > 4) {   /* no. of parameters should be one or two */
    ifn_msgs("Invalid number of parameters", 4, 24, 79, 1, 1);
  }                             /* display no.-of-parameters message [above] and exit */
  if (argv[2][0] != '/') {      /* slash preceding parameter missing */
    ifn_msgs("Invalid operation parameter", 4, 24, 79, 1, 1);
  }                             /* display invalid-parameter message [above] and exit */
  strupr(argv[1]);              /* uppercase the filename */
  strupr(argv[2]);              /* uppercase the operation code */
  if (strchr("DEPU", argv[2][1]) == NULL) {     /* invalid parameter */
    ifn_msgs("Invalid operation parameter", 4, 24, 79, 1, 1);
  }                             /* display invalid-parameter message [above] and exit */
  idot = strcspn(argv[1], "."); /* position of filename extension separator */
  ilen = strlen(argv[1]);       /* length of filename */
  if (idot == 0 || idot > 8 || ilen - idot > 4) {       /* filename tests bad */
    ifn_msgs("Invalid filename", 4, 24, 79, 1, 1);
  }                             /* display invalid-filename message [above] and exit */
  if (idot < ilen) {            /* filename extension separator found! */
    if (strcspn(argv[1] + idot + 1, ".") < ilen - idot - 1) {   /* 2nd found! */
      ifn_msgs("Invalid filename", 4, 24, 79, 1, 1);
    }                           /* display invalid-filename message [above] and exit */
  }
  strcpy(cmsg, argv[1]);        /* copy filename to message */
  strcat(cmsg, " not found");   /* add "not found" to message */
  ebuf = fopen(argv[1], "rb+"); /* open the selected file */
  llof = filelength(fileno(ebuf));      /* filelength of selected file */
  if (ebuf == NULL || llof == -1L || llof == 0) {       /* length=0 or call failed */
    fclose(ebuf);               /* close the file */
    remove(argv[1]);            /* kill the zero-length file */
    ifn_msgs(cmsg, 4, 24, 79, 1, 1);    /* display message and exit */
  }
  iopr = argv[2][1] - 68;       /* opcode (1=encrypt, 0=decrypt, 12=pad bits) */
  if (argc == 4) {              /* a seed key was supplied */
    ilen = strlen(argv[3]);     /* length of optional seed key */
    for (indx = 0; indx < ilen; indx++) {       /* loop through the seed key */
      irnd = argv[3][indx];     /* character at byte position */
      switch (indx % 3) {       /* select on byte significance */
        case 0:                /* least significant byte */
          lrnd += irnd;         /* add to randomizer accum. */
          break;
        case 1:                /* 2nd least significant byte */
          lrnd += (L) irnd *256;        /* add to randomizer accum. */
          break;
        case 2:                /* most significant byte */
          lrnd += (L) irnd *65536;      /* add to randomizer accum. */
          break;
        default:
          break;
      }
    }
    irnd = (U) (lrnd % 32640) + 1;      /* mod randomizer seed to <= 32640 */
  }
  ifn_msgs("Please standby", 4, 24, 79, 0, 0);  /* standby message */

  if (iopr > 1) {               /* operation code is 'P' or 'U' */
    ifn_pack(cbuf, llof, ibuf, iopr, ebuf);     /* add 8th bits if 7-bit file */
  }                             /* NOTE: ifn_pack does NOT return here */
  srand(irnd);                  /* initialize the random number generator */
  for (lbyt = 0; lbyt < llof; lbyt += ibuf) {   /* process in ibuf segments */
    if (lbyt + ibuf >= llof) {  /* current file pointer + ibuf spans EOF */
      ibuf = (U) (llof - lbyt); /* reset maximum file buffer length */
      ieof = 1;                 /* set the EOF flag ON */
    }
    ifn_read(cbuf, lbyt, ibuf, ebuf);   /* read data into the file buffer */
    while (1) {                 /* loop to process bit groups in cbuf */
      ilen = (rand() / 26) + 256;       /* buffer seg. bit-len.: 256<=ilen<=1536 */
      if (ibit + ilen > ibuf * 8) {     /* current bit-pointer+ilen spans cbuf */
        if (ieof) {             /* EOF flag is ON */
          ilen = ibuf * 8 - ibit;       /* reset bit-length of buffer segment */
        } else {                /* EOF flag is OFF; adjust file pointer */
          ifn_write(cbuf, lbyt, ibuf, ebuf);    /* write data to the file */
          lbyt -= (ibuf - ibit / 8);    /* set file ptr to reload from ibit */
          ibit %= 8;            /* set ibit to first byte of <new> cbuf */
          break;                /* exit loop to reload cbuf from lbyt */
        }
      }                         /* encrypt or decrypt the current segment [below] */
      ifn_cryp(int1, int2, istk, cbuf, ctmp, (I) ibit, ilen, iopr);
      ibit += ilen;             /* increment ibit to next bit-segment */
      if (ibit == ibuf * 8) {   /* loop until ibit == length of cbuf */
        ifn_write(cbuf, lbyt, ibuf, ebuf);      /* write data to the file */
        ibit = 0;               /* set ibit to first byte of <new> cbuf */
        break;
      }
    }
  }
  ifn_msgs("Translation complete", 4, 24, 79, 0, 1);    /* disp. message & exit */
}

I bitget(C * cstr, I ibit)
{                               /* get a bit-value from a string */
  I ival;                       /* initialize the bit value */

  switch (ibit % 8) {           /* switch on bit# within character */
    case 0:                    /* bit #0 in target character */
      ival = 1;                 /* value of bit #0 */
      break;
    case 1:                    /* bit #1 in target character */
      ival = 2;                 /* value of bit #1 */
      break;
    case 2:                    /* bit #2 in target character */
      ival = 4;                 /* value of bit #2 */
      break;
    case 3:                    /* bit #3 in target character */
      ival = 8;                 /* value of bit #3 */
      break;
    case 4:                    /* bit #4 in target character */
      ival = 16;                /* value of bit #4 */
      break;
    case 5:                    /* bit #5 in target character */
      ival = 32;                /* value of bit #5 */
      break;
    case 6:                    /* bit #6 in target character */
      ival = 64;                /* value of bit #6 */
      break;
    case 7:                    /* bit #7 in target character */
      ival = 128;               /* value of bit #7 */
      break;
    default:
      break;
  }
  return ((cstr[ibit / 8] & ival) != 0);        /* return value of target bit */
}

V bitput(C * cstr, I ibit, I iput)
{                               /* put a bit-value to a string */
  I ival;                       /* initialize the bit value */
  I ipos = ibit / 8;            /* position of 8-bit char. in cstr */

  switch (ibit % 8) {           /* switch on bit# within character */
    case 0:                    /* bit #0 in target character */
      ival = 1;                 /* value of bit #0 */
      break;
    case 1:                    /* bit #1 in target character */
      ival = 2;                 /* value of bit #1 */
      break;
    case 2:                    /* bit #2 in target character */
      ival = 4;                 /* value of bit #2 */
      break;
    case 3:                    /* bit #3 in target character */
      ival = 8;                 /* value of bit #3 */
      break;
    case 4:                    /* bit #4 in target character */
      ival = 16;                /* value of bit #4 */
      break;
    case 5:                    /* bit #5 in target character */
      ival = 32;                /* value of bit #5 */
      break;
    case 6:                    /* bit #6 in target character */
      ival = 64;                /* value of bit #6 */
      break;
    case 7:                    /* bit #7 in target character */
      ival = 128;               /* value of bit #7 */
      break;
    default:
      break;
  }
  if (iput) {                   /* OK to set the bit ON */
    if (!(cstr[ipos] & ival)) { /* bit is NOT already ON */
      cstr[ipos] += ival;       /* set bit ON by adding ival */
    }
  } else {                      /* OK to set the bit OFF */
    if (cstr[ipos] & ival) {    /* bit is NOT already OFF */
      cstr[ipos] -= ival;       /* set bit OFF by subt. ival */
    }
  }
}

V ifn_cryp(I * int1, I * int2, I * istk, C * cbuf, C * ctmp, I ibit, I ilen, I iopr)
{
  I indx;                       /* initialize the for-next loop counter */

  for (indx = 0; indx < ilen; indx++) { /* loop through ilen array elements */
    int1[indx] = indx;          /* bit offsets from current ibit offset */
    int2[indx] = rand();        /* random number values for sort function */
  }
  ifn_sort(int1, int2, istk, ilen - 1); /* Quicksort by random no. array */
  memcpy(ctmp, cbuf, 2048);     /* copy data buffer to temp destination buffer */
  if (iopr) {                   /* encrypt operation */
    for (indx = 0; indx < ilen; indx++) {       /* loop thru ilen array elements */
      bitput(ctmp, indx + ibit, bitget(cbuf, int1[indx] + ibit));       /*encrypt */
    }
  } else {                      /* decrypt operation */
    for (indx = 0; indx < ilen; indx++) {       /* loop thru ilen array elements */
      bitput(ctmp, int1[indx] + ibit, bitget(cbuf, indx + ibit));       /*decrypt */
    }
  }
  memcpy(cbuf, ctmp, 2048);     /* copy temp destination buffer to data buffer */
}

V ifn_msgs(C * cmsg, I iofs, I irow, I icol, I ibrp, I iext)
{                               /* display msgs */
  io_vcls(7);                   /* clear the screen */
  io_vdsp(cmsg, 4, iofs, 7);    /* display the user message */
  if (ibrp) {                   /* OK to sound user-alert (beep) */
    printf("\a");               /* sound the user-alert */
  }
  if (iext) {                   /* OK to exit the program */
    io_vcsr(5, 0, 0);           /* relocate the cursor */
    fcloseall();                /* close all open files */
    exit(0);                    /* return to DOS */
  } else {                      /* do NOT exit the program */
    io_vcsr(irow, icol, 0);     /* 'hide' the cursor */
  }
}

V ifn_pack(C * cbuf, L llof, U ibuf, I iopr, struct _iobuf *ebuf)
{
  I ibit;                       /* initialize a temporary loop variable */
  U ichr;                       /* initialize a temporary loop variable */
  U incr;                       /* initialize the bit-pad loop increment */
  U itmp = ibuf;                /* make a copy of the file buffer length */
  L lbyt;                       /* initialize the file pointer variable */
  L lcnt = 0;                   /* initialize the current total one-bits */
  L ltmp;                       /* initialize a copy of current total one-bits */
  L ltot;                       /* initialize the no. of 8th bits to set ON */

  for (lbyt = 0; lbyt < llof; lbyt += itmp) {   /* process in itmp segments */
    if (lbyt + itmp > llof) {   /* current file pointer + itmp spans EOF */
      itmp = (U) (llof - lbyt); /* reset maximum file buffer length */
    }
    ifn_read(cbuf, lbyt, itmp, ebuf);   /* read data into the file buffer */
    if (iopr == 17) {           /* opcode == unpad bits */
      for (ichr = 0; ichr < itmp; ichr++) {     /* process bytes in cbuf */
        bitput(cbuf, ichr * 8 + 7, 0);  /* set each 8th bit OFF */
      }
      ifn_write(cbuf, lbyt, itmp, ebuf);        /* save current buffer to file */
    } else {                    /* opcode == pad bits - validation pass */
      for (ichr = 0; ichr < itmp; ichr++) {     /* process bytes in cbuf */
        for (ibit = 0; ibit < 8; ibit++) {      /* process bits in cbuf */
          lcnt += bitget(cbuf, ichr * 8 + ibit);        /* add 0/1 bit to total */
          if (ibit == 7) {      /* this is the 8th bit of ichr */
            if (bitget(cbuf, ichr * 8 + ibit)) {        /* the 8th bit is ON */
              ifn_msgs("8th bit(s) are ON - can't do bit-pad", 4, 24, 79, 1, 1);
            }                   /* can't add bits - display message (above) and exit */
          }
        }
      }
    }
  }
  if (iopr == 17) {             /* opcode == unpad bits */
    ifn_msgs("Bit-unpadding complete", 4, 24, 79, 0, 1);        /* message & exit */
  }
  ltot = llof * 4 - lcnt;       /* set ltot as the no. of 8th bits to set ON */
  if (ltot > 0) {               /* one-bits < zero bits; commence padding */
    if (ltot > llof) {          /* one-bits required exceed total bytes */
      ltot = llof;              /* reset one-bits to equal total bytes */
    }

    itmp = ibuf;                /* reset the copy of the file buffer length */
    ltmp = ltot;                /* make a copy of the 8th bits to set ON */
    for (lbyt = 0; lbyt < llof; lbyt += itmp) { /* process in itmp segments */
      if (lbyt + itmp > llof) { /* current file pointer + itmp spans EOF */
        itmp = (U) (llof - lbyt);       /* reset maximum file buffer length */
      }
      ifn_read(cbuf, lbyt, itmp, ebuf); /* read data into the file buffer */
      incr = (U) ((llof - lbyt) / ltmp);        /* set the bit-pad loop increment */
      for (ichr = 0; ichr < itmp; ichr += incr) {       /* loop to set 8th bits */
        bitput(cbuf, ichr * 8 + 7, 1);  /* set each 8th bit ON */
        ltmp--;                 /* decrement the total one-bits padded */
        if (ltmp == 0) {        /* all 8th bits are now set ON */
          break;                /* all 8th bits are ON - exit ichr loop */
        }
      }
      ifn_write(cbuf, lbyt, itmp, ebuf);        /* save current buffer to file */
      if (ltmp == 0) {          /* all 8th bits are now set ON */
        break;                  /* all 8th bits are ON - exit lbyt loop */
      }
    }
    ifn_msgs("Bit-padding complete", 4, 24, 79, 0, 0);  /* disp.message only */
  } else {                      /* one-bits >= zero bits; padding not needed */
    ifn_msgs("Bit-padding not needed", 4, 24, 79, 1, 0);        /* disp.msg.& exit */
    ltot = 0;                   /* reset one-bits required for below message */
  }
  io_vcsr(6, 0, 0);             /* relocate the cursor */
  printf("%s%ld", "Total bits in source: ", llof * 8);  /* total bits in file */
  io_vcsr(8, 0, 0);             /* relocate the cursor */
  printf("%s%ld", "Total one-bits begin: ", lcnt);      /* one-bits before pad */
  io_vcsr(10, 0, 0);            /* relocate the cursor */
  printf("%s%ld\n", "Total one-bits added: ", ltot);    /* no. one-bits added */
  fcloseall();                  /* close all open files */
  exit(0);                      /* return to DOS */
}

V ifn_sort(I * int1, I * int2, I * istk, I imax)
{                               /* array Quicksort function */
  I iext;                       /* initialize the outer-loop exit flag */
  I ilow;                       /* initialize the low array pointer */
  I irdx = 0;                   /* initialize the sort radix */
  I isp1;                       /* initialize the low stack pointer */
  I isp2;                       /* initialize the top stack pointer */
  I itop;                       /* initialize the top array pointer */
  I iva1;                       /* initialize array value from low stack pointer */
  I iva2;                       /* initialize array value from low stack pointer */

  istk[0] = 0;                  /* initialize the low array pointer */
  istk[1] = imax;               /* initialize the top array pointer */
  while (irdx >= 0) {           /* loop until sort radix < 0 */
    isp1 = istk[irdx + irdx];   /* set the low stack pointer */
    isp2 = istk[irdx + irdx + 1];       /* set the top stack pointer */
    irdx--;                     /* decrement the sort radix */
    iva1 = int1[isp1];          /* get array value from low stack pointer */
    iva2 = int2[isp1];          /* get array value from low stack pointer */
    itop = isp2 + 1;            /* set the top array pointer */
    ilow = isp1;                /* set the low array pointer */
    while (1) {                 /* loop to sort within the radix limit */
      itop--;                   /* decrement the top array pointer */
      if (itop == ilow) {       /* top array pointer==low array pointer */
        break;                  /* skip to next radix value */
      }
      if (iva2 > int2[itop]) {  /* value @low pointer>value @top pointer */
        int1[ilow] = int1[itop];        /* swap low and top array values */
        int2[ilow] = int2[itop];        /* swap low and top array values */
        iext = 0;               /* initialize outer-loop exit flag */
        while (1) {             /* loop to compare and swap array values */
          ilow++;               /* increment the low array pointer */
          if (itop == ilow) {   /* top array pointer==low array pointer */
            iext = 1;           /* set outer-loop exit flag ON */
            break;              /* skip to next radix value */
          }
          if (iva2 < int2[ilow]) {      /* value @low ptr.<value @low ptr. */
            int1[itop] = int1[ilow];    /* swap top and low array values */
            int2[itop] = int2[ilow];    /* swap top and low array values */
            break;              /* repeat sort within the radix limit */
          }
        }
        if (iext) {             /* outer-loop exit flag is ON */
          break;                /* skip to next radix value */
        }
      }
    }
    int1[ilow] = iva1;          /* put array value from low stack pointer */
    int2[ilow] = iva2;          /* put array value from low stack pointer */
    if (isp2 - ilow > 1) {      /* low segment-width is > 1 */
      irdx++;                   /* increment the sort radix */
      istk[irdx + irdx] = ilow + 1;     /* reset low array pointer */
      istk[irdx + irdx + 1] = isp2;     /* reset top array pointer */
    }
    if (itop - isp1 > 1) {      /* top segment-width is > 1 */
      irdx++;                   /* increment the sort radix */
      istk[irdx + irdx] = isp1; /* reset low array pointer */
      istk[irdx + irdx + 1] = itop - 1; /* reset top array pointer */
    }
  }
}

V ifn_read(C * cbuf, L lbyt, U ibuf, struct _iobuf *ebuf)
{                               /* read f/binary */
  fseek(ebuf, lbyt, SEEK_SET);  /* set the buffer-read pointer */
  fread((V *) cbuf, 1, ibuf, ebuf);     /* read data from the binary file */
}

V ifn_write(C * cbuf, L lbyt, U ibuf, struct _iobuf *ebuf)
{                               /* write t/binary */
  fseek(ebuf, lbyt, SEEK_SET);  /* set the buffer-write pointer */
  fwrite((V *) cbuf, 1, ibuf, ebuf);    /* write data to the binary file */
}

U io_vadr(I inop)
{                               /* get video address (color or b/w) */
  rg.h.ah = 15;                 /* video-address function */
  int86(0x10, &rg, &rg);        /* call DOS for video address */
  if (rg.h.al == 7) {           /* register A-low is 7 */
    return (0xb000);            /* return b/w address */
  } else {                      /* register A-low is NOT 7 */
    return (0xb800);            /* return color address */
  }
}

V io_vcls(I iclr)
{                               /* clear screen function */
  I irow;                       /* initialize the row number variable */
  C cdat[81];                   /* initialize the row data buffer */

  memset(cdat, ' ', 80);        /* clear the row data buffer */
  cdat[80] = '\0';              /* terminate the row data buffer */
  for (irow = 0; irow < 25; irow++) {   /* loop thru the screen rows */
    io_vdsp(cdat, irow, 0, iclr);       /* display each <blank> screen row */
  }
}

V io_vcsr(I irow, I icol, I icsr)
{                               /* set cursor position [and size] */
  rg.h.ah = 2;                  /* cursor-position function */
  rg.h.bh = 0;                  /* video page zero */
  rg.h.dh = (C) irow;           /* row number */
  rg.h.dl = (C) icol;           /* column number */
  int86(0x10, &rg, &rg);        /* call DOS to position cursor */
  if (icsr) {                   /* cursor-size specified */
    rg.h.ah = 1;                /* cursor-size function */
    rg.h.ch = (C) (13 - icsr);  /* set cursor-begin line */
    rg.h.cl = 12;               /* set cursor-end line */
    int86(0x10, &rg, &rg);      /* call DOS to set cursor size */
  }
}

V io_vdsp(C * cdat, I irow, I icol, I iclr)
{                               /* display data on screen */
  I ilen = strlen(cdat);        /* length of string to be displayed */
  I iptr;                       /* byte-counter for displayed string */
  U uclr = iclr * 256;          /* unsigned attribute high-byte value */

  if (!uvadr) {                 /* video pointer segment not set */
    FP_SEG(uvadr) = io_vadr(0); /* set video pointer segment */
  }
  FP_OFF(uvadr) = irow * 160 + icol * 2;        /* set video pointer offset */
  for (iptr = 0; iptr < ilen; iptr++) { /* loop thru displayed string */
    *uvadr = uclr + (UC) cdat[iptr];    /* put data to video memory */
    uvadr++;                    /* increment video display pointer */
  }
}

Version 4.3


ccrp.h:

/* CCRP.H - Version 4.3 */
typedef char C;                 /* char (strings, null-terminated) */
typedef double D;               /* double float (double precision) */
typedef float F;                /* float (single precision) */
typedef int I;                  /* short integer (signed) */
typedef long L;                 /* long integer (signed) */
typedef unsigned int U;         /* short integer (unsigned) */
typedef unsigned char UC;       /* unsigned character */
typedef void V;                 /* void data type */

I bitget(C * cstr, I ibit);
V bitput(C * cstr, I ibit, I iput);
V ifn_cryp(U ibuf, FILE * ebuf, I iopr, L llof, L lrnd);
V ifn_msgs(C * cmsg, I iofs, I irow, I icol, I ibrp, I iext);
V ifn_read(C * cbuf, L lbyt, U ibuf, FILE * ebuf);
V ifn_sort(I * intl, L * lnt2, I * istk, I imax);
V ifn_write(C * cbuf, L lbyt, U ibuf, FILE * ebuf);
U io_vadr(I inop);
V io_vcls(I iclr);
V io_vcsr(I irow, I icol, I icsr);
V io_vdsp(C * cdat, I irow, I icol, I iclr);
L ltable(L lrnd);

union REGS rg;                  /* DOS registers declaration (video) */
U _far *uvadr = 0;              /* video display pointer */

ccrp.c:

/* CCRP.C  - Version 4.3 */
#include "stdlib.h"
#include "string.h"
#include "stdio.h"
#include "dos.h"
#include "io.h"
#include "ccrp.h"

V main(I argc, C **argv)
{                               /* get user's command-line arguments */
  C cmsg[64];                   /* initialize the User message string */
  C cwrd[58] = "!#$%&'()+-.0123456789@ABCDEFGHIJKLMNOPORSTUVWXYZ[]^_`{}~";
  C cwrx[58] = "                                                        ";
  U ibeg;                       /* initialize the loop-begin variable */
  U ibuf = 2048;                /* set the maximum file buffer length */
  C *cchr;                      /* initialize a temporary character variable */
  U idot;                       /* initialize the filename extension separator */
  U idx2;                       /* initialize a temporary loop variable */
  U iend;                       /* initialize the loop-ending variable */
  U ilen;                       /* initialize a temporary length variable */
  U incr;                       /* initialize the loop-increment variable */
  U indx;                       /* initialize a temporary loop variable */
  I iopr;                       /* initialize the operation code */
  U iwrd = strlen(cwrd);        /* initialize length of filename chars */
  L llof;                       /* initialize the file length variable */
  L lrnd;                       /* initialize the lookup table value */
  FILE *ebuf;                   /* get next available DOS file handle */
  U _far *uvadr = 0;            /* video display pointer */
  I int1[58];                   /* allocate filename sort index array */
  L 1 nt2[58];                  /* allocate filename sort lookup array */
  I istk[58];                   /* allocate filename sort stack array */

  if (argc == 1) {              /* a command line was not supplied */
    strcpy(cmsg, "Usage: CCRP(v4.3) filename [/e /d] [keyl key2 ....]");
    ifn_msgs(cmsg, 4, 24, 79, 0, 1);    /* display usage message and exit */
  }
  if (argc < 4 || argc > 15) {  /* no. of seed keys should be one to 12 */
    ifn_msgs("Invalid number of parameters", 4, 24, 79, 1, 1);
  }                             /* display error message [above] and exit */
  if (argv[2][0] != '/') {      /* slash preceding opcode param missing */
    ifn_msgs("Invalid operation parameter", 4, 24, 79, 1, 1);
  }                             /* display error message [above] and exit */

  strupr(argv[1]);              /* uppercase the target filename */
  strupr(argv[2]);              /* uppercase the operation code */
  if (strchr("ED", argv[2][1]) == NULL) {       /* invalid opcode parameter */
    ifn_msgs("Invalid operation parameter", 4, 24, 79, 1, 1);
  }                             /* display error message [above] and exit */
  idot = strcespn(argv[1], ".");        /* position of filename extension separator */
  ilen = strlen(argv[1]);       /* length of target filename */
  if (idot == 0 || idot > 8 || ilen - idot > 4) {       /* filename is bad */
    ifn_msgs("Invalid filename", 4, 24, 79, 1, 1);      /* filename is bad */
  }                             /* display error message [above] and exit */
  if (idot < ilen) {            /* filename extension separator found! */
    if (strcespn(argv[1] + idot + 1, ".") < ilen - idot - 1) {
      ifn_msgs("Invalid filename", 4, 24, 79, 1, 1);    /* 2nd '.' was found! */
    }                           /* display error message [above] and exit */
    if (idot == ilen - 1) {     /* extension separator at end of filename */
      ilen--;                   /* decrement length of target filename */
      argv[1][ilen] = '\ 0';    /* decrement length of target filename */
    }
  }

  ebuf = fopen(argv[1], "rbt+");        /* open the selected file */
  llof = filelength(fileno(ebuf));      /* get length of selected file */
  if (ebuf == NULL || llof == -1L || llof == 0) {       /* length=0 or call failed */
    fclose(ebuf);               /* close the selected file */
    remove(argv[1]);            /* kill the zero-length file */
    strcpy(cmsg, argv[1]);      /* copy filename to message */
    strcat(cmsg, " not found"); /* add "not found" to message */
    ifn_msgs(cmsg, 4, 24, 79, 1, 1);    /* display message and exit */
  }
  iopr = argv[2][1] - 68;       /* opcode (l=encrypt, O=decrypt) */
  if (iopr == 1) {              /* this is the encrypt operation */
    ibeg = 3;                   /* set the loop-begin variable */
    iend = argc;                /* set the loop-ending variable */
    incr = 1;                   /* set the loop-increment variable */
  } else {                      /* this is the decrypt operation */
    ibeg = argc - 1;            /* set the loop-begin variable */
    iend = 2;                   /* set the loop-ending variable */
    incr = -1;                  /* set the loop-increment variable */
  }
  for (indx = ibeg; indx != iend; indx += incr) {       /* loop thru #of seed keys */
    lrnd = atol(argv[indx]) % (L) 1048576;      /* get lookup table seed key */
    for (idx2 = 0; idx2 < iwrd; idx2++) {       /* loop through array elements */
      intl[idx2] = idx2;        /* offsets from current byte offset */
      lrnd = ltable(lrnd);      /* get the next lookup table value */
      lnt2[idx2] = lrnd;        /* put lookup value to sort array */
    }

    ifn_sort(int1, lnt2, istk, iwrd - 1);       /* sort lookup array */
    for (idx2 = 0; idx2 < iwrd; idx2++) {       /* loop thru filename chars */
      cwrx[int1[idx2]] = cwrd[idx2];
    }                           /* shuffle bytes in valid filename chars [above] */

    lrnd = atol(argv[indx]) % (L) 1048576;      /* get lookup table seed key */
    for (idx2 = 0; idx2 < ilen; idx2++) {       /* loop thru filename chars */
      cchr = strchr(cwrx, argv[1][idx2]);       /* filename char. position */
      if (cchr == NULL) {       /* character not found in filename */
        ifn_msgs("Invalid character in filename", 4, 24, 79, 1, 1);
      }                         /* display error message [above] and exit */

      lrnd = (lrnd + (cchr - cwrx + 1)) % (L) 1048576;  /* add value to seed */
      lrnd = ltable(lrnd);      /* reiterate value of seed key */
    }
    if (iopr == 1) {            /* encrypt operation specified */
      ifn_msgs("Encrypting layer", 4, 24, 79, 0, 0);    /* encrypt msg. */
    } else {                    /* decrypt operation specified */
      ifn_msgs("Decrypting layer", 4, 24, 79, 0, 0);    /* decrypt msg. */
      itoa(indx - 2, cmsg, 10); /* convert ‘'indx' to string */
      ifn_msgs(cmsg, -21, 24, 79, 0, 0);        /* show layer number message */
      ifn_cryp(ibuf, ebuf, iopr, llof, lrnd);   /* encrypt or decrypt */
    }
    ifn_msgs("Translation complete", 4, 24, 79, 0, 1);
  }

  V ifn_cryp(U ibuf, FILE * ebuf, I iopr, L llof, L lrnd) {     /* encrypt routine */
    C cmsg[64];                 /* initialize the User message string */
    U ibit = 0;                 /* initialize the bit offset in cbuf */
    I ieof = 0;                 /* initialize the EOF flag */
    U ilen;                     /* initialize a temporary length variable */
    U indx;                     /* initialize the for-next loop counter */
    L lbyt;                     /* initialize the file pointer variable */
    C *cbuf = (C *) malloc(2048);       /* initialize the file buffer */
    C *ctmp = (C *) malloc(2048);       /* initialize the temp buffer */
    I *intl = (I *) malloc(3074);       /* allocate the sort index array */
    L *lnt2 = (L *) malloc(6148);       /* allocate sort lookup number array */
    I *istk = (I *) malloc(3074);       /* allocate the sort stack array */

    for (lbyt = 0; lbyt < llof; lbyt += ibuf) { /* process in ibuf segments */
      if (llof > (L) ibuf) {    /* so we don't divide by zero */
        ltoa(lbyt / (llof / 100), cmsg, 10);    /* convert pet. to string */
        strcat(cmsg, "%");      /* append '%' symbol to message */
        ifn_msgs("    ", -24, 24, 79, 0, 0);    /* erase prev.complete msg. */
        ifn_msgs(cmsg, -24, 24, 79, 0, 0);      /* show pct. completed msg. */
      }
      if (lbyt + ibuf >= llof) {        /* current file pointer + ibuf spans EOF */
        ibuf = (U) (llof - lbyt);       /* reset file buffer length */
        ieof = 1;               /* set the EOF flag ON */
      }
      ifn_read(cbuf, lbyt, ibuf, ebuf); /* read data into the file buffer */
      while (1) {               /* loop to process bit groups in cbuf */
        irnd = ltable(lrnd);    /* get the next lookup table value */
        ilen = (U) (lrnd / 832 + 256);  /* buffer bitlen: 256<=ilen<=1516 */
        if (ibit + ilen > ibuf * 8) {   /* curr. bit-pointer+tilen spans cbuf */
          if (ieof) {           /* EOF flag is ON */
            ilen = ibuf * 8 - ibit;     /* reset bit-length of buffer segment */
          } else {              /* EOF flag is OFF; adjust file pointer */
            ifn_write(cbuf, lbyt, ibuf, ebuf);  /* write data to the file */
            lbyt -= (ibuf - ibit / 8);  /* set lbyt to load from ibit */
            ibit %= 8;          /* set ibit to first byte of <new> cbhuf */
            break;              /* exit loop to reload cbuf from lbyt */
          }
        }                       /* encrypt or decrypt the current segment [below] */
        for (indx = 0; indx < ilen; indx++) {   /* loop through array elements */
          intl[indx] = indx;    /* bit offsets from current ibit offset */
          lrnd = ltable(lrnd);  /* get the next lookup table value */
          int2[indx] = lrnd;    /* lookup values for sort function */
        }

        ifn_sort(intl, lnt2, istk, ilen - 1);   /* sort lookup array */
        memcpy(ctmp, cbuf, 2048);       /* copy data buffer to dest. buffer */
        if (iopr) {             /* this is the encrypt operation */
          for (indx = 0; indx < ilen; indx++) { /* loop through bit group */
            bitput(ctmp, indx + ibit, bitget(cbuf, intl[indx] + ibit));
          }                     /* move bits to "random" positions [above] */
        } else {                /* this is the decrypt operation */
          for (indx = 0; indx < ilen; indx++) { /* loop through bit group */
            bitput(ctmp, intl[indx] + ibit, bitget(cbuf, indx + ibit));
          }                     /* restore bits from "random" positions [above] */
        }
        memcpy(cbuf, ctmp, 2048);       /* copy dest. buffer to data buffer */
        ibit += ilen;           /* increment ibit to next bit-segment */
        if (ibit == ibuf * 8) { /* loop until ibit == length of cbuf */
          ifn_write(cbuf, lbyt, ibuf, ebuf);    /* put current buffer to file */
          ibit = 0;             /* set ibit to first byte of <new> cbuf */
          break;                /* ibit == length of cbhuf; exit loop */
        }
      }
    }

    free(chuf);                 /* deallocate the file buffer */
    free(ctmp);                 /* deallocate the temp buffer */
    free(intl);                 /* deallocate the sort index array */
    free(lnt2);                 /* deallocate the sort lookup array */
    free(istk);                 /* deallocate the sort stack array */
  }

  I bitget(C * cstrl, I ibit) { /* get a bit-value from a string */
    I ival;                     /* initialize the bit value */
    switch (ibit % 8) {         /* switch on bit# within character */
      case 0:                  /* bit #0 in target character */
        ival = 1;               /* value of bit #0 */
        break;
      case 1:                  /* bit #1 in target character */
        ival = 2;               /* value of bit #1 */
        break;
      case 2:                  /* bit #2 in target character */
        ival = 4;               /* value of bit #2 */
        break;
      case 3:                  /* bit #3 in target character */
        ival = 8;               /* value of bit #3 */
        break;
      case 4:                  /* bit #4 in target character */
        ival = 16;              /* value of bit #4 */
        break;
      case 5:                  /* bit #5 in target character */
        ival = 32;              /* value of bit #5 */
        break;
      case 6:                  /* bit #6 in target character */
        ival = 64;              /* value of bit #6 */
        break;
      case 7:                  /* bit #7 in target character */
        ival = 128;             /* value of bit #7 */
        break;
      default:
        break;
    }
    return ((cstrl[ibit / 8] & ival) != 0);
  }                             /* return the value of the target bit [above] */

  V bitput(C * cstrl, I ibit, I iput) {
    I ival;
    I ipos = ibit / 8;
    switch (ibit % 8) {
      case 0:                  /* bit #0 in target character */
        ival = 1;               /* value of bit #0 */
        break;
      case 1:                  /* bit #1 in target character */
        ival = 2;               /* value of bit #1 */
        break;
      case 2:                  /* bit #2 in target character */
        ival = 4;               /* value of bit #2 */
        break;
      case 3:                  /* bit #3 in target character */
        ival = 8;               /* value of bit #3 */
        break;
      case 4:                  /* bit #4 in target character */
        ival = 16;              /* value of bit #4 */
        break;
      case 5:                  /* bit #5 in target character */
        ival = 32;              /* value of bit #5 */
        break;
      case 6:                  /* bit #6 in target character */
        ival = 64;              /* value of bit #6 */
        break;
      case 7:                  /* bit #7 in target character */
        ival = 128;             /* value of bit #7 */
        break;
      default:
        break;
    }

    if (iput) {                 /* OK to set the bit ON */
      if (!(cstrl[ipos] & ival)) {      /* bit is NOT already ON */
        cstrl[ipos] += ival;    /* set bit ON by adding ival */
      }
    } else {                    /* OK to set the bit OFF */
      if (cstrl[ipos] & ival) { /* bit is NOT already OFF */
        cstrl[ipos] -= ival;    /* set bit OFF by subt. ival */
      }
    }
  }

  V ifn_sort(I * intl, L * lnt2, I * istk, I imax) {    /* array Quicksort function */
    I iex1;                     /* initialize the outer-loop exit flag */
    I iex2;                     /* initialize the inner-loop exit flag */
    I ilap;                     /* initialize the low array pointer */
    *ilsp;                      /* initialize the low stack pointer */
    I irdx = 0;                 /* initialize the sort radix */
    I itap;                     /* initialize the top array pointer */
    I itsp;                     /* initialize the top stack pointer */
    I ival;                     /* initialize array value from low stack pointer */
    L lva2;                     /* initialize array value from low stack pointer */

    istk[0] = 0;
    istk[1] = imax;
    while (irdx >= 0) {
      ilsp = istk[irdx + irdx];
      itsp = istk[irdx + irdx + 1];
      irdx--;
      iva1 = int1[ilsp];
      lva2 = lnt2[ilsp];
      ilap = ilsp;
      itap = itsp + 1;
      ilap = ilsp;
      itap = itsp + 1;
      iexl = 0;
      while (!iexl) {
        itap--;
        if (itap == ilap) {
          iex1 = 1;
        } else if (lva2 > lnt2[itap]) { /* value @low ptr > value @top ptr */
          int1[ilap] = int1[itap];      /* swap low and top array values */
          int2[ilap] = lnt2[itap];      /* swap low and top array values */
          iex2 = 0;             /* initialize the inner-loop exit flag */
          while (!iex2) {       /* loop to compare and swap array values */
            ilap++;             /* increment the low array pointer */
            if (itap == ilap) { /* top array pointer==low array pointer */
              iex1 = 1;         /* set the outer-loop exit flag ON */
              iex2 = 1;         /* set the inner-loop exit flag ON */
            } else if (lva2 < lnt2[ilap]) {     /* value@low ptr<value@low ptr */
              int1[itap] = int1[ilap];  /* swap top and low array values */
              lnt2[itap] = lnt2[ilap];  /* swap top and low array values */
              iex2 = 1;         /* set the inner-loop exit flag ON */
            }
          }
        }
      }

      int1[ilap] = iva1;        /* put array value from low stack pointer */
      lnt2[ilap] = lva2;        /* put array value from low stack pointer */
      if (itsp - ilap > 1) {    /* low segment-width is > 1 */
      irdx++:                  /* increment the sort radix */
        istk[irdx + irdx] = ilap + 1;   /* reset low array pointer */
        istk[irdx + irdx + 1] = itsp;   /* reset top array pointer */
      }
      if (itap - ilsp > 1) {    /* top segment-width is > 1 */
        irdx++;                 /* increment the sort radix */
        istk[irdx + irdx] = ilsp;       /* reset low array pointer */
        istk[irdx + irdx + 1] = itap - 1;       /* reset top array pointer */
      }
    }
  }

  V ifn_msgs(C * cmsg, I iofs, I irow, I icol, I ibrp, I iext) {        /* display msgs */
    if (iofs >= 0) {            /* OK to clear screen */
      io_vcls(7);               /* clear the screen */
    }
    io_vdsp(cmsg, 4, abs(iofs), 7);     /* display the user message */
    if (ibrp) {                 /* OK to sound user-alert (beep) */
      printf("\ a");            /* sound the user-alert */
    }
    if (iext) {                 /* OK to exit the program */
      io_vcsr(5, 0, 0);         /* relocate the cursor */
      fcloseall();              /* close all open files */
      exit(0);                  /* return to DOS */
    } else {                    /* do NOT exit the program */
      io_vcsr(irow, icol, 0);   /* ‘thide' the cursor */
    }
  }

  L ltable(L lrnd) {            /* get next lookup table no. */
    L l1;                       /* initialize temp value #1 */
    L l2;                       /* initialize temp value #2 */
    L l3;                       /* initialize temp value #3 */
    L l4;                       /* initialize temp value #4 */
    l1 = lrnd % 8;              /* These 5 lines are an integer-only */
    l2 = (lrnd - l1) % 16;      /* equivalent to the floating-point */
    l3 = (lrnd - l1 - l2) % 64; /* operations formerly used in this, */
    l4 = (lrnd - l1 - l2 - l3); /* the 16-bit DOS version of the code */
    return (l1 * 214013 + l2 * 82941 + l3 * 17405 + l4 * 1021 + 2531011) % 1048576;
  }

  V ifn_read(C * cbuf, L lbyt, U ibuf, FILE * ebuf) {   /* read from binary file */
    fseek(ebuf, lbyt, SEEK_SET);        /* set the buffer-read pointer */
    fread((V *) cbuf, 1, ibuf, ebuf);   /* read data from the binary file */
  }
  V ifn_write(C * cbuf, L lbyt, U ibuf, FILE * ebuf) {  /* write to binary file */
    fseek(ebuf, lbyt, SEEK_SET);        /* set the buffer-write pointer */
    fwrite((V *) cbuf, 1, ibuf, ebuf);  /* write data to the binary file */
  }
  U io_vadr(I inop) {           /* get video address (color or b/w) */
    rg.h.ah = 15;
    int86(0x10, &rg, &rg);
    if (rg.h.al == 7) {
      return (0xb000);
    } else {
      return (0xb800);
    }
  }

  V io_vcls(I iclr) {
    I irow;
    C cdat[81];
    memset(cdat, ' ', 80);
    cdat[80] '\ 0';
    for (irow = 0; irow < 25; irow++) {
      io_vdsp(cdat, irow, 0, iclr);
    }
  }

  V io_vesr(I irow, I icol, I icsr) {
    rg.h.ah = 2;
    rg.h.bh = 0;
    rg.h.dh = (C) irow;
    rg.h.dl = (C) icol;
    int86(0x10, &rg, &rg);
    if (icsr) {
      rg.h.ah = 1;
      rg.h.ch = (C) (13 - icsr);
      rg.h.cl = 12;
      int86(0x10, &rg, &rg);
    }
  }

  V io_vdsp(C * cdat, I irow, I icol, I iclr)
  I ilen = strlen(cdat);
  I iptr;
  U uclr = iclr * 256;
  if (!uvadr) {
    FP_SEG(uvadr) = io_vadr(0);
  }
  FP_OFF(uvadr) = irow * 160 + icol * 2;
  for (iptr = 0; iptr < ilen; iptr++) {
    *uvadr = uclr + (UC) cdat[iptr];
    uvadr++;
  }
}

Code: ccrp.h  Version 3.1

Code: ccrp.c  Version 3.1

Code: ccrp.h  Version 4.3

Code: ccrp.c  Version 4.3

Return to $2600 Index