diff --git a/alliance/src/growstk/src/Makefile.am b/alliance/src/growstk/src/Makefile.am new file mode 100644 index 00000000..a29ddb41 --- /dev/null +++ b/alliance/src/growstk/src/Makefile.am @@ -0,0 +1,12 @@ +## Process this file with automake to produce Makefile.in + +bin_PROGRAMS = growstk + +AM_CFLAGS = @ALLIANCE_CFLAGS@ + +growstk_LDADD = @ALLIANCE_LIBS@ \ + -lMpu -lMcp -lMap -lMmg \ + -lRtl -lRgs -lRcf -lRfm -lRpr -lRwi -lRut -lRds\ + -lMph -lMut + +growstk_SOURCES = hash.h hash.c growstk.c diff --git a/alliance/src/growstk/src/growstk.c b/alliance/src/growstk/src/growstk.c new file mode 100644 index 00000000..45a172e2 --- /dev/null +++ b/alliance/src/growstk/src/growstk.c @@ -0,0 +1,443 @@ +#include +#include +#include +//#include +#include "hash.h" +#include "mph.h" +#include "mpu.h" +#include "mut.h" +#include "rds.h" +#include "rfm.h" +#include "rpr.h" +#include "rwi.h" +#include "rut.h" +#include "rtl.h" + +#define NEED_PATCH 0x08000000 +#define NEED_PATCH_MASK 0x08000000 +#define OBSTACLE_NORTH 0x80000000 +#define OBSTACLE_SOUTH 0x40000000 +#define OBSTACLE_EAST 0x20000000 +#define OBSTACLE_WEST 0x10000000 +#define OBSTACLE_MASK 0xF0000000 + +#define SetRdsNeedPatch(R) ((R)->FLAGS = ((R)->FLAGS | NEED_PATCH_MASK)) +#define IsRdsNeedPatch(R) ((R)->FLAGS & NEED_PATCH_MASK) +#define SetRdsObstacle(R,O) ((R)->FLAGS = (R)->FLAGS | (O)) +#define IsRdsObstacle(R) ((R)->FLAGS & OBSTACLE_MASK) + +#define rds2mbklayer(L) (((L)==RDS_ALU2) ? ALU2 :\ + ((L)==RDS_ALU3) ? ALU3 :\ + ((L)==RDS_ALU4) ? ALU4 :\ + ((L)==RDS_ALU5) ? ALU5 :\ + ((L)==RDS_ALU6) ? ALU6 :0) + +/* return 1 if r1 and r2 are in touch + */ +int RecInTouch (rdsrec_list * r1, rdsrec_list * r2) +{ + if ( ( ((r2->X >= r1->X) && ((r2->X) <= (r1->X + r1->DX))) + || ((r2->X <= r1->X) && ((r2->X + r2->DX) >= (r1->X))) + ) + && ( ((r2->Y >= r1->Y) && ((r2->Y) <= (r1->Y + r1->DY))) + || ((r2->Y <= r1->Y) && ((r2->Y + r2->DY) >= (r1->Y))) + ) + ) + return 1; + return 0; +} + +long verbose = 1; + +void usage (char *av[]) +{ + printf ("Usage : %s [-h] [-v level] [-o OutFile] InFile\n\n", av[0]); + printf (" -h this help\n"); + printf (" -v verbose mode (level is 1:2:3:4)\n"); + printf (" -o define the output file (InFile by default)\n"); + printf (" InFile define the input file\n"); + printf ("\n uses only symbolic technology file !!!\n"); + printf ("\n"); + exit (1); +} + +void getoption (int ac, char *av[], char **OutFile, char **InFile) +{ + char option; + while ((option = getopt (ac, av, "hv:o:")) != EOF) + { + switch (option) + { + case 'v': + verbose = *optarg - '0'; + if ((verbose < 0) || (verbose > 9)) + usage (av); + break; + case 'o': + *OutFile = namealloc (optarg); + break; + default: + usage (av); + } + } + if (optind == ac - 1) + { + *InFile = namealloc (av[optind]); + } + else + usage (av); +} + +#define NbLayerList 5 +#define EquivNbLayerList 2 +int main (int ac, char *av[]) +{ + char *InFile, *OutFile; + phfig_list *PhFig; + phseg_list *PhSeg; + phvia_list *PhVia; + rdsfig_list *RdsFig; + rdswindow *Window; + long WX, WY, Offset, Pitch, BorderX, BorderY; + rdswin_list *Win; + rdswinrec_list *WinRec; + rdsrec_list *NewRec = NULL; + rdsrec_list *ScanRec, *WinScanRec; + rdsrec_list *RecNorth, *RecSouth, *RecEast, *RecWest; + int Layer, WinLayer; + int LayerIdx, WinLayerIdx; + int MinLayerArea[NbLayerList] = + { 2, // Alu2 + 2, // Alu3 + 2, // Alu4 + 2, // Alu5 + 2}; // Alu6 + int LayerList[NbLayerList][EquivNbLayerList] = + {{RDS_LAYER_ALU2, RDS_LAYER_TALU2}, + {RDS_LAYER_ALU3, RDS_LAYER_TALU3}, + {RDS_LAYER_ALU4, RDS_LAYER_TALU4}, + {RDS_LAYER_ALU5, RDS_LAYER_TALU5}, + {RDS_LAYER_ALU6, RDS_LAYER_TALU6}}; + int Index; + ht_t *dejavu = htinit (63179); + char buffer[1000]; + + /* read parameters & environment */ + mbkenv (); + rdsenv (); + loadrdsparam (); + if (RDS_LAMBDA/RDS_UNIT != 1) usage (av); + + Pitch = 5 * RDS_LAMBDA; + + getoption (ac, av, &OutFile, &InFile); + if (verbose != 0) + alliancebanner ("GrowStk", VERSION, "grows the stacked vias", "2002", ALLIANCE_VERSION); + + /* read files and buids mbk & rds structures */ + PhFig = getphfig (InFile, 'A'); + PhFig -> NAME = namealloc (OutFile); + RdsFig = addrdsfig (InFile, 0); + for (PhSeg = PhFig->PHSEG; PhSeg; PhSeg = PhSeg->NEXT) + segmbkrds (RdsFig, PhSeg, 0); + for (PhVia = PhFig->PHVIA; PhVia; PhVia = PhVia->NEXT) + viambkrds (RdsFig, PhVia, 0); + + RecNorth = allocrdsrec(0); + RecSouth = allocrdsrec(0); + RecEast = allocrdsrec(0); + RecWest = allocrdsrec(0); + + /* build windows */ + Window = buildrdswindow (RdsFig); + for (LayerIdx = 0; LayerIdx < NbLayerList; LayerIdx++) + { + int first = 1; + Layer = RDS_DYNAMIC_LAYER[LayerList[LayerIdx][0]]; + if (RdsFig->LAYERTAB) + { + for (ScanRec=RdsFig->LAYERTAB[Layer]; ScanRec; ScanRec = ScanRec->NEXT) + { + if (ScanRec == NULL) break; + if ((ScanRec->DX > RDS_LAMBDA * MinLayerArea[LayerIdx]) + || (ScanRec->DY > RDS_LAMBDA * MinLayerArea[LayerIdx])) + continue; + + if (verbose > 3) + { + if (first) printf ("LAYER = %s\n", RDS_LAYER_NAME[Layer]); + printf ("X=%.2f, Y=%.2f, DX=%.2f, DY=%.2f\n", + (float)ScanRec->X/RDS_UNIT, (float)ScanRec->Y/RDS_UNIT, + (float)ScanRec->DX/RDS_UNIT, (float)ScanRec->DY/RDS_UNIT); + first = 0; + } + + /* there is a small square of metal */ + /* scan all rectangles of the current window */ + WX = ScanRec->X / Window->SIDE; + WY = ScanRec->Y / Window->SIDE; + if (verbose > 2) printf (" WINDOW (%ld,%ld)\n", WX, WY); + + Offset = (WY) * Window->DX + (WX); + Win = Window->WINTAB + Offset; + { + int first = 1; + for (WinLayerIdx = 0; WinLayerIdx < EquivNbLayerList; WinLayerIdx++) + { + WinLayer = RDS_DYNAMIC_LAYER[LayerList[LayerIdx][WinLayerIdx]]; + for (WinRec = Win->LAYERTAB[WinLayer]; WinRec != (rdswinrec_list *) NULL; WinRec = WinRec->NEXT) + { + for (Index = 0; Index < RWI_MAX_REC; Index++) + { + WinScanRec = WinRec->RECTAB[Index]; + if (WinScanRec == NULL) break; + if ( (ScanRec->X == WinScanRec->X) + && (ScanRec->Y == WinScanRec->Y) + && (ScanRec->DX == WinScanRec->DX) + && (ScanRec->DY == WinScanRec->DY) + ) + continue; + if (RecInTouch (ScanRec, WinScanRec)) + { + if (verbose > 3) printf (" abort\n"); + goto in_touch; + } + if (verbose > 3) + { + if (first) printf (" NLAYER = %s\n", RDS_LAYER_NAME[WinLayer]); + printf (" X=%.2f, Y=%.2f, DX=%.2f, DY=%.2f\n", + (float)WinScanRec->X/RDS_UNIT, (float)WinScanRec->Y/RDS_UNIT, + (float)WinScanRec->DX/RDS_UNIT, (float)WinScanRec->DY/RDS_UNIT); + first = 0; + } + } + } + } + } + if (verbose > 3) printf (" need patch\n"); + SetRdsNeedPatch (ScanRec); + + RecNorth->X = ScanRec->X; RecNorth->DX = ScanRec->DX; RecNorth->Y = ScanRec->Y; RecNorth->DY = ScanRec->DY + Pitch; + RecSouth->X = ScanRec->X; RecSouth->DX = ScanRec->DX; RecSouth->Y = ScanRec->Y - Pitch; RecSouth->DY = ScanRec->DY + Pitch; + RecEast->X = ScanRec->X - Pitch; RecEast->DX = ScanRec->DX + Pitch; RecEast->Y = ScanRec->Y; RecEast->DY = ScanRec->DY; + RecWest->X = ScanRec->X; RecWest->DX = ScanRec->DX + Pitch; RecWest->Y = ScanRec->Y; RecWest->DY = ScanRec->DY; + + for (BorderX = -1; BorderX < 1; BorderX++) + { + if (BorderX+WX == -1) continue; + if (BorderX+WX == Window->DX +1) continue; + for (BorderY = -1; BorderY < 1; BorderY++) + { + if (BorderY+WY == -1) continue; + if (BorderY+WY == Window->DY +1) continue; + if (verbose > 2) printf (" NEIGHBOUR WINDOW (%ld,%ld)\n", WX+BorderX, WY+BorderY); + + Offset = (WY+BorderY) * Window->DX + (WX+BorderX); + Win = Window->WINTAB + Offset; + + if (Win->LAYERTAB>(void *)0x1000) // j'ai l'impression que les fenetres ne sont pas initialisées à 0. + { + for (WinLayerIdx = 0; WinLayerIdx < EquivNbLayerList; WinLayerIdx++) + { + int first = 1; + WinLayer = RDS_DYNAMIC_LAYER[LayerList[LayerIdx][WinLayerIdx]]; + for (WinRec = Win->LAYERTAB[WinLayer]; WinRec != (rdswinrec_list *) NULL; WinRec = WinRec->NEXT) + { + for (Index = 0; Index < RWI_MAX_REC; Index++) + { + WinScanRec = WinRec->RECTAB[Index]; + if (WinScanRec == NULL) break; + if ( (ScanRec->X == WinScanRec->X) + && (ScanRec->Y == WinScanRec->Y) + && (ScanRec->DX == WinScanRec->DX) + && (ScanRec->DY == WinScanRec->DY) + ) + continue; + + if (RecInTouch (RecNorth, WinScanRec)) + { + SetRdsObstacle(ScanRec,OBSTACLE_NORTH); + if (verbose > 3) + { + if (first) printf (" NLAYER = %s\n", RDS_LAYER_NAME[WinLayer]); + printf (" X=%.2f, Y=%.2f, DX=%.2f, DY=%.2f is an obstacle north\n", + (float)WinScanRec->X/RDS_UNIT, (float)WinScanRec->Y/RDS_UNIT, + (float)WinScanRec->DX/RDS_UNIT, (float)WinScanRec->DY/RDS_UNIT); + first = 0; + } + } + if (RecInTouch (RecSouth, WinScanRec)) + { + SetRdsObstacle(ScanRec,OBSTACLE_SOUTH); + if (verbose > 3) + { + if (first) printf (" NLAYER = %s\n", RDS_LAYER_NAME[WinLayer]); + printf (" X=%.2f, Y=%.2f, DX=%.2f, DY=%.2f is an obstacle south\n", + (float)WinScanRec->X/RDS_UNIT, (float)WinScanRec->Y/RDS_UNIT, + (float)WinScanRec->DX/RDS_UNIT, (float)WinScanRec->DY/RDS_UNIT); + first = 0; + } + } + if (RecInTouch (RecWest, WinScanRec)) + { + SetRdsObstacle(ScanRec,OBSTACLE_WEST); + if (verbose > 3) + { + if (first) printf (" NLAYER = %s\n", RDS_LAYER_NAME[WinLayer]); + printf (" X=%.2f, Y=%.2f, DX=%.2f, DY=%.2f is an obstacle west\n", + (float)WinScanRec->X/RDS_UNIT, (float)WinScanRec->Y/RDS_UNIT, + (float)WinScanRec->DX/RDS_UNIT, (float)WinScanRec->DY/RDS_UNIT); + first = 0; + } + } + if (RecInTouch (RecEast, WinScanRec)) + { + SetRdsObstacle(ScanRec,OBSTACLE_EAST); + if (verbose > 3) + { + if (first) printf (" NLAYER = %s\n", RDS_LAYER_NAME[WinLayer]); + printf (" X=%.2f, Y=%.2f, DX=%.2f, DY=%.2f is an obstacle east\n", + (float)WinScanRec->X/RDS_UNIT, (float)WinScanRec->Y/RDS_UNIT, + (float)WinScanRec->DX/RDS_UNIT, (float)WinScanRec->DY/RDS_UNIT); + first = 0; + } + } + } + } + } + } + } + } + in_touch : + } + } + } + if (verbose > 1) + printf ("Segments that need patches :\n"); + + for (LayerIdx = 0; LayerIdx < NbLayerList; LayerIdx++) + { + int first = 1; + Layer = RDS_DYNAMIC_LAYER[LayerList[LayerIdx][0]]; + for (ScanRec=RdsFig->LAYERTAB[Layer]; ScanRec; ScanRec = ScanRec->NEXT) + { + if (IsRdsNeedPatch(ScanRec)) + { + rdsrec_list * rec; + + sprintf (buffer, "%d %d %d %d %d", + ScanRec->X, ScanRec->Y, ScanRec->DX, ScanRec->DY, ScanRec->FLAGS); + if (!htget (dejavu, buffer)) + { + htset (dejavu, buffer); + rec = allocrdsrec(0); + rec->NEXT = NewRec; + NewRec = rec; + NewRec->X = ScanRec->X; + NewRec->Y = ScanRec->Y; + NewRec->DX = ScanRec->DX; + NewRec->DY = ScanRec->DY; + NewRec->FLAGS = ScanRec->FLAGS; + NewRec->NAME = NULL; + NewRec->USER = NULL; + + if (verbose > 1) + { + if (first) printf ("LAYER = %s\n", RDS_LAYER_NAME[Layer]); + printf (" X=%.2f, Y=%.2f, DX=%.2f, DY=%.2f, OBS=%s%s%s%s\n", + (float)ScanRec->X/RDS_UNIT, (float)ScanRec->Y/RDS_UNIT, + (float)ScanRec->DX/RDS_UNIT, (float)ScanRec->DY/RDS_UNIT, + (IsRdsObstacle(ScanRec) & OBSTACLE_NORTH)?"NORTH ":"", + (IsRdsObstacle(ScanRec) & OBSTACLE_SOUTH)?"SOUTH ":"", + (IsRdsObstacle(ScanRec) & OBSTACLE_EAST)?"EAST ":"", + (IsRdsObstacle(ScanRec) & OBSTACLE_WEST)?"WEST ":"" + ); + first = 0; + } + if ((IsRdsObstacle(ScanRec) & OBSTACLE_NORTH) == 0) + { + NewRec->DY += Pitch; + } + else + if ((IsRdsObstacle(ScanRec) & OBSTACLE_EAST) == 0) + { + NewRec->DX += Pitch; + NewRec->X -= Pitch; + } + else + if ((IsRdsObstacle(ScanRec) & OBSTACLE_SOUTH) == 0) + { + NewRec->DY += Pitch; + NewRec->Y -= Pitch; + } + else + if ((IsRdsObstacle(ScanRec) & OBSTACLE_WEST) == 0) + { + NewRec->DX += Pitch; + } + else + { + if (first) printf ("LAYER = %s\n", RDS_LAYER_NAME[Layer]); + printf ("ERROR X=%.2f, Y=%.2f, DX=%.2f, DY=%.2f CANNOT BE REPAIRED\n", + (float)ScanRec->X/RDS_UNIT, (float)ScanRec->Y/RDS_UNIT, + (float)ScanRec->DX/RDS_UNIT, (float)ScanRec->DY/RDS_UNIT); + first = 0; + } + } + else + { + if (verbose > 2) + { + printf ("DEJA VU : LAYER = %s ", RDS_LAYER_NAME[Layer]); + printf (" X=%.2f, Y=%.2f, DX=%.2f, DY=%.2f, OBS=%s%s%s%s\n", + (float)ScanRec->X/RDS_UNIT, (float)ScanRec->Y/RDS_UNIT, + (float)ScanRec->DX/RDS_UNIT, (float)ScanRec->DY/RDS_UNIT, + (IsRdsObstacle(ScanRec) & OBSTACLE_NORTH)?"NORTH ":"", + (IsRdsObstacle(ScanRec) & OBSTACLE_SOUTH)?"SOUTH ":"", + (IsRdsObstacle(ScanRec) & OBSTACLE_EAST)?"EAST ":"", + (IsRdsObstacle(ScanRec) & OBSTACLE_WEST)?"WEST ":"" + ); + } + } + } + } + } + for (ScanRec=NewRec; ScanRec; ScanRec = ScanRec->NEXT) + { + char MbkLayer = rds2mbklayer(GetRdsLayer(ScanRec)); + + if (MbkLayer==0) + { + printf ("Internal error during the layer translation\n"); + printf ("LAYER = %s X=%.2f, Y=%.2f, DX=%.2f, DY=%.2f\n", RDS_LAYER_NAME[GetRdsLayer(ScanRec)], + (float)ScanRec->X/RDS_UNIT, (float)ScanRec->Y/RDS_UNIT, + (float)ScanRec->DX/RDS_UNIT, (float)ScanRec->DY/RDS_UNIT); + exit (1); + } + if (verbose > 1) + { + printf ("LAYER = %s X=%.2f, Y=%.2f, DX=%.2f, DY=%.2f\n", RDS_LAYER_NAME[GetRdsLayer(ScanRec)], + (float)ScanRec->X/RDS_UNIT, (float)ScanRec->Y/RDS_UNIT, + (float)ScanRec->DX/RDS_UNIT, (float)ScanRec->DY/RDS_UNIT); + } + + if (ScanRec->DX < ScanRec->DY) + addphseg (PhFig, MbkLayer, + (SCALE_X * ScanRec->DX) / RDS_UNIT, + (SCALE_X * (ScanRec->X + ScanRec->DX / 2)) / RDS_UNIT , + (SCALE_X * (ScanRec->Y + RDS_LAMBDA)) / RDS_UNIT , + (SCALE_X * (ScanRec->X + ScanRec->DX / 2)) / RDS_UNIT , + (SCALE_X * (ScanRec->Y + ScanRec->DY - RDS_LAMBDA)) / RDS_UNIT , + NULL); + else + addphseg (PhFig, MbkLayer, + (SCALE_X * ScanRec->DY) / RDS_UNIT, + (SCALE_X * (ScanRec->X + RDS_LAMBDA)) / RDS_UNIT , + (SCALE_X * (ScanRec->Y + ScanRec->DY / 2)) / RDS_UNIT , + (SCALE_X * (ScanRec->X + ScanRec->DX - RDS_LAMBDA)) / RDS_UNIT , + (SCALE_X * (ScanRec->Y + ScanRec->DY / 2)) / RDS_UNIT , + NULL); + } + savephfig (PhFig); + return 0; +} diff --git a/alliance/src/growstk/src/hash.c b/alliance/src/growstk/src/hash.c new file mode 100644 index 00000000..d1574654 --- /dev/null +++ b/alliance/src/growstk/src/hash.c @@ -0,0 +1,107 @@ +/* + * This file is part of the Alliance CAD System + * Copyright (C) Laboratoire LIP6 - Département ASIM + * Universite Pierre et Marie Curie + * + * Home page : http://www-asim.lip6.fr/alliance/ + * E-mail support : mailto:alliance-support@asim.lip6.fr + * + * This progam 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 2 of the License, or (at your + * option) any later version. + * + * Alliance VLSI CAD System 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 the GNU C Library; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + + +#include +#include +#include +#include +#include "hash.h" + +static int primes[] = { + 101, 223, 311, 419, 547, 659, 727, 877, 967, + 1061, 2053, 3299, 4391, 5309, 6421, 7069, 8543, 9397, + 10337, 20143, 32423, 43151, 52223, 63179, 0 +}; + +void htremove (ht_t * htable) +{ + int i; + for (i = 1; i < (int)htable[0]; i++) + freechain (htable[i]); + free (htable); +} + +ht_t *htinit (int size) +{ + int i; + ht_t *htable; + + /* prend le premier nombre premier au dela de size */ + for (i = 0; primes[i] && (size > primes[i]); i++); + if (primes[i] == 0) + { + fprintf (stderr, "Erreur : hash table trop grande (> %d)\n", primes[i - 1]); + exit (1); + } + size = primes[i]; + if ((htable = calloc (size + 1, sizeof (chain_list *))) == NULL) + { + perror ("htinit"); + exit (1); + } + htable[0] = (chain_list *) size; /* taille de la table dans premiere case */ + return htable; +} + +static int hash (ht_t * htable, char *key) +{ + int alveole = 0; + int length = strlen (key); + int segment; + int l; + + if ((key == NULL) || (length == 0)) + { + fprintf (stderr, "Error : hash (NULL)\n"); + exit (1); + } + for (l = 0; l < length; l += 2) + { + segment = 0xFFFF & ((key[l] << 8) | key[l + 1]); + alveole = alveole ^ ((segment << 1) | (segment >> 15)); + } + alveole %= (int) htable[0]; /* htable[0] == la taille de la table */ + return (alveole + 1); /* +1 car on ne doit rien mettre dans case 0 */ +} + +chain_list *htget (ht_t * htable, char *key) +{ + int alveole = hash (htable, key); + chain_list *p; + + for (p = htable[alveole]; p && strcmp (p->DATA, key); p = p->NEXT); + return p; +} + +chain_list *htset (ht_t * htable, char *key) +{ + int alveole = hash (htable, key); + chain_list *p; + + for (p = htable[alveole]; p && strcmp (p->DATA, key); p = p->NEXT); + if (p) + return p; + htable[alveole] = addchain (htable[alveole], strdup (key)); + return htable[alveole]; +} diff --git a/alliance/src/growstk/src/hash.h b/alliance/src/growstk/src/hash.h new file mode 100644 index 00000000..d85d5cc3 --- /dev/null +++ b/alliance/src/growstk/src/hash.h @@ -0,0 +1,37 @@ +/* + * This file is part of the Alliance CAD System + * Copyright (C) Laboratoire LIP6 - Département ASIM + * Universite Pierre et Marie Curie + * + * Home page : http://www-asim.lip6.fr/alliance/ + * E-mail support : mailto:alliance-support@asim.lip6.fr + * + * This progam 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 2 of the License, or (at your + * option) any later version. + * + * Alliance VLSI CAD System 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 the GNU C Library; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + + +#ifndef HASH_H +#define HASH_H + +#include + +typedef chain_list *ht_t; /* def d'1 table de hachage table de htele_t */ + +extern ht_t *htinit (int size); +extern void htremove (ht_t * htable); +extern chain_list *htset (ht_t * htable, char *key); +extern chain_list *htget (ht_t * htable, char *key); + +#endif