1// File: excxx_example_database_load.cpp
2#include <iostream>
3#include <fstream>
4#include <cstdlib>
5
6#include "MyDb.hpp"
7#include "gettingStartedCommon.hpp"
8
9#ifdef _WIN32
10extern "C" {
11  extern int getopt(int, char * const *, const char *);
12  extern char *optarg;
13}
14#else
15#include <unistd.h>
16#endif
17
18// Forward declarations
19void loadInventoryDB(MyDb &, std::string &);
20void loadVendorDB(MyDb &, std::string &);
21
22using namespace std;
23
24int
25usage()
26{
27    std::cout << "example_database_load [-b <path to data files>]"
28              << " [-h <database home directory>]" << std::endl;
29
30    std::cout << "Note: If -b -h is specified, then the path must end"
31              << " with your system's path delimiter (/ or \\)"
32              << std::endl;
33    return (-1);
34}
35
36// Loads the contents of vendors.txt and inventory.txt into
37// Berkeley DB databases.
38int
39main (int argc, char *argv[])
40{
41
42   char ch, lastChar;
43
44   // Initialize the path to the database files
45   std::string basename("./");
46   std::string databaseHome("./");
47
48   // Database names
49   std::string vDbName("vendordb.db");
50   std::string iDbName("inventorydb.db");
51   std::string itemSDbName("itemname.sdb");
52
53    // Parse the command line arguments
54    while ((ch = getopt(argc, argv, "b:h:")) != EOF)
55        switch (ch) {
56        case 'h':
57            databaseHome = optarg;
58            lastChar = databaseHome[databaseHome.size() -1];
59            if (lastChar != '/' && lastChar != '\\')
60                return (usage());
61            break;
62        case 'b':
63            basename = optarg;
64            lastChar = basename[basename.size() -1];
65            if (lastChar != '/' && lastChar != '\\')
66                return (usage());
67            break;
68        case '?':
69        default:
70            return (usage());
71            break;
72        }
73
74    // Identify the full name for our input files, which should
75    // also include some path information.
76    std::string inventoryFile = basename + "inventory.txt";
77    std::string vendorFile = basename + "vendors.txt";
78
79    try
80    {
81        // Open all databases.
82        MyDb inventoryDB(databaseHome, iDbName);
83        MyDb vendorDB(databaseHome, vDbName);
84        MyDb itemnameSDB(databaseHome, itemSDbName, true);
85
86        // Associate the primary and the secondary
87        inventoryDB.getDb().associate(NULL,
88                                      &(itemnameSDB.getDb()),
89                                      get_item_name,
90                                      0);
91
92        // Load the inventory database
93        loadInventoryDB(inventoryDB, inventoryFile);
94
95        // Load the vendor database
96        loadVendorDB(vendorDB, vendorFile);
97    } catch(DbException &e) {
98        std::cerr << "Error loading databases. " << std::endl;
99        std::cerr << e.what() << std::endl;
100        return (e.get_errno());
101    } catch(std::exception &e) {
102        std::cerr << "Error loading databases. " << std::endl;
103        std::cerr << e.what() << std::endl;
104        return (-1);
105    }
106
107    // MyDb class constructors will close the databases when they
108    // go out of scope.
109    return (0);
110} // End main
111
112// Used to locate the first pound sign (a field delimiter)
113// in the input string.
114size_t
115getNextPound(std::string &theString, std::string &substring)
116{
117    size_t pos = theString.find("#");
118    substring.assign(theString, 0, pos);
119    theString.assign(theString, pos + 1, theString.size());
120    return (pos);
121}
122
123// Loads the contents of the inventory.txt file into a database
124void
125loadInventoryDB(MyDb &inventoryDB, std::string &inventoryFile)
126{
127    InventoryData inventoryData;
128    std::string substring;
129    size_t nextPound;
130
131    std::ifstream inFile(inventoryFile.c_str(), std::ios::in);
132    if ( !inFile )
133    {
134        std::cerr << "Could not open file '" << inventoryFile
135                  << "'. Giving up." << std::endl;
136        throw std::exception();
137    }
138
139    while (!inFile.eof())
140    {
141        inventoryData.clear();
142        std::string stringBuf;
143        std::getline(inFile, stringBuf);
144
145        // Now parse the line
146        if (!stringBuf.empty())
147        {
148            nextPound = getNextPound(stringBuf, substring);
149            inventoryData.setName(substring);
150
151            nextPound = getNextPound(stringBuf, substring);
152            inventoryData.setSKU(substring);
153
154            nextPound = getNextPound(stringBuf, substring);
155            inventoryData.setPrice(strtod(substring.c_str(), 0));
156
157            nextPound = getNextPound(stringBuf, substring);
158            inventoryData.setQuantity(strtol(substring.c_str(), 0, 10));
159
160            nextPound = getNextPound(stringBuf, substring);
161            inventoryData.setCategory(substring);
162
163            nextPound = getNextPound(stringBuf, substring);
164            inventoryData.setVendor(substring);
165
166            void *buff = (void *)inventoryData.getSKU().c_str();
167            size_t size = inventoryData.getSKU().size()+1;
168            Dbt key(buff, (u_int32_t)size);
169
170            buff = inventoryData.getBuffer();
171            size = inventoryData.getBufferSize();
172            Dbt data(buff, (u_int32_t)size);
173
174            inventoryDB.getDb().put(NULL, &key, &data, 0);
175        }
176
177    }
178
179    inFile.close();
180
181}
182
183// Loads the contents of the vendors.txt file into a database
184void
185loadVendorDB(MyDb &vendorDB, std::string &vendorFile)
186{
187    std::ifstream inFile(vendorFile.c_str(), std::ios::in);
188    if ( !inFile )
189    {
190        std::cerr << "Could not open file '" << vendorFile
191                  << "'. Giving up." << std::endl;
192        throw std::exception();
193    }
194
195    VENDOR my_vendor;
196    while (!inFile.eof())
197    {
198        std::string stringBuf;
199        std::getline(inFile, stringBuf);
200        memset(&my_vendor, 0, sizeof(VENDOR));
201
202         // Scan the line into the structure.
203         // Convenient, but not particularly safe.
204         // In a real program, there would be a lot more
205         // defensive code here.
206        sscanf(stringBuf.c_str(),
207          "%20[^#]#%20[^#]#%20[^#]#%3[^#]#%6[^#]#%13[^#]#%20[^#]#%20[^\n]",
208          my_vendor.name, my_vendor.street,
209          my_vendor.city, my_vendor.state,
210          my_vendor.zipcode, my_vendor.phone_number,
211          my_vendor.sales_rep, my_vendor.sales_rep_phone);
212
213        Dbt key(my_vendor.name, (u_int32_t)strlen(my_vendor.name) + 1);
214        Dbt data(&my_vendor, sizeof(VENDOR));
215
216        vendorDB.getDb().put(NULL, &key, &data, 0);
217    }
218
219    inFile.close();
220}
221