/*
* Fußnotensortierprogramm optimiert auf die Aufgabe aus dem Linux-Magazin
* Ausgabe 10/08 Seite 30ff
*
* Beschränkungen: max. 2^32 Fußnoten, größte max. Nummerierung: 2^32.
* Je nach Vorsortierung max. 2^32 bytes Fußnoten oder mehr,
* bzw. beschränkt durch RAM.
*
* Funktionsweise:
* Gelesen wird von stdin, ausgegeben auf stdout. Es gibt keine Hilfe oder
* sonstige sinnvolle Ausgaben.
*
* Ich bin kein Programmierer und daher... öhm, sieht der Code
* etwas Grauenhaft aus?? k.A.
* Nach fast einem Tag Arbeit (ich wollte halt nur mal ein wenig C lernen, da
* war mir das ganze hier Recht) hab ich jetzt auch keine Lust mehr, nochmal
* drüberzugucken und noch Teile in Funktionen auszulagern etc.
*
* Meinen Teil hab ich mal (denke ich) auf geringen Speicherverbrauch
* optimiert. Daher Langsamer durch häufiges freigeben
* auch kleiner nicht benötigter Speicherbereiche(?). Speicherverbrauch ohne
* b-Baum(*altzuneu) im ungünstigsten Fall etwas mehr als der untere Teil der
* Eingabedatei, oder?
* Die Verwendete btree Implementierung ist nicht von mir und daher u.U.
* deutlich Speicherintensiver. k.A., hab keine Lust mehr noch selber was zu
* implementieren ;-)
*
* Lizenz dieser Datei: Public Domain
* Lizenz btree.c und btree.h: GPL v2.
*
* BUGs: Ich nutze eine btree-implementierung, die ich auf der LKML gefunden
* habe. Diese steht unter der GPL v2. Ich musste eine Zeile hinzufügen,
* da diese sonst nachvollziehbar Segfaults bei btree_search() lieferte.
*
* Wenn im Text irgendwo ein [XXX] auftaucht, wo XXX eine beliebige Zahl
* ist, aber [XXX] keinen Verweis auf eine Fußnote darstellt, wird dafür
* ein Verweis angelegt (die Zahl XXX also geändert), und in der
* Fußnotenliste dafür die originale Zahl wieder angegeben.
*/
//globale Variablen
int alloziierterspeicher = 0;
int *neuzualt; //flacher speicher für mapping neu->alt
int laufendenummer = 0;
btree *altzuneu; //btree für mapping alt->neu
char **fussnoten;
//funktionen für die btree-lib
unsigned int value(void * key)
{
return *(int *)key;
}
unsigned int keysize(void * key)
{
return sizeof(int);
}
unsigned int datasize(void * data)
{
return sizeof(int);
}
/*
* fehler ausgeben und programm beenden
*/
fehler(char * fehlermeldung)
{
printf(fehlermeldung);
exit(1);
}
/*
* Es wurde eine Fußnote im Text gefunden. Diese sollte eine neue Nummer
* bekommen und in die Korrespondenztabelle der alten eingefügt werden.
*/
int fn_einfuegen(char* altenummer_s)
{
int altenummer,i,neuenummer;
bt_key_val * kv = NULL;
//falls Speicher knapp wird, neuen alloziieren.
if (alloziierterspeicher<(laufendenummer+1))
{
if (alloziierterspeicher==0)
{
neuzualt=(int *)malloc(64*sizeof(int));
if (neuzualt==NULL) fehler("malloc: zu wenig speicher");
alloziierterspeicher=64;
}
else
{
alloziierterspeicher=alloziierterspeicher+(alloziierterspeicher);
neuzualt=(int *)
realloc(neuzualt,alloziierterspeicher*sizeof(int));
if (neuzualt==NULL) fehler("realloc: zu wenig speicher");
}
}
altenummer = atoi(altenummer_s);
//alte nummer schon aufgetreten?
if (laufendenummer>0)
{
kv = btree_search(altzuneu, &altenummer);
}
if (kv!=NULL)
{ //schon da -> vorhandene neue ausgeben
return *(int *) kv->val;
}
else
{ //noch nicht da -> anfügen
neuenummer = ++laufendenummer;
kv = (bt_key_val*)malloc(sizeof(*kv));
kv->key = malloc(sizeof(int));
*(int *)kv->key = altenummer;
kv->val = malloc(sizeof(int));
*(int *)kv->val = neuenummer;
btree_insert_key(altzuneu,kv);
/*
* Eine Klammer wurde im Text erkannt. Nun wird geprüft, ob dies auch eine
* Fußnote ist und diese ggf. aufgenommen.
*/
void klammer_im_text()
{
char fussnotennummer[10];
int i = 0, neuenummer; char c;
c=getchar();
while (c>=48 && c<=57 && i<10)
{
fussnotennummer[i]=c;
i++;
c=getchar();
}
fussnotennummer[i]=0;
if (c==93 && i>0)
{
neuenummer = fn_einfuegen(fussnotennummer);
printf("[%i]",neuenummer);
return; //neue Nummer eingefügt und ausgegeben.
}
// ist keine Fußnote, der hier eingelesene Text wird ausgegeben
printf("[%s",fussnotennummer);
putchar(c);
}
int fussnoten_folgen()
{
char trenntext[10] = "footnotes:";
char c; int i,j;
for (i=0; i<10; i++)
{
c=getchar();
if (c!=trenntext[i])
{
putchar('@');
for (j=0; j<i; j++)
putchar(trenntext[j]);
putchar(c);
return 0;
}
}
return 1;
}
int main()
{
char c;
int i,infussnote=0,altenummer,aktuellefussnotenmaxlaenge=0;
int aktuellefussnote=0,aktuellefussnotenlaenge=0,maxausgegebenefn=0;
char fussnotennummer[10];
bt_key_val * kv; //für btree_search
//ab hier der obere Teil (Textmodus)
while ((c=getchar())!=EOF)
{
if (c==91) klammer_im_text();
else if (c==64) {if (fussnoten_folgen()) break;}
else putchar(c);
}
//neuzualt-Speicher aufs nötigte schrumpfen
neuzualt=(int *)realloc(neuzualt,laufendenummer*sizeof(int));
//Speicher für die Zeiger auf die Fußnoten alloziieren.
fussnoten=(char **)malloc(laufendenummer*sizeof(char*));
//TODO:hier wird 1*sizeof(int) verschenkt, da fussnoten[0] nie vorkommen wird
//ab hier der untere Teil (Fußnotenmodus)
printf("@footnotes:");
alloziierterspeicher = 0;
while ((c=getchar())!=EOF)
{
if (c==91)
{
i=0;
c=getchar();
while (c>=48 && c<=57 && i<10)
{
fussnotennummer[i]=c;
i++;
c=getchar();
}
fussnotennummer[i]=0;
if (c==93 && i>0) //fussnotenanfang gefunden
{
if (aktuellefussnote) //string beenden
fussnoten[aktuellefussnote][aktuellefussnotenlaenge++]=0;
if (aktuellefussnotenmaxlaenge>aktuellefussnotenlaenge
&& aktuellefussnote) //TODO: schrumpfen könnte man auch nach ausg.
{ //platz für alte fußnote zurechtschrumpfen
fussnoten[aktuellefussnote]=(char *)realloc(
fussnoten[aktuellefussnote],aktuellefussnotenlaenge*sizeof(char));
}
//prüfen, ob vor dieser fn schon alle anderen ausgegeben wurden
if (maxausgegebenefn==aktuellefussnote-1)
{ //ja, es können weitere fussnoten ausgegeben werden
while (fussnoten[aktuellefussnote])
{
printf("[%i]%s",aktuellefussnote,fussnoten[aktuellefussnote]);
free(fussnoten[aktuellefussnote]);
fussnoten[aktuellefussnote]=NULL;
maxausgegebenefn++;
aktuellefussnote++;
}
}
aktuellefussnotenlaenge=0;
aktuellefussnotenmaxlaenge=0;
altenummer = atoi(fussnotennummer);
kv = btree_search(altzuneu, &altenummer);
if (kv==NULL)
{
printf("[unreferenziert]");
aktuellefussnote = 0;
} else //kv!=NULL
{
aktuellefussnote = *(int *) kv->val;
}
} else
{
//TODO: schon gelesene nicht-fußnoten-nummer wieder ausgeben
printf("TODO");
}
}
else if (aktuellefussnote)
{ //in fussnote: gelesenes zeichen laden
if (aktuellefussnotenmaxlaenge==0)
{
aktuellefussnotenmaxlaenge=256;
fussnoten[aktuellefussnote]=(char *)
malloc(aktuellefussnotenmaxlaenge*sizeof(char));
} else if (aktuellefussnotenmaxlaenge<aktuellefussnotenlaenge+1)
{
aktuellefussnotenmaxlaenge=aktuellefussnotenmaxlaenge+256;
fussnoten[aktuellefussnote]=(char *) realloc(
fussnoten[aktuellefussnote],aktuellefussnotenmaxlaenge*sizeof(char));
}
fussnoten[aktuellefussnote][aktuellefussnotenlaenge]=c;
aktuellefussnotenlaenge++;
}
else putchar(c); //wenn nicht in einer referenzierten Fußnote
}
if (aktuellefussnote) //string beenden
fussnoten[aktuellefussnote][aktuellefussnotenlaenge++]=0;
for (i=maxausgegebenefn+1;i<=laufendenummer;i++)
if (fussnoten[i]==NULL)
printf("[%i] Alte Zahl: %i\n",i,neuzualt[i]);
else
printf("[%i]%s",i,fussnoten[i]);