This is shells.c in view mode; [Download] [Up]
//------------------------------------------------------------------------
// ^FILE: shells.c - implement classes for the various Unix shells
//
// ^DESCRIPTION:
// This file packages all the information we need to know about each
// of the shells that cmdparse(1) will support into a set of (sub)classes.
//
// ^HISTORY:
// 04/19/92 Brad Appleton <brad@ssd.csd.harris.com> Created
//-^^---------------------------------------------------------------------
#include <stdlib.h>
#include <iostream.h>
#include <string.h>
#include <ctype.h>
#include <fifolist.h>
#include "shells.h"
#include "argtypes.h"
//--------------------------------------------------------------- ShellVariable
ShellVariable::ShellVariable(const char * name)
: var_name(name), var_value(NULL)
{
}
ShellVariable::~ShellVariable(void)
{
}
//------------------------------------------------------------ ShellArrayValues
DECLARE_FIFO_LIST(CharPtrList, char *);
struct ShellArrayValues {
CharPtrList list;
CharPtrListArray array;
ShellArrayValues(void);
} ;
ShellArrayValues::ShellArrayValues(void)
: array(list)
{
list.self_cleaning(1);
}
//------------------------------------------------------------------ ShellArray
ShellArray::ShellArray(const char * name)
: array_name(name), array_value(NULL)
{
}
ShellArray::~ShellArray(void)
{
delete array_value ;
}
void
ShellArray::append(const char * value)
{
if (array_value == NULL) {
array_value = new ShellArrayValues ;
}
char ** valptr = new char* ;
if (valptr) {
*valptr = (char *)value;
array_value->list.add(valptr);
}
}
unsigned
ShellArray::count(void) const
{
return ((array_value) ? array_value->list.count() : 0);
}
const char *
ShellArray::operator[](unsigned index) const
{
return ((array_value) ? array_value->array[index] : NULL);
}
//----------------------------------------------------------- AbstractUnixShell
AbstractUnixShell::~AbstractUnixShell(void)
{
}
//------------------------------------------------------------------- UnixShell
UnixShell::UnixShell(const char * shell_name)
: shell(NULL), valid(1)
{
if (::strcmp(BourneShell::NAME, shell_name) == 0) {
shell = new BourneShell ;
} else if (::strcmp("ash", shell_name) == 0) {
shell = new BourneShell ;
} else if (::strcmp(KornShell::NAME, shell_name) == 0) {
shell = new KornShell ;
} else if (::strcmp(BourneAgainShell::NAME, shell_name) == 0) {
shell = new BourneAgainShell ;
} else if (::strcmp(CShell::NAME, shell_name) == 0) {
shell = new CShell ;
} else if (::strcmp("tcsh", shell_name) == 0) {
shell = new CShell ;
} else if (::strcmp("itcsh", shell_name) == 0) {
shell = new CShell ;
} else if (::strcmp(ZShell::NAME, shell_name) == 0) {
shell = new ZShell ;
} else if (::strcmp(Plan9Shell::NAME, shell_name) == 0) {
shell = new Plan9Shell ;
} else if (::strcmp(PerlShell::NAME, shell_name) == 0) {
shell = new PerlShell ;
} else if (::strcmp(TclShell::NAME, shell_name) == 0) {
shell = new TclShell ;
} else {
valid = 0;
}
}
UnixShell::~UnixShell(void)
{
delete shell;
}
const char *
UnixShell::name(void) const
{
return ((shell) ? shell->name() : NULL);
}
void
UnixShell::unset_args(const char * name) const
{
if (shell) shell->unset_args(name);
}
int
UnixShell::is_positionals(const char * name) const
{
return ((shell) ? shell->is_positionals(name) : 0);
}
void
UnixShell::set(const ShellVariable & variable) const
{
if (shell) shell->set(variable);
}
void
UnixShell::set(const ShellArray & array, int variant) const
{
if (shell) shell->set(array, variant);
}
//----------------------------------------------------------------- varname
// Remove any "esoteric" portions of a vraible name (such as a leading '$')
//
inline static const char *
varname(const char * name, char skip)
{
return ((*name == skip) && (*(name + 1))) ? (name + 1): name ;
}
//----------------------------------------------------------------- BourneShell
const char * BourneShell::NAME = "sh" ;
BourneShell::BourneShell(void)
{
}
BourneShell::~BourneShell(void)
{
}
const char *
BourneShell::name(void) const
{
return BourneShell::NAME ;
}
void
BourneShell::unset_args(const char *) const
{
cout << "shift $# ;" << endl ;
}
int
BourneShell::is_positionals(const char * name) const
{
name = varname(name, '$');
return ((::strcmp(name, "--") == 0) || (::strcmp(name, "-") == 0) ||
(::strcmp(name, "@") == 0) || (::strcmp(name, "*") == 0)) ;
}
void
BourneShell::set(const ShellVariable & variable) const
{
const char * name = varname(variable.name(), '$');
if (is_positionals(name)) {
cout << "set -- '" ;
} else {
cout << name << "='" ;
}
escape_value(variable.value());
cout << "';" << endl ;
}
void
BourneShell::set(const ShellArray & array, int variant) const
{
int ndx;
const char * name = varname(array.name(), '$');
if (is_positionals(name)) {
// set -- 'arg1' 'arg2' ...
cout << "set -- ";
for (ndx = 0 ; ndx < array.count() ; ndx++) {
if (ndx) cout << ' ' ;
cout << '\'' ;
escape_value(array[ndx]);
cout << '\'' ;
}
cout << ';' << endl ;
} else if (variant) {
// argname_count=N
// argname1='arg1'
// ...
// argnameN='argN'
cout << name << "_count=" << array.count() << ';' << endl ;
for (ndx = 0 ; ndx < array.count() ; ndx++) {
cout << name << (ndx + 1) << "='";
escape_value(array[ndx]);
cout << "';" << endl ;
}
} else {
// argname='arg1 arg2 ...'
cout << name << "='";
for (ndx = 0 ; ndx < array.count() ; ndx++) {
if (ndx) cout << ' ' ;
escape_value(array[ndx]);
}
cout << "';" << endl ;
}
}
void
BourneShell::escape_value(const char * value) const
{
for ( ; *value ; value++) {
switch (*value) {
case '\'' :
cout << "'\\''" ;
break ;
case '\\' :
case '\b' :
case '\r' :
case '\v' :
case '\f' :
cout << '\\' ; // fall thru to default case
default :
cout << char(*value) ;
}
} //for
}
//------------------------------------------------------------------- KornShell
const char * KornShell::NAME = "ksh" ;
KornShell::KornShell(void)
{
}
KornShell::~KornShell(void)
{
}
const char *
KornShell::name(void) const
{
return KornShell::NAME ;
}
void
KornShell::unset_args(const char *) const
{
cout << "set -- ;" << endl ;
}
void
KornShell::set(const ShellVariable & variable) const
{
BourneShell::set(variable);
}
void
KornShell::set(const ShellArray & array, int variant) const
{
const char * name = varname(array.name(), '$');
if (is_positionals(name)) {
cout << "set -- " ;
} else {
cout << "set " << (variant ? '+' : '-') << "A " << name << ' ' ;
}
for (int ndx = 0 ; ndx < array.count() ; ndx++) {
if (ndx) cout << ' ' ;
cout << '\'' ;
escape_value(array[ndx]);
cout << '\'' ;
}
cout << ';' << endl ;
}
//------------------------------------------------------------ BourneAgainShell
const char * BourneAgainShell::NAME = "bash" ;
BourneAgainShell::BourneAgainShell(void)
{
}
BourneAgainShell::~BourneAgainShell(void)
{
}
const char *
BourneAgainShell::name(void) const
{
return BourneAgainShell::NAME ;
}
void
BourneAgainShell::set(const ShellVariable & variable) const
{
BourneShell::set(variable);
}
void
BourneAgainShell::set(const ShellArray & array, int variant) const
{
BourneShell::set(array, variant);
}
//---------------------------------------------------------------------- CShell
const char * CShell::NAME = "csh" ;
CShell::CShell(void)
{
}
CShell::~CShell(void)
{
}
const char *
CShell::name(void) const
{
return CShell::NAME ;
}
void
CShell::unset_args(const char *) const
{
cout << "set argv=();" << endl ;
}
int
CShell::is_positionals(const char * name) const
{
name = varname(name, '$');
return (::strcmp(name, "argv") == 0);
}
void
CShell::set(const ShellVariable & variable) const
{
const char * name = varname(variable.name(), '$');
int posl = is_positionals(name);
cout << "set " << name << '=' ;
if (posl) cout << '(' ;
cout << '\'' ;
escape_value(variable.value());
cout << '\'' ;
if (posl) cout << ')' ;
cout << ';' << endl ;;
}
void
CShell::set(const ShellArray & array, int ) const
{
cout << "set " << varname(array.name(), '$') << "=(" ;
for (int ndx = 0 ; ndx < array.count() ; ndx++) {
if (ndx) cout << ' ' ;
cout << '\'' ;
escape_value(array[ndx]);
cout << '\'' ;
}
cout << ");" << endl ;
}
void
CShell::escape_value(const char * value) const
{
for ( ; *value ; value++) {
switch (*value) {
case '\'' :
cout << "'\\''" ;
break ;
case '!' :
case '\n' :
case '\b' :
case '\r' :
case '\v' :
case '\f' :
cout << '\\' ; // fall thru to default case
default :
cout << char(*value) ;
}
} //for
}
//---------------------------------------------------------------------- ZShell
const char * ZShell::NAME = "zsh" ;
ZShell::ZShell(void)
{
}
ZShell::~ZShell(void)
{
}
const char *
ZShell::name(void) const
{
return ZShell::NAME ;
}
void
ZShell::unset_args(const char *) const
{
cout << "argv=();" << endl ;
}
int
ZShell::is_positionals(const char * name) const
{
name = varname(name, '$');
return ((::strcmp(name, "--") == 0) || (::strcmp(name, "-") == 0) ||
(::strcmp(name, "@") == 0) || (::strcmp(name, "*") == 0) ||
(::strcmp(name, "argv") == 0));
}
void
ZShell::set(const ShellVariable & variable) const
{
const char * name = varname(variable.name(), '$');
int posl = is_positionals(name);
cout << name << '=' ;
if (posl) cout << '(' ;
cout << '\'' ;
escape_value(variable.value());
cout << '\'' ;
if (posl) cout << ')' ;
cout << ';' << endl ;;
}
void
ZShell::set(const ShellArray & array, int ) const
{
cout << varname(array.name(), '$') << "=(" ;
for (int ndx = 0 ; ndx < array.count() ; ndx++) {
if (ndx) cout << ' ' ;
cout << '\'' ;
escape_value(array[ndx]);
cout << '\'' ;
}
cout << ");" << endl ;
}
void
ZShell::escape_value(const char * value) const
{
for ( ; *value ; value++) {
switch (*value) {
case '\'' :
cout << "'\\''" ;
break ;
case '!' :
case '\\' :
case '\b' :
case '\r' :
case '\v' :
case '\f' :
cout << '\\' ; // fall thru to default case
default :
cout << char(*value) ;
}
} //for
}
//------------------------------------------------------------------ Plan9Shell
const char * Plan9Shell::NAME = "rc" ;
Plan9Shell::Plan9Shell(void)
{
}
Plan9Shell::~Plan9Shell(void)
{
}
const char *
Plan9Shell::name(void) const
{
return Plan9Shell::NAME ;
}
void
Plan9Shell::unset_args(const char *) const
{
cout << "*=();" << endl ;
}
int
Plan9Shell::is_positionals(const char * name) const
{
name = varname(name, '$');
return (::strcmp(name, "*") == 0);
}
void
Plan9Shell::set(const ShellVariable & variable) const
{
const char * name = varname(variable.name(), '$');
int posl = is_positionals(name);
cout << name << '=' ;
if (posl) cout << '(' ;
cout << '\'' ;
escape_value(variable.value());
cout << '\'' ;
if (posl) cout << ')' ;
cout << ';' << endl ;;
}
void
Plan9Shell::set(const ShellArray & array, int ) const
{
cout << varname(array.name(), '$') << "=(" ;
for (int ndx = 0 ; ndx < array.count() ; ndx++) {
if (ndx) cout << ' ' ;
cout << '\'' ;
escape_value(array[ndx]);
cout << '\'' ;
}
cout << ");" << endl ;
}
void
Plan9Shell::escape_value(const char * value) const
{
for ( ; *value ; value++) {
switch (*value) {
case '\'' :
cout << "''" ;
break ;
case '\\' :
case '\b' :
case '\r' :
case '\v' :
case '\f' :
cout << '\\' ; // fall thru to default case
default :
cout << char(*value) ;
}
} //for
}
//------------------------------------------------------------------- PerlShell
const char * PerlShell::NAME = "perl" ;
PerlShell::PerlShell(void)
{
static const char perl_true[] = "1" ;
static const char perl_false[] = "0" ;
// use different defaults for TRUE and FALSE
ShellCmdArgBool::True(perl_true);
ShellCmdArgBool::False(perl_false);
}
PerlShell::~PerlShell(void)
{
}
const char *
PerlShell::name(void) const
{
return PerlShell::NAME ;
}
void
PerlShell::unset_args(const char *) const
{
cout << "@ARGV = ();" << endl ;
}
int
PerlShell::is_positionals(const char * name) const
{
name = varname(name, '@');
return (::strcmp(name, "ARGV") == 0);
}
void
PerlShell::set(const ShellVariable & variable) const
{
const char * name = varname(variable.name(), '$');
int array = (*name == '@') ;
cout << (array ? "" : "$") << name << " = " ;
if (array) cout << '(' ;
cout << '\'' ;
escape_value(variable.value());
cout << '\'' ;
if (array) cout << ')' ;
cout << ';' << endl ;;
}
void
PerlShell::set(const ShellArray & array, int ) const
{
const char * name = varname(array.name(), '@');
int scalar = (*name == '$') ;
cout << (scalar ? "" : "@") << name << " = " ;
cout << (scalar ? '\'' : '(') ;
for (int ndx = 0 ; ndx < array.count() ; ndx++) {
if (ndx) cout << (scalar ? " " : ", ") ;
if (! scalar) cout << '\'' ;
escape_value(array[ndx]);
if (! scalar) cout << '\'' ;
}
cout << (scalar ? '\'' : ')') ;
cout << ";" << endl ;
}
void
PerlShell::escape_value(const char * value) const
{
for ( ; *value ; value++) {
switch (*value) {
case '\t' : cout << "\\t" ; break ;
case '\n' : cout << "\\n" ; break ;
case '\b' : cout << "\\b" ; break ;
case '\r' : cout << "\\r" ; break ;
case '\v' : cout << "\\v" ; break ;
case '\f' : cout << "\\f" ; break ;
case '\'' :
case '\\' :
cout << "\\" ; // fall thru to default
default :
cout << char(*value) ;
}
} //for
}
//------------------------------------------------------------------- TclShell
const char * TclShell::NAME = "tcl" ;
TclShell::TclShell(void)
{
static const char tcl_true[] = "1" ;
static const char tcl_false[] = "0" ;
// use different defaults for TRUE and FALSE
ShellCmdArgBool::True(tcl_true);
ShellCmdArgBool::False(tcl_false);
}
TclShell::~TclShell(void)
{
}
const char *
TclShell::name(void) const
{
return TclShell::NAME ;
}
void
TclShell::unset_args(const char * name) const
{
cout << "set " << varname(name, '$') << " {};" << endl ;
}
int
TclShell::is_positionals(const char * name) const
{
name = varname(name, '$');
return ((::strcmp(name, "argv") == 0) || (::strcmp(name, "args") == 0));
}
void
TclShell::set(const ShellVariable & variable) const
{
const char * name = varname(variable.name(), '$');
cout << "set " << name << ' ' ;
cout << '"' ;
escape_value(variable.value());
cout << '"' ;
cout << ';' << endl ;;
}
void
TclShell::set(const ShellArray & array, int ) const
{
const char * name = varname(array.name(), '@');
int scalar = (*name == '$') ;
cout << "set " << name << " [ list " ;
for (int ndx = 0 ; ndx < array.count() ; ndx++) {
if (ndx) cout << ' ' ;
cout << '"' ;
escape_value(array[ndx]);
cout << '"' ;
}
cout << " ]" ;
cout << ";" << endl ;
}
void
TclShell::escape_value(const char * value) const
{
for ( ; *value ; value++) {
switch (*value) {
case '\t' : cout << "\\t" ; break ;
case '\n' : cout << "\\n" ; break ;
case '\b' : cout << "\\b" ; break ;
case '\r' : cout << "\\r" ; break ;
case '\v' : cout << "\\v" ; break ;
case '\f' : cout << "\\f" ; break ;
case '\'' :
case '\\' :
case '{' :
case '}' :
case '[' :
case ']' :
case '$' :
case ';' :
case '"' :
cout << "\\" ; // fall thru to default
default :
cout << char(*value) ;
}
} //for
}
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.