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