1 /*-
2  * Copyright (c) 2004, 2020 Oracle and/or its affiliates.  All rights reserved.
3  *
4  * See the file EXAMPLES-LICENSE for license information.
5  */
6 
7 #include "gettingstarted_common.h"
8 
9 /* Forward declarations */
10 int usage(void);
11 char *show_inventory_item(void *);
12 int show_all_records(STOCK_DBS *);
13 int show_records(STOCK_DBS *, char *);
14 int show_vendor_record(char *, DB *);
15 
16 int
usage()17 usage()
18 {
19     fprintf(stderr, "example_database_read [-i <item name>]");
20     fprintf(stderr, " [-h <database home>]\n");
21 
22     fprintf(stderr,
23 	"\tNote: Any path specified to the -h parameter must end\n");
24     fprintf(stderr, " with your system's path delimiter (/ or \\)\n");
25     return (-1);
26 }
27 
28 /*
29  * Searches for a inventory item based on that item's name. The search is
30  * performed using the item name secondary database. Displays all
31  * inventory items that use the specified name, as well as the vendor
32  * associated with that inventory item.
33  *
34  * If no item name is provided, then all inventory items are displayed.
35  */
36 int
main(int argc,char * argv[])37 main(int argc, char *argv[])
38 {
39     STOCK_DBS my_stock;
40     int ch, ret;
41     char *itemname;
42 
43     /* Initialize the STOCK_DBS struct */
44     initialize_stockdbs(&my_stock);
45 
46     /* Parse the command line arguments */
47     itemname = NULL;
48     while ((ch = getopt(argc, argv, "h:i:?")) != EOF)
49 	switch (ch) {
50 	case 'h':
51 	    if (optarg[strlen(optarg)-1] != '/' &&
52 		optarg[strlen(optarg)-1] != '\\')
53 		return (usage());
54 	    my_stock.db_home_dir = optarg;
55 	    break;
56 	case 'i':
57 	    itemname = optarg;
58 	    break;
59 	case '?':
60 	default:
61 	    return (usage());
62 	}
63 
64     /* Identify the files that hold our databases */
65     set_db_filenames(&my_stock);
66 
67     /* Open all databases */
68     ret = databases_setup(&my_stock, "example_database_read", stderr);
69     if (ret != 0) {
70 	fprintf(stderr, "Error opening databases\n");
71 	databases_close(&my_stock);
72 	return (ret);
73     }
74 
75 	/*
76 	 * Show either a single item or all items, depending
77 	 * on whether itemname is set to a value.
78 	 */
79     if (itemname == NULL)
80 	ret = show_all_records(&my_stock);
81     else
82 	ret = show_records(&my_stock, itemname);
83 
84     /* close our databases */
85     databases_close(&my_stock);
86     return (ret);
87 }
88 
show_all_records(STOCK_DBS * my_stock)89 int show_all_records(STOCK_DBS *my_stock)
90 {
91     DBC *inventory_cursorp;
92     DBT key, data;
93     char *the_vendor;
94     int exit_value, ret;
95 
96     /* Initialize our DBTs. */
97     memset(&key, 0, sizeof(DBT));
98     memset(&data, 0, sizeof(DBT));
99 
100     /* Get a cursor to the inventory db */
101     my_stock->inventory_dbp->cursor(my_stock->inventory_dbp, NULL,
102       &inventory_cursorp, 0);
103 
104     /*
105      * Iterate over the inventory database, from the first record
106      * to the last, displaying each in turn.
107      */
108     exit_value = 0;
109     while ((ret =
110       inventory_cursorp->get(inventory_cursorp, &key, &data, DB_NEXT)) == 0)
111     {
112 	the_vendor = show_inventory_item(data.data);
113 	ret = show_vendor_record(the_vendor, my_stock->vendor_dbp);
114 	if (ret) {
115 	    exit_value = ret;
116 	    break;
117 	}
118     }
119 
120     /* Close the cursor */
121     inventory_cursorp->close(inventory_cursorp);
122     return (exit_value);
123 }
124 
125 /*
126  * Search for an inventory item given its name (using the inventory item
127  * secondary database) and display that record and any duplicates that may
128  * exist.
129  */
130 int
show_records(STOCK_DBS * my_stock,char * itemname)131 show_records(STOCK_DBS *my_stock, char *itemname)
132 {
133     DBC *itemname_cursorp;
134     DBT key, data;
135     char *the_vendor;
136     int ret, exit_value;
137 
138     /* Initialize our DBTs. */
139     memset(&key, 0, sizeof(DBT));
140     memset(&data, 0, sizeof(DBT));
141 
142     /* Get a cursor to the itemname db */
143     my_stock->itemname_sdbp->cursor(my_stock->itemname_sdbp, NULL,
144       &itemname_cursorp, 0);
145 
146     /*
147      * Get the search key. This is the name on the inventory
148      * record that we want to examine.
149      */
150     key.data = itemname;
151     key.size = (u_int32_t)strlen(itemname) + 1;
152 
153     /*
154      * Position our cursor to the first record in the secondary
155      * database that has the appropriate key.
156      */
157     exit_value = 0;
158     ret = itemname_cursorp->get(itemname_cursorp, &key, &data, DB_SET);
159     if (!ret) {
160 	do {
161 	    /*
162 	     * Show the inventory record and the vendor responsible
163 	     * for this inventory item.
164 	     */
165 	    the_vendor = show_inventory_item(data.data);
166 	    ret = show_vendor_record(the_vendor, my_stock->vendor_dbp);
167 	    if (ret) {
168 		exit_value = ret;
169 		break;
170 	    }
171 	    /*
172 	     * Our secondary allows duplicates, so we need to loop over
173 	     * the next duplicate records and show them all. This is done
174 	     * because an inventory item's name is not a unique value.
175 	     */
176 	} while (itemname_cursorp->get(itemname_cursorp, &key, &data,
177 	    DB_NEXT_DUP) == 0);
178     } else {
179 	printf("No records found for '%s'\n", itemname);
180     }
181 
182     /* Close the cursor */
183     itemname_cursorp->close(itemname_cursorp);
184 
185     return (exit_value);
186 }
187 
188 /*
189  * Shows an inventory item. How we retrieve the inventory
190  * item values from the provided buffer is strictly dependent
191  * on the order that those items were originally stored in the
192  * DBT. See load_inventory_database in example_database_load
193  * for how this was done.
194  */
195 char *
show_inventory_item(void * vBuf)196 show_inventory_item(void *vBuf)
197 {
198     float price;
199     int quantity;
200     size_t buf_pos;
201     char *category, *name, *sku, *vendor_name;
202     char *buf = (char *)vBuf;
203 
204     /* Get the price. */
205     price = *((float *)buf);
206     buf_pos = sizeof(float);
207 
208     /* Get the quantity. */
209     quantity = *((int *)(buf + buf_pos));
210     buf_pos += sizeof(int);
211 
212     /* Get the inventory item's name */
213     name = buf + buf_pos;
214     buf_pos += strlen(name) + 1;
215 
216     /* Get the inventory item's sku */
217     sku = buf + buf_pos;
218     buf_pos += strlen(sku) + 1;
219 
220     /*
221      * Get the category (fruits, vegetables, desserts) that this
222      * item belongs to.
223      */
224     category = buf + buf_pos;
225     buf_pos += strlen(category) + 1;
226 
227     /* Get the vendor's name */
228     vendor_name = buf + buf_pos;
229 
230     /* Display all this information */
231     printf("name: %s\n", name);
232     printf("\tSKU: %s\n", sku);
233     printf("\tCategory: %s\n", category);
234     printf("\tPrice: %.2f\n", price);
235     printf("\tQuantity: %i\n", quantity);
236     printf("\tVendor:\n");
237 
238     /* Return the vendor's name */
239     return (vendor_name);
240 }
241 
242 /*
243  * Shows a vendor record. Each vendor record is an instance of
244  * a vendor structure. See load_vendor_database() in
245  * example_database_load for how this structure was originally
246  * put into the database.
247  */
248 int
show_vendor_record(char * vendor_name,DB * vendor_dbp)249 show_vendor_record(char *vendor_name, DB *vendor_dbp)
250 {
251     DBT key, data;
252     VENDOR my_vendor;
253     int ret;
254 
255     /* Zero our DBTs */
256     memset(&key, 0, sizeof(DBT));
257     memset(&data, 0, sizeof(DBT));
258 
259     /* Set the search key to the vendor's name */
260     key.data = vendor_name;
261     key.size = (u_int32_t)strlen(vendor_name) + 1;
262 
263     /*
264      * Make sure we use the memory we set aside for the VENDOR
265      * structure rather than the memory that DB allocates.
266      * Some systems may require structures to be aligned in memory
267      * in a specific way, and DB may not get it right.
268      */
269 
270     data.data = &my_vendor;
271     data.ulen = sizeof(VENDOR);
272     data.flags = DB_DBT_USERMEM;
273 
274     /* Get the record */
275     ret = vendor_dbp->get(vendor_dbp, NULL, &key, &data, 0);
276     if (ret != 0) {
277 	vendor_dbp->err(vendor_dbp, ret, "Error searching for vendor: '%s'",
278 	  vendor_name);
279 	return (ret);
280     } else {
281 	printf("\t\t%s\n", my_vendor.name);
282 	printf("\t\t%s\n", my_vendor.street);
283 	printf("\t\t%s, %s\n", my_vendor.city, my_vendor.state);
284 	printf("\t\t%s\n\n", my_vendor.zipcode);
285 	printf("\t\t%s\n\n", my_vendor.phone_number);
286 	printf("\t\tContact: %s\n", my_vendor.sales_rep);
287 	printf("\t\t%s\n", my_vendor.sales_rep_phone);
288     }
289     return (0);
290 }
291