#define _XOPEN_SOURCE 500 #include #include #include #include /* Makron */ #define NAMEMAXLENGTH 30 /* Globala variabler så att de är tillgängliga både från main() och de övriga funktionerna. struct myData används t.ex. både från main() och new() */ struct myData { char name[NAMEMAXLENGTH]; int quantity; float price; }; char filename[] = "storage.bin"; /* Funktionsprototyper */ void list(struct myData *datap, int numRec); void search(struct myData *datap, int numRec, char *name); void modify(struct myData *datap, int numRec, char *name); void delete(struct myData *datap, int numRec, char *name); int new(struct myData *datap, int numRec); void printUsage(char *arg); void printHeader(void); int main(int argc, char* argv[]) { FILE *fp; /* Filpekare */ int newart = 0; /* Ska vi skapa en ny artikel? */ int numRec; /* För antalet för artiklar */ int create; /* För y/n-fråga */ int opt; /* För getopt() */ /* Skapa en strukturvariabel (en pekare) av struct myData */ struct myData *data; /* Skriv ut hjälptexten och returnera 1 om vi saknar argument */ if (argc < 2) { printUsage(argv[0]); return 1; } /* Kontrollera om filen finns och är läs- och skrivbar. Om inte, fråga om vi ska skapa den och börja läsa in artiklar. access() är ett systemanrop för UNIX-miljöer */ if ( access(filename, R_OK|W_OK) != 0 ) { /* Använd fprintf() för att skriva felmeddelanden till stderr */ fprintf(stderr, "Could not open %s\n", filename); printf("Create the file and start adding records? (y/n): "); create = getchar(); if ( create == 'y' ) { /* Allokera minne för en struct myData och anropa sedan new() med en pekare till minnet för att lägga till artiklar i lagret, en i taget */ numRec = 1; data = calloc(numRec, sizeof(struct myData)); new(data, numRec); free(data); return 0; } else return 1; } /* Öppna filen i läsläge */ fp = fopen(filename, "rb"); /* Läs in befintlig data från filen till strukturen */ fseek(fp, 0, SEEK_END); numRec = ftell(fp) / sizeof(struct myData); data = calloc(numRec, sizeof(struct myData)); rewind(fp); fread(data, sizeof(struct myData), numRec, fp); fclose(fp); /* Behandla argumenten med getopt() */ while ((opt = getopt(argc, argv, "hls:m:d:n")) != -1) { switch (opt) { case 'l': list(data, numRec); break; case 's': search(data, numRec, optarg); break; case 'm': modify(data, numRec, optarg); break; case 'd': delete(data, numRec, optarg); break; case 'n': newart = 1; break; case 'h': printUsage(argv[0]); return 0; default: printUsage(argv[0]); return 1; } } /* Fortsätt här om filen finns och vi valde att lägga till artiklar */ if ( newart == 1 ) { data = calloc(1, sizeof(struct myData)); if ( new(data, numRec) == 1 ) return 1; } /* Här är programmet klart, så frigör minnet och returnera 0 */ free(data); return 0; } /* Funktionerna nedan tar en pekare till datatypen struct myData som första argument. Som andra argument ett heltal som innehåller antalet artiklar i lagret. */ void list(struct myData *datap, int numRec) { int i; printHeader(); for (i = 0; iname, NAMEMAXLENGTH, stdin); datap->name[strcspn(datap->name, "\n")] = '\0'; if ( strcmp(datap->name, "done") == 0 ) { fclose(fp); return 0; } printf("Quantity: "); scanf("%d", &datap->quantity); printf("Price: "); scanf("%f", &datap->price); bytes = fwrite(datap, sizeof(struct myData), 1, fp); if (bytes != 1) { fprintf(stderr, "Could not write to the file!\n"); return 1; } } } void printUsage(char *arg) { fprintf(stderr, "Usage: %s [-l] [-s name] " "[-m name] \n" "[-d name] [-n] [-h]\n\n" "-l = list the articles in the database\n" "-s name = search for an article named 'name' in the database\n" "-m name = modify the article named 'name' in the database\n" " You'll then have the choice to change name, quantity " "and price.\n" "-d name = delete the article named 'name'\n" "-n = create new articles (interactive mode only)\n" "-h = display this help message\n", arg); } void printHeader(void) { int i; printf("\n%-30s\t", "Name"); printf("%s\t", "Quantity"); printf("%s\t\n", "Price"); for (i = 0; i<=52; i++) printf("="); printf("\n"); }