Facebook
From Scribby Owl, 5 Years ago, written in Plain Text.
This paste is a reply to Re: Untitled from Unreliable Macaque - view diff
Embed
Download Paste or View Raw
Hits: 362
  1. #include <stdio.h>
  2. #include <assert.h>
  3. #include <stdlib.h>
  4. #include <errno.h>
  5. #include <string.h>
  6. #define MAX_DATA 512
  7. #define MAX_ROWS 100
  8. struct Address {
  9.  int id;
  10.  int set;
  11.  char name[MAX_DATA];
  12.  char email[MAX_DATA];
  13. };
  14. struct Database {
  15.  struct Address rows[MAX_ROWS];
  16. };
  17. struct Connection {
  18.  FILE *file;
  19.  struct Database *db;
  20. };
  21. void die(const char *message)
  22. {
  23.  if(errno) {
  24.  perror(message);
  25.  } else {
  26.  printf("ERROR: %s\n", message);
  27.  }
  28.  exit(1);
  29. }
  30. void Address_print(struct Address *addr)
  31. {
  32.  printf("%d %s %s\n",
  33.  addr->id, addr->name, addr->email);
  34. }
  35. void Database_load(struct Connection *conn)
  36. {
  37.  int rc = fread(conn->db, sizeof(struct Database), 1, conn->file);
  38.  if(rc != 1) die("Failed to load database.");
  39. }
  40. struct Connection *Database_open(const char *filename, char mode)
  41. {
  42.  struct Connection *conn = malloc(sizeof(struct Connection));
  43.  if(!conn) die("Memory error");
  44.  conn->db = malloc(sizeof(struct Database));
  45.  if(!conn->db) die("Memory error");
  46.  if(mode == 'c') {
  47.  conn->file = fopen(filename, "w");
  48.  } else {
  49.  conn->file = fopen(filename, "r+");
  50.  if(conn->file) {
  51.  Database_load(conn);
  52.  }
  53.  }
  54.  if(!conn->file) die("Failed to open the file");
  55.  return conn;
  56. }
  57. void Database_close(struct Connection *conn)
  58. {
  59.  if(conn) {
  60.  if(conn->file) fclose(conn->file);
  61.  if(conn->db) free(conn->db);
  62.  free(conn);
  63.  }
  64. }
  65. void Database_write(struct Connection *conn)
  66. {
  67.  rewind(conn->file);
  68.  int rc = fwrite(conn->db, sizeof(struct Database), 1, conn->file);
  69.  if(rc != 1) die("Failed to write database.");
  70.  rc = fflush(conn->file);
  71.  if(rc == -1) die("Cannot flush database.");
  72. }
  73. void Database_create(struct Connection *conn)
  74. {
  75.  int i = 0;
  76.  for(i = 0; i < MAX_ROWS; i++) {
  77.  // make a prototype to initialize it
  78.  struct Address addr = {.id = i, .set = 0};
  79.  // then just assign it
  80.  conn->db->rows[i] = addr;
  81.  }
  82. }
  83. void Database_set(struct Connection *conn, int id, const char *name, const cha
  84. r *email)
  85. {
  86.  struct Address *addr = &conn->db->rows[id];
  87.  if(addr->set) die("Already set, delete it first");
  88.  addr->set = 1;
  89.  // WARNING: bug, read the "How To Break It" and fix this
  90.  char *res = strncpy(addr->name, name, MAX_DATA);
  91.  // demonstrate the strncpy bug
  92.  if(!res) die("Name copy failed");
  93.  res = strncpy(addr->email, email, MAX_DATA);
  94.  if(!res) die("Email copy failed");
  95. }
  96. void Database_get(struct Connection *conn, int id)
  97. {
  98.  struct Address *addr = &conn->db->rows[id];
  99.  if(addr->set) {
  100.  Address_print(addr);
  101.  } else {
  102.  die("ID is not set");
  103.  }
  104. }
  105. void Database_delete(struct Connection *conn, int id)
  106. {
  107.  struct Address addr = {.id = id, .set = 0};
  108.  conn->db->rows[id] = addr;
  109. }
  110. void Database_list(struct Connection *conn)
  111. {
  112.  int i = 0;
  113.  struct Database *db = conn->db;
  114.  for(i = 0; i < MAX_ROWS; i++) {
  115.  struct Address *cur = &db->rows[i];
  116.  if(cur->set) {
  117.  Address_print(cur);
  118.  }
  119.  }
  120. }
  121. int main(int argc, char *argv[])
  122. {
  123.  if(argc < 3) die("USAGE: ex17 <dbfile> <action> [action params]");
  124.  char *filename = argv[1];
  125.  char action = argv[2][0];
  126.  struct Connection *conn = Database_open(filename, action);
  127.  int id = 0;
  128.  if(argc > 3) id = atoi(argv[3]);
  129.  if(id >= MAX_ROWS) die("There's not that many records.");
  130.  switch(action) {
  131.  case 'c':
  132.  Database_create(conn);
  133.  Database_write(conn);
  134.  break;
  135.  case 'g':
  136.  if(argc != 4) die("Need an id to get");
  137.  Database_get(conn, id);
  138.  break;
  139.  case 's':
  140.  if(argc != 6) die("Need id, name, email to set");
  141.  Database_set(conn, id, argv[4], argv[5]);
  142.  Database_write(conn);
  143.  break;
  144.  case 'd':
  145.  if(argc != 4) die("Need id to delete");
  146.  Database_delete(conn, id);
  147.  Database_write(conn);
  148.  break;
  149.  case 'l':
  150.  Database_list(conn);
  151.  break;
  152.  default:
  153.  die("Invalid action, only: c=create, g=get, s=set, d=del, l=list")
  154. ;
  155.  }
  156.  Database_close(conn);
  157.  return 0;
  158. }