// Systemnahe Software (II) im SS 2009 // Musterloesung fuer Aufgabe 4 von Blatt 1 // Michael Mattes, 26.04.2009 // Sprache: C nach dem C99-Standard mit GNU-Extensions, // mit gcc zu uebersetzen mit Flag -std=gnu99 // Der Kommentar hinter jedem #include gibt an, fuer welche Funktion das // #include hier genutzt wird. #include // open #include // open #include // open #include // perror, fprintf #include // exit, malloc/calloc #include // close #include // cftime (ist optional) // Die Struktur, wie sie von der Aufgabe vorgegeben wird. struct messung { unsigned int zeit; float temp; short station; char kurz[2]; struct messung *next; }; int main(int argc, char *argv[]) { int fd; // unser Filehandle // Versuche, die Datei lesend zu oeffnen // Programmierstil 1: Zuweisung und Fehlerabfrage in einem if(( fd=open("messung.dat", O_RDONLY) ) < 0) { // Oeffnen fehlgeschlagen perror("open"); // Da wir in der main()-Funktion sind, wuerde hier auch return 1; klappen exit(1); // Mit exit ist es aber immer moeglich } ssize_t bytes_gelesen; // die Anzahl der mit read() gelesenen Bytes char puffer[100]; // der Puffer fuer eine Messung und weitere Sachen char *pb; // ein allgemeiner Zeiger auf einzelne Bytes ssize_t puffer_pos = 0; // unsere Position im Puffer struct messung *p; // ein allgemeiner Zeiger auf einen Datensatz struct messung *anfang; // der Anfang der Liste struct messung *letztes; // das letzte gueltige Element der Liste // Initialisiere die Liste p = calloc(1, sizeof(*p)); // oder malloc(1*sizeof(*p)), da ausnullen egal anfang = NULL; letztes = NULL; // Endlosschleife, kann mit break verlassen werden. Alternativ // geht auch while(1) { ... } for(;;) { puffer_pos = 0; // Lies den naechsten Datensatz while(puffer_pos<12) { // Programmierstil 2: Getrennte Fehlerabfrage bytes_gelesen = read(fd, &puffer+puffer_pos, 12-puffer_pos); if(bytes_gelesen<0) { perror("read"); exit(1); } else if(bytes_gelesen == 0) { // Weder O_NONBLOCK noch O_NDELAY sind beim Oeffnen der Datei // gesetzt worden, also bedeutet Rueckgabewert 0 das Ende der Datei break; } puffer_pos += bytes_gelesen; } // Jetzt muesste puffer_pos entweder 0 oder 12 sein, sonst ist die Datei // falsch/beschaedigt if(puffer_pos == 12) { // "Zerhacke" den Strukturzeiger in einzelne Bytes pb = (char*)p; // Kopiere den Puffer byteweise in die Struktur: for(int i=0; i<12; ++i) { *(pb+i) = *(puffer+i); } // Liste um eins vergroessern if(anfang == NULL) { anfang = p; } letztes = p; p = calloc(1, sizeof(*p)); p->next = NULL; letztes->next = p; } else if(puffer_pos == 0) { // Kein Element ist dazugekommen, also verwerfen wir den Puffer und // verlassen die Leseschleife if(letztes != NULL) { letztes->next = NULL; } break; } else { fprintf(stderr, "Ohnoez! Habe %d Bytes bekommen, aber 0 oder 12 erwartet. Verwerfe Datensatz.\n", puffer_pos); if(letztes != NULL) { letztes->next = NULL; } break; } } // Lesen beendet, schliesse Datei close(fd); // Unsere Liste ist nun fertig. Jetzt geben wir sie aus: for(p=anfang; p!=NULL; p=p->next) { // Bonus: Wir interpretieren den Zeitstempel als lesbares Datum. // Dafuer verwenden wir nun den Puffer wieder. // ACHTUNG unsicher: Buffer overflow, wenn cftime mehr als 99 Zeichen // in puffer einfuegt. cftime((char*)&puffer, (char*)NULL, (const time_t*)&(p->zeit)); // Eigentliche Ausgabe printf("%d (%s); Temp. %02.2f; Station %c%c (%d)\n", p->zeit, (char*)&puffer, p->temp, p->kurz[0], p->kurz[1], p->station); } // Alles fertig return 0; }