1/*- 2 * See the file LICENSE for redistribution information. 3 * 4 * Copyright (c) 2004,2008 Oracle. All rights reserved. 5 */ 6 7#include "gettingstarted_common.h" 8 9/* Forward declarations */ 10int usage(void); 11int load_vendors_database(STOCK_DBS, char *); 12size_t pack_string(char *, char *, size_t); 13int load_inventory_database(STOCK_DBS, char *); 14 15int 16usage() 17{ 18 fprintf(stderr, "example_database_load [-b <path to data files>]"); 19 fprintf(stderr, " [-h <database_home_directory>]\n"); 20 21 fprintf(stderr, "\tNote: Any path specified must end with your"); 22 fprintf(stderr, " system's path delimiter (/ or \\)\n"); 23 return (-1); 24} 25 26/* 27 * Loads the contents of vendors.txt and inventory.txt into 28 * Berkeley DB databases. Also causes the itemname secondary 29 * database to be created and loaded. 30 */ 31int 32main(int argc, char *argv[]) 33{ 34 STOCK_DBS my_stock; 35 int ch, ret; 36 size_t size; 37 char *basename, *inventory_file, *vendor_file; 38 39 /* Initialize the STOCK_DBS struct */ 40 initialize_stockdbs(&my_stock); 41 42 /* Initialize the base path. */ 43 basename = "./"; 44 45 /* Parse the command line arguments */ 46 while ((ch = getopt(argc, argv, "b:h:")) != EOF) 47 switch (ch) { 48 case 'h': 49 if (optarg[strlen(optarg)-1] != '/' && 50 optarg[strlen(optarg)-1] != '\\') 51 return (usage()); 52 my_stock.db_home_dir = optarg; 53 break; 54 case 'b': 55 if (basename[strlen(basename)-1] != '/' && 56 basename[strlen(basename)-1] != '\\') 57 return (usage()); 58 basename = optarg; 59 break; 60 case '?': 61 default: 62 return (usage()); 63 } 64 65 /* Identify the files that will hold our databases */ 66 set_db_filenames(&my_stock); 67 68 /* Find our input files */ 69 size = strlen(basename) + strlen(INVENTORY_FILE) + 1; 70 inventory_file = malloc(size); 71 snprintf(inventory_file, size, "%s%s", basename, INVENTORY_FILE); 72 73 size = strlen(basename) + strlen(VENDORS_FILE) + 1; 74 vendor_file = malloc(size); 75 snprintf(vendor_file, size, "%s%s", basename, VENDORS_FILE); 76 77 /* Open all databases */ 78 ret = databases_setup(&my_stock, "example_database_load", stderr); 79 if (ret) { 80 fprintf(stderr, "Error opening databases\n"); 81 databases_close(&my_stock); 82 return (ret); 83 } 84 85 ret = load_vendors_database(my_stock, vendor_file); 86 if (ret) { 87 fprintf(stderr, "Error loading vendors database.\n"); 88 databases_close(&my_stock); 89 return (ret); 90 } 91 ret = load_inventory_database(my_stock, inventory_file); 92 if (ret) { 93 fprintf(stderr, "Error loading inventory database.\n"); 94 databases_close(&my_stock); 95 return (ret); 96 } 97 98 /* close our environment and databases */ 99 databases_close(&my_stock); 100 101 printf("Done loading databases.\n"); 102 return (ret); 103} 104 105/* 106 * Loads the contents of the vendors.txt file into 107 * a database. 108 */ 109int 110load_vendors_database(STOCK_DBS my_stock, char *vendor_file) 111{ 112 DBT key, data; 113 char buf[MAXLINE]; 114 FILE *ifp; 115 VENDOR my_vendor; 116 117 /* Load the vendors database */ 118 ifp = fopen(vendor_file, "r"); 119 if (ifp == NULL) { 120 fprintf(stderr, "Error opening file '%s'\n", vendor_file); 121 return (-1); 122 } 123 124 while (fgets(buf, MAXLINE, ifp) != NULL) { 125 /* zero out the structure */ 126 memset(&my_vendor, 0, sizeof(VENDOR)); 127 /* Zero out the DBTs */ 128 memset(&key, 0, sizeof(DBT)); 129 memset(&data, 0, sizeof(DBT)); 130 131 /* 132 * Scan the line into the structure. 133 * Convenient, but not particularly safe. 134 * In a real program, there would be a lot more 135 * defensive code here. 136 */ 137 sscanf(buf, 138 "%20[^#]#%20[^#]#%20[^#]#%3[^#]#%6[^#]#%13[^#]#%20[^#]#%20[^\n]", 139 my_vendor.name, my_vendor.street, 140 my_vendor.city, my_vendor.state, 141 my_vendor.zipcode, my_vendor.phone_number, 142 my_vendor.sales_rep, my_vendor.sales_rep_phone); 143 144 /* Now that we have our structure we can load it into the database. */ 145 146 /* Set up the database record's key */ 147 key.data = my_vendor.name; 148 key.size = (u_int32_t)strlen(my_vendor.name) + 1; 149 150 /* Set up the database record's data */ 151 data.data = &my_vendor; 152 data.size = sizeof(VENDOR); 153 154 /* 155 * Note that given the way we built our struct, there's extra 156 * bytes in it. Essentially we're using fixed-width fields with 157 * the unused portion of some fields padded with zeros. This 158 * is the easiest thing to do, but it does result in a bloated 159 * database. Look at load_inventory_data() for an example of how 160 * to avoid this. 161 */ 162 163 /* Put the data into the database */ 164 my_stock.vendor_dbp->put(my_stock.vendor_dbp, 0, &key, &data, 0); 165 } /* end vendors database while loop */ 166 167 fclose(ifp); 168 return (0); 169} 170 171/* 172 * Simple little convenience function that takes a buffer, a string, 173 * and an offset and copies that string into the buffer at the 174 * appropriate location. Used to ensure that all our strings 175 * are contained in a single contiguous chunk of memory. 176 */ 177size_t 178pack_string(char *buffer, char *string, size_t start_pos) 179{ 180 size_t string_size; 181 182 string_size = strlen(string) + 1; 183 memcpy(buffer+start_pos, string, string_size); 184 185 return (start_pos + string_size); 186} 187 188/* 189 * Loads the contents of the inventory.txt file into 190 * a database. Note that because the itemname 191 * secondary database is associated to the inventorydb 192 * (see env_setup() in gettingstarted_common.c), the 193 * itemname index is automatically created when this 194 * database is loaded. 195 */ 196int 197load_inventory_database(STOCK_DBS my_stock, char *inventory_file) 198{ 199 DBT key, data; 200 char buf[MAXLINE]; 201 char databuf[MAXDATABUF]; 202 size_t bufLen, dataLen; 203 FILE *ifp; 204 205 /* 206 * Rather than lining everything up nicely in a struct, we're being 207 * deliberately a bit sloppy here. This function illustrates how to 208 * store mixed data that might be obtained from various locations 209 * in your application. 210 */ 211 float price; 212 int quantity; 213 char category[MAXFIELD], name[MAXFIELD]; 214 char vendor[MAXFIELD], sku[MAXFIELD]; 215 216 /* Load the inventory database */ 217 ifp = fopen(inventory_file, "r"); 218 if (ifp == NULL) { 219 fprintf(stderr, "Error opening file '%s'\n", inventory_file); 220 return (-1); 221 } 222 223 while (fgets(buf, MAXLINE, ifp) != NULL) { 224 /* 225 * Scan the line into the appropriate buffers and variables. 226 * Convenient, but not particularly safe. In a real 227 * program, there would be a lot more defensive code here. 228 */ 229 sscanf(buf, 230 "%20[^#]#%20[^#]#%f#%i#%20[^#]#%20[^\n]", 231 name, sku, &price, &quantity, category, vendor); 232 233 /* 234 * Now pack it into a single contiguous memory location for 235 * storage. 236 */ 237 memset(databuf, 0, MAXDATABUF); 238 bufLen = 0; 239 dataLen = 0; 240 241 dataLen = sizeof(float); 242 memcpy(databuf, &price, dataLen); 243 bufLen += dataLen; 244 245 dataLen = sizeof(int); 246 memcpy(databuf + bufLen, &quantity, dataLen); 247 bufLen += dataLen; 248 249 bufLen = pack_string(databuf, name, bufLen); 250 bufLen = pack_string(databuf, sku, bufLen); 251 bufLen = pack_string(databuf, category, bufLen); 252 bufLen = pack_string(databuf, vendor, bufLen); 253 254 /* Zero out the DBTs */ 255 memset(&key, 0, sizeof(DBT)); 256 memset(&data, 0, sizeof(DBT)); 257 258 /* The key is the item's SKU */ 259 key.data = sku; 260 key.size = (u_int32_t)strlen(sku) + 1; 261 262 /* The data is the information that we packed into databuf. */ 263 data.data = databuf; 264 data.size = (u_int32_t)bufLen; 265 266 /* Put the data into the database */ 267 my_stock.vendor_dbp->put(my_stock.inventory_dbp, 0, &key, &data, 0); 268 } /* end vendors database while loop */ 269 270 /* Cleanup */ 271 fclose(ifp); 272 273 return (0); 274} 275