#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <assert.h>
#include "jtools.h"

/* grain d'alloc. dynamique private def. */
#define NELM 16

char *err_malloc = "erreur d'allocation mémoire";

char *err_calloc = "erreur d'allocation mémoire (caloc)";

char *err_realloc = "erreur d'extension mémoire";

char *exit_message=NULL;

void exit_if(char *fichier, int ligne, int condition,
             char *code, char *message)
{
  if (condition == 0)
    return;
  if (message == NULL)
    fprintf(stderr,
            "%s:%d:condition d'arrêt: |%s|\n",
            fichier, ligne, code);
  else
    fprintf(stderr, "%s:%d: %s\n", fichier, ligne, message);

  exit_message = message;
  exit(EXIT_FAILURE);
}

void perror_and_exit(char *localisation)
{
  perror(localisation);
  exit(EXIT_FAILURE);
}

struct pil
{
  vec contenu;
  int sommet;
};

pil pil_new(size_t s)
{
  INSTANCIER(pil);

  recv->contenu = vec_new(s);
  recv->sommet = 0;
  return recv;
}

void
pil_free(pil recv)
{
  vec_free(recv->contenu);
  free(recv);
}

void
pil_emp(pil recv, void *valeur)
{
  vec_aff(recv->contenu, recv->sommet, valeur);
  (recv->sommet)++;
}

void
pil_dep(pil recv, void* v)
{
  assert(pil_pro(recv)>0);
  --(recv->sommet);
  vec_elm(recv->contenu, recv->sommet, v);
}

void
pil_top(pil recv, void* v)
{
  assert(pil_pro(recv)>0);
  vec_elm(recv->contenu, recv->sommet - 1, v);
}

int
pil_pro(pil recv)
{
  return (recv->sommet);
}

void
pil_vrb(pil recv, int mode)
{
  vec_vrb(recv->contenu, mode);
}

struct vec
{
  void* add;     /* add. de l'élément 0    */
  long max;      /* long. courante allouée */
  long nbr;      /* [deb:0,der-]           */
  int verb;      /* verbose                */
  size_t noct;   /* sizeof(element)        */
};

vec
vec_new(size_t noct)
{
  INSTANCIER(vec);

  recv->add = calloc(NELM, noct);
  EXIT_IF(recv->add==NULL, "err_malloc");
  memset(recv->add,0,NELM*noct);
  recv->max = NELM;
  recv->nbr = 0;
  recv->verb = 0;
  recv->noct = noct;
  return recv;
}

void
vec_free(vec recv)
{
  free(recv->add);
  free(recv);
}

void
vec_mt(vec recv)
{
  assert(recv->add!=NULL);
  memset(recv->add,0,recv->max*recv->noct);
  recv->nbr=0;
}

void
vec_aff(vec recv, int indice, void* valeur)
{
  assert(recv->add!=NULL);
  if (indice >= recv->max)
  {
    unsigned long n = indice + (NELM - (indice % NELM));
    
    recv->add = realloc(recv->add, n * recv->noct);
    EXIT_IF(recv->add==NULL, "err_realloc");
    memset(recv->add+(recv->max*recv->noct),0,recv->noct*(n-recv->max));
    if (recv->verb)
    {
      fprintf(stderr, ">*< vec: extension de %ld à %ld >*<\n",
              recv->max, n);
    }
    recv->max = n;
  }
  memcpy(recv->add+recv->noct*indice, valeur, recv->noct);
  if (recv->nbr < indice+1) recv->nbr = indice+1;
}

void
vec_elm(vec recv, int indice, void* v)
{
  assert(recv->add!=NULL);
  assert(indice>=0);
  assert(indice<recv->nbr);
  memcpy(v, recv->add+indice*recv->noct, recv->noct);
}

int
vec_nbr(vec recv)
{
  assert(recv->add!=NULL);
  return recv->nbr;
}

void
vec_vrb(vec recv, int mode)
{
  assert(recv->add!=NULL);
  recv->verb = mode;
}

struct set{
  char* add;
  card  car; // nbre d'octets alloués  1 elem-> 1 bit
};

set
set_new(card c){
  INSTANCIER(set);
//
  recv->car = (c/8)+1;
  recv->add = calloc(recv->car,1);
  memset(recv->add,0,recv->car);
  return recv;
}

void
set_free(set recv){
  free(recv->add);
  free(recv);
}

void
set_mt(set s){
//
  memset(s->add,0,s->car);
}

void
set_add(set recv, card e){
  div_t qr;
//
  assert(recv->add!=NULL);
  assert((e/8)<recv->car);
  qr=div(e,8);
//  recv->add[qr.quot] = recv->add[qr.quot] | (1 << qr.rem);
  recv->add[qr.quot] |= 1 << qr.rem;
}

void
set_union(set s1, set s2, set r){
  card i;
//
  assert(s1->add!=NULL);
  assert(s2->add!=NULL);
  assert(r->add!=NULL);
  assert(s1->car==s2->car);
  assert(s1->car==r->car);
  for (i=0;i<r->car;i++)
    r->add[i]=s1->add[i] | s2->add[i];
}

void
set_inter(set s1, set s2, set r){
  card i;
//
  assert(s1->add!=NULL);
  assert(s2->add!=NULL);
  assert(r->add!=NULL);
  assert(s1->car==s2->car);
  assert(s1->car==r->car);
  for (i=0;i<r->car;i++)
    r->add[i]=s1->add[i] & s2->add[i];
}

bool
set_egal(set s1, set s2){
  bool r;
  card i;
//
  assert(s1->car==s2->car);
  assert(s1->add!=NULL);
  assert(s2->add!=NULL);
  r=1;
  for (i=0;i<s1->car;++i){
    r &= s1->add[i]==s2->add[i];
    if (!r) break;
  }
  return r;
}

bool
set_incl(set s1, set s2){
  bool r;
  set s;
//
  assert(s1->car==s2->car);
  assert(s1->add!=NULL);
  assert(s2->add!=NULL);
//  printf("in set_incl ---<\n");
//  set_print("s1",s1);
//  set_print("s2",s2);
  s = set_new((s1->car*8)-1);
  set_inter(s1,s2,s);
//  set_print("s1 inter s2 ",s);
  r = set_egal(s2,s);
  set_free(s);
//  printf("r : %d\n",r);
//  printf(">--- set_incl\n");
  return r;
}

bool
set_app(set s1, card e){
  div_t qr;
//
  assert(s1->add!=NULL);
  assert(e<s1->car*8);
  qr = div(e,8);
  return s1->add[qr.quot] & (1 << qr.rem);
}

void
set_dump(set recv){
  card i;
//
  assert(recv->add!=NULL);
  for (i=0;i<recv->car;i++) printf("%x ",recv->add[i]);
  printf("\n");
}

void
set_print(char *m, set recv){
  vec v;
  card i;
  card e;
//
  v=vec_new(sizeof(card));
  set_2vec(recv,v);
  printf("%s : [", m);
  for (i=0;i<vec_nbr(v);i++){
    vec_elm(v,i,&e);
    printf("%d ",e);
  }
  printf("]\n");
  vec_free(v);
}

void
set_2vec(set s, vec v){
  char j, oct, mask;
  int i, k;
  card l;
//
  k = 0;
  l = 0;
  for (i=0;i<s->car;++i){
    mask = 1;
    oct = s->add[i];
    for (j=0;j<8;++j){
      if (oct&mask){
        vec_aff(v,k,&l);
        ++k;
      }
      mask = mask << 1;
      ++l;
    }
  }
}

char
*getarg(int argc, char **argv, char *nom)
{
  static char mty[1]="";
  char *p;
  char *q;
  int i;
//
  for (i=1;i<argc;i++)
  {
    p=argv[i];
    q=nom;
    while(*p==*q){p++;q++;};
    if ((*p=='=')&&(*q=='\000')) return ++p;
  }
  p=getenv(nom);
  if (p==NULL) return mty;
  return p;
}

char
*argstr(int argc, char **argv, char *nom, char *def)
{
  char *p;

  p=getarg(argc, argv, nom);
  assert(p != NULL);
  if ( p[0] == 0 ) {
    return def;
  } else {
    return p;
  }
}

int
argint(int argc, char **argv, char *nom, int def)
{
  char *p;
  int i;
  int j;
//
  p=getarg(argc, argv, nom);
  assert(p != NULL);
  i=sscanf(p,"%d",&j);
  if (i<=0) return def; else return j;
}

float
argflt(int argc, char **argv, char *nom, float def)
{
  char *p;
  int i;
  float v;
//
  p = getarg (argc, argv, nom);
  assert ( p != NULL );
  i = sscanf (p,"%f",&v);
  if (i<=0) return def; else return v;
}
void
avant(char *dst, char *src, char sep)
{
  char *p=index(src,sep);
//
  assert(sep != '\0');
  if (p==NULL) strncpy(dst,src,STRSIZE);
  else
  {
    memmove(dst,src,p-src);
    dst[p-src]='\0';
  }
}

void
apres(char *dst, char *src, char sep)
{
  char *p=index(src,sep);
//
  assert(sep != '\0');
  if (p==NULL) dst[0]='\0';
  else strncpy(dst,p+1,STRSIZE);
}

void
before(char *dst, char *src, char *sep)
{
  char *p=strstr(src,sep);
//
  if (p==NULL) strncpy(dst,src,STRSIZE);
  else
  {
    memmove(dst,src,p-src);
    dst[p-src]='\0';
  }
}

void
after(char *dst, char *src, char *sep)
{
  char *p=strstr(src,sep);
  int l=strlen(sep);
//
  if (p==NULL) dst[0]='\0';
  else strncpy(dst,p+l,STRSIZE);
}

int
scan(char *mot, char **src)
{
  int l;
  char blank[]=" ,;\t\n";
//
  *src=*src+strspn(*src,blank);
  l=strcspn(*src,blank);
  if (l==0) mot[0]='\0';
  else
  {
    memmove(mot,*src,l);
    *src=*src+l;
    mot[l]='\0';
  }
 return l;
}

int
ReadLn (FILE* fd, char *s)
{
  int n;

  fgets(s, STRSIZE, fd);
  n = strlen(s);
  assert(n>0);
  s[n-1] = 0x00;
  return n-1;
}


