1 /* $XConsortium: CmdLineApp.C /main/2 1996/08/12 12:36:14 mgreess $ */
2 // Copyright (c) 1996 James Clark
3 // See the file COPYING for copying permission.
5 // Need option registration method that allows derived class to change
13 #include "CmdLineApp.h"
14 #include "CmdLineAppMessages.h"
15 #include "MessageArg.h"
16 #include "ErrnoMessageArg.h"
22 #include "MessageTable.h"
25 #include "UTF8CodingSystem.h"
26 #include "Fixed2CodingSystem.h"
27 #include "UnicodeCodingSystem.h"
28 #include "EUCJPCodingSystem.h"
29 #include "SJISCodingSystem.h"
30 #include "ISO8859InputCodingSystem.h"
32 #include "Win32CodingSystem.h"
34 #endif /* SP_MULTI_BYTE */
35 #include "IdentityCodingSystem.h"
37 #include "ConsoleOutput.h"
49 #ifdef SP_HAVE_SETMODE
53 #ifdef SP_HAVE_SETMODE
54 #define IOS_BINARY ios::binary
62 #else /* not SP_WIDE_SYSTEM */
64 #include <sys/types.h>
65 #ifdef SP_INCLUDE_UNISTD_H
68 #ifdef SP_INCLUDE_IO_H
72 #endif /* not SP_WIDE_SYSTEM */
75 namespace SP_NAMESPACE {
79 static UTF8CodingSystem utf8CodingSystem;
80 static Fixed2CodingSystem fixed2CodingSystem;
81 static UnicodeCodingSystem unicodeCodingSystem;
82 static EUCJPCodingSystem eucjpCodingSystem;
83 static SJISCodingSystem sjisCodingSystem;
85 static Win32CodingSystem ansiCodingSystem(Win32CodingSystem::codePageAnsi);
86 static Win32CodingSystem oemCodingSystem(Win32CodingSystem::codePageOEM);
87 static UnicodeCodingSystem maybeUnicodeCodingSystem(&ansiCodingSystem);
89 #endif /* SP_MULTI_BYTE */
90 static IdentityCodingSystem identityCodingSystem;
94 const CodingSystem *cs;
97 { "UTF-8", &utf8CodingSystem },
98 { "FIXED-2", &fixed2CodingSystem },
99 { "UNICODE", &unicodeCodingSystem },
100 { "EUC-JP", &eucjpCodingSystem },
101 { "SJIS", &sjisCodingSystem },
103 { "WINDOWS", &ansiCodingSystem },
104 { "MS-DOS", &oemCodingSystem },
105 { "WUNICODE", &maybeUnicodeCodingSystem },
107 #endif /* SP_MULTI_BYTE */
108 { "IS8859-1", &identityCodingSystem },
109 { "IDENTITY", &identityCodingSystem },
112 const CodingSystem *CmdLineApp::codingSystem_ = 0;
114 static const SP_TCHAR *progName = 0;
116 static const SP_TCHAR versionString[] = SP_VERSION;
118 CmdLineApp::CmdLineApp()
120 outputCodingSystem_(0),
121 // Colon at beginning is Posix.2ism that says to return : rather than ? for
122 // missing option argument.
123 optstr_(SP_T(":"), 1),
124 MessageReporter(makeStdErr())
126 registerOption('b', SP_T("bctf"));
127 registerOption('f', SP_T("error_file"));
131 void CmdLineApp::registerOption(AppChar c, const AppChar *argName)
135 optstr_ += SP_T(':');
136 optArgNames_.push_back(argName);
140 StringC CmdLineApp::usageString()
142 String<AppChar> result;
146 result.assign(progName, tcslen(progName));
147 PackedBoolean hadOption[128];
148 for (i = 0; i < 128; i++)
150 Boolean hadNoArgOption = 0;
151 for (i = 1; i < optstr_.size(); i++) {
154 if (i + 1 < optstr_.size() && optstr_[i + 1] == ':')
156 else if (!hadOption[optstr_[i]]) {
157 hadOption[optstr_[i]] = 1;
158 if (!hadNoArgOption) {
160 result.append(SP_T(" [-"), 3);
162 result += optstr_[i];
168 for (i = 1; i < optstr_.size(); i++) {
169 if (i + 1 < optstr_.size() && optstr_[i + 1] == ':') {
170 if (!hadOption[optstr_[i]]) {
171 hadOption[optstr_[i]] = 1;
175 result += optstr_[i];
177 result.append(optArgNames_[j], tcslen(optArgNames_[j]));
184 result.append(SP_T(" sysid..."), tcslen(SP_T(" sysid...")));
186 return convertInput(result.data());
190 void ewrite(const AppChar *s)
192 #ifdef SP_WIDE_SYSTEM
195 int n = (int)strlen(s);
197 int nw = write(2, s, n);
207 #ifdef SP_FANCY_NEW_HANDLER
208 int outOfMemory(size_t)
217 ewrite(SP_T(": out of memory\n"));
219 #ifdef SP_FANCY_NEW_HANDLER
224 int CmdLineApp::init(int, AppChar **argv)
226 set_new_handler(outOfMemory);
227 #ifdef SP_HAVE_LOCALE
228 setlocale(LC_ALL, "");
230 #ifdef SP_HAVE_SETMODE
231 _setmode(1, _O_BINARY);
232 _setmode(2, _O_BINARY);
236 setProgramName(convertInput(progName));
238 // cout is a performance disaster in libg++ unless we do this.
239 ios::sync_with_stdio(0);
244 int CmdLineApp::run(int argc, AppChar **argv)
246 int ret = init(argc, argv);
250 ret = processOptions(argc, argv, firstArg);
253 ret = processArguments(argc - firstArg, argv + firstArg);
258 Boolean CmdLineApp::openFilebufWrite(filebuf &file,
259 const AppChar *filename)
261 #ifdef SP_WIDE_SYSTEM
262 int fd = _wopen(filename, _O_CREAT|_O_WRONLY|_O_TRUNC|_O_BINARY);
265 return file.attach(fd) != 0;
267 return file.open(filename, ios::out|ios::trunc|IOS_BINARY) != 0;
271 int CmdLineApp::processOptions(int argc, AppChar **argv, int &nextArg)
274 optstr_ += SP_T('\0');
275 Options<AppChar> options(argc, argv, optstr_.data());
277 while (options.get(opt)) {
280 ostr[0] = options.opt();
281 ostr[1] = SP_T('\0');
282 message(CmdLineAppMessages::missingOptionArgError,
283 StringMessageArg(convertInput(ostr)));
284 message(CmdLineAppMessages::usage,
285 StringMessageArg(usageString()));
288 ostr[0] = options.opt();
289 ostr[1] = SP_T('\0');
290 message(CmdLineAppMessages::invalidOptionError,
291 StringMessageArg(convertInput(ostr)));
292 message(CmdLineAppMessages::usage,
293 StringMessageArg(usageString()));
296 processOption(opt, options.arg());
300 nextArg = options.ind();
303 if (!openFilebufWrite(file, errorFile_)) {
304 message(CmdLineAppMessages::cannotOpenOutputError,
305 StringMessageArg(convertInput(errorFile_)),
306 ErrnoMessageArg(errno));
309 setMessageStream(new IosOutputCharStream(&file, codingSystem()));
311 if (!outputCodingSystem_)
312 outputCodingSystem_ = codingSystem();
316 void CmdLineApp::processOption(AppChar opt, const AppChar *arg)
320 outputCodingSystem_ = lookupCodingSystem(arg);
321 if (!outputCodingSystem_)
322 message(CmdLineAppMessages::unknownBctf,
323 StringMessageArg(convertInput(arg)));
329 // print the version number
330 message(CmdLineAppMessages::versionInfo,
331 StringMessageArg(convertInput(versionString)));
338 Boolean CmdLineApp::getMessageText(const MessageFragment &frag,
341 String<SP_TCHAR> str;
342 if (!MessageTable::instance()->getText(frag, str))
344 #ifdef SP_WIDE_SYSTEM
345 text.assign((const Char *)str.data(), str.size());
348 text = codingSystem()->convertIn(str.data());
353 const CodingSystem *CmdLineApp::codingSystem()
355 if (!codingSystem_) {
356 const SP_TCHAR *codingName = tgetenv(SP_T("SP_BCTF"));
358 codingSystem_ = lookupCodingSystem(codingName);
360 #ifndef SP_WIDE_SYSTEM
361 || codingSystem_->fixedBytesPerChar() > 1
364 codingSystem_ = &identityCodingSystem;
366 return codingSystem_;
370 CmdLineApp::lookupCodingSystem(const SP_TCHAR *codingName)
372 #define MAX_CS_NAME 50
373 if (tcslen(codingName) < MAX_CS_NAME) {
374 char buf[MAX_CS_NAME];
376 for (i = 0; codingName[i] != SP_T('\0'); i++) {
377 SP_TUCHAR c = totupper((SP_TUCHAR)(codingName[i]));
378 #ifdef SP_WIDE_SYSTEM
379 if (c > (unsigned char)-1)
386 for (size_t i = 0; i < SIZEOF(codingSystems); i++)
387 if (strcmp(buf, codingSystems[i].name) == 0)
388 return codingSystems[i].cs;
395 CmdLineApp::codingSystem(size_t i, const char *&name)
397 if (i < SIZEOF(codingSystems)) {
398 name = codingSystems[i].name;
399 return codingSystems[i].cs;
404 StringC CmdLineApp::convertInput(const SP_TCHAR *s)
406 #ifdef SP_WIDE_SYSTEM
407 StringC str(s, wcslen(s));
409 StringC str(codingSystem()->convertIn(s));
411 for (size_t i = 0; i < str.size(); i++)
417 OutputCharStream *CmdLineApp::makeStdErr()
419 OutputCharStream *os = ConsoleOutput::makeOutputCharStream(2);
422 return new IosOutputCharStream(cerr.rdbuf(), codingSystem());
425 OutputCharStream *CmdLineApp::makeStdOut()
427 OutputCharStream *os = ConsoleOutput::makeOutputCharStream(1);
430 return new IosOutputCharStream(cout.rdbuf(), outputCodingSystem_);