cdesktopenv/cde/programs/nsgmls/CmdLineApp.C

468 lines
11 KiB
C

/*
* CDE - Common Desktop Environment
*
* Copyright (c) 1993-2012, The Open Group. All rights reserved.
*
* These libraries and programs are free software; you can
* redistribute them and/or modify them under the terms of the GNU
* Lesser General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* These libraries and programs are distributed in the hope that
* they will be useful, but WITHOUT ANY WARRANTY; without even the
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU Lesser General Public License for more
* details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with these librararies and programs; if not, write
* to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
* Floor, Boston, MA 02110-1301 USA
*/
/* $XConsortium: CmdLineApp.C /main/2 1996/08/12 12:36:14 mgreess $ */
// Copyright (c) 1996 James Clark
// See the file COPYING for copying permission.
// Need option registration method that allows derived class to change
// option names.
#ifdef __GNUG__
#pragma implementation
#endif
#include "splib.h"
#include "CmdLineApp.h"
#include "CmdLineAppMessages.h"
#include "MessageArg.h"
#include "ErrnoMessageArg.h"
#include "Options.h"
#include "version.h"
#include "xnew.h"
#include "macros.h"
#include "sptchar.h"
#include "MessageTable.h"
#ifdef SP_MULTI_BYTE
#include "UTF8CodingSystem.h"
#include "Fixed2CodingSystem.h"
#include "UnicodeCodingSystem.h"
#include "EUCJPCodingSystem.h"
#include "SJISCodingSystem.h"
#include "ISO8859InputCodingSystem.h"
#ifdef WIN32
#include "Win32CodingSystem.h"
#endif
#endif /* SP_MULTI_BYTE */
#include "IdentityCodingSystem.h"
#include "ConsoleOutput.h"
#if defined(linux) || defined(CSRG_BASED)
#include <iostream>
#include <fstream>
using namespace std;
#else
#include <iostream.h>
#include <fstream.h>
#endif
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#ifdef SP_HAVE_LOCALE
#include <locale.h>
#endif
#ifdef SP_HAVE_SETMODE
#include <fcntl.h>
#include <io.h>
#endif
#ifdef SP_HAVE_SETMODE
#define IOS_BINARY ios::binary
#else
#define IOS_BINARY 0
#endif
#ifdef SP_WIDE_SYSTEM
#include <stdio.h>
#else /* not SP_WIDE_SYSTEM */
#include <sys/types.h>
#ifdef SP_INCLUDE_UNISTD_H
#include <unistd.h>
#endif
#ifdef SP_INCLUDE_IO_H
#include <io.h>
#endif
#endif /* not SP_WIDE_SYSTEM */
#ifdef SP_NAMESPACE
namespace SP_NAMESPACE {
#endif
#ifdef SP_MULTI_BYTE
static UTF8CodingSystem utf8CodingSystem;
static Fixed2CodingSystem fixed2CodingSystem;
static UnicodeCodingSystem unicodeCodingSystem;
static EUCJPCodingSystem eucjpCodingSystem;
static SJISCodingSystem sjisCodingSystem;
#ifdef WIN32
static Win32CodingSystem ansiCodingSystem(Win32CodingSystem::codePageAnsi);
static Win32CodingSystem oemCodingSystem(Win32CodingSystem::codePageOEM);
static UnicodeCodingSystem maybeUnicodeCodingSystem(&ansiCodingSystem);
#endif
#endif /* SP_MULTI_BYTE */
static IdentityCodingSystem identityCodingSystem;
static struct {
const char *name;
const CodingSystem *cs;
} codingSystems[] = {
#ifdef SP_MULTI_BYTE
{ "UTF-8", &utf8CodingSystem },
{ "FIXED-2", &fixed2CodingSystem },
{ "UNICODE", &unicodeCodingSystem },
{ "EUC-JP", &eucjpCodingSystem },
{ "SJIS", &sjisCodingSystem },
#ifdef WIN32
{ "WINDOWS", &ansiCodingSystem },
{ "MS-DOS", &oemCodingSystem },
{ "WUNICODE", &maybeUnicodeCodingSystem },
#endif
#endif /* SP_MULTI_BYTE */
{ "IS8859-1", &identityCodingSystem },
{ "IDENTITY", &identityCodingSystem },
};
const CodingSystem *CmdLineApp::codingSystem_ = 0;
static const SP_TCHAR *progName = 0;
static const SP_TCHAR versionString[] = SP_VERSION;
CmdLineApp::CmdLineApp()
: errorFile_(0),
outputCodingSystem_(0),
// Colon at beginning is Posix.2ism that says to return : rather than ? for
// missing option argument.
optstr_(SP_T(":"), 1),
MessageReporter(makeStdErr())
{
registerOption('b', SP_T("bctf"));
registerOption('f', SP_T("error_file"));
registerOption('v');
}
void CmdLineApp::registerOption(AppChar c, const AppChar *argName)
{
optstr_ += c;
if (argName) {
optstr_ += SP_T(':');
optArgNames_.push_back(argName);
}
}
StringC CmdLineApp::usageString()
{
String<AppChar> result;
size_t i;
if (progName)
result.assign(progName, tcslen(progName));
PackedBoolean hadOption[128];
for (i = 0; i < 128; i++)
hadOption[i] = 0;
Boolean hadNoArgOption = 0;
for (i = 1; i < optstr_.size(); i++) {
if (optstr_[i] == 0)
break;
if (i + 1 < optstr_.size() && optstr_[i + 1] == ':')
i++;
else if (!hadOption[optstr_[i]]) {
hadOption[optstr_[i]] = 1;
if (!hadNoArgOption) {
hadNoArgOption = 1;
result.append(SP_T(" [-"), 3);
}
result += optstr_[i];
}
}
if (hadNoArgOption)
result += SP_T(']');
size_t j = 0;
for (i = 1; i < optstr_.size(); i++) {
if (i + 1 < optstr_.size() && optstr_[i + 1] == ':') {
if (!hadOption[optstr_[i]]) {
hadOption[optstr_[i]] = 1;
result += SP_T(' ');
result += SP_T('[');
result += SP_T('-');
result += optstr_[i];
result += SP_T(' ');
result.append(optArgNames_[j], tcslen(optArgNames_[j]));
result += SP_T(']');
}
i++;
j++;
}
}
result.append(SP_T(" sysid..."), tcslen(SP_T(" sysid...")));
result += 0;
return convertInput(result.data());
}
static
void ewrite(const AppChar *s)
{
#ifdef SP_WIDE_SYSTEM
fputts(s, stderr);
#else
int n = (int)strlen(s);
while (n > 0) {
int nw = write(2, s, n);
if (nw < 0)
break;
n -= nw;
s += nw;
}
#endif
}
static
#ifdef SP_FANCY_NEW_HANDLER
int outOfMemory(size_t)
#else
void outOfMemory()
#endif
{
if (progName) {
ewrite(progName);
ewrite(SP_T(": "));
}
ewrite(SP_T(": out of memory\n"));
exit(1);
#ifdef SP_FANCY_NEW_HANDLER
return 0;
#endif
}
int CmdLineApp::init(int, AppChar **argv)
{
set_new_handler(outOfMemory);
#ifdef SP_HAVE_LOCALE
setlocale(LC_ALL, "");
#endif
#ifdef SP_HAVE_SETMODE
_setmode(1, _O_BINARY);
_setmode(2, _O_BINARY);
#endif
progName = argv[0];
if (progName)
setProgramName(convertInput(progName));
#ifdef __GNUG__
// cout is a performance disaster in libg++ unless we do this.
ios::sync_with_stdio(0);
#endif
return 0;
}
int CmdLineApp::run(int argc, AppChar **argv)
{
int ret = init(argc, argv);
if (ret)
return ret;
int firstArg;
ret = processOptions(argc, argv, firstArg);
if (ret)
return ret;
ret = processArguments(argc - firstArg, argv + firstArg);
progName = 0;
return ret;
}
Boolean CmdLineApp::openFilebufWrite(filebuf &file,
const AppChar *filename)
{
#ifdef SP_WIDE_SYSTEM
int fd = _wopen(filename, _O_CREAT|_O_WRONLY|_O_TRUNC|_O_BINARY);
if (fd < 0)
return 0;
return file.attach(fd) != 0;
#else
#if defined(linux) || defined(CSRG_BASED)
return file.open(filename, ios::out|ios::trunc) != 0;
#else
return file.open(filename, ios::out|ios::trunc|IOS_BINARY) != 0;
#endif
#endif
}
int CmdLineApp::processOptions(int argc, AppChar **argv, int &nextArg)
{
AppChar ostr[2];
optstr_ += SP_T('\0');
Options<AppChar> options(argc, argv, optstr_.data());
AppChar opt;
while (options.get(opt)) {
switch (opt) {
case ':':
ostr[0] = options.opt();
ostr[1] = SP_T('\0');
message(CmdLineAppMessages::missingOptionArgError,
StringMessageArg(convertInput(ostr)));
message(CmdLineAppMessages::usage,
StringMessageArg(usageString()));
return 1;
case '?':
ostr[0] = options.opt();
ostr[1] = SP_T('\0');
message(CmdLineAppMessages::invalidOptionError,
StringMessageArg(convertInput(ostr)));
message(CmdLineAppMessages::usage,
StringMessageArg(usageString()));
return 1;
default:
processOption(opt, options.arg());
break;
}
}
nextArg = options.ind();
if (errorFile_) {
static filebuf file;
if (!openFilebufWrite(file, errorFile_)) {
message(CmdLineAppMessages::cannotOpenOutputError,
StringMessageArg(convertInput(errorFile_)),
ErrnoMessageArg(errno));
return 1;
}
setMessageStream(new IosOutputCharStream(&file, codingSystem()));
}
if (!outputCodingSystem_)
outputCodingSystem_ = codingSystem();
return 0;
}
void CmdLineApp::processOption(AppChar opt, const AppChar *arg)
{
switch (opt) {
case 'b':
outputCodingSystem_ = lookupCodingSystem(arg);
if (!outputCodingSystem_)
message(CmdLineAppMessages::unknownBctf,
StringMessageArg(convertInput(arg)));
break;
case 'f':
errorFile_ = arg;
break;
case 'v':
// print the version number
message(CmdLineAppMessages::versionInfo,
StringMessageArg(convertInput(versionString)));
break;
default:
CANNOT_HAPPEN();
}
}
Boolean CmdLineApp::getMessageText(const MessageFragment &frag,
StringC &text)
{
String<SP_TCHAR> str;
if (!MessageTable::instance()->getText(frag, str))
return 0;
#ifdef SP_WIDE_SYSTEM
text.assign((const Char *)str.data(), str.size());
#else
str += 0;
text = codingSystem()->convertIn(str.data());
#endif
return 1;
}
const CodingSystem *CmdLineApp::codingSystem()
{
if (!codingSystem_) {
const SP_TCHAR *codingName = tgetenv(SP_T("SP_BCTF"));
if (codingName)
codingSystem_ = lookupCodingSystem(codingName);
if (!codingSystem_
#ifndef SP_WIDE_SYSTEM
|| codingSystem_->fixedBytesPerChar() > 1
#endif
)
codingSystem_ = &identityCodingSystem;
}
return codingSystem_;
}
const CodingSystem *
CmdLineApp::lookupCodingSystem(const SP_TCHAR *codingName)
{
#define MAX_CS_NAME 50
if (tcslen(codingName) < MAX_CS_NAME) {
char buf[MAX_CS_NAME];
int i;
for (i = 0; codingName[i] != SP_T('\0'); i++) {
SP_TUCHAR c = totupper((SP_TUCHAR)(codingName[i]));
#ifdef SP_WIDE_SYSTEM
if (c > (unsigned char)-1)
return 0;
#endif
buf[i] = char(c);
}
buf[i] = SP_T('\0');
{
for (size_t i = 0; i < SIZEOF(codingSystems); i++)
if (strcmp(buf, codingSystems[i].name) == 0)
return codingSystems[i].cs;
}
}
return 0;
}
const CodingSystem *
CmdLineApp::codingSystem(size_t i, const char *&name)
{
if (i < SIZEOF(codingSystems)) {
name = codingSystems[i].name;
return codingSystems[i].cs;
}
return 0;
}
StringC CmdLineApp::convertInput(const SP_TCHAR *s)
{
#ifdef SP_WIDE_SYSTEM
StringC str(s, wcslen(s));
#else
StringC str(codingSystem()->convertIn(s));
#endif
for (size_t i = 0; i < str.size(); i++)
if (str[i] == '\n')
str[i] = '\r';
return str;
}
OutputCharStream *CmdLineApp::makeStdErr()
{
OutputCharStream *os = ConsoleOutput::makeOutputCharStream(2);
if (os)
return os;
return new IosOutputCharStream(cerr.rdbuf(), codingSystem());
}
OutputCharStream *CmdLineApp::makeStdOut()
{
OutputCharStream *os = ConsoleOutput::makeOutputCharStream(1);
if (os)
return os;
return new IosOutputCharStream(cout.rdbuf(), outputCodingSystem_);
}
#ifdef SP_NAMESPACE
}
#endif