--- /dev/null
+/**
+ * @file proj1.c
+ * @brief Implementacao do primeiro projecto de IAED.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#define P 5
+#define M 3
+#define O 5
+#define LEN 10
+
+/**
+ * @brief Estrutura que representa um produto.
+ */
+typedef struct {
+ char nome[LEN + 1];
+ double m[M], perdas, k_mo, k_en, k_eq, vendas, pvenda;
+} produto_t;
+
+/**
+ * @brief Estrutura que representa uma materia.
+ */
+typedef struct {
+ char nome[LEN + 1];
+ double custo;
+} materia_t;
+
+/**
+ * Variaveis locais ao programa.
+ */
+static produto_t produto[P];
+static materia_t materia[M];
+static double orcamento[O];
+
+/**
+ * Declaracao das funcaoes utilizadas neste programa.
+ */
+void go_d();
+void go_d_i();
+void go_d_j();
+void go_d_y();
+void go_d_v();
+void go_d_z();
+void go_d_p();
+void go_d_m();
+void go_d_n();
+void go_d_q();
+void go_d_o();
+void go_d_c();
+
+void go_c();
+void go_w();
+void go_t();
+void go_v();
+void go_x();
+
+double custo_a();
+double custo_b(int p);
+double custo_c(int p);
+double custo_d(int p);
+double custo_e();
+double custo_f(int p);
+
+double custo_tot(int p);
+double custo_ind(int p);
+double custo_mpee(int p);
+double margem(int p, double d);
+
+/**
+ * @brief Funcao main.
+ *
+ * @return Codigo de estado de saida do programa.
+ */
+int
+main()
+{
+ char comando;
+
+ while (1) {
+ /* Comandos: d(3, 5 15) c(0) w(1) t(0) v(2) x(1) */
+ comando = getchar();
+
+ /* Processa o comando. */
+ switch (comando) {
+ case 'd':
+ go_d();
+ break;
+ case 'c':
+ go_c();
+ break;
+ case 'w':
+ go_w();
+ break;
+ case 't':
+ go_t();
+ break;
+ case 'v':
+ go_v();
+ break;
+ case 'x':
+ go_x();
+ /* Este comando termina o programa. */
+ return EXIT_SUCCESS;
+ default:
+ /* Nao devemos chegar aqui. */
+ assert(0);
+ }
+ }
+
+ /* Nao devemos chegar aqui em situacoes normais. */
+ return EXIT_FAILURE;
+}
+
+/**
+ * @brief Funcao para processar o comando 'd'.
+ */
+void
+go_d()
+{
+ char subcomando;
+
+ getchar(); /* Apanha o espaco. */
+ subcomando = getchar();
+
+ /* Processa o subcomando. */
+ switch (subcomando) {
+ case 'i':
+ go_d_i();
+ break;
+ case 'j':
+ go_d_j();
+ break;
+ case 'y':
+ go_d_y();
+ break;
+ case 'v':
+ go_d_v();
+ break;
+ case 'z':
+ go_d_z();
+ break;
+ case 'p':
+ go_d_p();
+ break;
+ case 'm':
+ go_d_m();
+ break;
+ case 'n':
+ go_d_n();
+ break;
+ case 'q':
+ go_d_q();
+ break;
+ case 'o':
+ go_d_o();
+ break;
+ case 'c':
+ go_d_c();
+ break;
+ default:
+ /* Nao devemos chegar aqui. */
+ assert(0);
+ }
+}
+
+/**
+ * @brief Funcao para processar o comando 'd i'.
+ */
+void
+go_d_i()
+{
+ int i = 0;
+
+ for (i = 0; i < P; i++) {
+ /* Ler, e escrever como solicitado. */
+ scanf("%s", produto[i].nome);
+ printf ("%s", produto[i].nome);
+ if (i < P -1)
+ printf(" ");
+ }
+ putchar(getchar()); /* Apanha e escreve fim de linha. */
+}
+
+/**
+ * @brief Funcao para processar o comando 'd j'.
+ */
+void
+go_d_j()
+{
+ int i = 0;
+
+ for (i = 0; i < M; i++) {
+ /* Ler, e escrever como solicitado. */
+ scanf("%s", materia[i].nome);
+ printf ("%s", materia[i].nome);
+ if (i < M -1)
+ printf(" ");
+ }
+ putchar(getchar()); /* Apanha e escreve fim de linha. */
+}
+
+/**
+ * @brief Funcao para processar o comando 'd y'.
+ */
+void
+go_d_y()
+{
+ int i = 0;
+
+ for (i = 0; i < M; i++)
+ scanf("%lf", &materia[i].custo);
+ getchar(); /* Apanha fim de linha. */
+}
+
+/**
+ * @brief Funcao para processar o comando 'd v'.
+ */
+void
+go_d_v()
+{
+ int i = 0;
+
+ for (i = 0; i < P; i++)
+ scanf("%lf", &produto[i].vendas);
+ getchar(); /* Apanha fim de linha. */
+}
+
+/**
+ * @brief Funcao para processar o comando 'd z'.
+ */
+void
+go_d_z()
+{
+ int i = 0;
+
+ for (i = 0; i < P; i++)
+ scanf("%lf", &produto[i].pvenda);
+ getchar(); /* Apanha fim de linha. */
+}
+
+/**
+ * @brief Funcao para processar o comando 'd p'.
+ */
+void
+go_d_p()
+{
+ int i = 0;
+
+ for (i = 0; i < P; i++)
+ scanf("%lf", &produto[i].perdas);
+ getchar(); /* Apanha fim de linha. */
+}
+
+/**
+ * @brief Funcao para processar o comando 'd m'.
+ */
+void
+go_d_m()
+{
+ int i = 0;
+
+ for (i = 0; i < P; i++)
+ scanf("%lf", &produto[i].k_mo);
+ getchar(); /* Apanha fim de linha. */
+}
+
+/**
+ * @brief Funcao para processar o comando 'd n'.
+ */
+void
+go_d_n()
+{
+ int i = 0;
+
+ for (i = 0; i < P; i++)
+ scanf("%lf", &produto[i].k_en);
+ getchar(); /* Apanha fim de linha. */
+}
+
+/**
+ * @brief Funcao para processar o comando 'd q'.
+ */
+void
+go_d_q()
+{
+ int i = 0;
+
+ for (i = 0; i < P; i++)
+ scanf("%lf", &produto[i].k_eq);
+ getchar(); /* Apanha fim de linha. */
+}
+
+/**
+ * @brief Funcao para processar o comando 'd o'.
+ */
+void
+go_d_o()
+{
+ int i = 0;
+
+ for (i = 0; i < O; i++)
+ scanf("%lf", &orcamento[i]);
+ getchar(); /* Apanha fim de linha. */
+}
+
+/**
+ * @brief Funcao para processar o comando 'd c'.
+ */
+void
+go_d_c()
+{
+ int i = 0, j = 0;
+
+ /* Constituicao dos produtos. */
+ for (i = 0; i < P; i++)
+ for (j = 0; j < M; j++)
+ scanf("%lf", &produto[i].m[j]);
+ getchar(); /* Apanha fim de linha. */
+}
+
+/**
+ * @brief Funcao para processar o comando 'c'.
+ */
+void
+go_c()
+{
+ int i;
+
+ getchar(); /* Apanha fim de linha. */
+
+ printf("cTOT");
+ for (i = 0; i < P; i++)
+ printf(" %.2f", custo_tot(i));
+ printf("\n");
+
+ printf("M");
+ for (i = 0; i < P; i++)
+ printf(" %.2f", margem(i, 0.0));
+ printf("\n");
+
+ printf("cIND");
+ for (i = 0; i < P; i++)
+ printf(" %.2f", custo_ind(i));
+ printf("\n");
+
+ printf("cMPEE");
+ for (i = 0; i < P; i++)
+ printf(" %.2f", custo_mpee(i));
+ printf("\n");
+}
+
+/**
+ * @brief Funcao para processar o comando 'w'.
+ */
+void
+go_w()
+{
+ int p;
+
+ scanf("%d", &p);
+ getchar(); /* Apanha fim de linha. */
+ p--;
+
+ printf("W %s A:%.2f B:%.2f C:%.2f D:%.2f E:%.2f F:%.2f\n",
+ produto[p].nome,
+ custo_a(),
+ custo_b(p),
+ custo_c(p),
+ custo_d(p),
+ custo_e(),
+ custo_f(p));
+}
+
+/**
+ * @brief Funcao para processar o comando 't'.
+ */
+void
+go_t()
+{
+ int i;
+ double custo = 0.0, venda = 0.0;
+
+ getchar(); /* Apanha fim de linha. */
+
+ /* Calcular os valores acumulados para as vendas e para os custos
+ * totais. */
+ for (i = 0; i < P; i++) {
+ custo += custo_tot(i) * produto[i].vendas;
+ venda += produto[i].pvenda * produto[i].vendas;
+ }
+
+ printf("T %.2f %.2f %.2f %.2f\n",
+ custo,
+ venda,
+ venda - custo,
+ (venda - custo) * 100 / venda);
+}
+
+/**
+ * @brief Funcao para processar o comando 'v'.
+ */
+void
+go_v()
+{
+ int p;
+ double d, vd;
+
+ scanf("%d %lf", &p, &d);
+ getchar(); /* Apanha fim de linha. */
+ p--;
+
+ printf("VD %s %.2f %.2f %.2f",
+ produto[p].nome,
+ margem(p, 0),
+ d,
+ margem(p, d));
+
+ /* Calcular valor com desconto. */
+ vd = produto[p].pvenda * (1 - d/100);
+
+ /* Analise da decisao face ao desconto. */
+ if (custo_tot(p) <= vd)
+ printf(" tot\n");
+ else if (custo_ind(p) <= vd)
+ printf(" ind\n");
+ else if (custo_mpee(p) <= vd)
+ printf(" mpee\n");
+ else
+ printf(" 0\n");
+}
+
+/**
+ * @brief Funcao de comparacao para produtos.
+ *
+ * Funcao de comapracao para produtos que tem em conta o custo total,
+ * por ordem crescente, e caso os dois produtos tenham o mesmo custo
+ * total, tem em conta o seu identificados também por ordem crescente.
+ *
+ * @return 0 se os produtos tiverem o mesmo custo total e o mesmo
+ * identificador, -1 se o custo total do primeiro for menor do que
+ * o custo total do segundo, ou sendo iguais, se o identificador do
+ * primeiro for menor do que o do segundo, 1 caso contrario.
+ */
+static int
+pcmp(const void * pa, const void *pb)
+{
+ int i = * (int *) pa, j = * (int *) pb;
+
+ /* Comparar custos totais. */
+ if (custo_tot(i) < custo_tot(j))
+ return -1;
+
+ if (custo_tot(i) > custo_tot(j))
+ return 1;
+
+ /* Os custos totais sao iguais, comparar identificadores. */
+ return i - j;
+}
+
+/**
+ * @brief Funcao para processar o comando 'x'.
+ */
+void
+go_x()
+{
+ int choice, tmp[P], i;
+
+ scanf("%d", &choice);
+ getchar(); /* Apanha fim de linha. */
+
+ /* Se a escolha e' diferente de 0, entao temos de ordenar. */
+ if (choice) {
+
+ /* Preencher vector auxiliar para comparacao indirecta. Na pratica
+ * vamos estar a ordenar indices do vector dos produtos. */
+ for (i = 0; i < P; i++)
+ tmp[i] = i;
+
+ /* Ordenar com fase na funcao pcmp que implementa os criterios de
+ * comparacao. */
+ qsort(tmp, P, sizeof(int), pcmp);
+
+ /* Imprimir os produtos ordenados. Notar o acesso indirecto ao
+ * vector com os produtos. */
+ for (i = 0; i < P; i++)
+ printf("%s %.2f\n", produto[tmp[i]].nome, custo_tot(tmp[i]));
+ }
+}
+
+/**
+ * @brief Funcao para calcular CUSTO A.
+ *
+ * @return valor do CUSTO A
+ */
+double
+custo_a()
+{
+ int i;
+ double vendas_total = 0;
+
+ for (i = 0; i < P; i++)
+ vendas_total += produto[i].vendas;
+
+ return orcamento[0] / vendas_total;
+}
+
+/**
+ * @brief Funcao para calcular CUSTO B.
+ *
+ * @param 'p' identificador/indice do produto
+ * @return valor do CUSTO B para o produto 'p'
+ */
+double
+custo_b(int p)
+{
+ int i;
+ double mo = 0;
+
+ for (i = 0; i < P; i++)
+ mo += produto[i].k_mo * produto[i].vendas;
+
+ return orcamento[1] * produto[p].k_mo / mo;
+}
+
+/**
+ * @brief Funcao para calcular CUSTO C.
+ *
+ * @param 'p' identificador/indice do produto
+ * @return valor do CUSTO C para o produto 'p'
+ */
+double
+custo_c(int p)
+{
+ int i;
+ double en = 0;
+
+ for (i = 0; i < P; i++)
+ en += produto[i].k_en * produto[i].vendas;
+
+ return orcamento[2] * produto[p].k_en / en;
+}
+
+/**
+ * @brief Funcao para calcular CUSTO D.
+ *
+ * @param 'p' identificador/indice do produto
+ * @return valor do CUSTO C para o produto 'p'
+ */
+double
+custo_d(int p)
+{
+ int i;
+ double eq = 0;
+
+ for (i = 0; i < P; i++)
+ eq += produto[i].k_eq * produto[i].vendas;
+
+ return orcamento[3] * produto[p].k_eq / eq;
+}
+
+/**
+ * @brief Funcao para calcular CUSTO E.
+ *
+ * @return valor do CUSTO E
+ */
+double
+custo_e()
+{
+ int i;
+ double vendas_total = 0;
+
+ for (i = 0; i < P; i++)
+ vendas_total += produto[i].vendas;
+
+ return orcamento[4] / vendas_total;
+}
+
+/**
+ * @brief Funcao para calcular CUSTO F.
+ *
+ * @param 'p' identificador/indice do produto
+ * @return valor do CUSTO F para o produto 'p'
+ */
+double
+custo_f(int p)
+{
+ int i;
+ double mat = 0;
+
+ for (i = 0; i < M; i++)
+ mat += produto[p].m[i] * materia[i].custo;
+
+ return mat / (100 - produto[p].perdas) * 1000;
+}
+
+/**
+ * @brief Funcao para calcular o custo total
+ *
+ * @param 'p' identificador/indice do produto
+ * @return valor do custo total para o produto 'p'
+ */
+double
+custo_tot(int p)
+{
+ return custo_a() + custo_b(p) + custo_c(p)
+ + custo_d(p) + custo_e() + custo_f(p);
+}
+
+/**
+ * @brief Funcao para calcular o custo indirecto.
+ *
+ * @param 'p' identificador/indice do produto
+ * @return valor do custo indirecto para o produto 'p'
+ */
+double
+custo_ind(int p)
+{
+ return custo_b(p) + custo_c(p) + custo_d(p)
+ + custo_e() + custo_f(p);
+}
+
+/**
+ * @brief Funcao para calcular o custo MPEE.
+ *
+ * @param 'p' identificador/indice do produto
+ * @return valor do custo MPEE para o produto 'p'
+ */
+double custo_mpee(int p)
+{
+ return custo_c(p) + custo_e() + custo_f(p);
+}
+
+/**
+ * @brief Funcao para calcular a margem.
+ *
+ * @param 'p' identificador/indice do produto
+ * @param 'd' desconto em percentagem a aplicar
+ * @return valor da margem de lucro para o produto 'p'
+ */
+double margem(int p, double d)
+{
+ return ((produto[p].pvenda * (1 - d/100)) - custo_tot(p)) * 100
+ / (produto[p].pvenda * (1 - d/100));
+}
+
--- /dev/null
+/*-
+ * Copyright (c) 2011, A P Francisco
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <assert.h>
+
+#define LEFT(x) ((((x) + 1) << 1) - 1)
+#define RIGHT(x) (((x) + 1) << 1)
+#define PARENT(x) ((((x) + 1) >> 1) - 1)
+
+void
+binheap_exchange(size_t *heap, size_t *map, size_t i, size_t j)
+{
+ size_t v;
+
+ assert(map[heap[i]] == i && map[heap[j]] == j);
+
+ map[heap[i]] = j;
+ map[heap[j]] = i;
+ v = heap[i];
+ heap[i] = heap[j];
+ heap[j] = v;
+
+ assert(map[heap[i]] == i && map[heap[j]] == j);
+}
+
+void
+binheap_siftdown(void *key, size_t *heap, size_t *map, size_t n, size_t size,
+ size_t i, int(*cmp)(const void *, const void *))
+{
+ size_t l = LEFT(i), r = RIGHT(i), m = i;
+
+ if (l < n && cmp(((char *) key) + heap[l]*size,
+ ((char *) key) + heap[m]*size) < 0)
+ m = l;
+ if (r < n && cmp(((char *) key) + heap[r]*size,
+ ((char *) key) + heap[m]*size) < 0)
+ m = r;
+ if (m == i) return;
+ binheap_exchange(heap, map, i, m);
+ binheap_siftdown(key, heap, map, n, size, m, cmp);
+}
+
+void
+binheap_siftup(void *key, size_t *heap, size_t *map, size_t n, size_t size,
+ size_t i, int(*cmp)(const void *, const void *))
+{
+ size_t p = PARENT(i);
+
+ if (p >= ULONG_MAX || cmp(((char *) key) + heap[p]*size,
+ ((char *) key) + heap[i]*size) <= 0) {
+ return;
+ }
+ binheap_exchange(heap, map, i, p);
+ binheap_siftup(key, heap, map, n, size, p, cmp);
+}
+
+void
+binheap_make(void *key, size_t *heap, size_t *map, size_t n,
+ size_t size, int(*cmp)(const void *, const void *))
+{
+ int i;
+
+ for (i = 0; i < n; i++)
+ heap[i] = map[i] = i;
+
+ for (i = PARENT(n - 1); i >= 0; i--)
+ binheap_siftdown(key, heap, map, n, size, i, cmp);
+}
+
--- /dev/null
+/*-
+ * Copyright (c) 2013, A P Francisco
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _BINHEAP_H_
+#define _BINHEAP_H_
+
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+
+struct binheap {
+ size_t size;
+ size_t max_size;
+ size_t *heap;
+ size_t *map;
+ void *key;
+ size_t ksz;
+ int (*cmp)(const void *,const void *);
+};
+
+#define LEFT(x) ((((x) + 1) << 1) - 1)
+#define RIGHT(x) (((x) + 1) << 1)
+#define PARENT(x) ((((x) + 1) >> 1) - 1)
+
+#define BINHEAP_INIT(q, type, k, n, c) do { \
+ (q) = malloc(sizeof(struct binheap)); \
+ (q)->max_size = (n); \
+ (q)->size = 0; \
+ (q)->heap = malloc(sizeof(size_t)*(n)); \
+ memset((q)->heap, 0xFF, sizeof(size_t)*(n)); \
+ (q)->map = malloc(sizeof(size_t)*(n)); \
+ memset((q)->map, 0xFF, sizeof(size_t)*(n)); \
+ (q)->key = (k); \
+ (q)->ksz = sizeof(type); \
+ (q)->cmp = (c); \
+} while (/*CONSTCOND*/0)
+
+#define BINHEAP_FREE(q) do { \
+ free((q)->heap); \
+ free((q)->map); \
+ free(q); \
+} while (/*CONSTCOND*/0)
+
+#define BINHEAP_EMPTY(q) ((q)->size == 0)
+#define BINHEAP_HAS(q, id) ((q)->map[id] < (q)->size)
+#define BINHEAP_TOP(q) ((q)->heap[0])
+
+#define BINHEAP_RESET(q) do { \
+ (q)->size = 0; \
+ memset((q)->heap, 0xFF, sizeof(size_t)*(q)->max_size); \
+ memset((q)->map, 0xFF, sizeof(size_t)*(q)->max_size); \
+} while (/*CONSTCOND*/0)
+
+#define BINHEAP_PUSH(q, id) do { \
+ if ((q)->map[id] >= ULONG_MAX) { \
+ if ((q)->size >= (q)->max_size) \
+ abort(); \
+ \
+ (q)->map[id] = (q)->size; \
+ (q)->heap[(q)->size] = (id); \
+ (q)->size ++; \
+ } \
+ binheap_siftup((q)->key, (q)->heap, (q)->map, (q)->size, \
+ (q)->ksz, (q)->map[id], (q)->cmp); \
+ binheap_siftdown((q)->key, (q)->heap, (q)->map, (q)->size, \
+ (q)->ksz, (q)->map[id], (q)->cmp); \
+} while (/*CONSTCOND*/0)
+
+#define BINHEAP_UPDATE(q, id) BINHEAP_PUSH(q, id)
+
+#define BINHEAP_DEL(q, id) do { \
+ register size_t aux = (q)->map[id]; \
+ q->size--; \
+ if (q->size != aux) { \
+ binheap_exchange((q)->heap, (q)->map, (q)->size, aux); \
+ binheap_siftup((q)->key, (q)->heap, (q)->map, (q)->size, \
+ (q)->ksz, aux, (q)->cmp); \
+ binheap_siftdown((q)->key, (q)->heap, (q)->map, (q)->size, \
+ (q)->ksz, aux, (q)->cmp); \
+ } \
+ q->heap[q->size] = ULONG_MAX; \
+ q->map[id] = ULONG_MAX; \
+} while (/*CONSTCOND*/0)
+
+#define BINHEAP_POP(q) do { \
+ register size_t aux = q->heap[0]; \
+ q->size--; \
+ binheap_exchange((q)->heap, (q)->map, (q)->size, 0); \
+ binheap_siftdown((q)->key, (q)->heap, (q)->map, (q)->size, \
+ (q)->ksz, 0, (q)->cmp); \
+ q->heap[q->size] = ULONG_MAX; \
+ q->map[aux] = ULONG_MAX; \
+} while (/*CONSTCOND*/0)
+
+#define BINHEAP_MAKE(q, n) do { \
+ (q)->size = (n); \
+ binheap_make((q)->key, (q)->heap, (q)->map, \
+ (q)->size, (q)->ksz, (q)->cmp); \
+} while (/*CONSTCOND*/0)
+
+void binheap_exchange(size_t *heap, size_t *map, size_t i, size_t j);
+
+void binheap_make(void *key, size_t *heap, size_t *map, size_t n,
+ size_t size, int(*cmp)(const void *, const void *));
+
+void binheap_siftdown(void *key, size_t *heap, size_t *map, size_t n,
+ size_t size, size_t i, int(*cmp)(const void *, const void *));
+
+void binheap_siftup(void *key, size_t *heap, size_t *map, size_t n,
+ size_t size, size_t i, int(*cmp)(const void *, const void *));
+
+#endif /* _BINHEAP_H_ */
--- /dev/null
+/**
+ * @file hash.c
+ * @brief Implementacao basica de uma tabela de dispersao com
+ * resolucao por encadeamento linear.
+ */
+#include <stdlib.h>
+#include <string.h>
+
+#include "hash.h"
+
+/* Lista de primos auxiliar, tem de ser aumentada se precisarmos de
+ * guardar mais elementos. */
+#define PRIMES 7
+static int primes[PRIMES] = {16127, 34651, 68111, 131071, 260999, 524287, 999983};
+
+/**
+ * @brief Estrutura que representa a tabela de dispersao.
+ */
+struct SThash_s {
+ int N, M, p;
+ int (*hash)(const void *, int M);
+ void ** tab;
+};
+
+/**
+ * @brief Funcao que inicializa uma tabela de dispersao.
+ *
+ * @param 'hash' identifica a funcao de dispersao a utilizar nesta
+ * tabela de dispersao.
+ * @return Uma tabela de dispersao.
+ */
+SThash
+STinit(int (*hash)(const void *, int M))
+{
+ SThash st = malloc(sizeof(struct SThash_s));
+
+ st->N = st->p = 0;
+ st->M = primes[st->p];
+ st->hash = hash;
+
+ st->tab = malloc(st->M*sizeof(void *));
+ memset(st->tab, 0x0, st->M*sizeof(void *));
+
+ return st;
+}
+
+/**
+ * @brief Funcao que liberta a memoria associada a uma tabela de
+ * dipersao.
+ *
+ * @param 'h' identifica a tabela de dispersao a libertar.
+ */
+void
+STfree(SThash h)
+{
+ free(h->tab);
+ free(h);
+}
+
+/**
+ * @brief Funcao para procurar numa tabela de dispersao.
+ *
+ * @para 'h' identifica a tabela onde procurar.
+ * @param 'item' identifica o elemento a procurar.
+ * @param 'cmp' identifica a funcao de comparacao a utilizar.
+ *
+ * @return O elemento se existir, NULL caso contrario.
+ */
+void *
+STsearch(SThash h, void * item, int (*cmp)(const void *, const void *))
+{
+ int i = h->hash(item, h->M);
+
+ while (h->tab[i] != NULL)
+ if (cmp(item, h->tab[i]) == 0)
+ return h->tab[i];
+ else
+ i = (i+1) % h->M;
+
+ return NULL;
+}
+
+/**
+ * @brief Funcao para apagar numa tabela de dispersao.
+ *
+ * @para 'h' identifica a tabela onde apagar.
+ * @param 'item' identifica o elemento a apagar.
+ * @param 'cmp' identifica a funcao de comparacao a utilizar.
+ */
+void
+STdelete(SThash h, void * item, int (*cmp)(const void *, const void *))
+{
+ int j, i = h->hash(item, h->M);
+ void * v;
+
+ while (h->tab[i] != NULL)
+ if (cmp(item, h->tab[i]) == 0)
+ break;
+ else
+ i = (i+1) % h->M;
+
+ if (h->tab[i] == NULL) return;
+
+ h->tab[i] = NULL;
+
+ h->N--;
+ for (j = (i+1) % h->M; h->tab[j] != NULL; j = (j+1) % h->M, h->N--) {
+ v = h->tab[j];
+ h->tab[j] = NULL;
+ STinsert(h, v);
+ }
+}
+
+/**
+ * Funcao auxiliar que permitir aumentar o tamanho da tabela. Se nao
+ * for possivel (ver lista de primos em cima), o programa termina de
+ * imediato.
+ */
+static void
+STexpand(SThash h) {
+ int i;
+ void **t = h->tab;
+
+ if (++(h->p) >= PRIMES)
+ exit(1);
+
+ h->N = 0;
+ h->M = primes[h->p];
+ h->tab = malloc(h->M*sizeof(void *));
+ memset(h->tab, 0x0, h->M*sizeof(void *));
+ for (i = 0; i < primes[h->p - 1]; i++)
+ if (t[i] != NULL)
+ STinsert(h, t[i]);
+ free(t);
+}
+
+/**
+ * @brief Funcao para inserir numa tabela de dispersao.
+ *
+ * @para 'h' identifica a tabela onde inserir.
+ * @param 'item' identifica o elemento a inserir.
+ */
+void
+STinsert(SThash h, void * item) {
+ int i = h->hash(item, h->M);
+
+ while (h->tab[i] != NULL)
+ i = (i+1) % h->M;
+
+ h->tab[i] = item;
+
+ if (h->N++ > 0.6*h->M)
+ STexpand(h);
+}
+
--- /dev/null
+/**
+ * @file hash.h
+ * @brief Implementacao basica de uma tabela de dispersao com
+ * resolucao por encadeamento linear.
+ */
+#ifndef HASH_H
+#define HASH_H
+
+typedef struct SThash_s * SThash;
+
+SThash STinit(int (*hash)(const void *, int M));
+void STfree(SThash h);
+
+void * STsearch(SThash h, void * item, int (*cmp)(const void *, const void *));
+
+void STdelete(SThash h, void * item, int (*cmp)(const void *, const void *));
+void STinsert(SThash h, void * item);
+
+#endif
--- /dev/null
+/**
+ * @file list.c
+ * @brief Implementacao basica de uma lista circular.
+ */
+#include <stdlib.h>
+
+#include "list.h"
+
+/**
+ * @brief Funcao para insercao.
+ *
+ * @param 'head' identifica a cabeca da lista onde inserir.
+ * @param 'value' identifica o valor a inserir.
+ */
+void
+list_insert(link head, void * value)
+{
+ link node = (link) malloc(sizeof(struct node));
+ node->value = value;
+ node->next = head;
+ node->prev = head->prev;
+ head->prev->next = node;
+ head->prev = node;
+}
+
+/**
+ * @brief Funcao para mover um no' entre listas.
+ *
+ * ATENCAO: Nao verifica se o no' ja' faz parte da lista!
+ *
+ * @param 'head' identifica a cabeca da lista onde mover.
+ * @param 'node' identifica o no' a mover.
+ */
+void
+list_move(link head, link node)
+{
+ /* Remove */
+ node->prev->next = node->next;
+ node->next->prev = node->prev;
+
+ /* Add */
+ node->next = head;
+ node->prev = head->prev;
+ head->prev->next = node;
+ head->prev = node;
+}
+
+/**
+ * @brief Funcao para remover um no' da lista.
+ *
+ * Neste caso nao e' necessaria a cabeca da lista uma vez que estamos
+ * a utilizar listas duplamente ligadas.
+ *
+ * @param 'node' identifica o no' a mover.
+ */
+void
+list_delete(link node)
+{
+ node->prev->next = node->next;
+ node->next->prev = node->prev;
+ free(node);
+}
+
+/**
+ * @brief Funcao para libertar a memoria associada a uma lista.
+ *
+ * @param 'head' identifica a cabeca da lista a libertar.
+ * @param 'freevalue' identifica a funcao que liberta a memoria
+ * associada aos valores (pode ser NULL).
+ */
+void
+list_free(link head, void (*freevalue)(void *))
+{
+ link l = head->next, aux;
+
+ while (l != head) {
+ if (freevalue)
+ (*freevalue)(l->value);
+ aux = l;
+ l = l->next;
+ free(aux);
+ }
+}
+
--- /dev/null
+/**
+ * @file list.h
+ * @brief Implementacao basica de uma lista circular.
+ */
+#ifndef LIST_H
+#define LIST_H
+
+typedef struct node *link;
+
+struct node {
+ void * value;
+ struct node *next, *prev;
+};
+
+void list_insert(link head, void * value);
+void list_move(link head, link node);
+void list_delete(link node);
+void list_free(link head, void (*freevalue)(void *));
+
+#endif
--- /dev/null
+/**
+ * @file proj2.c
+ * @brief Implementacao do segundo projecto de IAED:
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "list.h"
+#include "hash.h"
+
+#define NPKG 5
+#define MINC 128
+
+/**
+ * @brief Estrutura que representa uma chamada.
+ */
+struct call {
+ unsigned long nr;
+ char *name, pkg;
+};
+
+/**
+ * Variaveis locais ao programa. A fila de prioridades e' representada
+ * por pq e consiste em NPKG listas ligadas. Utilizamos duas tabelas
+ * de dispersao, namehash e nrhash, respectivamente indexadas por nome
+ * e numero, para acelerar a procura nas listas.
+ */
+static struct node pq[NPKG];
+static SThash namehash;
+static SThash nrhash;
+
+/**
+ * Funcao para libertar a memoria associada a uma chamada.
+ */
+static void
+free_call(void * c) {
+ free(((struct call *) c)->name);
+ free(c);
+}
+
+/**
+ * Funcao auxiliar para ler nomes (ilimitados).
+ */
+static char *
+readname()
+{
+ size_t size = 0, i = 0;
+ char * name = NULL, c;
+
+ while ((c = getchar()) != ' ' && c != '\n') {
+ /* Verificar se existe ainda espaco livre. */
+ if (i >= size) {
+ size += MINC;
+ name = realloc(name, sizeof(char)*(size+1));
+ }
+
+ name[i++] = c;
+ }
+ name[i++] = '\0';
+ /* name = realloc(name, i*sizeof(char)); */
+
+ return name;
+}
+
+/**
+ * Funcao que compara dois nos das listas com base no numero de
+ * cliente associado.
+ */
+static int
+nrcmp(const void *pa, const void *pb)
+{
+ struct call * la = (struct call *) ((link) pa)->value;
+ struct call * lb = (struct call *) ((link) pb)->value;
+
+ if (la->nr < lb->nr)
+ return -1;
+ if (la->nr > lb->nr)
+ return 1;
+ return 0;
+}
+
+/**
+ * Funcao que compara dois nos das listas com base no nome de
+ * cliente associado.
+ */
+static int
+namecmp(const void *pa, const void *pb)
+{
+ struct call * la = (struct call *) ((link) pa)->value;
+ struct call * lb = (struct call *) ((link) pb)->value;
+
+ return strcmp(la->name, lb->name);
+}
+
+/**
+ * Funcao de dispersao para os nos das listas com base no numero de
+ * cliente associado.
+ */
+static int
+nrhashfun(const void *p, int M)
+{
+ return ((struct call *) ((link) p)->value)->nr % M;
+}
+
+/**
+ * Funcao de dispersao para os nos das listas com base no nome de
+ * cliente associado.
+ */
+static int
+namehashfun(const void *p, int M)
+{
+ char * v = ((struct call *) ((link) p)->value)->name;
+ int h = 0, a = 127;
+
+ for (; *v != '\0'; v++)
+ h = (a*h + *v) % M;
+ return h;
+}
+
+/**
+ * @brief Funcao main.
+ *
+ * @return Codigo de estado de saida do programa.
+ */
+int
+main(int argc, char * argv[])
+{
+ char cmd;
+ struct call * c, ctmp;
+ struct node ntmp;
+ link ltmp;
+ size_t i;
+
+ /* Inicializacao das filas e das tabelas de dispersao. */
+ memset(pq, 0x0, sizeof(struct node)*NPKG);
+ for (i = 0; i < NPKG; i++)
+ pq[i].next = pq[i].prev = &pq[i];
+ namehash = STinit(namehashfun);
+ nrhash = STinit(nrhashfun);
+
+ /* Processar comando. */
+ while ((cmd = getchar()) != 'x') {
+ switch (cmd) {
+ case 'a':
+ /* Nova chamada. */
+ c = malloc(sizeof(struct call));
+ getchar(); /* catch ' ' */
+ c->name = readname();
+ scanf("%lu", &c->nr);
+ scanf(" %c", &c->pkg);
+
+ getchar(); /* catch '\n' */
+
+ /* Inserir chamada na fila de espera. */
+ list_insert(&pq[c->pkg - 'A'], c);
+
+ /* Indexar o novo no adicionado 'a fila (lista duplamente
+ * ligada). */
+ STinsert(namehash, pq[c->pkg - 'A'].prev);
+ STinsert(nrhash, pq[c->pkg - 'A'].prev);
+ break;
+ case 'u':
+ /* Identificar cliente e guardar numa estrutura temporaria. */
+ scanf("%lu", &ctmp.nr);
+ scanf(" %c", &ctmp.pkg);
+
+ getchar(); /* catch '\n' */
+
+ /* Guardar chamada temporaria num no' tambem temporario. */
+ ntmp.value = &ctmp;
+
+ /* Procurar no' na tabela indexada por numero. */
+ ltmp = (link) STsearch(nrhash, &ntmp, nrcmp);
+
+ /* Verificar se existe de facto alteracao. */
+ if (ctmp.pkg != ((struct call *) ltmp->value)->pkg) {
+
+ /* Actualizar pacote. */
+ c = (struct call *) ltmp->value;
+ ((struct call *) ltmp->value)->pkg = ctmp.pkg;
+
+ /* Mover no' entre as filas. */
+ list_move(&pq[c->pkg - 'A'], ltmp);
+ }
+ break;
+ case 'l':
+ getchar(); /* catch '\n' */
+
+ /* Procurar proxima chamda. */
+ for (i = 0; i < NPKG && pq[i].next == &pq[i]; i++);
+
+ /* Se existir, imprimir informacao. */
+ if (i < NPKG) {
+ c = (struct call *) pq[i].next->value;
+ printf("%s %lu %c\n", c->name, c->nr, c->pkg);
+ } else /* NA caso contrario. */
+ printf("NA\n");
+ break;
+ case 'p':
+ getchar(); /* catch '\n' */
+ /* Procurar proxima chamada. */
+ for (i = 0; i < NPKG && pq[i].next == &pq[i]; i++);
+
+ /* Se existir, imprimir e apagar a chamada. */
+ if (i < NPKG) {
+ c = (struct call *) pq[i].next->value;
+ printf("%s %lu %c\n", c->name, c->nr, c->pkg);
+
+ /* Apagar em ambas as tabelas e na fila. */
+ STdelete(namehash, pq[i].next, namecmp);
+ STdelete(nrhash, pq[i].next, nrcmp);
+ list_delete(pq[i].next);
+
+ /* Libertar memoria associada 'a chamada. */
+ free_call(c);
+ } else /* NA caso contrario. */
+ printf("NA\n");
+ break;
+ case 'r':
+ getchar(); /* catch ' ' */
+
+ /* Identificar cliente e guardar em estruturas temporarias. */
+ ctmp.name = readname();
+ ntmp.value = &ctmp;
+
+ /* Procurar no' na tabela indexada por nome. */
+ ltmp = (link) STsearch(namehash, &ntmp, namecmp);
+ c = (struct call *) ltmp->value;
+
+ /* Apagar em ambas as tabelas e na fila. */
+ STdelete(namehash, ltmp, namecmp);
+ STdelete(nrhash, ltmp, nrcmp);
+ list_delete(ltmp);
+
+ /* Libertar memoria associada 'a chamada e ao nome temporario. */
+ free_call(c);
+ free(ctmp.name);
+ }
+ }
+
+ /* Libertar a memoria ainda alocada. */
+ STfree(namehash);
+ STfree(nrhash);
+ for (i = 0; i < NPKG; i++)
+ list_free(&pq[i], free_call);
+
+ return EXIT_SUCCESS;
+}
+
--- /dev/null
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <search.h>
+
+#include "list.h"
+
+#define NPKG 5
+#define MINC 128
+
+struct call {
+ unsigned long nr;
+ char *name, pkg;
+};
+
+static struct node pq[NPKG];
+static void * nameroot;
+static void * nrroot;
+
+static void
+free_call(void * c) {
+ free(((struct call *) c)->name);
+ free(c);
+}
+
+static void do_nothing(void * n) { }
+
+static char *
+readname()
+{
+ size_t size = MINC, i = 0;
+ char * name = malloc(sizeof(char)*MINC), c;
+
+ while ((c = getchar()) != ' ' && c != '\n') {
+ if (i >= size - 1) {
+ size += MINC;
+ name = realloc(name, sizeof(char)*size);
+ }
+ name[i++] = c;
+ }
+ name[i] = '\0';
+
+ return name;
+}
+
+static int
+nrcmp (const void *pa, const void *pb)
+{
+ struct call * la = (struct call *) ((link) pa)->value;
+ struct call * lb = (struct call *) ((link) pb)->value;
+
+ if (la->nr < lb->nr)
+ return -1;
+ if (la->nr > lb->nr)
+ return 1;
+ return 0;
+}
+
+static int
+namecmp(const void *pa, const void *pb)
+{
+ struct call * la = (struct call *) ((link) pa)->value;
+ struct call * lb = (struct call *) ((link) pb)->value;
+
+ return strcmp(la->name, lb->name);
+}
+
+int
+main(int argc, char * argv[])
+{
+ char cmd;
+ struct call * c, ctmp;
+ struct node ntmp;
+ link ltmp;
+ size_t i;
+
+ memset(pq, 0x0, sizeof(struct node)*NPKG);
+ for (i = 0; i < NPKG; i++)
+ pq[i].next = pq[i].prev = &pq[i];
+ nameroot = nrroot = NULL;
+
+ while ((cmd = getchar()) != 'x') {
+ switch (cmd) {
+ case 'a':
+ c = malloc(sizeof(struct call));
+ getchar(); /* catch ' ' */
+ c->name = readname();
+ scanf("%lu", &c->nr);
+ scanf(" %c", &c->pkg);
+ getchar(); /* catch '\n' */
+ list_insert(&pq[c->pkg - 'A'], c);
+ tsearch(pq[c->pkg - 'A'].prev, &nameroot, namecmp);
+ tsearch(pq[c->pkg - 'A'].prev, &nrroot, nrcmp);
+ break;
+ case 'u':
+ scanf("%lu", &ctmp.nr);
+ scanf(" %c", &ctmp.pkg);
+ getchar(); /* catch '\n' */
+ ntmp.value = &ctmp;
+ ltmp = *((link*) tfind(&ntmp, &nrroot, nrcmp));
+ if (ctmp.pkg != ((struct call *) ltmp->value)->pkg) {
+ c = (struct call *) ltmp->value;
+ ((struct call *) ltmp->value)->pkg = ctmp.pkg;
+ list_move(&pq[c->pkg - 'A'], ltmp);
+ }
+ break;
+ case 'l':
+ getchar(); /* catch '\n' */
+ for (i = 0; i < NPKG && pq[i].next == &pq[i]; i++);
+ if (i < NPKG) {
+ c = (struct call *) pq[i].next->value;
+ printf("%s %lu %c\n", c->name, c->nr, c->pkg);
+ } else
+ printf("NA\n");
+ break;
+ case 'p':
+ getchar(); /* catch '\n' */
+ for (i = 0; i < NPKG && pq[i].next == &pq[i]; i++);
+ if (i < NPKG) {
+ c = (struct call *) pq[i].next->value;
+ printf("%s %lu %c\n", c->name, c->nr, c->pkg);
+ tdelete(pq[i].next, &nameroot, namecmp);
+ tdelete(pq[i].next, &nrroot, nrcmp);
+ list_delete(pq[i].next);
+ free_call(c);
+ } else
+ printf("NA\n");
+ break;
+ case 'r':
+ getchar(); /* catch ' ' */
+ ctmp.name = readname();
+ ntmp.value = &ctmp;
+ /*fprintf(stderr, "ERROR: %s\n", ctmp.name);*/
+ ltmp = *((link *) tfind(&ntmp, &nameroot, namecmp));
+ c = (struct call *) ltmp->value;
+ tdelete(ltmp, &nameroot, namecmp);
+ tdelete(ltmp, &nrroot, nrcmp);
+ list_delete(ltmp);
+ free_call(c);
+ free(ctmp.name);
+ }
+ }
+
+ tdestroy(nameroot, do_nothing);
+ tdestroy(nrroot, do_nothing);
+ for (i = 0; i < NPKG; i++)
+ list_free(&pq[i], free_call);
+
+ return EXIT_SUCCESS;
+}
+
--- /dev/null
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <search.h>
+
+#include <assert.h>
+
+#include "binheap.h"
+
+#define MAXNAME 64
+#define MAXNUM 1000000000
+#define MAXPKG 5
+
+struct call {
+ unsigned long nr;
+ size_t time;
+ char *name, pkg;
+};
+
+static int alpha[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '_', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'};
+
+static struct call ** store;
+static size_t storei, time;
+static struct binheap * q;
+static void * nameroot;
+static void * nrroot;
+
+static void do_nothing(void * n) { }
+
+void
+*genname()
+{
+ size_t len = rand()%MAXNAME + 1, i;
+ char * name = malloc(sizeof(char)*(len+1));
+
+ name[0] = alpha[rand()%52];
+ for (i = 1; i < len; i++)
+ name[i] = alpha[rand()%63];
+ name[i] = '\0';
+
+ return name;
+}
+
+unsigned long
+gennum()
+{
+ return rand()%MAXNUM;
+}
+
+char
+genpkg()
+{
+ return 'A' + rand()%MAXPKG;
+}
+
+int
+callcmp(const void *ap, const void *bp)
+{
+ struct call * a = * (struct call **) ap;
+ struct call * b = * (struct call **) bp;
+
+ if (a->pkg < b->pkg)
+ return -1;
+ if (a->pkg > b->pkg)
+ return 1;
+
+ return a->time - b->time;
+}
+
+static int
+nrcmp (const void *pa, const void *pb)
+{
+ unsigned long la = (unsigned long) pa;
+ unsigned long lb = (unsigned long) pb;
+
+ if (la < lb)
+ return -1;
+ if (la > lb)
+ return 1;
+ return 0;
+}
+
+static int
+namecmp (const void *pa, const void *pb)
+{
+ return strcmp((char *) pa, (char *) pb);
+}
+
+int
+main(int argc, char * argv[])
+{
+ struct call * c;
+ int i, k, n, op, maxop;
+ char pkg;
+
+ if (argc != 4) {
+ fprintf(stderr, "Usage: %s <seed> <size> <maxop>\nseed\tsemente para o srand\nsize\ttamanho do teste\nmaxop\toperacoes a considerar, valores possiveis: 1, 2, 3, 4, 5\n", argv[0]);
+ return EXIT_FAILURE;
+ }
+ srand(atoi(argv[1]));
+ k = atoi(argv[2]);
+ maxop = atoi(argv[3]);
+
+ store = malloc(sizeof(struct call *)*2*k);
+ memset(store, 0x0, sizeof(struct call *)*2*k);
+ storei = time = 0;
+ nameroot = nrroot = NULL;
+
+ for (i = 0; i < k; i++) {
+ c = malloc(sizeof(struct call));
+ c->name = genname();
+ while (tfind(c->name, &nameroot, namecmp)) {
+ free(c->name);
+ c->name = genname();
+ }
+ tsearch(c->name, &nameroot, namecmp);
+
+ c->nr = gennum();
+ while (tfind((void *) c->nr, &nrroot, nrcmp))
+ c->nr = gennum();
+ tsearch((void *) c->nr, &nrroot, nrcmp);
+
+ c->pkg = genpkg();
+ c->time = time ++;
+ printf("a %s %lu %c\n", c->name, c->nr, c->pkg);
+ store[storei++] = c;
+ }
+
+ assert(k == storei);
+
+ BINHEAP_INIT(q, struct call *, store, 2*k, callcmp);
+ BINHEAP_MAKE(q, k);
+ assert(q->size == storei);
+
+ for (i = 0; i < k; i++) {
+ op = rand()%maxop;
+
+ switch (op) {
+ case 0:
+ c = malloc(sizeof(struct call));
+ c->name = genname();
+ while (tfind(c->name, &nameroot, namecmp)) {
+ free(c->name);
+ c->name = genname();
+ }
+ tsearch(c->name, &nameroot, namecmp);
+
+ c->nr = gennum();
+ while (tfind((void *) c->nr, &nrroot, nrcmp))
+ c->nr = gennum();
+ tsearch((void *) c->nr, &nrroot, nrcmp);
+
+ c->pkg = genpkg();
+ c->time = time ++;
+ printf("a %s %lu %c\n", c->name, c->nr, c->pkg);
+ store[storei++] = c;
+
+ BINHEAP_UPDATE(q, storei-1);
+ assert(q->size == storei);
+ break;
+ case 1:
+ printf("l\n");
+ break;
+ case 2:
+ printf("p\n");
+ n = BINHEAP_TOP(q);
+ BINHEAP_POP(q);
+ /* printf("\t%s %lu %c (%lu)\n", store[n]->name, store[n]->nr, store[n]->pkg, store[n]->time); */
+ tdelete(store[n]->name, &nameroot, namecmp);
+ tdelete((void *) store[n]->nr, &nrroot, nrcmp);
+ free(store[n]->name);
+ free(store[n]);
+ store[n] = NULL;
+ storei--;
+ if (storei != n) {
+ BINHEAP_DEL(q, storei);
+ store[n] = store[storei];
+ store[storei] = NULL;
+ BINHEAP_UPDATE(q, n);
+ }
+ assert(q->size == storei);
+ break;
+ case 3:
+ n = rand()%storei;
+ pkg = genpkg();
+ if (pkg != store[n]->pkg) {
+ store[n]->pkg = pkg;
+ store[n]->time = time ++;
+ printf("u %lu %c\n", store[n]->nr, store[n]->pkg);
+ BINHEAP_UPDATE(q, n);
+ assert(q->size == storei);
+ }
+ break;
+ case 4:
+ n = rand()%storei;
+ printf("r %s\n", store[n]->name);
+ BINHEAP_DEL(q, n);
+ tdelete(store[n]->name, &nameroot, namecmp);
+ tdelete((void *) store[n]->nr, &nrroot, nrcmp);
+ free(store[n]->name);
+ free(store[n]);
+ storei--;
+ if (storei != n) {
+ BINHEAP_DEL(q, storei);
+ store[n] = store[storei];
+ store[storei] = NULL;
+ BINHEAP_UPDATE(q, n);
+ }
+ assert(q->size == storei);
+ break;
+ }
+ }
+
+ printf("x\n");
+
+ BINHEAP_FREE(q);
+ for (i = 0; i < storei; i++) {
+ free(store[i]->name);
+ free(store[i]);
+ }
+ free(store);
+ tdestroy(nameroot, do_nothing);
+ tdestroy(nrroot, do_nothing);
+
+ return EXIT_SUCCESS;
+}
+