//||
//||	`rhybag' - Rhythmic BinAural Generator
//||
//||	(c) 1999 Jim Peters <jim@aguazul.demon.co.uk>.  All Rights Reserved.
//||	For latest version see <http://www.aguazul.demon.co.uk/bagen/>.
//||	Released under the GNU GPL.  Use at your own risk.
//||
//||	" 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, version 2.
//||
//||	  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. "
//||
//||	If you really don't have a copy of the GNU GPL, I'll send you one.
//||	

//
//	 Memory-allocation functions
//	=============================
//
//	Other functions are provided that act as wrappers for the C
//	functions, guaranteeing that memory will always be returned to
//	the caller.
//
//	Free() is a macro that calls ::free(), to fit the capitalised
//	naming scheme, and allow member functions called `free'.
//
//	  Obj *oo;
//	  char *cp;
//
//	  oo= (Obj*)CAlloc(siz);
//	  oo= (Obj*)Alloc(siz);
//	  cp= DataDup(data, data_len);
//	  cp= StrDup(str);
//	  cp= StrPrintF(fmt, ...);
//	  cp= StrVPrintF(fmt, ap);
//
//	  Free(cp);
//	

// General purpose scratch buffer, usable in all functions so long as
// they call no other library functions whilst the buffer is in use.
char scratch[32768];

void *
CAlloc(size_t len) {
  void *vp= calloc(1, len);
  if (!vp) error("Out of memory");
  return vp;
}

void *
Alloc(size_t len) {
  void *vp= malloc(len);
  if (!vp) error("Out of memory");
  return vp;
}

char *
DataDup(char *dat, int datlen) {
  char *cp= (char*)Alloc(datlen);
  memcpy(cp, dat, datlen);
  return cp;
}

char *
StrDup(char *nam) {
  char *cp= strdup(nam);
  if (!cp) error("Out of memory");
  return cp;
}

char *
StrPrintF(char *fmt, ...) {
  va_list ap;
  int len;
  char *rv;

  va_start(ap, fmt);
  vsprintf(scratch, fmt, ap);
  len= 1+strlen(scratch);
  if (len >= sizeof(scratch)) error("StrPrintF buffer overflow");

  rv= (char*)Alloc(len);
  memcpy(rv, scratch, len);
  return rv;
}

char *
StrVPrintF(char *fmt, va_list ap) {
  int len;
  char *rv;

  vsprintf(scratch, fmt, ap);
  len= 1+strlen(scratch);
  if (len >= sizeof(scratch)) error("StrVPrintF buffer overflow");

  rv= (char*)Alloc(len);
  memcpy(rv, scratch, len);
  return rv;
}

#define Free(xx) free(xx)

void
error(char *fmt, ...) { 
  va_list ap; va_start(ap, fmt); 
  if (program_name) fprintf(stderr, "%s: ", program_name);
  vfprintf(stderr, fmt, ap); fprintf(stderr, "\n");
  exit(1);
}

void
errorE(char *fmt, ...) { 
  int err= errno;
  va_list ap; va_start(ap, fmt);
  if (program_name) fprintf(stderr, "%s: ", program_name);
  vfprintf(stderr, fmt, ap); fprintf(stderr, ": %s\n", strerror(err));
  exit(1);
}

void
warn(char *fmt, ...) {
  va_list ap; va_start(ap, fmt); 
  vfprintf(stderr, fmt, ap); fprintf(stderr, "\n");
}

void
debug(char *fmt, ...) {
  va_list ap; va_start(ap, fmt); fprintf(stderr, "DEBUG: ");
  vfprintf(stderr, fmt, ap); fprintf(stderr, "\n");
}

//	cc= packCC(str)
//
//	  Pack character-constant.  Pack a string of 0-4 characters
//	  into the same format as a character constant.  5 or more
//	  characters returns -1.
//
//	  The code for this routine optimizes down into almost
//	  nothing.
//

int
packCC(char *cp) {
  switch (strlen(cp)) {
   case 0: return 0;
   case 1: return ('1'-'0') * cp[0];
   case 2: return (('01'-'00') * cp[1] +
		   ('10'-'00') * cp[0]);
   case 3: return (('001'-'000') * cp[2] +
		   ('010'-'000') * cp[1] +
		   ('100'-'000') * cp[0]);
   case 4: return (('0001'-'0000') * cp[3] +
		   ('0010'-'0000') * cp[2] +
		   ('0100'-'0000') * cp[1] +
		   ('1000'-'0000') * cp[0]);
  }
  return -1;
}

// END //
