// A simple database to demonstrate all the parts you have learned // and may be of some real world use for you depending on how you rewrite it // database.c // K. J. Rock // November 11, 2018 // for Bacona Design LLC #include "database.h" int id = 42; // guard id number for unique values // working functions void addRecord(int); // add record manually int save(void); // needs work to use any filename instead of myList.dat int read(void); // reads myList.dat and no others int print(void); // prints all fields of all records void sort(int); // added sorting field choice void swap(struct node *, struct node *); // helper function for sort routine int deleteID(int); // wrapper function void deleteNode(struct node *); int printRecord(struct node *); // standard print format struct node * newNode(void); struct data * newData(void); int testTime(void); int ttesting(void); int tInfo(void); int dayWeek(void); int secs(void); // functions needing work int report(void); // initial attempt at filtering on a field value int find(int); // helper function // random data generators void getName(void); // get name from women.txt or men.txt struct data *newRandomData(void); // create random data for node void addNode(int); // add new node with randomly generated data int main(void) { int choice; char filename[128]; // myList.dat now int loop = 1; // loop until this becomes a zero int num = 1; // for random record creation counter int idx = 0; // id choice for delete function char *firstName; // holder for name from man[] or woman[] arrays char *sName, *tName; // extras char *p, *r, *t; // working pointers instead of those lazy kind char *word; // instantiate a list here head = NULL; // empty list state tail = NULL; // these guard values are necessary. at least for head srand((unsigned) time(NULL)); // randomize seed from time getName(); // get lists of 100 men's and 100 women's first names while (loop) // our forever loop { // with a bit of old fashioned command line UI printf("\n"); printf("\t Menu\n"); printf("1) Add a record\n"); // records?? in sub menu printf("2) Edit a record\n"); printf("3) Delete a record\n"); printf("\n"); printf("4) Print all fields of all records\n"); printf("5) Print a report\n"); printf("6) Sort on key\n"); printf("\n"); printf("7) Read file\n"); // ask for file name printf("8) Save records\n"); // ask for file name printf("9) Exit\n"); printf("\n"); printf("11) Find a record\n"); // keep these as hidden choices // make sure they work so you can use them for testing purposes // but don't expose them to the public, it will be our little secret. /* printf("19) Fiddle with strings\n"); printf("23) Display file statistics\n"); printf("27) Ask for a filename\n"); printf("31) Add random record(s)\n"); */ // printf("24) What time is it?\n"); printf("\n"); printf(" Please make your choice => "); // need to change to sscanf() so I can trap for non-numeric characters if (scanf(" %d", &choice)) // space before d sets ignore white spaces flag printf("Your choice was #%d\n\n", choice); switch (choice) { case 1: // add record // make enter default to one record at a time printf("How many records will you add => "); if (scanf(" %d", &num)) printf("Your choice was #%d\n\n", num); addRecord(num); break; case 2: // edit record printf("edit is not implemented yet\n"); // add code to find a certain record // which will work for case 6 too // once you have found a record you can edit or delete it. // to edit you need to add menu structure after you have displayed your choice // pick a field and go to the data entry routine for that field. // Our search will be based on id // find a group of records matching certain criteria // but reference each individual by their unique id break; case 3: // delete record // run find() to get a list with the proper attributes // once you have the unique id // scan list for that record // then you can delete *here find(1); // 1 signifies id field printf("Delete which id => "); if (scanf(" %d", &idx)) ; deleteID(idx); // then call delete( *here of id number ) // translates id number into its memory location then deletes that node break; case 4: // print all print(); // print all fields of all records // need to be able to pass ep to print so you can // print a single record // needs to be a function because it // could factor out of many places break; case 5: // print some // needs work to choose report criteria(on) // related to find report(); break; case 6: // sort printf("\n"); printf("\t Menu\n"); printf("1) Use id as key\n"); // printf("x) Use name as key\n"); printf("2) Use age as key\n"); printf("3) Use salary as key\n"); printf("4) Use seniority as key\n"); printf("\t Reverse\n"); printf("5) Use id as key, largest to smallest\n"); printf("6) Use age as key, reverse\n"); printf("7) Use salary as key, backwards\n"); printf("8) Use seniority as key, old to young\n"); printf("9) Use name as key, from z to a\n"); printf(" Please make your choice => "); if (scanf(" %d", &choice)) ; sort(choice); break; case 7: // read file read(); break; case 8: // write file save(); break; case 9: // exit app loop = 0; // flag to drop out of menu loop break; case 11: // find record(s) helper function printf("\n"); printf("\t Menu\n"); printf("1) Use id as key\n"); printf("2) Use name as key\n"); printf("3) Use age as key\n"); printf("4) Use salary as key\n"); printf("5) Use seniority as key\n"); /* printf(" Reverse\n"); printf("5) Use id as key, largest to smallest\n"); printf("6) Use age as key, reverse\n"); printf("7) Use salary as key, backwards\n"); printf("8) Use seniority as key, old to young\n"); */ printf(" Please make your choice => "); if (scanf(" %d", &num)) ; //if (num > 1) { printf("only id works for now\n"); num = 1; } find(num); break; case 19: // fiddle with strings // char *sName, *tName, *p, *t; // non-lazy pointers firstName = (char *) malloc(strlen(woman[6])); // this segment works OK for (int i = 0; i <= (int) strlen(woman[6]); i++) *(firstName + i) = *(woman[6] + i); printf("%s\n", firstName); // this routine does not change the address of fName sName = (char *) malloc(strlen(woman[21])); // allocate space tName = (char *) woman[21];// point tName at first char of woman[21] printf("tName => %p %c %s\n", tName, *tName, tName); // print address, initial, name t = sName; // point at the start while ((*(sName++) = *(tName++))) ; // this routine modifies both pointers sName = t; // reset the address printf("$2 %s\n", sName); p = (char *) malloc(50); printf("a %p\n", p); t = (char *) malloc(strlen(woman[93])); t = woman[93]; r = p; // points at the beginning of your new memory space while ((*(p++) = *(t++))) ; printf("b %p\n", p); // Indy, they’re looking in the wrong place!!! p = r; // reset pointer back to beginning of memory space printf("|4| %s | %s |\n", p, woman[93]); word = (char *) malloc(sizeof(char) * 35); // space for largish word memset(word, '\0', sizeof(char) * 35); printf("What's the word? => "); if (scanf(" %s", word)) ; //puts(word); printf("|#%s#|\n", word); r = p; // remember beginning of string while ((*(p++) = *(word++))) ; p = r; // recover beginning of string printf("*/%s/*\n", p); printf("***************\n"); /* if ((ep=head)) ; else printf("no list in memory\n"); while (ep) { idx = rand() % 200; if (idx > 100) t = man[idx-100]; else t = woman[idx]; ep->data->name = (char *) malloc(strlen(t)); p = ep->data->name; while ((*(p++) = *(t++))) ; ep = ep->next; } print(); */ break; case 23: // display list/report statistics printf("display statistics is not implemented yet\n"); // total payroll, average pay // average age // // have statistics function for reports too // count would be nice for reports // how many found, how many fit criteria break; case 24: // test the time functions of testTime(); break; case 27: // helper function // ask for a file name printf("Please give me the name of your list => "); if (scanf(" %s", filename)) ; puts(filename); break; case 31: // generate random records printf("How many new records should I add?\n"); printf("Please make your choice => "); // need to change to sscanf() so I can trap for non-numeric characters if (scanf(" %d", &num)) printf("Your choice was #%d\n\n", num); addNode(num); // was for adding random records break; } } } //////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////// // get name from women.txt or men.txt void getName(void) { FILE *fp = NULL; // guard value fp = fopen("men.txt", "r"); // open file for read if (fp != NULL) { for (int i = 0; i < 100; i++) { if (fscanf(fp, "%s", str)) ; // read string into str[] array if (fscanf(fp, "%d", &dummy)) ; // eats rank which is not used here s = (char *) malloc(strlen(str)); // allocate memory for new string man[i] = s; // point array at memory space s[0] = str[0]; // copy first letter unchanged for (int j = 1; j < (int) strlen(str); j++)// skip first letter to maintain case s[j] = str[j] + 32; // offset to lower case s[strlen(str)] = '\0'; // terminate string } fclose(fp); } fp = fopen("women.txt", "r"); if (fp != NULL) { for (int i = 0; i < 100; i++) { if (fscanf(fp, "%s", str)) ; // read string into str[] array if (fscanf(fp, "%d", &dummy)) ; // eats rank which is unused s = (char *) malloc(strlen(str)); // allocate space for string woman[i] = s; // point woman array at new string space s[0] = str[0]; // set pointer s to first char of name string for (int j = 1; j < (int) strlen(str); j++) s[j] = str[j] + 32; // change to lower case s[strlen(str)] = '\0'; // terminate string } fclose(fp); } } //////////////////////////////////////////////////////////////////////// // Remo Williams: Do you always talk like a Chinese fortune cookie? // // [Outraged, Chiun strikes Remo in his solar plexus. // // Remo stumbles to the window, // // partially paralyzed, and in pain] // // Chiun: Chinese! *Korean* is the most perfect creature ever // // to sanctify the earth with the imprint of its foot. // //////////////////////////////////////////////////////////////////////// struct data * newRandomData(void) { struct data *myData; int i = 42; // our founder holds id #42 to honor Douglas Adams myData = (struct data *) malloc(sizeof(struct data)); myData->id = ++i; myData->age = rand() % 50 + 20; myData->salary = (float) (rand() % 95000 + 30000); myData->seniority = rand() % 45; return (myData); } void addNode(int num) { struct node *myNode; for (int i = 0; i < num; i++) { myNode = (struct node *) malloc(sizeof(struct node)); // create new node myNode->data = newRandomData(); // add data to our new node if (head == NULL) // empty list case { head = myNode; myNode->next = NULL; } else // non-empty list { tail->next = myNode; myNode->prev = tail; } tail = myNode; } } // Parker, on the prom at Harvard University: "If all the ladies // were laid end to end, I wouldn't be surprised." struct data * newData(void) { struct data *myData; myData = (struct data *) malloc(sizeof(struct data)); return (myData); } struct node * newNode(void) { struct node *myNode; myNode = (struct node *) malloc(sizeof(struct node)); // create new node myNode->data = newData(); // add data to our new node myNode->next = NULL; myNode->prev = NULL; return (myNode); } void addRecord(int num) { int age, seniority; float salary; struct node *myNode; char *word; char *p; // working pointers instead of those lazy kind word = (char *) malloc(sizeof(char) * 35); // space for largish word // id = 42 if new list otherwise // id = whatever you read from myList for (int i = 0; i < num; i++) // how are either myNode or myData in any way new here? { myNode = newNode(); // this module needs some trapping - I entered 140,000 for the salary and blew it up! // did not like that comma one bit - I need to catch it before it bites me printf("\n\n"); // ask user for manual input printf("Add a new record to the list\n"); printf("\n"); memset(word, '\0', sizeof(char) * 35); // clear memory space printf("Who are you? => "); if (scanf("%s", word)) ; printf("Age => "); if (scanf(" %d", &age)) printf("age = %d\n", age); printf("Salary => "); if (scanf(" %f", &salary)) printf("salary = %10.2f\n", salary); printf("Seniority => "); if (scanf(" %d", &seniority)) printf("seniority = %d\n", seniority); printf("\n\n"); myNode->data->id = ++id; // increment either from 42 or from retrieved value myNode->data->name = (char *) malloc(strlen(word)); p = myNode->data->name; while ((*(p++) = *(word++))) ; myNode->data->age = age; myNode->data->salary = salary; myNode->data->seniority = seniority; if (head == NULL) // empty list case { head = myNode; } else // non-empty list { tail->next = myNode; // add at end of list myNode->prev = tail; } tail = myNode; } } int deleteID(int idx) { ep = head; while (ep) { if (ep->data->id == idx) break; ep = ep->next; } printf("node to delete %p sanity check %4d\n", ep, ep->data->id); deleteNode (ep); return 0; } void deleteNode(struct node *here) { if ((here->next == NULL) && (here->prev == NULL)) { // only one left in list case free(here->data); // free data memory space free(here); // free list node memory space printf("List is now empty.\n"); return; } if (here->prev != NULL) // you want to delete the first node here->prev->next = here->next; else { head = here->next; head->prev = NULL; } if (here->next != NULL) // you want to delete the last node here->next->prev = here->prev; else { tail = here->prev; // you're deleting node from the middle of the list tail->next = NULL; } free(here->data); // free data memory space free(here); // free list node memory space } // sort helper function void swap(struct node *start, struct node *ep) { // notice how only the pointers to the data change struct data *temp; // while the data stays in the very same place it started temp = ep->data; ep->data = start->data; start->data = temp; } // a simple selection sort void sort(int choice) { struct node *start, *ptr; // working pointers, you lazy ones can stay home start = head; // start at the head of the list while (start != NULL) { // find the smallest and move it into the first position ptr = start; while (ptr != NULL) { // change next line to reflect sort index of choice switch (choice) { case 1: // use id as the key if (ptr->data->id < start->data->id) swap(start, ptr); // swap the pointers, the data stays in place break; case 2: // use age as key if (ptr->data->age < start->data->age) swap(start, ptr); // swap the pointers, the data stays in place break; case 3: // use salary as key if (ptr->data->salary < start->data->salary) swap(start, ptr); break; case 4: // use seniority as key if (ptr->data->seniority < start->data->seniority) swap(start, ptr); break; case 5: // use id as the key if (ptr->data->id >= start->data->id) swap(start, ptr); // swap the pointers, the data stays in place break; case 6: // use age as key if (ptr->data->age >= start->data->age) swap(start, ptr); // swap the pointers, the data stays in place break; case 7: // use salary as key if (ptr->data->salary >= start->data->salary) swap(start, ptr); break; case 8: // use seniority as key if (ptr->data->seniority >= start->data->seniority) swap(start, ptr); break; case 9: // use name as a key if (strcmp(ptr->data->name, start->data->name) < 0) swap(start, ptr); break; } ptr = ptr->next; // step inner loop } start = start->next; // step outer loop, find next smallest list member } } int save(void) { FILE *fp; fp = fopen("myList.dat", "w"); fprintf(fp, "%4d\n", id); // need to save MAX id number // walk the list and print out the data it holds ep = head; while (ep != NULL) { fprintf(fp, "%4d", ep->data->id); fprintf(fp, " %s", ep->data->name); fprintf(fp, " %3d", ep->data->age); fprintf(fp, " %10.2f", ep->data->salary); fprintf(fp, " %3d", ep->data->seniority); fprintf(fp, "\n"); ep = ep->next; } fclose(fp); return 0; } int read(void) // string pointer to the filename) { int age, seniority; float salary; char name[25]; struct node *myNode; struct data *myData; FILE *fp; // ask for a file name // printf("Please give me the name of your list => "); // if(scanf(" %s", filename); // puts(filename); // convert selection 27 into a routine // so you can standardize the request for a filename head = NULL; tail = NULL; fp = fopen("myList.dat", "r"); //fp = fopen(str ptr my file, "r"); // need to read id number if (fscanf(fp, "%d", &id)) ; // there is only one id now // one ring to rule them all, and in the darkness bind them. while (1) { if (fscanf(fp, "%d", &id) == EOF) break; if (fscanf(fp, "%s", name) == EOF) break; if (fscanf(fp, "%d", &age) == EOF) break; if (fscanf(fp, "%f", &salary) == EOF) break; if (fscanf(fp, "%d", &seniority) == EOF) break; myNode = (struct node *) malloc(sizeof(struct node)); // create new node myData = (struct data *) malloc(sizeof(struct data)); myNode->data = myData; // add data to our new node myData->id = id; myData->name = (char *) malloc(strlen(name)); strcpy(myData->name, name); myData->age = age; myData->salary = salary; myData->seniority = seniority; if (head == NULL) // empty list case { head = myNode; } else // non-empty list { tail->next = myNode; // add at end of list myNode->prev = tail; } tail = myNode; } fclose(fp); return 0; } // walk the list and print out the data it holds int print(void) { ep = head; while (ep != NULL) { printRecord (ep); ep = ep->next; } printf("\n"); return 0; } int printRecord(struct node *ep) { printf("id %3d\t ", ep->data->id); printf("name %-13s ", ep->data->name); printf("age %3d ", ep->data->age); printf("salary $%10.2f\t", ep->data->salary); printf("seniority %3d\n", ep->data->seniority); return 0; } // need to expand this into a more thorough reporting tool // choice of fields to print // as well as choice of range of values in those fields // Maybe get to ANDing and ORing choices together. // That would require I write my own db language // I think not, I'll just mirror the SQL forms I need // remember: nothing fancy, light, fast int report(void) { ep = head; while (ep) { if ((ep->data->age > 60) && (ep->data->salary < 35000)) //if (ep->data->salary > 200000) { printRecord (ep); } ep = ep->next; } printf("\n"); return 0; } //////////////////////////////////////////////////////////////////////// int find(int num) { int idx; int high = 0, low = 0; char *word; switch (num) { case 1: // use id as the key printf("Which id should I find for you? => "); if (scanf(" %d", &idx)) /*dummy*/ ; ep = head; while (ep) { if (ep->data->id == idx) { printRecord (ep); } ep = ep->next; } break; case 2: // use name as the key word = (char *) malloc(sizeof(char) * 35); // space for largish word memset(word, '\0', sizeof(char) * 35); // clear memory space printf("Who are you? => "); if (scanf("%s", word)) ; printf("\n"); // printf("^%s^\n", word); ep = head; while (ep) { if (strcmp(word, ep->data->name) == 0 ) { printRecord (ep); } ep = ep->next; } break; case 3: // use age as the key printf("What age should I find for you? => "); if (scanf(" %d", &idx)) /*dummy*/ ; ep = head; while (ep) { if (ep->data->age == idx) { printRecord (ep); } ep = ep->next; } break; case 4: // use salary as the key printf("What is the high salary of your range => "); if (scanf(" %d", &high)) ; printf("What is the low salary => "); if (scanf(" %d", &low)) ; ep = head; while (ep) { if ((ep->data->salary >= low) && (ep->data->salary <= high)) { printRecord (ep); } ep = ep->next; } break; case 5: // use seniority as the key printf("What seniority should I find for you? => "); if (scanf(" %d", &idx)) ; ep = head; while (ep) { if (ep->data->seniority == idx) { printRecord (ep); } ep = ep->next; } break; } return 0; } #define SIZE 256 int testTime(void) { char buffer[SIZE]; time_t curtime; struct tm *loctime; /* Get the current time. */ curtime = time (NULL); /* Convert it to local time representation. */ loctime = localtime (&curtime); /* Print out the date and time in the standard format. */ fputs (asctime (loctime), stdout); /* Print it out in a nice format. */ strftime (buffer, SIZE, "Today is %A, %B %d.\n", loctime); fputs (buffer, stdout); strftime (buffer, SIZE, "The time is %I:%M:%S %p %Z.\n", loctime); fputs (buffer, stdout); printf("\n\n\t"); for (int j=0; j<2; j++) ttesting(); tInfo(); dayWeek(); secs(); return 0; } #include int ttesting(void) { time_t start_t, end_t; double diff_t; printf("Starting of the program...\n"); time(&start_t); printf("Sleeping for 5 seconds...\n"); sleep(5); time(&end_t); diff_t = difftime(end_t, start_t); printf("\t\tExecution time = %f\n\n\n", diff_t); //printf("Exiting of the program...\n"); return(0); } int secs(void) { time_t now; struct tm newyear; double seconds; time(&now); // get current time; same as: now = time(NULL) newyear = *localtime(&now); newyear.tm_hour = 0; newyear.tm_min = 0; newyear.tm_sec = 0; newyear.tm_mon = 0; newyear.tm_mday = 1; seconds = difftime(now,mktime(&newyear)); printf ("%.f seconds since New Year in the Pacific timezone.\n", seconds); return 0; } int dayWeek(void) { time_t rawtime; struct tm * timeinfo; int year, month ,day; const char * weekday[] = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"}; // prompt user for date printf ("Enter year: "); fflush(stdout); scanf ("%d",&year); printf ("Enter month: "); fflush(stdout); scanf ("%d",&month); printf ("Enter day: "); fflush(stdout); scanf ("%d",&day); // get current timeinfo and modify it to the user's choice time ( &rawtime ); timeinfo = localtime ( &rawtime ); timeinfo->tm_year = year - 1900; timeinfo->tm_mon = month - 1; timeinfo->tm_mday = day; // call mktime: timeinfo->tm_wday will be set mktime ( timeinfo ); printf ("That day is a %s.\n", weekday[timeinfo->tm_wday]); return 0; } int tInfo(void) { time_t rawtime; struct tm * timeinfo; char buffer [80]; time (&rawtime); timeinfo = localtime (&rawtime); strftime (buffer,80,"Now it's %I:%M:%S %p %Z.",timeinfo); puts (buffer); // fputs would store this to disk return 0; } //////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////// /* struct tm { int tm_sec; // seconds, range 0 to 59 int tm_min; // minutes, range 0 to 59 int tm_hour; // hours, range 0 to 23 int tm_mday; // day of the month, range 1 to 31 int tm_mon; // month, range 0 to 11 int tm_year; // The number of years since 1900 int tm_wday; // day of the week, range 0 to 6 int tm_yday; // day in the year, range 0 to 365 int tm_isdst; // daylight saving time }; */ //////////////////////////////////////////////////////////////////////// // // Tool kit of parts from lessons 5 sortLink, 6 tree, 3 structure // parts of 7 search, 8 string, and 13 queue too // //////////////////////////////////////////////////////////////////////// // need these functions to really feel like a database // one that can be useful for day to day stuff // input/output are randomly generated now // edit is related to input, don't create new but read and overwrite // Reports yes but they lead to read() and write() // Sort by your choice of field by tree or function // search within an indexed array // delete a node of the linked list // lists: arrays, linked lists, trees, queue?