home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / cpp_libs / cmdline.lha / cmdline / src / cmd / shells.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-08-03  |  16.1 KB  |  774 lines

  1. //------------------------------------------------------------------------
  2. // ^FILE: shells.c - implement classes for the various Unix shells
  3. //
  4. // ^DESCRIPTION:
  5. //     This file packages all the information we need to know about each
  6. //  of the shells that cmdparse(1) will support into a set of (sub)classes.
  7. //
  8. // ^HISTORY:
  9. //    04/19/92    Brad Appleton    <brad@ssd.csd.harris.com>    Created
  10. //-^^---------------------------------------------------------------------
  11.  
  12. #include <stdlib.h>
  13. #include <iostream.h>
  14. #include <string.h>
  15. #include <ctype.h>
  16.  
  17. #include <fifolist.h>
  18.  
  19. #include "shells.h"
  20. #include "argtypes.h"
  21.  
  22. //--------------------------------------------------------------- ShellVariable
  23.  
  24. ShellVariable::ShellVariable(const char * name)
  25.    : var_name(name), var_value(NULL)
  26. {
  27. }
  28.  
  29. ShellVariable::~ShellVariable(void)
  30. {
  31. }
  32.  
  33. //------------------------------------------------------------ ShellArrayValues
  34.  
  35. DECLARE_FIFO_LIST(CharPtrList, char *);
  36.  
  37. struct  ShellArrayValues {
  38.    CharPtrList       list;
  39.    CharPtrListArray  array;
  40.  
  41.    ShellArrayValues(void);
  42. } ;
  43.  
  44. ShellArrayValues::ShellArrayValues(void)
  45.    : array(list)
  46. {
  47.    list.self_cleaning(1);
  48. }
  49.  
  50. //------------------------------------------------------------------ ShellArray
  51.  
  52. ShellArray::ShellArray(const char * name)
  53.    : array_name(name), array_value(NULL)
  54. {
  55. }
  56.  
  57. ShellArray::~ShellArray(void)
  58. {
  59.    delete  array_value ;
  60. }
  61.  
  62. void
  63. ShellArray::append(const char * value)
  64. {
  65.    if (array_value == NULL) {
  66.       array_value = new ShellArrayValues ;
  67.    }
  68.    char ** valptr = new char* ;
  69.    if (valptr) {
  70.       *valptr = (char *)value;
  71.       array_value->list.add(valptr);
  72.    }
  73. }
  74.  
  75. unsigned
  76. ShellArray::count(void) const
  77. {
  78.    return  ((array_value) ? array_value->list.count() : 0);
  79. }
  80.  
  81. const char *
  82. ShellArray::operator[](unsigned  index) const
  83. {
  84.    return  ((array_value) ? array_value->array[index] : NULL);
  85. }
  86.  
  87. //----------------------------------------------------------- AbstractUnixShell
  88.  
  89. AbstractUnixShell::~AbstractUnixShell(void)
  90. {
  91. }
  92.  
  93. //------------------------------------------------------------------- UnixShell
  94.  
  95. UnixShell::UnixShell(const char * shell_name)
  96.    : shell(NULL), valid(1)
  97. {
  98.    if (::strcmp(BourneShell::NAME, shell_name) == 0) {
  99.       shell = new BourneShell ;
  100.    } else if (::strcmp("ash", shell_name) == 0) {
  101.       shell = new BourneShell ;
  102.    } else if (::strcmp(KornShell::NAME, shell_name) == 0) {
  103.       shell = new KornShell ;
  104.    } else if (::strcmp(BourneAgainShell::NAME, shell_name) == 0) {
  105.       shell = new BourneAgainShell ;
  106.    } else if (::strcmp(CShell::NAME, shell_name) == 0) {
  107.       shell = new CShell ;
  108.    } else if (::strcmp("tcsh", shell_name) == 0) {
  109.       shell = new CShell ;
  110.    } else if (::strcmp("itcsh", shell_name) == 0) {
  111.       shell = new CShell ;
  112.    } else if (::strcmp(ZShell::NAME, shell_name) == 0) {
  113.       shell = new ZShell ;
  114.    } else if (::strcmp(Plan9Shell::NAME, shell_name) == 0) {
  115.       shell = new Plan9Shell ;
  116.    } else if (::strcmp(PerlShell::NAME, shell_name) == 0) {
  117.       shell = new PerlShell ;
  118.    } else if (::strcmp(TclShell::NAME, shell_name) == 0) {
  119.       shell = new TclShell ;
  120.    } else {
  121.       valid = 0;
  122.    }
  123. }
  124.  
  125. UnixShell::~UnixShell(void)
  126. {
  127.    delete  shell;
  128. }
  129.  
  130. const char *
  131. UnixShell::name(void) const
  132. {
  133.    return  ((shell) ? shell->name() : NULL);
  134. }
  135.  
  136. void
  137. UnixShell::unset_args(const char * name) const
  138. {
  139.    if (shell)  shell->unset_args(name);
  140. }
  141.  
  142. int
  143. UnixShell::is_positionals(const char * name) const
  144. {
  145.    return  ((shell) ? shell->is_positionals(name) : 0);
  146. }
  147.  
  148. void
  149. UnixShell::set(const ShellVariable & variable) const
  150. {
  151.    if (shell)  shell->set(variable);
  152. }
  153.  
  154. void
  155. UnixShell::set(const ShellArray & array, int variant) const
  156. {
  157.    if (shell)  shell->set(array, variant);
  158. }
  159.  
  160. //----------------------------------------------------------------- varname
  161.  
  162. // Remove any "esoteric" portions of a vraible name (such as a leading '$')
  163. //
  164. inline  static  const char *
  165. varname(const char * name, char skip)
  166. {
  167.    return  ((*name == skip) && (*(name + 1))) ? (name + 1): name ;
  168. }
  169.  
  170. //----------------------------------------------------------------- BourneShell
  171.  
  172. const char * BourneShell::NAME = "sh" ;
  173.  
  174. BourneShell::BourneShell(void)
  175. {
  176. }
  177.  
  178. BourneShell::~BourneShell(void)
  179. {
  180. }
  181.  
  182. const char *
  183. BourneShell::name(void) const
  184. {
  185.    return  BourneShell::NAME ;
  186. }
  187.  
  188. void
  189. BourneShell::unset_args(const char *) const
  190. {
  191.    cout << "shift $# ;" << endl ;
  192. }
  193.  
  194. int
  195. BourneShell::is_positionals(const char * name) const
  196. {
  197.    name = varname(name, '$');
  198.    return  ((::strcmp(name, "--") == 0) || (::strcmp(name, "-") == 0) ||
  199.             (::strcmp(name, "@") == 0)  || (::strcmp(name, "*") == 0)) ;
  200. }
  201.  
  202. void
  203. BourneShell::set(const ShellVariable & variable) const
  204. {
  205.    const char * name = varname(variable.name(), '$');
  206.    if (is_positionals(name)) {
  207.       cout << "set -- '" ;
  208.    } else {
  209.       cout << name << "='" ;
  210.    }
  211.    escape_value(variable.value());
  212.    cout << "';" << endl ;
  213. }
  214.  
  215. void
  216. BourneShell::set(const ShellArray & array, int variant) const
  217. {
  218.    int  ndx;
  219.    const char * name = varname(array.name(), '$');
  220.  
  221.    if (is_positionals(name)) {
  222.       // set -- 'arg1' 'arg2' ...
  223.       cout << "set -- ";
  224.       for (ndx = 0 ; ndx < array.count() ; ndx++) {
  225.          if (ndx)  cout << ' ' ;
  226.          cout << '\'' ;
  227.          escape_value(array[ndx]);
  228.          cout << '\'' ;
  229.       }
  230.       cout << ';' << endl ;
  231.    } else if (variant) {
  232.       // argname_count=N
  233.       // argname1='arg1'
  234.       //   ...
  235.       // argnameN='argN'
  236.       cout << name << "_count=" << array.count() << ';' << endl ;
  237.       for (ndx = 0 ; ndx < array.count() ; ndx++) {
  238.          cout << name << (ndx + 1) << "='";
  239.          escape_value(array[ndx]);
  240.          cout << "';" << endl ;
  241.       }
  242.    } else {
  243.       // argname='arg1 arg2 ...'
  244.       cout << name << "='";
  245.       for (ndx = 0 ; ndx < array.count() ; ndx++) {
  246.          if (ndx)  cout << ' ' ;
  247.          escape_value(array[ndx]);
  248.       }
  249.       cout << "';" << endl ;
  250.    }
  251. }
  252.  
  253. void
  254. BourneShell::escape_value(const char * value) const
  255. {
  256.    for ( ; *value ; value++) {
  257.       switch (*value) {
  258.       case '\'' :
  259.          cout << "'\\''" ;
  260.          break ;
  261.  
  262.       case '\\' :
  263.       case '\b' :
  264.       case '\r' :
  265.       case '\v' :
  266.       case '\f' :
  267.          cout << '\\' ;    // fall thru to default case
  268.       default :
  269.          cout << char(*value) ;
  270.       }
  271.    } //for
  272. }
  273.  
  274. //------------------------------------------------------------------- KornShell
  275.  
  276. const char * KornShell::NAME = "ksh" ;
  277.  
  278. KornShell::KornShell(void)
  279. {
  280. }
  281.  
  282. KornShell::~KornShell(void)
  283. {
  284. }
  285.  
  286. const char *
  287. KornShell::name(void) const
  288. {
  289.    return  KornShell::NAME ;
  290. }
  291.  
  292. void
  293. KornShell::unset_args(const char *) const
  294. {
  295.    cout << "set -- ;" << endl ;
  296. }
  297.  
  298. void
  299. KornShell::set(const ShellVariable & variable) const
  300. {
  301.    BourneShell::set(variable);
  302.  
  303. void
  304. KornShell::set(const ShellArray & array, int variant) const
  305. {
  306.    const char * name = varname(array.name(), '$');
  307.    if (is_positionals(name)) {
  308.       cout << "set -- " ;
  309.    } else {
  310.       cout << "set " << (variant ? '+' : '-') << "A " << name << ' ' ;
  311.    }
  312.    for (int  ndx = 0 ; ndx < array.count() ; ndx++) {
  313.       if (ndx)  cout << ' ' ;
  314.       cout << '\'' ;
  315.       escape_value(array[ndx]);
  316.       cout << '\'' ;
  317.    }
  318.    cout << ';' << endl ;
  319. }
  320.  
  321. //------------------------------------------------------------ BourneAgainShell
  322.  
  323. const char * BourneAgainShell::NAME = "bash" ;
  324.  
  325. BourneAgainShell::BourneAgainShell(void)
  326. {
  327. }
  328.  
  329. BourneAgainShell::~BourneAgainShell(void)
  330. {
  331. }
  332.  
  333. const char *
  334. BourneAgainShell::name(void) const
  335. {
  336.    return  BourneAgainShell::NAME ;
  337. }
  338.  
  339. void
  340. BourneAgainShell::set(const ShellVariable & variable) const
  341. {
  342.    BourneShell::set(variable);
  343.  
  344. void
  345. BourneAgainShell::set(const ShellArray & array, int variant) const
  346. {
  347.    BourneShell::set(array, variant);
  348. }
  349.  
  350. //---------------------------------------------------------------------- CShell
  351.  
  352. const char * CShell::NAME = "csh" ;
  353.  
  354. CShell::CShell(void)
  355. {
  356. }
  357.  
  358. CShell::~CShell(void)
  359. {
  360. }
  361.  
  362. const char *
  363. CShell::name(void) const
  364. {
  365.    return  CShell::NAME ;
  366. }
  367.  
  368. void
  369. CShell::unset_args(const char *) const
  370. {
  371.    cout << "set argv=();" << endl ;
  372. }
  373.  
  374. int
  375. CShell::is_positionals(const char * name) const
  376. {
  377.    name = varname(name, '$');
  378.    return  (::strcmp(name, "argv") == 0);
  379. }
  380.  
  381. void
  382. CShell::set(const ShellVariable & variable) const
  383. {
  384.    const char * name = varname(variable.name(), '$');
  385.    int  posl = is_positionals(name);
  386.    cout << "set " << name << '=' ;
  387.    if (posl)  cout << '(' ;
  388.    cout << '\'' ;
  389.    escape_value(variable.value());
  390.    cout << '\'' ;
  391.    if (posl)  cout << ')' ;
  392.    cout << ';' << endl ;;
  393. }
  394.  
  395. void
  396. CShell::set(const ShellArray & array, int ) const
  397. {
  398.    cout << "set " << varname(array.name(), '$') << "=(" ;
  399.    for (int  ndx = 0 ; ndx < array.count() ; ndx++) {
  400.       if (ndx)  cout << ' ' ;
  401.       cout << '\'' ;
  402.       escape_value(array[ndx]);
  403.       cout << '\'' ;
  404.    }
  405.    cout << ");" << endl ;
  406. }
  407.  
  408. void
  409. CShell::escape_value(const char * value) const
  410. {
  411.    for ( ; *value ; value++) {
  412.       switch (*value) {
  413.       case '\'' :
  414.          cout << "'\\''" ;
  415.          break ;
  416.  
  417.       case '!' :
  418.       case '\n' :
  419.       case '\b' :
  420.       case '\r' :
  421.       case '\v' :
  422.       case '\f' :
  423.          cout << '\\' ;    // fall thru to default case
  424.       default :
  425.          cout << char(*value) ;
  426.       }
  427.    } //for
  428. }
  429.  
  430. //---------------------------------------------------------------------- ZShell
  431.  
  432. const char * ZShell::NAME = "zsh" ;
  433.  
  434. ZShell::ZShell(void)
  435. {
  436. }
  437.  
  438. ZShell::~ZShell(void)
  439. {
  440. }
  441.  
  442. const char *
  443. ZShell::name(void) const
  444. {
  445.    return  ZShell::NAME ;
  446. }
  447.  
  448. void
  449. ZShell::unset_args(const char *) const
  450. {
  451.    cout << "argv=();" << endl ;
  452. }
  453.  
  454. int
  455. ZShell::is_positionals(const char * name) const
  456. {
  457.    name = varname(name, '$');
  458.    return  ((::strcmp(name, "--") == 0) || (::strcmp(name, "-") == 0) ||
  459.             (::strcmp(name, "@") == 0)  || (::strcmp(name, "*") == 0) ||
  460.             (::strcmp(name, "argv") == 0));
  461. }
  462.  
  463. void
  464. ZShell::set(const ShellVariable & variable) const
  465. {
  466.    const char * name = varname(variable.name(), '$');
  467.    int  posl = is_positionals(name);
  468.    cout << name << '=' ;
  469.    if (posl)  cout << '(' ;
  470.    cout << '\'' ;
  471.    escape_value(variable.value());
  472.    cout << '\'' ;
  473.    if (posl)  cout << ')' ;
  474.    cout << ';' << endl ;;
  475. }
  476.  
  477. void
  478. ZShell::set(const ShellArray & array, int ) const
  479. {
  480.    cout << varname(array.name(), '$') << "=(" ;
  481.    for (int  ndx = 0 ; ndx < array.count() ; ndx++) {
  482.       if (ndx)  cout << ' ' ;
  483.       cout << '\'' ;
  484.       escape_value(array[ndx]);
  485.       cout << '\'' ;
  486.    }
  487.    cout << ");" << endl ;
  488. }
  489.  
  490. void
  491. ZShell::escape_value(const char * value) const
  492. {
  493.    for ( ; *value ; value++) {
  494.       switch (*value) {
  495.       case '\'' :
  496.          cout << "'\\''" ;
  497.          break ;
  498.  
  499.       case '!' :
  500.       case '\\' :
  501.       case '\b' :
  502.       case '\r' :
  503.       case '\v' :
  504.       case '\f' :
  505.          cout << '\\' ;    // fall thru to default case
  506.       default :
  507.          cout << char(*value) ;
  508.       }
  509.    } //for
  510. }
  511.  
  512. //------------------------------------------------------------------ Plan9Shell
  513.  
  514. const char * Plan9Shell::NAME = "rc" ;
  515.  
  516. Plan9Shell::Plan9Shell(void)
  517. {
  518. }
  519.  
  520. Plan9Shell::~Plan9Shell(void)
  521. {
  522. }
  523.  
  524. const char *
  525. Plan9Shell::name(void) const
  526. {
  527.    return  Plan9Shell::NAME ;
  528. }
  529.  
  530. void
  531. Plan9Shell::unset_args(const char *) const
  532. {
  533.    cout << "*=();" << endl ;
  534. }
  535.  
  536. int
  537. Plan9Shell::is_positionals(const char * name) const
  538. {
  539.    name = varname(name, '$');
  540.    return  (::strcmp(name, "*") == 0);
  541. }
  542.  
  543. void
  544. Plan9Shell::set(const ShellVariable & variable) const
  545. {
  546.    const char * name = varname(variable.name(), '$');
  547.    int  posl = is_positionals(name);
  548.    cout << name << '=' ;
  549.    if (posl)  cout << '(' ;
  550.    cout << '\'' ;
  551.    escape_value(variable.value());
  552.    cout << '\'' ;
  553.    if (posl)  cout << ')' ;
  554.    cout << ';' << endl ;;
  555. }
  556.  
  557. void
  558. Plan9Shell::set(const ShellArray & array, int ) const
  559. {
  560.    cout << varname(array.name(), '$') << "=(" ;
  561.    for (int  ndx = 0 ; ndx < array.count() ; ndx++) {
  562.       if (ndx)  cout << ' ' ;
  563.       cout << '\'' ;
  564.       escape_value(array[ndx]);
  565.       cout << '\'' ;
  566.    }
  567.    cout << ");" << endl ;
  568. }
  569.  
  570. void
  571. Plan9Shell::escape_value(const char * value) const
  572. {
  573.    for ( ; *value ; value++) {
  574.       switch (*value) {
  575.       case '\'' :
  576.          cout << "''" ;
  577.          break ;
  578.  
  579.       case '\\' :
  580.       case '\b' :
  581.       case '\r' :
  582.       case '\v' :
  583.       case '\f' :
  584.          cout << '\\' ;    // fall thru to default case
  585.       default :
  586.          cout << char(*value) ;
  587.       }
  588.    } //for
  589. }
  590.  
  591. //------------------------------------------------------------------- PerlShell
  592.  
  593. const char * PerlShell::NAME = "perl" ;
  594.  
  595. PerlShell::PerlShell(void)
  596. {
  597.    static const char perl_true[]  = "1" ;
  598.    static const char perl_false[] = "0" ;
  599.  
  600.       // use different defaults for TRUE and FALSE
  601.    ShellCmdArgBool::True(perl_true);
  602.    ShellCmdArgBool::False(perl_false);
  603. }
  604.  
  605. PerlShell::~PerlShell(void)
  606. {
  607. }
  608.  
  609. const char *
  610. PerlShell::name(void) const
  611. {
  612.    return  PerlShell::NAME ;
  613. }
  614.  
  615. void
  616. PerlShell::unset_args(const char *) const
  617. {
  618.    cout << "@ARGV = ();" << endl ;
  619. }
  620.  
  621. int
  622. PerlShell::is_positionals(const char * name) const
  623. {
  624.    name = varname(name, '@');
  625.    return  (::strcmp(name, "ARGV") == 0);
  626. }
  627.  
  628. void
  629. PerlShell::set(const ShellVariable & variable) const
  630. {
  631.    const char * name = varname(variable.name(), '$');
  632.    int array = (*name == '@') ;
  633.    cout << (array ? "" : "$") << name << " = " ;
  634.    if (array)  cout << '(' ;
  635.    cout << '\'' ;
  636.    escape_value(variable.value());
  637.    cout << '\'' ;
  638.    if (array)  cout << ')' ;
  639.    cout << ';' << endl ;;
  640. }
  641.  
  642. void
  643. PerlShell::set(const ShellArray & array, int ) const
  644. {
  645.    const char * name = varname(array.name(), '@');
  646.    int scalar = (*name == '$') ;
  647.    cout << (scalar ? "" : "@") << name << " = " ;
  648.    cout << (scalar ? '\'' : '(') ;
  649.    for (int  ndx = 0 ; ndx < array.count() ; ndx++) {
  650.       if (ndx)  cout << (scalar ? " " : ", ") ;
  651.       if (! scalar)  cout << '\'' ;
  652.       escape_value(array[ndx]);
  653.       if (! scalar)  cout << '\'' ;
  654.    }
  655.    cout << (scalar ? '\'' : ')') ;
  656.    cout << ";" << endl ;
  657. }
  658.  
  659. void
  660. PerlShell::escape_value(const char * value) const
  661. {
  662.    for ( ; *value ; value++) {
  663.       switch (*value) {
  664.       case '\t' :  cout << "\\t" ; break ;
  665.       case '\n' :  cout << "\\n" ; break ;
  666.       case '\b' :  cout << "\\b" ; break ;
  667.       case '\r' :  cout << "\\r" ; break ;
  668.       case '\v' :  cout << "\\v" ; break ;
  669.       case '\f' :  cout << "\\f" ; break ;
  670.  
  671.       case '\'' :
  672.       case '\\' :
  673.          cout << "\\" ;    // fall thru to default
  674.       default :
  675.          cout << char(*value) ;
  676.       }
  677.    } //for
  678. }
  679.  
  680. //------------------------------------------------------------------- TclShell
  681.  
  682. const char * TclShell::NAME = "tcl" ;
  683.  
  684. TclShell::TclShell(void)
  685. {
  686.    static const char tcl_true[]  = "1" ;
  687.    static const char tcl_false[] = "0" ;
  688.  
  689.       // use different defaults for TRUE and FALSE
  690.    ShellCmdArgBool::True(tcl_true);
  691.    ShellCmdArgBool::False(tcl_false);
  692. }
  693.  
  694. TclShell::~TclShell(void)
  695. {
  696. }
  697.  
  698. const char *
  699. TclShell::name(void) const
  700. {
  701.    return  TclShell::NAME ;
  702. }
  703.  
  704. void
  705. TclShell::unset_args(const char * name) const
  706. {
  707.    cout << "set " << varname(name, '$') << " {};" << endl ;
  708. }
  709.  
  710. int
  711. TclShell::is_positionals(const char * name) const
  712. {
  713.    name = varname(name, '$');
  714.    return  ((::strcmp(name, "argv") == 0) || (::strcmp(name, "args") == 0));
  715. }
  716.  
  717. void
  718. TclShell::set(const ShellVariable & variable) const
  719. {
  720.    const char * name = varname(variable.name(), '$');
  721.    cout << "set " << name << ' ' ;
  722.    cout << '"' ;
  723.    escape_value(variable.value());
  724.    cout << '"' ;
  725.    cout << ';' << endl ;;
  726. }
  727.  
  728. void
  729. TclShell::set(const ShellArray & array, int ) const
  730. {
  731.    const char * name = varname(array.name(), '@');
  732.    int scalar = (*name == '$') ;
  733.    cout << "set " << name << " [ list " ;
  734.    for (int  ndx = 0 ; ndx < array.count() ; ndx++) {
  735.       if (ndx)  cout << ' ' ;
  736.       cout << '"' ;
  737.       escape_value(array[ndx]);
  738.       cout << '"' ;
  739.    }
  740.    cout << " ]" ;
  741.    cout << ";" << endl ;
  742. }
  743.  
  744. void
  745. TclShell::escape_value(const char * value) const
  746. {
  747.    for ( ; *value ; value++) {
  748.       switch (*value) {
  749.       case '\t' :  cout << "\\t" ; break ;
  750.       case '\n' :  cout << "\\n" ; break ;
  751.       case '\b' :  cout << "\\b" ; break ;
  752.       case '\r' :  cout << "\\r" ; break ;
  753.       case '\v' :  cout << "\\v" ; break ;
  754.       case '\f' :  cout << "\\f" ; break ;
  755.  
  756.       case '\'' :
  757.       case '\\' :
  758.       case '{' :
  759.       case '}' :
  760.       case '[' :
  761.       case ']' :
  762.       case '$' :
  763.       case ';' :
  764.       case '"' :
  765.          cout << "\\" ;    // fall thru to default
  766.       default :
  767.          cout << char(*value) ;
  768.       }
  769.    } //for
  770. }
  771.  
  772.