#include <stdio.h>

struct student {
	char nachname[25];
	char vorname[25];
	char gebdatum[11];
	int matrnr;
	short gruppe;
	char best;
};

struct eintrag {
	struct student stud;
	struct eintrag *naechster;
};

int eintrag_lesen(struct student *);
struct eintrag *einfuegepos_suchen(struct eintrag *, struct eintrag *);
int liste_anzeigen(struct eintrag *);

main () 
{
	struct eintrag leer = { {"", "" }, NULL};		/* Struktur mit leeren Namen und NULL-Zeiger */

	struct eintrag *stud_liste = &leer;			/* Zeiger auf Listen-Anfang, als erstes Listen-Element immer ein "leer" */
	struct eintrag *akt_eintrag;				/* aktuell bearbeiteter Eintrag */
	struct eintrag *einfuege_pos;				/* Einfuegeposition */


	/* erstes Listen-Element anfordern und Listen-Anfang drauf zeigen lassen */
	akt_eintrag = (struct eintrag *)malloc(sizeof (struct eintrag));

	while (eintrag_lesen(&akt_eintrag->stud) != EOF ) {

		/* Eintrag, hinter dem einzufügen ist suchen */
		einfuege_pos = einfuegepos_suchen(stud_liste, akt_eintrag);

		/* akt_eintrag hinter einfuege_pos einketten */
		akt_eintrag->naechster = einfuege_pos->naechster;
		einfuege_pos->naechster = akt_eintrag;

		/* neues Listen-Element anfordern */
		akt_eintrag = (struct eintrag *)malloc(sizeof (struct eintrag)); 
	}
	liste_anzeigen(stud_liste);
}

struct eintrag *einfuegepos_suchen(struct eintrag *liste, struct eintrag *neuer_eintrag) {
	/* mit Zeiger "liste" durch die verkettete Liste laufen und in jedem
	   Listeneintrag den Nachnamen mit dem Namen im neuen Eintrag vergleichen.
	   Jeweils Zeiger auf den vorherigen Listeneintrag merken.
	   Sobald der Vergleich (Funktion strcmp) anzeigt, dass der Name im neuen
	   Eintrag lexikalisch vor dem aktuellen Listeneintrag liegt, wird der
	   gemerkte Zeiger auf den davorliegenden Eintrag zurueckgegeben.
	   Der leere Eintrag am Anfang liegt lexikalisch vor allem anderen -
	   Eintraege sind also immer garantiert erst dahinter!
	   Wenn das Listenende erreicht wird, wird der Zeiger auf das bisher letzte
	   Listenelement zurueckgegeben (damit wird der neue Eintrag ganz hinten
	   angehaengt).
	*/
	struct eintrag *vorheriger;
	do {
		vorheriger = liste;
		liste = liste->naechster;
		if ( liste == NULL ) break;	/* Listenende erreicht */
	} while(strcmp(liste->stud.nachname, neuer_eintrag->stud.nachname) < 0);

	return(vorheriger);
}
	
int eintrag_lesen(struct student *stud) {
	printf("Datensatz eingeben\n");
	printf("Nachname: ");
	if (scanf("%24s", stud->nachname) < 1) return (EOF);
	printf("Vorname: ");
	scanf("%24s", stud->vorname);
	printf("Geburtsdatum [Format tt.mm.jj] / Matrikelnr. / Gruppe:");
	scanf("%10s / %d / %hd", stud->gebdatum, &stud->matrnr, &stud->gruppe);
	printf("\n");

	/* ein ordentliches Programm muesste natuerlich bei jedem
	   scanf abpruefen, ob die richtige Anzahl an Parametern eingelesen wurde,
	   das Geburtsdatum und die Matrikelnummer muessten auf Plausibilitaet geprueft
	   werden, und und und...
	*/
	return(1);
}

int liste_anzeigen(struct eintrag *liste) {

	/* leeren Eintrag am Anfang ueberspringen */
	liste = liste->naechster;

	while (liste != NULL) {
		printf("%s, %s, %s, %d, %d\n", 
			liste->stud.nachname, liste->stud.vorname, 
			liste->stud.gebdatum, 
			liste->stud.matrnr, liste->stud.gruppe);

		liste=liste->naechster;
	}
		
}

