Guest User

C trouble

a guest
Jul 3rd, 2014
346
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 3.91 KB | None | 0 0
  1. #include <stdio.h>
  2. #include <assert.h>
  3. #include <stdlib.h>
  4. #include <errno.h>
  5. #include <string.h>
  6.  
  7. #define MAX_DATA 512
  8. #define MAX_ROWS 100
  9.  
  10. struct Address {
  11.     int id;
  12.     int set;
  13.     char name[MAX_DATA];
  14.     char email[MAX_DATA];
  15. };
  16.  
  17. struct Database {
  18.     struct Address rows[MAX_ROWS];
  19. };
  20.  
  21. struct Connection {
  22.     FILE *file;
  23.     struct Database *db;
  24. };
  25.  
  26. void die(const char *message)
  27. {
  28.     if(errno) {
  29.         perror(message);
  30.     } else {
  31.         printf("ERROR: %s\n", message);
  32.     }
  33.  
  34.     exit(1);
  35. }
  36.  
  37. void Address_print(struct Address *addr)
  38. {
  39.     printf("%d %s %s\n",
  40.         addr->id, addr->name, addr->email);
  41. }
  42.  
  43. void Database_load(struct Connection *conn)
  44. {
  45.     int rc = fread(conn->db, sizeof(struct Database), 1, conn->file);
  46.     if(rc != 1) die("Failed to load database.");
  47. }
  48.  
  49. struct Connection *Database_open(const char *filename, char mode)
  50. {
  51.     struct Connection *conn = malloc(sizeof(struct Connection));
  52.     if(!conn) die("Memory error");
  53.  
  54.     conn->db = malloc(sizeof(struct Database));
  55.     if(!conn->db) die("Memory error");
  56.  
  57.     if(mode == 'c') {
  58.         conn->file = fopen(filename, 'w');
  59.     } else {
  60.         conn->file = fopen(filename, 'r+');
  61.  
  62.         if(conn->file) {
  63.             Database_load(conn);
  64.         }
  65.     }
  66.  
  67.     if(!conn->file) die("Failed to open the file");
  68.  
  69.     return conn;
  70. }
  71.  
  72. void Database_close(struct Connection *conn)
  73. {
  74.     if(conn) {
  75.         if(conn->file) fclose(conn->file);
  76.         if(conn->db) free(conn->db);
  77.         free(conn);
  78.     }
  79. }
  80.  
  81. void Database_write(struct Connection *conn)
  82. {
  83.     rewind(conn->file);
  84.  
  85.     int rc = fwrite(conn->db, sizeof(struct Database), 1, conn->file);
  86.     if(rc != 1) die ("Failed to write database");
  87.  
  88.     rc = fflush(conn->file);
  89.     if(rc == -1) die("Cannot flush database");
  90. }
  91.  
  92. void Database_create(struct Connection *conn)
  93. {
  94.     int i = 0;
  95.  
  96.     for(i = 0; i < MAX_ROWS; i++) {
  97.         // make a prototype to initialize it
  98.         struct Address addr = {.id = i, .set = 0};
  99.         // then just assign it
  100.         conn->db->rows[i] = addr;
  101.     }
  102. }
  103.  
  104. void Database_set(struct Connection *conn, int id, const char *name, const char *email)
  105. {
  106.     struct Address *addr = &conn->db->rows[id];
  107.     if(addr->set) die("Already set, delete it first");
  108.  
  109.     addr->set = 1;
  110.     // WARNING: bug, read how to break it to fix
  111.     char *res = strcat(strncpy(addr->name, name, MAX_DATA), '\0');
  112.     // demonstrates strncopy bug
  113.     if(!res) die("Name copy failed");
  114.  
  115.     res = strcat(strncpy(addr->email, email, MAX_DATA), '\0');
  116.     if(!res) die("Email copy failed");
  117. }
  118.  
  119. void Database_get(struct Connection *conn, int id)
  120. {
  121.     struct Address *addr = &conn->db->rows[id];
  122.  
  123.     if(addr->set) {
  124.         Address_print(addr);
  125.     } else {
  126.         die("ID is not set");
  127.     }
  128. }
  129.  
  130. void Database_delete(struct Connection *conn, int id)
  131. {
  132.     struct Address addr = {.id = id, .set = 0};
  133.     conn->db->rows[id] = addr;
  134. }
  135.  
  136. void Database_list(struct Connection *conn)
  137. {
  138.     int i = 0;
  139.     struct Database *db = conn-> db;
  140.  
  141.     for(i = 0; i < MAX_ROWS; i++) {
  142.         struct Address *cur = &db->rows[i];
  143.  
  144.         if(cur->set) {
  145.             Address_print(cur);
  146.         }
  147.     }
  148. }
  149.  
  150. int main(int argc, char *argv[])
  151. {
  152.     if(argc < 3) die("USAGE: ./ex17 <dbfile> <action> [action params]");
  153.  
  154.     char *filename = argv[1];
  155.     char action = argv[2][0];
  156.     struct Connection *conn = Database_open(filename, action);
  157.     int id = 0;
  158.  
  159.     if(argc > 3) id = atoi(argv[3]);
  160.     if(id >= MAX_ROWS) die("There's not that many records");
  161.  
  162.     switch(action) {
  163.         case 'c':
  164.             Database_create(conn);
  165.             Database_write(conn);
  166.             break;
  167.  
  168.         case 'g':
  169.             if(argc != 4) die("Need an ID to get");
  170.  
  171.             Database_get(conn, id);
  172.             break;
  173.  
  174.         case 's':
  175.             if(argc != 6) die ("Need ID, Name, and EMail to set");
  176.  
  177.             Database_set(conn, id, argv[4], argv[5]);
  178.             Database_write(conn);
  179.             break;
  180.  
  181.         case 'd':
  182.             if(argc != 4) die("Need ID to delete");
  183.  
  184.             Database_delete(conn, id);
  185.             Database_write(conn);
  186.             break;
  187.  
  188.         case 'l':
  189.             Database_list(conn);
  190.             break;
  191.  
  192.         default:
  193.             die("Invalid action, only: c=create, g=get, s=set, d=del, l=list");
  194.     }
  195.     Database_close(conn);
  196.  
  197.     return 0;
  198. }
Advertisement
Add Comment
Please, Sign In to add comment