#include <stdio.h> /* version from 2020-03-09 16:10 UTC+1 */
#define  NL  "\n"
#define  FF  "\f"
#define  alphabet  "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMN"
#define  D  1   //  0 for new-style

static unsigned char  table[256][4];


int main(unsigned argc, char *argv[])
{  int   c;
   short  outformat;
   unsigned   h, i, j, j0, lb, m, n, len, bits, sz;
   unsigned long   k, no, next, total, offset;
   FILE  *fp, *gp;
   if (argc <= 1)
      return  fprintf(stderr,"usage: %s datafile [-O?] [first n [total number [linelength] ] ]\n",argv[0]), 1;
   for (sz=0;alphabet[sz];sz++);
   if (!(fp = fopen (argv[1],"r")))
      return  fprintf(stderr,"can't open %s\n",argv[1]), 3;
#ifdef  LOOKUP_TABLE
   if (!(gp = fopen (LOOKUP_TABLE,"r")))
      return  fprintf(stderr,"can't open %s\n",LOOKUP_TABLE), 3;
   n= fread(table, 4, 256, gp);
   fclose(gp);
   offset=0
#else
   if (1 != fread(&n, 4, 1, fp))
      return  fprintf(stderr,"can't read %s\n",argv[1]), 5;
   if (n > 256)
   {  if (!(n&255) + !(n>>8&255) + !(n>>16&255) + !(n>>24&255) == 3)
         return  fprintf(stderr,"probably CPU byte-word-order mismatch\n"), 10;
      else
         return  fprintf(stderr,"lookup table too large\n"), 10;
   }
   if (n != fread(table, 4, n, fp))
      return  fprintf(stderr,"corrupted data in %s\n",argv[1]), 6;
   offset = 4 + 4*n;
#endif
   len=0;
   no= 1;
   total=0;
   i=2;
   outformat=0;
   if (argc > i  &&  *argv[i]=='-')
      if (*(argv[i]+1)=='O' && *(argv[i]+2)>='1' && *(argv[i]+2)<='4')
         outformat= *(argv[i++]+2)-'0';
      else
         return  fprintf(stderr,"unknown option %s\n",argv[i]), 2;
   if (argc > i  &&  1!=sscanf(argv[i++],"%lu",&no) || !no)
      return  fprintf(stderr,"illegal first n: %s\n",argv[i-1]), 4;
   if (argc > i  &&  1!=sscanf(argv[i++],"%lu",&total))
      return  fprintf(stderr,"illegal total: %s\n",argv[i-1]), 4;
   if (argc > i  &&  1!=sscanf(argv[i++],"%u",&len))
      return  fprintf(stderr,"illegal linelength: %s\n",argv[i-1]), 4;

   if (fseek(fp, offset+(no-D)/4, SEEK_SET))
      return  fprintf(stderr,"insufficient data in %s\n",argv[1]), 7;
   gp = stdout;
   j0= (no-D)&4-1;
   bits= 0;
   lb= -1;
   for (k=no-1;k;k>>=1,lb++)
      bits += k&1;
   next= no+len;
   if (outformat == 4)
      fprintf(gp,"          n lb(n) v(n) l(n) s(n) D(n)\n"
                 "-------------------------------------\n");
   while ( EOF != (c=getc(fp)) )
   {  if (c >= n) 
         return  fprintf(stderr,"index=%u is too big for lookup-table\n",c), 8;
      for (j=j0;j<4;j++)
      {  for (k=no;!(k&1);k>>=1)
            bits--;
         for (h=0,i=bits;i;h++)
            i >>= 1;
         if (!bits++)
            lb++;
         m = lb+h + table[c][no-D&4-1];
         if (outformat == 0 || outformat == 1)
         {
            if (m >= sz) 
               return  fprintf(stderr,"alphabet too small for n=%lu. At least %u characters needed\n",no,m), 9;
         }
         switch(outformat)
         {
         case 1:
            putc(alphabet[m] , gp);
            break;
         case 2:
            fprintf(gp,"%3u", m);
            break;
         case 3:
            putc('0'+m-lb-h , gp);
            break;
         case 4:
            fprintf(gp,"%11lu   %2u   %2u   %2u   %2u   %2u"NL,no,lb,bits,m,m-lb,m-lb-h);
            break;
         }
         no++;
         if (no == next)
         {  if (outformat == 4)
               fputs(FF, gp);
            else if (outformat > 0 && outformat  < 4)    
               fputs(NL, gp);
            next += len;
         }
         if (total && !--total)
            goto over;
      }
      j0=0;
   }
   if (EOF == c && total)
      fprintf(stderr,"insufficient data in %s\n",argv[1]);
   over:
   fclose(fp);
   if (outformat > 0 && outformat  < 4)
      putc(NL[0],gp);
   return  c != EOF ? 0 : 7;
}
