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