summaryrefslogtreecommitdiff
path: root/utils/cli/ledgersmb_cli.pl
blob: 606cfac0654487c570ceaa851b37a7d8f6d5dccd (plain)
  1. #!/usr/bin/perl
  2. #===========================================================================
  3. #
  4. # LedgerSMB Command-line script host
  5. #
  6. #
  7. # LedgerSMB
  8. # Small Medium Business Accounting software
  9. # http://www.ledgersmb.org/
  10. #
  11. #
  12. # Copyright (C) 2006
  13. # This work contains copyrighted information from a number of sources all used
  14. # with permission. It is released under the GNU General Public License
  15. # Version 2 or, at your option, any later version. See COPYRIGHT file for
  16. # details.
  17. #
  18. # This is a simple wrapper that allows you to write simple scripts with LSMB
  19. # See sample for the file format.
  20. #
  21. # THIS IS EXPERIMENTAL AND THE INTERFACE IS SUBJECT TO CHANGE
  22. use Parse::RecDescent;
  23. use LedgerSMB::User;
  24. use LedgerSMB::Form;
  25. use LedgerSMB::Sysconfig;
  26. $form = new Form;
  27. $syntax = << '_END_SYNTAX_';
  28. KEY : /\w[a-z0-9_]*/i
  29. MODSTR : /\w[a-z0-9_:]*/i
  30. FNKEY : /(?:\w|:|\-\>)+/
  31. OP : m([-+*/%])
  32. NUMBER : /[+-]?\d*\.?\d+/
  33. ARGS : /(\w[a-z0-9_]*,?\s?)+/i
  34. expression : NUMBER OP expression
  35. { return main::expression(@item) }
  36. | KEY OP expression
  37. { return main::expression(@item) }
  38. | NUMBER
  39. | KEY
  40. assign_instruction : KEY "=" expression
  41. { main::assignval($item{KEY}, $item{expression}) }
  42. call_and_assign : /call/i FNKEY '(' ARGS ')' /into/i KEY
  43. { main::call_and_assign($item{FNKEY}, $item{ARGSTR}, $item{KEY}) }
  44. FUNCTIONCALL : /call/i FNKEY '(' ARGS ')'
  45. { main::call($item{FNKEY}, $item{ARGS});}
  46. for : /for/i KEY
  47. { main::push_loop($item{KEY}) }
  48. done : /^\s*done\s*$/
  49. { main::pop_loop() }
  50. if : /^\s*if/i KEY
  51. { main::if_handler($item{KEY}) }
  52. # IF is terminated by END IF or FI on its own line
  53. login : /login/i
  54. { main::login() }
  55. module : /module/i MODSTR
  56. { main::load_mod($item{MODSTR}) }
  57. instruction : assign_instruction
  58. | call_and_assign
  59. | FUNCTIONCALL
  60. | for
  61. | done
  62. | if
  63. | login
  64. | module
  65. startrule : instruction
  66. _END_SYNTAX_
  67. $::RD_HINT = 1;
  68. $::RD_ERRORS = 1; # Make sure the parser dies when it encounters an error
  69. $::RD_WARN = 1; # Enable warnings. This will warn on unused rules &c.`
  70. #$::RD_TRACE = 1;
  71. my @loopstack;
  72. my $loopindex;
  73. my $stackref;
  74. my @control_stack;
  75. push @loopstack, $form;
  76. sub assignval {
  77. my ( $key, $value ) = @_;
  78. if ( $key =~ /^ENV:/i ) {
  79. $ENV{$key} = $value;
  80. }
  81. else {
  82. %{ $loopstack[ $#loopstack - 1 ] }->{$key} = $value;
  83. }
  84. }
  85. sub expression {
  86. shift;
  87. my ( $lhs, $op, $rhs ) = @_;
  88. $lhs = $VARIABLE{$lhs} if $lhs =~ /[^-+0-9]/;
  89. return eval "$lhs $op $rhs";
  90. }
  91. sub call {
  92. my ( $call, $argstr ) = @_;
  93. $argstr =~ s/form/\\\%\$form/;
  94. $argstr =~ s/user/\\\%myconfig/;
  95. my @args = split /,\s/, $argstr;
  96. eval "$call($argstr);\n" || print STDERR $@ . "\n";
  97. }
  98. sub call_and_assign {
  99. my $key = pop;
  100. $stackref->{key} = call(@_);
  101. }
  102. sub push_loop {
  103. my $key = shift;
  104. my $is_hash = 0;
  105. if ( ref( $stackref->{$key} ) =~ /HASH/ ) {
  106. $is_hash = 1;
  107. }
  108. elsif ( ref( $stackref->{$key} ) !~ /ARRAY/ ) {
  109. print STDERR "Warning: Must loop through array or hash.";
  110. }
  111. push @loopstack, \$stackref->{$key};
  112. push @controlstack,
  113. {
  114. "key" => $key,
  115. 'index' => 0,
  116. 'linenum' => $#linestack,
  117. is_hash => $is_hash
  118. };
  119. }
  120. sub pop_loop {
  121. pop @loopstack;
  122. $stackref = \$loopstack[$#loopstack];
  123. }
  124. sub if_handler {
  125. my $key = shift;
  126. if ( !$stackref->{$key} ) {
  127. $if_count = 1;
  128. }
  129. }
  130. sub login {
  131. $myconfig = new LedgerSMB::User "${LedgerSMB::Sysconfig::memberfile}",
  132. "$form->{login}";
  133. $form->db_init($myconfig);
  134. }
  135. sub load_mod {
  136. my $mod = shift;
  137. $mod =~ s/::/\//;
  138. require "$mod.pm";
  139. }
  140. my $scriptparse = new Parse::RecDescent($syntax);
  141. $loopindex = 0;
  142. my @linestack;
  143. while ( $line = <> ) {
  144. push @linestack, $line;
  145. if ($if_count) {
  146. if ( $line =~ /^\s*IF\s/ ) {
  147. ++$if_count;
  148. }
  149. if ( $line =~ /^(\s*FI\s*|\s*END\s+IF\s*)$/ ) {
  150. --$if_count;
  151. }
  152. }
  153. next if ($if_count);
  154. $line =~ s/#.*$//; # strip comments
  155. $scriptparse->startrule($line);
  156. }
  157. delete $form->{password};
  158. for ( keys %$form ) {
  159. print "$_ = $form->{$_}\n";
  160. }