1
// Copyright (c) 1996 James Clark
2
// See the file COPYING for copying permission.
4
// Need option registration method that allows derived class to change
12
#include "CmdLineApp.h"
13
#include "CmdLineAppMessages.h"
14
#include "MessageArg.h"
15
#include "ErrnoMessageArg.h"
21
#include "MessageTable.h"
22
#include "CodingSystemKit.h"
24
#include "ConsoleOutput.h"
36
#ifdef SP_HAVE_SETMODE
41
#include <sys/types.h>
42
#ifdef SP_INCLUDE_UNISTD_H
45
#ifdef SP_INCLUDE_IO_H
53
#ifndef SP_DEFAULT_ENCODING
55
#define SP_DEFAULT_ENCODING SP_T("WINDOWS")
57
#define SP_DEFAULT_ENCODING SP_T("IS8859-1")
59
#endif /* not SP_DEFAULT_ENCODING */
62
namespace SP_NAMESPACE {
65
static const SP_TCHAR *progName = 0;
67
static const SP_TCHAR versionString[] = SP_VERSION;
69
static FileOutputByteStream standardOutput(1, 0);
70
static FileOutputByteStream standardError(2, 0);
72
CmdLineApp::CmdLineApp(const char *requiredInternalCode)
74
outputCodingSystem_(0),
75
// Colon at beginning is Posix.2ism that says to return : rather than ? for
76
// missing option argument.
77
optstr_(SP_T(":"), 1),
79
internalCharsetIsDocCharset_(1),
82
initCodingSystem(requiredInternalCode);
83
setMessageStream(makeStdErr());
84
registerOption('b', internalCharsetIsDocCharset_ ? SP_T("bctf") : SP_T("encoding"));
85
registerOption('f', SP_T("error_file"));
89
void CmdLineApp::resetCodingSystemKit()
91
codingSystemKit_ = codingSystemKit_->copy();
94
void CmdLineApp::registerOption(AppChar c, const AppChar *argName)
99
optArgNames_.push_back(argName);
103
StringC CmdLineApp::usageString()
105
String<AppChar> result;
107
result.assign(progName, tcslen(progName));
108
PackedBoolean hadOption[128];
109
for (int i = 0; i < 128; i++)
111
Boolean hadNoArgOption = 0;
112
for (size_t i = 1; i < optstr_.size(); i++) {
115
if (i + 1 < optstr_.size() && optstr_[i + 1] == ':')
117
else if (!hadOption[optstr_[i]]) {
118
hadOption[optstr_[i]] = 1;
119
if (!hadNoArgOption) {
121
result.append(SP_T(" [-"), 3);
123
result += optstr_[i];
129
for (size_t i = 1; i < optstr_.size(); i++) {
130
if (i + 1 < optstr_.size() && optstr_[i + 1] == ':') {
131
if (!hadOption[optstr_[i]]) {
132
hadOption[optstr_[i]] = 1;
136
result += optstr_[i];
138
result.append(optArgNames_[j], tcslen(optArgNames_[j]));
145
result.append(SP_T(" sysid..."), tcslen(SP_T(" sysid...")));
147
return convertInput(result.data());
151
void ewrite(const char *s)
153
int n = (int)strlen(s);
155
int nw = write(2, s, n);
164
#ifdef SP_FANCY_NEW_HANDLER
165
int outOfMemory(size_t)
170
ewrite("SP library: out of memory\n");
172
#ifdef SP_FANCY_NEW_HANDLER
177
int CmdLineApp::init(int, AppChar **argv)
180
set_new_handler(outOfMemory);
182
#ifdef SP_HAVE_LOCALE
184
setlocale(LC_ALL, "");
187
#ifdef SP_HAVE_SETMODE
188
_setmode(1, _O_BINARY);
189
_setmode(2, _O_BINARY);
193
setProgramName(convertInput(progName));
197
int CmdLineApp::run(int argc, AppChar **argv)
200
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF|_CRTDBG_LEAK_CHECK_DF);
205
int ret = init(argc, argv);
209
ret = processOptions(argc, argv, firstArg);
212
ret = processArguments(argc - firstArg, argv + firstArg);
218
#ifndef SP_NO_STD_NAMESPACE
222
#ifdef SP_FANCY_NEW_HANDLER
229
#endif /* SP_ANSI_LIB */
232
int CmdLineApp::processOptions(int argc, AppChar **argv, int &nextArg)
235
optstr_ += SP_T('\0');
236
Options<AppChar> options(argc, argv, optstr_.data());
238
while (options.get(opt)) {
241
ostr[0] = options.opt();
242
ostr[1] = SP_T('\0');
243
message(CmdLineAppMessages::missingOptionArgError,
244
StringMessageArg(convertInput(ostr)));
245
message(CmdLineAppMessages::usage,
246
StringMessageArg(usageString()));
249
ostr[0] = options.opt();
250
ostr[1] = SP_T('\0');
251
message(CmdLineAppMessages::invalidOptionError,
252
StringMessageArg(convertInput(ostr)));
253
message(CmdLineAppMessages::usage,
254
StringMessageArg(usageString()));
257
processOption(opt, options.arg());
261
nextArg = options.ind();
263
static FileOutputByteStream file;
264
if (!file.open(errorFile_)) {
265
message(CmdLineAppMessages::openFileError,
266
StringMessageArg(convertInput(errorFile_)),
267
ErrnoMessageArg(errno));
270
setMessageStream(new EncodeOutputCharStream(&file, codingSystem()));
272
if (!outputCodingSystem_)
273
outputCodingSystem_ = codingSystem();
277
void CmdLineApp::processOption(AppChar opt, const AppChar *arg)
281
outputCodingSystem_ = lookupCodingSystem(arg);
282
if (!outputCodingSystem_)
283
message(internalCharsetIsDocCharset_
284
? CmdLineAppMessages::unknownBctf
285
: CmdLineAppMessages::unknownEncoding,
286
StringMessageArg(convertInput(arg)));
292
// print the version number
293
message(CmdLineAppMessages::versionInfo,
294
StringMessageArg(convertInput(versionString)));
301
Boolean CmdLineApp::getMessageText(const MessageFragment &frag,
304
String<SP_TCHAR> str;
305
if (!MessageTable::instance()->getText(frag, str))
307
#ifdef SP_WIDE_SYSTEM
308
text.assign((const Char *)str.data(), str.size());
311
text = codingSystem()->convertIn(str.data());
316
Boolean CmdLineApp::stringMatches(const SP_TCHAR *s, const char *key)
318
for (; *key != '\0'; s++, key++) {
319
if (*s != tolower(*key) && *s != toupper(*key))
325
void CmdLineApp::initCodingSystem(const char *requiredInternalCode)
327
const char *name = requiredInternalCode;
331
const SP_TCHAR *internalCode = tgetenv(SP_T("SP_SYSTEM_CHARSET"));
334
for (size_t i = 0; i < 255; i++) {
335
buf[i] = internalCode[i];
342
if (requiredInternalCode)
343
internalCharsetIsDocCharset_ = 0;
345
const SP_TCHAR *useInternal = tgetenv(SP_T("SP_CHARSET_FIXED"));
347
&& (stringMatches(useInternal, "YES")
348
|| stringMatches(useInternal, "1")))
349
internalCharsetIsDocCharset_ = 0;
351
#endif /* SP_MULTI_BYTE */
352
codingSystemKit_ = CodingSystemKit::make(name);
353
const SP_TCHAR *codingName = tgetenv(internalCharsetIsDocCharset_
355
: SP_T("SP_ENCODING"));
357
codingSystem_ = lookupCodingSystem(codingName);
359
if (!codingSystem_ && !internalCharsetIsDocCharset_)
360
codingSystem_ = lookupCodingSystem(SP_DEFAULT_ENCODING);
363
#ifndef SP_WIDE_SYSTEM
364
|| codingSystem_->fixedBytesPerChar() > 1
367
codingSystem_ = codingSystemKit_->identityCodingSystem();
371
CmdLineApp::lookupCodingSystem(const AppChar *codingName)
373
#define MAX_CS_NAME 50
374
if (tcslen(codingName) < MAX_CS_NAME) {
375
char buf[MAX_CS_NAME];
377
for (i = 0; codingName[i] != SP_T('\0'); i++) {
378
SP_TUCHAR c = codingName[i];
379
#ifdef SP_WIDE_SYSTEM
380
if (c > (unsigned char)-1)
386
return codingSystemKit_->makeCodingSystem(buf, internalCharsetIsDocCharset_);
391
StringC CmdLineApp::convertInput(const SP_TCHAR *s)
393
#ifdef SP_WIDE_SYSTEM
394
StringC str(s, wcslen(s));
396
StringC str(codingSystem()->convertIn(s));
398
for (size_t i = 0; i < str.size(); i++)
404
OutputCharStream *CmdLineApp::makeStdErr()
406
OutputCharStream *os = ConsoleOutput::makeOutputCharStream(2);
409
return new EncodeOutputCharStream(&standardError, codingSystem());
412
OutputCharStream *CmdLineApp::makeStdOut()
414
OutputCharStream *os = ConsoleOutput::makeOutputCharStream(1);
417
return new EncodeOutputCharStream(&standardOutput, outputCodingSystem_);
420
const MessageType2 &CmdLineApp::openFileErrorMessage()
422
return CmdLineAppMessages::openFileError;
425
const MessageType2 &CmdLineApp::closeFileErrorMessage()
427
return CmdLineAppMessages::closeFileError;