<commit_before>/**
 * sha3sum – SHA-3 (Keccak) checksum calculator
 * 
 * Copyright © 2013  <NAME> (<EMAIL>)
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
#include <stdio.h>
#include <stdlib.h>

#include "sha3.h"


#define false 0
#define true  1
#define null  0

#define SET void**

#define HEXADECA "0123456789ABCDEF"


/**
 * Prints a number of bytes to stdout
 * 
 * @param  bytes  The bytes to print
 * @param  n      The number of bytes
 */
inline void putchars(char* bytes, long n)
{
  fwrite(bytes, 1, n, stdout);
}


/**
 * Creates a new set
 * 
 * @return  The set
 */
SET set_new()
{
  long i;
  void** rc = = (void**)malloc(sizeof(void*) << 4);
  for (i = 0; i < 16; i++)
    *(rc + i) = 0;
  return rc;
}


/**
 * Frees a set
 * 
 * @param  set  The set
 */
void set_free(SET set)
{
  if (*(set +  0))  set_free((void**)*(set +  0));
  if (*(set +  1))  set_free((void**)*(set +  1));
  if (*(set +  2))  set_free((void**)*(set +  2));
  if (*(set +  3))  set_free((void**)*(set +  3));
  if (*(set +  4))  set_free((void**)*(set +  4));
  if (*(set +  5))  set_free((void**)*(set +  5));
  if (*(set +  6))  set_free((void**)*(set +  6));
  if (*(set +  7))  set_free((void**)*(set +  7));
  if (*(set +  8))  set_free((void**)*(set +  8));
  if (*(set +  9))  set_free((void**)*(set +  9));
  if (*(set + 10))  set_free((void**)*(set + 10));
  if (*(set + 11))  set_free((void**)*(set + 11));
  if (*(set + 12))  set_free((void**)*(set + 12));
  if (*(set + 13))  set_free((void**)*(set + 13));
  if (*(set + 14))  set_free((void**)*(set + 14));
  if (*(set + 15))  set_free((void**)*(set + 15));
  free(set);
}


/**
 * Adds an item to a set
 * 
 * @param  set   The set
 * @param  item  The item
 * @param  n     The length of the item
 */
void set_add(SET set, char* item, long n)
{
  long i, j;
  void** at = set;
  for (i = 0; i < n; i++)
    {
      long a = (long)((*(item + i)) & 15), b = (long)((*(item + i) >> 4) & 15);
      if (*(at + a))
	at = (void**)*(at + a);
      else
	{
	  at = (void**)(*(at + a) = (void*)malloc(sizeof(void*) << 4));
	  for (j = 0; j < 16; j++)
	    *(at + j) = 0;
	}
      if (*(at + b))
	at = (void**)*(at + b);
      else
	{
	  at = (void**)(*(at + b) = (void*)malloc(sizeof(void*) << 4));
	  for (j = 0; j < 16; j++)
	    *(at + j) = 0;
	}
    }
}


/**
 * Checks if a set contains an item
 * 
 * @param   set   The set
 * @param   item  The item
 * @param   n     The length of the item
 * @return        Whether the set contains the item
 */
long set_contains(SET set, char* item, long n)
{
  long i;
  void** at = set;
  for (i = 0; i < n; i++)
    {
      long a = (long)((*(item + i)) & 15), b = (long)((*(item + i) >> 4) & 15);
      if (*(at + a))
	at = (void**)*(at + a);
      else
	return false;
      if (*(at + b))
	at = (void**)*(at + b);
      else
	return false;
    }
  return true;
}


/**
 * String equality comparator
 * 
 * @param   a  First comparand
 * @param   b  Second comparand
 * @return     Whether the comparands are equal
 */
long eq(char* a, char* b)
{
  while (*a)
    if (*a++ != *b++)
      return false;
  return !*b;
}


/**
 * Convert a string to an integer
 * 
 * @param   str  String representation
 * @return       Native representation
 */
long parseInt(char* str)
{
  long rc = 0;
  while (*str)
    rc = rc * 10 - (*str++ & 15);
  return -rc;
}


/**
 * This is the main entry point of the program
 * 
 * @param   argc  Command line argument count
 * @param   argv  Command line arguments
 * @return        Exit value, zero on and only on successful execution
 */
int main(int argc, char** argv)
{
  char* cmd = *argv;
  
  long _o, o, _s, s, _r, r, _c, c, _w, w, _i, i, _j, j;
  long _O, O, _S, S, _R, R, _C, C, _W, W, _I, I, _J, J;
  long binary = false, hex = false, dashed = false, freelinger = true;
  long multi = 0, fptr = 0, bn;
  
  char** files = (char**)malloc(argc * sizeof(char*));
  char** linger = (char**)malloc(sizeof(char*) << 1);
  
  long a = 0, an = argc - 1;
  char** args = argv + 1;
  
  
  _O = _S = _R = _C = _W = _I = false;
  O = S = R = C = W = I = J = 0;
  o = s = r = c = w = i = j = 0;
  
  *linger = 0;
  
  
  s = -1;
  for (i = 0; *(cmd + i); i++)
    if (*(cmd + i) == '/')
      s = i;
  if (s >= 0)
    cmd += s + 1;
  
  _o = 512;           /* --outputsize */
  if ((cmd[0] == 's') && (cmd[1] == 'h') && (cmd[2] == 'a') && (cmd[3] == '3') && (cmd[4] == '-'))
    if ((cmd[5] != 0) && (cmd[6] != 0) && (cmd[7] != 0))
      if ((cmd[8] == 's') && (cmd[9] == 'u') && (cmd[10] == 'm') && (cmd[11] == 0))
	{
	  if ((cmd[5] == '2') && (cmd[6] == '2') && (cmd[7] == '4'))
	    _o = 224;
	  else if ((cmd[5] == '2') && (cmd[6] == '5') && (cmd[7] == '6'))
	    _o = 256;
	  else if ((cmd[5] == '3') && (cmd[6] == '8') && (cmd[7] == '4'))
	    _o = 384;
	  else if ((cmd[5] == '5') && (cmd[6] == '1') && (cmd[7] == '2'))
	    _o = 512;
	}
  _s = 1600;            /* --statesize  */
  _c = _s - (_o << 1);  /* --capacity   */
  _r = _s - _c;         /* --bitrate    */
  _w = _s / 25;         /* --wordsize   */
  _i = 1;               /* --iterations */
  _j = 1;               /* --squeezes   */
  
  
  for (; a <= an; a++)
    {
      char* arg = a == an ? null : *(args + a);
      if (*linger)
	{
	  if (eq(*linger, "-h") || eq(*linger, "--help"))
	    {
	      printf("\n");
	      printf("SHA-3/Keccak checksum calculator\n");
	      printf("\n");
	      printf("USAGE:	sha3sum [option...] < file\n");
	      printf("	sha3sum [option...] file...\n");
	      printf("\n");
	      printf("\n");
	      printf("OPTIONS:\n");
	      printf("        -r BITRATE\n");
	      printf("        --bitrate       The bitrate to use for SHA-3.           (default: %li)\n", _r);
	      printf("        \n");
	      printf("        -c CAPACITY\n");
	      printf("        --capacity      The capacity to use for SHA-3.          (default: %li)\n", _c);
	      printf("        \n");
	      printf("        -w WORDSIZE\n");
	      printf("        --wordsize      The word size to use for SHA-3.         (default: %li)\n", _w);
	      printf("        \n");
	      printf("        -o OUTPUTSIZE\n");
	      printf("        --outputsize    The output size to use for SHA-3.       (default: %li)\n", _o);
	      printf("        \n");
	      printf("        -s STATESIZE\n");
	      printf("        --statesize     The state size to use for SHA-3.        (default: %li)\n", _s);
	      printf("        \n");
	      printf("        -i ITERATIONS\n");
	      printf("        --iterations    The number of hash iterations to run.   (default: %li)\n", _i);
	      printf("        \n");
	      printf("        -j SQUEEZES\n");
	      printf("        --squeezes      The number of hash squeezes to run.     (default: %li)\n", _j);
	      printf("        \n");
	      printf("        -h\n");
	      printf("        --hex           Read the input in hexadecimal, rather than binary.\n");
	      printf("        \n");
	      printf("        -b\n");
	      printf("        --binary        Print the checksum in binary, rather than hexadecimal.\n");
	      printf("        \n");
	      printf("        -m\n");
	      printf("        --multi         Print the chechsum at all iterations.\n");
	      printf("\n");
	      printf("\n");
	      printf("COPYRIGHT:\n");
	      printf("\n");
	      printf("Copyright © 2013  <NAME> (<EMAIL>)\n");
	      printf("\n");
	      printf("This program is free software: you can redistribute it and/or modify\n");
	      printf("it under the terms of the GNU General Public License as published by\n");
	      printf("the Free Software Foundation, either version 3 of the License, or\n");
	      printf("(at your option) any later version.\n");
	      printf("\n");
	      printf("This program is distributed in the hope that it will be useful,\n");
	      printf("but WITHOUT ANY WARRANTY; without even the implied warranty of\n");
	      printf("MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n");
	      printf("GNU General Public License for more details.\n");
	      printf("\n");
	      printf("You should have received a copy of the GNU General Public License\n");
	      printf("along with this program.  If not, see <http://www.gnu.org/licenses/>.\n");
	      printf("\n");
	      fflush(stdout);
	      fflush(stderr);
	      if (freelinger)
		free(*linger);
	      free(linger);
	      free(files);
	      return 0;
	    }
	  else
	    {
	      if (*(linger + 1) == null)
		{
		  *(linger + 1) = arg;
		  arg = null;
		}
	      if (eq(*linger, "-r") || eq(*linger, "--bitrate"))
		_R = 1 | (R = parseInt(linger[1]));
	      else if (eq(*linger, "-c") || eq(*linger, "--capacity"))
		_C = 1 | (C = parseInt(linger[1]));
	      else if (eq(*linger, "-w") || eq(*linger, "--wordsize"))
		_W = 1 | (W = parseInt(linger[1]));
	      else if (eq(*linger, "-o") || eq(*linger, "--outputsize"))
		_O = 1 | (O = parseInt(linger[1]));
	      else if (eq(*linger, "-s") || eq(*linger, "--statesize"))
		_S = 1 | (S = parseInt(linger[1]));
	      else if (eq(*linger, "-i") || eq(*linger, "--iterations"))
		_I = 1 | (I = parseInt(linger[1]));
	      else if (eq(*linger, "-j") || eq(*linger, "--squeezes"))
		_J = 1 | (J = parseInt(linger[1]));
	      else
		{
		  fprintf(stderr, "%s: unrecognised option: %s\n", cmd, *linger);
		  fflush(stdout);
		  fflush(stderr);
		  if (freelinger)
		    free(*linger);
		  free(linger);
		  free(files);
		  return 1;
		}
	    }
	  if (freelinger)
	    free(*linger);
	  freelinger = false;
	  *linger = null;
	  if (arg == null)
	    continue;
	}
      if (arg == null)
	continue;
      if (dashed)
	files[fptr++] = ((arg[0] == '-') && (arg[1] == 0)) ? null : arg;
      else if ((arg[0] == '-') && (arg[1] == '-') && (arg[2] == 0))
	dashed = true;
      else if ((arg[0] == '-') && (arg[1] == 0))
	files[fptr++] = null;
      else if ((arg[0] == '-') && (arg[1] == '-') && arg[2])
	{
	  long idx = -1, j;
	  for (j = 0; *(arg + j); j++)
	    if (*(arg + j) == '=')
	      {
		idx = j;
		break;
	      }
	  if (idx >= 0)
	    {
	      linger[0] = (char*)malloc(idx);
	      linger[1] = arg + idx + 1;
	      for (j = 0; j < idx; j++)
		*(*linger + j) = *(arg + j);
	    }
	  else
	    if (eq(arg, "--binary"))
	      binary = true;
	    else if (eq(arg, "--multi"))
	      multi++;
	    else if (eq(arg, "--hex"))
	      hex = true;
	    else
	      {
		linger[0] = arg;
		linger[1] = null;
		freelinger = false;
	      }
	}
      else if ((arg[0] == '-') && arg[1])
	{
	  arg++;
	  if (*arg == 'b')
	    {
	      binary = true;
	      arg++;
	    }
	  else if (*arg == 'm')
	    {
	      multi++;
	      arg++;
	    }
	  else if (*arg == 'h')
	    {
	      hex = true;
	      arg++;
	    }
	  else
	    {
	      {
		char* _ = (char*)malloc(3);
		*_++ = '-'; *_++ = *arg; *_ = 0;
		linger[0] = _ - 2;
	      }
	      {
		long _ = 0;
		while (*(arg + _))
		  _++;
		linger[1] = _ == 1 ? null : arg + 1;
	      }
	    }
	}
      else
	files[fptr++] = arg;
    }
  
  free(linger);
  
  
  i = _I ? I : _i;
  j = _J ? J : _j;
  
  #define ERR(text)  fprintf(stderr, "%s: " text "\n", cmd);  fflush(stdout);  fflush(stderr)
  
  if (_S)
    {
      s = S;
      if ((s <= 0) || (s > 1600) || (s % 25))
	{
	  ERR("the state size must be a positive multiple of 25 and is limited to 1600.");
	  return 6;
	}
    }
  
  if (_W)
    {
      w = W;
      if ((w <= 0) || (w > 64))
	{
	  ERR("the word size must be positive and is limited to 64.");
	  return 6;
	}
      if (_S && (s != w * 25))
	{
	  ERR("the state size must be 25 times of the word size.");
	  return 6;
	}
      else if (_S == null)
	_S = 1 | (S = w * 25);
    }
  
  if (_C)
    {
      c = C;
      if ((c <= 0) || (c & 7))
	{
	  ERR("the capacity must be a positive multiple of 8.");
	  return 6;
	}
    }
  
  if (_R)
    {
      r = R;
      if ((r <= 0) || (r & 7))
	{
	  ERR("the bitrate must be a positive multiple of 8.");
	  return 6;
	}
    }
  
  if (_O)
    {
      o = o;
      if (o <= 0)
	{
	  ERR("the output size must be positive.");
	  return 6;
	}
    }
  
  if ((_R & _C & _O) == null) /* s? */
    {
      s = _S ? s : _s;
      c = -((r = (o = (((s << 5) / 100 + 7) >> 3) << 3) << 1) - s);
      o = o < 8 ? 8 : o;
    }
  else if ((_R & _C) == null) /* !o s? */
    {
      r = _r;
      c = _c;
      s = _S ? s : (r + c);
    }
  else if (_R == null) /* !c o? s? */
    {
      r = (s = _S ? s : _s) - c;
      o = _O ? o : (c == 8 ? 8 : (c << 1));
    }
  else if (_C == null) /* !r o? s? */
    {
      c = (s = _S ? s : _s) - r;
      o = _O ? o : (c == 8 ? 8 : (c << 1));
    }
  else /* !r !c o? s? */
    {
      s = _S ? s : (r + c);
      o = _O ? o : (c == 8 ? 8 : (c << 1));
    }
  
  
  fprintf(stderr, "Bitrate: %li\n", r);
  fprintf(stderr, "Capacity: %li\n", c);
  fprintf(stderr, "Word size: %li\n", w);
  fprintf(stderr, "State size: %li\n", s);
  fprintf(stderr, "Output Size: %li\n", o);
  fprintf(stderr, "Iterations: %li\n", i);
  fprintf(stderr, "Squeezes: %li\n", j);
  
  
  if (r > s)
    {
      ERR("the bitrate must not be higher than the state size.");
      return 6;
    }
  if (c > s)
    {
      ERR("the capacity must not be higher than the state size.");
      return 6;
    }
  if (r + c != s)
    {
      ERR("the sum of the bitrate and the capacity must equal the state size.");
      return 6;
    }
  
  
  if (fptr == 0)
    files[fptr++] = null;
  if (i < 1)
    {
      ERR("sorry, I will only do at least one hash iteration!");
      free(files);
      return 3;
    }
  if (j < 1)
    {
      ERR("sorry, I will only do at least one squeeze iteration!");
      free(files);
      return 3;
    }
  
  #undef ERR
  
  bn = (o + 7) >> 3;
  {
    char* stdin;
    char* filename;
    char* fn;
    long f, fail, _;
    
    char* out = binary ? null : (char*)malloc(bn * 2);
    
    fail = false;
    stdin = null;
    
    for (f = 0; f < fptr; f++)
      {
	FILE* file;
	long blksize;
	char* chunk;
	char* bs;
	
	filename = *(files + f)
	fn = filename ? filename : "/dev/stdin";
	file = fopen(fn, "r");
	if (file == null)
	  {
	    fprintf(stderr, "%s: cannot read file: %s\n", cmd, filename);
	    fail = true;
	    continue;
	  }
	
	if ((filename != null) || (stdin == null))
	  {
	    initialise(r, c, o);
	    blksize = 4096; /** XXX os.stat(os.path.realpath(fn)).st_size; **/
	    chunk = (char*)malloc(blksize);
	    for (;;)
	      {
		long read = fread(chunk, 1, blksize, file);
		if (read <= 0)
		  break;
		if (hex == false)
		  update(chunk, read);
		else
		  {
		    int n = read >> 1;
		    for (_ = 0; _ < n; _++)
		      {
			char a = *(chunk + (_ << 1)), b = *(chunk + ((_ << 1) | 1));
			a = (a & 15) + (a <= '9' ? 0 : 9);
			b = (b & 15) + (b <= '9' ? 0 : 9);
			*(chunk + _) = (a << 4) | b;<commit_msg>m<commit_after>/**
 * sha3sum – SHA-3 (Keccak) checksum calculator
 * 
 * Copyright © 2013  <NAME> (<EMAIL>)
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
#include <stdio.h>
#include <stdlib.h>

#include "sha3.h"


#define false 0
#define true  1
#define null  0

#define SET void**

#define HEXADECA "0123456789ABCDEF"


/**
 * Prints a number of bytes to stdout
 * 
 * @param  bytes  The bytes to print
 * @param  n      The number of bytes
 */
inline void putchars(char* bytes, long n)
{
  fwrite(bytes, 1, n, stdout);
}


/**
 * Creates a new set
 * 
 * @return  The set
 */
SET set_new()
{
  long i;
  void** rc = (void**)malloc(sizeof(void*) << 4);
  for (i = 0; i < 16; i++)
    *(rc + i) = 0;
  return rc;
}


/**
 * Frees a set
 * 
 * @param  set  The set
 */
void set_free(SET set)
{
  if (*(set +  0))  set_free((void**)*(set +  0));
  if (*(set +  1))  set_free((void**)*(set +  1));
  if (*(set +  2))  set_free((void**)*(set +  2));
  if (*(set +  3))  set_free((void**)*(set +  3));
  if (*(set +  4))  set_free((void**)*(set +  4));
  if (*(set +  5))  set_free((void**)*(set +  5));
  if (*(set +  6))  set_free((void**)*(set +  6));
  if (*(set +  7))  set_free((void**)*(set +  7));
  if (*(set +  8))  set_free((void**)*(set +  8));
  if (*(set +  9))  set_free((void**)*(set +  9));
  if (*(set + 10))  set_free((void**)*(set + 10));
  if (*(set + 11))  set_free((void**)*(set + 11));
  if (*(set + 12))  set_free((void**)*(set + 12));
  if (*(set + 13))  set_free((void**)*(set + 13));
  if (*(set + 14))  set_free((void**)*(set + 14));
  if (*(set + 15))  set_free((void**)*(set + 15));
  free(set);
}


/**
 * Adds an item to a set
 * 
 * @param  set   The set
 * @param  item  The item
 * @param  n     The length of the item
 */
void set_add(SET set, char* item, long n)
{
  long i, j;
  void** at = set;
  for (i = 0; i < n; i++)
    {
      long a = (long)((*(item + i)) & 15), b = (long)((*(item + i) >> 4) & 15);
      if (*(at + a))
	at = (void**)*(at + a);
      else
	{
	  at = (void**)(*(at + a) = (void*)malloc(sizeof(void*) << 4));
	  for (j = 0; j < 16; j++)
	    *(at + j) = 0;
	}
      if (*(at + b))
	at = (void**)*(at + b);
      else
	{
	  at = (void**)(*(at + b) = (void*)malloc(sizeof(void*) << 4));
	  for (j = 0; j < 16; j++)
	    *(at + j) = 0;
	}
    }
}


/**
 * Checks if a set contains an item
 * 
 * @param   set   The set
 * @param   item  The item
 * @param   n     The length of the item
 * @return        Whether the set contains the item
 */
long set_contains(SET set, char* item, long n)
{
  long i;
  void** at = set;
  for (i = 0; i < n; i++)
    {
      long a = (long)((*(item + i)) & 15), b = (long)((*(item + i) >> 4) & 15);
      if (*(at + a))
	at = (void**)*(at + a);
      else
	return false;
      if (*(at + b))
	at = (void**)*(at + b);
      else
	return false;
    }
  return true;
}


/**
 * String equality comparator
 * 
 * @param   a  First comparand
 * @param   b  Second comparand
 * @return     Whether the comparands are equal
 */
long eq(char* a, char* b)
{
  while (*a)
    if (*a++ != *b++)
      return false;
  return !*b;
}


/**
 * Convert a string to an integer
 * 
 * @param   str  String representation
 * @return       Native representation
 */
long parseInt(char* str)
{
  long rc = 0;
  while (*str)
    rc = rc * 10 - (*str++ & 15);
  return -rc;
}


/**
 * This is the main entry point of the program
 * 
 * @param   argc  Command line argument count
 * @param   argv  Command line arguments
 * @return        Exit value, zero on and only on successful execution
 */
int main(int argc, char** argv)
{
  char* cmd = *argv;
  
  long _o, o, _s, s, _r, r, _c, c, _w, w, _i, i, _j, j;
  long _O, O, _S, S, _R, R, _C, C, _W, W, _I, I, _J, J;
  long binary = false, hex = false, dashed = false, freelinger = true;
  long multi = 0, fptr = 0, bn;
  
  char** files = (char**)malloc(argc * sizeof(char*));
  char** linger = (char**)malloc(sizeof(char*) << 1);
  
  long a = 0, an = argc - 1;
  char** args = argv + 1;
  
  
  _O = _S = _R = _C = _W = _I = _J = false;
  O = S = R = C = W = I = J = 0;
  o = s = r = c = w = i = j = 0;
  
  *linger = 0;
  
  
  s = -1;
  for (i = 0; *(cmd + i); i++)
    if (*(cmd + i) == '/')
      s = i;
  if (s >= 0)
    cmd += s + 1;
  
  _o = 512;           /* --outputsize */
  if ((cmd[0] == 's') && (cmd[1] == 'h') && (cmd[2] == 'a') && (cmd[3] == '3') && (cmd[4] == '-'))
    if ((cmd[5] != 0) && (cmd[6] != 0) && (cmd[7] != 0))
      if ((cmd[8] == 's') && (cmd[9] == 'u') && (cmd[10] == 'm') && (cmd[11] == 0))
	{
	  if ((cmd[5] == '2') && (cmd[6] == '2') && (cmd[7] == '4'))
	    _o = 224;
	  else if ((cmd[5] == '2') && (cmd[6] == '5') && (cmd[7] == '6'))
	    _o = 256;
	  else if ((cmd[5] == '3') && (cmd[6] == '8') && (cmd[7] == '4'))
	    _o = 384;
	  else if ((cmd[5] == '5') && (cmd[6] == '1') && (cmd[7] == '2'))
	    _o = 512;
	}
  _s = 1600;            /* --statesize  */
  _c = _s - (_o << 1);  /* --capacity   */
  _r = _s - _c;         /* --bitrate    */
  _w = _s / 25;         /* --wordsize   */
  _i = 1;               /* --iterations */
  _j = 1;               /* --squeezes   */
  
  
  for (; a <= an; a++)
    {
      char* arg = a == an ? null : *(args + a);
      if (*linger)
	{
	  if (eq(*linger, "-h") || eq(*linger, "--help"))
	    {
	      printf("\n");
	      printf("SHA-3/Keccak checksum calculator\n");
	      printf("\n");
	      printf("USAGE:	sha3sum [option...] < file\n");
	      printf("	sha3sum [option...] file...\n");
	      printf("\n");
	      printf("\n");
	      printf("OPTIONS:\n");
	      printf("        -r BITRATE\n");
	      printf("        --bitrate       The bitrate to use for SHA-3.           (default: %li)\n", _r);
	      printf("        \n");
	      printf("        -c CAPACITY\n");
	      printf("        --capacity      The capacity to use for SHA-3.          (default: %li)\n", _c);
	      printf("        \n");
	      printf("        -w WORDSIZE\n");
	      printf("        --wordsize      The word size to use for SHA-3.         (default: %li)\n", _w);
	      printf("        \n");
	      printf("        -o OUTPUTSIZE\n");
	      printf("        --outputsize    The output size to use for SHA-3.       (default: %li)\n", _o);
	      printf("        \n");
	      printf("        -s STATESIZE\n");
	      printf("        --statesize     The state size to use for SHA-3.        (default: %li)\n", _s);
	      printf("        \n");
	      printf("        -i ITERATIONS\n");
	      printf("        --iterations    The number of hash iterations to run.   (default: %li)\n", _i);
	      printf("        \n");
	      printf("        -j SQUEEZES\n");
	      printf("        --squeezes      The number of hash squeezes to run.     (default: %li)\n", _j);
	      printf("        \n");
	      printf("        -h\n");
	      printf("        --hex           Read the input in hexadecimal, rather than binary.\n");
	      printf("        \n");
	      printf("        -b\n");
	      printf("        --binary        Print the checksum in binary, rather than hexadecimal.\n");
	      printf("        \n");
	      printf("        -m\n");
	      printf("        --multi         Print the chechsum at all iterations.\n");
	      printf("\n");
	      printf("\n");
	      printf("COPYRIGHT:\n");
	      printf("\n");
	      printf("Copyright © 2013  <NAME> (<EMAIL>)\n");
	      printf("\n");
	      printf("This program is free software: you can redistribute it and/or modify\n");
	      printf("it under the terms of the GNU General Public License as published by\n");
	      printf("the Free Software Foundation, either version 3 of the License, or\n");
	      printf("(at your option) any later version.\n");
	      printf("\n");
	      printf("This program is distributed in the hope that it will be useful,\n");
	      printf("but WITHOUT ANY WARRANTY; without even the implied warranty of\n");
	      printf("MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n");
	      printf("GNU General Public License for more details.\n");
	      printf("\n");
	      printf("You should have received a copy of the GNU General Public License\n");
	      printf("along with this program.  If not, see <http://www.gnu.org/licenses/>.\n");
	      printf("\n");
	      fflush(stdout);
	      fflush(stderr);
	      if (freelinger)
		free(*linger);
	      free(linger);
	      free(files);
	      return 0;
	    }
	  else
	    {
	      if (*(linger + 1) == null)
		{
		  *(linger + 1) = arg;
		  arg = null;
		}
	      if (eq(*linger, "-r") || eq(*linger, "--bitrate"))
		_R = 1 | (R = parseInt(linger[1]));
	      else if (eq(*linger, "-c") || eq(*linger, "--capacity"))
		_C = 1 | (C = parseInt(linger[1]));
	      else if (eq(*linger, "-w") || eq(*linger, "--wordsize"))
		_W = 1 | (W = parseInt(linger[1]));
	      else if (eq(*linger, "-o") || eq(*linger, "--outputsize"))
		_O = 1 | (O = parseInt(linger[1]));
	      else if (eq(*linger, "-s") || eq(*linger, "--statesize"))
		_S = 1 | (S = parseInt(linger[1]));
	      else if (eq(*linger, "-i") || eq(*linger, "--iterations"))
		_I = 1 | (I = parseInt(linger[1]));
	      else if (eq(*linger, "-j") || eq(*linger, "--squeezes"))
		_J = 1 | (J = parseInt(linger[1]));
	      else
		{
		  fprintf(stderr, "%s: unrecognised option: %s\n", cmd, *linger);
		  fflush(stdout);
		  fflush(stderr);
		  if (freelinger)
		    free(*linger);
		  free(linger);
		  free(files);
		  return 1;
		}
	    }
	  if (freelinger)
	    free(*linger);
	  freelinger = false;
	  *linger = null;
	  if (arg == null)
	    continue;
	}
      if (arg == null)
	continue;
      if (dashed)
	files[fptr++] = ((arg[0] == '-') && (arg[1] == 0)) ? null : arg;
      else if ((arg[0] == '-') && (arg[1] == '-') && (arg[2] == 0))
	dashed = true;
      else if ((arg[0] == '-') && (arg[1] == 0))
	files[fptr++] = null;
      else if ((arg[0] == '-') && (arg[1] == '-') && arg[2])
	{
	  long idx = -1, j;
	  for (j = 0; *(arg + j); j++)
	    if (*(arg + j) == '=')
	      {
		idx = j;
		break;
	      }
	  if (idx >= 0)
	    {
	      linger[0] = (char*)malloc(idx);
	      linger[1] = arg + idx + 1;
	      for (j = 0; j < idx; j++)
		*(*linger + j) = *(arg + j);
	    }
	  else
	    if (eq(arg, "--binary"))
	      binary = true;
	    else if (eq(arg, "--multi"))
	      multi++;
	    else if (eq(arg, "--hex"))
	      hex = true;
	    else
	      {
		linger[0] = arg;
		linger[1] = null;
		freelinger = false;
	      }
	}
      else if ((arg[0] == '-') && arg[1])
	{
	  arg++;
	  if (*arg == 'b')
	    {
	      binary = true;
	      arg++;
	    }
	  else if (*arg == 'm')
	    {
	      multi++;
	      arg++;
	    }
	  else if (*arg == 'h')
	    {
	      hex = true;
	      arg++;
	    }
	  else
	    {
	      {
		char* _ = (char*)malloc(3);
		*_++ = '-'; *_++ = *arg; *_ = 0;
		linger[0] = _ - 2;
	      }
	      {
		long _ = 0;
		while (*(arg + _))
		  _++;
		linger[1] = _ == 1 ? null : arg + 1;
	      }
	    }
	}
      else
	files[fptr++] = arg;
    }
  
  free(linger);
  
  
  i = _I ? I : _i;
  j = _J ? J : _j;
  
  #define ERR(text)  fprintf(stderr, "%s: " text "\n", cmd);  fflush(stdout);  fflush(stderr)
  
  if (_S)
    {
      s = S;
      if ((s <= 0) || (s > 1600) || (s % 25))
	{
	  ERR("the state size must be a positive multiple of 25 and is limited to 1600.");
	  return 6;
	}
    }
  
  if (_W)
    {
      w = W;
      if ((w <= 0) || (w > 64))
	{
	  ERR("the word size must be positive and is limited to 64.");
	  return 6;
	}
      if (_S && (s != w * 25))
	{
	  ERR("the state size must be 25 times of the word size.");
	  return 6;
	}
      else if (_S == null)
	_S = 1 | (S = w * 25);
    }
  
  if (_C)
    {
      c = C;
      if ((c <= 0) || (c & 7))
	{
	  ERR("the capacity must be a positive multiple of 8.");
	  return 6;
	}
    }
  
  if (_R)
    {
      r = R;
      if ((r <= 0) || (r & 7))
	{
	  ERR("the bitrate must be a positive multiple of 8.");
	  return 6;
	}
    }
  
  if (_O)
    {
      o = o;
      if (o <= 0)
	{
	  ERR("the output size must be positive.");
	  return 6;
	}
    }
  
  if ((_R & _C & _O) == null) /* s? */
    {
      s = _S ? s : _s;
      c = -((r = (o = (((s << 5) / 100 + 7) >> 3) << 3) << 1) - s);
      o = o < 8 ? 8 : o;
    }
  else if ((_R & _C) == null) /* !o s? */
    {
      r = _r;
      c = _c;
      s = _S ? s : (r + c);
    }
  else if (_R == null) /* !c o? s? */
    {
      r = (s = _S ? s : _s) - c;
      o = _O ? o : (c == 8 ? 8 : (c << 1));
    }
  else if (_C == null) /* !r o? s? */
    {
      c = (s = _S ? s : _s) - r;
      o = _O ? o : (c == 8 ? 8 : (c << 1));
    }
  else /* !r !c o? s? */
    {
      s = _S ? s : (r + c);
      o = _O ? o : (c == 8 ? 8 : (c << 1));
    }
  
  
  fprintf(stderr, "Bitrate: %li\n", r);
  fprintf(stderr, "Capacity: %li\n", c);
  fprintf(stderr, "Word size: %li\n", w);
  fprintf(stderr, "State size: %li\n", s);
  fprintf(stderr, "Output Size: %li\n", o);
  fprintf(stderr, "Iterations: %li\n", i);
  fprintf(stderr, "Squeezes: %li\n", j);
  
  
  if (r > s)
    {
      ERR("the bitrate must not be higher than the state size.");
      return 6;
    }
  if (c > s)
    {
      ERR("the capacity must not be higher than the state size.");
      return 6;
    }
  if (r + c != s)
    {
      ERR("the sum of the bitrate and the capacity must equal the state size.");
      return 6;
    }
  
  
  if (fptr == 0)
    files[fptr++] = null;
  if (i < 1)
    {
      ERR("sorry, I will only do at least one hash iteration!");
      free(files);
      return 3;
    }
  if (j < 1)
    {
      ERR("sorry, I will only do at least one squeeze iteration!");
      free(files);
      return 3;
    }
  
  #undef ERR
  
  bn = (o + 7) >> 3;
  {
    char* stdin;
    char* filename;
    char* fn;
    long f, fail, _;
    
    char* out = binary ? null : (char*)malloc(bn * 2);
    
    fail = false;
    stdin = null;
    
    for (f = 0; f < fptr; f++)
      {
	FILE* file;
	long blksize;
	char* chunk;
	char* bs;
	
	filename = *(files + f);
	fn = filename ? filename : "/dev/stdin";
	file = fopen(fn, "r");
	if (file == null)
	  {
	    fprintf(stderr, "%s: cannot read file: %s\n", cmd, filename);
	    fail = true;
	    continue;
	  }
	
	if ((filename != null) || (stdin == null))
	  {
	    initialise(r, c, o);
	    blksize = 4096; /** XXX os.stat(os.path.realpath(fn)).st_size; **/
	    chunk = (char*)malloc(blksize);
	    for (;;)
	      {
		long read = fread(chunk, 1, blksize, file);
		if (read <= 0)
		  break;
		if (hex == false)
		  update(chunk, read);
		else
		  {
		    int n = read >> 1;
		    for (_ = 0; _ < n; _++)
		      {
			char a = *(chunk + (_ << 1)), b = *(chunk + ((_ << 1) | 1));
			a = (a & 15) + (a <= '9' ? 0 : 9);
			b = (b & 15) + (b <= '9' ? 0 : 9);
			*(chunk + _) = (a << 4) | b;
{'fraction_non_alphanumeric': 0.20645518499218343, 'fraction_numerical': 0.021625846795205836, 'mean_word_length': 1.887979683972912, 'pattern_counts': {'":': 0, '<': 117, '<?xml version=': 0, '>': 51, 'https://': 0, 'lorem ipsum': 0, 'www.': 4, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 6, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2516869', 'n_tokens_mistral': 12645, 'n_tokens_neox': 11531, 'n_words': 3578}