Skip to content

Commit 3555ada

Browse files
committed
Replacing use of getopt() and glob() with portable SimpleOpt and SimpleGlob.
1 parent e220275 commit 3555ada

5 files changed

Lines changed: 139 additions & 78 deletions

File tree

src/common.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,10 @@ extern bool g_db_initialize();
4747
//! free global SQL database connection
4848
extern void g_db_free();
4949

50+
#ifdef OUT
51+
#undef OUT
52+
#endif
53+
5054
//! conditional debug output
5155
#define OUTC(dbg,X) do { if (dbg) { std::cerr << X; } } while(0)
5256

src/importdata.cpp

Lines changed: 85 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -23,18 +23,18 @@
2323

2424
#include <stdlib.h>
2525
#include <stdio.h>
26-
#include <getopt.h>
2726
#include <errno.h>
2827
#include <string.h>
2928
#include <assert.h>
30-
#include <glob.h>
3129

3230
#include <iostream>
3331
#include <fstream>
3432
#include <sstream>
3533
#include <vector>
3634
#include <set>
3735

36+
#include "simpleopt.h"
37+
#include "simpleglob.h"
3838
#include "importdata.h"
3939
#include "common.h"
4040

@@ -330,6 +330,29 @@ ImportData::ImportData(bool temporary_table)
330330
{
331331
}
332332

333+
//! define identifiers for command line arguments
334+
enum { OPT_HELP, OPT_VERBOSE,
335+
OPT_FIRSTLINE, OPT_ALL_LINES, OPT_NO_DUPLICATE,
336+
OPT_COLUMN_NUMBERS, OPT_EMPTY_OKAY,
337+
OPT_TEMPORARY_TABLE, OPT_PERMANENT_TABLE,
338+
OPT_DATABASE };
339+
340+
//! define command line arguments
341+
static CSimpleOpt::SOption sopt_list[] = {
342+
{ OPT_HELP, "-?", SO_NONE },
343+
{ OPT_HELP, "-h", SO_NONE },
344+
{ OPT_VERBOSE, "-v", SO_NONE },
345+
{ OPT_FIRSTLINE, "-1", SO_NONE },
346+
{ OPT_ALL_LINES, "-a", SO_NONE },
347+
{ OPT_NO_DUPLICATE, "-d", SO_NONE },
348+
{ OPT_COLUMN_NUMBERS, "-C", SO_NONE },
349+
{ OPT_EMPTY_OKAY, "-E", SO_NONE },
350+
{ OPT_TEMPORARY_TABLE, "-T", SO_NONE },
351+
{ OPT_PERMANENT_TABLE, "-P", SO_NONE },
352+
{ OPT_DATABASE, "-D", SO_REQ_SEP },
353+
SO_END_OF_OPTIONS
354+
};
355+
333356
//! print command line usage
334357
int ImportData::print_usage(const std::string& progname)
335358
{
@@ -349,55 +372,68 @@ int ImportData::print_usage(const std::string& progname)
349372
}
350373

351374
//! process command line arguments and data
352-
int ImportData::main(int argc, char* const argv[])
375+
int ImportData::main(int argc, char* argv[])
353376
{
354377
FieldSet::check_detect();
355378

356-
int save_optind = 1;
357-
std::swap(optind, save_optind);
379+
//! parse command line parameters using SimpleOpt
380+
CSimpleOpt args(argc, argv, sopt_list);
381+
382+
while (args.Next())
383+
{
384+
if (args.LastError() != SO_SUCCESS) {
385+
OUT(argv[0] << ": invalid command line argument '" << args.OptionText() << "'");
386+
return EXIT_FAILURE;
387+
}
358388

359-
/* parse command line parameters */
360-
int opt;
389+
switch (args.OptionId())
390+
{
391+
case OPT_HELP: default:
392+
return print_usage(argv[0]);
361393

362-
while ((opt = getopt(argc, argv, "h1avdCETPD:")) != -1) {
363-
switch (opt) {
364-
case '1':
394+
case OPT_FIRSTLINE:
365395
mopt_firstline = true;
366396
break;
367-
case 'a':
397+
398+
case OPT_ALL_LINES:
368399
mopt_all_lines = true;
369400
break;
370-
case 'v':
401+
402+
case OPT_VERBOSE:
371403
mopt_verbose++;
372404
break;
373-
case 'd':
405+
406+
case OPT_NO_DUPLICATE:
374407
mopt_noduplicates = true;
375408
break;
376-
case 'C':
409+
410+
case OPT_COLUMN_NUMBERS:
377411
mopt_colnums = true;
378412
break;
379-
case 'E':
413+
414+
case OPT_EMPTY_OKAY:
380415
mopt_empty_okay = true;
381416
break;
382-
case 'T':
417+
418+
case OPT_TEMPORARY_TABLE:
383419
mopt_temporary_table = true;
384420
break;
385-
case 'P':
421+
422+
case OPT_PERMANENT_TABLE:
386423
mopt_temporary_table = false;
387424
break;
388-
case 'D':
389-
gopt_db_connection = optarg;
425+
426+
case OPT_DATABASE:
427+
gopt_db_connection = args.OptionArg();
390428
break;
391-
case 'h': default:
392-
return print_usage(argv[0]);
393429
}
394430
}
395431

396432
// no table name given
397-
if (optind == argc)
433+
if (args.FileCount() == 0)
398434
print_usage(argv[0]);
399435

400-
m_tablename = argv[optind++];
436+
m_tablename = args.File(0);
401437

402438
// maybe connect to database
403439
bool opt_dbconnect = false;
@@ -412,47 +448,41 @@ int ImportData::main(int argc, char* const argv[])
412448
g_db->execute("BEGIN");
413449

414450
// process file commandline arguments
415-
if (optind < argc)
451+
if (args.FileCount())
416452
{
417-
while (optind < argc)
418-
{
419-
// glob() for matching file names
420-
glob_t globbuf;
453+
// glob to expand wild cards in arguments
421454

422-
int gflags = GLOB_TILDE | GLOB_BRACE;
423-
if (mopt_empty_okay) gflags |= GLOB_NOCHECK;
455+
int gflags = SG_GLOB_TILDE | SG_GLOB_ONLYFILE;
456+
if (mopt_empty_okay) gflags |= SG_GLOB_NOCHECK;
424457

425-
int gr = glob(argv[optind], gflags, NULL, &globbuf);
426-
if (gr != 0) {
427-
OUT_THROW("Error globing " << argv[optind] << ": " << strerror(errno));
458+
CSimpleGlob glob(SG_GLOB_NODOT | SG_GLOB_NOCHECK);
459+
if (SG_SUCCESS != glob.Add(args.FileCount() - 1, args.Files() + 1)) {
460+
OUT_THROW("Error while globbing files");
461+
return EXIT_FAILURE;
462+
}
463+
464+
for (int fi = 0; fi < glob.FileCount(); ++fi)
465+
{
466+
const char* fname = glob.File(fi);
467+
468+
m_count = 0;
469+
std::ifstream in(fname);
470+
if (!in.good()) {
471+
if (mopt_empty_okay)
472+
OUT("Error reading " << fname << ": " << strerror(errno));
473+
else
474+
OUT_THROW("Error reading " << fname << ": " << strerror(errno));
428475
}
476+
else {
477+
process_stream(in);
429478

430-
for (size_t gi = 0; gi < globbuf.gl_pathc; ++gi)
431-
{
432-
const char* fname = globbuf.gl_pathv[gi];
433-
434-
m_count = 0;
435-
std::ifstream in(fname);
436-
if (!in.good()) {
437-
if (mopt_empty_okay)
438-
OUT("Error reading " << fname << ": " << strerror(errno));
439-
else
440-
OUT_THROW("Error reading " << fname << ": " << strerror(errno));
479+
if (mopt_firstline) {
480+
OUT("Imported " << m_count << " rows of data from " << fname);
441481
}
442482
else {
443-
process_stream(in);
444-
445-
if (mopt_firstline) {
446-
OUT("Imported " << m_count << " rows of data from " << fname);
447-
}
448-
else {
449-
OUT("Cached " << m_count << " rows of data from " << fname);
450-
}
483+
OUT("Cached " << m_count << " rows of data from " << fname);
451484
}
452485
}
453-
454-
globfree(&globbuf);
455-
++optind;
456486
}
457487
}
458488
else // no file arguments -> process stdin
@@ -462,8 +492,6 @@ int ImportData::main(int argc, char* const argv[])
462492
process_stream(std::cin);
463493
}
464494

465-
std::swap(optind, save_optind);
466-
467495
// process cached data lines
468496
if (!mopt_firstline)
469497
{

src/importdata.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ class ImportData
9999
int print_usage(const std::string& progname);
100100

101101
//! process command line arguments and data
102-
int main(int argc, char* const argv[]);
102+
int main(int argc, char* argv[]);
103103
};
104104

105105
#endif // IMPORTDATA_HEADER

src/simpleglob.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,8 @@ enum SG_Error {
165165
// on Windows we want to use MBCS aware string functions and mimic the
166166
// Unix glob functionality. On Unix we just use glob.
167167
#ifdef _WIN32
168+
# define WIN32_LEAN_AND_MEAN
169+
# include <windows.h>
168170
# include <mbstring.h>
169171
# define sg_strchr ::_mbschr
170172
# define sg_strrchr ::_mbsrchr

src/sp-process.cpp

Lines changed: 47 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@
2424
#include <cstdlib>
2525
#include <cstring>
2626
#include <fstream>
27-
#include <getopt.h>
2827

28+
#include "simpleopt.h"
2929
#include "common.h"
3030
#include "strtools.h"
3131
#include "pgsql.h"
@@ -86,6 +86,22 @@ sp_process_stream(const std::string& filename, std::istream& is)
8686
return lines;
8787
}
8888

89+
//! define identifiers for command line arguments
90+
enum { OPT_HELP, OPT_VERBOSE, OPT_FILETYPE,
91+
OPT_OUTPUT, OPT_CHECK_OUTPUT, OPT_DATABASE };
92+
93+
//! define command line arguments
94+
static CSimpleOpt::SOption sopt_list[] = {
95+
{ OPT_HELP, "-?", SO_NONE },
96+
{ OPT_HELP, "-h", SO_NONE },
97+
{ OPT_VERBOSE, "-v", SO_NONE },
98+
{ OPT_FILETYPE, "-f", SO_REQ_SEP },
99+
{ OPT_OUTPUT, "-o", SO_REQ_SEP },
100+
{ OPT_CHECK_OUTPUT, "-C", SO_NONE },
101+
{ OPT_DATABASE, "-D", SO_REQ_SEP },
102+
SO_END_OF_OPTIONS
103+
};
104+
89105
//! print command line usage
90106
static inline int
91107
sp_process_usage(const std::string& progname)
@@ -107,31 +123,43 @@ sp_process_usage(const std::string& progname)
107123
static inline int
108124
sp_process(int argc, char* argv[])
109125
{
110-
// parse command line parameters
111-
int opt;
112-
113126
//! output file name
114127
std::string opt_outputfile;
115128

116-
while ((opt = getopt(argc, argv, "vo:Cf:D:")) != -1) {
117-
switch (opt) {
118-
case 'v':
129+
//! parse command line parameters using SimpleOpt
130+
CSimpleOpt args(argc, argv, sopt_list);
131+
132+
while (args.Next())
133+
{
134+
if (args.LastError() != SO_SUCCESS) {
135+
OUT(argv[0] << ": invalid command line argument '" << args.OptionText() << "'");
136+
return EXIT_FAILURE;
137+
}
138+
139+
switch (args.OptionId())
140+
{
141+
case OPT_HELP: default:
142+
return sp_process_usage(argv[0]);
143+
144+
case OPT_VERBOSE:
119145
gopt_verbose++;
120146
break;
121-
case 'o':
122-
opt_outputfile = optarg;
147+
148+
case OPT_FILETYPE:
149+
sopt_filetype = args.OptionArg();
123150
break;
124-
case 'f':
125-
sopt_filetype = optarg;
151+
152+
case OPT_OUTPUT:
153+
opt_outputfile = args.OptionArg();
126154
break;
127-
case 'C':
155+
156+
case OPT_CHECK_OUTPUT:
128157
gopt_check_output = true;
129158
break;
130-
case 'D':
131-
gopt_db_connection = optarg;
159+
160+
case OPT_DATABASE:
161+
gopt_db_connection = args.OptionArg();
132162
break;
133-
case 'h': default:
134-
return sp_process_usage(argv[0]);
135163
}
136164
}
137165

@@ -161,11 +189,11 @@ sp_process(int argc, char* argv[])
161189
}
162190

163191
// process file commandline arguments
164-
if (optind < argc)
192+
if (args.FileCount())
165193
{
166-
while (optind < argc)
194+
for (int fi = 0; fi < args.FileCount(); ++fi)
167195
{
168-
const char* filename = argv[optind];
196+
const char* filename = args.File(fi);
169197

170198
std::ifstream in(filename);
171199
if (!in.good()) {
@@ -190,7 +218,6 @@ sp_process(int argc, char* argv[])
190218
OUT_THROW("Error writing " << filename << ": " << strerror(errno));
191219
}
192220
}
193-
++optind;
194221
}
195222
}
196223
else // no file arguments -> process stdin

0 commit comments

Comments
 (0)