package my_gtk; # $Id$ use diagnostics; use strict; use vars qw(@ISA %EXPORT_TAGS @EXPORT_OK $border); @ISA = qw(Exporter); %EXPORT_TAGS = ( helpers => [ qw(create_okcancel createScrolledWindow create_menu create_notebook create_packtable create_hbox create_vbox create_adjustment create_box_with_title create_treeitem) ], wrappers => [ qw(gtksignal_connect gtkradio gtkpack gtkpack_ gtkpack__ gtkpack2 gtkpack2_ gtkpack2__ gtkpowerpack gtkset_editable gtksetstyle gtkset_tip gtkappenditems gtkappend gtkset_shadow_type gtkset_layout gtkset_relief gtkadd gtkput gtktext_insert gtkset_usize gtksize gtkset_justify gtkset_active gtkset_sensitive gtkset_visibility gtkset_modal gtkset_border_width gtkmove gtkresize gtkshow gtkhide gtkdestroy gtkcolor gtkset_mousecursor gtkset_mousecursor_normal gtkset_mousecursor_wait gtkset_background gtkset_default_fontset gtkctree_children gtkxpm gtkpng create_pix_text get_text_coord fill_tiled gtkicons_labels_widget write_on_pixmap gtkcreate_xpm gtkcreate_png gtkbuttonset create_pixbutton gtkroot gtkentry) ], ask => [ qw(ask_warn ask_okcancel ask_yesorno ask_from_entry ask_browse_tree_info ask_browse_tree_info_given_widgets ask_dir) ], various => [ qw(add_icon_path) ], ); $EXPORT_TAGS{all} = [ map { @$_ } values %EXPORT_TAGS ]; @EXPORT_OK = map { @$_ } values %EXPORT_TAGS; use ugtk qw(:helpers :wrappers :various); use common; use log; add_icon_path(@ugtk::icon_paths, "$ENV{SHARE_PATH}/libDrakX/pixmaps", '/usr/lib/libDrakX/icons', 'standalone/icons'); my $forgetTime = 1000; #- in milli-seconds $border = 5; #-############################################################################### #- OO stuff #-############################################################################### sub new { my ($type, $title, %opts) = @_; Gtk->set_locale; my $o = bless { %opts }, $type; $o->_create_window($title); while (my $e = shift @tempory::objects) { $e->destroy } foreach (@interactive::objects) { $_->{rwindow}->set_modal(0) if $_->{rwindow}->can('set_modal'); } push @interactive::objects, $o if !$opts{no_interactive_objects}; $o->{rwindow}->set_position('center_always') if $::isStandalone; $o->{rwindow}->set_modal(1) if $my_gtk::grab || $o->{grab}; if ($::isWizard && !$my_gtk::pop_it) { $o->{isWizard} = 1; $o->{window} = new Gtk::VBox(0,0); $o->{window}->set_border_width($::Wizard_splash ? 0 : 10); $o->{rwindow} = $o->{window}; if (!defined($::WizardWindow)) { $::WizardWindow = new Gtk::Window; $::WizardWindow->set_position('center_always'); $::WizardWindow->signal_connect(delete_event => sub { die 'wizcancel' }); $::WizardTable = new Gtk::Table(2, 2, 0); $::WizardWindow->add($::WizardTable); my $draw1 = new Gtk::DrawingArea; $draw1->set_usize(540,100); my $draw2 = new Gtk::DrawingArea; $draw2->set_usize(100,300); my ($im_up, $_mask_up) = gtkcreate_png($::Wizard_pix_up || "wiz_default_up.png"); my ($y1, $x1) = $im_up->get_size; my ($im_left, $_mask_left) = gtkcreate_png($::Wizard_pix_left || "wiz_default_left.png"); my ($y2, $x2) = $im_left->get_size; my $style = $draw1->style->copy; $style->font(Gtk::Gdk::Font->fontset_load(N("-adobe-utopia-regular-r-*-*-25-*-*-*-p-*-iso8859-*,*-r-*"))); $draw1->signal_connect(expose_event => sub { for (my $i = 0; $i < 540/$y1; $i++) { $draw1->window->draw_pixmap($draw1->style->bg_gc('normal'), $im_up, 0, 0, 0, $y1*$i, $x1, $y1); $draw1->window->draw_string( $style->font, $draw1->style->white_gc, 40, 62, ($::Wizard_title)); } }); $draw2->signal_connect(expose_event => sub { for (my $i = 0; $i < 300/$y2; $i++) { $draw2->window->draw_pixmap($draw2->style->bg_gc('normal'), $im_left, 0, 0, 0, $y2*$i, $x2, $y2); } }); $::WizardTable->attach($draw1, 0, 2, 0, 1, 'fill', 'fill', 0, 0); #- $::WizardTable->attach($draw2, 0, 1, 1, 2, 'fill', 'fill', 0, 0); $::WizardTable->set_usize(540,420); $::WizardWindow->show_all; flush(); } $::WizardTable->attach($o->{window}, 0, 2, 1, 2, ['fill', 'expand'], ['fill', 'expand'], 0, 0); } if ($::isEmbedded && !$my_gtk::pop_it && !eval { $::Plug && $::Plug->child }) { $o->{isEmbedded} = 1; $o->{window} = new Gtk::HBox(0,0); $o->{rwindow} = $o->{window}; $::Plug ||= new Gtk::Plug($::XID); $::Plug->show; flush(); $::Plug->add($o->{window}); } $o; } sub main { my ($o, $completed, $canceled) = @_; gtkset_mousecursor_normal(); my $timeout = Gtk->timeout_add(1000, sub { gtkset_mousecursor_normal(); 1 }); my $_b = MDK::Common::Func::before_leaving { Gtk->timeout_remove($timeout) }; $o->show; do { Gtk->main; } while ($o->{retval} ? $completed && !$completed->() : $canceled && !$canceled->()); $o->destroy; $o->{retval} } sub show($) { my ($o) = @_; $o->{window}->show; $o->{rwindow}->show; } sub destroy($) { my ($o) = @_; $o->{rwindow} and $o->{rwindow}->destroy; gtkset_mousecursor_wait(); flush(); } sub DESTROY { goto &destroy } sub sync { my ($o) = @_; show($o); flush(); } sub flush { gtkflush() } sub exit { gtkset_mousecursor_normal(); #- for restoring a normal in any case flush(); c::_exit($_[1]) #- workaround } #- in case "exit" above was not called by the program END { print "BUG in $0 : my_gtk->exit was *NOT* called !! \n"; &exit() } #-############################################################################### #- createXXX functions #- these functions return a widget #-############################################################################### sub create_okcancel { my ($w, $ok, $cancel, $spread, @other) = @_; $spread ||= $::isWizard ? "end" : "spread"; $cancel = $::isWizard ? N("<- Previous") : N("Cancel") if !defined $cancel && !defined $ok; $ok = $::isWizard ? ($::Wizard_finished ? N("Finish") : N("Next ->")) : N("Ok") if !defined $ok; my $b1 = gtksignal_connect($w->{ok} = new Gtk::Button($ok), clicked => $w->{ok_clicked} || sub { $w->{retval} = 1; Gtk->main_quit }); my $b2 = $cancel && gtksignal_connect($w->{cancel} = new Gtk::Button($cancel), clicked => $w->{cancel_clicked} || sub { log::l("default cancel_clicked"); undef $w->{retval}; Gtk->main_quit }); $::isWizard and gtksignal_connect($w->{wizcancel} = new Gtk::Button(N("Cancel")), clicked => sub { die 'wizcancel' }); my @l = grep { $_ } $::isWizard ? ($w->{wizcancel}, if_(!$::Wizard_no_previous, $b2, $b1)) : ($b1, $b2); push @l, map { gtksignal_connect(new Gtk::Button($_->[0]), clicked => $_->[1]) } @other; $_->can_default($::isWizard) foreach @l; gtkadd(create_hbox($spread), @l); } sub _create_window($$) { my ($o, $title) = @_; my $w = new Gtk::Window; my $gc = Gtk::Gdk::GC->new(gtkroot()); !$::isStandalone && !$::live && !$::g_auto_install and $my_gtk::shape_width = 3; #- $gc->set_foreground(gtkcolor(8448, 17664, 40191)); #- in hex : 33, 69, 157 $gc->set_foreground(gtkcolor(5120, 10752, 22784)); #- in hex : 20, 42, 89 #- $gc->set_foreground(gtkcolor(16896, 16896, 16896)); #- in hex : 66, 66, 66 my $inner = gtkadd(gtkset_shadow_type(new Gtk::Frame(undef), 'out'), my $f = gtkset_border_width(gtkset_shadow_type(new Gtk::Frame(undef), 'none'), 3) ); my $table; if ($::isStandalone || $::live || $::g_auto_install || $::noShadow) { gtkadd($w, $inner) if !$::noBorder } else { my $sqw = $my_gtk::shape_width; gtkadd($w, $table = new Gtk::Table(2, 2, 0)); $table->attach($inner, 0, 1, 0, 1, 1|4, 1|4, 0, 0); $table->attach(gtksignal_connect(gtkset_usize(new Gtk::DrawingArea, $sqw, 1), expose_event => sub { $_[0]->window->draw_rectangle($_[0]->style->bg_gc('normal'), 1, 0, 0, $sqw, $sqw); $_[0]->window->draw_rectangle($gc, 1, 0, $sqw, $sqw, $_[0]->allocation->[3]); }), 1, 2, 0, 1, 'fill', 'fill', 0, 0); $table->attach(gtksignal_connect(gtkset_usize(new Gtk::DrawingArea, 1, $sqw), expose_event => sub { $_[0]->window->draw_rectangle($_[0]->style->bg_gc('normal'), 1, 0, 0, $sqw, $sqw); $_[0]->window->draw_rectangle($gc, 1, $sqw, 0, $_[0]->allocation->[2], $sqw); }), 0, 1, 1, 2, 'fill', 'fill', 0, 0); $table->attach(gtksignal_connect(gtkset_usize(new Gtk::DrawingArea, $sqw, $sqw), expose_event => sub { $_[0]->window->draw_rectangle($gc, 1, 0, 0, $sqw, $sqw); }), 1, 2, 1, 2, 'fill', 'fill', 0, 0); $table->show_all; } $w->set_name("Title"); $w->set_title($title); $w->signal_connect(expose_event => sub { eval { $interactive::objects[-1]{rwindow} == $w and $w->window->XSetInputFocus } }) if $my_gtk::force_focus || $o->{force_focus}; $w->signal_connect(delete_event => sub { if ($::isWizard) { $w->destroy; die 'wizcancel' } else { Gtk->main_quit } }); $w->set_uposition(@{$my_gtk::force_position || $o->{force_position}}) if $my_gtk::force_position || $o->{force_position}; my $focusing; $w->signal_connect(focus => sub { return 1 if $focusing; $focusing = 1; Gtk->idle_add(sub { $w->ensure_focus($_[0]); $focusing = 0; 0 }, $_[1]); }) if $w->can('ensure_focus'); if ($::o->{mouse}{unsafe}) { $w->set_events("pointer_motion_mask"); my $signal; $signal = $w->signal_connect(motion_notify_event => sub { delete $::o->{mouse}{unsafe}; log::l("unsetting unsafe mouse"); $w->signal_disconnect($signal); }); } $w->signal_connect(key_press_event => sub { my $d = ${{ 0xffbe => 'help', 0xffbf => 'screenshot' }}{$_[1]{keyval}}; if ($d eq "help") { require install_gtk; install_gtk::create_big_help($::o); } elsif ($::isInstall && $d eq 'screenshot') { common::take_screenshot(); } elsif (chr($_[1]{keyval}) eq 'e' && $_[1]{state} & 8) { log::l("Switching to " . ($::expert ? "beginner" : "expert")); $::expert = !$::expert; } }); $w->signal_connect(size_allocate => sub { my ($wi, $he) = @{$_[1]}[2,3]; my ($X, $Y, $Wi, $He) = @{$my_gtk::force_center || $o->{force_center}}; $w->set_uposition(max(0, $X + ($Wi - $wi) / 2), max(0, $Y + ($He - $he) / 2)); if (!$::isStandalone && !$::live && !$::g_auto_install && !$::noShadow) { my $sqw = $my_gtk::shape_width; #square width my $wia = int(($wi+7)/8); my $s = "\xFF" x ($wia*$he); my $wib = $wia*8; my $dif = $wib-$wi; foreach my $y (0..$sqw-1) { vec($s, $wib-1-$dif-$_+$wib*$y, 1) = 0x0 foreach 0..$sqw-1 } foreach my $y (0..$sqw-1) { vec($s, (($he-1)*$wib)-$wib*$y+$_, 1) = 0x0 foreach 0..$sqw-1 } $w->realize; my $b = Gtk::Gdk::Bitmap->create_from_data($w->window, $s, $wib, $he); $w->window->shape_combine_mask($b, 0, 0); } }) if ($my_gtk::force_center || $o->{force_center}) && !($my_gtk::force_position || $o->{force_position}); $o->{window} = $::noBorder ? $w : $f; $o->{rwindow} = $w; $table and $table->draw(undef); } #-############################################################################### #- ask_XXX #- just give a title and some args, and it will return the value given by the user #-############################################################################### sub ask_warn { my $w = my_gtk->new(shift @_); $w->_ask_warn(@_); main($w) } sub ask_yesorno { my $w = my_gtk->new(shift @_); $w->_ask_okcancel(@_, N("Yes"), N("No")); main($w) } sub ask_okcancel { my $w = my_gtk->new(shift @_); $w->_ask_okcancel(@_, N("Is this correct?"), N("Ok"), N("Cancel")); main($w) } sub ask_from_entry { my $w = my_gtk->new(shift @_); $w->_ask_from_entry(@_); main($w) } sub ask_dir { my $w = my_gtk->new(shift @_); $w->_ask_dir(@_); main($w) } sub _ask_from_entry($$@) { my ($o, @msgs) = @_; my $entry = new Gtk::Entry; my $f = sub { $o->{retval} = $entry->get_text; Gtk->main_quit }; $o->{ok_clicked} = $f; $o->{cancel_clicked} = sub { undef $o->{retval}; Gtk->main_quit }; gtkadd($o->{window}, gtkpack($o->create_box_with_title(@msgs), gtksignal_connect($entry, 'activate' => $f), ($o->{hide_buttons} ? () : create_okcancel($o))), ); $entry->grab_focus; } sub _ask_warn($@) { my ($o, @msgs) = @_; gtkadd($o->{window}, gtkpack($o->create_box_with_title(@msgs), gtksignal_connect(my $w = new Gtk::Button(N("Ok")), "clicked" => sub { Gtk->main_quit }), ), ); $w->grab_focus; } sub _ask_okcancel($@) { my ($o, @msgs) = @_; my ($ok, $cancel) = splice @msgs, -2; gtkadd($o->{window}, gtkpack(create_box_with_title($o, @msgs), create_okcancel($o, $ok, $cancel), ) ); $o->{ok}->grab_focus; } sub _ask_file { my ($o, $title, $path) = @_; my $f = $o->{rwindow} = new Gtk::FileSelection($title); $f->set_filename($path); $f->ok_button->signal_connect(clicked => sub { $o->{retval} = $f->get_filename; Gtk->main_quit }); $f->cancel_button->signal_connect(clicked => sub { Gtk->main_quit }); $f->hide_fileop_buttons; $f; } sub _ask_dir { my $f = _ask_file(@_); $f->file_list->parent->hide; $f->selection_entry->parent->hide; } sub ask_browse_tree_info { my ($common) = @_; my $w = my_gtk->new($common->{title}); my $tree = Gtk::CTree->new(3, 0); $tree->set_selection_mode('browse'); $tree->set_column_auto_resize($_, 1) foreach 1..2; $tree->set_column_width(0, 200); gtkadd($w->{window}, gtkpack_(new Gtk::VBox(0,5), 0, $common->{message}, 1, gtkpack(new Gtk::HBox(0,0), createScrolledWindow($tree), gtkadd(gtkset_usize(new Gtk::Frame(N("Info")), $::windowwidth - 490, 0), createScrolledWindow(my $info = new Gtk::Text), )), 0, my $l = new Gtk::HBox(0,15), 0, gtkpack(new Gtk::HBox(0,10), my $go = gtksignal_connect(new Gtk::Button($common->{ok}), "clicked" => sub { $w->{retval} = 1; Gtk->main_quit }), $common->{cancel} ? gtksignal_connect(new Gtk::Button($common->{cancel}), "clicked" => sub { $w->{retval} = 0; Gtk->main_quit }) : (), ) )); gtkpack__($l, my $toolbar = new Gtk::Toolbar('horizontal', 'icons')); if ($common->{auto_deps}) { gtkpack__($l, gtksignal_connect(gtkset_active(new Gtk::CheckButton($common->{auto_deps}), $common->{state}{auto_deps}), clicked => sub { invbool \$common->{state}{auto_deps} })); } $l->pack_end(my $status = new Gtk::Label, 0, 1, 20); $w->{window}->set_usize(map { $_ - 2 * $my_gtk::border - 4 } $::windowwidth, $::windowheight); $go->grab_focus; $w->{rwindow}->show_all; my @toolbar = (ftout => [ N("Expand Tree"), sub { $tree->expand_recursive(undef) } ], ftin => [ N("Collapse Tree"), sub { $tree->collapse_recursive(undef) } ], reload => [ N("Toggle between flat and group sorted"), sub { invbool(\$common->{state}{flat}); $common->{rebuild_tree}->() } ]); foreach my $ic (@{$common->{icons} || []}) { push @toolbar, ($ic->{icon} => [ $ic->{help}, sub { if ($ic->{code}) { my $_w = $ic->{wait_message} && $common->{wait_message}->('', $ic->{wait_message}); $ic->{code}(); $common->{rebuild_tree}->(); } } ]); } my %toolbar = @toolbar; $toolbar->set_button_relief("none"); foreach (grep_index { $::i % 2 == 0 } @toolbar) { gtksignal_connect($toolbar->append_item(undef, $toolbar{$_}[0], undef, gtkpng("$_.png")), clicked => $toolbar{$_}[1]); } $toolbar->set_style("icons"); my $widgets = { w => $w, tree => $tree, info => $info, status => $status }; ask_browse_tree_info_given_widgets($common, $widgets); } sub ask_browse_tree_info_given_widgets { my ($common, $w) = @_; my ($curr, $parent, $prev_label, $idle); my (%wtree, %ptree, %pix); my $update_size = sub { my $new_label = $common->{get_status}(); $prev_label ne $new_label and $w->{status}->set($prev_label = $new_label); }; my $set_node_state_flat = sub { my ($node, $state) = @_; $state eq 'XXX' and return; $pix{$state} ||= [ gtkcreate_png($state) ]; $w->{tree}->node_set_pixmap($node, 1, $pix{$state}[0], $pix{$state}[1]); }; my $set_node_state_tree; $set_node_state_tree = sub { my ($node, $state) = @_; $state eq 'XXX' and return; $pix{$state} ||= [ gtkcreate_png($state) ]; if ($node->{state} ne $state) { if ($node->row->is_leaf) { my $parent = $node->row->parent; my $stats = $parent->{state_stats} ||= {}; --$stats->{$node->{state}}; ++$stats->{$state}; my @list = grep { $stats->{$_} > 0 } keys %$stats; my $new_state = @list == 1 ? $list[0] : 'semiselected'; $parent->{state} ne $new_state and $set_node_state_tree->($parent, $new_state); } $w->{tree}->node_set_pixmap($node, 1, $pix{$state}[0], $pix{$state}[1]); $node->{state} = $state; #- hack to to get this features efficiently. } }; my $set_node_state = $common->{state}{flat} ? $set_node_state_flat : $set_node_state_tree; my $set_leaf_state = sub { my ($leaf, $state) = @_; $set_node_state->($_, $state) foreach @{$ptree{$leaf}}; }; my $add_parent; $add_parent = sub { my ($root, $state) = @_; $root or return undef; if (my $w = $wtree{$root}) { return $w } my $s; foreach (split '\|', $root) { my $s2 = $s ? "$s|$_" : $_; $wtree{$s2} ||= do { my $n = $w->{tree}->insert_node($s ? $add_parent->($s, $state) : undef, undef, [$_, '', ''], 5, (undef) x 4, 0, 0); $n; }; $s = $s2; } $set_node_state->($wtree{$s}, $state); #- use this state by default as tree is building. $wtree{$s}; }; my $add_node = sub { my ($leaf, $root, $options) = @_; my $state = $common->{node_state}($leaf) or return; if ($leaf) { my $node = $w->{tree}->insert_node($add_parent->($root, $state), undef, [$leaf, '', ''], 5, (undef) x 4, 1, 0); $set_node_state->($node, $state); push @{$ptree{$leaf}}, $node; } else { my $parent = $add_parent->($root, $state); #- hackery for partial displaying of trees, used in rpmdrake: #- if leaf is void, we may create the parent and one child (to have the [+] in front of the parent in the ctree) #- though we use '' as the label of the child; then rpmdrake will connect on tree_expand, and whenever #- the first child has '' as the label, it will remove the child and add all the "right" children $options->{nochild} or $w->{tree}->insert_node($parent, undef, ['', '', ''], 5, (undef) x 4, 1, 0); } }; $common->{delete_all} = sub { foreach (values %ptree) { delete $_->{state} foreach @$_; } foreach (values %wtree) { delete $_->{state}; delete $_->{state_stats}; } %ptree = %wtree = (); $w->{tree}->freeze; $w->{tree}->clear; $w->{tree}->thaw; }; $common->{rebuild_tree} = sub { $common->{delete_all}->(); $set_node_state = $common->{state}{flat} ? $set_node_state_flat : $set_node_state_tree; $w->{tree}->freeze; $common->{build_tree}($add_node, $common->{state}{flat}, $common->{tree_mode}); $w->{tree}->thaw; &$update_size; }; $common->{delete_category} = sub { my ($cat) = @_; exists $wtree{$cat} or return; $w->{tree}->freeze; foreach (keys %ptree) { my @to_remove; foreach my $node (@{$ptree{$_}}) { my $category; my $parent = $node; while ($parent->row->parent) { $parent = $parent->row->parent; my $parent_name = ($w->{tree}->node_get_pixtext($parent, 0))[0]; $category = $category ? "$parent_name|$category" : $parent_name; } $cat eq $category and push @to_remove, $node; } delete $_->{state} foreach @to_remove; @{$ptree{$_}} = difference2($ptree{$_}, \@to_remove); } if (exists $wtree{$cat}) { delete $wtree{$cat}{$_} foreach qw(state state_stats); $w->{tree}->remove_node($wtree{$cat}); delete $wtree{$cat}; } $w->{tree}->thaw; &$update_size; }; $common->{add_nodes} = sub { my (@nodes) = @_; $w->{tree}->freeze; $add_node->($_->[0], $_->[1], $_->[2]) foreach @nodes; $w->{tree}->thaw; &$update_size; }; $common->{display_info} = sub { gtktext_insert($w->{info}, $common->{get_info}($curr)); 0 }; my $children = sub { map { ($w->{tree}->node_get_pixtext($_, 0))[0] } gtkctree_children($_[0]) }; my $toggle = sub { if (ref $curr && ! $_[0]) { $w->{tree}->toggle_expansion($curr); } else { if (ref $curr) { my @l = $common->{grep_allowed_to_toggle}($children->($curr)) or return; my @unsel = $common->{grep_unselected}(@l); my @p = @unsel ? #- not all is selected, select all if no option to potentially override (exists $common->{partialsel_unsel} && $common->{partialsel_unsel}->(\@unsel, \@l) ? difference2(\@l, \@unsel) : @unsel) : @l; $common->{toggle_nodes}($set_leaf_state, @p); &$update_size; $parent = $curr; } else { $common->{check_interactive_to_toggle}($curr) and $common->{toggle_nodes}($set_leaf_state, $curr); &$update_size; } } }; $w->{tree}->signal_connect(key_press_event => sub { my ($_w, $e) = @_; my $c = chr($e->{keyval} & 0xff); $toggle->(0) if $e->{keyval} >= 0x100 ? $c eq "\r" || $c eq "\x8d" : $c eq ' '; 1; }); $w->{tree}->signal_connect(tree_select_row => sub { Gtk->timeout_remove($idle) if $idle; if ($_[1]->row->is_leaf) { ($curr) = $w->{tree}->node_get_pixtext($_[1], 0); $parent = $_[1]->row->parent; $idle = Gtk->timeout_add(100, $common->{display_info}); } else { $curr = $_[1]; } $toggle->(1) if $_[2] == 1; }); $common->{rebuild_tree}->(); &$update_size; my $_b = before_leaving { #- ensure cleaning here. foreach (values %ptree) { delete $_->{state} foreach @$_; } foreach (values %wtree) { delete $_->{state}; delete $_->{state_stats}; } }; $w->{w}->main; } 1; #-############################################################################### #- rubbish #-############################################################################### #-sub label_align($$) { #- my $w = shift; #- local $_ = shift; #- $w->set_alignment(!/W/i, !/N/i); #- $w #-} s='add'>mdk-stage1/slang/slarith.inc783
-rw-r--r--mdk-stage1/slang/slarray.c3139
-rw-r--r--mdk-stage1/slang/slarrfun.c464
-rw-r--r--mdk-stage1/slang/slarrfun.inc257
-rw-r--r--mdk-stage1/slang/slarrmis.c38
-rw-r--r--mdk-stage1/slang/slassoc.c713
-rw-r--r--mdk-stage1/slang/slbstr.c615
-rw-r--r--mdk-stage1/slang/slclass.c1391
-rw-r--r--mdk-stage1/slang/slcmd.c351
-rw-r--r--mdk-stage1/slang/slcmplex.c1142
-rw-r--r--mdk-stage1/slang/slcompat.c34
-rw-r--r--mdk-stage1/slang/slcurses.c972
-rw-r--r--mdk-stage1/slang/slcurses.h353
-rw-r--r--mdk-stage1/slang/sldisply.c2596
-rw-r--r--mdk-stage1/slang/slerr.c181
-rw-r--r--mdk-stage1/slang/slerrno.c219
-rw-r--r--mdk-stage1/slang/slgetkey.c306
-rw-r--r--mdk-stage1/slang/slimport.c281
-rw-r--r--mdk-stage1/slang/slinclud.h26
-rw-r--r--mdk-stage1/slang/slintall.c27
-rw-r--r--mdk-stage1/slang/slistruc.c218
-rw-r--r--mdk-stage1/slang/slkeymap.c596
-rw-r--r--mdk-stage1/slang/slkeypad.c163
-rw-r--r--mdk-stage1/slang/sllimits.h64
-rw-r--r--mdk-stage1/slang/slmalloc.c165
-rw-r--r--mdk-stage1/slang/slmath.c565
-rw-r--r--mdk-stage1/slang/slmemchr.c47
-rw-r--r--mdk-stage1/slang/slmemcmp.c76
-rw-r--r--mdk-stage1/slang/slmemcpy.c49
-rw-r--r--mdk-stage1/slang/slmemset.c39
-rw-r--r--mdk-stage1/slang/slmisc.c330
-rw-r--r--mdk-stage1/slang/slnspace.c242
-rw-r--r--mdk-stage1/slang/slospath.c73
-rw-r--r--mdk-stage1/slang/slpack.c785
-rw-r--r--mdk-stage1/slang/slparse.c1970
-rw-r--r--mdk-stage1/slang/slpath.c344
-rw-r--r--mdk-stage1/slang/slposdir.c1057
-rw-r--r--mdk-stage1/slang/slposio.c568
-rw-r--r--mdk-stage1/slang/slprepr.c427
-rw-r--r--mdk-stage1/slang/slproc.c155
-rw-r--r--mdk-stage1/slang/slregexp.c935
-rw-r--r--mdk-stage1/slang/slrline.c836
-rw-r--r--mdk-stage1/slang/slscanf.c718
-rw-r--r--mdk-stage1/slang/slscroll.c450
-rw-r--r--mdk-stage1/slang/slsearch.c239
-rw-r--r--mdk-stage1/slang/slsignal.c336
-rw-r--r--mdk-stage1/slang/slsmg.c1584
-rw-r--r--mdk-stage1/slang/slstd.c724
-rw-r--r--mdk-stage1/slang/slstdio.c1050
-rw-r--r--mdk-stage1/slang/slstring.c546
-rw-r--r--mdk-stage1/slang/slstrops.c1686
-rw-r--r--mdk-stage1/slang/slstruct.c932
-rw-r--r--mdk-stage1/slang/sltermin.c1155
-rw-r--r--mdk-stage1/slang/sltime.c310
-rw-r--r--mdk-stage1/slang/sltoken.c1702
-rw-r--r--mdk-stage1/slang/sltypes.c966
-rw-r--r--mdk-stage1/slang/slutty.c596
-rw-r--r--mdk-stage1/slang/slxstrng.c43
86 files changed, 52622 insertions, 13 deletions
diff --git a/mdk-stage1/Makefile b/mdk-stage1/Makefile
index 9a3ecae43..96eade486 100644
--- a/mdk-stage1/Makefile
+++ b/mdk-stage1/Makefile
@@ -47,22 +47,17 @@ INITOBJS = $(subst .c,.o,$(INITSRC))
#- frontends
NEWT_FRONTEND_SRC = newt-frontend.c
-NEWT_FRONTEND_LIBS = /usr/lib/libnewt.a /usr/lib/libslang.a
+GLIBC_NEWT_FRONTEND_LIBS = newt/libnewt.a slang/libslang.a
+DIETLIBC_NEWT_FRONTEND_LIBS = $(subst .a,-DIET.a,$(GLIBC_NEWT_FRONTEND_LIBS))
STDIO_FRONTEND_SRC = stdio-frontend.c
-STDIO_FRONTEND_LIBS =
+GLIBC_STDIO_FRONTEND_LIBS =
+DIETLIBC_STDIO_FRONTEND_LIBS =
FRONTEND_OBJS = $(subst .c,.o,$($(F)_FRONTEND_SRC))
-FRONTEND_LIBS = $($(F)_FRONTEND_LIBS)
-FRONTEND_LINK = $(FRONTEND_OBJS) $(FRONTEND_LIBS)
-
-ifeq (DIETLIBC, $(L))
-ifeq (NEWT, $(F))
-FRONTEND_LINK = $(subst .c,.o,$(STDIO_FRONTEND_SRC)) $(STDIO_FRONTEND_LIBS)
-endif
-endif
+FRONTEND_LINK = $(FRONTEND_OBJS) $($(L)_$(F)_FRONTEND_LIBS)
ifeq (i386, $(ARCH))
INSMOD = insmod-busybox
@@ -71,7 +66,7 @@ INSMOD = insmod-modutils
endif
GLIBC_STAGE1_OWN_LIBS = $(INSMOD)/libinsmod.a mar/libmar.a bzlib/libbzlib.a
-DIETLIBC_STAGE1_OWN_LIBS = $(INSMOD)/libinsmod-DIET.a mar/libmar-DIET.a bzlib/libbzlib-DIET.a
+DIETLIBC_STAGE1_OWN_LIBS = $(subst .a,-DIET.a,$(GLIBC_STAGE1_OWN_LIBS))
STAGE1_OWN_LIBS = $($(L)_STAGE1_OWN_LIBS)
@@ -125,7 +120,7 @@ BINS += stage1-cdrom stage1-disk stage1-network
endif
-DIRS = dietlibc mar pci-resource bzlib $(INSMOD)
+DIRS = dietlibc mar pci-resource bzlib $(INSMOD) slang newt
ifeq (i386,$(ARCH))
DIRS += pcmcia
endif
diff --git a/mdk-stage1/newt-frontend.c b/mdk-stage1/newt-frontend.c
index 85f56ec10..867a6d7f1 100644
--- a/mdk-stage1/newt-frontend.c
+++ b/mdk-stage1/newt-frontend.c
@@ -33,7 +33,7 @@
#include <sys/time.h>
#include "stage1.h"
#include "log.h"
-#include "newt.h"
+#include "newt/newt.h"
#include "frontend.h"
diff --git a/mdk-stage1/newt/Makefile b/mdk-stage1/newt/Makefile
new file mode 100644
index 000000000..c4e6a7207
--- /dev/null
+++ b/mdk-stage1/newt/Makefile
@@ -0,0 +1,49 @@
+ #******************************************************************************
+ #
+ # Guillaume Cottenceau (gc@mandrakesoft.com)
+ #
+ # Copyright 2000 MandrakeSoft
+ #
+ # This software may be freely redistributed under the terms of the GNU
+ # public license.
+ #
+ # You should have received a copy of the GNU General Public License
+ # along with this program; if not, write to the Free Software
+ # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ #
+ #*****************************************************************************
+
+top_dir = ..
+
+include $(top_dir)/Makefile.common
+
+
+all: libnewt.a libnewt-DIET.a
+
+clean:
+ rm -f *.o *.a
+
+FLAGS = -Wall -Werror -Os -fomit-frame-pointer -DVERSION=\"0.50.19\" -c
+
+INCS = -I../slang
+
+
+OBJS = newt.o button.o form.o checkbox.o entry.o label.o listbox.o scrollbar.o textbox.o scale.o grid.o windows.o buttonbar.o checkboxtree.o
+OBJS-DIET = $(subst .o,-DIET.o,$(OBJS))
+
+
+libnewt.a: $(OBJS)
+ ar -cru $@ $^
+ ranlib $@
+
+libnewt-DIET.a: $(OBJS-DIET)
+ ar -cru $@ $^
+ ranlib $@
+
+
+$(OBJS): %.o: %.c
+ gcc $(FLAGS) $(GLIBC_INCLUDES) $(INCS) -c $< -o $@
+
+$(OBJS-DIET): %-DIET.o: %.c
+ gcc $(FLAGS) $(DIETLIBC_INCLUDES) $(INCS) -c $< -o $@
+
diff --git a/mdk-stage1/newt/button.c b/mdk-stage1/newt/button.c
new file mode 100644
index 000000000..1ff360dc5
--- /dev/null
+++ b/mdk-stage1/newt/button.c
@@ -0,0 +1,190 @@
+#include <slang.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "newt.h"
+#include "newt_pr.h"
+
+struct button {
+ char * text;
+ int compact;
+};
+
+static void buttonDrawIt(newtComponent co, int active, int pushed);
+static void buttonDrawText(newtComponent co, int active, int pushed);
+
+static void buttonDraw(newtComponent c);
+static void buttonDestroy(newtComponent co);
+static struct eventResult buttonEvent(newtComponent c,
+ struct event ev);
+static void buttonPlace(newtComponent co, int newLeft, int newTop);
+
+static struct componentOps buttonOps = {
+ buttonDraw,
+ buttonEvent,
+ buttonDestroy,
+ buttonPlace,
+ newtDefaultMappedHandler,
+} ;
+
+static newtComponent createButton(int left, int row, const char * text, int compact) {
+ newtComponent co;
+ struct button * bu;
+
+ co = malloc(sizeof(*co));
+ bu = malloc(sizeof(struct button));
+ co->data = bu;
+
+ bu->text = strdup(text);
+ bu->compact = compact;
+ co->ops = &buttonOps;
+
+ if (bu->compact) {
+ co->height = 1;
+ co->width = strlen(text) + 3;
+ } else {
+ co->height = 4;
+ co->width = strlen(text) + 5;
+ }
+
+ co->top = row;
+ co->left = left;
+ co->takesFocus = 1;
+ co->isMapped = 0;
+
+ newtGotorc(co->top, co->left);
+
+ return co;
+}
+
+newtComponent newtCompactButton(int left, int row, const char * text) {
+ return createButton(left, row, text, 1);
+}
+
+newtComponent newtButton(int left, int row, const char * text) {
+ return createButton(left, row, text, 0);
+}
+
+static void buttonDestroy(newtComponent co) {
+ struct button * bu = co->data;
+
+ free(bu->text);
+ free(bu);
+ free(co);
+}
+
+static void buttonPlace(newtComponent co, int newLeft, int newTop) {
+ co->top = newTop;
+ co->left = newLeft;
+
+ newtGotorc(co->top, co->left);
+}
+
+static void buttonDraw(newtComponent co) {
+ buttonDrawIt(co, 0, 0);
+}
+
+static void buttonDrawIt(newtComponent co, int active, int pushed) {
+ struct button * bu = co->data;
+
+ if (!co->isMapped) return;
+
+ SLsmg_set_color(NEWT_COLORSET_BUTTON);
+
+ if (bu->compact) {
+ if (active)
+ SLsmg_set_color(NEWT_COLORSET_COMPACTBUTTON);
+ else
+ SLsmg_set_color(NEWT_COLORSET_BUTTON);
+ newtGotorc(co->top+ pushed, co->left + 1 + pushed);
+ SLsmg_write_char('<');
+ SLsmg_write_string(bu->text);
+ SLsmg_write_char('>');
+ } else {
+ if (pushed) {
+ SLsmg_set_color(NEWT_COLORSET_BUTTON);
+ newtDrawBox(co->left + 1, co->top + 1, co->width - 1, 3, 0);
+
+ SLsmg_set_color(NEWT_COLORSET_WINDOW);
+ newtClearBox(co->left, co->top, co->width, 1);
+ newtClearBox(co->left, co->top, 1, co->height);
+ } else {
+ newtDrawBox(co->left, co->top, co->width - 1, 3, 1);
+ }
+
+ buttonDrawText(co, active, pushed);
+ }
+}
+
+static void buttonDrawText(newtComponent co, int active, int pushed) {
+ struct button * bu = co->data;
+
+ if (pushed) pushed = 1;
+
+ if (active)
+ SLsmg_set_color(NEWT_COLORSET_ACTBUTTON);
+ else
+ SLsmg_set_color(NEWT_COLORSET_BUTTON);
+
+ newtGotorc(co->top + 1 + pushed, co->left + 1 + pushed);
+ SLsmg_write_char(' ');
+ SLsmg_write_string(bu->text);
+ SLsmg_write_char(' ');
+}
+
+static struct eventResult buttonEvent(newtComponent co,
+ struct event ev) {
+ struct eventResult er;
+ struct button * bu = co->data;
+
+ if (ev.when == EV_NORMAL) {
+ switch (ev.event) {
+ case EV_FOCUS:
+ buttonDrawIt(co, 1, 0);
+ er.result = ER_SWALLOWED;
+ break;
+
+ case EV_UNFOCUS:
+ buttonDrawIt(co, 0, 0);
+ er.result = ER_SWALLOWED;
+ break;
+
+ case EV_KEYPRESS:
+ if (ev.u.key == ' ' || ev.u.key == '\r') {
+ if (!bu->compact) {
+ /* look pushed */
+ buttonDrawIt(co, 1, 1);
+ newtRefresh();
+ newtDelay(150000);
+ buttonDrawIt(co, 1, 0);
+ newtRefresh();
+ newtDelay(150000);
+ }
+
+ er.result = ER_EXITFORM;
+ } else
+ er.result = ER_IGNORED;
+ break;
+ case EV_MOUSE:
+ if (ev.u.mouse.type == MOUSE_BUTTON_DOWN &&
+ co->top <= ev.u.mouse.y &&
+ co->top + co->height - !bu->compact > ev.u.mouse.y &&
+ co->left <= ev.u.mouse.x &&
+ co->left + co->width - !bu->compact > ev.u.mouse.x) {
+ if (!bu->compact) {
+ buttonDrawIt(co, 1, 1);
+ newtRefresh();
+ newtDelay(150000);
+ buttonDrawIt(co, 1, 0);
+ newtRefresh();
+ newtDelay(150000);
+ }
+ er.result = ER_EXITFORM;
+ }
+ break;
+ }
+ } else
+ er.result = ER_IGNORED;
+
+ return er;
+}
diff --git a/mdk-stage1/newt/buttonbar.c b/mdk-stage1/newt/buttonbar.c
new file mode 100644
index 000000000..45473c9d2
--- /dev/null
+++ b/mdk-stage1/newt/buttonbar.c
@@ -0,0 +1,46 @@
+#include <stdarg.h>
+
+#include "newt.h"
+
+/* if they try and pack more then 50 buttons, screw 'em */
+newtGrid newtButtonBarv(char * button1, newtComponent * b1comp, va_list args) {
+ newtGrid grid;
+ struct buttonInfo {
+ char * name;
+ newtComponent * compPtr;
+ } buttons[50];
+ int num;
+ int i;
+
+ buttons[0].name = button1, buttons[0].compPtr = b1comp, num = 1;
+ while (1) {
+ buttons[num].name = va_arg(args, char *);
+ if (!buttons[num].name) break;
+ buttons[num].compPtr = va_arg(args, newtComponent *);
+ num++;
+ }
+
+ grid = newtCreateGrid(num, 1);
+
+ for (i = 0; i < num; i++) {
+ *buttons[i].compPtr = newtButton(-1, -1, buttons[i].name);
+ newtGridSetField(grid, i, 0, NEWT_GRID_COMPONENT,
+ *buttons[i].compPtr,
+ num ? 1 : 0, 0, 0, 0, 0, 0);
+ }
+
+ return grid;
+}
+
+newtGrid newtButtonBar(char * button1, newtComponent * b1comp, ...) {
+ va_list args;
+ newtGrid grid;
+
+ va_start(args, b1comp);
+
+ grid = newtButtonBarv(button1, b1comp, args);
+
+ va_end(args);
+
+ return grid;
+}
diff --git a/mdk-stage1/newt/checkbox.c b/mdk-stage1/newt/checkbox.c
new file mode 100644
index 000000000..eee514c98
--- /dev/null
+++ b/mdk-stage1/newt/checkbox.c
@@ -0,0 +1,290 @@
+#include <slang.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "newt.h"
+#include "newt_pr.h"
+
+enum type { CHECK, RADIO };
+
+struct checkbox {
+ char * text;
+ char * seq;
+ char * result;
+ newtComponent prevButton, lastButton;
+ enum type type;
+ char value;
+ int active, inactive;
+ const void * data;
+ int flags;
+ int hasFocus;
+};
+
+static void makeActive(newtComponent co);
+
+static void cbDraw(newtComponent c);
+static void cbDestroy(newtComponent co);
+struct eventResult cbEvent(newtComponent co, struct event ev);
+
+static struct componentOps cbOps = {
+ cbDraw,
+ cbEvent,
+ cbDestroy,
+ newtDefaultPlaceHandler,
+ newtDefaultMappedHandler,
+} ;
+
+newtComponent newtRadiobutton(int left, int top, const char * text, int isDefault,
+ newtComponent prevButton) {
+ newtComponent co;
+ newtComponent curr;
+ struct checkbox * rb;
+ char initialValue;
+
+ if (isDefault)
+ initialValue = '*';
+ else
+ initialValue = ' ';
+
+ co = newtCheckbox(left, top, text, initialValue, " *", NULL);
+ rb = co->data;
+ rb->type = RADIO;
+
+ rb->prevButton = prevButton;
+
+ for (curr = co; curr; curr = rb->prevButton) {
+ rb = curr->data;
+ rb->lastButton = co;
+ }
+
+ return co;
+}
+
+newtComponent newtRadioGetCurrent(newtComponent setMember) {
+ struct checkbox * rb = setMember->data;
+
+ setMember = rb->lastButton;
+ rb = setMember->data;
+
+ while (rb && rb->value != '*') {
+ setMember = rb->prevButton;
+ if (!setMember)
+ return NULL;
+ rb = setMember->data;
+ }
+
+ return setMember;
+}
+
+char newtCheckboxGetValue(newtComponent co) {
+ struct checkbox * cb = co->data;
+
+ return cb->value;
+}
+
+void newtCheckboxSetValue(newtComponent co, char value) {
+ struct checkbox * cb = co->data;
+
+ *cb->result = value;
+ cbDraw(co);
+}
+
+newtComponent newtCheckbox(int left, int top, const char * text, char defValue,
+ const char * seq, char * result) {
+ newtComponent co;
+ struct checkbox * cb;
+
+ if (!seq) seq = " *";
+
+ co = malloc(sizeof(*co));
+ cb = malloc(sizeof(struct checkbox));
+ co->data = cb;
+ cb->flags = 0;
+ if (result)
+ cb->result = result;
+ else
+ cb->result = &cb->value;
+
+ cb->text = strdup(text);
+ cb->seq = strdup(seq);
+ cb->type = CHECK;
+ cb->hasFocus = 0;
+ cb->inactive = COLORSET_CHECKBOX;
+ cb->active = COLORSET_ACTCHECKBOX;
+ defValue ? (*cb->result = defValue) : (*cb->result = cb->seq[0]);
+
+ co->ops = &cbOps;
+
+ co->callback = NULL;
+ co->height = 1;
+ co->width = strlen(text) + 4;
+ co->top = top;
+ co->left = left;
+ co->takesFocus = 1;
+
+ return co;
+}
+
+void newtCheckboxSetFlags(newtComponent co, int flags, enum newtFlagsSense sense) {
+ struct checkbox * cb = co->data;
+ int row, col;
+
+ cb->flags = newtSetFlags(cb->flags, flags, sense);
+
+ if (!(cb->flags & NEWT_FLAG_DISABLED))
+ co->takesFocus = 1;
+ else
+ co->takesFocus = 0;
+
+ newtGetrc(&row, &col);
+ cbDraw(co);
+ newtGotorc(row, col);
+}
+
+static void cbDraw(newtComponent c) {
+ struct checkbox * cb = c->data;
+
+ if (c->top == -1 || !c->isMapped) return;
+
+ if (cb->flags & NEWT_FLAG_DISABLED) {
+ cb->inactive = NEWT_COLORSET_DISENTRY;
+ cb->active = NEWT_COLORSET_DISENTRY;
+ } else {
+ cb->inactive = COLORSET_CHECKBOX;
+ cb->active = COLORSET_ACTCHECKBOX;
+ }
+
+ SLsmg_set_color(cb->inactive);
+
+ newtGotorc(c->top, c->left);
+
+ switch (cb->type) {
+ case RADIO:
+ SLsmg_write_string("( ) ");
+ break;
+
+ case CHECK:
+ SLsmg_write_string("[ ] ");
+ break;
+
+ default:
+ break;
+ }
+
+ SLsmg_write_string(cb->text);
+
+ if (cb->hasFocus)
+ SLsmg_set_color(cb->active);
+
+ newtGotorc(c->top, c->left + 1);
+ SLsmg_write_char(*cb->result);
+}
+
+static void cbDestroy(newtComponent co) {
+ struct checkbox * cb = co->data;
+
+ free(cb->text);
+ free(cb->seq);
+ free(cb);
+ free(co);
+}
+
+struct eventResult cbEvent(newtComponent co, struct event ev) {
+ struct checkbox * cb = co->data;
+ struct eventResult er;
+ const char * cur;
+
+ if (ev.when == EV_NORMAL) {
+ switch (ev.event) {
+ case EV_FOCUS:
+ cb->hasFocus = 1;
+ cbDraw(co);
+ er.result = ER_SWALLOWED;
+ break;
+
+ case EV_UNFOCUS:
+ cb->hasFocus = 0;
+ cbDraw(co);
+ er.result = ER_SWALLOWED;
+ break;
+
+ case EV_KEYPRESS:
+ if (ev.u.key == ' ') {
+ if (cb->type == RADIO) {
+ makeActive(co);
+ } else if (cb->type == CHECK) {
+ cur = strchr(cb->seq, *cb->result);
+ if (!cur)
+ *cb->result = *cb->seq;
+ else {
+ cur++;
+ if (! *cur)
+ *cb->result = *cb->seq;
+ else
+ *cb->result = *cur;
+ }
+ cbDraw(co);
+ er.result = ER_SWALLOWED;
+
+ if (co->callback)
+ co->callback(co, co->callbackData);
+ } else {
+ er.result = ER_IGNORED;
+ }
+ } else if(ev.u.key == NEWT_KEY_ENTER) {
+ er.result = ER_IGNORED;
+ } else {
+ er.result = ER_IGNORED;
+ }
+ break;
+ case EV_MOUSE:
+ if (ev.u.mouse.type == MOUSE_BUTTON_DOWN) {
+ if (cb->type == RADIO) {
+ makeActive(co);
+ } else if (cb->type == CHECK) {
+ cur = strchr(cb->seq, *cb->result);
+ if (!cur)
+ *cb->result = *cb->seq;
+ else {
+ cur++;
+ if (! *cur)
+ *cb->result = *cb->seq;
+ else
+ *cb->result = *cur;
+ }
+ cbDraw(co);
+ er.result = ER_SWALLOWED;
+
+ if (co->callback)
+ co->callback(co, co->callbackData);
+ }
+ }
+ }
+ } else
+ er.result = ER_IGNORED;
+
+ return er;
+}
+
+static void makeActive(newtComponent co) {
+ struct checkbox * cb = co->data;
+ struct checkbox * rb;
+ newtComponent curr;
+
+ /* find the one that's turned off */
+ curr = cb->lastButton;
+ rb = curr->data;
+ while (curr && rb->value == rb->seq[0]) {
+ curr = rb->prevButton;
+ if (curr) rb = curr->data;
+ }
+ if (curr) {
+ rb->value = rb->seq[0];
+ cbDraw(curr);
+ }
+ cb->value = cb->seq[1];
+ cbDraw(co);
+
+ if (co->callback)
+ co->callback(co, co->callbackData);
+}
diff --git a/mdk-stage1/newt/checkboxtree.c b/mdk-stage1/newt/checkboxtree.c
new file mode 100644
index 000000000..b56bd1e9f
--- /dev/null
+++ b/mdk-stage1/newt/checkboxtree.c
@@ -0,0 +1,714 @@
+#include <slang.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "newt.h"
+#include "newt_pr.h"
+
+struct items {
+ char * text;
+ const void *data;
+ unsigned char selected;
+ struct items *next;
+ struct items *prev;
+ struct items *branch;
+ int flags;
+ int depth;
+};
+
+struct CheckboxTree {
+ newtComponent sb;
+ int curWidth; /* size of text w/o scrollbar or border*/
+ int curHeight; /* size of text w/o border */
+ struct items * itemlist;
+ struct items ** flatList, ** currItem, ** firstItem;
+ int flatCount;
+ int flags;
+ int pad;
+ char * seq;
+ char * result;
+};
+
+static void ctDraw(newtComponent c);
+static void ctDestroy(newtComponent co);
+static void ctPlace(newtComponent co, int newLeft, int newTop);
+struct eventResult ctEvent(newtComponent co, struct event ev);
+static void ctMapped(newtComponent co, int isMapped);
+static struct items * findItem(struct items * items, const void * data);
+static void buildFlatList(newtComponent co);
+static void doBuildFlatList(struct CheckboxTree * ct, struct items * item);
+enum countWhat { COUNT_EXPOSED=0, COUNT_SELECTED=1 };
+static int countItems(struct items * item, enum countWhat justExposed);
+
+static struct componentOps ctOps = {
+ ctDraw,
+ ctEvent,
+ ctDestroy,
+ ctPlace,
+ ctMapped,
+} ;
+
+static int countItems(struct items * item, enum countWhat what) {
+ int count = 0;
+
+ while (item) {
+ if ((!item->branch && item->selected == what) || (what == COUNT_EXPOSED))
+ count++;
+ if (item->branch || (what == COUNT_EXPOSED && item->selected))
+ count += countItems(item->branch, what);
+ item = item->next;
+ }
+
+ return count;
+}
+
+static void doBuildFlatList(struct CheckboxTree * ct, struct items * item) {
+ while (item) {
+ ct->flatList[ct->flatCount++] = item;
+ if (item->branch && item->selected) doBuildFlatList(ct, item->branch);
+ item = item->next;
+ }
+}
+
+static void buildFlatList(newtComponent co) {
+ struct CheckboxTree * ct = co->data;
+
+ if (ct->flatList) free(ct->flatList);
+ ct->flatCount = countItems(ct->itemlist, COUNT_EXPOSED);
+
+ ct->flatList = malloc(sizeof(*ct->flatList) * (ct->flatCount+1));
+ ct->flatCount = 0;
+ doBuildFlatList(ct, ct->itemlist);
+ ct->flatList[ct->flatCount] = NULL;
+}
+
+int newtCheckboxTreeAddItem(newtComponent co,
+ const char * text, const void * data,
+ int flags, int index, ...) {
+ va_list argList;
+ int numIndexes;
+ int * indexes;
+ int i;
+
+ va_start(argList, index);
+ numIndexes = 0;
+ i = index;
+ while (i != NEWT_ARG_LAST) {
+ numIndexes++;
+ i = va_arg(argList, int);
+ }
+
+ va_end(argList);
+
+ indexes = alloca(sizeof(*indexes) * (numIndexes + 1));
+ va_start(argList, index);
+ numIndexes = 0;
+ i = index;
+ va_start(argList, index);
+ while (i != NEWT_ARG_LAST) {
+ indexes[numIndexes++] = i;
+ i = va_arg(argList, int);
+ }
+ va_end(argList);
+
+ indexes[numIndexes++] = NEWT_ARG_LAST;
+
+ return newtCheckboxTreeAddArray(co, text, data, flags, indexes);
+}
+
+static int doFindItemPath(struct items * items, void * data, int * path,
+ int * len) {
+ int where = 0;
+
+ while (items) {
+ if (items->data == data) {
+ if (path) path[items->depth] = where;
+ if (len) *len = items->depth + 1;
+ return 1;
+ }
+
+ if (items->branch && doFindItemPath(items->branch, data, path, len)) {
+ if (path) path[items->depth] = where;
+ return 1;
+ }
+
+ items = items->next;
+ where++;
+ }
+
+ return 0;
+}
+
+int * newtCheckboxTreeFindItem(newtComponent co, void * data) {
+ int len;
+ int * path;
+ struct CheckboxTree * ct = co->data;
+
+ if (!doFindItemPath(ct->itemlist, data, NULL, &len)) return NULL;
+
+ path = malloc(sizeof(*path) * (len + 1));
+ doFindItemPath(ct->itemlist, data, path, NULL);
+ path[len] = NEWT_ARG_LAST;
+
+ return path;
+}
+
+int newtCheckboxTreeAddArray(newtComponent co,
+ const char * text, const void * data,
+ int flags, int * indexes) {
+ struct items * curList, * newNode, * item = NULL;
+ struct items ** listPtr = NULL;
+ int i, index, numIndexes;
+ struct CheckboxTree * ct = co->data;
+
+ numIndexes = 0;
+ while (indexes[numIndexes] != NEWT_ARG_LAST) numIndexes++;
+
+ if (!ct->itemlist) {
+ if (numIndexes > 1) return -1;
+
+ ct->itemlist = malloc(sizeof(*ct->itemlist));
+ item = ct->itemlist;
+ item->prev = NULL;
+ item->next = NULL;
+ } else {
+ curList = ct->itemlist;
+ listPtr = &ct->itemlist;
+
+ i = 0;
+ index = indexes[i];
+ while (i < numIndexes) {
+ item = curList;
+
+ if (index == NEWT_ARG_APPEND) {
+ item = NULL;
+ } else {
+ while (index && item)
+ item = item->next, index--;
+ }
+
+ i++;
+ if (i < numIndexes) {
+ curList = item->branch;
+ listPtr = &item->branch;
+ if (!curList && (i + 1 != numIndexes)) return -1;
+
+ index = indexes[i];
+ }
+ }
+
+ if (!curList) { /* create a new branch */
+ item = malloc(sizeof(*curList->prev));
+ item->next = item->prev = NULL;
+ *listPtr = item;
+ } else if (!item) { /* append to end */
+ item = curList;
+ while (item->next) item = item->next;
+ item->next = malloc(sizeof(*curList->prev));
+ item->next->prev = item;
+ item = item->next;
+ item->next = NULL;
+ } else {
+ newNode = malloc(sizeof(*newNode));
+ newNode->prev = item->prev;
+ newNode->next = item;
+
+ if (item->prev) item->prev->next = newNode;
+ item->prev = newNode;
+ item = newNode;
+ if (!item->prev) *listPtr = item;
+ }
+ }
+
+ item->text = strdup(text);
+ item->data = data;
+ if (flags & NEWT_FLAG_SELECTED) {
+ item->selected = 1;
+ } else {
+ item->selected = 0;
+ }
+ item->flags = flags;
+ item->branch = NULL;
+ item->depth = numIndexes - 1;
+
+ i = 4 + (3 * item->depth);
+
+ if ((strlen(text) + i + ct->pad) > co->width) {
+ co->width = strlen(text) + i + ct->pad;
+ }
+
+ return 0;
+}
+
+static struct items * findItem(struct items * items, const void * data) {
+ struct items * i;
+
+ while (items) {
+ if (items->data == data) return items;
+ if (items->branch) {
+ i = findItem(items->branch, data);
+ if (i) return i;
+ }
+
+ items = items->next;
+ }
+
+ return NULL;
+}
+
+static void listSelected(struct items * items, int * num, const void ** list, int seqindex) {
+ while (items) {
+ if ((seqindex ? items->selected==seqindex : items->selected) && !items->branch)
+ list[(*num)++] = (void *) items->data;
+ if (items->branch)
+ listSelected(items->branch, num, list, seqindex);
+ items = items->next;
+ }
+}
+
+const void ** newtCheckboxTreeGetSelection(newtComponent co, int *numitems)
+{
+ return newtCheckboxTreeGetMultiSelection(co, numitems, 0);
+}
+
+const void ** newtCheckboxTreeGetMultiSelection(newtComponent co, int *numitems, char seqnum)
+{
+ struct CheckboxTree * ct;
+ const void **retval;
+ int seqindex=0;
+
+ if(!co || !numitems) return NULL;
+
+ ct = co->data;
+
+ if (seqnum) {
+ while( ct->seq[seqindex] && ( ct->seq[seqindex] != seqnum )) seqindex++;
+ } else {
+ seqindex = 0;
+ }
+
+ *numitems = countItems(ct->itemlist, (seqindex ? seqindex : COUNT_SELECTED));
+ if (!*numitems) return NULL;
+
+ retval = malloc(*numitems * sizeof(void *));
+ *numitems = 0;
+ listSelected(ct->itemlist, numitems, retval, seqindex);
+
+ return retval;
+}
+
+newtComponent newtCheckboxTree(int left, int top, int height, int flags) {
+ return newtCheckboxTreeMulti(left, top, height, NULL, flags);
+}
+
+newtComponent newtCheckboxTreeMulti(int left, int top, int height, char *seq, int flags) {
+ newtComponent co;
+ struct CheckboxTree * ct;
+
+ co = malloc(sizeof(*co));
+ ct = malloc(sizeof(struct CheckboxTree));
+ co->callback = NULL;
+ co->data = ct;
+ co->ops = &ctOps;
+ co->takesFocus = 1;
+ co->height = height;
+ co->width = 0;
+ co->isMapped = 0;
+ ct->itemlist = NULL;
+ ct->firstItem = NULL;
+ ct->currItem = NULL;
+ ct->flatList = NULL;
+ if (seq)
+ ct->seq = strdup(seq);
+ else
+ ct->seq = strdup(" *");
+ if (flags & NEWT_FLAG_SCROLL) {
+ ct->sb = newtVerticalScrollbar(left, top, height,
+ COLORSET_LISTBOX, COLORSET_ACTLISTBOX);
+ ct->pad = 2;
+ } else {
+ ct->sb = NULL;
+ ct->pad = 0;
+ }
+
+ return co;
+}
+
+static void ctMapped(newtComponent co, int isMapped) {
+ struct CheckboxTree * ct = co->data;
+
+ co->isMapped = isMapped;
+ if (ct->sb)
+ ct->sb->ops->mapped(ct->sb, isMapped);
+}
+
+static void ctPlace(newtComponent co, int newLeft, int newTop) {
+ struct CheckboxTree * ct = co->data;
+
+ co->top = newTop;
+ co->left = newLeft;
+
+ if (ct->sb)
+ ct->sb->ops->place(ct->sb, co->left + co->width - 1, co->top);
+}
+
+int ctSetItem(newtComponent co, struct items *item, enum newtFlagsSense sense)
+{
+ struct CheckboxTree * ct = co->data;
+ struct items * currItem;
+ struct items * firstItem;
+
+ if (!item)
+ return 1;
+
+ switch(sense) {
+ case NEWT_FLAGS_RESET:
+ item->selected = 0;
+ break;
+ case NEWT_FLAGS_SET:
+ item->selected = 1;
+ break;
+ case NEWT_FLAGS_TOGGLE:
+ if (item->branch)
+ item->selected = !item->selected;
+ else {
+ item->selected++;
+ if (item->selected==strlen(ct->seq))
+ item->selected = 0;
+ }
+ break;
+ }
+
+ if (item->branch) {
+ currItem = *ct->currItem;
+ firstItem = *ct->firstItem;
+
+ buildFlatList(co);
+
+ ct->currItem = ct->flatList;
+ while (*ct->currItem != currItem) ct->currItem++;
+
+ ct->firstItem = ct->flatList;
+ if (ct->flatCount > co->height) {
+ struct items ** last = ct->flatList + ct->flatCount - co->height;
+ while (*ct->firstItem != firstItem && ct->firstItem != last)
+ ct->firstItem++;
+ }
+ }
+
+ return 0;
+}
+
+static void ctSetItems(struct items *item, int selected)
+{
+ for (; item; item = item->next) {
+ if (!item->branch)
+ item->selected = selected;
+ else
+ ctSetItems(item->branch, selected);
+ }
+}
+
+static void ctDraw(newtComponent co) {
+ struct CheckboxTree * ct = co->data;
+ struct items ** item;
+ int i, j;
+ char * spaces = NULL;
+ int currRow = -1;
+
+ if (!co->isMapped) return ;
+
+ if (!ct->firstItem) {
+ buildFlatList(co);
+ ct->firstItem = ct->currItem = ct->flatList;
+ }
+
+ item = ct->firstItem;
+
+ i = 0;
+ while (*item && i < co->height) {
+ newtGotorc(co->top + i, co->left);
+ if (*item == *ct->currItem) {
+ SLsmg_set_color(NEWT_COLORSET_ACTLISTBOX);
+ currRow = co->top + i;
+ } else
+ SLsmg_set_color(NEWT_COLORSET_LISTBOX);
+
+ for (j = 0; j < (*item)->depth; j++)
+ SLsmg_write_string(" ");
+
+ if ((*item)->branch) {
+ if ((*item)->selected)
+ SLsmg_write_string("<-> ");
+ else
+ SLsmg_write_string("<+> ");
+ } else {
+ char tmp[5];
+ snprintf(tmp,5,"[%c] ",ct->seq[(*item)->selected]);
+ SLsmg_write_string(tmp);
+ }
+
+ SLsmg_write_nstring((*item)->text, co->width - 4 -
+ (3 * (*item)->depth));
+ item++;
+ i++;
+ }
+
+ /* There could be empty lines left (i.e. if the user closes an expanded
+ list which is the last thing in the tree, and whose elements are
+ displayed at the bottom of the screen */
+ if (i < co->height) {
+ spaces = alloca(co->width);
+ memset(spaces, ' ', co->width);
+ SLsmg_set_color(NEWT_COLORSET_LISTBOX);
+ }
+ while (i < co->height) {
+ newtGotorc(co->top + i, co->left);
+ SLsmg_write_nstring(spaces, co->width);
+ i++;
+ }
+
+ if(ct->sb) {
+ newtScrollbarSet(ct->sb, ct->currItem - ct->flatList,
+ ct->flatCount - 1);
+ ct->sb->ops->draw(ct->sb);
+ }
+
+ newtGotorc(currRow, co->left + 1);
+}
+
+static void ctDestroy(newtComponent co) {
+ struct CheckboxTree * ct = co->data;
+ struct items * item, * nextitem;
+
+ nextitem = item = ct->itemlist;
+
+ while (item != NULL) {
+ nextitem = item->next;
+ free(item->text);
+ free(item);
+ item = nextitem;
+ }
+
+ free(ct->seq);
+ free(ct);
+ free(co);
+}
+
+struct eventResult ctEvent(newtComponent co, struct event ev) {
+ struct CheckboxTree * ct = co->data;
+ struct eventResult er;
+ struct items ** listEnd, ** lastItem;
+ int key, selnum = 1;
+
+ er.result = ER_IGNORED;
+
+ if(ev.when == EV_EARLY || ev.when == EV_LATE) {
+ return er;
+ }
+
+ switch(ev.event) {
+ case EV_KEYPRESS:
+ key = ev.u.key;
+ if (key == (char) key && key != ' ') {
+ for (selnum = 0; ct->seq[selnum]; selnum++)
+ if (key == ct->seq[selnum])
+ break;
+ if (!ct->seq[selnum])
+ switch (key) {
+ case '-': selnum = 0; break;
+ case '+':
+ case '*': selnum = 1; break;
+ }
+ if (ct->seq[selnum])
+ key = '*';
+ }
+ switch(key) {
+ case ' ':
+ case NEWT_KEY_ENTER:
+ ctSetItem(co, *ct->currItem, NEWT_FLAGS_TOGGLE);
+ er.result = ER_SWALLOWED;
+ if (!(*ct->currItem)->branch || (*ct->currItem)->selected)
+ key = NEWT_KEY_DOWN;
+ else
+ key = '*';
+ break;
+ case '*':
+ if ((*ct->currItem)->branch) {
+ ctSetItems((*ct->currItem)->branch, selnum);
+ if (!(*ct->currItem)->selected)
+ key = NEWT_KEY_DOWN;
+ } else {
+ (*ct->currItem)->selected = selnum;
+ key = NEWT_KEY_DOWN;
+ }
+ er.result = ER_SWALLOWED;
+ break;
+ }
+ switch (key) {
+ case '*':
+ ctDraw(co);
+ if(co->callback) co->callback(co, co->callbackData);
+ return er;
+ case NEWT_KEY_HOME:
+ ct->currItem = ct->flatList;
+ ct->firstItem = ct->flatList;
+ ctDraw(co);
+ if(co->callback) co->callback(co, co->callbackData);
+ er.result = ER_SWALLOWED;
+ return er;
+ case NEWT_KEY_END:
+ ct->currItem = ct->flatList + ct->flatCount - 1;
+ if (ct->flatCount <= co->height)
+ ct->firstItem = ct->flatList;
+ else
+ ct->firstItem = ct->flatList + ct->flatCount - co->height;
+ ctDraw(co);
+ if(co->callback) co->callback(co, co->callbackData);
+ er.result = ER_SWALLOWED;
+ return er;
+ case NEWT_KEY_DOWN:
+ if (ev.u.key != NEWT_KEY_DOWN) {
+ if(co->callback) co->callback(co, co->callbackData);
+ if (strlen(ct->seq) != 2) {
+ ctDraw(co);
+ return er;
+ }
+ }
+ if ((ct->currItem - ct->flatList + 1) < ct->flatCount) {
+ ct->currItem++;
+
+ if (ct->currItem - ct->firstItem >= co->height)
+ ct->firstItem++;
+
+ ctDraw(co);
+ } else if (ev.u.key != NEWT_KEY_DOWN)
+ ctDraw(co);
+ if(co->callback) co->callback(co, co->callbackData);
+ er.result = ER_SWALLOWED;
+ return er;
+ case NEWT_KEY_UP:
+ if (ct->currItem != ct->flatList) {
+ ct->currItem--;
+
+ if (ct->currItem < ct->firstItem)
+ ct->firstItem = ct->currItem;
+
+ ctDraw(co);
+ }
+ er.result = ER_SWALLOWED;
+ if(co->callback) co->callback(co, co->callbackData);
+ return er;
+ case NEWT_KEY_PGUP:
+ if (ct->firstItem - co->height < ct->flatList) {
+ ct->firstItem = ct->currItem = ct->flatList;
+ } else {
+ ct->currItem -= co->height;
+ ct->firstItem -= co->height;
+ }
+
+ ctDraw(co);
+ if(co->callback) co->callback(co, co->callbackData);
+ er.result = ER_SWALLOWED;
+ return er;
+ case NEWT_KEY_PGDN:
+ listEnd = ct->flatList + ct->flatCount - 1;
+ lastItem = ct->firstItem + co->height - 1;
+
+ if (lastItem + co->height > listEnd) {
+ ct->firstItem = listEnd - co->height + 1;
+ ct->currItem = listEnd;
+ } else {
+ ct->currItem += co->height;
+ ct->firstItem += co->height;
+ }
+
+ ctDraw(co);
+ if(co->callback) co->callback(co, co->callbackData);
+ er.result = ER_SWALLOWED;
+ return er;
+ }
+ break;
+
+ case EV_FOCUS:
+ ctDraw(co);
+ er.result = ER_SWALLOWED;
+ break;
+
+ case EV_UNFOCUS:
+ ctDraw(co);
+ er.result = ER_SWALLOWED;
+ break;
+ default:
+ break;
+ }
+
+ return er;
+}
+
+const void * newtCheckboxTreeGetCurrent(newtComponent co) {
+ struct CheckboxTree * ct = co->data;
+
+ if (!ct->currItem) return NULL;
+ return (*ct->currItem)->data;
+}
+
+void newtCheckboxTreeSetEntry(newtComponent co, const void * data, const char * text)
+{
+ struct CheckboxTree * ct;
+ struct items * item;
+ int i;
+
+ if (!co) return;
+ ct = co->data;
+ item = findItem(ct->itemlist, data);
+ if (!item) return;
+
+ free(item->text);
+ item->text = strdup(text);
+
+ i = 4 + (3 * item->depth);
+
+ if ((strlen(text) + i + ct->pad) > co->width) {
+ co->width = strlen(text) + i + ct->pad;
+ }
+
+ ctDraw(co);
+}
+
+char newtCheckboxTreeGetEntryValue(newtComponent co, const void * data)
+{
+ struct CheckboxTree * ct;
+ struct items * item;
+
+ if (!co) return -1;
+ ct = co->data;
+ item = findItem(ct->itemlist, data);
+ if (!item) return -1;
+ if (item->branch)
+ return item->selected ? NEWT_CHECKBOXTREE_EXPANDED : NEWT_CHECKBOXTREE_COLLAPSED;
+ else
+ return ct->seq[item->selected];
+}
+
+void newtCheckboxTreeSetEntryValue(newtComponent co, const void * data, char value)
+{
+ struct CheckboxTree * ct;
+ struct items * item;
+ int i;
+
+ if (!co) return;
+ ct = co->data;
+ item = findItem(ct->itemlist, data);
+ if (!item || item->branch) return;
+
+ for(i = 0; ct->seq[i]; i++)
+ if (value == ct->seq[i])
+ break;
+
+ if (!ct->seq[i]) return;
+ item->selected = i;
+
+ ctDraw(co);
+}
+
diff --git a/mdk-stage1/newt/entry.c b/mdk-stage1/newt/entry.c
new file mode 100644
index 000000000..154edba71
--- /dev/null
+++ b/mdk-stage1/newt/entry.c
@@ -0,0 +1,376 @@
+#include <ctype.h>
+#include <slang.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "newt.h"
+#include "newt_pr.h"
+
+struct entry {
+ int flags;
+ char * buf;
+ char ** resultPtr;
+ int bufAlloced;
+ int bufUsed; /* amount of the buffer that's been used */
+ int cursorPosition; /* cursor *in the string* on on screen */
+ int firstChar; /* first character position being shown */
+ newtEntryFilter filter;
+ void * filterData;
+};
+
+static void entryDraw(newtComponent co);
+static void entryDestroy(newtComponent co);
+static struct eventResult entryEvent(newtComponent co,
+ struct event ev);
+
+static struct eventResult entryHandleKey(newtComponent co, int key);
+
+static struct componentOps entryOps = {
+ entryDraw,
+ entryEvent,
+ entryDestroy,
+ newtDefaultPlaceHandler,
+ newtDefaultMappedHandler,
+} ;
+
+void newtEntrySet(newtComponent co, const char * value, int cursorAtEnd) {
+ struct entry * en = co->data;
+
+ if ((strlen(value) + 1) > (unsigned int)en->bufAlloced) {
+ free(en->buf);
+ en->bufAlloced = strlen(value) + 1;
+ en->buf = malloc(en->bufAlloced);
+ if (en->resultPtr) *en->resultPtr = en->buf;
+ }
+ memset(en->buf, 0, en->bufAlloced); /* clear the buffer */
+ strcpy(en->buf, value);
+ en->bufUsed = strlen(value);
+ en->firstChar = 0;
+ if (cursorAtEnd)
+ en->cursorPosition = en->bufUsed;
+ else
+ en->cursorPosition = 0;
+
+ entryDraw(co);
+} ;
+
+newtComponent newtEntry(int left, int top, const char * initialValue, int width,
+ char ** resultPtr, int flags) {
+ newtComponent co;
+ struct entry * en;
+
+ co = malloc(sizeof(*co));
+ en = malloc(sizeof(struct entry));
+ co->data = en;
+
+ co->top = top;
+ co->left = left;
+ co->height = 1;
+ co->width = width;
+ co->isMapped = 0;
+ co->callback = NULL;
+
+ co->ops = &entryOps;
+
+ en->flags = flags;
+ en->cursorPosition = 0;
+ en->firstChar = 0;
+ en->bufUsed = 0;
+ en->bufAlloced = width + 1;
+ en->filter = NULL;
+
+ if (!(en->flags & NEWT_FLAG_DISABLED))
+ co->takesFocus = 1;
+ else
+ co->takesFocus = 0;
+
+ if (initialValue && strlen(initialValue) > (unsigned int)width) {
+ en->bufAlloced = strlen(initialValue) + 1;
+ }
+ en->buf = malloc(en->bufAlloced);
+ en->resultPtr = resultPtr;
+ if (en->resultPtr) *en->resultPtr = en->buf;
+
+ memset(en->buf, 0, en->bufAlloced);
+ if (initialValue) {
+ strcpy(en->buf, initialValue);
+ en->bufUsed = strlen(initialValue);
+ en->cursorPosition = en->bufUsed;
+ } else {
+ *en->buf = '\0';
+ en->bufUsed = 0;
+ en->cursorPosition = 0;
+ }
+
+ return co;
+}
+
+static void entryDraw(newtComponent co) {
+ struct entry * en = co->data;
+ int i;
+ char * chptr;
+ int len;
+
+ if (!co->isMapped) return;
+
+ if (en->flags & NEWT_FLAG_DISABLED)
+ SLsmg_set_color(NEWT_COLORSET_DISENTRY);
+ else
+ SLsmg_set_color(NEWT_COLORSET_ENTRY);
+
+ if (en->flags & NEWT_FLAG_HIDDEN) {
+ newtGotorc(co->top, co->left);
+ for (i = 0; i < co->width; i++)
+ SLsmg_write_char('_');
+ newtGotorc(co->top, co->left);
+
+ return;
+ }
+
+ newtGotorc(co->top, co->left);
+
+ if (en->cursorPosition < en->firstChar) {
+ /* scroll to the left */
+ en->firstChar = en->cursorPosition;
+ } else if ((en->firstChar + co->width) <= en->cursorPosition) {
+ /* scroll to the right */
+ en->firstChar = en->cursorPosition - co->width + 1;
+ }
+
+ chptr = en->buf + en->firstChar;
+
+ if (en->flags & NEWT_FLAG_PASSWORD) {
+ char *tmpptr, *p;
+
+ tmpptr = alloca(strlen(chptr+2));
+ strcpy(tmpptr, chptr);
+ for (p = tmpptr; *p; p++)
+ *p = '*';
+ chptr = tmpptr;
+ }
+
+ len = strlen(chptr);
+
+ if (len <= co->width) {
+ i = len;
+ SLsmg_write_string(chptr);
+ while (i < co->width) {
+ SLsmg_write_char('_');
+ i++;
+ }
+ } else {
+ SLsmg_write_nstring(chptr, co->width);
+ }
+
+ if (en->flags & NEWT_FLAG_HIDDEN)
+ newtGotorc(co->top, co->left);
+ else
+ newtGotorc(co->top, co->left + (en->cursorPosition - en->firstChar));
+}
+
+void newtEntrySetFlags(newtComponent co, int flags, enum newtFlagsSense sense) {
+ struct entry * en = co->data;
+ int row, col;
+
+ en->flags = newtSetFlags(en->flags, flags, sense);
+
+ if (!(en->flags & NEWT_FLAG_DISABLED))
+ co->takesFocus = 1;
+ else
+ co->takesFocus = 0;
+
+ newtGetrc(&row, &col);
+ entryDraw(co);
+ newtGotorc(row, col);
+}
+
+static void entryDestroy(newtComponent co) {
+ struct entry * en = co->data;
+
+ free(en->buf);
+ free(en);
+ free(co);
+}
+
+static struct eventResult entryEvent(newtComponent co,
+ struct event ev) {
+ struct entry * en = co->data;
+ struct eventResult er;
+ int ch;
+
+ if (ev.when == EV_NORMAL) {
+ switch (ev.event) {
+ case EV_FOCUS:
+ newtCursorOn();
+ if (en->flags & NEWT_FLAG_HIDDEN)
+ newtGotorc(co->top, co->left);
+ else
+ newtGotorc(co->top, co->left +
+ (en->cursorPosition - en->firstChar));
+ er.result = ER_SWALLOWED;
+ break;
+
+ case EV_UNFOCUS:
+ newtCursorOff();
+ newtGotorc(0, 0);
+ er.result = ER_SWALLOWED;
+ if (co->callback)
+ co->callback(co, co->callbackData);
+ break;
+
+ case EV_KEYPRESS:
+ ch = ev.u.key;
+ if (en->filter)
+ ch = en->filter(co, en->filterData, ch, en->cursorPosition);
+ if (ch) er = entryHandleKey(co, ch);
+ break;
+
+ case EV_MOUSE:
+ if ((ev.u.mouse.type == MOUSE_BUTTON_DOWN) &&
+ (en->flags ^ NEWT_FLAG_HIDDEN)) {
+ if (strlen(en->buf) >= ev.u.mouse.x - co->left) {
+ en->cursorPosition = ev.u.mouse.x - co->left;
+ newtGotorc(co->top,
+ co->left +(en->cursorPosition - en->firstChar));
+ } else {
+ en->cursorPosition = strlen(en->buf);
+ newtGotorc(co->top,
+ co->left +(en->cursorPosition - en->firstChar));
+ }
+ }
+ break;
+ }
+ } else
+ er.result = ER_IGNORED;
+
+ return er;
+}
+
+static struct eventResult entryHandleKey(newtComponent co, int key) {
+ struct entry * en = co->data;
+ struct eventResult er;
+ char * chptr, * insPoint;
+
+ er.result = ER_SWALLOWED;
+ switch (key) {
+ case '\r': /* Return */
+ if (en->flags & NEWT_FLAG_RETURNEXIT) {
+ er.result = ER_EXITFORM;
+ } else {
+ er.result = ER_NEXTCOMP;
+ }
+ break;
+
+ case '\001': /* ^A */
+ case NEWT_KEY_HOME:
+ en->cursorPosition = 0;
+ break;
+
+ case '\005': /* ^E */
+ case NEWT_KEY_END:
+ en->cursorPosition = en->bufUsed;
+ break;
+
+ case '\013': /* ^K */
+ en->bufUsed = en->cursorPosition;
+ memset(en->buf + en->bufUsed, 0, en->bufAlloced - en->bufUsed);
+ break;
+
+ case '\002': /* ^B */
+ case NEWT_KEY_LEFT:
+ if (en->cursorPosition)
+ en->cursorPosition--;
+ break;
+
+ case '\004':
+ case NEWT_KEY_DELETE:
+ chptr = en->buf + en->cursorPosition;
+ if (*chptr) {
+ chptr++;
+ while (*chptr) {
+ *(chptr - 1) = *chptr;
+ chptr++;
+ }
+ *(chptr - 1) = '\0';
+ en->bufUsed--;
+ }
+ break;
+
+ case NEWT_KEY_BKSPC:
+ if (en->cursorPosition) {
+ /* if this isn't true, there's nothing to erase */
+ chptr = en->buf + en->cursorPosition;
+ en->bufUsed--;
+ en->cursorPosition--;
+ while (*chptr) {
+ *(chptr - 1) = *chptr;
+ chptr++;
+ }
+ *(chptr - 1) = '\0';
+ }
+ break;
+
+ case '\006': /* ^B */
+ case NEWT_KEY_RIGHT:
+ if (en->cursorPosition < en->bufUsed)
+ en->cursorPosition++;
+ break;
+
+ default:
+ if ((key >= 0x20 && key <= 0x7e) || (key >= 0xa0 && key <= 0xff)) {
+ if (!(en->flags & NEWT_FLAG_SCROLL) && en->bufUsed >= co->width) {
+ SLtt_beep();
+ break;
+ }
+
+ if ((en->bufUsed + 1) == en->bufAlloced) {
+ en->bufAlloced += 20;
+ en->buf = realloc(en->buf, en->bufAlloced);
+ if (en->resultPtr) *en->resultPtr = en->buf;
+ memset(en->buf + en->bufUsed + 1, 0, 20);
+ }
+
+ if (en->cursorPosition == en->bufUsed) {
+ en->bufUsed++;
+ } else {
+ /* insert the new character */
+
+ /* chptr is the last character in the string */
+ chptr = (en->buf + en->bufUsed) - 1;
+ if ((en->bufUsed + 1) == en->bufAlloced) {
+ /* this string fills the buffer, so clip it */
+ chptr--;
+ } else
+ en->bufUsed++;
+
+ insPoint = en->buf + en->cursorPosition;
+
+ while (chptr >= insPoint) {
+ *(chptr + 1) = *chptr;
+ chptr--;
+ }
+
+ }
+
+ en->buf[en->cursorPosition++] = key;
+ } else {
+ er.result = ER_IGNORED;
+ }
+ }
+
+ entryDraw(co);
+
+ return er;
+}
+
+char * newtEntryGetValue(newtComponent co) {
+ struct entry * en = co->data;
+
+ return en->buf;
+}
+
+void newtEntrySetFilter(newtComponent co, newtEntryFilter filter, void * data) {
+ struct entry * en = co->data;
+ en->filter = filter;
+ en->filterData = data;
+}
diff --git a/mdk-stage1/newt/form.c b/mdk-stage1/newt/form.c
new file mode 100644
index 000000000..4ad465e38
--- /dev/null
+++ b/mdk-stage1/newt/form.c
@@ -0,0 +1,712 @@
+#include <unistd.h>
+#include <slang.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <sys/time.h>
+#include <sys/types.h>
+
+#include "newt.h"
+#include "newt_pr.h"
+
+
+/****************************************************************************
+ These forms handle vertical scrolling of components with a height of 1
+
+ Horizontal scrolling won't work, and scrolling large widgets will fail
+ miserably. It shouldn't be too hard to fix either of those if anyone
+ cares to. I only use scrolling for listboxes and text boxes though so
+ I didn't bother.
+*****************************************************************************/
+
+struct element {
+ int top, left; /* Actual, not virtual. These are translated */
+ newtComponent co; /* into actual through vertOffset */
+};
+
+struct fdInfo {
+ int fd;
+ int flags;
+};
+
+struct form {
+ int numCompsAlloced;
+ struct element * elements;
+ int numComps;
+ int currComp;
+ int fixedHeight;
+ int flags;
+ int vertOffset;
+ newtComponent vertBar, exitComp;
+ const char * help;
+ int numRows;
+ int * hotKeys;
+ int numHotKeys;
+ int background;
+ int beenSet;
+ int numFds;
+ struct fdInfo * fds;
+ int maxFd;
+ int timer; /* in milliseconds */
+ struct timeval lastTimeout;
+ void * helpTag;
+ newtCallback helpCb;
+};
+
+static void gotoComponent(struct form * form, int newComp);
+static struct eventResult formEvent(newtComponent co, struct event ev);
+static struct eventResult sendEvent(newtComponent comp, struct event ev);
+static void formPlace(newtComponent co, int left, int top);
+
+/* Global, ick */
+static newtCallback helpCallback;
+
+/* this isn't static as grid.c tests against it to find forms */
+struct componentOps formOps = {
+ newtDrawForm,
+ formEvent,
+ newtFormDestroy,
+ formPlace,
+ newtDefaultMappedHandler,
+} ;
+
+static inline int componentFits(newtComponent co, int compNum) {
+ struct form * form = co->data;
+ struct element * el = form->elements + compNum;
+
+ if ((co->top + form->vertOffset) > el->top) return 0;
+ if ((co->top + form->vertOffset + co->height) <
+ (el->top + el->co->height)) return 0;
+
+ return 1;
+}
+
+newtComponent newtForm(newtComponent vertBar, void * help, int flags) {
+ newtComponent co;
+ struct form * form;
+
+ co = malloc(sizeof(*co));
+ form = malloc(sizeof(*form));
+ co->data = form;
+ co->width = 0;
+ co->height = 0;
+ co->top = -1;
+ co->left = -1;
+ co->isMapped = 0;
+
+ co->takesFocus = 0; /* we may have 0 components */
+ co->ops = &formOps;
+
+ form->help = help;
+ form->flags = flags;
+ form->numCompsAlloced = 5;
+ form->numComps = 0;
+ form->currComp = -1;
+ form->vertOffset = 0;
+ form->fixedHeight = 0;
+ form->numRows = 0;
+ form->numFds = 0;
+ form->maxFd = 0;
+ form->fds = NULL;
+ form->beenSet = 0;
+ form->elements = malloc(sizeof(*(form->elements)) * form->numCompsAlloced);
+
+ form->background = COLORSET_WINDOW;
+ form->hotKeys = malloc(sizeof(int));
+ form->numHotKeys = 0;
+ form->timer = 0;
+ form->lastTimeout.tv_sec = form->lastTimeout.tv_usec = 0;
+ if (!(form->flags & NEWT_FLAG_NOF12)) {
+ newtFormAddHotKey(co, NEWT_KEY_F12);
+ }
+
+ if (vertBar)
+ form->vertBar = vertBar;
+ else
+ form->vertBar = NULL;
+
+ form->helpTag = help;
+ form->helpCb = helpCallback;
+
+ return co;
+}
+
+newtComponent newtFormGetCurrent(newtComponent co) {
+ struct form * form = co->data;
+
+ return form->elements[form->currComp].co;
+}
+
+void newtFormSetCurrent(newtComponent co, newtComponent subco) {
+ struct form * form = co->data;
+ int i, new;
+
+ for (i = 0; i < form->numComps; i++) {
+ if (form->elements[i].co == subco) break;
+ }
+
+ if (form->elements[i].co != subco) return;
+ new = i;
+
+ if (co->isMapped && !componentFits(co, new)) {
+ gotoComponent(form, -1);
+ form->vertOffset = form->elements[new].top - co->top - 1;
+ if (form->vertOffset > (form->numRows - co->height))
+ form->vertOffset = form->numRows - co->height;
+ }
+
+ gotoComponent(form, new);
+}
+
+void newtFormSetTimer(newtComponent co, int millisecs) {
+ struct form * form = co->data;
+
+ form->timer = millisecs;
+ form->lastTimeout.tv_usec = 0;
+ form->lastTimeout.tv_sec = 0;
+}
+
+void newtFormSetHeight(newtComponent co, int height) {
+ struct form * form = co->data;
+
+ form->fixedHeight = 1;
+ co->height = height;
+}
+
+void newtFormSetWidth(newtComponent co, int width) {
+ co->width = width;
+}
+
+void newtFormAddComponent(newtComponent co, newtComponent newco) {
+ struct form * form = co->data;
+
+ co->takesFocus = 1;
+
+ if (form->numCompsAlloced == form->numComps) {
+ form->numCompsAlloced += 5;
+ form->elements = realloc(form->elements,
+ sizeof(*(form->elements)) * form->numCompsAlloced);
+ }
+
+ /* we grab real values for these a bit later */
+ form->elements[form->numComps].left = -2;
+ form->elements[form->numComps].top = -2;
+ form->elements[form->numComps].co = newco;
+
+ if (newco->takesFocus && form->currComp == -1)
+ form->currComp = form->numComps;
+
+ form->numComps++;
+}
+
+void newtFormAddComponents(newtComponent co, ...) {
+ va_list ap;
+ newtComponent subco;
+
+ va_start(ap, co);
+
+ while ((subco = va_arg(ap, newtComponent)))
+ newtFormAddComponent(co, subco);
+
+ va_end(ap);
+}
+
+static void formPlace(newtComponent co, int left, int top) {
+ struct form * form = co->data;
+ int vertDelta, horizDelta;
+ struct element * el;
+ int i;
+
+ newtFormSetSize(co);
+
+ vertDelta = top - co->top;
+ horizDelta = left - co->left;
+ co->top = top;
+ co->left = left;
+
+ for (i = 0, el = form->elements; i < form->numComps; i++, el++) {
+ el->co->top += vertDelta;
+ el->top += vertDelta;
+ el->co->left += horizDelta;
+ el->left += horizDelta;
+ }
+}
+
+void newtDrawForm(newtComponent co) {
+ struct form * form = co->data;
+ struct element * el;
+ int i;
+
+ newtFormSetSize(co);
+
+ SLsmg_set_color(form->background);
+ newtClearBox(co->left, co->top, co->width, co->height);
+ for (i = 0, el = form->elements; i < form->numComps; i++, el++) {
+ /* the scrollbar *always* fits somewhere */
+ if (el->co == form->vertBar) {
+ el->co->ops->mapped(el->co, 1);
+ el->co->ops->draw(el->co);
+ } else {
+ /* only draw it if it'll fit on the screen vertically */
+ if (componentFits(co, i)) {
+ el->co->top = el->top - form->vertOffset;
+ el->co->ops->mapped(el->co, 1);
+ el->co->ops->draw(el->co);
+ } else {
+ el->co->ops->mapped(el->co, 0);
+ }
+ }
+ }
+
+ if (form->vertBar)
+ newtScrollbarSet(form->vertBar, form->vertOffset,
+ form->numRows - co->height);
+}
+
+static struct eventResult formEvent(newtComponent co, struct event ev) {
+ struct form * form = co->data;
+ newtComponent subco = form->elements[form->currComp].co;
+ int new, wrap = 0;
+ struct eventResult er;
+ int dir = 0, page = 0;
+ int i, num, found;
+ struct element * el;
+
+ er.result = ER_IGNORED;
+ if (!form->numComps) return er;
+
+ subco = form->elements[form->currComp].co;
+
+ switch (ev.when) {
+ case EV_EARLY:
+ if (ev.event == EV_KEYPRESS) {
+ if (ev.u.key == NEWT_KEY_TAB) {
+ er.result = ER_SWALLOWED;
+ dir = 1;
+ wrap = 1;
+ } else if (ev.u.key == NEWT_KEY_UNTAB) {
+ er.result = ER_SWALLOWED;
+ dir = -1;
+ wrap = 1;
+ }
+ }
+
+ if (form->numComps) {
+ i = form->currComp;
+ num = 0;
+ while (er.result == ER_IGNORED && num != form->numComps ) {
+ er = form->elements[i].co->ops->event(form->elements[i].co, ev);
+
+ num++;
+ i++;
+ if (i == form->numComps) i = 0;
+ }
+ }
+
+ break;
+
+ case EV_NORMAL:
+ if (ev.event == EV_MOUSE) {
+ found = 0;
+ for (i = 0, el = form->elements; i < form->numComps; i++, el++) {
+ if ((el->co->top <= ev.u.mouse.y) &&
+ (el->co->top + el->co->height > ev.u.mouse.y) &&
+ (el->co->left <= ev.u.mouse.x) &&
+ (el->co->left + el->co->width > ev.u.mouse.x)) {
+ found = 1;
+ if (el->co->takesFocus) {
+ gotoComponent(form, i);
+ subco = form->elements[form->currComp].co;
+ }
+ }
+ /* If we did not find a co to send this event to, we
+ should just swallow the event here. */
+ }
+ if (!found) {
+ er.result = ER_SWALLOWED;
+
+ return er;
+ }
+ }
+ er = subco->ops->event(subco, ev);
+ switch (er.result) {
+ case ER_NEXTCOMP:
+ er.result = ER_SWALLOWED;
+ dir = 1;
+ break;
+
+ case ER_EXITFORM:
+ form->exitComp = subco;
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case EV_LATE:
+ er = subco->ops->event(subco, ev);
+
+ if (er.result == ER_IGNORED) {
+ switch (ev.u.key) {
+ case NEWT_KEY_UP:
+ case NEWT_KEY_LEFT:
+ case NEWT_KEY_BKSPC:
+ er.result = ER_SWALLOWED;
+ dir = -1;
+ break;
+
+ case NEWT_KEY_DOWN:
+ case NEWT_KEY_RIGHT:
+ er.result = ER_SWALLOWED;
+ dir = 1;
+ break;
+
+ case NEWT_KEY_PGUP:
+ er.result = ER_SWALLOWED;
+ dir = -1;
+ page = 1;
+ break;
+
+ case NEWT_KEY_PGDN:
+ er.result = ER_SWALLOWED;
+ dir = 1;
+ page = 1;
+ break;
+ }
+ }
+ }
+
+ if (dir) {
+ new = form->currComp;
+
+ if (page) {
+ new += dir * co->height;
+ if (new < 0)
+ new = 0;
+ else if (new >= form->numComps)
+ new = (form->numComps - 1);
+
+ while (!form->elements[new].co->takesFocus)
+ new = new - dir;
+ } else {
+ do {
+ new += dir;
+
+ if (wrap) {
+ if (new < 0)
+ new = form->numComps - 1;
+ else if (new >= form->numComps)
+ new = 0;
+ } else if (new < 0 || new >= form->numComps)
+ return er;
+ } while (!form->elements[new].co->takesFocus);
+ }
+
+ /* make sure this component is visible */
+ if (!componentFits(co, new)) {
+ gotoComponent(form, -1);
+
+ if (dir < 0) {
+ /* make the new component the first one */
+ form->vertOffset = form->elements[new].top - co->top;
+ } else {
+ /* make the new component the last one */
+ form->vertOffset = (form->elements[new].top +
+ form->elements[new].co->height) -
+ (co->top + co->height);
+ }
+
+ if (form->vertOffset < 0) form->vertOffset = 0;
+ if (form->vertOffset > (form->numRows - co->height))
+ form->vertOffset = form->numRows - co->height;
+
+ newtDrawForm(co);
+ }
+
+ gotoComponent(form, new);
+ er.result = ER_SWALLOWED;
+ }
+
+ return er;
+}
+
+/* this also destroys all of the components on the form */
+void newtFormDestroy(newtComponent co) {
+ newtComponent subco;
+ struct form * form = co->data;
+ int i;
+
+ /* first, destroy all of the components */
+ for (i = 0; i < form->numComps; i++) {
+ subco = form->elements[i].co;
+ if (subco->ops->destroy) {
+ subco->ops->destroy(subco);
+ } else {
+ if (subco->data) free(subco->data);
+ free(subco);
+ }
+ }
+
+ if (form->hotKeys) free(form->hotKeys);
+
+ free(form->elements);
+ free(form);
+ free(co);
+}
+
+newtComponent newtRunForm(newtComponent co) {
+ struct newtExitStruct es;
+
+ newtFormRun(co, &es);
+ if (es.reason == NEWT_EXIT_HOTKEY) {
+ if (es.u.key == NEWT_KEY_F12) {
+ es.reason = NEWT_EXIT_COMPONENT;
+ es.u.co = co;
+ } else {
+ return NULL;
+ }
+ }
+
+ return es.u.co;
+}
+
+void newtFormAddHotKey(newtComponent co, int key) {
+ struct form * form = co->data;
+
+ form->numHotKeys++;
+ form->hotKeys = realloc(form->hotKeys, sizeof(int) * form->numHotKeys);
+ form->hotKeys[form->numHotKeys - 1] = key;
+}
+
+void newtFormSetSize(newtComponent co) {
+ struct form * form = co->data;
+ int delta, i;
+ struct element * el;
+
+ if (form->beenSet) return;
+
+ form->beenSet = 1;
+
+ if (!form->numComps) return;
+
+ co->width = 0;
+ if (!form->fixedHeight) co->height = 0;
+
+ co->top = form->elements[0].co->top;
+ co->left = form->elements[0].co->left;
+ for (i = 0, el = form->elements; i < form->numComps; i++, el++) {
+ if (el->co->ops == &formOps)
+ newtFormSetSize(el->co);
+
+ el->left = el->co->left;
+ el->top = el->co->top;
+
+ if (co->left > el->co->left) {
+ delta = co->left - el->co->left;
+ co->left -= delta;
+ co->width += delta;
+ }
+
+ if (co->top > el->co->top) {
+ delta = co->top - el->co->top;
+ co->top -= delta;
+ if (!form->fixedHeight)
+ co->height += delta;
+ }
+
+ if ((co->left + co->width) < (el->co->left + el->co->width))
+ co->width = (el->co->left + el->co->width) - co->left;
+
+ if (!form->fixedHeight) {
+ if ((co->top + co->height) < (el->co->top + el->co->height))
+ co->height = (el->co->top + el->co->height) - co->top;
+ }
+
+ if ((el->co->top + el->co->height - co->top) > form->numRows) {
+ form->numRows = el->co->top + el->co->height - co->top;
+ }
+ }
+}
+
+void newtFormRun(newtComponent co, struct newtExitStruct * es) {
+ struct form * form = co->data;
+ struct event ev;
+ struct eventResult er;
+ int key, i, max;
+ int done = 0;
+ fd_set readSet, writeSet;
+ struct timeval nextTimeout, now, timeout;
+
+ newtFormSetSize(co);
+ /* draw all of the components */
+ newtDrawForm(co);
+
+ if (form->currComp == -1) {
+ gotoComponent(form, 0);
+ } else
+ gotoComponent(form, form->currComp);
+
+ while (!done) {
+ newtRefresh();
+
+ FD_ZERO(&readSet);
+ FD_ZERO(&writeSet);
+ FD_SET(0, &readSet);
+ max = form->maxFd;
+
+ for (i = 0; i < form->numFds; i++) {
+ if (form->fds[i].flags & NEWT_FD_READ)
+ FD_SET(form->fds[i].fd, &readSet);
+ if (form->fds[i].flags & NEWT_FD_WRITE)
+ FD_SET(form->fds[i].fd, &writeSet);
+ }
+
+ if (form->timer) {
+ /* Calculate when we next need to return with a timeout. Do
+ this inside the loop in case a callback resets the timer. */
+ if (!form->lastTimeout.tv_sec && !form->lastTimeout.tv_usec)
+ gettimeofday(&form->lastTimeout, NULL);
+
+ nextTimeout.tv_sec = form->lastTimeout.tv_sec +
+ (form->timer / 1000);
+ nextTimeout.tv_usec = form->lastTimeout.tv_usec +
+ (form->timer % 1000) * 1000;
+
+ gettimeofday(&now, 0);
+
+ if (now.tv_sec > nextTimeout.tv_sec) {
+ timeout.tv_sec = timeout.tv_usec = 0;
+ } else if (now.tv_sec == nextTimeout.tv_sec) {
+ timeout.tv_sec = 0;
+ if (now.tv_usec > nextTimeout.tv_usec)
+ timeout.tv_usec = 0;
+ else
+ timeout.tv_usec = nextTimeout.tv_usec - now.tv_usec;
+ } else if (now.tv_sec < nextTimeout.tv_sec) {
+ timeout.tv_sec = nextTimeout.tv_sec - now.tv_sec;
+ if (now.tv_usec > nextTimeout.tv_usec)
+ timeout.tv_sec--,
+ timeout.tv_usec = nextTimeout.tv_usec + 1000000 -
+ now.tv_usec;
+ else
+ timeout.tv_usec = nextTimeout.tv_usec - now.tv_usec;
+ }
+ } else {
+ timeout.tv_sec = timeout.tv_usec = 0;
+ }
+
+ i = select(max + 1, &readSet, &writeSet, NULL,
+ form->timer ? &timeout : NULL);
+ if (i < 0) continue; /* ?? What should we do here? */
+
+ if (i == 0) {
+ done = 1;
+ es->reason = NEWT_EXIT_TIMER;
+ gettimeofday(&form->lastTimeout, NULL);
+ } else
+ {
+ if (FD_ISSET(0, &readSet)) {
+
+ key = newtGetKey();
+
+ if (key == NEWT_KEY_RESIZE) {
+ /* newtResizeScreen(1); */
+ continue;
+ }
+
+ for (i = 0; i < form->numHotKeys; i++) {
+ if (form->hotKeys[i] == key) {
+ es->reason = NEWT_EXIT_HOTKEY;
+ es->u.key = key;
+ done = 1;
+ break;
+ }
+ }
+
+ if (key == NEWT_KEY_F1 && form->helpTag && form->helpCb)
+ form->helpCb(co, form->helpTag);
+
+ if (!done) {
+ ev.event = EV_KEYPRESS;
+ ev.u.key = key;
+
+ er = sendEvent(co, ev);
+
+ if (er.result == ER_EXITFORM) {
+ done = 1;
+ es->reason = NEWT_EXIT_COMPONENT;
+ es->u.co = form->exitComp;
+ }
+ }
+ } else {
+ es->reason = NEWT_EXIT_FDREADY;
+ done = 1;
+ }
+ }
+ }
+ newtRefresh();
+}
+
+static struct eventResult sendEvent(newtComponent co, struct event ev) {
+ struct eventResult er;
+
+ ev.when = EV_EARLY;
+ er = co->ops->event(co, ev);
+
+ if (er.result == ER_IGNORED) {
+ ev.when = EV_NORMAL;
+ er = co->ops->event(co, ev);
+ }
+
+ if (er.result == ER_IGNORED) {
+ ev.when = EV_LATE;
+ er = co->ops->event(co, ev);
+ }
+
+ return er;
+}
+
+static void gotoComponent(struct form * form, int newComp) {
+ struct event ev;
+
+ if (form->currComp != -1) {
+ ev.event = EV_UNFOCUS;
+ sendEvent(form->elements[form->currComp].co, ev);
+ }
+
+ form->currComp = newComp;
+
+ if (form->currComp != -1) {
+ ev.event = EV_FOCUS;
+ ev.when = EV_NORMAL;
+ sendEvent(form->elements[form->currComp].co, ev);
+ }
+}
+
+void newtComponentAddCallback(newtComponent co, newtCallback f, void * data) {
+ co->callback = f;
+ co->callbackData = data;
+}
+
+void newtComponentTakesFocus(newtComponent co, int val) {
+ co->takesFocus = val;
+}
+
+void newtFormSetBackground(newtComponent co, int color) {
+ struct form * form = co->data;
+
+ form->background = color;
+}
+
+void newtFormWatchFd(newtComponent co, int fd, int fdFlags) {
+ struct form * form = co->data;
+
+ form->fds = realloc(form->fds, (form->numFds + 1) * sizeof(*form->fds));
+ form->fds[form->numFds].fd = fd;
+ form->fds[form->numFds++].flags = fdFlags;
+ if (form->maxFd < fd) form->maxFd = fd;
+}
+
+void newtSetHelpCallback(newtCallback cb) {
+ helpCallback = cb;
+}
diff --git a/mdk-stage1/newt/grid.c b/mdk-stage1/newt/grid.c
new file mode 100644
index 000000000..433011396
--- /dev/null
+++ b/mdk-stage1/newt/grid.c
@@ -0,0 +1,389 @@
+#include <alloca.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "newt.h"
+#include "newt_pr.h"
+
+struct gridField {
+ enum newtGridElement type;
+ union {
+ newtGrid grid;
+ newtComponent co;
+ } u;
+ int padLeft, padTop, padRight, padBottom;
+ int anchor;
+ int flags;
+};
+
+struct grid_s {
+ int rows, cols;
+ int width, height; /* totals, -1 means unknown */
+ struct gridField ** fields;
+};
+
+/* this is a bit of a hack */
+extern struct componentOps formOps[];
+
+newtGrid newtCreateGrid(int cols, int rows) {
+ newtGrid grid;
+
+ grid = malloc(sizeof(*grid));
+ grid->rows = rows;
+ grid->cols = cols;
+
+ grid->fields = malloc(sizeof(*grid->fields) * cols);
+ while (cols--) {
+ grid->fields[cols] = malloc(sizeof(**(grid->fields)) * rows);
+ memset(grid->fields[cols], 0, sizeof(**(grid->fields)) * rows);
+ }
+
+ grid->width = grid->height = -1;
+
+ return grid;
+}
+
+void newtGridSetField(newtGrid grid, int col, int row,
+ enum newtGridElement type, void * val, int padLeft,
+ int padTop, int padRight, int padBottom, int anchor,
+ int flags) {
+ struct gridField * field = &grid->fields[col][row];
+
+ if (field->type == NEWT_GRID_SUBGRID)
+ newtGridFree(field->u.grid, 1);
+
+ field->type = type;
+ field->u.co = (void *) val;
+
+ field->padLeft = padLeft;
+ field->padRight = padRight;
+ field->padTop = padTop;
+ field->padBottom = padBottom;
+ field->anchor = anchor;
+ field->flags = flags;
+
+ grid->width = grid->height = -1;
+}
+
+static void distSpace(int extra, int items, int * list) {
+ int all, some, i;
+
+ all = extra / items;
+ some = extra % items;
+ for (i = 0; i < items; i++) {
+ list[i] += all;
+ if (some) {
+ list[i]++;
+ some--;
+ }
+ }
+}
+
+static void shuffleGrid(newtGrid grid, int left, int top, int set) {
+ struct gridField * field;
+ int row, col;
+ int i, j;
+ int minWidth, minHeight;
+ int * widths, * heights;
+ int thisLeft, thisTop;
+ int x, y, remx, remy;
+
+ widths = alloca(sizeof(*widths) * grid->cols);
+ memset(widths, 0, sizeof(*widths) * grid->cols);
+ heights = alloca(sizeof(*heights) * grid->rows);
+ memset(heights, 0, sizeof(*heights) * grid->rows);
+
+ minWidth = 0;
+ for (row = 0; row < grid->rows; row++) {
+ i = 0;
+ for (col = 0; col < grid->cols; col++) {
+ field = &grid->fields[col][row];
+ if (field->type == NEWT_GRID_SUBGRID) {
+ /* we'll have to redo this later */
+ if (field->u.grid->width == -1)
+ shuffleGrid(field->u.grid, left, top, 0);
+ j = field->u.grid->width;
+ } else if (field->type == NEWT_GRID_COMPONENT) {
+ if (field->u.co->ops == formOps)
+ newtFormSetSize(field->u.co);
+ j = field->u.co->width;
+ } else
+ j = 0;
+
+ j += field->padLeft + field->padRight;
+
+ if (j > widths[col]) widths[col] = j;
+ i += widths[col];
+ }
+
+ if (i > minWidth) minWidth = i;
+ }
+
+ minHeight = 0;
+ for (col = 0; col < grid->cols; col++) {
+ i = 0;
+ for (row = 0; row < grid->rows; row++) {
+ field = &grid->fields[col][row];
+ if (field->type == NEWT_GRID_SUBGRID) {
+ /* we'll have to redo this later */
+ if (field->u.grid->height == -1)
+ shuffleGrid(field->u.grid, 0, 0, 0);
+ j = field->u.grid->height;
+ } else if (field->type == NEWT_GRID_COMPONENT){
+ j = field->u.co->height;
+ } else
+ j = 0;
+
+ j += field->padTop + field->padBottom;
+
+ if (j > heights[row]) heights[row] = j;
+ i += heights[row];
+ }
+
+ if (i > minHeight) minHeight = i;
+ }
+
+ /* this catches the -1 case */
+ if (grid->width < minWidth) grid->width = minWidth; /* ack! */
+ if (grid->height < minHeight) grid->height = minHeight; /* ditto! */
+
+ if (!set) return;
+
+ distSpace(grid->width - minWidth, grid->cols, widths);
+ distSpace(grid->height - minHeight, grid->rows, heights);
+
+ thisTop = top;
+ for (row = 0; row < grid->rows; row++) {
+ i = 0;
+ thisLeft = left;
+ for (col = 0; col < grid->cols; col++) {
+ field = &grid->fields[col][row];
+
+ if (field->type == NEWT_GRID_EMPTY) continue;
+
+ x = thisLeft + field->padLeft;
+ remx = widths[col] - field->padLeft - field->padRight;
+ y = thisTop + field->padTop;
+ remy = heights[row] - field->padTop - field->padBottom;
+
+ if (field->type == NEWT_GRID_SUBGRID) {
+ remx -= field->u.grid->width;
+ remy -= field->u.grid->height;
+ } else if (field->type == NEWT_GRID_COMPONENT) {
+ remx -= field->u.co->width;
+ remy -= field->u.co->height;
+ }
+
+ if (!(field->flags & NEWT_GRID_FLAG_GROWX)) {
+ if (field->anchor & NEWT_ANCHOR_RIGHT)
+ x += remx;
+ else if (!(field->anchor & NEWT_ANCHOR_LEFT))
+ x += (remx / 2);
+ }
+
+ if (!(field->flags & NEWT_GRID_FLAG_GROWY)) {
+ if (field->anchor & NEWT_ANCHOR_BOTTOM)
+ y += remx;
+ else if (!(field->anchor & NEWT_ANCHOR_TOP))
+ y += (remy / 2);
+ }
+
+ if (field->type == NEWT_GRID_SUBGRID) {
+ if (field->flags & NEWT_GRID_FLAG_GROWX)
+ field->u.grid->width = widths[col] - field->padLeft
+ - field->padRight;
+ if (field->flags & NEWT_GRID_FLAG_GROWY)
+ field->u.grid->height = heights[col] - field->padTop
+ - field->padBottom;
+
+ shuffleGrid(field->u.grid, x, y, 1);
+ } else if (field->type == NEWT_GRID_COMPONENT) {
+ field->u.co->ops->place(field->u.co, x, y);
+ }
+
+ thisLeft += widths[col];
+ }
+
+ thisTop += heights[row];
+ }
+}
+
+void newtGridPlace(newtGrid grid, int left, int top) {
+ shuffleGrid(grid, left, top, 1);
+}
+
+void newtGridFree(newtGrid grid, int recurse) {
+ int row, col;
+
+ for (col = 0; col < grid->cols; col++) {
+ if (recurse) {
+ for (row = 0; row < grid->rows; row++) {
+ if (grid->fields[col][row].type == NEWT_GRID_SUBGRID)
+ newtGridFree(grid->fields[col][row].u.grid, 1);
+ }
+ }
+
+ free(grid->fields[col]);
+ }
+
+ free(grid->fields);
+ free(grid);
+}
+
+void newtGridGetSize(newtGrid grid, int * width, int * height) {
+ if (grid->width == -1 || grid->height == -1) {
+ grid->width = grid->height = -1;
+ shuffleGrid(grid, 0, 0, 1);
+ }
+
+ *width = grid->width;
+ *height = grid->height;
+}
+
+void newtGridWrappedWindow(newtGrid grid, char * title) {
+ int width, height, offset = 0;
+
+ newtGridGetSize(grid, &width, &height);
+ if (width < strlen(title) + 2) {
+ offset = ((strlen(title) + 2) - width) / 2;
+ width = strlen(title) + 2;
+ }
+ newtCenteredWindow(width + 2, height + 2, title);
+ newtGridPlace(grid, 1 + offset, 1);
+}
+
+void newtGridWrappedWindowAt(newtGrid grid, char * title, int left, int top) {
+ int width, height;
+
+ newtGridGetSize(grid, &width, &height);
+ newtOpenWindow(left, top, width + 2, height + 2, title);
+ newtGridPlace(grid, 1, 1);
+}
+
+void newtGridAddComponentsToForm(newtGrid grid, newtComponent form,
+ int recurse) {
+ int row, col;
+
+ for (col = 0; col < grid->cols; col++) {
+ for (row = 0; row < grid->rows; row++) {
+ if (grid->fields[col][row].type == NEWT_GRID_SUBGRID && recurse)
+ newtGridAddComponentsToForm(grid->fields[col][row].u.grid,
+ form, 1);
+ else if (grid->fields[col][row].type == NEWT_GRID_COMPONENT)
+ newtFormAddComponent(form, grid->fields[col][row].u.co);
+ }
+ }
+}
+
+/* this handles up to 50 items */
+static newtGrid stackem(int isVert, enum newtGridElement type1, void * what1,
+ va_list args, int close) {
+ struct item {
+ enum newtGridElement type;
+ void * what;
+ } items[50];
+ int i, num;
+ newtGrid grid;
+
+ items[0].type = type1, items[0].what = what1, num = 1;
+ while (1) {
+ items[num].type = va_arg(args, enum newtGridElement);
+ if (items[num].type == NEWT_GRID_EMPTY) break;
+
+ items[num].what = va_arg(args, void *);
+ num++;
+ }
+
+ grid = newtCreateGrid(isVert ? 1 : num, isVert ? num : 1);
+
+ for (i = 0; i < num; i++) {
+ newtGridSetField(grid, isVert ? 0 : i, isVert ? i : 0,
+ items[i].type, items[i].what,
+ close ? 0 : (i ? (isVert ? 0 : 1) : 0),
+ close ? 0 : (i ? (isVert ? 1 : 0) : 0), 0, 0, 0, 0);
+ }
+
+ return grid;
+}
+
+newtGrid newtGridHCloseStacked(enum newtGridElement type1, void * what1, ...) {
+ va_list args;
+ newtGrid grid;
+
+ va_start(args, what1);
+
+ grid = stackem(0, type1, what1, args, 1);
+
+ va_start(args, what1);
+
+ return grid;
+}
+
+newtGrid newtGridVCloseStacked(enum newtGridElement type1, void * what1, ...) {
+ va_list args;
+ newtGrid grid;
+
+ va_start(args, what1);
+
+ grid = stackem(1, type1, what1, args, 1);
+
+ va_start(args, what1);
+
+ return grid;
+}
+
+newtGrid newtGridVStacked(enum newtGridElement type1, void * what1, ...) {
+ va_list args;
+ newtGrid grid;
+
+ va_start(args, what1);
+
+ grid = stackem(1, type1, what1, args, 0);
+
+ va_start(args, what1);
+
+ return grid;
+}
+
+newtGrid newtGridHStacked(enum newtGridElement type1, void * what1, ...) {
+ va_list args;
+ newtGrid grid;
+
+ va_start(args, what1);
+
+ grid = stackem(0, type1, what1, args, 0);
+
+ va_start(args, what1);
+
+ return grid;
+}
+
+newtGrid newtGridBasicWindow(newtComponent text, newtGrid middle,
+ newtGrid buttons) {
+ newtGrid grid;
+
+ grid = newtCreateGrid(1, 3);
+ newtGridSetField(grid, 0, 0, NEWT_GRID_COMPONENT, text,
+ 0, 0, 0, 0, NEWT_ANCHOR_LEFT, 0);
+ newtGridSetField(grid, 0, 1, NEWT_GRID_SUBGRID, middle,
+ 0, 1, 0, 0, 0, 0);
+ newtGridSetField(grid, 0, 2, NEWT_GRID_SUBGRID, buttons,
+ 0, 1, 0, 0, 0, NEWT_GRID_FLAG_GROWX);
+
+ return grid;
+}
+
+newtGrid newtGridSimpleWindow(newtComponent text, newtComponent middle,
+ newtGrid buttons) {
+ newtGrid grid;
+
+ grid = newtCreateGrid(1, 3);
+ newtGridSetField(grid, 0, 0, NEWT_GRID_COMPONENT, text,
+ 0, 0, 0, 0, NEWT_ANCHOR_LEFT, 0);
+ newtGridSetField(grid, 0, 1, NEWT_GRID_COMPONENT, middle,
+ 0, 1, 0, 0, 0, 0);
+ newtGridSetField(grid, 0, 2, NEWT_GRID_SUBGRID, buttons,
+ 0, 1, 0, 0, 0, NEWT_GRID_FLAG_GROWX);
+
+ return grid;
+}
diff --git a/mdk-stage1/newt/label.c b/mdk-stage1/newt/label.c
new file mode 100644
index 000000000..f1a9cebbf
--- /dev/null
+++ b/mdk-stage1/newt/label.c
@@ -0,0 +1,81 @@
+#include <slang.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "newt.h"
+#include "newt_pr.h"
+
+struct label {
+ char * text;
+ int length;
+};
+
+static void labelDraw(newtComponent co);
+static void labelDestroy(newtComponent co);
+
+static struct componentOps labelOps = {
+ labelDraw,
+ newtDefaultEventHandler,
+ labelDestroy,
+ newtDefaultPlaceHandler,
+ newtDefaultMappedHandler,
+} ;
+
+newtComponent newtLabel(int left, int top, const char * text) {
+ newtComponent co;
+ struct label * la;
+
+ co = malloc(sizeof(*co));
+ la = malloc(sizeof(struct label));
+ co->data = la;
+
+ co->ops = &labelOps;
+
+ co->height = 1;
+ co->width = strlen(text);
+ co->top = top;
+ co->left = left;
+ co->takesFocus = 0;
+
+ la->length = strlen(text);
+ la->text = strdup(text);
+
+ return co;
+}
+
+void newtLabelSetText(newtComponent co, const char * text) {
+ int newLength;
+ struct label * la = co->data;
+
+ newLength = strlen(text);
+ if (newLength <= la->length) {
+ memset(la->text, ' ', la->length);
+ memcpy(la->text, text, newLength);
+ } else {
+ free(la->text);
+ la->text = strdup(text);
+ la->length = newLength;
+ co->width = newLength;
+ }
+
+ labelDraw(co);
+}
+
+static void labelDraw(newtComponent co) {
+ struct label * la = co->data;
+
+ if (co->isMapped == -1) return;
+
+ SLsmg_set_color(COLORSET_LABEL);
+
+ newtGotorc(co->top, co->left);
+ SLsmg_write_string(la->text);
+}
+
+static void labelDestroy(newtComponent co) {
+ struct label * la = co->data;
+
+ free(la->text);
+ free(la);
+ free(co);
+}
diff --git a/mdk-stage1/newt/listbox.c b/mdk-stage1/newt/listbox.c
new file mode 100644
index 000000000..ef276aeb4
--- /dev/null
+++ b/mdk-stage1/newt/listbox.c
@@ -0,0 +1,752 @@
+/* This goofed-up box whacked into shape by Elliot Lee <sopwith@cuc.edu>
+ (from the original listbox by Erik Troan <ewt@redhat.com>)
+ and contributed to newt for use under the LGPL license.
+ Copyright (C) 1996, 1997 Elliot Lee */
+
+#include <slang.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "newt.h"
+#include "newt_pr.h"
+
+
+/* Linked list of items in the listbox */
+struct items {
+ char * text;
+ const void *data;
+ unsigned char isSelected;
+ struct items *next;
+};
+
+/* Holds all the relevant information for this listbox */
+struct listbox {
+ newtComponent sb; /* Scrollbar on right side of listbox */
+ int curWidth; /* size of text w/o scrollbar or border*/
+ int curHeight; /* size of text w/o border */
+ int sbAdjust;
+ int bdxAdjust, bdyAdjust;
+ int numItems, numSelected;
+ int userHasSetWidth;
+ int currItem, startShowItem; /* startShowItem is the first item displayed
+ on the screen */
+ int isActive; /* If we handle key events all the time, it seems
+ to do things even when they are supposed to be for
+ another button/whatever */
+ struct items *boxItems;
+ int grow;
+ int flags; /* flags for this listbox, right now just
+ NEWT_FLAG_RETURNEXIT */
+};
+
+static void listboxDraw(newtComponent co);
+static void listboxDestroy(newtComponent co);
+static struct eventResult listboxEvent(newtComponent co, struct event ev);
+static void newtListboxRealSetCurrent(newtComponent co);
+static void listboxPlace(newtComponent co, int newLeft, int newTop);
+static inline void updateWidth(newtComponent co, struct listbox * li,
+ int maxField);
+static void listboxMapped(newtComponent co, int isMapped);
+
+static struct componentOps listboxOps = {
+ listboxDraw,
+ listboxEvent,
+ listboxDestroy,
+ listboxPlace,
+ listboxMapped,
+};
+
+static void listboxMapped(newtComponent co, int isMapped) {
+ struct listbox * li = co->data;
+
+ co->isMapped = isMapped;
+ if (li->sb)
+ li->sb->ops->mapped(li->sb, isMapped);
+}
+
+static void listboxPlace(newtComponent co, int newLeft, int newTop) {
+ struct listbox * li = co->data;
+
+ co->top = newTop;
+ co->left = newLeft;
+
+ if (li->sb)
+ li->sb->ops->place(li->sb, co->left + co->width - li->bdxAdjust - 1,
+ co->top);
+}
+
+newtComponent newtListbox(int left, int top, int height, int flags) {
+ newtComponent co, sb;
+ struct listbox * li;
+
+ if (!(co = malloc(sizeof(*co))))
+ return NULL;
+
+ if (!(li = malloc(sizeof(struct listbox)))) {
+ free(co);
+ return NULL;
+ }
+
+ li->boxItems = NULL;
+ li->numItems = 0;
+ li->currItem = 0;
+ li->numSelected = 0;
+ li->isActive = 0;
+ li->userHasSetWidth = 0;
+ li->startShowItem = 0;
+ li->sbAdjust = 0;
+ li->bdxAdjust = 0;
+ li->bdyAdjust = 0;
+ li->flags = flags & (NEWT_FLAG_RETURNEXIT | NEWT_FLAG_BORDER |
+ NEWT_FLAG_MULTIPLE);
+
+ if (li->flags & NEWT_FLAG_BORDER) {
+ li->bdxAdjust = 2;
+ li->bdyAdjust = 1;
+ }
+
+ co->height = height;
+ li->curHeight = co->height - (2 * li->bdyAdjust);
+
+ if (height) {
+ li->grow = 0;
+ if (flags & NEWT_FLAG_SCROLL) {
+ sb = newtVerticalScrollbar(left, top + li->bdyAdjust,
+ li->curHeight,
+ COLORSET_LISTBOX, COLORSET_ACTLISTBOX);
+ li->sbAdjust = 3;
+ } else {
+ sb = NULL;
+ }
+ } else {
+ li->grow = 1;
+ sb = NULL;
+ }
+
+ li->sb = sb;
+ co->data = li;
+ co->isMapped = 0;
+ co->left = left;
+ co->top = top;
+ co->ops = &listboxOps;
+ co->takesFocus = 1;
+ co->callback = NULL;
+
+ updateWidth(co, li, 5);
+
+ return co;
+}
+
+static inline void updateWidth(newtComponent co, struct listbox * li,
+ int maxField) {
+ li->curWidth = maxField;
+ co->width = li->curWidth + li->sbAdjust + 2 * li->bdxAdjust;
+
+ if (li->sb)
+ li->sb->left = co->left + co->width - li->bdxAdjust - 1;
+}
+
+void newtListboxSetCurrentByKey(newtComponent co, void * key) {
+ struct listbox * li = co->data;
+ struct items * item;
+ int i;
+
+ item = li->boxItems, i = 0;
+ while (item && item->data != key)
+ item = item->next, i++;
+
+ if (item)
+ newtListboxSetCurrent(co, i);
+}
+
+void newtListboxSetCurrent(newtComponent co, int num)
+{
+ struct listbox * li = co->data;
+
+ if (num >= li->numItems)
+ li->currItem = li->numItems - 1;
+ else if (num < 0)
+ li->currItem = 0;
+ else
+ li->currItem = num;
+
+ if (li->currItem < li->startShowItem)
+ li->startShowItem = li->currItem;
+ else if (li->currItem - li->startShowItem > li->curHeight - 1)
+ li->startShowItem = li->currItem - li->curHeight + 1;
+ if (li->startShowItem + li->curHeight > li->numItems)
+ li->startShowItem = li->numItems - li->curHeight;
+ if(li->startShowItem < 0)
+ li->startShowItem = 0;
+
+ newtListboxRealSetCurrent(co);
+}
+
+static void newtListboxRealSetCurrent(newtComponent co)
+{
+ struct listbox * li = co->data;
+
+ if(li->sb)
+ newtScrollbarSet(li->sb, li->currItem + 1, li->numItems);
+ listboxDraw(co);
+ if(co->callback) co->callback(co, co->callbackData);
+}
+
+void newtListboxSetWidth(newtComponent co, int width) {
+ struct listbox * li = co->data;
+
+ co->width = width;
+ li->curWidth = co->width - li->sbAdjust - 2 * li->bdxAdjust;
+ li->userHasSetWidth = 1;
+ if (li->sb) li->sb->left = co->width + co->left - 1;
+ listboxDraw(co);
+}
+
+void * newtListboxGetCurrent(newtComponent co) {
+ struct listbox * li = co->data;
+ int i;
+ struct items *item;
+
+ for(i = 0, item = li->boxItems; item != NULL && i < li->currItem;
+ i++, item = item->next);
+
+ if (item)
+ return (void *)item->data;
+ else
+ return NULL;
+}
+
+void newtListboxSelectItem(newtComponent co, const void * key,
+ enum newtFlagsSense sense)
+{
+ struct listbox * li = co->data;
+ int i;
+ struct items * item;
+
+ item = li->boxItems, i = 0;
+ while (item && item->data != key)
+ item = item->next, i++;
+
+ if (!item) return;
+
+ if (item->isSelected)
+ li->numSelected--;
+
+ switch(sense) {
+ case NEWT_FLAGS_RESET:
+ item->isSelected = 0; break;
+ case NEWT_FLAGS_SET:
+ item->isSelected = 1; break;
+ case NEWT_FLAGS_TOGGLE:
+ item->isSelected = !item->isSelected;
+ }
+
+ if (item->isSelected)
+ li->numSelected++;
+
+ listboxDraw(co);
+}
+
+void newtListboxClearSelection(newtComponent co)
+{
+ struct items *item;
+ struct listbox * li = co->data;
+
+ for(item = li->boxItems; item != NULL;
+ item = item->next)
+ item->isSelected = 0;
+ li->numSelected = 0;
+ listboxDraw(co);
+}
+
+/* Free the returned array after use, but NOT the values in the array */
+void ** newtListboxGetSelection(newtComponent co, int *numitems)
+{
+ struct listbox * li;
+ int i;
+ void **retval;
+ struct items *item;
+
+ if(!co || !numitems) return NULL;
+
+ li = co->data;
+ if(!li || !li->numSelected) return NULL;
+
+ retval = malloc(li->numSelected * sizeof(void *));
+ for(i = 0, item = li->boxItems; item != NULL;
+ item = item->next)
+ if(item->isSelected)
+ retval[i++] = (void *)item->data;
+ *numitems = li->numSelected;
+ return retval;
+}
+
+void newtListboxSetEntry(newtComponent co, int num, const char * text) {
+ struct listbox * li = co->data;
+ int i;
+ struct items *item;
+
+ for(i = 0, item = li->boxItems; item != NULL && i < num;
+ i++, item = item->next);
+
+ if(!item)
+ return;
+ else {
+ free(item->text);
+ item->text = strdup(text);
+ }
+ if (li->userHasSetWidth == 0 && strlen(text) > li->curWidth) {
+ updateWidth(co, li, strlen(text));
+ }
+
+ if (num >= li->startShowItem && num <= li->startShowItem + co->height)
+ listboxDraw(co);
+}
+
+void newtListboxSetData(newtComponent co, int num, void * data) {
+ struct listbox * li = co->data;
+ int i;
+ struct items *item;
+
+ for(i = 0, item = li->boxItems; item != NULL && i < num;
+ i++, item = item->next);
+
+ item->data = data;
+}
+
+int newtListboxAppendEntry(newtComponent co, const char * text,
+ const void * data) {
+ struct listbox * li = co->data;
+ struct items *item;
+
+ if(li->boxItems) {
+ for (item = li->boxItems; item->next != NULL; item = item->next);
+
+ item = item->next = malloc(sizeof(struct items));
+ } else {
+ item = li->boxItems = malloc(sizeof(struct items));
+ }
+
+ if (!li->userHasSetWidth && text && (strlen(text) > li->curWidth))
+ updateWidth(co, li, strlen(text));
+
+ item->text = strdup(text); item->data = data; item->next = NULL;
+ item->isSelected = 0;
+
+ if (li->grow)
+ co->height++, li->curHeight++;
+ li->numItems++;
+
+ return 0;
+}
+
+int newtListboxInsertEntry(newtComponent co, const char * text,
+ const void * data, void * key) {
+ struct listbox * li = co->data;
+ struct items *item, *t;
+
+ if (li->boxItems) {
+ if (key) {
+ item = li->boxItems;
+ while (item && item->data != key) item = item->next;
+
+ if (!item) return 1;
+
+ t = item->next;
+ item = item->next = malloc(sizeof(struct items));
+ item->next = t;
+ } else {
+ t = li->boxItems;
+ item = li->boxItems = malloc(sizeof(struct items));
+ item->next = t;
+ }
+ } else if (key) {
+ return 1;
+ } else {
+ item = li->boxItems = malloc(sizeof(struct items));
+ item->next = NULL;
+ }
+
+ if (!li->userHasSetWidth && text && (strlen(text) > li->curWidth))
+ updateWidth(co, li, strlen(text));
+
+ item->text = strdup(text?text:"(null)"); item->data = data;
+ item->isSelected = 0;
+
+ if (li->sb)
+ li->sb->left = co->left + co->width - li->bdxAdjust - 1;
+ li->numItems++;
+
+ listboxDraw(co);
+
+ return 0;
+}
+
+int newtListboxDeleteEntry(newtComponent co, void * key) {
+ struct listbox * li = co->data;
+ int widest = 0, t;
+ struct items *item, *item2 = NULL;
+ int num;
+
+ if (li->boxItems == NULL || li->numItems <= 0)
+ return 0;
+
+ num = 0;
+
+ item2 = NULL, item = li->boxItems;
+ while (item && item->data != key) {
+ item2 = item;
+ item = item->next;
+ num++;
+ }
+
+ if (!item)
+ return -1;
+
+ if (item2)
+ item2->next = item->next;
+ else
+ li->boxItems = item->next;
+
+ free(item->text);
+ free(item);
+ li->numItems--;
+
+ if (!li->userHasSetWidth) {
+ widest = 0;
+ for (item = li->boxItems; item != NULL; item = item->next)
+ if ((t = strlen(item->text)) > widest) widest = t;
+ }
+
+ if (li->currItem >= num)
+ li->currItem--;
+
+ if (!li->userHasSetWidth) {
+ updateWidth(co, li, widest);
+ }
+
+ listboxDraw(co);
+
+ return 0;
+}
+
+void newtListboxClear(newtComponent co)
+{
+ struct listbox * li;
+ struct items *anitem, *nextitem;
+ if(co == NULL || (li = co->data) == NULL)
+ return;
+ for(anitem = li->boxItems; anitem != NULL; anitem = nextitem) {
+ nextitem = anitem->next;
+ free(anitem->text);
+ free(anitem);
+ }
+ li->numItems = li->numSelected = li->currItem = li->startShowItem = 0;
+ li->boxItems = NULL;
+ if (!li->userHasSetWidth)
+ updateWidth(co, li, 5);
+}
+
+/* If you don't want to get back the text, pass in NULL for the ptr-ptr. Same
+ goes for the data. */
+void newtListboxGetEntry(newtComponent co, int num, char **text, void **data) {
+ struct listbox * li = co->data;
+ int i;
+ struct items *item;
+
+ if (!li->boxItems || num >= li->numItems) {
+ if(text)
+ *text = NULL;
+ if(data)
+ *data = NULL;
+ return;
+ }
+
+ i = 0;
+ item = li->boxItems;
+ while (item && i < num) {
+ i++, item = item->next;
+ }
+
+ if (item) {
+ if (text)
+ *text = item->text;
+ if (data)
+ *data = (void *)item->data;
+ }
+}
+
+static void listboxDraw(newtComponent co)
+{
+ struct listbox * li = co->data;
+ struct items *item;
+ int i, j;
+
+ if (!co->isMapped) return ;
+
+ if(li->flags & NEWT_FLAG_BORDER) {
+ if(li->isActive)
+ SLsmg_set_color(NEWT_COLORSET_ACTLISTBOX);
+ else
+ SLsmg_set_color(NEWT_COLORSET_LISTBOX);
+
+ newtDrawBox(co->left, co->top, co->width, co->height, 0);
+ }
+
+ if(li->sb)
+ li->sb->ops->draw(li->sb);
+
+ SLsmg_set_color(NEWT_COLORSET_LISTBOX);
+
+ for(i = 0, item = li->boxItems; item != NULL && i < li->startShowItem;
+ i++, item = item->next);
+
+ j = i;
+
+ for (i = 0; item != NULL && i < li->curHeight; i++, item = item->next) {
+ if (!item->text) continue;
+
+ newtGotorc(co->top + i + li->bdyAdjust, co->left + li->bdxAdjust);
+ if(j + i == li->currItem) {
+ if(item->isSelected)
+ SLsmg_set_color(NEWT_COLORSET_ACTSELLISTBOX);
+ else
+ SLsmg_set_color(NEWT_COLORSET_ACTLISTBOX);
+ } else if(item->isSelected)
+ SLsmg_set_color(NEWT_COLORSET_SELLISTBOX);
+ else
+ SLsmg_set_color(NEWT_COLORSET_LISTBOX);
+
+ SLsmg_write_nstring(item->text, li->curWidth);
+
+ }
+ newtGotorc(co->top + (li->currItem - li->startShowItem), co->left);
+}
+
+static struct eventResult listboxEvent(newtComponent co, struct event ev) {
+ struct eventResult er;
+ struct listbox * li = co->data;
+ struct items *item;
+ int i;
+
+ er.result = ER_IGNORED;
+
+ if(ev.when == EV_EARLY || ev.when == EV_LATE) {
+ return er;
+ }
+
+ switch(ev.event) {
+ case EV_KEYPRESS:
+ if (!li->isActive) break;
+
+ switch(ev.u.key) {
+ case ' ':
+ if(!(li->flags & NEWT_FLAG_MULTIPLE)) break;
+ newtListboxSelectItem(co, li->boxItems[li->currItem].data,
+ NEWT_FLAGS_TOGGLE);
+ er.result = ER_SWALLOWED;
+ /* We don't break here, because it is cool to be able to
+ hold space to select a bunch of items in a list at once */
+
+ case NEWT_KEY_DOWN:
+ if(li->numItems <= 0) break;
+ if(li->currItem < li->numItems - 1) {
+ li->currItem++;
+ if(li->currItem > (li->startShowItem + li->curHeight - 1)) {
+ li->startShowItem = li->currItem - li->curHeight + 1;
+ if(li->startShowItem + li->curHeight > li->numItems)
+ li->startShowItem = li->numItems - li->curHeight;
+ }
+ if(li->sb)
+ newtScrollbarSet(li->sb, li->currItem + 1, li->numItems);
+ listboxDraw(co);
+ }
+ if(co->callback) co->callback(co, co->callbackData);
+ er.result = ER_SWALLOWED;
+ break;
+
+ case NEWT_KEY_ENTER:
+ if(li->numItems <= 0) break;
+ if(li->flags & NEWT_FLAG_RETURNEXIT)
+ er.result = ER_EXITFORM;
+ break;
+
+ case NEWT_KEY_UP:
+ if(li->numItems <= 0) break;
+ if(li->currItem > 0) {
+ li->currItem--;
+ if(li->currItem < li->startShowItem)
+ li->startShowItem = li->currItem;
+ if(li->sb)
+ newtScrollbarSet(li->sb, li->currItem + 1, li->numItems);
+ listboxDraw(co);
+ }
+ if(co->callback) co->callback(co, co->callbackData);
+ er.result = ER_SWALLOWED;
+ break;
+
+ case NEWT_KEY_PGUP:
+ if(li->numItems <= 0) break;
+ li->startShowItem -= li->curHeight - 1;
+ if(li->startShowItem < 0)
+ li->startShowItem = 0;
+ li->currItem -= li->curHeight - 1;
+ if(li->currItem < 0)
+ li->currItem = 0;
+ newtListboxRealSetCurrent(co);
+ er.result = ER_SWALLOWED;
+ break;
+
+ case NEWT_KEY_PGDN:
+ if(li->numItems <= 0) break;
+ li->startShowItem += li->curHeight;
+ if(li->startShowItem > (li->numItems - li->curHeight)) {
+ li->startShowItem = li->numItems - li->curHeight;
+ }
+ li->currItem += li->curHeight;
+ if(li->currItem >= li->numItems) {
+ li->currItem = li->numItems - 1;
+ }
+ newtListboxRealSetCurrent(co);
+ er.result = ER_SWALLOWED;
+ break;
+
+ case NEWT_KEY_HOME:
+ if(li->numItems <= 0) break;
+ newtListboxSetCurrent(co, 0);
+ er.result = ER_SWALLOWED;
+ break;
+
+ case NEWT_KEY_END:
+ if(li->numItems <= 0) break;
+ li->startShowItem = li->numItems - li->curHeight;
+ if(li->startShowItem < 0)
+ li->startShowItem = 0;
+ li->currItem = li->numItems - 1;
+ newtListboxRealSetCurrent(co);
+ er.result = ER_SWALLOWED;
+ break;
+ default:
+ if (li->numItems <= 0) break;
+ if (ev.u.key < NEWT_KEY_EXTRA_BASE && isalpha(ev.u.key)) {
+ for(i = 0, item = li->boxItems; item != NULL &&
+ i < li->currItem; i++, item = item->next);
+
+ if (item && item->text && (toupper(*item->text) == toupper(ev.u.key))) {
+ item = item->next;
+ i++;
+ } else {
+ item = li->boxItems;
+ i = 0;
+ }
+ while (item && item->text &&
+ toupper(*item->text) != toupper(ev.u.key)) {
+ item = item->next;
+ i++;
+ }
+ if (item) {
+ li->currItem = i;
+ if(li->currItem < li->startShowItem ||
+ li->currItem > li->startShowItem)
+ li->startShowItem =
+ li->currItem > li->numItems - li->curHeight ?
+ li->startShowItem = li->numItems - li->curHeight :
+ li->currItem;
+ if(li->sb)
+ newtScrollbarSet(li->sb, li->currItem + 1, li->numItems);
+ newtListboxRealSetCurrent(co);
+ er.result = ER_SWALLOWED;
+ }
+ }
+ }
+ break;
+
+ case EV_FOCUS:
+ li->isActive = 1;
+ listboxDraw(co);
+ er.result = ER_SWALLOWED;
+ break;
+
+ case EV_UNFOCUS:
+ li->isActive = 0;
+ listboxDraw(co);
+ er.result = ER_SWALLOWED;
+ break;
+
+ case EV_MOUSE:
+ /* if this mouse click was within the listbox, make the current
+ item the item clicked on. */
+ /* Up scroll arrow */
+ if (li->sb &&
+ ev.u.mouse.x == co->left + co->width - li->bdxAdjust - 1 &&
+ ev.u.mouse.y == co->top + li->bdyAdjust) {
+ if(li->numItems <= 0) break;
+ if(li->currItem > 0) {
+ li->currItem--;
+ if(li->currItem < li->startShowItem)
+ li->startShowItem = li->currItem;
+ if(li->sb)
+ newtScrollbarSet(li->sb, li->currItem + 1, li->numItems);
+ listboxDraw(co);
+ }
+ if(co->callback) co->callback(co, co->callbackData);
+ er.result = ER_SWALLOWED;
+ break;
+ }
+ /* Down scroll arrow */
+ if (li->sb &&
+ ev.u.mouse.x == co->left + co->width - li->bdxAdjust - 1 &&
+ ev.u.mouse.y == co->top + co->height - li->bdyAdjust - 1) {
+ if(li->numItems <= 0) break;
+ if(li->currItem < li->numItems - 1) {
+ li->currItem++;
+ if(li->currItem > (li->startShowItem + li->curHeight - 1)) {
+ li->startShowItem = li->currItem - li->curHeight + 1;
+ if(li->startShowItem + li->curHeight > li->numItems)
+ li->startShowItem = li->numItems - li->curHeight;
+ }
+ if(li->sb)
+ newtScrollbarSet(li->sb, li->currItem + 1, li->numItems);
+ listboxDraw(co);
+ }
+ if(co->callback) co->callback(co, co->callbackData);
+ er.result = ER_SWALLOWED;
+ break;
+ }
+ if ((ev.u.mouse.y >= co->top + li->bdyAdjust) &&
+ (ev.u.mouse.y <= co->top + co->height - (li->bdyAdjust * 2)) &&
+ (ev.u.mouse.x >= co->left + li->bdxAdjust) &&
+ (ev.u.mouse.x <= co->left + co->width + (li->bdxAdjust * 2))) {
+ li->currItem = li->startShowItem +
+ (ev.u.mouse.y - li->bdyAdjust - co->top);
+ newtListboxRealSetCurrent(co);
+ listboxDraw(co);
+ if(co->callback) co->callback(co, co->callbackData);
+ er.result = ER_SWALLOWED;
+ break;
+ }
+ }
+
+ return er;
+}
+
+static void listboxDestroy(newtComponent co) {
+ struct listbox * li = co->data;
+ struct items * item, * nextitem;
+
+ nextitem = item = li->boxItems;
+
+ while (item != NULL) {
+ nextitem = item->next;
+ free(item->text);
+ free(item);
+ item = nextitem;
+ }
+
+ if (li->sb) li->sb->ops->destroy(li->sb);
+
+ free(li);
+ free(co);
+}
diff --git a/mdk-stage1/newt/newt.c b/mdk-stage1/newt/newt.c
new file mode 100644
index 000000000..1cfe3ac93
--- /dev/null
+++ b/mdk-stage1/newt/newt.c
@@ -0,0 +1,672 @@
+#include <slang.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/signal.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <termios.h>
+#include <unistd.h>
+
+#include "newt.h"
+#include "newt_pr.h"
+
+struct Window {
+ int height, width, top, left;
+ short * buffer;
+ char * title;
+};
+
+struct keymap {
+ char * str;
+ int code;
+ char * tc;
+};
+
+static struct Window windowStack[20];
+static struct Window * currentWindow = NULL;
+
+static char * helplineStack[20];
+static char ** currentHelpline = NULL;
+
+static int cursorRow, cursorCol;
+static int needResize;
+static int cursorOn = 1;
+
+static const char * defaultHelpLine =
+" <Tab>/<Alt-Tab> between elements | <Space> selects | <F12> next screen"
+;
+
+const struct newtColors newtDefaultColorPalette = {
+ "cyan", "black", /* root fg, bg */
+ "black", "blue", /* border fg, bg */
+ "white", "blue", /* window fg, bg */
+ "white", "black", /* shadow fg, bg */
+ "white", "blue", /* title fg, bg */
+ "black", "cyan", /* button fg, bg */
+ "yellow", "cyan", /* active button fg, bg */
+ "yellow", "blue", /* checkbox fg, bg */
+ "blue", "brown", /* active checkbox fg, bg */
+ "yellow", "blue", /* entry box fg, bg */
+ "white", "blue", /* label fg, bg */
+ "black", "cyan", /* listbox fg, bg */
+ "yellow", "cyan", /* active listbox fg, bg */
+ "white", "blue", /* textbox fg, bg */
+ "cyan", "black", /* active textbox fg, bg */
+ "white", "blue", /* help line */
+ "yellow", "blue", /* root text */
+ "blue", /* scale full */
+ "red", /* scale empty */
+ "blue", "cyan", /* disabled entry fg, bg */
+ "white", "blue", /* compact button fg, bg */
+ "yellow", "red", /* active & sel listbox */
+ "black", "brown" /* selected listbox */
+};
+
+static const struct keymap keymap[] = {
+ { "\033OA", NEWT_KEY_UP, "kh" },
+ { "\033[A", NEWT_KEY_UP, "ku" },
+ { "\033OB", NEWT_KEY_DOWN, "kd" },
+ { "\033[B", NEWT_KEY_DOWN, "kd" },
+ { "\033[C", NEWT_KEY_RIGHT, "kr" },
+ { "\033OC", NEWT_KEY_RIGHT, "kr" },
+ { "\033[D", NEWT_KEY_LEFT, "kl" },
+ { "\033OD", NEWT_KEY_LEFT, "kl" },
+ { "\033[H", NEWT_KEY_HOME, "kh" },
+ { "\033[1~", NEWT_KEY_HOME, "kh" },
+ { "\033Ow", NEWT_KEY_END, "kH" },
+ { "\033[4~", NEWT_KEY_END, "kH" },
+
+ { "\033[3~", NEWT_KEY_DELETE, "kl" },
+ { "\033[2~", NEWT_KEY_INSERT, NULL },
+
+ { "\033\t", NEWT_KEY_UNTAB, NULL },
+
+ { "\033[5~", NEWT_KEY_PGUP, NULL },
+ { "\033[6~", NEWT_KEY_PGDN, NULL },
+ { "\033V", NEWT_KEY_PGUP, "kH" },
+ { "\033v", NEWT_KEY_PGUP, "kH" },
+
+ { "\033[[A", NEWT_KEY_F1, NULL },
+ { "\033[[B", NEWT_KEY_F2, NULL },
+ { "\033[[C", NEWT_KEY_F3, NULL },
+ { "\033[[D", NEWT_KEY_F4, NULL },
+ { "\033[[E", NEWT_KEY_F5, NULL },
+
+ { "\033OP", NEWT_KEY_F1, NULL },
+ { "\033OQ", NEWT_KEY_F2, NULL },
+ { "\033OR", NEWT_KEY_F3, NULL },
+ { "\033OS", NEWT_KEY_F4, NULL },
+
+ { "\033[11~", NEWT_KEY_F1, NULL },
+ { "\033[12~", NEWT_KEY_F2, NULL },
+ { "\033[13~", NEWT_KEY_F3, NULL },
+ { "\033[14~", NEWT_KEY_F4, NULL },
+ { "\033[15~", NEWT_KEY_F5, NULL },
+ { "\033[17~", NEWT_KEY_F6, NULL },
+ { "\033[18~", NEWT_KEY_F7, NULL },
+ { "\033[19~", NEWT_KEY_F8, NULL },
+ { "\033[20~", NEWT_KEY_F9, NULL },
+ { "\033[21~", NEWT_KEY_F10, NULL },
+ { "\033[23~", NEWT_KEY_F11, NULL },
+ { "\033[24~", NEWT_KEY_F12, NULL },
+
+ { NULL, 0, NULL }, /* LEAVE this one */
+};
+static char keyPrefix = '\033';
+
+static const char * version = "Newt windowing library version " VERSION
+ " - (C) 1996-2000 Red Hat Software. "
+ "Redistributable under the term of the Library "
+ "GNU Public License. "
+ "Written by Erik Troan\n";
+
+static newtSuspendCallback suspendCallback = NULL;
+static void * suspendCallbackData = NULL;
+
+void newtSetSuspendCallback(newtSuspendCallback cb, void * data) {
+ suspendCallback = cb;
+ suspendCallbackData = data;
+}
+
+static void handleSigwinch(int signum) {
+ needResize = 1;
+}
+
+static int getkeyInterruptHook(void) {
+ return -1;
+}
+
+void newtFlushInput(void) {
+ while (SLang_input_pending(0)) {
+ SLang_getkey();
+ }
+}
+
+void newtRefresh(void) {
+ SLsmg_refresh();
+}
+
+void newtSuspend(void) {
+ SLtt_set_cursor_visibility (1);
+ SLsmg_suspend_smg();
+ SLang_reset_tty();
+ SLtt_set_cursor_visibility (cursorOn);
+}
+
+void newtResume(void) {
+ SLsmg_resume_smg ();
+ SLsmg_refresh();
+ SLang_init_tty(0, 0, 0);
+}
+
+void newtCls(void) {
+ SLsmg_set_color(NEWT_COLORSET_ROOT);
+ SLsmg_gotorc(0, 0);
+ SLsmg_erase_eos();
+
+ newtRefresh();
+}
+
+#if defined(THIS_DOESNT_WORK)
+void newtResizeScreen(int redraw) {
+ newtPushHelpLine("");
+
+ SLtt_get_screen_size();
+ SLang_init_tty(0, 0, 0);
+
+ SLsmg_touch_lines (0, SLtt_Screen_Rows - 1);
+
+ /* I don't know why I need this */
+ SLsmg_refresh();
+
+ newtPopHelpLine();
+
+ if (redraw)
+ SLsmg_refresh();
+}
+#endif
+
+int newtInit(void) {
+ char * MonoValue, * MonoEnv = "NEWT_MONO";
+
+ /* use the version variable just to be sure it gets included */
+ strlen(version);
+
+ SLtt_get_terminfo();
+ SLtt_get_screen_size();
+
+ MonoValue = getenv(MonoEnv);
+ if ( MonoValue == NULL ) {
+ SLtt_Use_Ansi_Colors = 1;
+ } else {
+ SLtt_Use_Ansi_Colors = 0;
+ }
+
+ SLsmg_init_smg();
+ SLang_init_tty(0, 0, 0);
+
+ newtSetColors(newtDefaultColorPalette);
+ newtCursorOff();
+ /*initKeymap();*/
+
+ /*memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = handleSigwinch;
+ sigaction(SIGWINCH, &sa, NULL);*/
+
+ SLsignal_intr(SIGWINCH, handleSigwinch);
+ SLang_getkey_intr_hook = getkeyInterruptHook;
+
+
+
+ return 0;
+}
+
+int newtFinished(void) {
+ SLsmg_gotorc(SLtt_Screen_Rows - 1, 0);
+ newtCursorOn();
+ SLsmg_refresh();
+ SLsmg_reset_smg();
+ SLang_reset_tty();
+
+ return 0;
+}
+
+void newtSetColors(struct newtColors colors) {
+ SLtt_set_color(NEWT_COLORSET_ROOT, "", colors.rootFg, colors.rootBg);
+ SLtt_set_color(NEWT_COLORSET_BORDER, "", colors.borderFg, colors.borderBg);
+ SLtt_set_color(NEWT_COLORSET_WINDOW, "", colors.windowFg, colors.windowBg);
+ SLtt_set_color(NEWT_COLORSET_SHADOW, "", colors.shadowFg, colors.shadowBg);
+ SLtt_set_color(NEWT_COLORSET_TITLE, "", colors.titleFg, colors.titleBg);
+ SLtt_set_color(NEWT_COLORSET_BUTTON, "", colors.buttonFg, colors.buttonBg);
+ SLtt_set_color(NEWT_COLORSET_ACTBUTTON, "", colors.actButtonFg,
+ colors.actButtonBg);
+ SLtt_set_color(NEWT_COLORSET_CHECKBOX, "", colors.checkboxFg,
+ colors.checkboxBg);
+ SLtt_set_color(NEWT_COLORSET_ACTCHECKBOX, "", colors.actCheckboxFg,
+ colors.actCheckboxBg);
+ SLtt_set_color(NEWT_COLORSET_ENTRY, "", colors.entryFg, colors.entryBg);
+ SLtt_set_color(NEWT_COLORSET_LABEL, "", colors.labelFg, colors.labelBg);
+ SLtt_set_color(NEWT_COLORSET_LISTBOX, "", colors.listboxFg,
+ colors.listboxBg);
+ SLtt_set_color(NEWT_COLORSET_ACTLISTBOX, "", colors.actListboxFg,
+ colors.actListboxBg);
+ SLtt_set_color(NEWT_COLORSET_TEXTBOX, "", colors.textboxFg,
+ colors.textboxBg);
+ SLtt_set_color(NEWT_COLORSET_ACTTEXTBOX, "", colors.actTextboxFg,
+ colors.actTextboxBg);
+ SLtt_set_color(NEWT_COLORSET_HELPLINE, "", colors.helpLineFg,
+ colors.helpLineBg);
+ SLtt_set_color(NEWT_COLORSET_ROOTTEXT, "", colors.rootTextFg,
+ colors.rootTextBg);
+
+ SLtt_set_color(NEWT_COLORSET_EMPTYSCALE, "", "black",
+ colors.emptyScale);
+ SLtt_set_color(NEWT_COLORSET_FULLSCALE, "", "black",
+ colors.fullScale);
+ SLtt_set_color(NEWT_COLORSET_DISENTRY, "", colors.disabledEntryFg,
+ colors.disabledEntryBg);
+
+ SLtt_set_color(NEWT_COLORSET_COMPACTBUTTON, "", colors.compactButtonFg,
+ colors.compactButtonBg);
+
+ SLtt_set_color(NEWT_COLORSET_ACTSELLISTBOX, "", colors.actSelListboxFg,
+ colors.actSelListboxBg);
+ SLtt_set_color(NEWT_COLORSET_SELLISTBOX, "", colors.selListboxFg,
+ colors.selListboxBg);
+}
+
+int newtGetKey(void) {
+ int key;
+ char buf[10], * chptr = buf;
+ const struct keymap * curr;
+
+ do {
+ key = SLang_getkey();
+ if (key == 0xFFFF) {
+ if (needResize)
+ return NEWT_KEY_RESIZE;
+
+ /* ignore other signals */
+ continue;
+ }
+
+ if (key == NEWT_KEY_SUSPEND && suspendCallback)
+ suspendCallback(suspendCallbackData);
+ } while (key == NEWT_KEY_SUSPEND);
+
+ switch (key) {
+ case 'v' | 0x80:
+ case 'V' | 0x80:
+ return NEWT_KEY_PGUP;
+
+ case 22:
+ return NEWT_KEY_PGDN;
+
+ return NEWT_KEY_BKSPC;
+ case 0x7f:
+ return NEWT_KEY_BKSPC;
+
+ case 0x08:
+ return NEWT_KEY_BKSPC;
+
+ default:
+ if (key != keyPrefix) return key;
+ }
+
+ memset(buf, 0, sizeof(buf));
+
+ *chptr++ = key;
+ while (SLang_input_pending(5)) {
+ key = SLang_getkey();
+ if (key == keyPrefix) {
+ /* he hit unknown keys too many times -- start over */
+ memset(buf, 0, sizeof(buf));
+ chptr = buf;
+ }
+
+ *chptr++ = key;
+
+ /* this search should use bsearch(), but when we only look through
+ a list of 20 (or so) keymappings, it's probably faster just to
+ do a inline linear search */
+
+ for (curr = keymap; curr->code; curr++) {
+ if (curr->str) {
+ if (!strcmp(curr->str, buf))
+ return curr->code;
+ }
+ }
+ }
+
+ for (curr = keymap; curr->code; curr++) {
+ if (curr->str) {
+ if (!strcmp(curr->str, buf))
+ return curr->code;
+ }
+ }
+
+ /* Looks like we were a bit overzealous in reading characters. Return
+ just the first character, and put everything else back in the buffer
+ for later */
+
+ chptr--;
+ while (chptr > buf)
+ SLang_ungetkey(*chptr--);
+
+ return *chptr;
+}
+
+void newtWaitForKey(void) {
+ newtRefresh();
+
+ SLang_getkey();
+ newtClearKeyBuffer();
+}
+
+void newtClearKeyBuffer(void) {
+ while (SLang_input_pending(1)) {
+ SLang_getkey();
+ }
+}
+
+int newtOpenWindow(int left, int top, int width, int height,
+ const char * title) {
+ int j, row, col;
+ int n;
+ int i;
+
+ newtFlushInput();
+
+ if (!currentWindow) {
+ currentWindow = windowStack;
+ } else {
+ currentWindow++;
+ }
+
+ currentWindow->left = left;
+ currentWindow->top = top;
+ currentWindow->width = width;
+ currentWindow->height = height;
+ currentWindow->title = title ? strdup(title) : NULL;
+
+ currentWindow->buffer = malloc(sizeof(short) * (width + 3) * (height + 3));
+
+ row = top - 1;
+ col = left - 1;
+ n = 0;
+ for (j = 0; j < height + 3; j++, row++) {
+ SLsmg_gotorc(row, col);
+ SLsmg_read_raw(currentWindow->buffer + n,
+ currentWindow->width + 3);
+ n += currentWindow->width + 3;
+ }
+
+ SLsmg_set_color(NEWT_COLORSET_BORDER);
+ SLsmg_draw_box(top - 1, left - 1, height + 2, width + 2);
+
+ if (currentWindow->title) {
+ i = strlen(currentWindow->title) + 4;
+ i = ((width - i) / 2) + left;
+ SLsmg_gotorc(top - 1, i);
+ SLsmg_set_char_set(1);
+ SLsmg_write_char(SLSMG_RTEE_CHAR);
+ SLsmg_set_char_set(0);
+ SLsmg_write_char(' ');
+ SLsmg_set_color(NEWT_COLORSET_TITLE);
+ SLsmg_write_string((char *)currentWindow->title);
+ SLsmg_set_color(NEWT_COLORSET_BORDER);
+ SLsmg_write_char(' ');
+ SLsmg_set_char_set(1);
+ SLsmg_write_char(SLSMG_LTEE_CHAR);
+ SLsmg_set_char_set(0);
+ }
+
+ SLsmg_set_color(NEWT_COLORSET_WINDOW);
+ SLsmg_fill_region(top, left, height, width, ' ');
+
+ SLsmg_set_color(NEWT_COLORSET_SHADOW);
+ SLsmg_fill_region(top + height + 1, left, 1, width + 2, ' ');
+ SLsmg_fill_region(top, left + width + 1, height + 1, 1, ' ');
+
+ for (i = top; i < (top + height + 1); i++) {
+ SLsmg_gotorc(i, left + width + 1);
+ SLsmg_write_string(" ");
+ }
+
+ return 0;
+}
+
+int newtCenteredWindow(int width, int height, const char * title) {
+ int top, left;
+
+ top = (SLtt_Screen_Rows - height) / 2;
+
+ /* I don't know why, but this seems to look better */
+ if ((SLtt_Screen_Rows % 2) && (top % 2)) top--;
+
+ left = (SLtt_Screen_Cols - width) / 2;
+
+ newtOpenWindow(left, top, width, height, title);
+
+ return 0;
+}
+
+void newtPopWindow(void) {
+ int j, row, col;
+ int n = 0;
+
+ row = col = 0;
+
+ row = currentWindow->top - 1;
+ col = currentWindow->left - 1;
+ for (j = 0; j < currentWindow->height + 3; j++, row++) {
+ SLsmg_gotorc(row, col);
+ SLsmg_write_raw(currentWindow->buffer + n,
+ currentWindow->width + 3);
+ n += currentWindow->width + 3;
+ }
+
+ free(currentWindow->buffer);
+ free(currentWindow->title);
+
+ if (currentWindow == windowStack)
+ currentWindow = NULL;
+ else
+ currentWindow--;
+
+ SLsmg_set_char_set(0);
+
+ newtRefresh();
+}
+
+void newtGetWindowPos(int * x, int * y) {
+ if (currentWindow) {
+ *x = currentWindow->left;
+ *y = currentWindow->top;
+ } else
+ *x = *y = 0;
+}
+
+void newtGetrc(int * row, int * col) {
+ *row = cursorRow;
+ *col = cursorCol;
+}
+
+void newtGotorc(int newRow, int newCol) {
+ if (currentWindow) {
+ newRow += currentWindow->top;
+ newCol += currentWindow->left;
+ }
+
+ cursorRow = newRow;
+ cursorCol = newCol;
+ SLsmg_gotorc(cursorRow, cursorCol);
+}
+
+void newtDrawBox(int left, int top, int width, int height, int shadow) {
+ if (currentWindow) {
+ top += currentWindow->top;
+ left += currentWindow->left;
+ }
+
+ SLsmg_draw_box(top, left, height, width);
+
+ if (shadow) {
+ SLsmg_set_color(NEWT_COLORSET_SHADOW);
+ SLsmg_fill_region(top + height, left + 1, 1, width - 1, ' ');
+ SLsmg_fill_region(top + 1, left + width, height, 1, ' ');
+ }
+}
+
+void newtClearBox(int left, int top, int width, int height) {
+ if (currentWindow) {
+ top += currentWindow->top;
+ left += currentWindow->left;
+ }
+
+ SLsmg_fill_region(top, left, height, width, ' ');
+}
+
+#if 0
+/* This doesn't seem to work quite right. I don't know why not, but when
+ I rsh from an rxvt into a box and run this code, the machine returns
+ console key's (\033[B) rather then xterm ones (\033OB). */
+static void initKeymap(void) {
+ struct keymap * curr;
+
+ for (curr = keymap; curr->code; curr++) {
+ if (!curr->str)
+ curr->str = SLtt_tgetstr(curr->tc);
+ }
+
+ /* Newt's keymap handling is a bit broken. It assumes that any extended
+ keystrokes begin with ESC. If you're using a homebrek terminal you
+ will probably need to fix this, or just yell at me and I'll be so
+ ashamed of myself for doing it this way I'll fix it */
+
+ keyPrefix = 0x1b; /* ESC */
+}
+#endif
+
+void newtDelay(int usecs) {
+ fd_set set;
+ struct timeval tv;
+
+ FD_ZERO(&set);
+
+ tv.tv_sec = usecs / 1000000;
+ tv.tv_usec = usecs % 1000000;
+
+ select(0, &set, &set, &set, &tv);
+}
+
+struct eventResult newtDefaultEventHandler(newtComponent c,
+ struct event ev) {
+ struct eventResult er;
+
+ er.result = ER_IGNORED;
+ return er;
+}
+
+void newtRedrawHelpLine(void) {
+ char * buf;
+
+ SLsmg_set_color(NEWT_COLORSET_HELPLINE);
+
+ buf = alloca(SLtt_Screen_Cols + 1);
+ memset(buf, ' ', SLtt_Screen_Cols);
+ buf[SLtt_Screen_Cols] = '\0';
+
+ if (currentHelpline)
+ memcpy(buf, *currentHelpline, strlen(*currentHelpline));
+
+ SLsmg_gotorc(SLtt_Screen_Rows - 1, 0);
+ SLsmg_write_string(buf);
+}
+
+void newtPushHelpLine(const char * text) {
+ if (!text)
+ text = defaultHelpLine;
+
+ if (currentHelpline)
+ (*(++currentHelpline)) = strdup(text);
+ else {
+ currentHelpline = helplineStack;
+ *currentHelpline = strdup(text);
+ }
+
+ newtRedrawHelpLine();
+}
+
+void newtPopHelpLine(void) {
+ if (!currentHelpline) return;
+
+ free(*currentHelpline);
+ if (currentHelpline == helplineStack)
+ currentHelpline = NULL;
+ else
+ currentHelpline--;
+
+ newtRedrawHelpLine();
+}
+
+void newtDrawRootText(int col, int row, const char * text) {
+ SLsmg_set_color(NEWT_COLORSET_ROOTTEXT);
+
+ if (col < 0) {
+ col = SLtt_Screen_Cols + col;
+ }
+
+ if (row < 0) {
+ row = SLtt_Screen_Rows + row;
+ }
+
+ SLsmg_gotorc(row, col);
+ SLsmg_write_string((char *)text);
+}
+
+int newtSetFlags(int oldFlags, int newFlags, enum newtFlagsSense sense) {
+ switch (sense) {
+ case NEWT_FLAGS_SET:
+ return oldFlags | newFlags;
+
+ case NEWT_FLAGS_RESET:
+ return oldFlags & (~newFlags);
+
+ case NEWT_FLAGS_TOGGLE:
+ return oldFlags ^ newFlags;
+
+ default:
+ return oldFlags;
+ }
+}
+
+void newtBell(void)
+{
+ SLtt_beep();
+}
+
+void newtGetScreenSize(int * cols, int * rows) {
+ if (rows) *rows = SLtt_Screen_Rows;
+ if (cols) *cols = SLtt_Screen_Cols;
+}
+
+void newtDefaultPlaceHandler(newtComponent c, int newLeft, int newTop) {
+ c->left = newLeft;
+ c->top = newTop;
+}
+
+void newtDefaultMappedHandler(newtComponent c, int isMapped) {
+ c->isMapped = isMapped;
+}
+
+void newtCursorOff(void) {
+ cursorOn = 0;
+ SLtt_set_cursor_visibility (cursorOn);
+}
+
+void newtCursorOn(void) {
+ cursorOn = 1;
+ SLtt_set_cursor_visibility (cursorOn);
+}
diff --git a/mdk-stage1/newt/newt.h b/mdk-stage1/newt/newt.h
new file mode 100644
index 000000000..d3fd8bedc
--- /dev/null
+++ b/mdk-stage1/newt/newt.h
@@ -0,0 +1,362 @@
+#ifndef H_NEWT
+#define H_NEWT
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdarg.h>
+
+#define NEWT_COLORSET_ROOT 2
+#define NEWT_COLORSET_BORDER 3
+#define NEWT_COLORSET_WINDOW 4
+#define NEWT_COLORSET_SHADOW 5
+#define NEWT_COLORSET_TITLE 6
+#define NEWT_COLORSET_BUTTON 7
+#define NEWT_COLORSET_ACTBUTTON 8
+#define NEWT_COLORSET_CHECKBOX 9
+#define NEWT_COLORSET_ACTCHECKBOX 10
+#define NEWT_COLORSET_ENTRY 11
+#define NEWT_COLORSET_LABEL 12
+#define NEWT_COLORSET_LISTBOX 13
+#define NEWT_COLORSET_ACTLISTBOX 14
+#define NEWT_COLORSET_TEXTBOX 15
+#define NEWT_COLORSET_ACTTEXTBOX 16
+#define NEWT_COLORSET_HELPLINE 17
+#define NEWT_COLORSET_ROOTTEXT 18
+#define NEWT_COLORSET_EMPTYSCALE 19
+#define NEWT_COLORSET_FULLSCALE 20
+#define NEWT_COLORSET_DISENTRY 21
+#define NEWT_COLORSET_COMPACTBUTTON 22
+#define NEWT_COLORSET_ACTSELLISTBOX 23
+#define NEWT_COLORSET_SELLISTBOX 24
+
+#define NEWT_ARG_LAST -100000
+#define NEWT_ARG_APPEND -1
+
+struct newtColors {
+ char * rootFg, * rootBg;
+ char * borderFg, * borderBg;
+ char * windowFg, * windowBg;
+ char * shadowFg, * shadowBg;
+ char * titleFg, * titleBg;
+ char * buttonFg, * buttonBg;
+ char * actButtonFg, * actButtonBg;
+ char * checkboxFg, * checkboxBg;
+ char * actCheckboxFg, * actCheckboxBg;
+ char * entryFg, * entryBg;
+ char * labelFg, * labelBg;
+ char * listboxFg, * listboxBg;
+ char * actListboxFg, * actListboxBg;
+ char * textboxFg, * textboxBg;
+ char * actTextboxFg, * actTextboxBg;
+ char * helpLineFg, * helpLineBg;
+ char * rootTextFg, * rootTextBg;
+ char * emptyScale, * fullScale;
+ char * disabledEntryFg, * disabledEntryBg;
+ char * compactButtonFg, * compactButtonBg;
+ char * actSelListboxFg, * actSelListboxBg;
+ char * selListboxFg, * selListboxBg;
+};
+
+enum newtFlagsSense { NEWT_FLAGS_SET, NEWT_FLAGS_RESET, NEWT_FLAGS_TOGGLE };
+
+#define NEWT_FLAG_RETURNEXIT (1 << 0)
+#define NEWT_FLAG_HIDDEN (1 << 1)
+#define NEWT_FLAG_SCROLL (1 << 2)
+#define NEWT_FLAG_DISABLED (1 << 3)
+/* OBSOLETE #define NEWT_FLAG_NOSCROLL (1 << 4) for listboxes */
+#define NEWT_FLAG_BORDER (1 << 5)
+#define NEWT_FLAG_WRAP (1 << 6)
+#define NEWT_FLAG_NOF12 (1 << 7)
+#define NEWT_FLAG_MULTIPLE (1 << 8)
+#define NEWT_FLAG_SELECTED (1 << 9)
+#define NEWT_FLAG_CHECKBOX (1 << 10)
+#define NEWT_FLAG_PASSWORD (1 << 11) /* draw '*' of chars in entrybox */
+#define NEWT_FD_READ (1 << 0)
+#define NEWT_FD_WRITE (1 << 1)
+
+#define NEWT_CHECKBOXTREE_COLLAPSED '\0'
+#define NEWT_CHECKBOXTREE_EXPANDED '\1'
+#define NEWT_CHECKBOXTREE_UNSELECTED ' '
+#define NEWT_CHECKBOXTREE_SELECTED '*'
+
+/* Backwards compatibility */
+#define NEWT_LISTBOX_RETURNEXIT NEWT_FLAG_RETURNEXIT
+#define NEWT_ENTRY_SCROLL NEWT_FLAG_SCROLL
+#define NEWT_ENTRY_HIDDEN NEWT_FLAG_HIDDEN
+#define NEWT_ENTRY_RETURNEXIT NEWT_FLAG_RETURNEXIT
+#define NEWT_ENTRY_DISABLED NEWT_FLAG_DISABLED
+
+#define NEWT_TEXTBOX_WRAP NEWT_FLAG_WRAP
+#define NEWT_TEXTBOX_SCROLL NEWT_FLAG_SCROLL
+#define NEWT_FORM_NOF12 NEWT_FLAG_NOF12
+
+#define newtListboxAddEntry newtListboxAppendEntry
+
+
+typedef struct newtComponent_struct * newtComponent;
+
+extern const struct newtColors newtDefaultColorPalette;
+
+typedef void (*newtCallback)(newtComponent, void *);
+typedef void (*newtSuspendCallback)(void * data);
+
+int newtInit(void);
+int newtFinished(void);
+void newtCls(void);
+void newtResizeScreen(int redraw);
+void newtWaitForKey(void);
+void newtClearKeyBuffer(void);
+void newtDelay(int usecs);
+/* top, left are *not* counting the border */
+int newtOpenWindow(int left, int top, int width, int height,
+ const char * title);
+int newtCenteredWindow(int width, int height, const char * title);
+void newtPopWindow(void);
+void newtSetColors(struct newtColors colors);
+void newtRefresh(void);
+void newtSuspend(void);
+void newtSetSuspendCallback(newtSuspendCallback cb, void * data);
+void newtSetHelpCallback(newtCallback cb);
+void newtResume(void);
+void newtPushHelpLine(const char * text);
+void newtRedrawHelpLine(void);
+void newtPopHelpLine(void);
+void newtDrawRootText(int col, int row, const char * text);
+void newtBell(void);
+void newtCursorOff(void);
+void newtCursorOn(void);
+
+/* Components */
+
+newtComponent newtCompactButton(int left, int top, const char * text);
+newtComponent newtButton(int left, int top, const char * text);
+newtComponent newtCheckbox(int left, int top, const char * text, char defValue,
+ const char * seq, char * result);
+char newtCheckboxGetValue(newtComponent co);
+void newtCheckboxSetValue(newtComponent co, char value);
+void newtCheckboxSetFlags(newtComponent co, int flags, enum newtFlagsSense sense);
+
+
+newtComponent newtRadiobutton(int left, int top, const char * text, int isDefault,
+ newtComponent prevButton);
+newtComponent newtRadioGetCurrent(newtComponent setMember);
+newtComponent newtListitem(int left, int top, const char * text, int isDefault,
+ newtComponent prevItem, const void * data, int flags);
+void newtListitemSet(newtComponent co, const char * text);
+void * newtListitemGetData(newtComponent co);
+void newtGetScreenSize(int * cols, int * rows);
+
+newtComponent newtLabel(int left, int top, const char * text);
+void newtLabelSetText(newtComponent co, const char * text);
+newtComponent newtVerticalScrollbar(int left, int top, int height,
+ int normalColorset, int thumbColorset);
+void newtScrollbarSet(newtComponent co, int where, int total);
+
+newtComponent newtListbox(int left, int top, int height, int flags);
+void * newtListboxGetCurrent(newtComponent co);
+void newtListboxSetCurrent(newtComponent co, int num);
+void newtListboxSetCurrentByKey(newtComponent co, void * key);
+void newtListboxSetEntry(newtComponent co, int num, const char * text);
+void newtListboxSetWidth(newtComponent co, int width);
+void newtListboxSetData(newtComponent co, int num, void * data);
+int newtListboxAppendEntry(newtComponent co, const char * text,
+ const void * data);
+/* Send the key to insert after, or NULL to insert at the top */
+int newtListboxInsertEntry(newtComponent co, const char * text, const void * data, void * key);
+int newtListboxDeleteEntry(newtComponent co, void * data);
+void newtListboxClear(newtComponent co); /* removes all entries from listbox */
+void newtListboxGetEntry(newtComponent co, int num, char **text, void **data);
+/* Returns an array of data pointers from items, last element is NULL */
+void **newtListboxGetSelection(newtComponent co, int *numitems);
+void newtListboxClearSelection(newtComponent co);
+void newtListboxSelectItem(newtComponent co, const void * key,
+ enum newtFlagsSense sense);
+
+newtComponent newtCheckboxTree(int left, int top, int height, int flags);
+newtComponent newtCheckboxTreeMulti(int left, int top, int height, char *seq, int flags);
+const void ** newtCheckboxTreeGetSelection(newtComponent co, int *numitems);
+const void * newtCheckboxTreeGetCurrent(newtComponent co);
+const void ** newtCheckboxTreeGetMultiSelection(newtComponent co, int *numitems, char seqnum);
+/* last item is NEWT_ARG_LAST for all of these */
+int newtCheckboxTreeAddItem(newtComponent co,
+ const char * text, const void * data,
+ int flags, int index, ...);
+int newtCheckboxTreeAddArray(newtComponent co,
+ const char * text, const void * data,
+ int flags, int * indexes);
+int * newtCheckboxTreeFindItem(newtComponent co, void * data);
+void newtCheckboxTreeSetEntry(newtComponent co, const void * data,
+ const char * text);
+char newtCheckboxTreeGetEntryValue(newtComponent co, const void * data);
+void newtCheckboxTreeSetEntryValue(newtComponent co, const void * data,
+ char value);
+
+newtComponent newtTextboxReflowed(int left, int top, char * text, int width,
+ int flexDown, int flexUp, int flags);
+newtComponent newtTextbox(int left, int top, int width, int height, int flags);
+void newtTextboxSetText(newtComponent co, const char * text);
+void newtTextboxSetHeight(newtComponent co, int height);
+int newtTextboxGetNumLines(newtComponent co);
+char * newtReflowText(char * text, int width, int flexDown, int flexUp,
+ int * actualWidth, int * actualHeight);
+
+struct newtExitStruct {
+ enum { NEWT_EXIT_HOTKEY, NEWT_EXIT_COMPONENT, NEWT_EXIT_FDREADY,
+ NEWT_EXIT_TIMER } reason;
+ union {
+ int key;
+ newtComponent co;
+ } u;
+} ;
+
+newtComponent newtForm(newtComponent vertBar, void * helpTag, int flags);
+void newtFormSetTimer(newtComponent form, int millisecs);
+void newtFormWatchFd(newtComponent form, int fd, int fdFlags);
+void newtFormSetSize(newtComponent co);
+newtComponent newtFormGetCurrent(newtComponent co);
+void newtFormSetBackground(newtComponent co, int color);
+void newtFormSetCurrent(newtComponent co, newtComponent subco);
+void newtFormAddComponent(newtComponent form, newtComponent co);
+void newtFormAddComponents(newtComponent form, ...);
+void newtFormSetHeight(newtComponent co, int height);
+void newtFormSetWidth(newtComponent co, int width);
+newtComponent newtRunForm(newtComponent form); /* obsolete */
+void newtFormRun(newtComponent co, struct newtExitStruct * es);
+void newtDrawForm(newtComponent form);
+void newtFormAddHotKey(newtComponent co, int key);
+
+typedef int (*newtEntryFilter)(newtComponent entry, void * data, int ch,
+ int cursor);
+newtComponent newtEntry(int left, int top, const char * initialValue, int width,
+ char ** resultPtr, int flags);
+void newtEntrySet(newtComponent co, const char * value, int cursorAtEnd);
+void newtEntrySetFilter(newtComponent co, newtEntryFilter filter, void * data);
+char * newtEntryGetValue(newtComponent co);
+void newtEntrySetFlags(newtComponent co, int flags, enum newtFlagsSense sense);
+
+newtComponent newtScale(int left, int top, int width, int fullValue);
+void newtScaleSet(newtComponent co, unsigned int amount);
+
+void newtComponentAddCallback(newtComponent co, newtCallback f, void * data);
+void newtComponentTakesFocus(newtComponent co, int val);
+
+/* this also destroys all of the components (including other forms) on the
+ form */
+void newtFormDestroy(newtComponent form);
+
+/* Key codes */
+
+#define NEWT_KEY_TAB '\t'
+#define NEWT_KEY_ENTER '\r'
+#define NEWT_KEY_SUSPEND '\032' /* ctrl - z*/
+#define NEWT_KEY_RETURN NEWT_KEY_ENTER
+
+#define NEWT_KEY_EXTRA_BASE 0x8000
+#define NEWT_KEY_UP NEWT_KEY_EXTRA_BASE + 1
+#define NEWT_KEY_DOWN NEWT_KEY_EXTRA_BASE + 2
+#define NEWT_KEY_LEFT NEWT_KEY_EXTRA_BASE + 4
+#define NEWT_KEY_RIGHT NEWT_KEY_EXTRA_BASE + 5
+#define NEWT_KEY_BKSPC NEWT_KEY_EXTRA_BASE + 6
+#define NEWT_KEY_DELETE NEWT_KEY_EXTRA_BASE + 7
+#define NEWT_KEY_HOME NEWT_KEY_EXTRA_BASE + 8
+#define NEWT_KEY_END NEWT_KEY_EXTRA_BASE + 9
+#define NEWT_KEY_UNTAB NEWT_KEY_EXTRA_BASE + 10
+#define NEWT_KEY_PGUP NEWT_KEY_EXTRA_BASE + 11
+#define NEWT_KEY_PGDN NEWT_KEY_EXTRA_BASE + 12
+#define NEWT_KEY_INSERT NEWT_KEY_EXTRA_BASE + 13
+
+#define NEWT_KEY_F1 NEWT_KEY_EXTRA_BASE + 101
+#define NEWT_KEY_F2 NEWT_KEY_EXTRA_BASE + 102
+#define NEWT_KEY_F3 NEWT_KEY_EXTRA_BASE + 103
+#define NEWT_KEY_F4 NEWT_KEY_EXTRA_BASE + 104
+#define NEWT_KEY_F5 NEWT_KEY_EXTRA_BASE + 105
+#define NEWT_KEY_F6 NEWT_KEY_EXTRA_BASE + 106
+#define NEWT_KEY_F7 NEWT_KEY_EXTRA_BASE + 107
+#define NEWT_KEY_F8 NEWT_KEY_EXTRA_BASE + 108
+#define NEWT_KEY_F9 NEWT_KEY_EXTRA_BASE + 109
+#define NEWT_KEY_F10 NEWT_KEY_EXTRA_BASE + 110
+#define NEWT_KEY_F11 NEWT_KEY_EXTRA_BASE + 111
+#define NEWT_KEY_F12 NEWT_KEY_EXTRA_BASE + 112
+
+/* not really a key, but newtGetKey returns it */
+#define NEWT_KEY_RESIZE NEWT_KEY_EXTRA_BASE + 113
+
+#define NEWT_ANCHOR_LEFT (1 << 0)
+#define NEWT_ANCHOR_RIGHT (1 << 1)
+#define NEWT_ANCHOR_TOP (1 << 2)
+#define NEWT_ANCHOR_BOTTOM (1 << 3)
+
+#define NEWT_GRID_FLAG_GROWX (1 << 0)
+#define NEWT_GRID_FLAG_GROWY (1 << 1)
+
+typedef struct grid_s * newtGrid;
+enum newtGridElement { NEWT_GRID_EMPTY = 0,
+ NEWT_GRID_COMPONENT, NEWT_GRID_SUBGRID };
+
+newtGrid newtCreateGrid(int cols, int rows);
+/* TYPE, what, TYPE, what, ..., NULL */
+newtGrid newtGridVStacked(enum newtGridElement type, void * what, ...);
+newtGrid newtGridVCloseStacked(enum newtGridElement type, void * what, ...);
+newtGrid newtGridHStacked(enum newtGridElement type1, void * what1, ...);
+newtGrid newtGridHCloseStacked(enum newtGridElement type1, void * what1, ...);
+newtGrid newtGridBasicWindow(newtComponent text, newtGrid middle,
+ newtGrid buttons);
+newtGrid newtGridSimpleWindow(newtComponent text, newtComponent middle,
+ newtGrid buttons);
+void newtGridSetField(newtGrid grid, int col, int row,
+ enum newtGridElement type, void * val, int padLeft,
+ int padTop, int padRight, int padBottom, int anchor,
+ int flags);
+void newtGridPlace(newtGrid grid, int left, int top);
+#define newtGridDestroy newtGridFree
+void newtGridFree(newtGrid grid, int recurse);
+void newtGridGetSize(newtGrid grid, int * width, int * height);
+void newtGridWrappedWindow(newtGrid grid, char * title);
+void newtGridWrappedWindowAt(newtGrid grid, char * title, int left, int top);
+void newtGridAddComponentsToForm(newtGrid grid, newtComponent form,
+ int recurse);
+
+/* convienve */
+newtGrid newtButtonBarv(char * button1, newtComponent * b1comp, va_list args);
+newtGrid newtButtonBar(char * button1, newtComponent * b1comp, ...);
+
+/* automatically centered and shrink wrapped */
+void newtWinMessage(char * title, char * buttonText, char * text, ...);
+void newtWinMessagev(char * title, char * buttonText, char * text,
+ va_list argv);
+
+/* having separate calls for these two seems silly, but having two separate
+ variable length-arg lists seems like a bad idea as well */
+
+/* Returns 0 if F12 was pressed, 1 for button1, 2 for button2 */
+int newtWinChoice(char * title, char * button1, char * button2,
+ char * text, ...);
+/* Returns 0 if F12 was pressed, 1 for button1, 2 for button2,
+ 3 for button3 */
+int newtWinTernary(char * title, char * button1, char * button2,
+ char * button3, char * message, ...);
+
+/* Returns the button number pressed, 0 on F12 */
+int newtWinMenu(char * title, char * text, int suggestedWidth, int flexDown,
+ int flexUp, int maxListHeight, char ** items, int * listItem,
+ char * button1, ...);
+
+struct newtWinEntry {
+ char * text;
+ char ** value; /* may be initialized to set default */
+ int flags;
+};
+
+/* Returns the button number pressed, 0 on F12. The final values are
+ dynamically allocated, and need to be freed. */
+int newtWinEntries(char * title, char * text, int suggestedWidth, int flexDown,
+ int flexUp, int dataWidth,
+ struct newtWinEntry * items, char * button1, ...);
+
+#ifdef __cplusplus
+} /* End of extern "C" { */
+#endif
+
+#endif /* H_NEWT */
diff --git a/mdk-stage1/newt/newt_pr.h b/mdk-stage1/newt/newt_pr.h
new file mode 100644
index 000000000..76f5e2f6f
--- /dev/null
+++ b/mdk-stage1/newt/newt_pr.h
@@ -0,0 +1,82 @@
+#ifndef H_NEWT_PR
+#define H_NEWT_PR
+
+#define COLORSET_ROOT NEWT_COLORSET_ROOT
+#define COLORSET_BORDER NEWT_COLORSET_BORDER
+#define COLORSET_WINDOW NEWT_COLORSET_WINDOW
+#define COLORSET_SHADOW NEWT_COLORSET_SHADOW
+#define COLORSET_TITLE NEWT_COLORSET_TITLE
+#define COLORSET_BUTTON NEWT_COLORSET_BUTTON
+#define COLORSET_ACTBUTTON NEWT_COLORSET_ACTBUTTON
+#define COLORSET_CHECKBOX NEWT_COLORSET_CHECKBOX
+#define COLORSET_ACTCHECKBOX NEWT_COLORSET_ACTCHECKBOX
+#define COLORSET_ENTRY NEWT_COLORSET_ENTRY
+#define COLORSET_LABEL NEWT_COLORSET_LABEL
+#define COLORSET_LISTBOX NEWT_COLORSET_LISTBOX
+#define COLORSET_ACTLISTBOX NEWT_COLORSET_ACTLISTBOX
+#define COLORSET_TEXTBOX NEWT_COLORSET_TEXTBOX
+#define COLORSET_ACTTEXTBOX NEWT_COLORSET_ACTTEXTBOX
+
+int newtSetFlags(int oldFlags, int newFlags, enum newtFlagsSense sense);
+
+void newtGotorc(int row, int col);
+void newtGetrc(int * row, int * col);
+void newtGetWindowPos(int * x, int * y);
+void newtDrawBox(int left, int top, int width, int height, int shadow);
+void newtClearBox(int left, int top, int width, int height);
+
+int newtGetKey(void);
+
+struct newtComponent_struct {
+ /* common data */
+ int height, width;
+ int top, left;
+ int takesFocus;
+ int isMapped;
+
+ struct componentOps * ops;
+
+ newtCallback callback;
+ void * callbackData;
+
+ void * data;
+} ;
+
+enum eventResultTypes { ER_IGNORED, ER_SWALLOWED, ER_EXITFORM, ER_SETFOCUS,
+ ER_NEXTCOMP };
+struct eventResult {
+ enum eventResultTypes result;
+ union {
+ newtComponent focus;
+ } u;
+};
+
+enum eventTypes { EV_FOCUS, EV_UNFOCUS, EV_KEYPRESS, EV_MOUSE };
+enum eventSequence { EV_EARLY, EV_NORMAL, EV_LATE };
+
+struct event {
+ enum eventTypes event;
+ enum eventSequence when;
+ union {
+ int key;
+ struct {
+ enum { MOUSE_MOTION, MOUSE_BUTTON_DOWN, MOUSE_BUTTON_UP } type;
+ int x, y;
+ } mouse;
+ } u;
+} ;
+
+struct componentOps {
+ void (* draw)(newtComponent c);
+ struct eventResult (* event)(newtComponent c, struct event ev);
+ void (* destroy)(newtComponent c);
+ void (* place)(newtComponent c, int newLeft, int newTop);
+ void (* mapped)(newtComponent c, int isMapped);
+} ;
+
+void newtDefaultPlaceHandler(newtComponent c, int newLeft, int newTop);
+void newtDefaultMappedHandler(newtComponent c, int isMapped);
+struct eventResult newtDefaultEventHandler(newtComponent c,
+ struct event ev);
+
+#endif /* H_NEWT_PR */
diff --git a/mdk-stage1/newt/scale.c b/mdk-stage1/newt/scale.c
new file mode 100644
index 000000000..800958580
--- /dev/null
+++ b/mdk-stage1/newt/scale.c
@@ -0,0 +1,72 @@
+#include <slang.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "newt.h"
+#include "newt_pr.h"
+
+struct scale {
+ int fullValue;
+ int charsSet;
+};
+
+static void scaleDraw(newtComponent co);
+
+static struct componentOps scaleOps = {
+ scaleDraw,
+ newtDefaultEventHandler,
+ NULL,
+ newtDefaultPlaceHandler,
+ newtDefaultMappedHandler,
+} ;
+
+newtComponent newtScale(int left, int top, int width, int fullValue) {
+ newtComponent co;
+ struct scale * sc;
+
+ co = malloc(sizeof(*co));
+ sc = malloc(sizeof(struct scale));
+ co->data = sc;
+
+ co->ops = &scaleOps;
+
+ co->height = 1;
+ co->width = width;
+ co->top = top;
+ co->left = left;
+ co->takesFocus = 0;
+
+ sc->fullValue = fullValue;
+ sc->charsSet = 0;
+
+ return co;
+}
+
+void newtScaleSet(newtComponent co, unsigned int amount) {
+ struct scale * sc = co->data;
+ int newCharsSet;
+
+ newCharsSet = (amount * co->width) / sc->fullValue;
+
+ if (newCharsSet != sc->charsSet) {
+ sc->charsSet = newCharsSet;
+ scaleDraw(co);
+ }
+}
+
+static void scaleDraw(newtComponent co) {
+ struct scale * sc = co->data;
+ int i;
+
+ if (co->top == -1) return;
+
+ newtGotorc(co->top, co->left);
+
+ SLsmg_set_color(NEWT_COLORSET_FULLSCALE);
+ for (i = 0; i < sc->charsSet; i++)
+ SLsmg_write_string(" ");
+
+ SLsmg_set_color(NEWT_COLORSET_EMPTYSCALE);
+ for (i = 0; i < (co->width - sc->charsSet); i++)
+ SLsmg_write_string(" ");
+}
diff --git a/mdk-stage1/newt/scrollbar.c b/mdk-stage1/newt/scrollbar.c
new file mode 100644
index 000000000..cb4bc2757
--- /dev/null
+++ b/mdk-stage1/newt/scrollbar.c
@@ -0,0 +1,124 @@
+#include <slang.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "newt.h"
+#include "newt_pr.h"
+
+struct scrollbar {
+ int curr;
+ int cs, csThumb;
+ int arrows;
+} ;
+
+static void sbDraw(newtComponent co);
+static void sbDestroy(newtComponent co);
+static void sbDrawThumb(newtComponent co, int isOn);
+
+static struct componentOps sbOps = {
+ sbDraw,
+ newtDefaultEventHandler,
+ sbDestroy,
+ newtDefaultPlaceHandler,
+ newtDefaultMappedHandler,
+} ;
+
+void newtScrollbarSet(newtComponent co, int where, int total) {
+ struct scrollbar * sb = co->data;
+ int new;
+
+ if (sb->arrows)
+ new = (where * (co->height - 3)) / (total ? total : 1) + 1;
+ else
+ new = (where * (co->height - 1)) / (total ? total : 1);
+ if (new != sb->curr) {
+ sbDrawThumb(co, 0);
+ sb->curr = new;
+ sbDrawThumb(co, 1);
+ }
+}
+
+newtComponent newtVerticalScrollbar(int left, int top, int height,
+ int normalColorset, int thumbColorset) {
+ newtComponent co;
+ struct scrollbar * sb;
+
+ co = malloc(sizeof(*co));
+ sb = malloc(sizeof(*sb));
+ co->data = sb;
+
+ if (!strcmp(getenv("TERM"), "linux") && height >= 2) {
+ sb->arrows = 1;
+ sb->curr = 1;
+ } else {
+ sb->arrows = 0;
+ sb->curr = 0;
+ }
+ sb->cs = normalColorset;
+ sb->csThumb = thumbColorset;
+
+ co->ops = &sbOps;
+ co->isMapped = 0;
+ co->left = left;
+ co->top = top;
+ co->height = height;
+ co->width = 1;
+ co->takesFocus = 0;
+
+ return co;
+}
+
+static void sbDraw(newtComponent co) {
+ struct scrollbar * sb = co->data;
+ int i;
+
+ if (!co->isMapped) return;
+
+ SLsmg_set_color(sb->cs);
+
+ SLsmg_set_char_set(1);
+ if (sb->arrows) {
+ newtGotorc(co->top, co->left);
+ SLsmg_write_char('\x2d');
+ for (i = 1; i < co->height - 1; i++) {
+ newtGotorc(i + co->top, co->left);
+ SLsmg_write_char('\x61');
+ }
+ newtGotorc(co->top + co->height - 1, co->left);
+ SLsmg_write_char('\x2e');
+ } else {
+ for (i = 0; i < co->height; i++) {
+ newtGotorc(i + co->top, co->left);
+ SLsmg_write_char('\x61');
+ }
+ }
+
+ SLsmg_set_char_set(0);
+
+ sbDrawThumb(co, 1);
+}
+
+static void sbDrawThumb(newtComponent co, int isOn) {
+ struct scrollbar * sb = co->data;
+ char ch = isOn ? '#' : '\x61';
+
+ if (!co->isMapped) return;
+
+ newtGotorc(sb->curr + co->top, co->left);
+ SLsmg_set_char_set(1);
+
+ /*if (isOn)
+ SLsmg_set_color(sb->csThumb);
+ else*/
+ SLsmg_set_color(sb->cs);
+
+ SLsmg_write_char(ch);
+ SLsmg_set_char_set(0);
+}
+
+static void sbDestroy(newtComponent co) {
+ struct scrollbar * sb = co->data;
+
+ free(sb);
+ free(co);
+}
diff --git a/mdk-stage1/newt/textbox.c b/mdk-stage1/newt/textbox.c
new file mode 100644
index 000000000..272c9b675
--- /dev/null
+++ b/mdk-stage1/newt/textbox.c
@@ -0,0 +1,409 @@
+#include <ctype.h>
+#include <slang.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "newt.h"
+#include "newt_pr.h"
+
+struct textbox {
+ char ** lines;
+ int numLines;
+ int linesAlloced;
+ int doWrap;
+ newtComponent sb;
+ int topLine;
+ int textWidth;
+};
+
+static char * expandTabs(const char * text);
+static void textboxDraw(newtComponent co);
+static void addLine(newtComponent co, const char * s, int len);
+static void doReflow(const char * text, char ** resultPtr, int width,
+ int * badness, int * heightPtr);
+static struct eventResult textboxEvent(newtComponent c,
+ struct event ev);
+static void textboxDestroy(newtComponent co);
+static void textboxPlace(newtComponent co, int newLeft, int newTop);
+static void textboxMapped(newtComponent co, int isMapped);
+
+static struct componentOps textboxOps = {
+ textboxDraw,
+ textboxEvent,
+ textboxDestroy,
+ textboxPlace,
+ textboxMapped,
+} ;
+
+static void textboxMapped(newtComponent co, int isMapped) {
+ struct textbox * tb = co->data;
+
+ co->isMapped = isMapped;
+ if (tb->sb)
+ tb->sb->ops->mapped(tb->sb, isMapped);
+}
+
+static void textboxPlace(newtComponent co, int newLeft, int newTop) {
+ struct textbox * tb = co->data;
+
+ co->top = newTop;
+ co->left = newLeft;
+
+ if (tb->sb)
+ tb->sb->ops->place(tb->sb, co->left + co->width - 1, co->top);
+}
+
+void newtTextboxSetHeight(newtComponent co, int height) {
+ co->height = height;
+}
+
+int newtTextboxGetNumLines(newtComponent co) {
+ struct textbox * tb = co->data;
+
+ return (tb->numLines);
+}
+
+newtComponent newtTextboxReflowed(int left, int top, char * text, int width,
+ int flexDown, int flexUp, int flags) {
+ newtComponent co;
+ char * reflowedText;
+ int actWidth, actHeight;
+
+ reflowedText = newtReflowText(text, width, flexDown, flexUp,
+ &actWidth, &actHeight);
+
+ co = newtTextbox(left, top, actWidth, actHeight, NEWT_FLAG_WRAP);
+ newtTextboxSetText(co, reflowedText);
+ free(reflowedText);
+
+ return co;
+}
+
+newtComponent newtTextbox(int left, int top, int width, int height, int flags) {
+ newtComponent co;
+ struct textbox * tb;
+
+ co = malloc(sizeof(*co));
+ tb = malloc(sizeof(*tb));
+ co->data = tb;
+
+ co->ops = &textboxOps;
+
+ co->height = height;
+ co->top = top;
+ co->left = left;
+ co->takesFocus = 0;
+ co->width = width;
+
+ tb->doWrap = flags & NEWT_FLAG_WRAP;
+ tb->numLines = 0;
+ tb->linesAlloced = 0;
+ tb->lines = NULL;
+ tb->topLine = 0;
+ tb->textWidth = width;
+
+ if (flags & NEWT_FLAG_SCROLL) {
+ co->width += 2;
+ tb->sb = newtVerticalScrollbar(co->left + co->width - 1, co->top,
+ co->height, COLORSET_TEXTBOX, COLORSET_TEXTBOX);
+ } else {
+ tb->sb = NULL;
+ }
+
+ return co;
+}
+
+static char * expandTabs(const char * text) {
+ int bufAlloced = strlen(text) + 40;
+ char * buf, * dest;
+ const char * src;
+ int bufUsed = 0;
+ int linePos = 0;
+ int i;
+
+ buf = malloc(bufAlloced + 1);
+ for (src = text, dest = buf; *src; src++) {
+ if ((bufUsed + 10) > bufAlloced) {
+ bufAlloced += strlen(text) / 2;
+ buf = realloc(buf, bufAlloced + 1);
+ dest = buf + bufUsed;
+ }
+ if (*src == '\t') {
+ i = 8 - (linePos & 8);
+ memset(dest, ' ', i);
+ dest += i, bufUsed += i, linePos += i;
+ } else {
+ if (*src == '\n')
+ linePos = 0;
+ else
+ linePos++;
+
+ *dest++ = *src;
+ bufUsed++;
+ }
+ }
+
+ *dest = '\0';
+ return buf;
+}
+
+#define iseuckanji(c) (0xa1 <= (unsigned char)(c&0xff) && (unsigned char)(c&0xff) <= 0xfe)
+
+static void doReflow(const char * text, char ** resultPtr, int width,
+ int * badness, int * heightPtr) {
+ char * result = NULL;
+ const char * chptr, * end;
+ int i;
+ int howbad = 0;
+ int height = 0;
+ int kanji = 0;
+
+ if (resultPtr) {
+ /* XXX I think this will work */
+ result = malloc(strlen(text) + (strlen(text) / width) + 50);
+ *result = '\0';
+ }
+
+ while (*text) {
+ kanji = 0;
+ end = strchr(text, '\n');
+ if (!end)
+ end = text + strlen(text);
+
+ while (*text && text < end) {
+ if (end - text < width) {
+ if (result) {
+ strncat(result, text, end - text + 1);
+ strcat(result, "\n");
+ height++;
+ }
+
+ if (end - text < (width / 2))
+ howbad += ((width / 2) - (end - text)) / 2;
+ text = end;
+ if (*text) text++;
+ } else {
+ chptr = text;
+ kanji = 0;
+ for ( i = 0; i < width - 1; i++ ) {
+ if ( !iseuckanji(*chptr)) {
+ kanji = 0;
+ } else if ( kanji == 1 ) {
+ kanji = 2;
+ } else {
+ kanji = 1;
+ }
+ chptr++;
+ }
+ if (kanji == 0) {
+ while (chptr > text && !isspace(*chptr)) chptr--;
+ while (chptr > text && isspace(*chptr)) chptr--;
+ chptr++;
+ }
+
+ if (chptr-text == 1 && !isspace(*chptr))
+ chptr = text + width - 1;
+
+ if (chptr > text)
+ howbad += width - (chptr - text) + 1;
+ if (result) {
+ if (kanji == 1) {
+ strncat(result, text, chptr - text + 1);
+ chptr++;
+ kanji = 0;
+ } else {
+ strncat(result, text, chptr - text + 1);
+ }
+ strcat(result, "\n");
+ height++;
+ }
+
+ if (isspace(*chptr))
+ text = chptr + 1;
+ else
+ text = chptr;
+ while (isspace(*text)) text++;
+ }
+ }
+ }
+
+// if (result) printf("result: %s\n", result);
+
+ if (badness) *badness = howbad;
+ if (resultPtr) *resultPtr = result;
+ if (heightPtr) *heightPtr = height;
+}
+
+char * newtReflowText(char * text, int width, int flexDown, int flexUp,
+ int * actualWidth, int * actualHeight) {
+ int min, max;
+ int i;
+ char * result;
+ int minbad, minbadwidth, howbad;
+ char * expandedText;
+
+ expandedText = expandTabs(text);
+
+ if (flexDown || flexUp) {
+ min = width - flexDown;
+ max = width + flexUp;
+
+ minbad = -1;
+ minbadwidth = width;
+
+ for (i = min; i <= max; i++) {
+ doReflow(expandedText, NULL, i, &howbad, NULL);
+
+ if (minbad == -1 || howbad < minbad) {
+ minbad = howbad;
+ minbadwidth = i;
+ }
+ }
+
+ width = minbadwidth;
+ }
+
+ doReflow(expandedText, &result, width, NULL, actualHeight);
+ free(expandedText);
+ if (actualWidth) *actualWidth = width;
+ return result;
+}
+
+void newtTextboxSetText(newtComponent co, const char * text) {
+ const char * start, * end;
+ struct textbox * tb = co->data;
+ char * reflowed, * expanded;
+ int badness, height;
+
+ if (tb->lines) {
+ free(tb->lines);
+ tb->linesAlloced = tb->numLines = 0;
+ }
+
+ expanded = expandTabs(text);
+
+ if (tb->doWrap) {
+ doReflow(expanded, &reflowed, tb->textWidth, &badness, &height);
+ free(expanded);
+ expanded = reflowed;
+ }
+
+ for (start = expanded; *start; start++)
+ if (*start == '\n') tb->linesAlloced++;
+
+ /* This ++ leaves room for an ending line w/o a \n */
+ tb->linesAlloced++;
+ tb->lines = malloc(sizeof(char *) * tb->linesAlloced);
+
+ start = expanded;
+ while ((end = strchr(start, '\n'))) {
+ addLine(co, start, end - start);
+ start = end + 1;
+ }
+
+ if (*start)
+ addLine(co, start, strlen(start));
+
+ free(expanded);
+}
+
+/* This assumes the buffer is allocated properly! */
+static void addLine(newtComponent co, const char * s, int len) {
+ struct textbox * tb = co->data;
+
+ if (len > tb->textWidth) len = tb->textWidth;
+
+ tb->lines[tb->numLines] = malloc(tb->textWidth + 1);
+ memset(tb->lines[tb->numLines], ' ', tb->textWidth);
+ memcpy(tb->lines[tb->numLines], s, len);
+ tb->lines[tb->numLines++][tb->textWidth] = '\0';
+}
+
+static void textboxDraw(newtComponent c) {
+ int i;
+ struct textbox * tb = c->data;
+ int size;
+
+ if (tb->sb) {
+ size = tb->numLines - c->height;
+ newtScrollbarSet(tb->sb, tb->topLine, size ? size : 0);
+ tb->sb->ops->draw(tb->sb);
+ }
+
+ SLsmg_set_color(NEWT_COLORSET_TEXTBOX);
+
+ for (i = 0; (i + tb->topLine) < tb->numLines && i < c->height; i++) {
+ newtGotorc(c->top + i, c->left);
+ SLsmg_write_string(tb->lines[i + tb->topLine]);
+ }
+}
+
+static struct eventResult textboxEvent(newtComponent co,
+ struct event ev) {
+ struct textbox * tb = co->data;
+ struct eventResult er;
+
+ er.result = ER_IGNORED;
+
+ if (ev.when == EV_EARLY && ev.event == EV_KEYPRESS && tb->sb) {
+ switch (ev.u.key) {
+ case NEWT_KEY_UP:
+ if (tb->topLine) tb->topLine--;
+ textboxDraw(co);
+ er.result = ER_SWALLOWED;
+ break;
+
+ case NEWT_KEY_DOWN:
+ if (tb->topLine < (tb->numLines - co->height)) tb->topLine++;
+ textboxDraw(co);
+ er.result = ER_SWALLOWED;
+ break;
+
+ case NEWT_KEY_PGDN:
+ tb->topLine += co->height;
+ if (tb->topLine > (tb->numLines - co->height)) {
+ tb->topLine = tb->numLines - co->height;
+ if (tb->topLine < 0) tb->topLine = 0;
+ }
+ textboxDraw(co);
+ er.result = ER_SWALLOWED;
+ break;
+
+ case NEWT_KEY_PGUP:
+ tb->topLine -= co->height;
+ if (tb->topLine < 0) tb->topLine = 0;
+ textboxDraw(co);
+ er.result = ER_SWALLOWED;
+ break;
+ }
+ }
+ if (ev.when == EV_EARLY && ev.event == EV_MOUSE && tb->sb) {
+ /* Top scroll arrow */
+ if (ev.u.mouse.x == co->width && ev.u.mouse.y == co->top) {
+ if (tb->topLine) tb->topLine--;
+ textboxDraw(co);
+
+ er.result = ER_SWALLOWED;
+ }
+ /* Bottom scroll arrow */
+ if (ev.u.mouse.x == co->width &&
+ ev.u.mouse.y == co->top + co->height - 1) {
+ if (tb->topLine < (tb->numLines - co->height)) tb->topLine++;
+ textboxDraw(co);
+
+ er.result = ER_SWALLOWED;
+ }
+ }
+ return er;
+}
+
+static void textboxDestroy(newtComponent co) {
+ int i;
+ struct textbox * tb = co->data;
+
+ for (i = 0; i < tb->numLines; i++)
+ free(tb->lines[i]);
+ free(tb->lines);
+ free(tb);
+ free(co);
+}
diff --git a/mdk-stage1/newt/windows.c b/mdk-stage1/newt/windows.c
new file mode 100644
index 000000000..792d3ed76
--- /dev/null
+++ b/mdk-stage1/newt/windows.c
@@ -0,0 +1,275 @@
+#include <errno.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "errno.h"
+#include "newt.h"
+
+static void * newtvwindow(char * title, char * button1, char * button2,
+ char * button3, char * message, va_list args) {
+ newtComponent b1, b2 = NULL, b3 = NULL, t, f, answer;
+ char * buf = NULL;
+ int size = 0;
+ int i = 0;
+ int scroll = 0;
+ int width, height;
+ char * flowedText;
+ newtGrid grid, buttonGrid;
+
+ do {
+ size += 1000;
+ if (buf) free(buf);
+ buf = malloc(size);
+ i = vsnprintf(buf, size, message, args);
+ } while (i >= size || i == -1);
+
+ flowedText = newtReflowText(buf, 35, 5, 5, &width, &height);
+ if (height > 6) {
+ free(flowedText);
+ flowedText = newtReflowText(buf, 60, 5, 5, &width, &height);
+ }
+ free(buf);
+
+ if (height > 12) {
+ height = 12;
+ scroll = NEWT_FLAG_SCROLL;
+ }
+ t = newtTextbox(-1, -1, width, height, NEWT_TEXTBOX_WRAP | scroll);
+ newtTextboxSetText(t, flowedText);
+ free(flowedText);
+
+ if (button3) {
+ buttonGrid = newtButtonBar(button1, &b1, button2, &b2,
+ button3, &b3, NULL);
+ } else if (button2) {
+ buttonGrid = newtButtonBar(button1, &b1, button2, &b2, NULL);
+ } else {
+ buttonGrid = newtButtonBar(button1, &b1, NULL);
+ }
+
+ newtGridSetField(buttonGrid, 0, 0, NEWT_GRID_COMPONENT, b1,
+ 0, 0, button2 ? 1 : 0, 0, 0, 0);
+
+ grid = newtCreateGrid(1, 2);
+ newtGridSetField(grid, 0, 0, NEWT_GRID_COMPONENT, t, 0, 0, 0, 0, 0, 0);
+ newtGridSetField(grid, 0, 1, NEWT_GRID_SUBGRID, buttonGrid,
+ 0, 1, 0, 0, 0, NEWT_GRID_FLAG_GROWX);
+ newtGridWrappedWindow(grid, title);
+
+ f = newtForm(NULL, NULL, 0);
+ newtFormAddComponents(f, t, b1, NULL);
+
+ if (button2)
+ newtFormAddComponent(f, b2);
+ if (button3)
+ newtFormAddComponent(f, b3);
+
+ answer = newtRunForm(f);
+ newtGridFree(grid, 1);
+
+ newtFormDestroy(f);
+ newtPopWindow();
+
+ if (answer == f)
+ return NULL;
+ else if (answer == b1)
+ return button1;
+ else if (answer == b2)
+ return button2;
+
+ return button3;
+}
+
+int newtWinChoice(char * title, char * button1, char * button2,
+ char * message, ...) {
+ va_list args;
+ void * rc;
+
+ va_start(args, message);
+ rc = newtvwindow(title, button1, button2, NULL, message, args);
+ va_end(args);
+
+ if (rc == button1)
+ return 1;
+ else if (rc == button2)
+ return 2;
+
+ return 0;
+}
+
+void newtWinMessage(char * title, char * buttonText, char * text, ...) {
+ va_list args;
+
+ va_start(args, text);
+ newtvwindow(title, buttonText, NULL, NULL, text, args);
+ va_end(args);
+}
+
+void newtWinMessagev(char * title, char * buttonText, char * text,
+ va_list argv) {
+ newtvwindow(title, buttonText, NULL, NULL, text, argv);
+}
+
+int newtWinTernary(char * title, char * button1, char * button2,
+ char * button3, char * message, ...) {
+ va_list args;
+ void * rc;
+
+ va_start(args, message);
+ rc = newtvwindow(title, button1, button2, button3, message, args);
+ va_end(args);
+
+ if (rc == button1)
+ return 1;
+ else if (rc == button2)
+ return 2;
+ else if (rc == button3)
+ return 3;
+
+ return 0;
+}
+
+/* only supports up to 50 buttons -- shucks! */
+int newtWinMenu(char * title, char * text, int suggestedWidth, int flexDown,
+ int flexUp, int maxListHeight, char ** items, int * listItem,
+ char * button1, ...) {
+ newtComponent textbox, listbox, result, form;
+ va_list args;
+ newtComponent buttons[50];
+ newtGrid grid, buttonBar;
+ int numButtons;
+ int i, rc;
+ int needScroll;
+ char * buttonName;
+
+ textbox = newtTextboxReflowed(-1, -1, text, suggestedWidth, flexDown,
+ flexUp, 0);
+
+ for (i = 0; items[i]; i++) ;
+ if (i < maxListHeight) maxListHeight = i;
+ needScroll = i > maxListHeight;
+
+ listbox = newtListbox(-1, -1, maxListHeight,
+ (needScroll ? NEWT_FLAG_SCROLL : 0) | NEWT_FLAG_RETURNEXIT);
+ for (i = 0; items[i]; i++) {
+ newtListboxAddEntry(listbox, items[i], (void *) i);
+ }
+
+ newtListboxSetCurrent(listbox, *listItem);
+
+ buttonName = button1, numButtons = 0;
+ va_start(args, button1);
+ while (buttonName) {
+ buttons[numButtons] = newtButton(-1, -1, buttonName);
+ numButtons++;
+ buttonName = va_arg(args, char *);
+ }
+
+ va_end(args);
+
+ buttonBar = newtCreateGrid(numButtons, 1);
+ for (i = 0; i < numButtons; i++) {
+ newtGridSetField(buttonBar, i, 0, NEWT_GRID_COMPONENT,
+ buttons[i],
+ i ? 1 : 0, 0, 0, 0, 0, 0);
+ }
+
+ grid = newtGridSimpleWindow(textbox, listbox, buttonBar);
+ newtGridWrappedWindow(grid, title);
+
+ form = newtForm(NULL, 0, 0);
+ newtGridAddComponentsToForm(grid, form, 1);
+ newtGridFree(grid, 1);
+
+ result = newtRunForm(form);
+
+ *listItem = ((long) newtListboxGetCurrent(listbox));
+
+ for (rc = 0; result != buttons[rc] && rc < numButtons; rc++);
+ if (rc == numButtons)
+ rc = 0; /* F12 or return-on-exit (which are the same for us) */
+ else
+ rc++;
+
+ newtFormDestroy(form);
+ newtPopWindow();
+
+ return rc;
+}
+
+/* only supports up to 50 buttons and entries -- shucks! */
+int newtWinEntries(char * title, char * text, int suggestedWidth, int flexDown,
+ int flexUp, int dataWidth,
+ struct newtWinEntry * items, char * button1, ...) {
+ newtComponent buttons[50], result, form, textw;
+ newtGrid grid, buttonBar, subgrid;
+ int numItems;
+ int rc, i;
+ int numButtons;
+ char * buttonName;
+ va_list args;
+
+ textw = newtTextboxReflowed(-1, -1, text, suggestedWidth, flexDown,
+ flexUp, 0);
+
+ for (numItems = 0; items[numItems].text; numItems++);
+
+ buttonName = button1, numButtons = 0;
+ va_start(args, button1);
+ while (buttonName) {
+ buttons[numButtons] = newtButton(-1, -1, buttonName);
+ numButtons++;
+ buttonName = va_arg(args, char *);
+ }
+
+ va_end(args);
+
+ buttonBar = newtCreateGrid(numButtons, 1);
+ for (i = 0; i < numButtons; i++) {
+ newtGridSetField(buttonBar, i, 0, NEWT_GRID_COMPONENT,
+ buttons[i],
+ i ? 1 : 0, 0, 0, 0, 0, 0);
+ }
+
+ subgrid = newtCreateGrid(2, numItems);
+ for (i = 0; i < numItems; i++) {
+ newtGridSetField(subgrid, 0, i, NEWT_GRID_COMPONENT,
+ newtLabel(-1, -1, items[i].text),
+ 0, 0, 0, 0, NEWT_ANCHOR_LEFT, 0);
+ newtGridSetField(subgrid, 1, i, NEWT_GRID_COMPONENT,
+ newtEntry(-1, -1, items[i].value ?
+ *items[i].value : NULL, dataWidth,
+ items[i].value, items[i].flags),
+ 1, 0, 0, 0, 0, 0);
+ }
+
+ grid = newtCreateGrid(1, 3);
+ form = newtForm(NULL, 0, 0);
+ newtGridSetField(grid, 0, 0, NEWT_GRID_COMPONENT, textw,
+ 0, 0, 0, 0, NEWT_ANCHOR_LEFT, 0);
+ newtGridSetField(grid, 0, 1, NEWT_GRID_SUBGRID, subgrid,
+ 0, 1, 0, 0, 0, 0);
+ newtGridSetField(grid, 0, 2, NEWT_GRID_SUBGRID, buttonBar,
+ 0, 1, 0, 0, 0, NEWT_GRID_FLAG_GROWX);
+ newtGridAddComponentsToForm(grid, form, 1);
+ newtGridWrappedWindow(grid, title);
+ newtGridFree(grid, 1);
+
+ result = newtRunForm(form);
+
+ for (rc = 0; rc < numItems; rc++)
+ *items[rc].value = strdup(*items[rc].value);
+
+ for (rc = 0; result != buttons[rc] && rc < numButtons; rc++);
+ if (rc == numButtons)
+ rc = 0; /* F12 */
+ else
+ rc++;
+
+ newtFormDestroy(form);
+ newtPopWindow();
+
+ return rc;
+}
diff --git a/mdk-stage1/slang/Makefile b/mdk-stage1/slang/Makefile
new file mode 100644
index 000000000..c78ee4668
--- /dev/null
+++ b/mdk-stage1/slang/Makefile
@@ -0,0 +1,48 @@
+ #******************************************************************************
+ #
+ # Guillaume Cottenceau (gc@mandrakesoft.com)
+ #
+ # Copyright 2000 MandrakeSoft
+ #
+ # This software may be freely redistributed under the terms of the GNU
+ # public license.
+ #
+ # You should have received a copy of the GNU General Public License
+ # along with this program; if not, write to the Free Software
+ # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ #
+ #*****************************************************************************
+
+top_dir = ..
+
+include $(top_dir)/Makefile.common
+
+
+all: libslang.a libslang-DIET.a
+
+clean:
+ rm -f *.o *.a
+
+FLAGS = -Wall -Werror -Os -fomit-frame-pointer -Dunix -DSLANG -c
+
+
+OBJS = sltermin.o sldisply.o slutty.o slang.o slarray.o slclass.o slcmd.o slerr.o slgetkey.o slkeymap.o slmalloc.o slmath.o slmemchr.o slmemcmp.o slmemcpy.o slmemset.o slmisc.o slparse.o slprepr.o slregexp.o slrline.o slsearch.o slsmg.o slstd.o sltoken.o sltypes.o slxstrng.o slcurses.o slscroll.o slsignal.o slkeypad.o slerrno.o slstring.o slstruct.o slcmplex.o slarrfun.o slimport.o slpath.o slarith.o slassoc.o slcompat.o slposdir.o slstdio.o slproc.o sltime.o slstrops.o slbstr.o slpack.o slintall.o slistruc.o slposio.o slnspace.o slarrmis.o slospath.o slscanf.o
+
+OBJS-DIET = $(subst .o,-DIET.o,$(OBJS))
+
+
+libslang.a: $(OBJS)
+ ar -cru $@ $^
+ ranlib $@
+
+libslang-DIET.a: $(OBJS-DIET)
+ ar -cru $@ $^
+ ranlib $@
+
+
+$(OBJS): %.o: %.c
+ gcc $(FLAGS) $(GLIBC_INCLUDES) -c $< -o $@
+
+$(OBJS-DIET): %-DIET.o: %.c
+ gcc $(FLAGS) $(DIETLIBC_INCLUDES) -c $< -o $@
+
diff --git a/mdk-stage1/slang/_slang.h b/mdk-stage1/slang/_slang.h
new file mode 100644
index 000000000..02ee13505
--- /dev/null
+++ b/mdk-stage1/slang/_slang.h
@@ -0,0 +1,743 @@
+#ifndef _PRIVATE_SLANG_H_
+#define _PRIVATE_SLANG_H_
+/* header file for S-Lang internal structures that users do not (should not)
+ need. Use slang.h for that purpose. */
+/* Copyright (c) 1992, 1999, 2001 John E. Davis
+ * This file is part of the S-Lang library.
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Perl Artistic License.
+ */
+
+/* #include "config.h" */
+#include "jdmacros.h"
+#include "sllimits.h"
+
+#ifdef VMS
+# define SLANG_SYSTEM_NAME "_VMS"
+#else
+# if defined (IBMPC_SYSTEM)
+# define SLANG_SYSTEM_NAME "_IBMPC"
+# else
+# define SLANG_SYSTEM_NAME "_UNIX"
+# endif
+#endif /* VMS */
+
+/* These quantities are main_types for byte-compiled code. They are used
+ * by the inner_interp routine. The _BC_ means byte-code.
+ */
+
+#define _SLANG_BC_LVARIABLE SLANG_LVARIABLE /* 0x01 */
+#define _SLANG_BC_GVARIABLE SLANG_GVARIABLE /* 0x02 */
+#define _SLANG_BC_IVARIABLE SLANG_IVARIABLE /* 0x03 */
+#define _SLANG_BC_RVARIABLE SLANG_RVARIABLE /* 0x04 */
+#define _SLANG_BC_INTRINSIC SLANG_INTRINSIC /* 0x05 */
+#define _SLANG_BC_FUNCTION SLANG_FUNCTION /* 0x06 */
+#define _SLANG_BC_MATH_UNARY SLANG_MATH_UNARY /* 0x07 */
+#define _SLANG_BC_APP_UNARY SLANG_APP_UNARY /* 0x08 */
+#define _SLANG_BC_ICONST SLANG_ICONSTANT /* 0x09 */
+#define _SLANG_BC_DCONST SLANG_DCONSTANT /* 0x0A */
+#define _SLANG_BC_PVARIABLE SLANG_PVARIABLE /* 0x0B */
+#define _SLANG_BC_PFUNCTION SLANG_PFUNCTION /* 0x0C */
+
+#define _SLANG_BC_BINARY 0x10
+#define _SLANG_BC_LITERAL 0x11 /* constant objects */
+#define _SLANG_BC_LITERAL_INT 0x12
+#define _SLANG_BC_LITERAL_STR 0x13
+#define _SLANG_BC_BLOCK 0x14
+
+/* These 3 MUST be in this order too ! */
+#define _SLANG_BC_RETURN 0x15
+#define _SLANG_BC_BREAK 0x16
+#define _SLANG_BC_CONTINUE 0x17
+
+#define _SLANG_BC_EXCH 0x18
+#define _SLANG_BC_LABEL 0x19
+#define _SLANG_BC_LOBJPTR 0x1A
+#define _SLANG_BC_GOBJPTR 0x1B
+#define _SLANG_BC_X_ERROR 0x1C
+/* These must be in this order */
+#define _SLANG_BC_X_USER0 0x1D
+#define _SLANG_BC_X_USER1 0x1E
+#define _SLANG_BC_X_USER2 0x1F
+#define _SLANG_BC_X_USER3 0x20
+#define _SLANG_BC_X_USER4 0x21
+
+#define _SLANG_BC_CALL_DIRECT 0x24
+#define _SLANG_BC_CALL_DIRECT_FRAME 0x25
+#define _SLANG_BC_UNARY 0x26
+#define _SLANG_BC_UNARY_FUNC 0x27
+
+#define _SLANG_BC_DEREF_ASSIGN 0x30
+#define _SLANG_BC_SET_LOCAL_LVALUE 0x31
+#define _SLANG_BC_SET_GLOBAL_LVALUE 0x32
+#define _SLANG_BC_SET_INTRIN_LVALUE 0x33
+#define _SLANG_BC_SET_STRUCT_LVALUE 0x34
+#define _SLANG_BC_FIELD 0x35
+#define _SLANG_BC_SET_ARRAY_LVALUE 0x36
+
+#define _SLANG_BC_LINE_NUM 0x40
+
+#define _SLANG_BC_TMP 0x50
+#define _SLANG_BC_LVARIABLE_AGET 0x60
+#define _SLANG_BC_LVARIABLE_APUT 0x61
+#define _SLANG_BC_INTEGER_PLUS 0x62
+#define _SLANG_BC_INTEGER_MINUS 0x63
+#define _SLANG_BC_ARG_LVARIABLE 0x64
+#define _SLANG_BC_EARG_LVARIABLE 0x65
+
+#define _SLANG_BC_CALL_DIRECT_INTRINSIC 0x80
+#define _SLANG_BC_INTRINSIC_CALL_DIRECT 0x81
+#define _SLANG_BC_CALL_DIRECT_LSTR 0x82
+#define _SLANG_BC_CALL_DIRECT_SLFUN 0x83
+#define _SLANG_BC_CALL_DIRECT_INTRSTOP 0x84
+#define _SLANG_BC_INTRINSIC_STOP 0x85
+#define _SLANG_BC_CALL_DIRECT_EARG_LVAR 0x86
+#define _SLANG_BC_CALL_DIRECT_LINT 0x87
+#define _SLANG_BC_CALL_DIRECT_LVAR 0x88
+
+
+/* Byte-Code Sub Types (_BCST_) */
+
+/* These are sub_types of _SLANG_BC_BLOCK */
+#define _SLANG_BCST_ERROR_BLOCK 0x01
+#define _SLANG_BCST_EXIT_BLOCK 0x02
+#define _SLANG_BCST_USER_BLOCK0 0x03
+#define _SLANG_BCST_USER_BLOCK1 0x04
+#define _SLANG_BCST_USER_BLOCK2 0x05
+#define _SLANG_BCST_USER_BLOCK3 0x06
+#define _SLANG_BCST_USER_BLOCK4 0x07
+/* The user blocks MUST be in the above order */
+#define _SLANG_BCST_LOOP 0x10
+#define _SLANG_BCST_WHILE 0x11
+#define _SLANG_BCST_FOR 0x12
+#define _SLANG_BCST_FOREVER 0x13
+#define _SLANG_BCST_CFOR 0x14
+#define _SLANG_BCST_DOWHILE 0x15
+#define _SLANG_BCST_FOREACH 0x16
+
+#define _SLANG_BCST_IF 0x20
+#define _SLANG_BCST_IFNOT 0x21
+#define _SLANG_BCST_ELSE 0x22
+#define _SLANG_BCST_ANDELSE 0x23
+#define _SLANG_BCST_ORELSE 0x24
+#define _SLANG_BCST_SWITCH 0x25
+#define _SLANG_BCST_NOTELSE 0x26
+
+/* assignment (_SLANG_BC_SET_*_LVALUE) subtypes. The order MUST correspond
+ * to the assignment token order with the ASSIGN_TOKEN as the first!
+ */
+#define _SLANG_BCST_ASSIGN 0x01
+#define _SLANG_BCST_PLUSEQS 0x02
+#define _SLANG_BCST_MINUSEQS 0x03
+#define _SLANG_BCST_TIMESEQS 0x04
+#define _SLANG_BCST_DIVEQS 0x05
+#define _SLANG_BCST_BOREQS 0x06
+#define _SLANG_BCST_BANDEQS 0x07
+#define _SLANG_BCST_PLUSPLUS 0x08
+#define _SLANG_BCST_POST_PLUSPLUS 0x09
+#define _SLANG_BCST_MINUSMINUS 0x0A
+#define _SLANG_BCST_POST_MINUSMINUS 0x0B
+
+/* These use SLANG_PLUS, SLANG_MINUS, SLANG_PLUSPLUS, etc... */
+
+typedef union
+{
+#if SLANG_HAS_FLOAT
+ double double_val;
+ float float_val;
+#endif
+ long long_val;
+ unsigned long ulong_val;
+ VOID_STAR ptr_val;
+ char *s_val;
+ int int_val;
+ unsigned int uint_val;
+ SLang_MMT_Type *ref;
+ SLang_Name_Type *n_val;
+ struct _SLang_Struct_Type *struct_val;
+ struct _SLang_Array_Type *array_val;
+ short short_val;
+ unsigned short ushort_val;
+ char char_val;
+ unsigned char uchar_val;
+}
+_SL_Object_Union_Type;
+
+typedef struct _SLang_Object_Type
+{
+ unsigned char data_type; /* SLANG_INT_TYPE, ... */
+ _SL_Object_Union_Type v;
+}
+SLang_Object_Type;
+
+struct _SLang_MMT_Type
+{
+ unsigned char data_type; /* int, string, etc... */
+ VOID_STAR user_data; /* address of user structure */
+ unsigned int count; /* number of references */
+};
+
+extern int _SLang_pop_object_of_type (unsigned char, SLang_Object_Type *, int);
+
+typedef struct
+{
+ char *name; /* slstring */
+ SLang_Object_Type obj;
+}
+_SLstruct_Field_Type;
+
+typedef struct _SLang_Struct_Type
+{
+ _SLstruct_Field_Type *fields;
+ unsigned int nfields; /* number used */
+ unsigned int num_refs;
+}
+_SLang_Struct_Type;
+
+extern void _SLstruct_delete_struct (_SLang_Struct_Type *);
+extern int _SLang_push_struct (_SLang_Struct_Type *);
+extern int _SLang_pop_struct (_SLang_Struct_Type **);
+extern int _SLstruct_init (void);
+/* extern int _SLstruct_get_field (char *); */
+extern int _SLstruct_define_struct (void);
+extern int _SLstruct_define_typedef (void);
+
+extern int _SLang_pop_datatype (unsigned char *);
+extern int _SLang_push_datatype (unsigned char);
+
+struct _SLang_Ref_Type
+{
+ int is_global;
+ union
+ {
+ SLang_Name_Type *nt;
+ SLang_Object_Type *local_obj;
+ }
+ v;
+};
+
+extern int _SLang_dereference_ref (SLang_Ref_Type *);
+extern int _SLang_deref_assign (SLang_Ref_Type *);
+extern int _SLang_push_ref (int, VOID_STAR);
+
+extern int _SL_increment_frame_pointer (void);
+extern int _SL_decrement_frame_pointer (void);
+
+extern int SLang_pop(SLang_Object_Type *);
+extern void SLang_free_object (SLang_Object_Type *);
+extern int _SLanytype_typecast (unsigned char, VOID_STAR, unsigned int,
+ unsigned char, VOID_STAR);
+extern void _SLstring_intrinsic (void);
+
+
+/* These functions are used to create slstrings of a fixed length. Be
+ * very careful how they are used. In particular, if len bytes are allocated,
+ * then the string must be len characters long, no more and no less.
+ */
+extern char *_SLallocate_slstring (unsigned int);
+extern char *_SLcreate_via_alloced_slstring (char *, unsigned int);
+extern void _SLunallocate_slstring (char *, unsigned int);
+extern int _SLpush_alloced_slstring (char *, unsigned int);
+
+typedef struct
+{
+ char **buf;
+ unsigned int max_num;
+ unsigned int num;
+ unsigned int delta_num;
+}
+_SLString_List_Type;
+extern int _SLstring_list_append (_SLString_List_Type *, char *);
+extern int _SLstring_list_init (_SLString_List_Type *, unsigned int, unsigned int);
+extern void _SLstring_list_delete (_SLString_List_Type *);
+extern int _SLstring_list_push (_SLString_List_Type *);
+
+/* This function assumes that s is an slstring. */
+extern char *_SLstring_dup_slstring (char *);
+extern int _SLang_dup_and_push_slstring (char *);
+
+
+extern int _SLang_init_import (void);
+
+/* This function checks to see if the referenced object is initialized */
+extern int _SLang_is_ref_initialized (SLang_Ref_Type *);
+extern int _SLcheck_identifier_syntax (char *);
+extern int _SLang_uninitialize_ref (SLang_Ref_Type *);
+
+extern int _SLpush_slang_obj (SLang_Object_Type *);
+
+extern char *_SLexpand_escaped_char(char *, char *);
+extern void _SLexpand_escaped_string (char *, char *, char *);
+
+/* returns a pointer to an SLstring string-- use SLang_free_slstring */
+extern char *_SLstringize_object (SLang_Object_Type *);
+extern int _SLdump_objects (char *, SLang_Object_Type *, unsigned int, int);
+
+extern SLang_Object_Type *_SLRun_Stack;
+extern SLang_Object_Type *_SLStack_Pointer;
+
+struct _SLang_NameSpace_Type
+{
+ struct _SLang_NameSpace_Type *next;
+ char *name; /* this is the load_type name */
+ char *namespace_name; /* this name is assigned by implements */
+ unsigned int table_size;
+ SLang_Name_Type **table;
+};
+extern SLang_NameSpace_Type *_SLns_allocate_namespace (char *, unsigned int);
+extern SLang_NameSpace_Type *_SLns_find_namespace (char *);
+extern int _SLns_set_namespace_name (SLang_NameSpace_Type *, char *);
+extern SLang_Array_Type *_SLnspace_apropos (SLang_NameSpace_Type *, char *, unsigned int);
+extern void _SLang_use_namespace_intrinsic (char *name);
+extern char *_SLang_cur_namespace_intrinsic (void);
+extern SLang_Array_Type *_SLang_apropos (char *, char *, unsigned int);
+extern void _SLang_implements_intrinsic (char *);
+
+extern int _SLang_Trace;
+extern int _SLstack_depth(void);
+extern char *_SLang_Current_Function_Name;
+
+extern int _SLang_trace_fun(char *);
+extern int _SLang_Compile_Line_Num_Info;
+
+extern char *_SLstring_dup_hashed_string (char *, unsigned long);
+extern unsigned long _SLcompute_string_hash (char *);
+extern char *_SLstring_make_hashed_string (char *, unsigned int, unsigned long *);
+extern void _SLfree_hashed_string (char *, unsigned int, unsigned long);
+unsigned long _SLstring_hash (unsigned char *, unsigned char *);
+extern int _SLinit_slcomplex (void);
+
+extern int _SLang_init_slstrops (void);
+extern int _SLstrops_do_sprintf_n (int);
+extern int _SLang_sscanf (void);
+extern double _SLang_atof (char *);
+extern int _SLang_init_bstring (void);
+extern int _SLang_init_sltime (void);
+extern void _SLpack (void);
+extern void _SLunpack (char *, SLang_BString_Type *);
+extern void _SLpack_pad_format (char *);
+extern unsigned int _SLpack_compute_size (char *);
+extern int _SLusleep (unsigned long);
+
+/* frees upon error. NULL __NOT__ ok. */
+extern int _SLang_push_slstring (char *);
+
+extern unsigned char _SLarith_promote_type (unsigned char);
+extern int _SLarith_get_precedence (unsigned char);
+extern int _SLarith_typecast (unsigned char, VOID_STAR, unsigned int,
+ unsigned char, VOID_STAR);
+
+extern int SLang_push(SLang_Object_Type *);
+extern int SLadd_global_variable (char *);
+extern void _SLang_clear_error (void);
+
+extern int _SLdo_pop (void);
+extern unsigned int _SLsys_getkey (void);
+extern int _SLsys_input_pending (int);
+#ifdef IBMPC_SYSTEM
+extern unsigned int _SLpc_convert_scancode (unsigned int, unsigned int, int);
+#define _SLTT_KEY_SHIFT 1
+#define _SLTT_KEY_CTRL 2
+#define _SLTT_KEY_ALT 4
+#endif
+
+typedef struct _SLterminfo_Type SLterminfo_Type;
+extern SLterminfo_Type *_SLtt_tigetent (char *);
+extern char *_SLtt_tigetstr (SLterminfo_Type *, char *);
+extern int _SLtt_tigetnum (SLterminfo_Type *, char *);
+extern int _SLtt_tigetflag (SLterminfo_Type *, char *);
+
+#if SLTT_HAS_NON_BCE_SUPPORT
+extern int _SLtt_get_bce_color_offset (void);
+#endif
+extern void (*_SLtt_color_changed_hook)(void);
+
+extern unsigned char SLang_Input_Buffer [SL_MAX_INPUT_BUFFER_LEN];
+
+extern int _SLregister_types (void);
+extern SLang_Class_Type *_SLclass_get_class (unsigned char);
+extern VOID_STAR _SLclass_get_ptr_to_value (SLang_Class_Type *, SLang_Object_Type *);
+extern void _SLclass_type_mismatch_error (unsigned char, unsigned char);
+extern int _SLclass_init (void);
+extern int _SLclass_copy_class (unsigned char, unsigned char);
+
+extern unsigned char _SLclass_Class_Type [256];
+
+extern int (*_SLclass_get_typecast (unsigned char, unsigned char, int))
+(unsigned char, VOID_STAR, unsigned int,
+ unsigned char, VOID_STAR);
+
+extern int (*_SLclass_get_binary_fun (int, SLang_Class_Type *, SLang_Class_Type *, SLang_Class_Type **, int))
+(int,
+ unsigned char, VOID_STAR, unsigned int,
+ unsigned char, VOID_STAR, unsigned int,
+ VOID_STAR);
+
+extern int (*_SLclass_get_unary_fun (int, SLang_Class_Type *, SLang_Class_Type **, int))
+(int, unsigned char, VOID_STAR, unsigned int, VOID_STAR);
+
+extern int _SLarith_register_types (void);
+extern unsigned char _SLarith_Arith_Types [];
+extern unsigned char _SLarith_Is_Arith_Type [256];
+extern int _SLarith_bin_op (SLang_Object_Type *, SLang_Object_Type *, int);
+
+extern int _SLarray_add_bin_op (unsigned char);
+
+extern int _SLang_call_funptr (SLang_Name_Type *);
+extern void _SLset_double_format (char *);
+extern SLang_Name_Type *_SLlocate_global_name (char *);
+extern SLang_Name_Type *_SLlocate_name (char *);
+
+extern char *_SLdefines[];
+
+#define SL_ERRNO_NOT_IMPLEMENTED 0x7FFF
+extern int _SLerrno_errno;
+extern int _SLerrno_init (void);
+
+extern int _SLstdio_fdopen (char *, int, char *);
+
+extern void _SLstruct_pop_args (int *);
+extern void _SLstruct_push_args (SLang_Array_Type *);
+
+extern int _SLarray_aput (void);
+extern int _SLarray_aget (void);
+extern int _SLarray_inline_implicit_array (void);
+extern int _SLarray_inline_array (void);
+extern int _SLarray_wildcard_array (void);
+
+extern int
+_SLarray_typecast (unsigned char, VOID_STAR, unsigned int,
+ unsigned char, VOID_STAR, int);
+
+extern int _SLarray_aput_transfer_elem (SLang_Array_Type *, int *,
+ VOID_STAR, unsigned int, int);
+extern int _SLarray_aget_transfer_elem (SLang_Array_Type *, int *,
+ VOID_STAR, unsigned int, int);
+extern void _SLarray_free_array_elements (SLang_Class_Type *, VOID_STAR, unsigned int);
+
+extern SLang_Foreach_Context_Type *
+_SLarray_cl_foreach_open (unsigned char, unsigned int);
+extern void _SLarray_cl_foreach_close (unsigned char, SLang_Foreach_Context_Type *);
+extern int _SLarray_cl_foreach (unsigned char, SLang_Foreach_Context_Type *);
+
+extern int _SLarray_matrix_multiply (void);
+extern void (*_SLang_Matrix_Multiply)(void);
+
+extern int _SLarray_init_slarray (void);
+extern SLang_Array_Type *
+SLang_create_array1 (unsigned char, int, VOID_STAR, int *, unsigned int, int);
+
+extern int _SLcompile_push_context (SLang_Load_Type *);
+extern int _SLcompile_pop_context (void);
+extern int _SLang_Auto_Declare_Globals;
+
+typedef struct
+{
+ union
+ {
+ long long_val;
+ char *s_val; /* Used for IDENT_TOKEN, FLOAT, etc... */
+ SLang_BString_Type *b_val;
+ } v;
+ int free_sval_flag;
+ unsigned int num_refs;
+ unsigned long hash;
+#if _SLANG_HAS_DEBUG_CODE
+ int line_number;
+#endif
+ unsigned char type;
+}
+_SLang_Token_Type;
+
+extern void _SLcompile (_SLang_Token_Type *);
+extern void (*_SLcompile_ptr)(_SLang_Token_Type *);
+
+/* *** TOKENS *** */
+
+/* Note that that tokens corresponding to ^J, ^M, and ^Z should not be used.
+ * This is because a file that contains any of these characters will
+ * have an OS dependent interpretation, e.g., ^Z is EOF on MSDOS.
+ */
+
+/* Special tokens */
+#define EOF_TOKEN 0x01
+#define RPN_TOKEN 0x02
+#define NL_TOKEN 0x03
+#define NOP_TOKEN 0x05
+#define FARG_TOKEN 0x06
+#define TMP_TOKEN 0x07
+
+#define RESERVED1_TOKEN 0x0A /* \n */
+#define RESERVED2_TOKEN 0x0D /* \r */
+
+/* Literal tokens */
+#define CHAR_TOKEN 0x10
+#define UCHAR_TOKEN 0x11
+#define SHORT_TOKEN 0x12
+#define USHORT_TOKEN 0x13
+#define INT_TOKEN 0x14
+#define UINT_TOKEN 0x15
+#define LONG_TOKEN 0x16
+#define ULONG_TOKEN 0x17
+#define IS_INTEGER_TOKEN(x) ((x >= CHAR_TOKEN) && (x <= ULONG_TOKEN))
+#define FLOAT_TOKEN 0x18
+#define DOUBLE_TOKEN 0x19
+#define RESERVED3_TOKEN 0x1A /* ^Z */
+#define COMPLEX_TOKEN 0x1B
+#define STRING_TOKEN 0x1C
+#define BSTRING_TOKEN 0x1D
+#define _BSTRING_TOKEN 0x1E /* byte-compiled BSTRING */
+#define ESC_STRING_TOKEN 0x1F
+
+/* Tokens that can be LVALUES */
+#define IDENT_TOKEN 0x20
+#define ARRAY_TOKEN 0x21
+#define DOT_TOKEN 0x22
+#define IS_LVALUE_TOKEN (((t) <= DOT_TOKEN) && ((t) >= IDENT_TOKEN))
+
+/* do not use these values */
+#define RESERVED4_TOKEN 0x23 /* # */
+#define RESERVED5_TOKEN 0x25 /* % */
+
+/* Flags for struct fields */
+#define STATIC_TOKEN 0x26
+#define READONLY_TOKEN 0x27
+#define PRIVATE_TOKEN 0x28
+#define PUBLIC_TOKEN 0x29
+
+/* Punctuation tokens */
+#define OBRACKET_TOKEN 0x2a
+#define CBRACKET_TOKEN 0x2b
+#define OPAREN_TOKEN 0x2c
+#define CPAREN_TOKEN 0x2d
+#define OBRACE_TOKEN 0x2e
+#define CBRACE_TOKEN 0x2f
+
+#define COMMA_TOKEN 0x31
+#define SEMICOLON_TOKEN 0x32
+#define COLON_TOKEN 0x33
+#define NAMESPACE_TOKEN 0x34
+
+/* Operators */
+#define POW_TOKEN 0x38
+
+/* The order here must match the order in the Binop_Level table in slparse.c */
+#define FIRST_BINARY_OP 0x39
+#define ADD_TOKEN 0x39
+#define SUB_TOKEN 0x3a
+#define TIMES_TOKEN 0x3b
+#define DIV_TOKEN 0x3c
+#define LT_TOKEN 0x3d
+#define LE_TOKEN 0x3e
+#define GT_TOKEN 0x3f
+#define GE_TOKEN 0x40
+#define EQ_TOKEN 0x41
+#define NE_TOKEN 0x42
+#define AND_TOKEN 0x43
+#define OR_TOKEN 0x44
+#define MOD_TOKEN 0x45
+#define BAND_TOKEN 0x46
+#define SHL_TOKEN 0x47
+#define SHR_TOKEN 0x48
+#define BXOR_TOKEN 0x49
+#define BOR_TOKEN 0x4a
+#define POUND_TOKEN 0x4b /* matrix multiplication */
+
+#define LAST_BINARY_OP 0x4b
+#define IS_BINARY_OP(t) ((t >= FIRST_BINARY_OP) && (t <= LAST_BINARY_OP))
+
+/* unary tokens -- but not all of them (see grammar) */
+#define DEREF_TOKEN 0x4d
+#define NOT_TOKEN 0x4e
+#define BNOT_TOKEN 0x4f
+
+#define IS_INTERNAL_FUNC(t) ((t >= 0x50) && (t <= 0x56))
+#define POP_TOKEN 0x50
+#define CHS_TOKEN 0x51
+#define SIGN_TOKEN 0x52
+#define ABS_TOKEN 0x53
+#define SQR_TOKEN 0x54
+#define MUL2_TOKEN 0x55
+#define EXCH_TOKEN 0x56
+
+/* Assignment tokens. Note: these must appear with sequential values.
+ * The order here must match the specific lvalue assignments below.
+ * These tokens are used by rpn routines in slang.c. slparse.c maps them
+ * onto the specific lvalue tokens while parsing infix.
+ * Also the assignment _SLANG_BCST_ assumes this order
+ */
+#define ASSIGN_TOKEN 0x57
+#define PLUSEQS_TOKEN 0x58
+#define MINUSEQS_TOKEN 0x59
+#define TIMESEQS_TOKEN 0x5A
+#define DIVEQS_TOKEN 0x5B
+#define BOREQS_TOKEN 0x5C
+#define BANDEQS_TOKEN 0x5D
+#define PLUSPLUS_TOKEN 0x5E
+#define POST_PLUSPLUS_TOKEN 0x5F
+#define MINUSMINUS_TOKEN 0x60
+#define POST_MINUSMINUS_TOKEN 0x61
+
+/* Directives */
+#define FIRST_DIRECTIVE_TOKEN 0x62
+#define IFNOT_TOKEN 0x62
+#define IF_TOKEN 0x63
+#define ELSE_TOKEN 0x64
+#define FOREVER_TOKEN 0x65
+#define WHILE_TOKEN 0x66
+#define FOR_TOKEN 0x67
+#define _FOR_TOKEN 0x68
+#define LOOP_TOKEN 0x69
+#define SWITCH_TOKEN 0x6A
+#define DOWHILE_TOKEN 0x6B
+#define ANDELSE_TOKEN 0x6C
+#define ORELSE_TOKEN 0x6D
+#define ERRBLK_TOKEN 0x6E
+#define EXITBLK_TOKEN 0x6F
+/* These must be sequential */
+#define USRBLK0_TOKEN 0x70
+#define USRBLK1_TOKEN 0x71
+#define USRBLK2_TOKEN 0x72
+#define USRBLK3_TOKEN 0x73
+#define USRBLK4_TOKEN 0x74
+
+#define CONT_TOKEN 0x75
+#define BREAK_TOKEN 0x76
+#define RETURN_TOKEN 0x77
+
+#define CASE_TOKEN 0x78
+#define DEFINE_TOKEN 0x79
+#define DO_TOKEN 0x7a
+#define VARIABLE_TOKEN 0x7b
+#define GVARIABLE_TOKEN 0x7c
+#define _REF_TOKEN 0x7d
+#define PUSH_TOKEN 0x7e
+#define STRUCT_TOKEN 0x7f
+#define TYPEDEF_TOKEN 0x80
+#define NOTELSE_TOKEN 0x81
+#define DEFINE_STATIC_TOKEN 0x82
+#define FOREACH_TOKEN 0x83
+#define USING_TOKEN 0x84
+#define DEFINE_PRIVATE_TOKEN 0x85
+#define DEFINE_PUBLIC_TOKEN 0x86
+
+/* Note: the order here must match the order of the generic assignment tokens.
+ * Also, the first token of each group must be the ?_ASSIGN_TOKEN.
+ * slparse.c exploits this order, as well as slang.h.
+ */
+#define FIRST_ASSIGN_TOKEN 0x90
+#define _STRUCT_ASSIGN_TOKEN 0x90
+#define _STRUCT_PLUSEQS_TOKEN 0x91
+#define _STRUCT_MINUSEQS_TOKEN 0x92
+#define _STRUCT_TIMESEQS_TOKEN 0x93
+#define _STRUCT_DIVEQS_TOKEN 0x94
+#define _STRUCT_BOREQS_TOKEN 0x95
+#define _STRUCT_BANDEQS_TOKEN 0x96
+#define _STRUCT_PLUSPLUS_TOKEN 0x97
+#define _STRUCT_POST_PLUSPLUS_TOKEN 0x98
+#define _STRUCT_MINUSMINUS_TOKEN 0x99
+#define _STRUCT_POST_MINUSMINUS_TOKEN 0x9A
+
+#define _ARRAY_ASSIGN_TOKEN 0xA0
+#define _ARRAY_PLUSEQS_TOKEN 0xA1
+#define _ARRAY_MINUSEQS_TOKEN 0xA2
+#define _ARRAY_TIMESEQS_TOKEN 0xA3
+#define _ARRAY_DIVEQS_TOKEN 0xA4
+#define _ARRAY_BOREQS_TOKEN 0xA5
+#define _ARRAY_BANDEQS_TOKEN 0xA6
+#define _ARRAY_PLUSPLUS_TOKEN 0xA7
+#define _ARRAY_POST_PLUSPLUS_TOKEN 0xA8
+#define _ARRAY_MINUSMINUS_TOKEN 0xA9
+#define _ARRAY_POST_MINUSMINUS_TOKEN 0xAA
+
+#define _SCALAR_ASSIGN_TOKEN 0xB0
+#define _SCALAR_PLUSEQS_TOKEN 0xB1
+#define _SCALAR_MINUSEQS_TOKEN 0xB2
+#define _SCALAR_TIMESEQS_TOKEN 0xB3
+#define _SCALAR_DIVEQS_TOKEN 0xB4
+#define _SCALAR_BOREQS_TOKEN 0xB5
+#define _SCALAR_BANDEQS_TOKEN 0xB6
+#define _SCALAR_PLUSPLUS_TOKEN 0xB7
+#define _SCALAR_POST_PLUSPLUS_TOKEN 0xB8
+#define _SCALAR_MINUSMINUS_TOKEN 0xB9
+#define _SCALAR_POST_MINUSMINUS_TOKEN 0xBA
+
+#define _DEREF_ASSIGN_TOKEN 0xC0
+#define _DEREF_PLUSEQS_TOKEN 0xC1
+#define _DEREF_MINUSEQS_TOKEN 0xC2
+#define _DEREF_TIMESEQS_TOKEN 0xC3
+#define _DEREF_DIVEQS_TOKEN 0xC4
+#define _DEREF_BOREQS_TOKEN 0xC5
+#define _DEREF_BANDEQS_TOKEN 0xC6
+#define _DEREF_PLUSPLUS_TOKEN 0xC7
+#define _DEREF_POST_PLUSPLUS_TOKEN 0xC8
+#define _DEREF_MINUSMINUS_TOKEN 0xC9
+#define _DEREF_POST_MINUSMINUS_TOKEN 0xCA
+
+#define LAST_ASSIGN_TOKEN 0xCA
+#define IS_ASSIGN_TOKEN(t) (((t)>=FIRST_ASSIGN_TOKEN)&&((t)<=LAST_ASSIGN_TOKEN))
+
+#define _INLINE_ARRAY_TOKEN 0xE0
+#define _INLINE_IMPLICIT_ARRAY_TOKEN 0xE1
+#define _NULL_TOKEN 0xE2
+#define _INLINE_WILDCARD_ARRAY_TOKEN 0xE3
+
+#define LINE_NUM_TOKEN 0xFC
+#define ARG_TOKEN 0xFD
+#define EARG_TOKEN 0xFE
+#define NO_OP_LITERAL 0xFF
+
+typedef struct
+{
+ /* sltoken.c */
+ /* SLang_eval_object */
+ SLang_Load_Type *llt;
+ SLPreprocess_Type *this_slpp;
+ /* prep_get_char() */
+ char *input_line;
+ char cchar;
+ /* get_token() */
+ int want_nl_token;
+
+ /* slparse.c */
+ _SLang_Token_Type ctok;
+ int block_depth;
+ int assignment_expression;
+
+ /* slang.c : SLcompile() */
+ _SLang_Token_Type save_token;
+ _SLang_Token_Type next_token;
+ void (*slcompile_ptr)(_SLang_Token_Type *);
+}
+_SLEval_Context;
+
+extern int _SLget_token (_SLang_Token_Type *);
+extern void _SLparse_error (char *, _SLang_Token_Type *, int);
+extern void _SLparse_start (SLang_Load_Type *);
+extern int _SLget_rpn_token (_SLang_Token_Type *);
+extern void _SLcompile_byte_compiled (void);
+
+extern int (*_SLprep_eval_hook) (char *);
+
+#ifdef HAVE_VSNPRINTF
+#define _SLvsnprintf vsnprintf
+#else
+extern int _SLvsnprintf (char *, unsigned int, char *, va_list);
+#endif
+
+#ifdef HAVE_SNPRINTF
+# define _SLsnprintf snprintf
+#else
+extern int _SLsnprintf (char *, unsigned int, char *, ...);
+#endif
+
+#undef _INLINE_
+#if defined(__GNUC__) && _SLANG_USE_INLINE_CODE
+# define _INLINE_ __inline__
+#else
+# define _INLINE_
+#endif
+
+
+#endif /* _PRIVATE_SLANG_H_ */
diff --git a/mdk-stage1/slang/config.h b/mdk-stage1/slang/config.h
new file mode 100644
index 000000000..a5ab3273c
--- /dev/null
+++ b/mdk-stage1/slang/config.h
@@ -0,0 +1,163 @@
+/* src/sysconf.h. Generated automatically by configure. */
+/* -*- c -*- */
+/* Note: this is for unix only. */
+
+#ifndef SL_CONFIG_H
+#define SL_CONFIG_H
+
+/* define if you have stdlib.h */
+#define HAVE_STDLIB_H 1
+
+/* define if you have unistd.h */
+#define HAVE_UNISTD_H 1
+
+/* define if you have termios.h */
+#define HAVE_TERMIOS_H 1
+
+/* define if you have memory.h */
+#define HAVE_MEMORY_H 1
+
+/* define if you have malloc.h */
+#define HAVE_MALLOC_H 1
+
+/* define if you have memset */
+#define HAVE_MEMSET 1
+
+/* define if you have memcpy */
+#define HAVE_MEMCPY 1
+
+//#define HAVE_SETLOCALE 1
+//#define HAVE_LOCALE_H 1
+
+#define HAVE_VFSCANF 1
+
+/* define if you have fcntl.h */
+#define HAVE_FCNTL_H 1
+
+/* Define if you have the vsnprintf, snprintf functions and they return
+ * EOF upon failure.
+ */
+#define HAVE_VSNPRINTF 1
+#define HAVE_SNPRINTF 1
+
+/* define if you have sys/fcntl.h */
+#define HAVE_SYS_FCNTL_H 1
+
+#define HAVE_SYS_TYPES_H 1
+#define HAVE_SYS_WAIT_H 1
+#define HAVE_SYS_TIMES_H 1
+
+/* Set these to the appropriate values */
+#define SIZEOF_SHORT 2
+#define SIZEOF_INT 4
+#define SIZEOF_LONG 4
+#define SIZEOF_FLOAT 4
+#define SIZEOF_DOUBLE 8
+
+/* define if you have these. */
+#define HAVE_ATEXIT 1
+#define HAVE_ON_EXIT 1
+#define HAVE_PUTENV 1
+#define HAVE_GETCWD 1
+#define HAVE_TCGETATTR 1
+#define HAVE_TCSETATTR 1
+#define HAVE_CFGETOSPEED 1
+#define HAVE_LSTAT 1
+#define HAVE_KILL 1
+#define HAVE_CHOWN 1
+#define HAVE_VSNPRINTF 1
+#define HAVE_POPEN 1
+#define HAVE_UMASK 1
+#define HAVE_READLINK 1
+#define HAVE_TIMES 1
+#define HAVE_GMTIME 1
+#define HAVE_MKFIFO 1
+
+#define HAVE_GETPPID 1
+#define HAVE_GETGID 1
+#define HAVE_GETEGID 1
+#define HAVE_GETEUID 1
+/* #undef HAVE_GETUID */
+
+#define HAVE_SETGID 1
+#define HAVE_SETPGID 1
+#define HAVE_SETUID 1
+
+#define HAVE_ACOSH 1
+#define HAVE_ASINH 1
+#define HAVE_ATANH 1
+
+#define HAVE_DIRENT_H 1
+/* #undef HAVE_SYS_NDIR_H */
+/* #undef HAVE_SYS_DIR_H */
+/* #undef HAVE_NDIR_H */
+
+#define HAVE_DLFCN_H 1
+
+#define HAVE_SYS_UTSNAME_H 1
+#define HAVE_UNAME 1
+
+/* These two are needed on DOS-like systems. Unix does not require them.
+ * They are included here for consistency.
+ *
+#define HAVE_IO_H
+#define HAVE_PROCESS_H
+ */
+
+/* #undef USE_TERMCAP */
+
+/* #undef mode_t */
+/* #undef uid_t */
+/* #undef pid_t */
+/* #undef gid_t */
+
+/* Do we have posix signals? */
+#define HAVE_SIGACTION 1
+#define HAVE_SIGPROCMASK 1
+#define HAVE_SIGEMPTYSET 1
+#define HAVE_SIGADDSET 1
+
+#if defined(HAVE_SIGADDSET) && defined(HAVE_SIGEMPTYSET)
+# if defined(HAVE_SIGACTION) && defined(HAVE_SIGPROCMASK)
+# define SLANG_POSIX_SIGNALS
+# endif
+#endif
+
+/* Define if you need to in order for stat and other things to work. */
+/* #undef _POSIX_SOURCE */
+
+#ifdef _AIX
+# ifndef _POSIX_SOURCE
+# define _POSIX_SOURCE 1
+# endif
+# ifndef _ALL_SOURCE
+# define _ALL_SOURCE
+# endif
+/* This may generate warnings but the fact is that without it, xlc will
+ * INCORRECTLY inline many str* functions. */
+/* # undef __STR__ */
+#endif
+
+/* define USE_TERMCAP if you want to use it instead of terminfo. */
+#if defined(sequent) || defined(NeXT)
+# ifndef USE_TERMCAP
+# define USE_TERMCAP
+# endif
+#endif
+
+#if defined(ultrix) && !defined(__GNUC__)
+# ifndef NO_PROTOTYPES
+# define NO_PROTOTYPES
+# endif
+#endif
+
+#ifndef unix
+# define unix 1
+#endif
+
+#ifndef __unix__
+# define __unix__ 1
+#endif
+
+#define _SLANG_SOURCE_ 1
+#endif /* SL_CONFIG_H */
diff --git a/mdk-stage1/slang/jdmacros.h b/mdk-stage1/slang/jdmacros.h
new file mode 100644
index 000000000..70d491b78
--- /dev/null
+++ b/mdk-stage1/slang/jdmacros.h
@@ -0,0 +1,53 @@
+#ifndef _JD_MACROS_H_
+#define _JD_MACROS_H_
+
+#ifndef SLMEMSET
+# ifdef HAVE_MEMSET
+# define SLMEMSET memset
+# else
+# define SLMEMSET SLmemset
+# endif
+#endif
+
+#ifndef SLMEMCHR
+# ifdef HAVE_MEMCHR
+# define SLMEMCHR memchr
+# else
+# define SLMEMCHR SLmemchr
+# endif
+#endif
+
+#ifndef SLMEMCPY
+# ifdef HAVE_MEMCPY
+# define SLMEMCPY memcpy
+# else
+# define SLMEMCPY SLmemcpy
+# endif
+#endif
+
+/* Note: HAVE_MEMCMP requires an unsigned memory comparison!!! */
+#ifndef SLMEMCMP
+# ifdef HAVE_MEMCMP
+# define SLMEMCMP memcmp
+# else
+# define SLMEMCMP SLmemcmp
+# endif
+#endif
+
+#ifndef SLFREE
+# define SLFREE free
+#endif
+
+#ifndef SLMALLOC
+# define SLMALLOC malloc
+#endif
+
+#ifndef SLCALLOC
+# define SLCALLOC calloc
+#endif
+
+#ifndef SLREALLOC
+# define SLREALLOC realloc
+#endif
+
+#endif /* _JD_MACROS_H_ */
diff --git a/mdk-stage1/slang/keywhash.c b/mdk-stage1/slang/keywhash.c
new file mode 100644
index 000000000..17d94d5a3
--- /dev/null
+++ b/mdk-stage1/slang/keywhash.c
@@ -0,0 +1,190 @@
+/* Perfect hash generated by command line:
+ * ./a.out 1
+ */
+#define MIN_HASH_VALUE 2
+#define MAX_HASH_VALUE 118
+#define MIN_KEYWORD_LEN 2
+#define MAX_KEYWORD_LEN 11
+
+static unsigned char Keyword_Hash_Table [256] =
+{
+ 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119,
+ 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119,
+ 119, 1, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119,
+ 9, 7, 1, 8, 2, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119,
+ 119, 119, 0, 0, 119, 0, 119, 119, 119, 7, 119, 0, 0, 119, 119, 0,
+ 119, 119, 0, 0, 0, 0, 119, 119, 0, 119, 119, 119, 119, 119, 119, 2,
+ 119, 41, 1, 1, 9, 0, 55, 8, 0, 0, 119, 0, 27, 0, 0, 0,
+ 7, 2, 0, 21, 0, 0, 0, 3, 2, 0, 119, 119, 119, 119, 119, 119,
+ 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119,
+ 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119,
+ 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119,
+ 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119,
+ 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119,
+ 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119,
+ 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119,
+ 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119
+};
+
+static unsigned char keyword_hash (char *s, unsigned int len)
+{
+ unsigned int sum;
+
+ sum = len;
+ while (len)
+ {
+ len--;
+ sum += (unsigned int) Keyword_Hash_Table [(unsigned char)s[len]];
+ }
+ return sum;
+}
+
+typedef struct
+{
+ char *name;
+ unsigned int type;
+}
+Keyword_Table_Type;
+
+static Keyword_Table_Type Keyword_Table [/* 117 */] =
+{
+ {"or", OR_TOKEN},
+ {"not", NOT_TOKEN},
+ {NULL,0},
+ {"xor", BXOR_TOKEN},
+ {"return", RETURN_TOKEN},
+ {"exch", EXCH_TOKEN},
+ {NULL,0},
+ {"continue", CONT_TOKEN},
+ {NULL,0},
+ {"do", DO_TOKEN},
+ {"mod", MOD_TOKEN},
+ {"ERROR_BLOCK", ERRBLK_TOKEN},
+ {"USER_BLOCK2", USRBLK2_TOKEN},
+ {"USER_BLOCK4", USRBLK4_TOKEN},
+ {"__tmp", TMP_TOKEN},
+ {"pop", POP_TOKEN},
+ {NULL,0},
+ {"EXIT_BLOCK", EXITBLK_TOKEN},
+ {"USER_BLOCK1", USRBLK1_TOKEN},
+ {"USER_BLOCK3", USRBLK3_TOKEN},
+ {"USER_BLOCK0", USRBLK0_TOKEN},
+ {NULL,0},
+ {"shr", SHR_TOKEN},
+ {"chs", CHS_TOKEN},
+ {"sqr", SQR_TOKEN},
+ {NULL,0},
+ {"struct", STRUCT_TOKEN},
+ {NULL,0},
+ {NULL,0},
+ {"switch", SWITCH_TOKEN},
+ {"mul2", MUL2_TOKEN},
+ {"sign", SIGN_TOKEN},
+ {"using", USING_TOKEN},
+ {"while", WHILE_TOKEN},
+ {NULL,0},
+ {NULL,0},
+ {"loop", LOOP_TOKEN},
+ {NULL,0},
+ {NULL,0},
+ {NULL,0},
+ {"public", PUBLIC_TOKEN},
+ {NULL,0},
+ {NULL,0},
+ {NULL,0},
+ {NULL,0},
+ {"break", BREAK_TOKEN},
+ {NULL,0},
+ {"do_while", DOWHILE_TOKEN},
+ {NULL,0},
+ {"shl", SHL_TOKEN},
+ {"else", ELSE_TOKEN},
+ {"and", AND_TOKEN},
+ {"orelse", ORELSE_TOKEN},
+ {"private", PRIVATE_TOKEN},
+ {NULL,0},
+ {"if", IF_TOKEN},
+ {"for", FOR_TOKEN},
+ {"!if", IFNOT_TOKEN},
+ {NULL,0},
+ {"_for", _FOR_TOKEN},
+ {"forever", FOREVER_TOKEN},
+ {NULL,0},
+ {NULL,0},
+ {NULL,0},
+ {"abs", ABS_TOKEN},
+ {"case", CASE_TOKEN},
+ {NULL,0},
+ {"static", STATIC_TOKEN},
+ {"define", DEFINE_TOKEN},
+ {NULL,0},
+ {NULL,0},
+ {NULL,0},
+ {NULL,0},
+ {NULL,0},
+ {NULL,0},
+ {NULL,0},
+ {"typedef", TYPEDEF_TOKEN},
+ {NULL,0},
+ {NULL,0},
+ {NULL,0},
+ {NULL,0},
+ {NULL,0},
+ {NULL,0},
+ {NULL,0},
+ {NULL,0},
+ {NULL,0},
+ {NULL,0},
+ {NULL,0},
+ {NULL,0},
+ {NULL,0},
+ {NULL,0},
+ {NULL,0},
+ {NULL,0},
+ {NULL,0},
+ {NULL,0},
+ {NULL,0},
+ {NULL,0},
+ {NULL,0},
+ {NULL,0},
+ {NULL,0},
+ {NULL,0},
+ {NULL,0},
+ {"foreach", FOREACH_TOKEN},
+ {"andelse", ANDELSE_TOKEN},
+ {NULL,0},
+ {NULL,0},
+ {NULL,0},
+ {NULL,0},
+ {NULL,0},
+ {NULL,0},
+ {NULL,0},
+ {NULL,0},
+ {NULL,0},
+ {NULL,0},
+ {NULL,0},
+ {NULL,0},
+ {"variable", VARIABLE_TOKEN},
+};
+
+static Keyword_Table_Type *is_keyword (char *str, unsigned int len)
+{
+ unsigned int hash;
+ char *name;
+ Keyword_Table_Type *kw;
+
+ if ((len < MIN_KEYWORD_LEN)
+ || (len > MAX_KEYWORD_LEN))
+ return NULL;
+
+ hash = keyword_hash (str, len);
+ if ((hash > MAX_HASH_VALUE) || (hash < MIN_HASH_VALUE))
+ return NULL;
+
+ kw = &Keyword_Table[hash - MIN_HASH_VALUE];
+ if ((NULL != (name = kw->name))
+ && (*str == *name)
+ && (0 == strcmp (str, name)))
+ return kw;
+ return NULL;
+}
diff --git a/mdk-stage1/slang/sl-feat.h b/mdk-stage1/slang/sl-feat.h
new file mode 100644
index 000000000..511d72451
--- /dev/null
+++ b/mdk-stage1/slang/sl-feat.h
@@ -0,0 +1,60 @@
+/* Setting this to 1 enables automatic support for associative arrays.
+ * If this is set to 0, an application must explicitly enable associative
+ * array support via SLang_init_slassoc.
+ */
+#define SLANG_HAS_ASSOC_ARRAYS 1
+
+#define SLANG_HAS_COMPLEX 1
+#define SLANG_HAS_FLOAT 1
+
+/* This is the old space-speed trade off. To reduce memory usage and code
+ * size, set this to zero.
+ */
+#define _SLANG_OPTIMIZE_FOR_SPEED 2
+
+#define _SLANG_USE_INLINE_CODE 1
+
+/* This is experimental. It adds extra information for tracking down
+ * errors.
+ */
+#define _SLANG_HAS_DEBUG_CODE 1
+
+/* Allow optimizations based upon the __tmp operator. */
+#define _SLANG_USE_TMP_OPTIMIZATION 1
+
+/* Setting this to one will map 8 bit vtxxx terminals to 7 bit. Terminals
+ * such as the vt320 can be set up to output the two-character escape sequence
+ * encoded as 'ESC [' as single character. Setting this variable to 1 will
+ * insert code to map such characters to the 7 bit equivalent.
+ * This affects just input characters in the range 128-160 on non PC
+ * systems.
+ */
+#if defined(VMS) || defined(AMIGA)
+# define _SLANG_MAP_VTXXX_8BIT 1
+#else
+# define _SLANG_MAP_VTXXX_8BIT 0
+#endif
+
+/* Add support for color terminals that cannot do background color erases
+ * Such terminals are poorly designed and are slowly disappearing but they
+ * are still quite common. For example, screen is one of them!
+ *
+ * This is experimental. In particular, it is not known to work if
+ * KANJI suupport is enabled.
+ */
+#if !defined(IBMPC_SYSTEM)
+# define SLTT_HAS_NON_BCE_SUPPORT 1
+#else
+# define SLTT_HAS_NON_BCE_SUPPORT 0
+#endif
+
+/* If you want slang to assume that an xterm always has the background color
+ * erase feature, then set this to 1. Otherwise, it will check the terminfo
+ * database. This may or may not be a good idea since most good color xterms
+ * support bce but many terminfo systems do not support it.
+ */
+#define SLTT_XTERM_ALWAYS_BCE 0
+
+/* Set this to 1 to enable Kanji support. See above comment. */
+#define SLANG_HAS_KANJI_SUPPORT 0
+
diff --git a/mdk-stage1/slang/slang.c b/mdk-stage1/slang/slang.c
new file mode 100644
index 000000000..6edc7df37
--- /dev/null
+++ b/mdk-stage1/slang/slang.c
@@ -0,0 +1,5547 @@
+/* -*- mode: C; mode: fold; -*- */
+/* slang.c --- guts of S-Lang interpreter */
+/* Copyright (c) 1992, 1999, 2001 John E. Davis
+ * This file is part of the S-Lang library.
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Perl Artistic License.
+ */
+
+#include "slinclud.h"
+
+#if SLANG_HAS_FLOAT
+# include <math.h>
+#endif
+
+#include "slang.h"
+#include "_slang.h"
+
+#define USE_COMBINED_BYTECODES 0
+
+struct _SLBlock_Type;
+
+typedef struct
+{
+ struct _SLBlock_Type *body;
+ unsigned int num_refs;
+}
+_SLBlock_Header_Type;
+
+typedef struct
+{
+ char *name;
+ SLang_Name_Type *next;
+ char name_type;
+
+ union
+ {
+ _SLBlock_Header_Type *header; /* body of function */
+ char *autoload_filename;
+ }
+ v;
+#if _SLANG_HAS_DEBUG_CODE
+ char *file;
+#endif
+#define SLANG_MAX_LOCAL_VARIABLES 254
+#define AUTOLOAD_NUM_LOCALS (SLANG_MAX_LOCAL_VARIABLES + 1)
+ unsigned char nlocals; /* number of local variables */
+ unsigned char nargs; /* number of arguments */
+}
+_SLang_Function_Type;
+
+typedef struct
+{
+ char *name;
+ SLang_Name_Type *next;
+ char name_type;
+
+ SLang_Object_Type obj;
+}
+SLang_Global_Var_Type;
+
+typedef struct
+{
+ char *name;
+ SLang_Name_Type *next;
+ char name_type;
+
+ int local_var_number;
+}
+SLang_Local_Var_Type;
+
+typedef struct _SLBlock_Type
+{
+ unsigned char bc_main_type;
+ unsigned char bc_sub_type;
+ union
+ {
+ struct _SLBlock_Type *blk;
+ int i_blk;
+
+ SLang_Name_Type *nt_blk;
+ SLang_App_Unary_Type *nt_unary_blk;
+ SLang_Intrin_Var_Type *nt_ivar_blk;
+ SLang_Intrin_Fun_Type *nt_ifun_blk;
+ SLang_Global_Var_Type *nt_gvar_blk;
+ SLang_IConstant_Type *iconst_blk;
+ SLang_DConstant_Type *dconst_blk;
+ _SLang_Function_Type *nt_fun_blk;
+
+ VOID_STAR ptr_blk;
+ char *s_blk;
+ SLang_BString_Type *bs_blk;
+
+#if SLANG_HAS_FLOAT
+ double *double_blk; /*literal double is a pointer */
+#endif
+ float float_blk;
+ long l_blk;
+ struct _SLang_Struct_Type *struct_blk;
+ int (*call_function)(void);
+ }
+ b;
+}
+SLBlock_Type;
+
+/* Debugging and tracing variables */
+
+void (*SLang_Enter_Function)(char *) = NULL;
+void (*SLang_Exit_Function)(char *) = NULL;
+/* If non null, these call C functions before and after a slang function. */
+
+int _SLang_Trace = 0;
+/* If _SLang_Trace = -1, do not trace intrinsics */
+static int Trace_Mode = 0;
+
+static char *Trace_Function; /* function to be traced */
+int SLang_Traceback = 0;
+/* non zero means do traceback. If less than 0, do not show local variables */
+
+/* These variables handle _NARGS processing by the parser */
+int SLang_Num_Function_Args;
+static int *Num_Args_Stack;
+static unsigned int Recursion_Depth;
+static SLang_Object_Type *Frame_Pointer;
+static int Next_Function_Num_Args;
+static unsigned int Frame_Pointer_Depth;
+static unsigned int *Frame_Pointer_Stack;
+
+static int Lang_Break_Condition = 0;
+/* true if any one below is true. This keeps us from testing 3 variables.
+ * I know this can be perfomed with a bitmapped variable, but...
+ */
+static int Lang_Break = 0;
+static int Lang_Return = 0;
+/* static int Lang_Continue = 0; */
+
+SLang_Object_Type *_SLRun_Stack;
+SLang_Object_Type *_SLStack_Pointer;
+static SLang_Object_Type *_SLStack_Pointer_Max;
+
+/* Might want to increase this. */
+static SLang_Object_Type Local_Variable_Stack[SLANG_MAX_LOCAL_STACK];
+static SLang_Object_Type *Local_Variable_Frame = Local_Variable_Stack;
+
+static void free_function_header (_SLBlock_Header_Type *);
+
+void (*SLang_Dump_Routine)(char *);
+
+static void call_dump_routine (char *fmt, ...)
+{
+ char buf[1024];
+ va_list ap;
+
+ va_start (ap, fmt);
+ if (SLang_Dump_Routine != NULL)
+ {
+ (void) _SLvsnprintf (buf, sizeof (buf), fmt, ap);
+ (*SLang_Dump_Routine) (buf);
+ }
+ else
+ {
+ vfprintf (stderr, fmt, ap);
+ fflush (stderr);
+ }
+ va_end (ap);
+}
+
+static void do_traceback (char *, unsigned int, char *);
+static int init_interpreter (void);
+
+/*{{{ push/pop/etc stack manipulation functions */
+
+/* This routine is assumed to work even in the presence of a SLang_Error. */
+_INLINE_
+int SLang_pop (SLang_Object_Type *x)
+{
+ register SLang_Object_Type *y;
+
+ y = _SLStack_Pointer;
+ if (y == _SLRun_Stack)
+ {
+ if (SLang_Error == 0) SLang_Error = SL_STACK_UNDERFLOW;
+ x->data_type = 0;
+ return -1;
+ }
+ y--;
+ *x = *y;
+
+ _SLStack_Pointer = y;
+ return 0;
+}
+
+static int pop_ctrl_integer (int *i)
+{
+ int type;
+ SLang_Class_Type *cl;
+#if _SLANG_OPTIMIZE_FOR_SPEED
+ register SLang_Object_Type *y;
+
+ /* Most of the time, either an integer or a char will be on the stack.
+ * Optimize these cases.
+ */
+ y = _SLStack_Pointer;
+ if (y == _SLRun_Stack)
+ {
+ if (SLang_Error == 0) SLang_Error = SL_STACK_UNDERFLOW;
+ return -1;
+ }
+ y--;
+
+ type = y->data_type;
+ if (type == SLANG_INT_TYPE)
+ {
+ _SLStack_Pointer = y;
+ *i = y->v.int_val;
+ return 0;
+ }
+ if (type == SLANG_CHAR_TYPE)
+ {
+ _SLStack_Pointer = y;
+ *i = y->v.char_val;
+ return 0;
+ }
+#else
+ if (-1 == (type = SLang_peek_at_stack ()))
+ return -1;
+#endif
+
+ cl = _SLclass_get_class ((unsigned char) type);
+ if (cl->cl_to_bool == NULL)
+ {
+ SLang_verror (SL_TYPE_MISMATCH,
+ "%s cannot be used in a boolean context",
+ cl->cl_name);
+ return -1;
+ }
+ return cl->cl_to_bool ((unsigned char) type, i);
+}
+
+_INLINE_
+int SLang_peek_at_stack (void)
+{
+ if (_SLStack_Pointer == _SLRun_Stack)
+ {
+ if (SLang_Error == 0)
+ SLang_Error = SL_STACK_UNDERFLOW;
+ return -1;
+ }
+
+ return (_SLStack_Pointer - 1)->data_type;
+}
+
+int SLang_peek_at_stack1 (void)
+{
+ int type;
+
+ type = SLang_peek_at_stack ();
+ if (type == SLANG_ARRAY_TYPE)
+ type = (_SLStack_Pointer - 1)->v.array_val->data_type;
+
+ return type;
+}
+
+_INLINE_
+void SLang_free_object (SLang_Object_Type *obj)
+{
+ unsigned char data_type;
+ SLang_Class_Type *cl;
+
+ if (obj == NULL) return;
+ data_type = obj->data_type;
+#if _SLANG_OPTIMIZE_FOR_SPEED
+ if (SLANG_CLASS_TYPE_SCALAR == _SLclass_Class_Type [data_type])
+ return;
+ if (data_type == SLANG_STRING_TYPE)
+ {
+ SLang_free_slstring (obj->v.s_val);
+ return;
+ }
+#endif
+ cl = _SLclass_get_class (data_type);
+#if !_SLANG_OPTIMIZE_FOR_SPEED
+ if (cl->cl_class_type != SLANG_CLASS_TYPE_SCALAR)
+#endif
+ (*cl->cl_destroy) (data_type, (VOID_STAR) &obj->v);
+}
+
+_INLINE_
+int SLang_push (SLang_Object_Type *x)
+{
+ register SLang_Object_Type *y;
+ y = _SLStack_Pointer;
+
+ /* if there is a SLang_Error, probably not much harm will be done
+ if it is ignored here */
+ /* if (SLang_Error) return; */
+
+ /* flag it now */
+ if (y >= _SLStack_Pointer_Max)
+ {
+ if (!SLang_Error) SLang_Error = SL_STACK_OVERFLOW;
+ return -1;
+ }
+
+ *y = *x;
+ _SLStack_Pointer = y + 1;
+ return 0;
+}
+
+/* _INLINE_ */
+int SLclass_push_ptr_obj (unsigned char type, VOID_STAR pval)
+{
+ register SLang_Object_Type *y;
+ y = _SLStack_Pointer;
+
+ if (y >= _SLStack_Pointer_Max)
+ {
+ if (!SLang_Error) SLang_Error = SL_STACK_OVERFLOW;
+ return -1;
+ }
+
+ y->data_type = type;
+ y->v.ptr_val = pval;
+
+ _SLStack_Pointer = y + 1;
+ return 0;
+}
+
+_INLINE_
+int SLclass_push_int_obj (unsigned char type, int x)
+{
+ register SLang_Object_Type *y;
+ y = _SLStack_Pointer;
+
+ if (y >= _SLStack_Pointer_Max)
+ {
+ if (!SLang_Error) SLang_Error = SL_STACK_OVERFLOW;
+ return -1;
+ }
+
+ y->data_type = type;
+ y->v.int_val = x;
+
+ _SLStack_Pointer = y + 1;
+ return 0;
+}
+
+_INLINE_
+int _SLang_pop_object_of_type (unsigned char type, SLang_Object_Type *obj,
+ int allow_arrays)
+{
+ register SLang_Object_Type *y;
+
+ y = _SLStack_Pointer;
+ if (y == _SLRun_Stack)
+ return SLang_pop (obj);
+ y--;
+ if (y->data_type != type)
+ {
+#if _SLANG_OPTIMIZE_FOR_SPEED
+ /* This is an implicit typecast. We do not want to typecast
+ * floats to ints implicitly.
+ */
+ if (_SLarith_Is_Arith_Type [type]
+ && _SLarith_Is_Arith_Type [y->data_type]
+ && (_SLarith_Is_Arith_Type [type] >= _SLarith_Is_Arith_Type[y->data_type]))
+ {
+ /* This should not fail */
+ (void) _SLarith_typecast (y->data_type, (VOID_STAR)&y->v, 1,
+ type, (VOID_STAR)&obj->v);
+ obj->data_type = type;
+ _SLStack_Pointer = y;
+ return 0;
+ }
+#endif
+
+ if ((allow_arrays == 0)
+ || (y->data_type != SLANG_ARRAY_TYPE)
+ || (y->v.array_val->data_type != type))
+ if (-1 == SLclass_typecast (type, 1, 0))
+ return -1;
+ }
+ *obj = *y;
+ _SLStack_Pointer = y;
+ return 0;
+}
+
+/* This function reverses the top n items on the stack and returns a
+ * an offset from the start of the stack to the last item.
+ */
+int SLreverse_stack (int n)
+{
+ SLang_Object_Type *otop, *obot, tmp;
+
+ otop = _SLStack_Pointer;
+ if ((n > otop - _SLRun_Stack) || (n < 0))
+ {
+ SLang_Error = SL_STACK_UNDERFLOW;
+ return -1;
+ }
+ obot = otop - n;
+ otop--;
+ while (otop > obot)
+ {
+ tmp = *obot;
+ *obot = *otop;
+ *otop = tmp;
+ otop--;
+ obot++;
+ }
+ return (int) ((_SLStack_Pointer - n) - _SLRun_Stack);
+}
+
+_INLINE_
+int SLroll_stack (int np)
+{
+ int n, i;
+ SLang_Object_Type *otop, *obot, tmp;
+
+ if ((n = abs(np)) <= 1) return 0; /* identity */
+
+ obot = otop = _SLStack_Pointer;
+ i = n;
+ while (i != 0)
+ {
+ if (obot <= _SLRun_Stack)
+ {
+ SLang_Error = SL_STACK_UNDERFLOW;
+ return -1;
+ }
+ obot--;
+ i--;
+ }
+ otop--;
+
+ if (np > 0)
+ {
+ /* Put top on bottom and roll rest up. */
+ tmp = *otop;
+ while (otop > obot)
+ {
+ *otop = *(otop - 1);
+ otop--;
+ }
+ *otop = tmp;
+ }
+ else
+ {
+ /* Put bottom on top and roll rest down. */
+ tmp = *obot;
+ while (obot < otop)
+ {
+ *obot = *(obot + 1);
+ obot++;
+ }
+ *obot = tmp;
+ }
+ return 0;
+}
+
+int _SLstack_depth (void)
+{
+ return (int) (_SLStack_Pointer - _SLRun_Stack);
+}
+
+int SLdup_n (int n)
+{
+ SLang_Object_Type *bot, *top;
+
+ if (n <= 0)
+ return 0;
+
+ top = _SLStack_Pointer;
+ if (top < _SLRun_Stack + n)
+ {
+ if (SLang_Error == 0)
+ SLang_Error = SL_STACK_UNDERFLOW;
+ return -1;
+ }
+ if (top + n > _SLStack_Pointer_Max)
+ {
+ if (SLang_Error == 0)
+ SLang_Error = SL_STACK_OVERFLOW;
+ return -1;
+ }
+ bot = top - n;
+
+ while (bot < top)
+ {
+ SLang_Class_Type *cl;
+ unsigned char data_type = bot->data_type;
+
+#if _SLANG_OPTIMIZE_FOR_SPEED
+ if (SLANG_CLASS_TYPE_SCALAR == _SLclass_Class_Type [data_type])
+ {
+ *_SLStack_Pointer++ = *bot++;
+ continue;
+ }
+#endif
+ cl = _SLclass_get_class (data_type);
+ if (-1 == (*cl->cl_push) (data_type, (VOID_STAR) &bot->v))
+ return -1;
+ bot++;
+ }
+ return 0;
+}
+
+/*}}}*/
+
+/*{{{ inner interpreter and support functions */
+
+_INLINE_
+int _SL_increment_frame_pointer (void)
+{
+ if (Recursion_Depth >= SLANG_MAX_RECURSIVE_DEPTH)
+ {
+ SLang_verror (SL_STACK_OVERFLOW, "Num Args Stack Overflow");
+ return -1;
+ }
+ Num_Args_Stack [Recursion_Depth] = SLang_Num_Function_Args;
+
+ SLang_Num_Function_Args = Next_Function_Num_Args;
+ Next_Function_Num_Args = 0;
+ Recursion_Depth++;
+ return 0;
+}
+
+_INLINE_
+int _SL_decrement_frame_pointer (void)
+{
+ if (Recursion_Depth == 0)
+ {
+ SLang_verror (SL_STACK_UNDERFLOW, "Num Args Stack Underflow");
+ return -1;
+ }
+
+ Recursion_Depth--;
+ if (Recursion_Depth < SLANG_MAX_RECURSIVE_DEPTH)
+ SLang_Num_Function_Args = Num_Args_Stack [Recursion_Depth];
+
+ return 0;
+}
+
+_INLINE_
+int SLang_start_arg_list (void)
+{
+ if (Frame_Pointer_Depth < SLANG_MAX_RECURSIVE_DEPTH)
+ {
+ Frame_Pointer_Stack [Frame_Pointer_Depth] = (unsigned int) (Frame_Pointer - _SLRun_Stack);
+ Frame_Pointer = _SLStack_Pointer;
+ Frame_Pointer_Depth++;
+ Next_Function_Num_Args = 0;
+ return 0;
+ }
+
+ SLang_verror (SL_STACK_OVERFLOW, "Frame Stack Overflow");
+ return -1;
+}
+
+_INLINE_
+int SLang_end_arg_list (void)
+{
+ if (Frame_Pointer_Depth == 0)
+ {
+ SLang_verror (SL_STACK_UNDERFLOW, "Frame Stack Underflow");
+ return -1;
+ }
+ Frame_Pointer_Depth--;
+ if (Frame_Pointer_Depth < SLANG_MAX_RECURSIVE_DEPTH)
+ {
+ Next_Function_Num_Args = (int) (_SLStack_Pointer - Frame_Pointer);
+ Frame_Pointer = _SLRun_Stack + Frame_Pointer_Stack [Frame_Pointer_Depth];
+ }
+ return 0;
+}
+
+_INLINE_
+static int do_bc_call_direct_frame (int (*f)(void))
+{
+ if ((0 == SLang_end_arg_list ())
+ && (0 == _SL_increment_frame_pointer ()))
+ {
+ (void) (*f) ();
+ _SL_decrement_frame_pointer ();
+ }
+ if (SLang_Error)
+ return -1;
+ return 0;
+}
+
+static int do_name_type_error (SLang_Name_Type *nt)
+{
+ char buf[256];
+ if (nt != NULL)
+ {
+ (void) _SLsnprintf (buf, sizeof (buf), "(Error occurred processing %s)", nt->name);
+ do_traceback (buf, 0, NULL);
+ }
+ return -1;
+}
+
+/* local and global variable assignments */
+
+static int do_binary_ab (int op, SLang_Object_Type *obja, SLang_Object_Type *objb)
+{
+ SLang_Class_Type *a_cl, *b_cl, *c_cl;
+ unsigned char b_data_type, a_data_type, c_data_type;
+ int (*binary_fun) (int,
+ unsigned char, VOID_STAR, unsigned int,
+ unsigned char, VOID_STAR, unsigned int,
+ VOID_STAR);
+ VOID_STAR pa;
+ VOID_STAR pb;
+ VOID_STAR pc;
+ int ret;
+
+ b_data_type = objb->data_type;
+ a_data_type = obja->data_type;
+
+#if _SLANG_OPTIMIZE_FOR_SPEED
+ if (_SLarith_Is_Arith_Type[a_data_type]
+ && _SLarith_Is_Arith_Type[b_data_type])
+ {
+ int status;
+ status = _SLarith_bin_op (obja, objb, op);
+ if (status != 1)
+ return status;
+ /* drop and try it the hard way */
+ }
+#endif
+
+ a_cl = _SLclass_get_class (a_data_type);
+ if (a_data_type == b_data_type)
+ b_cl = a_cl;
+ else
+ b_cl = _SLclass_get_class (b_data_type);
+
+ if (NULL == (binary_fun = _SLclass_get_binary_fun (op, a_cl, b_cl, &c_cl, 1)))
+ return -1;
+
+ c_data_type = c_cl->cl_data_type;
+
+#if _SLANG_OPTIMIZE_FOR_SPEED
+ if (SLANG_CLASS_TYPE_SCALAR == _SLclass_Class_Type [a_data_type])
+ pa = (VOID_STAR) &obja->v;
+ else
+#endif
+ pa = _SLclass_get_ptr_to_value (a_cl, obja);
+
+#if _SLANG_OPTIMIZE_FOR_SPEED
+ if (SLANG_CLASS_TYPE_SCALAR == _SLclass_Class_Type [b_data_type])
+ pb = (VOID_STAR) &objb->v;
+ else
+#endif
+ pb = _SLclass_get_ptr_to_value (b_cl, objb);
+
+ pc = c_cl->cl_transfer_buf;
+
+ if (1 != (*binary_fun) (op,
+ a_data_type, pa, 1,
+ b_data_type, pb, 1,
+ pc))
+ {
+ SLang_verror (SL_NOT_IMPLEMENTED,
+ "Binary operation between %s and %s failed",
+ a_cl->cl_name, b_cl->cl_name);
+
+ return -1;
+ }
+
+ /* apush will create a copy, so make sure we free after the push */
+ ret = (*c_cl->cl_apush)(c_data_type, pc);
+#if _SLANG_OPTIMIZE_FOR_SPEED
+ if (SLANG_CLASS_TYPE_SCALAR != _SLclass_Class_Type [c_data_type])
+#endif
+ (*c_cl->cl_adestroy)(c_data_type, pc);
+
+ return ret;
+}
+
+_INLINE_
+static void do_binary (int op)
+{
+ SLang_Object_Type obja, objb;
+
+ if (SLang_pop (&objb)) return;
+ if (0 == SLang_pop (&obja))
+ {
+ (void) do_binary_ab (op, &obja, &objb);
+#if _SLANG_OPTIMIZE_FOR_SPEED
+ if (SLANG_CLASS_TYPE_SCALAR != _SLclass_Class_Type [obja.data_type])
+#endif
+ SLang_free_object (&obja);
+ }
+#if _SLANG_OPTIMIZE_FOR_SPEED
+ if (SLANG_CLASS_TYPE_SCALAR != _SLclass_Class_Type [objb.data_type])
+#endif
+ SLang_free_object (&objb);
+}
+
+static int do_unary_op (int op, SLang_Object_Type *obj, int unary_type)
+{
+ int (*f) (int, unsigned char, VOID_STAR, unsigned int, VOID_STAR);
+ VOID_STAR pa;
+ VOID_STAR pb;
+ SLang_Class_Type *a_cl, *b_cl;
+ unsigned char a_type, b_type;
+ int ret;
+
+ a_type = obj->data_type;
+ a_cl = _SLclass_get_class (a_type);
+
+ if (NULL == (f = _SLclass_get_unary_fun (op, a_cl, &b_cl, unary_type)))
+ return -1;
+
+ b_type = b_cl->cl_data_type;
+
+#if _SLANG_OPTIMIZE_FOR_SPEED
+ if (SLANG_CLASS_TYPE_SCALAR == _SLclass_Class_Type [a_type])
+ pa = (VOID_STAR) &obj->v;
+ else
+#endif
+ pa = _SLclass_get_ptr_to_value (a_cl, obj);
+
+ pb = b_cl->cl_transfer_buf;
+
+ if (1 != (*f) (op, a_type, pa, 1, pb))
+ {
+ SLang_verror (SL_NOT_IMPLEMENTED,
+ "Unary operation for %s failed", a_cl->cl_name);
+ return -1;
+ }
+
+ ret = (*b_cl->cl_apush)(b_type, pb);
+ /* cl_apush creates a copy, so make sure we call cl_adestroy */
+#if _SLANG_OPTIMIZE_FOR_SPEED
+ if (SLANG_CLASS_TYPE_SCALAR != _SLclass_Class_Type [b_type])
+#endif
+ (*b_cl->cl_adestroy)(b_type, pb);
+
+ return ret;
+}
+
+_INLINE_
+static int do_unary (int op, int unary_type)
+{
+ SLang_Object_Type obj;
+ int ret;
+
+ if (-1 == SLang_pop (&obj)) return -1;
+ ret = do_unary_op (op, &obj, unary_type);
+#if _SLANG_OPTIMIZE_FOR_SPEED
+ if (SLANG_CLASS_TYPE_SCALAR != _SLclass_Class_Type [obj.data_type])
+#endif
+ SLang_free_object (&obj);
+ return ret;
+}
+
+static int do_assignment_binary (int op, SLang_Object_Type *obja_ptr)
+{
+ SLang_Object_Type objb;
+ int ret;
+
+ if (SLang_pop (&objb))
+ return -1;
+
+ ret = do_binary_ab (op, obja_ptr, &objb);
+#if _SLANG_OPTIMIZE_FOR_SPEED
+ if (SLANG_CLASS_TYPE_SCALAR != _SLclass_Class_Type [objb.data_type])
+#endif
+ SLang_free_object (&objb);
+ return ret;
+}
+
+/* The order of these is assumed to match the binary operators
+ * defined in slang.h
+ */
+static int
+map_assignment_op_to_binary (unsigned char op_type, int *op, int *is_unary)
+{
+ *is_unary = 0;
+ switch (op_type)
+ {
+ case _SLANG_BCST_PLUSEQS:
+ case _SLANG_BCST_MINUSEQS:
+ case _SLANG_BCST_TIMESEQS:
+ case _SLANG_BCST_DIVEQS:
+ *op = SLANG_PLUS + (op_type - _SLANG_BCST_PLUSEQS);
+ break;
+
+ case _SLANG_BCST_BOREQS:
+ *op = SLANG_BOR;
+ break;
+
+ case _SLANG_BCST_BANDEQS:
+ *op = SLANG_BAND;
+ break;
+
+ case _SLANG_BCST_POST_MINUSMINUS:
+ case _SLANG_BCST_MINUSMINUS:
+ *op = SLANG_MINUS;
+ *is_unary = 1;
+ break;
+
+ case _SLANG_BCST_PLUSPLUS:
+ case _SLANG_BCST_POST_PLUSPLUS:
+ *op = SLANG_PLUS;
+ *is_unary = 1;
+ break;
+
+ default:
+ SLang_verror (SL_NOT_IMPLEMENTED, "Assignment operator not implemented");
+ return -1;
+ }
+ return 0;
+}
+
+static int
+perform_lvalue_operation (unsigned char op_type, SLang_Object_Type *obja_ptr)
+{
+ switch (op_type)
+ {
+ case _SLANG_BCST_ASSIGN:
+ break;
+
+ /* The order of these is assumed to match the binary operators
+ * defined in slang.h
+ */
+ case _SLANG_BCST_PLUSEQS:
+ case _SLANG_BCST_MINUSEQS:
+ case _SLANG_BCST_TIMESEQS:
+ case _SLANG_BCST_DIVEQS:
+ if (-1 == do_assignment_binary (SLANG_PLUS + (op_type - _SLANG_BCST_PLUSEQS), obja_ptr))
+ return -1;
+ break;
+
+ case _SLANG_BCST_BOREQS:
+ if (-1 == do_assignment_binary (SLANG_BOR, obja_ptr))
+ return -1;
+ break;
+
+ case _SLANG_BCST_BANDEQS:
+ if (-1 == do_assignment_binary (SLANG_BAND, obja_ptr))
+ return -1;
+ break;
+
+ case _SLANG_BCST_PLUSPLUS:
+ case _SLANG_BCST_POST_PLUSPLUS:
+#if _SLANG_OPTIMIZE_FOR_SPEED
+ if (obja_ptr->data_type == SLANG_INT_TYPE)
+ return SLclass_push_int_obj (SLANG_INT_TYPE, obja_ptr->v.int_val + 1);
+#endif
+ if (-1 == do_unary_op (SLANG_PLUSPLUS, obja_ptr, _SLANG_BC_UNARY))
+ return -1;
+ break;
+
+ case _SLANG_BCST_MINUSMINUS:
+ case _SLANG_BCST_POST_MINUSMINUS:
+#if _SLANG_OPTIMIZE_FOR_SPEED
+ if (obja_ptr->data_type == SLANG_INT_TYPE)
+ return SLclass_push_int_obj (SLANG_INT_TYPE, obja_ptr->v.int_val - 1);
+#endif
+ if (-1 == do_unary_op (SLANG_MINUSMINUS, obja_ptr, _SLANG_BC_UNARY))
+ return -1;
+ break;
+
+ default:
+ SLang_Error = SL_INTERNAL_ERROR;
+ return -1;
+ }
+ return 0;
+}
+
+_INLINE_
+static int
+set_lvalue_obj (unsigned char op_type, SLang_Object_Type *obja_ptr)
+{
+ if (op_type != _SLANG_BCST_ASSIGN)
+ {
+ if (-1 == perform_lvalue_operation (op_type, obja_ptr))
+ return -1;
+ }
+#if _SLANG_OPTIMIZE_FOR_SPEED
+ if (SLANG_CLASS_TYPE_SCALAR != _SLclass_Class_Type [obja_ptr->data_type])
+#endif
+ SLang_free_object (obja_ptr);
+
+ return SLang_pop(obja_ptr);
+}
+
+static int
+set_struct_lvalue (SLBlock_Type *bc_blk)
+{
+ int type;
+ SLang_Class_Type *cl;
+ char *name;
+ int op;
+
+ if (-1 == (type = SLang_peek_at_stack ()))
+ return -1;
+
+ cl = _SLclass_get_class (type);
+ if ((cl->cl_sput == NULL)
+ || (cl->cl_sget == NULL))
+ {
+ SLang_verror (SL_NOT_IMPLEMENTED,
+ "%s does not support structure access",
+ cl->cl_name);
+ SLdo_pop_n (2); /* object plus what was to be assigned */
+ return -1;
+ }
+ name = bc_blk->b.s_blk;
+ op = bc_blk->bc_sub_type;
+
+ if (op != _SLANG_BCST_ASSIGN)
+ {
+ /* We have something like (A.x += b) or (A.x++). In either case,
+ * we need A.x.
+ */
+ SLang_Object_Type obj_A;
+ SLang_Object_Type obj;
+
+ if (-1 == SLang_pop (&obj_A))
+ return -1;
+
+ if ((-1 == _SLpush_slang_obj (&obj_A))
+ || (-1 == cl->cl_sget ((unsigned char) type, name))
+ || (-1 == SLang_pop (&obj)))
+ {
+ SLang_free_object (&obj_A);
+ return -1;
+ }
+ /* Now the value of A.x is in obj. */
+ if (-1 == perform_lvalue_operation (op, &obj))
+ {
+ SLang_free_object (&obj);
+ SLang_free_object (&obj_A);
+ return -1;
+ }
+ SLang_free_object (&obj);
+ /* The result of the operation is now on the stack.
+ * Perform assignment */
+ if (-1 == SLang_push (&obj_A))
+ {
+ SLang_free_object (&obj_A);
+ return -1;
+ }
+ }
+
+ return (*cl->cl_sput) ((unsigned char) type, name);
+}
+
+static int make_unit_object (SLang_Object_Type *a, SLang_Object_Type *u)
+{
+ unsigned char type;
+
+ type = a->data_type;
+ if (type == SLANG_ARRAY_TYPE)
+ type = a->v.array_val->data_type;
+
+ u->data_type = type;
+ switch (type)
+ {
+ case SLANG_UCHAR_TYPE:
+ case SLANG_CHAR_TYPE:
+ u->v.char_val = 1;
+ break;
+
+ case SLANG_SHORT_TYPE:
+ case SLANG_USHORT_TYPE:
+ u->v.short_val = 1;
+ break;
+
+ case SLANG_LONG_TYPE:
+ case SLANG_ULONG_TYPE:
+ u->v.long_val = 1;
+ break;
+
+#if SLANG_HAS_FLOAT
+ case SLANG_FLOAT_TYPE:
+ u->v.float_val = 1;
+ break;
+
+ case SLANG_COMPLEX_TYPE:
+ u->data_type = SLANG_DOUBLE_TYPE;
+ case SLANG_DOUBLE_TYPE:
+ u->v.double_val = 1;
+ break;
+#endif
+ default:
+ u->data_type = SLANG_INT_TYPE;
+ u->v.int_val = 1;
+ }
+ return 0;
+}
+
+
+/* We want to convert 'A[i] op X' to 'A[i] = A[i] op X'. The code that
+ * has been generated is: X __args i A __aput-op
+ * where __aput-op represents this function. We need to generate:
+ * __args i A __eargs __aget X op __args i A __eargs __aput
+ * Here, __eargs implies a call to do_bc_call_direct_frame with either
+ * the aput or aget function. In addition, __args represents a call to
+ * SLang_start_arg_list. Of course, i represents a set of indices.
+ *
+ * Note: If op is an unary operation (e.g., ++ or --), then X will not
+ * b present an will have to be taken to be 1.
+ *
+ * Implementation note: For efficiency, calls to setup the frame, start
+ * arg list will be omitted and SLang_Num_Function_Args will be set.
+ * This is ugly but the alternative is much less efficient rendering these
+ * assignment operators useless. So, the plan is to roll the stack to get X,
+ * then duplicate the next N values, call __aget followed by op X, finally
+ * calling __aput. Hence, the sequence is:
+ *
+ * start: X i .. j A
+ * dupN: X i .. j A i .. j A
+ * __aget: X i .. j A Y
+ * roll: i .. j A Y X
+ * op: i .. j A Z
+ * roll: Z i .. j A
+ * __aput:
+ */
+static int
+set_array_lvalue (int op)
+{
+ SLang_Object_Type x, y;
+ int num_args, is_unary;
+
+ if (-1 == map_assignment_op_to_binary (op, &op, &is_unary))
+ return -1;
+
+ /* Grab the indices and the array. Do not start a new frame. */
+ if (-1 == SLang_end_arg_list ())
+ return -1;
+ num_args = Next_Function_Num_Args;
+ Next_Function_Num_Args = 0;
+
+ if (-1 == SLdup_n (num_args))
+ return -1;
+
+ SLang_Num_Function_Args = num_args;
+ if (-1 == _SLarray_aget ())
+ return -1;
+
+ if (-1 == SLang_pop (&y))
+ return -1;
+
+ if (is_unary == 0)
+ {
+ if ((-1 == SLroll_stack (-(num_args + 1)))
+ || (-1 == SLang_pop (&x)))
+ {
+ SLang_free_object (&y);
+ return -1;
+ }
+ }
+ else if (-1 == make_unit_object (&y, &x))
+ {
+ SLang_free_object (&y);
+ return -1;
+ }
+
+ if (-1 == do_binary_ab (op, &y, &x))
+ {
+ SLang_free_object (&y);
+ SLang_free_object (&x);
+ return -1;
+ }
+#if _SLANG_OPTIMIZE_FOR_SPEED
+ if (SLANG_CLASS_TYPE_SCALAR != _SLclass_Class_Type [y.data_type])
+#endif
+ SLang_free_object (&y);
+
+#if _SLANG_OPTIMIZE_FOR_SPEED
+ if (SLANG_CLASS_TYPE_SCALAR != _SLclass_Class_Type [x.data_type])
+#endif
+ SLang_free_object (&x);
+
+ if (-1 == SLroll_stack (num_args + 1))
+ return -1;
+
+ SLang_Num_Function_Args = num_args;
+ return _SLarray_aput ();
+}
+
+
+static int
+set_intrin_lvalue (SLBlock_Type *bc_blk)
+{
+ unsigned char op_type;
+ SLang_Object_Type obja;
+ SLang_Class_Type *cl;
+ SLang_Intrin_Var_Type *ivar;
+ VOID_STAR intrinsic_addr;
+ unsigned char intrinsic_type;
+
+ ivar = bc_blk->b.nt_ivar_blk;
+
+ intrinsic_type = ivar->type;
+ intrinsic_addr = ivar->addr;
+
+ op_type = bc_blk->bc_sub_type;
+
+ cl = _SLclass_get_class (intrinsic_type);
+
+ if (op_type != _SLANG_BCST_ASSIGN)
+ {
+ /* We want to get the current value into obja. This is the
+ * easiest way.
+ */
+ if ((-1 == (*cl->cl_push) (intrinsic_type, intrinsic_addr))
+ || (-1 == SLang_pop (&obja)))
+ return -1;
+
+ (void) perform_lvalue_operation (op_type, &obja);
+ SLang_free_object (&obja);
+
+ if (SLang_Error)
+ return -1;
+ }
+
+ return (*cl->cl_pop) (intrinsic_type, intrinsic_addr);
+}
+
+int _SLang_deref_assign (SLang_Ref_Type *ref)
+{
+ SLang_Object_Type *objp;
+ SLang_Name_Type *nt;
+ SLBlock_Type blk;
+
+ if (ref->is_global == 0)
+ {
+ objp = ref->v.local_obj;
+ if (objp > Local_Variable_Frame)
+ {
+ SLang_verror (SL_UNDEFINED_NAME, "Local variable reference is out of scope");
+ return -1;
+ }
+ return set_lvalue_obj (_SLANG_BCST_ASSIGN, objp);
+ }
+
+ nt = ref->v.nt;
+ switch (nt->name_type)
+ {
+ case SLANG_GVARIABLE:
+ case SLANG_PVARIABLE:
+ if (-1 == set_lvalue_obj (_SLANG_BCST_ASSIGN,
+ &((SLang_Global_Var_Type *)nt)->obj))
+ {
+ do_name_type_error (nt);
+ return -1;
+ }
+ break;
+
+ case SLANG_IVARIABLE:
+ blk.b.nt_blk = nt;
+ blk.bc_sub_type = _SLANG_BCST_ASSIGN;
+ if (-1 == set_intrin_lvalue (&blk))
+ {
+ do_name_type_error (nt);
+ return -1;
+ }
+ break;
+
+ case SLANG_LVARIABLE:
+ SLang_Error = SL_INTERNAL_ERROR;
+ /* set_intrin_lvalue (&blk); */
+ return -1;
+
+ case SLANG_RVARIABLE:
+ default:
+ SLang_verror (SL_READONLY_ERROR, "deref assignment to %s not allowed", nt->name);
+ return -1;
+ }
+
+ return 0;
+}
+
+static void set_deref_lvalue (SLBlock_Type *bc_blk)
+{
+ SLang_Object_Type *objp;
+ SLang_Ref_Type *ref;
+
+ switch (bc_blk->bc_sub_type)
+ {
+ case SLANG_LVARIABLE:
+ objp = (Local_Variable_Frame - bc_blk->b.i_blk);
+ break;
+ case SLANG_GVARIABLE:
+ case SLANG_PVARIABLE:
+ objp = &bc_blk->b.nt_gvar_blk->obj;
+ break;
+ default:
+ SLang_Error = SL_INTERNAL_ERROR;
+ return;
+ }
+
+ if (-1 == _SLpush_slang_obj (objp))
+ return;
+
+ if (-1 == SLang_pop_ref (&ref))
+ return;
+ (void) _SLang_deref_assign (ref);
+ SLang_free_ref (ref);
+}
+
+static int push_struct_field (char *name)
+{
+ int type;
+ SLang_Class_Type *cl;
+
+ if (-1 == (type = SLang_peek_at_stack ()))
+ return -1;
+
+ cl = _SLclass_get_class ((unsigned char) type);
+ if (cl->cl_sget == NULL)
+ {
+ SLang_verror (SL_NOT_IMPLEMENTED,
+ "%s does not permit structure access",
+ cl->cl_name);
+ SLdo_pop_n (2);
+ return -1;
+ }
+
+ return (*cl->cl_sget) ((unsigned char) type, name);
+}
+
+static void trace_dump (char *format, char *name, SLang_Object_Type *objs, int n, int dir)
+{
+ unsigned int len;
+ char prefix [52];
+
+ len = Trace_Mode - 1;
+ if (len + 2 >= sizeof (prefix))
+ len = sizeof (prefix) - 2;
+
+ SLMEMSET (prefix, ' ', len);
+ prefix[len] = 0;
+
+ call_dump_routine (prefix);
+ call_dump_routine (format, name, n);
+
+ if (n > 0)
+ {
+ prefix[len] = ' ';
+ len++;
+ prefix[len] = 0;
+
+ _SLdump_objects (prefix, objs, n, dir);
+ }
+}
+
+/* Pop a data item from the stack and return a pointer to it.
+ * Strings are not freed from stack so use another routine to do it.
+ */
+static VOID_STAR pop_pointer (SLang_Object_Type *obj, unsigned char type)
+{
+#ifndef _SLANG_OPTIMIZE_FOR_SPEED
+ SLang_Class_Type *cl;
+#endif
+
+ SLang_Array_Type *at;
+
+ /* Arrays are special. Allow scalars to automatically convert to arrays.
+ */
+ if (type == SLANG_ARRAY_TYPE)
+ {
+ if (-1 == SLang_pop_array (&at, 1))
+ return NULL;
+ obj->data_type = SLANG_ARRAY_TYPE;
+ return obj->v.ptr_val = (VOID_STAR) at;
+ }
+
+ if (type == 0)
+ {
+ /* This happens when an intrinsic is declared without any information
+ * regarding parameter types.
+ */
+ if (-1 == SLang_pop (obj))
+ return NULL;
+ type = obj->data_type;
+ }
+ else if (-1 == _SLang_pop_object_of_type (type, obj, 0))
+ return NULL;
+
+#if _SLANG_OPTIMIZE_FOR_SPEED
+ type = _SLclass_Class_Type [type];
+#else
+ type = _SLclass_get_class (type)->cl_class_type;
+#endif
+
+ if (type == SLANG_CLASS_TYPE_SCALAR)
+ return (VOID_STAR) &obj->v;
+ else if (type == SLANG_CLASS_TYPE_MMT)
+ return SLang_object_from_mmt (obj->v.ref);
+ else
+ return obj->v.ptr_val;
+}
+
+/* This is ugly. Does anyone have a advice for a cleaner way of doing
+ * this??
+ */
+typedef void (*VF0_Type)(void);
+typedef void (*VF1_Type)(VOID_STAR);
+typedef void (*VF2_Type)(VOID_STAR, VOID_STAR);
+typedef void (*VF3_Type)(VOID_STAR, VOID_STAR, VOID_STAR);
+typedef void (*VF4_Type)(VOID_STAR, VOID_STAR, VOID_STAR, VOID_STAR);
+typedef void (*VF5_Type)(VOID_STAR, VOID_STAR, VOID_STAR, VOID_STAR, VOID_STAR);
+typedef void (*VF6_Type)(VOID_STAR, VOID_STAR, VOID_STAR, VOID_STAR, VOID_STAR, VOID_STAR);
+typedef void (*VF7_Type)(VOID_STAR, VOID_STAR, VOID_STAR, VOID_STAR, VOID_STAR, VOID_STAR, VOID_STAR);
+typedef long (*LF0_Type)(void);
+typedef long (*LF1_Type)(VOID_STAR);
+typedef long (*LF2_Type)(VOID_STAR, VOID_STAR);
+typedef long (*LF3_Type)(VOID_STAR, VOID_STAR, VOID_STAR);
+typedef long (*LF4_Type)(VOID_STAR, VOID_STAR, VOID_STAR, VOID_STAR);
+typedef long (*LF5_Type)(VOID_STAR, VOID_STAR, VOID_STAR, VOID_STAR, VOID_STAR);
+typedef long (*LF6_Type)(VOID_STAR, VOID_STAR, VOID_STAR, VOID_STAR, VOID_STAR, VOID_STAR);
+typedef long (*LF7_Type)(VOID_STAR, VOID_STAR, VOID_STAR, VOID_STAR, VOID_STAR, VOID_STAR, VOID_STAR);
+#if SLANG_HAS_FLOAT
+typedef double (*FF0_Type)(void);
+typedef double (*FF1_Type)(VOID_STAR);
+typedef double (*FF2_Type)(VOID_STAR, VOID_STAR);
+typedef double (*FF3_Type)(VOID_STAR, VOID_STAR, VOID_STAR);
+typedef double (*FF4_Type)(VOID_STAR, VOID_STAR, VOID_STAR, VOID_STAR);
+typedef double (*FF5_Type)(VOID_STAR, VOID_STAR, VOID_STAR, VOID_STAR, VOID_STAR);
+typedef double (*FF6_Type)(VOID_STAR, VOID_STAR, VOID_STAR, VOID_STAR, VOID_STAR, VOID_STAR);
+typedef double (*FF7_Type)(VOID_STAR, VOID_STAR, VOID_STAR, VOID_STAR, VOID_STAR, VOID_STAR, VOID_STAR);
+#endif
+
+static int execute_intrinsic_fun (SLang_Intrin_Fun_Type *objf)
+{
+#if SLANG_HAS_FLOAT
+ double xf;
+#endif
+ VOID_STAR p[SLANG_MAX_INTRIN_ARGS];
+ SLang_Object_Type objs[SLANG_MAX_INTRIN_ARGS];
+ long ret;
+ unsigned char type;
+ unsigned int argc;
+ unsigned int i;
+ FVOID_STAR fptr;
+ unsigned char *arg_types;
+ int stk_depth;
+
+ fptr = objf->i_fun;
+ argc = objf->num_args;
+ type = objf->return_type;
+ arg_types = objf->arg_types;
+
+ if (argc > SLANG_MAX_INTRIN_ARGS)
+ {
+ SLang_verror(SL_APPLICATION_ERROR,
+ "Intrinsic function %s requires too many parameters", objf->name);
+ return -1;
+ }
+
+ if (-1 == _SL_increment_frame_pointer ())
+ return -1;
+
+ stk_depth = -1;
+ if (Trace_Mode && (_SLang_Trace > 0))
+ {
+ int nargs;
+
+ stk_depth = _SLstack_depth ();
+
+ nargs = SLang_Num_Function_Args;
+ if (nargs == 0)
+ nargs = (int)argc;
+
+ stk_depth -= nargs;
+
+ if (stk_depth >= 0)
+ trace_dump (">>%s (%d args)\n",
+ objf->name,
+ _SLStack_Pointer - nargs,
+ nargs,
+ 1);
+ }
+
+ i = argc;
+ while (i != 0)
+ {
+ i--;
+ if (NULL == (p[i] = pop_pointer (objs + i, arg_types[i])))
+ {
+ i++;
+ goto free_and_return;
+ }
+ }
+
+ ret = 0;
+#if SLANG_HAS_FLOAT
+ xf = 0.0;
+#endif
+
+ switch (argc)
+ {
+ case 0:
+ if (type == SLANG_VOID_TYPE) ((VF0_Type) fptr) ();
+#if SLANG_HAS_FLOAT
+ else if (type == SLANG_DOUBLE_TYPE) xf = ((FF0_Type) fptr)();
+#endif
+ else ret = ((LF0_Type) fptr)();
+ break;
+
+ case 1:
+ if (type == SLANG_VOID_TYPE) ((VF1_Type) fptr)(p[0]);
+#if SLANG_HAS_FLOAT
+ else if (type == SLANG_DOUBLE_TYPE) xf = ((FF1_Type) fptr)(p[0]);
+#endif
+ else ret = ((LF1_Type) fptr)(p[0]);
+ break;
+
+ case 2:
+ if (type == SLANG_VOID_TYPE) ((VF2_Type) fptr)(p[0], p[1]);
+#if SLANG_HAS_FLOAT
+ else if (type == SLANG_DOUBLE_TYPE) xf = ((FF2_Type) fptr)(p[0], p[1]);
+#endif
+ else ret = ((LF2_Type) fptr)(p[0], p[1]);
+ break;
+
+ case 3:
+ if (type == SLANG_VOID_TYPE) ((VF3_Type) fptr)(p[0], p[1], p[2]);
+#if SLANG_HAS_FLOAT
+ else if (type == SLANG_DOUBLE_TYPE) xf = ((FF3_Type) fptr)(p[0], p[1], p[2]);
+#endif
+ else ret = ((LF3_Type) fptr)(p[0], p[1], p[2]);
+ break;
+
+ case 4:
+ if (type == SLANG_VOID_TYPE) ((VF4_Type) fptr)(p[0], p[1], p[2], p[3]);
+#if SLANG_HAS_FLOAT
+ else if (type == SLANG_DOUBLE_TYPE) xf = ((FF4_Type) fptr)(p[0], p[1], p[2], p[3]);
+#endif
+ else ret = ((LF4_Type) fptr)(p[0], p[1], p[2], p[3]);
+ break;
+
+ case 5:
+ if (type == SLANG_VOID_TYPE) ((VF5_Type) fptr)(p[0], p[1], p[2], p[3], p[4]);
+#if SLANG_HAS_FLOAT
+ else if (type == SLANG_DOUBLE_TYPE) xf = ((FF5_Type) fptr)(p[0], p[1], p[2], p[3], p[4]);
+#endif
+ else ret = ((LF5_Type) fptr)(p[0], p[1], p[2], p[3], p[4]);
+ break;
+
+ case 6:
+ if (type == SLANG_VOID_TYPE) ((VF6_Type) fptr)(p[0], p[1], p[2], p[3], p[4], p[5]);
+#if SLANG_HAS_FLOAT
+ else if (type == SLANG_DOUBLE_TYPE) xf = ((FF6_Type) fptr)(p[0], p[1], p[2], p[3], p[4], p[5]);
+#endif
+ else ret = ((LF6_Type) fptr)(p[0], p[1], p[2], p[3], p[4], p[5]);
+ break;
+
+ case 7:
+ if (type == SLANG_VOID_TYPE) ((VF7_Type) fptr)(p[0], p[1], p[2], p[3], p[4], p[5], p[6]);
+#if SLANG_HAS_FLOAT
+ else if (type == SLANG_DOUBLE_TYPE) xf = ((FF7_Type) fptr)(p[0], p[1], p[2], p[3], p[4], p[5], p[6]);
+#endif
+ else ret = ((LF7_Type) fptr)(p[0], p[1], p[2], p[3], p[4], p[5], p[6]);
+ break;
+ }
+
+ switch (type)
+ {
+ case SLANG_VOID_TYPE:
+ break;
+
+#if SLANG_HAS_FLOAT
+ case SLANG_DOUBLE_TYPE:
+ (void) SLang_push_double (xf);
+ break;
+#endif
+ case SLANG_UINT_TYPE:
+ case SLANG_INT_TYPE: (void) SLclass_push_int_obj (type, (int) ret);
+ break;
+
+ case SLANG_CHAR_TYPE:
+ case SLANG_UCHAR_TYPE: (void) SLclass_push_char_obj (type, (char) ret);
+ break;
+
+ case SLANG_SHORT_TYPE:
+ case SLANG_USHORT_TYPE: (void) SLclass_push_short_obj (type, (short) ret);
+ break;
+
+ case SLANG_LONG_TYPE:
+ case SLANG_ULONG_TYPE: (void) SLclass_push_long_obj (type, ret);
+ break;
+
+ case SLANG_STRING_TYPE:
+ if (NULL == (char *)ret)
+ {
+ if (SLang_Error == 0) SLang_Error = SL_INTRINSIC_ERROR;
+ }
+ else (void) SLang_push_string ((char *)ret);
+ break;
+
+ default:
+ SLang_verror (SL_NOT_IMPLEMENTED,
+ "Support for intrinsic functions returning %s is not provided",
+ SLclass_get_datatype_name (type));
+ }
+
+ if (stk_depth >= 0)
+ {
+ stk_depth = _SLstack_depth () - stk_depth;
+
+ trace_dump ("<<%s (returning %d values)\n",
+ objf->name,
+ _SLStack_Pointer - stk_depth,
+ stk_depth,
+ 1);
+ }
+
+ free_and_return:
+ while (i < argc)
+ {
+ SLang_free_object (objs + i);
+ i++;
+ }
+
+ return _SL_decrement_frame_pointer ();
+}
+
+static int inner_interp(register SLBlock_Type *);
+
+/* Switch_Obj_Ptr points to the NEXT available free switch object */
+static SLang_Object_Type Switch_Objects[SLANG_MAX_NESTED_SWITCH];
+static SLang_Object_Type *Switch_Obj_Ptr = Switch_Objects;
+static SLang_Object_Type *Switch_Obj_Max = Switch_Objects + SLANG_MAX_NESTED_SWITCH;
+
+static void
+lang_do_loops (unsigned char stype, SLBlock_Type *block, unsigned int num_blocks)
+{
+ int i, ctrl;
+ int first, last;
+ SLBlock_Type *blks[4];
+ char *loop_name;
+ SLang_Foreach_Context_Type *foreach_context;
+ SLang_Class_Type *cl;
+ int type;
+ unsigned int j;
+
+ j = 0;
+ for (i = 0; i < (int) num_blocks; i++)
+ {
+ if (block[i].bc_main_type != _SLANG_BC_BLOCK)
+ {
+ if (block[i].bc_main_type == _SLANG_BC_LINE_NUM)
+ continue;
+
+ SLang_verror (SL_SYNTAX_ERROR, "Bytecode is not a looping block");
+ return;
+ }
+ blks[j] = block[i].b.blk;
+ j++;
+ }
+
+ num_blocks = j;
+ block = blks[0];
+
+ switch (stype)
+ {
+ case _SLANG_BCST_FOREACH:
+ loop_name = "foreach";
+ if (num_blocks != 1)
+ goto wrong_num_blocks_error;
+
+ /* We should find Next_Function_Num_Args + 1 items on the stack.
+ * The first Next_Function_Num_Args items represent the arguments to
+ * to USING. The last item (deepest in stack) is the object to loop
+ * over. So, roll the stack up and grab it.
+ */
+ if ((-1 == SLroll_stack (-(Next_Function_Num_Args + 1)))
+ || (-1 == (type = SLang_peek_at_stack ())))
+ goto return_error;
+
+ cl = _SLclass_get_class ((unsigned char) type);
+ if ((cl->cl_foreach == NULL)
+ || (cl->cl_foreach_open == NULL)
+ || (cl->cl_foreach_close == NULL))
+ {
+ SLang_verror (SL_NOT_IMPLEMENTED, "%s does not permit foreach", cl->cl_name);
+ SLdo_pop_n (Next_Function_Num_Args + 1);
+ goto return_error;
+ }
+
+ if (NULL == (foreach_context = (*cl->cl_foreach_open) ((unsigned char)type, Next_Function_Num_Args)))
+ goto return_error;
+
+ while (1)
+ {
+ int status;
+
+ if (SLang_Error)
+ {
+ (*cl->cl_foreach_close) ((unsigned char) type, foreach_context);
+ goto return_error;
+ }
+
+ status = (*cl->cl_foreach) ((unsigned char) type, foreach_context);
+ if (status <= 0)
+ {
+ if (status == 0)
+ break;
+
+ (*cl->cl_foreach_close) ((unsigned char) type, foreach_context);
+ goto return_error;
+ }
+
+ inner_interp (block);
+ if (Lang_Break) break;
+ Lang_Break_Condition = /* Lang_Continue = */ 0;
+ }
+ (*cl->cl_foreach_close) ((unsigned char) type, foreach_context);
+ break;
+
+ case _SLANG_BCST_WHILE:
+ loop_name = "while";
+
+ if (num_blocks != 2)
+ goto wrong_num_blocks_error;
+
+ type = blks[1]->bc_main_type;
+ while (1)
+ {
+ if (SLang_Error)
+ goto return_error;
+
+ inner_interp (block);
+ if (Lang_Break) break;
+
+ if (-1 == pop_ctrl_integer (&ctrl))
+ goto return_error;
+
+ if (ctrl == 0) break;
+
+ if (type)
+ {
+ inner_interp (blks[1]);
+ if (Lang_Break) break;
+ Lang_Break_Condition = /* Lang_Continue = */ 0;
+ }
+ }
+ break;
+
+ case _SLANG_BCST_DOWHILE:
+ loop_name = "do...while";
+
+ if (num_blocks != 2)
+ goto wrong_num_blocks_error;
+
+ while (1)
+ {
+ if (SLang_Error)
+ goto return_error;
+
+ Lang_Break_Condition = /* Lang_Continue = */ 0;
+ inner_interp (block);
+ if (Lang_Break) break;
+ Lang_Break_Condition = /* Lang_Continue = */ 0;
+ inner_interp (blks[1]);
+ if (-1 == pop_ctrl_integer (&ctrl))
+ goto return_error;
+
+ if (ctrl == 0) break;
+ }
+ break;
+
+ case _SLANG_BCST_CFOR:
+ loop_name = "for";
+
+ /* we need 4 blocks: first 3 control, the last is code */
+ if (num_blocks != 4) goto wrong_num_blocks_error;
+
+ inner_interp (block);
+ while (1)
+ {
+ if (SLang_Error)
+ goto return_error;
+
+ inner_interp(blks[1]); /* test */
+ if (-1 == pop_ctrl_integer (&ctrl))
+ goto return_error;
+
+ if (ctrl == 0) break;
+ inner_interp(blks[3]); /* code */
+ if (Lang_Break) break;
+ inner_interp(blks[2]); /* bump */
+ Lang_Break_Condition = /* Lang_Continue = */ 0;
+ }
+ break;
+
+ case _SLANG_BCST_FOR:
+ loop_name = "_for";
+
+ if (num_blocks != 1)
+ goto wrong_num_blocks_error;
+
+ /* 3 elements: first, last, step */
+ if ((-1 == SLang_pop_integer (&ctrl))
+ || (-1 == SLang_pop_integer (&last))
+ || (-1 == SLang_pop_integer (&first)))
+ goto return_error;
+
+ i = first;
+ while (1)
+ {
+ /* It is ugly to have this test here but I do not know of a
+ * simple way to do this without using two while loops.
+ */
+ if (ctrl >= 0)
+ {
+ if (i > last) break;
+ }
+ else if (i < last) break;
+
+ if (SLang_Error) goto return_error;
+
+ SLclass_push_int_obj (SLANG_INT_TYPE, i);
+ inner_interp (block);
+ if (Lang_Break) break;
+ Lang_Break_Condition = /* Lang_Continue = */ 0;
+
+ i += ctrl;
+ }
+ break;
+
+ case _SLANG_BCST_LOOP:
+ loop_name = "loop";
+ if (num_blocks != 1)
+ goto wrong_num_blocks_error;
+
+ if (-1 == SLang_pop_integer (&ctrl))
+ goto return_error;
+ while (ctrl > 0)
+ {
+ ctrl--;
+
+ if (SLang_Error)
+ goto return_error;
+
+ inner_interp (block);
+ if (Lang_Break) break;
+ Lang_Break_Condition = /* Lang_Continue = */ 0;
+ }
+ break;
+
+ case _SLANG_BCST_FOREVER:
+ loop_name = "forever";
+
+ if (num_blocks != 1)
+ goto wrong_num_blocks_error;
+
+ while (1)
+ {
+ if (SLang_Error)
+ goto return_error;
+
+ inner_interp (block);
+ if (Lang_Break) break;
+ Lang_Break_Condition = /* Lang_Continue = */ 0;
+ }
+ break;
+
+ default: SLang_verror(SL_INTERNAL_ERROR, "Unknown loop type");
+ return;
+ }
+ Lang_Break = /* Lang_Continue = */ 0;
+ Lang_Break_Condition = Lang_Return;
+ return;
+
+ wrong_num_blocks_error:
+ SLang_verror (SL_SYNTAX_ERROR, "Wrong number of blocks for '%s' construct", loop_name);
+
+ /* drop */
+ return_error:
+ do_traceback (loop_name, 0, NULL);
+}
+
+static void lang_do_and_orelse (unsigned char stype, SLBlock_Type *addr, SLBlock_Type *addr_max)
+{
+ int test = 0;
+ int is_or;
+
+ is_or = (stype == _SLANG_BCST_ORELSE);
+
+ while (addr <= addr_max)
+ {
+ if (addr->bc_main_type == _SLANG_BC_LINE_NUM)
+ {
+ addr++;
+ continue;
+ }
+
+ inner_interp (addr->b.blk);
+ if (SLang_Error
+ || Lang_Break_Condition
+ || (-1 == pop_ctrl_integer (&test)))
+ return;
+
+ if (is_or == (test != 0))
+ break;
+
+ /* if (((stype == _SLANG_BCST_ANDELSE) && (test == 0))
+ * || ((stype == _SLANG_BCST_ORELSE) && test))
+ * break;
+ */
+
+ addr++;
+ }
+ SLclass_push_int_obj (SLANG_INT_TYPE, test);
+}
+
+static void do_else_if (SLBlock_Type *zero_block, SLBlock_Type *non_zero_block)
+{
+ int test;
+
+ if (-1 == pop_ctrl_integer (&test))
+ return;
+
+ if (test == 0)
+ non_zero_block = zero_block;
+
+ if (non_zero_block != NULL)
+ inner_interp (non_zero_block->b.blk);
+}
+
+int _SLang_trace_fun (char *f)
+{
+ if (NULL == (f = SLang_create_slstring (f)))
+ return -1;
+
+ SLang_free_slstring (Trace_Function);
+ Trace_Function = f;
+ _SLang_Trace = 1;
+ return 0;
+}
+
+int _SLdump_objects (char *prefix, SLang_Object_Type *x, unsigned int n, int dir)
+{
+ char *s;
+ SLang_Class_Type *cl;
+
+ while (n)
+ {
+ cl = _SLclass_get_class (x->data_type);
+
+ if (NULL == (s = _SLstringize_object (x)))
+ s = "??";
+
+ call_dump_routine ("%s[%s]:%s\n", prefix, cl->cl_name, s);
+
+ SLang_free_slstring (s);
+
+ x += dir;
+ n--;
+ }
+ return 0;
+}
+
+static SLBlock_Type *Exit_Block_Ptr;
+static SLBlock_Type *Global_User_Block[5];
+static SLBlock_Type **User_Block_Ptr = Global_User_Block;
+char *_SLang_Current_Function_Name = NULL;
+
+static int execute_slang_fun (_SLang_Function_Type *fun)
+{
+ register unsigned int i;
+ register SLang_Object_Type *frame, *lvf;
+ register unsigned int n_locals;
+ _SLBlock_Header_Type *header;
+ /* SLBlock_Type *val; */
+ SLBlock_Type *exit_block_save;
+ SLBlock_Type **user_block_save;
+ SLBlock_Type *user_blocks[5];
+ char *save_fname;
+
+ exit_block_save = Exit_Block_Ptr;
+ user_block_save = User_Block_Ptr;
+ User_Block_Ptr = user_blocks;
+ *(user_blocks) = NULL;
+ *(user_blocks + 1) = NULL;
+ *(user_blocks + 2) = NULL;
+ *(user_blocks + 3) = NULL;
+ *(user_blocks + 4) = NULL;
+
+ Exit_Block_Ptr = NULL;
+
+ save_fname = _SLang_Current_Function_Name;
+ _SLang_Current_Function_Name = fun->name;
+
+ _SL_increment_frame_pointer ();
+
+ /* need loaded? */
+ if (fun->nlocals == AUTOLOAD_NUM_LOCALS)
+ {
+ header = NULL;
+ if (-1 == SLang_load_file(fun->v.autoload_filename))
+ goto the_return;
+
+ if (fun->nlocals == AUTOLOAD_NUM_LOCALS)
+ {
+ SLang_verror (SL_UNDEFINED_NAME, "%s: Function did not autoload",
+ _SLang_Current_Function_Name);
+ goto the_return;
+ }
+ }
+
+ n_locals = fun->nlocals;
+
+ /* let the error propagate through since it will do no harm
+ and allow us to restore stack. */
+
+ /* set new stack frame */
+ lvf = frame = Local_Variable_Frame;
+ i = n_locals;
+ if ((lvf + i) > Local_Variable_Stack + SLANG_MAX_LOCAL_STACK)
+ {
+ SLang_verror(SL_STACK_OVERFLOW, "%s: Local Variable Stack Overflow",
+ _SLang_Current_Function_Name);
+ goto the_return;
+ }
+
+ /* Make sure we do not allow this header to get destroyed by something
+ * like: define crash () { eval ("define crash ();") }
+ */
+ header = fun->v.header;
+ header->num_refs++;
+
+ while (i--)
+ {
+ lvf++;
+ lvf->data_type = SLANG_UNDEFINED_TYPE;
+ }
+ Local_Variable_Frame = lvf;
+
+ /* read values of function arguments */
+ i = fun->nargs;
+ while (i > 0)
+ {
+ i--;
+ (void) SLang_pop (Local_Variable_Frame - i);
+ }
+
+ if (SLang_Enter_Function != NULL) (*SLang_Enter_Function)(_SLang_Current_Function_Name);
+
+ if (_SLang_Trace)
+ {
+ int stack_depth;
+
+ stack_depth = _SLstack_depth ();
+
+ if ((Trace_Function != NULL)
+ && (0 == strcmp (Trace_Function, _SLang_Current_Function_Name))
+ && (Trace_Mode == 0))
+ Trace_Mode = 1;
+
+ if (Trace_Mode)
+ {
+ /* The local variable frame grows backwards */
+ trace_dump (">>%s (%d args)\n",
+ _SLang_Current_Function_Name,
+ Local_Variable_Frame,
+ (int) fun->nargs,
+ -1);
+ Trace_Mode++;
+ }
+
+ inner_interp (header->body);
+ Lang_Break_Condition = Lang_Return = Lang_Break = 0;
+ if (Exit_Block_Ptr != NULL) inner_interp(Exit_Block_Ptr);
+
+ if (Trace_Mode)
+ {
+ Trace_Mode--;
+ stack_depth = _SLstack_depth () - stack_depth;
+
+ trace_dump ("<<%s (returning %d values)\n",
+ _SLang_Current_Function_Name,
+ _SLStack_Pointer - stack_depth,
+ stack_depth,
+ 1);
+
+ if (Trace_Mode == 1)
+ Trace_Mode = 0;
+ }
+ }
+ else
+ {
+ inner_interp (header->body);
+ Lang_Break_Condition = Lang_Return = Lang_Break = 0;
+ if (Exit_Block_Ptr != NULL) inner_interp(Exit_Block_Ptr);
+ }
+
+ if (SLang_Exit_Function != NULL) (*SLang_Exit_Function)(_SLang_Current_Function_Name);
+
+ if (SLang_Error)
+ do_traceback(fun->name, n_locals,
+#if _SLANG_HAS_DEBUG_CODE
+ fun->file
+#else
+ NULL
+#endif
+ );
+
+ /* free local variables.... */
+ lvf = Local_Variable_Frame;
+ while (lvf > frame)
+ {
+#if _SLANG_OPTIMIZE_FOR_SPEED
+ if (SLANG_CLASS_TYPE_SCALAR != _SLclass_Class_Type [lvf->data_type])
+#endif
+ SLang_free_object (lvf);
+ lvf--;
+ }
+ Local_Variable_Frame = lvf;
+
+ if (header->num_refs == 1)
+ free_function_header (header);
+ else
+ header->num_refs--;
+
+ the_return:
+
+ Lang_Break_Condition = Lang_Return = Lang_Break = 0;
+ Exit_Block_Ptr = exit_block_save;
+ User_Block_Ptr = user_block_save;
+ _SLang_Current_Function_Name = save_fname;
+ _SL_decrement_frame_pointer ();
+
+ if (SLang_Error)
+ return -1;
+
+ return 0;
+}
+
+static void do_traceback (char *name, unsigned int locals, char *file)
+{
+ char *s;
+ unsigned int i;
+ SLang_Object_Type *objp;
+ unsigned short stype;
+
+ /* FIXME: Priority=low
+ * I need to make this configurable!!! That is, let the
+ * application decide whether or not a usage error should result in a
+ * traceback.
+ */
+ if (SLang_Error == SL_USAGE_ERROR)
+ return;
+
+ if (SLang_Traceback == 0)
+ return;
+
+ call_dump_routine ("S-Lang Traceback: %s\n", name);
+ if (SLang_Traceback < 0)
+ return;
+
+ if (file != NULL)
+ call_dump_routine ("File: %s\n", file);
+
+ if (locals == 0)
+ return;
+
+ call_dump_routine (" Local Variables:\n");
+
+ for (i = 0; i < locals; i++)
+ {
+ SLang_Class_Type *cl;
+ char *class_name;
+
+ objp = Local_Variable_Frame - i;
+ stype = objp->data_type;
+
+ s = _SLstringize_object (objp);
+ cl = _SLclass_get_class (stype);
+ class_name = cl->cl_name;
+
+ call_dump_routine ("\t$%d: Type: %s,\tValue:\t", i, class_name);
+
+ if (s == NULL) call_dump_routine("??\n");
+ else
+ {
+ char *q = "";
+#ifndef HAVE_VSNPRINTF
+ char buf[256];
+ if (strlen (s) >= sizeof (buf))
+ {
+ strncpy (buf, s, sizeof(buf));
+ s = buf;
+ s[sizeof(buf) - 1] = 0;
+ }
+#endif
+ if (SLANG_STRING_TYPE == stype) q = "\"";
+ call_dump_routine ("%s%s%s\n", q, s, q);
+ }
+ }
+}
+
+static void do_app_unary (SLang_App_Unary_Type *nt)
+{
+ if (-1 == do_unary (nt->unary_op, nt->name_type))
+ do_traceback (nt->name, 0, NULL);
+}
+
+static int inner_interp_nametype (SLang_Name_Type *nt)
+{
+ SLBlock_Type bc_blks[2];
+
+ bc_blks[0].b.nt_blk = nt;
+ bc_blks[0].bc_main_type = nt->name_type;
+ bc_blks[1].bc_main_type = 0;
+ return inner_interp(bc_blks);
+}
+
+int _SLang_dereference_ref (SLang_Ref_Type *ref)
+{
+ if (ref == NULL)
+ {
+ SLang_Error = SL_INTERNAL_ERROR;
+ return -1;
+ }
+
+ if (ref->is_global == 0)
+ {
+ SLang_Object_Type *obj = ref->v.local_obj;
+ if (obj > Local_Variable_Frame)
+ {
+ SLang_verror (SL_UNDEFINED_NAME, "Local variable deref is out of scope");
+ return -1;
+ }
+ return _SLpush_slang_obj (ref->v.local_obj);
+ }
+
+ (void) inner_interp_nametype (ref->v.nt);
+ return 0;
+}
+
+int _SLang_is_ref_initialized (SLang_Ref_Type *ref)
+{
+ unsigned char type;
+
+ if (ref == NULL)
+ {
+ SLang_Error = SL_INTERNAL_ERROR;
+ return -1;
+ }
+
+ if (ref->is_global == 0)
+ {
+ SLang_Object_Type *obj = ref->v.local_obj;
+ if (obj > Local_Variable_Frame)
+ {
+ SLang_verror (SL_UNDEFINED_NAME, "Local variable deref is out of scope");
+ return -1;
+ }
+ type = ref->v.local_obj->data_type;
+ }
+ else
+ {
+ SLang_Name_Type *nt = ref->v.nt;
+ if ((nt->name_type != SLANG_GVARIABLE)
+ && (nt->name_type != SLANG_PVARIABLE))
+ return 1;
+ type = ((SLang_Global_Var_Type *)nt)->obj.data_type;
+ }
+ return type != SLANG_UNDEFINED_TYPE;
+}
+
+int _SLang_uninitialize_ref (SLang_Ref_Type *ref)
+{
+ SLang_Object_Type *obj;
+
+ if (ref == NULL)
+ {
+ SLang_Error = SL_INTERNAL_ERROR;
+ return -1;
+ }
+
+ if (ref->is_global == 0)
+ {
+ obj = ref->v.local_obj;
+ if (obj > Local_Variable_Frame)
+ {
+ SLang_verror (SL_UNDEFINED_NAME, "Local variable deref is out of scope");
+ return -1;
+ }
+ obj = ref->v.local_obj;
+ }
+ else
+ {
+ SLang_Name_Type *nt = ref->v.nt;
+ if ((nt->name_type != SLANG_GVARIABLE)
+ && (nt->name_type != SLANG_PVARIABLE))
+ return -1;
+ obj = &((SLang_Global_Var_Type *)nt)->obj;
+ }
+ SLang_free_object (obj);
+ obj->data_type = SLANG_UNDEFINED_TYPE;
+ obj->v.ptr_val = NULL;
+ return 0;
+}
+
+void (*SLang_Interrupt)(void);
+static int Last_Error;
+void (*SLang_User_Clear_Error)(void);
+void _SLang_clear_error (void)
+{
+ if (Last_Error <= 0)
+ {
+ Last_Error = 0;
+ return;
+ }
+ Last_Error--;
+ if (SLang_User_Clear_Error != NULL) (*SLang_User_Clear_Error)();
+}
+
+int _SLpush_slang_obj (SLang_Object_Type *obj)
+{
+ unsigned char subtype;
+ SLang_Class_Type *cl;
+
+ if (obj == NULL) return SLang_push_null ();
+
+ subtype = obj->data_type;
+
+#if _SLANG_OPTIMIZE_FOR_SPEED
+ if (SLANG_CLASS_TYPE_SCALAR == _SLclass_Class_Type[subtype])
+ return SLang_push (obj);
+#endif
+
+ cl = _SLclass_get_class (subtype);
+ return (*cl->cl_push) (subtype, (VOID_STAR) &obj->v);
+}
+
+_INLINE_
+static int push_local_variable (int i)
+{
+ SLang_Class_Type *cl;
+ SLang_Object_Type *obj;
+ unsigned char subtype;
+
+ obj = Local_Variable_Frame - i;
+ subtype = obj->data_type;
+
+#if _SLANG_OPTIMIZE_FOR_SPEED
+ if (SLANG_CLASS_TYPE_SCALAR == _SLclass_Class_Type[subtype])
+ return SLang_push (obj);
+ if (subtype == SLANG_STRING_TYPE)
+ return _SLang_dup_and_push_slstring (obj->v.s_val);
+#endif
+
+ cl = _SLclass_get_class (subtype);
+ return (*cl->cl_push) (subtype, (VOID_STAR) &obj->v);
+}
+
+static int push_intrinsic_variable (SLang_Intrin_Var_Type *ivar)
+{
+ SLang_Class_Type *cl;
+ unsigned char stype;
+
+ stype = ivar->type;
+ cl = _SLclass_get_class (stype);
+
+ if (-1 == (*cl->cl_push_intrinsic) (stype, ivar->addr))
+ {
+ do_name_type_error ((SLang_Name_Type *) ivar);
+ return -1;
+ }
+ return 0;
+}
+
+static int dereference_object (void)
+{
+ SLang_Object_Type obj;
+ SLang_Class_Type *cl;
+ unsigned char type;
+ int ret;
+
+ if (-1 == SLang_pop (&obj))
+ return -1;
+
+ type = obj.data_type;
+
+ cl = _SLclass_get_class (type);
+ ret = (*cl->cl_dereference)(type, (VOID_STAR) &obj.v);
+
+ SLang_free_object (&obj);
+ return ret;
+}
+
+static int case_function (void)
+{
+ unsigned char type;
+ SLang_Object_Type obj;
+ SLang_Object_Type *swobjptr;
+
+ swobjptr = Switch_Obj_Ptr - 1;
+
+ if ((swobjptr < Switch_Objects)
+ || (0 == (type = swobjptr->data_type)))
+ {
+ SLang_verror (SL_SYNTAX_ERROR, "Misplaced 'case' keyword");
+ return -1;
+ }
+
+ if (-1 == SLang_pop (&obj))
+ return -1;
+
+ if (obj.data_type != type)
+ {
+ SLang_Class_Type *a_cl, *b_cl;
+
+ a_cl = _SLclass_get_class (obj.data_type);
+ b_cl = _SLclass_get_class (type);
+
+ if (NULL == _SLclass_get_binary_fun (SLANG_EQ, a_cl, b_cl, &a_cl, 0))
+ {
+ (void) SLclass_push_int_obj (SLANG_INT_TYPE, 0);
+ SLang_free_object (&obj);
+ return 0;
+ }
+ }
+
+ (void) do_binary_ab (SLANG_EQ, swobjptr, &obj);
+ SLang_free_object (&obj);
+ return 0;
+}
+
+static void tmp_variable_function (SLBlock_Type *addr)
+{
+ SLang_Object_Type *obj;
+
+ switch (addr->bc_sub_type)
+ {
+ case SLANG_GVARIABLE:
+ case SLANG_PVARIABLE:
+ obj = &addr->b.nt_gvar_blk->obj;
+ break;
+
+ case SLANG_LVARIABLE:
+ obj = Local_Variable_Frame - addr->b.i_blk;
+ break;
+
+ default:
+ SLang_Error = SL_INTERNAL_ERROR;
+ return;
+ }
+
+ /* There is no need to go through higher level routines since we are
+ * not creating or destroying extra copies.
+ */
+ if (-1 == SLang_push (obj))
+ return;
+
+ obj->data_type = SLANG_UNDEFINED_TYPE;
+ obj->v.ptr_val = NULL;
+}
+
+
+static int
+do_inner_interp_error (SLBlock_Type *err_block,
+ SLBlock_Type *addr_start,
+ SLBlock_Type *addr)
+{
+ int save_err, slerr;
+
+ /* Someday I can use the these variable to provide extra information
+ * about what went wrong.
+ */
+ (void) addr_start;
+ (void) addr;
+
+ if (err_block == NULL)
+ goto return_error;
+
+ if (SLang_Error < 0) /* errors less than 0 are severe */
+ goto return_error;
+
+ save_err = Last_Error++;
+ slerr = SLang_Error;
+ SLang_Error = 0;
+ inner_interp (err_block->b.blk);
+
+ if (Last_Error <= save_err)
+ {
+ /* Caught error and cleared it */
+ Last_Error = save_err;
+ if ((Lang_Break_Condition == 0)
+ /* An error may have cleared the error and then caused the
+ * function to return. We will allow that but let's not allow
+ * 'break' nor 'continue' statements until later.
+ */
+ || Lang_Return)
+ return 0;
+
+ /* drop--- either a break or continue was called */
+ }
+
+ Last_Error = save_err;
+ SLang_Error = slerr;
+
+ return_error:
+#if _SLANG_HAS_DEBUG_CODE
+ while (addr >= addr_start)
+ {
+ if (addr->bc_main_type == _SLANG_BC_LINE_NUM)
+ {
+ char buf[256];
+ sprintf (buf, "(Error occurred on line %lu)", addr->b.l_blk);
+ do_traceback (buf, 0, NULL);
+ break;
+ }
+ /* Special hack for 16 bit systems to prevent pointer wrapping. */
+#if defined(__16_BIT_SYSTEM__)
+ if (addr == addr_start)
+ break;
+#endif
+ addr--;
+ }
+#endif
+ return -1;
+}
+
+
+#define GATHER_STATISTICS 0
+#if GATHER_STATISTICS
+static unsigned int Bytecodes[0xFFFF];
+
+static void print_stats (void)
+{
+ unsigned int i;
+ unsigned long total;
+ FILE *fp = fopen ("stats.txt", "w");
+ if (fp == NULL)
+ return;
+
+ total = 0;
+ for (i = 0; i < 0xFFFF; i++)
+ total += Bytecodes[i];
+
+ if (total == 0)
+ total = 1;
+
+ for (i = 0; i < 0xFFFF; i++)
+ {
+ if (Bytecodes[i])
+ fprintf (fp, "0x%04X %9u %e\n", i, Bytecodes[i], Bytecodes[i]/(double) total);
+ }
+ fclose (fp);
+}
+
+static void add_to_statistics (SLBlock_Type *b)
+{
+ unsigned short x, y;
+
+ x = b->bc_main_type;
+ if (x == 0)
+ {
+ Bytecodes[0] += 1;
+ return;
+ }
+ b++;
+ y = b->bc_main_type;
+
+ Bytecodes[(x << 8) | y] += 1;
+}
+
+#endif
+
+/* inner interpreter */
+/* The return value from this function is only meaningful when it is used
+ * to process blocks for the switch statement. If it returns 0, the calling
+ * routine should pass the next block to it. Otherwise it will
+ * return non-zero, with or without error.
+ */
+static int inner_interp (SLBlock_Type *addr_start)
+{
+ SLBlock_Type *block, *err_block, *addr;
+#if GATHER_STATISTICS
+ static int inited = 0;
+
+ if (inited == 0)
+ {
+ (void) SLang_add_cleanup_function (print_stats);
+ inited = 1;
+ }
+#endif
+
+ /* for systems that have no real interrupt facility (e.g. go32 on dos) */
+ if (SLang_Interrupt != NULL) (*SLang_Interrupt)();
+
+ block = err_block = NULL;
+ addr = addr_start;
+
+#if GATHER_STATISTICS
+ add_to_statistics (addr);
+#endif
+ while (1)
+ {
+ switch (addr->bc_main_type)
+ {
+ case 0:
+ return 1;
+ case _SLANG_BC_LVARIABLE:
+ push_local_variable (addr->b.i_blk);
+ break;
+ case _SLANG_BC_GVARIABLE:
+ if (-1 == _SLpush_slang_obj (&addr->b.nt_gvar_blk->obj))
+ do_name_type_error (addr->b.nt_blk);
+ break;
+
+ case _SLANG_BC_IVARIABLE:
+ case _SLANG_BC_RVARIABLE:
+ push_intrinsic_variable (addr->b.nt_ivar_blk);
+ break;
+
+ case _SLANG_BC_INTRINSIC:
+ execute_intrinsic_fun (addr->b.nt_ifun_blk);
+ if (SLang_Error)
+ do_traceback(addr->b.nt_ifun_blk->name, 0, NULL);
+ break;
+
+ case _SLANG_BC_FUNCTION:
+ execute_slang_fun (addr->b.nt_fun_blk);
+ if (Lang_Break_Condition) goto handle_break_condition;
+ break;
+
+ case _SLANG_BC_MATH_UNARY:
+ case _SLANG_BC_APP_UNARY:
+ /* Make sure we treat these like function calls since the
+ * parser took sin(x) to be a function call.
+ */
+ if (0 == _SL_increment_frame_pointer ())
+ {
+ do_app_unary (addr->b.nt_unary_blk);
+ (void) _SL_decrement_frame_pointer ();
+ }
+ break;
+
+ case _SLANG_BC_ICONST:
+ SLclass_push_int_obj (SLANG_INT_TYPE, addr->b.iconst_blk->i);
+ break;
+
+#if SLANG_HAS_FLOAT
+ case _SLANG_BC_DCONST:
+ SLang_push_double (addr->b.dconst_blk->d);
+ break;
+#endif
+
+ case _SLANG_BC_PVARIABLE:
+ if (-1 == _SLpush_slang_obj (&addr->b.nt_gvar_blk->obj))
+ do_name_type_error (addr->b.nt_blk);
+ break;
+
+ case _SLANG_BC_PFUNCTION:
+ execute_slang_fun (addr->b.nt_fun_blk);
+ if (Lang_Break_Condition) goto handle_break_condition;
+ break;
+
+ case _SLANG_BC_BINARY:
+ do_binary (addr->b.i_blk);
+ break;
+
+ case _SLANG_BC_LITERAL:
+#if !_SLANG_OPTIMIZE_FOR_SPEED
+ case _SLANG_BC_LITERAL_INT:
+ case _SLANG_BC_LITERAL_STR:
+#endif
+ {
+ SLang_Class_Type *cl = _SLclass_get_class (addr->bc_sub_type);
+ (*cl->cl_push_literal) (addr->bc_sub_type, (VOID_STAR) &addr->b.ptr_blk);
+ }
+ break;
+#if _SLANG_OPTIMIZE_FOR_SPEED
+ case _SLANG_BC_LITERAL_INT:
+ SLclass_push_int_obj (addr->bc_sub_type, (int) addr->b.l_blk);
+ break;
+
+ case _SLANG_BC_LITERAL_STR:
+ _SLang_dup_and_push_slstring (addr->b.s_blk);
+ break;
+#endif
+ case _SLANG_BC_BLOCK:
+ switch (addr->bc_sub_type)
+ {
+ case _SLANG_BCST_ERROR_BLOCK:
+ err_block = addr;
+ break;
+
+ case _SLANG_BCST_EXIT_BLOCK:
+ Exit_Block_Ptr = addr->b.blk;
+ break;
+
+ case _SLANG_BCST_USER_BLOCK0:
+ case _SLANG_BCST_USER_BLOCK1:
+ case _SLANG_BCST_USER_BLOCK2:
+ case _SLANG_BCST_USER_BLOCK3:
+ case _SLANG_BCST_USER_BLOCK4:
+ User_Block_Ptr[addr->bc_sub_type - _SLANG_BCST_USER_BLOCK0] = addr->b.blk;
+ break;
+
+ case _SLANG_BCST_LOOP:
+ case _SLANG_BCST_WHILE:
+ case _SLANG_BCST_FOR:
+ case _SLANG_BCST_FOREVER:
+ case _SLANG_BCST_CFOR:
+ case _SLANG_BCST_DOWHILE:
+ case _SLANG_BCST_FOREACH:
+ if (block == NULL) block = addr;
+ lang_do_loops(addr->bc_sub_type, block, 1 + (unsigned int) (addr - block));
+ block = NULL;
+ break;
+
+ case _SLANG_BCST_IFNOT:
+#if _SLANG_OPTIMIZE_FOR_SPEED
+ {
+ int i;
+
+ if ((0 == pop_ctrl_integer (&i)) && (i == 0))
+ inner_interp (addr->b.blk);
+ }
+#else
+ do_else_if (addr, NULL);
+#endif
+ break;
+
+ case _SLANG_BCST_IF:
+#if _SLANG_OPTIMIZE_FOR_SPEED
+ {
+ int i;
+
+ if ((0 == pop_ctrl_integer (&i)) && i)
+ inner_interp (addr->b.blk);
+ }
+#else
+ do_else_if (NULL, addr);
+#endif
+ break;
+
+ case _SLANG_BCST_NOTELSE:
+ do_else_if (block, addr);
+ block = NULL;
+ break;
+
+ case _SLANG_BCST_ELSE:
+ do_else_if (addr, block);
+ block = NULL;
+ break;
+
+ case _SLANG_BCST_SWITCH:
+ if (Switch_Obj_Ptr == Switch_Obj_Max)
+ {
+ SLang_doerror("switch nesting too deep");
+ break;
+ }
+ (void) SLang_pop (Switch_Obj_Ptr);
+ Switch_Obj_Ptr++;
+
+ if (block == NULL) block = addr;
+ while ((SLang_Error == 0)
+ && (block <= addr)
+ && (Lang_Break_Condition == 0)
+ && (0 == inner_interp (block->b.blk)))
+ block++;
+ Switch_Obj_Ptr--;
+ SLang_free_object (Switch_Obj_Ptr);
+ Switch_Obj_Ptr->data_type = 0;
+ block = NULL;
+ break;
+
+ case _SLANG_BCST_ANDELSE:
+ case _SLANG_BCST_ORELSE:
+ if (block == NULL) block = addr;
+ lang_do_and_orelse (addr->bc_sub_type, block, addr);
+ block = NULL;
+ break;
+
+ default:
+ if (block == NULL) block = addr;
+ break;
+ }
+ if (Lang_Break_Condition) goto handle_break_condition;
+ break;
+
+ case _SLANG_BC_RETURN:
+ Lang_Break_Condition = Lang_Return = Lang_Break = 1; return 1;
+ case _SLANG_BC_BREAK:
+ Lang_Break_Condition = Lang_Break = 1; return 1;
+ case _SLANG_BC_CONTINUE:
+ Lang_Break_Condition = /* Lang_Continue = */ 1; return 1;
+
+ case _SLANG_BC_EXCH:
+ (void) SLreverse_stack (2);
+ break;
+
+ case _SLANG_BC_LABEL:
+ {
+ int test;
+ if ((0 == SLang_pop_integer (&test))
+ && (test == 0))
+ return 0;
+ }
+ break;
+
+ case _SLANG_BC_LOBJPTR:
+ (void)_SLang_push_ref (0, (VOID_STAR)(Local_Variable_Frame - addr->b.i_blk));
+ break;
+
+ case _SLANG_BC_GOBJPTR:
+ (void)_SLang_push_ref (1, (VOID_STAR)addr->b.nt_blk);
+ break;
+
+ case _SLANG_BC_X_ERROR:
+ if (err_block != NULL)
+ {
+ inner_interp(err_block->b.blk);
+ if (SLang_Error) err_block = NULL;
+ }
+ else SLang_verror(SL_SYNTAX_ERROR, "No ERROR_BLOCK");
+ if (Lang_Break_Condition) goto handle_break_condition;
+ break;
+
+ case _SLANG_BC_X_USER0:
+ case _SLANG_BC_X_USER1:
+ case _SLANG_BC_X_USER2:
+ case _SLANG_BC_X_USER3:
+ case _SLANG_BC_X_USER4:
+ if (User_Block_Ptr[addr->bc_main_type - _SLANG_BC_X_USER0] != NULL)
+ {
+ inner_interp(User_Block_Ptr[addr->bc_main_type - _SLANG_BC_X_USER0]);
+ }
+ else SLang_verror(SL_SYNTAX_ERROR, "No block for X_USERBLOCK");
+ if (Lang_Break_Condition) goto handle_break_condition;
+ break;
+
+ case _SLANG_BC_CALL_DIRECT:
+ (*addr->b.call_function) ();
+ break;
+
+ case _SLANG_BC_CALL_DIRECT_FRAME:
+ do_bc_call_direct_frame (addr->b.call_function);
+ break;
+
+ case _SLANG_BC_UNARY:
+ do_unary (addr->b.i_blk, _SLANG_BC_UNARY);
+ break;
+
+ case _SLANG_BC_UNARY_FUNC:
+ /* Make sure we treat these like function calls since the
+ * parser took abs(x) to be a function call.
+ */
+ if (0 == _SL_increment_frame_pointer ())
+ {
+ do_unary (addr->b.i_blk, _SLANG_BC_UNARY);
+ (void) _SL_decrement_frame_pointer ();
+ }
+ break;
+
+ case _SLANG_BC_DEREF_ASSIGN:
+ set_deref_lvalue (addr);
+ break;
+ case _SLANG_BC_SET_LOCAL_LVALUE:
+ set_lvalue_obj (addr->bc_sub_type, Local_Variable_Frame - addr->b.i_blk);
+ break;
+ case _SLANG_BC_SET_GLOBAL_LVALUE:
+ if (-1 == set_lvalue_obj (addr->bc_sub_type, &addr->b.nt_gvar_blk->obj))
+ do_name_type_error (addr->b.nt_blk);
+ break;
+ case _SLANG_BC_SET_INTRIN_LVALUE:
+ set_intrin_lvalue (addr);
+ break;
+ case _SLANG_BC_SET_STRUCT_LVALUE:
+ set_struct_lvalue (addr);
+ break;
+
+ case _SLANG_BC_FIELD:
+ (void) push_struct_field (addr->b.s_blk);
+ break;
+
+ case _SLANG_BC_SET_ARRAY_LVALUE:
+ set_array_lvalue (addr->bc_sub_type);
+ break;
+
+#if _SLANG_HAS_DEBUG_CODE
+ case _SLANG_BC_LINE_NUM:
+ break;
+#endif
+
+ case _SLANG_BC_TMP:
+ tmp_variable_function (addr);
+ break;
+
+#if _SLANG_OPTIMIZE_FOR_SPEED
+ case _SLANG_BC_LVARIABLE_AGET:
+ if (0 == push_local_variable (addr->b.i_blk))
+ do_bc_call_direct_frame (_SLarray_aget);
+ break;
+
+ case _SLANG_BC_LVARIABLE_APUT:
+ if (0 == push_local_variable (addr->b.i_blk))
+ do_bc_call_direct_frame (_SLarray_aput);
+ break;
+ case _SLANG_BC_INTEGER_PLUS:
+ if (0 == SLclass_push_int_obj (addr->bc_sub_type, (int) addr->b.l_blk))
+ do_binary (SLANG_PLUS);
+ break;
+
+ case _SLANG_BC_INTEGER_MINUS:
+ if (0 == SLclass_push_int_obj (addr->bc_sub_type, (int) addr->b.l_blk))
+ do_binary (SLANG_MINUS);
+ break;
+#endif
+#if 0
+ case _SLANG_BC_ARG_LVARIABLE:
+ (void) SLang_start_arg_list ();
+ push_local_variable (addr->b.i_blk);
+ break;
+#endif
+ case _SLANG_BC_EARG_LVARIABLE:
+ push_local_variable (addr->b.i_blk);
+ (void) SLang_end_arg_list ();
+ break;
+
+#if USE_COMBINED_BYTECODES
+ case _SLANG_BC_CALL_DIRECT_INTRINSIC:
+ (*addr->b.call_function) ();
+ addr++;
+ execute_intrinsic_fun (addr->b.nt_ifun_blk);
+ if (SLang_Error)
+ do_traceback(addr->b.nt_ifun_blk->name, 0, NULL);
+ break;
+
+ case _SLANG_BC_INTRINSIC_CALL_DIRECT:
+ execute_intrinsic_fun (addr->b.nt_ifun_blk);
+ if (SLang_Error)
+ {
+ do_traceback(addr->b.nt_ifun_blk->name, 0, NULL);
+ break;
+ }
+ addr++;
+ (*addr->b.call_function) ();
+ break;
+
+ case _SLANG_BC_CALL_DIRECT_LSTR:
+ (*addr->b.call_function) ();
+ addr++;
+ _SLang_dup_and_push_slstring (addr->b.s_blk);
+ break;
+
+ case _SLANG_BC_CALL_DIRECT_SLFUN:
+ (*addr->b.call_function) ();
+ addr++;
+ execute_slang_fun (addr->b.nt_fun_blk);
+ if (Lang_Break_Condition) goto handle_break_condition;
+ break;
+
+ case _SLANG_BC_CALL_DIRECT_INTRSTOP:
+ (*addr->b.call_function) ();
+ addr++;
+ /* drop */
+ case _SLANG_BC_INTRINSIC_STOP:
+ execute_intrinsic_fun (addr->b.nt_ifun_blk);
+ if (SLang_Error == 0)
+ return 1;
+ do_traceback(addr->b.nt_ifun_blk->name, 0, NULL);
+ break;
+
+ case _SLANG_BC_CALL_DIRECT_EARG_LVAR:
+ (*addr->b.call_function) ();
+ addr++;
+ push_local_variable (addr->b.i_blk);
+ (void) SLang_end_arg_list ();
+ break;
+
+ case _SLANG_BC_CALL_DIRECT_LINT:
+ (*addr->b.call_function) ();
+ addr++;
+ SLclass_push_int_obj (addr->bc_sub_type, (int) addr->b.l_blk);
+ break;
+
+ case _SLANG_BC_CALL_DIRECT_LVAR:
+ (*addr->b.call_function) ();
+ addr++;
+ push_local_variable (addr->b.i_blk);
+ break;
+#endif /* USE_COMBINED_BYTECODES */
+
+ default:
+ SLang_verror (SL_INTERNAL_ERROR, "Byte-Code 0x%X is not valid", addr->bc_main_type);
+ }
+
+ /* Someday I plan to add a 'signal' intrinsic function. Then when a
+ * signal is caught, a variable will be set to one and that value of
+ * that variable will need to be monitored here, e.g.,
+ * if (Handle_Signal) handle_signal ();
+ * It would be nice to check only one variable instead of Handle_Signal
+ * and SLang_Error. Perhaps I should phase out SLang_Error = xxx
+ * and used something like: SLang_set_error (code); Then, I could
+ * use:
+ * if (Handle_Condition)
+ * {
+ * Handle_Condition = 0;
+ * if (SLang_Error) ....
+ * else if (Handle_Signal) handle_signal ();
+ * else....
+ * }
+ */
+ if (SLang_Error)
+ {
+ if (-1 == do_inner_interp_error (err_block, addr_start, addr))
+ return 1;
+ if (SLang_Error)
+ return 1;
+
+ /* Otherwise, error cleared. Continue onto next bytecode.
+ * Someday I need to add something to indicate where the
+ * next statement begins since continuing on the next
+ * bytecode is not really what is desired.
+ */
+ if (Lang_Break_Condition) goto handle_break_condition;
+ }
+ addr++;
+ }
+
+ handle_break_condition:
+ /* Get here if Lang_Break_Condition != 0, which implies that either
+ * Lang_Return, Lang_Break, or Lang_Continue is non zero
+ */
+ if (Lang_Return)
+ Lang_Break = 1;
+
+ return 1;
+}
+
+/*}}}*/
+
+/* The functions below this point are used to implement the parsed token
+ * to byte-compiled code.
+ */
+/* static SLang_Name_Type **Static_Hash_Table; */
+
+static SLang_Name_Type **Locals_Hash_Table;
+static int Local_Variable_Number;
+static unsigned int Function_Args_Number;
+int _SLang_Auto_Declare_Globals = 0;
+int (*SLang_Auto_Declare_Var_Hook) (char *);
+
+static SLang_NameSpace_Type *This_Static_NameSpace;
+static SLang_NameSpace_Type *Global_NameSpace;
+
+#if _SLANG_HAS_DEBUG_CODE
+static char *This_Compile_Filename;
+#endif
+static SLBlock_Type SLShort_Blocks[6];
+/* These are initialized in add_table below. I cannot init a Union!! */
+
+static int Lang_Defining_Function;
+static void (*Default_Variable_Mode) (_SLang_Token_Type *);
+static void (*Default_Define_Function) (char *, unsigned long);
+
+static int push_compile_context (char *);
+static int pop_compile_context (void);
+
+typedef struct
+{
+ int block_type;
+ SLBlock_Type *block; /* beginning of block definition */
+ SLBlock_Type *block_ptr; /* current location */
+ SLBlock_Type *block_max; /* end of definition */
+ SLang_NameSpace_Type *static_namespace;
+}
+Block_Context_Type;
+
+static Block_Context_Type Block_Context_Stack [SLANG_MAX_BLOCK_STACK_LEN];
+static unsigned int Block_Context_Stack_Len;
+
+static SLBlock_Type *Compile_ByteCode_Ptr;
+static SLBlock_Type *This_Compile_Block;
+static SLBlock_Type *This_Compile_Block_Max;
+static int This_Compile_Block_Type;
+#define COMPILE_BLOCK_TYPE_FUNCTION 1
+#define COMPILE_BLOCK_TYPE_BLOCK 2
+#define COMPILE_BLOCK_TYPE_TOP_LEVEL 3
+
+/* If it returns 0, DO NOT FREE p */
+static int lang_free_branch (SLBlock_Type *p)
+{
+ /* Note: we look at 0,2,4, since these blocks are 0 terminated */
+ if ((p == SLShort_Blocks)
+ || (p == SLShort_Blocks + 2)
+ || (p == SLShort_Blocks + 4)
+ )
+ return 0;
+
+ while (1)
+ {
+ SLang_Class_Type *cl;
+
+ switch (p->bc_main_type)
+ {
+ case _SLANG_BC_BLOCK:
+ if (lang_free_branch(p->b.blk))
+ SLfree((char *)p->b.blk);
+ break;
+
+ case _SLANG_BC_LITERAL:
+ case _SLANG_BC_LITERAL_STR:
+ /* No user types should be here. */
+ cl = _SLclass_get_class (p->bc_sub_type);
+ (*cl->cl_byte_code_destroy) (p->bc_sub_type, (VOID_STAR) &p->b.ptr_blk);
+ break;
+
+ case _SLANG_BC_FIELD:
+ case _SLANG_BC_SET_STRUCT_LVALUE:
+ SLang_free_slstring (p->b.s_blk);
+ break;
+
+ default:
+ break;
+
+ case 0:
+ return 1;
+ }
+ p++;
+ }
+}
+
+static void free_function_header (_SLBlock_Header_Type *h)
+{
+ if (h->num_refs > 1)
+ {
+ h->num_refs--;
+ return;
+ }
+
+ if (h->body != NULL)
+ {
+ if (lang_free_branch (h->body))
+ SLfree ((char *) h->body);
+ }
+
+ SLfree ((char *) h);
+}
+
+static int push_block_context (int type)
+{
+ Block_Context_Type *c;
+ unsigned int num;
+ SLBlock_Type *b;
+
+ if (Block_Context_Stack_Len == SLANG_MAX_BLOCK_STACK_LEN)
+ {
+ SLang_verror (SL_STACK_OVERFLOW, "Block stack overflow");
+ return -1;
+ }
+
+ num = 5; /* 40 bytes */
+ if (NULL == (b = (SLBlock_Type *) SLcalloc (num, sizeof (SLBlock_Type))))
+ return -1;
+
+ c = Block_Context_Stack + Block_Context_Stack_Len;
+ c->block = This_Compile_Block;
+ c->block_ptr = Compile_ByteCode_Ptr;
+ c->block_max = This_Compile_Block_Max;
+ c->block_type = This_Compile_Block_Type;
+ c->static_namespace = This_Static_NameSpace;
+
+ Compile_ByteCode_Ptr = This_Compile_Block = b;
+ This_Compile_Block_Max = b + num;
+ This_Compile_Block_Type = type;
+
+ Block_Context_Stack_Len += 1;
+ return 0;
+}
+
+static int pop_block_context (void)
+{
+ Block_Context_Type *c;
+
+ if (Block_Context_Stack_Len == 0)
+ return -1;
+
+ Block_Context_Stack_Len -= 1;
+ c = Block_Context_Stack + Block_Context_Stack_Len;
+
+ This_Compile_Block = c->block;
+ This_Compile_Block_Max = c->block_max;
+ This_Compile_Block_Type = c->block_type;
+ Compile_ByteCode_Ptr = c->block_ptr;
+ This_Static_NameSpace = c->static_namespace;
+
+ return 0;
+}
+
+int _SLcompile_push_context (SLang_Load_Type *load_object)
+{
+ if (-1 == push_compile_context (load_object->name))
+ return -1;
+
+ if (NULL == (This_Static_NameSpace = _SLns_allocate_namespace (load_object->name, SLSTATIC_HASH_TABLE_SIZE)))
+ {
+ pop_compile_context ();
+ return -1;
+ }
+
+ if (-1 == push_block_context (COMPILE_BLOCK_TYPE_TOP_LEVEL))
+ {
+ pop_compile_context ();
+ return -1;
+ }
+
+ return 0;
+}
+
+int _SLcompile_pop_context (void)
+{
+ if (This_Compile_Block_Type == COMPILE_BLOCK_TYPE_TOP_LEVEL)
+ {
+ Compile_ByteCode_Ptr->bc_main_type = 0;
+ if (lang_free_branch (This_Compile_Block))
+ SLfree ((char *) This_Compile_Block);
+ }
+
+ (void) pop_block_context ();
+ (void) pop_compile_context ();
+
+ if (This_Compile_Block == NULL)
+ return 0;
+
+#if 0
+ if (This_Compile_Block_Type != COMPILE_BLOCK_TYPE_TOP_LEVEL)
+ {
+ SLang_verror (SL_INTERNAL_ERROR, "Not at top-level");
+ return -1;
+ }
+#endif
+
+ return 0;
+}
+
+/*{{{ Hash and Name Table Functions */
+
+static SLang_Name_Type *locate_name_in_table (char *name, unsigned long hash,
+ SLang_Name_Type **table, unsigned int table_size)
+{
+ SLang_Name_Type *t;
+ char ch;
+
+ t = table [(unsigned int) (hash % table_size)];
+ ch = *name++;
+
+ while (t != NULL)
+ {
+ if ((ch == t->name[0])
+ && (0 == strcmp (t->name + 1, name)))
+ break;
+
+ t = t->next;
+ }
+
+ return t;
+}
+
+static SLang_Name_Type *locate_namespace_encoded_name (char *name, int err_on_bad_ns)
+{
+ char *ns, *ns1;
+ SLang_NameSpace_Type *table;
+ SLang_Name_Type *nt;
+
+ ns = name;
+ name = strchr (name, '-');
+ if ((name == NULL) || (name [1] != '>'))
+ name = ns;
+
+ ns1 = SLang_create_nslstring (ns, (unsigned int) (name - ns));
+ if (ns1 == NULL)
+ return NULL;
+ if (ns != name)
+ name += 2;
+ ns = ns1;
+
+ if (*ns == 0)
+ {
+ /* Use Global Namespace */
+ SLang_free_slstring (ns);
+ return locate_name_in_table (name, _SLcompute_string_hash (name),
+ Global_NameSpace->table, Global_NameSpace->table_size);
+ }
+
+ if (NULL == (table = _SLns_find_namespace (ns)))
+ {
+ if (err_on_bad_ns)
+ SLang_verror (SL_SYNTAX_ERROR, "Unable to find namespace called %s", ns);
+ SLang_free_slstring (ns);
+ return NULL;
+ }
+ SLang_free_slstring (ns);
+
+ /* FIXME: the hash table size should be stored in the hash table itself */
+ nt = locate_name_in_table (name, _SLcompute_string_hash (name),
+ table->table, table->table_size);
+ if (nt == NULL)
+ return NULL;
+
+ switch (nt->name_type)
+ {
+ /* These are private and cannot be accessed through the namespace. */
+ case SLANG_PVARIABLE:
+ case SLANG_PFUNCTION:
+ return NULL;
+ }
+ return nt;
+}
+
+static SLang_Name_Type *locate_hashed_name (char *name, unsigned long hash)
+{
+ SLang_Name_Type *t;
+
+ if (Lang_Defining_Function)
+ {
+ t = locate_name_in_table (name, hash, Locals_Hash_Table, SLLOCALS_HASH_TABLE_SIZE);
+ if (t != NULL)
+ return t;
+ }
+
+ if ((This_Static_NameSpace != NULL)
+ && (NULL != (t = locate_name_in_table (name, hash, This_Static_NameSpace->table, This_Static_NameSpace->table_size))))
+ return t;
+
+ t = locate_name_in_table (name, hash, Global_NameSpace->table, Global_NameSpace->table_size);
+ if (NULL != t)
+ return t;
+
+ return locate_namespace_encoded_name (name, 1);
+}
+
+SLang_Name_Type *_SLlocate_name (char *name)
+{
+ return locate_hashed_name (name, _SLcompute_string_hash (name));
+}
+