1 /*
2     This file is part of GNU APL, a free implementation of the
3     ISO/IEC Standard 13751, "Programming Language APL, Extended"
4 
5     Copyright (C) 2008-2016  Dr. Jürgen Sauermann
6 
7     This program is free software: you can redistribute it and/or modify
8     it under the terms of the GNU General Public License as published by
9     the Free Software Foundation, either version 3 of the License, or
10     (at your option) any later version.
11 
12     This program is distributed in the hope that it will be useful,
13     but WITHOUT ANY WARRANTY; without even the implied warranty of
14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15     GNU General Public License for more details.
16 
17     You should have received a copy of the GNU General Public License
18     along with this program.  If not, see <http://www.gnu.org/licenses/>.
19 */
20 
21 #include <cassert>
22 #include <iostream>
23 
24 #include <signal.h>
25 #include <stdio.h>
26 #include <stdint.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <sys/wait.h>
30 
31 #include "APmain.hh"
32 #include "CDR_string.hh"
33 #include "Svar_DB.hh"
34 #include "Svar_signals.hh"
35 
36 using namespace std;
37 
38 //-----------------------------------------------------------------------------
prog_name()39 const char * prog_name()
40 {
41    return "AP100";
42 }
43 //-----------------------------------------------------------------------------
44 struct SVAR_context
45 {
SVAR_contextSVAR_context46    SVAR_context()
47   {}
48 };
49 //-----------------------------------------------------------------------------
50 int
set_ACK(Coupled_var & var,int exco)51 set_ACK(Coupled_var & var, int exco)
52 {
53 const uint8_t _cdr[] =
54    {
55      0x00, 0x00, 0x20, 0x20, // ptr
56      0x00, 0x00, 0x00, 0x20, // nb: total len
57      0x00, 0x00, 0x00, 0x01, // nelm: element count
58      0x01, 0x00, 0x00, 0x00, // type, rank, pad, pad
59      uint8_t(exco), uint8_t(exco>>8), uint8_t(exco>>16), uint8_t(exco>>24),
60      0x00, 0x00, 0x00, 0x00, // pad
61      0x00, 0x00, 0x00, 0x00, // pad
62      0x00, 0x00, 0x00, 0x00, // pad
63    };
64 
65 const CDR_string * cdr = new CDR_string(_cdr, sizeof(_cdr));
66    delete var.data;
67    var.data = cdr;
68    Svar_DB::set_state(var.key, true, LOC);
69 
70    return exco;
71 }
72 //-----------------------------------------------------------------------------
73 void
handle_var(Coupled_var & var)74 handle_var(Coupled_var & var)
75 {
76 FILE * fp = 0;
77 const CDR_string & cdr = *var.data;
78 const CDR_header & header = cdr.header();
79    if (cdr.size() < 20)   // less than min. size of CDR header
80       {
81         get_CERR() << "CDR record too short (" << cdr.size()
82              << " bytes)" << endl;
83         set_ACK(var, 444);
84         return;
85       }
86 
87    if (cdr[13] != 1)   // not a vector
88       {
89         get_CERR() << "Bad CDR rank (" << int(cdr[13]) << endl;
90         set_ACK(var, 445);
91         return;
92       }
93 
94    if (cdr[12] != 4)   // not a char vector
95       {
96         get_CERR() << "Bad CDR record type (" << int(cdr[12]) << endl;
97         set_ACK(var, 446);
98         return;
99       }
100 
101 const string cmd((const char *)cdr.get_items() + 20, header.get_nelm());
102 
103    if (verbose)   get_CERR() << pref << " got command[" << cmd.size() << "] '"
104                              << cmd << "'" << endl;
105 
106    fp = popen(cmd.c_str(), "r");
107    if (fp == 0)   // bad command
108       {
109         get_CERR() << pref << " popen() failed" << endl;
110         set_ACK(var, 1);  // 1 := INVALID COMMAND
111         return;
112       }
113 
114    for (;;)
115        {
116          const int cc = fgetc(fp);
117          if (cc == EOF)   break;
118          get_CERR() << char(cc);
119        }
120 
121    get_CERR() << flush;
122 const int result = pclose(fp);
123    if (verbose)
124    get_CERR() << pref << " finished command with exit code "
125               << result << endl;
126 
127    set_ACK(var, WEXITSTATUS(result));
128 }
129 //-----------------------------------------------------------------------------
130 bool
is_valid_varname(const uint32_t * varname)131 is_valid_varname(const uint32_t * varname)
132 {
133    // AP100 supports all variable names
134    //
135    return *varname;   // varname is not empty
136 }
137 //-----------------------------------------------------------------------------
138 bool
initialize(Coupled_var & var)139 initialize(Coupled_var & var)
140 {
141    Svar_DB::set_state(var.key, true, LOC);
142    Svar_DB::set_control(var.key, USE_BY_1);
143    return false;   // OK
144 }
145 //-----------------------------------------------------------------------------
146 bool
make_counter_offer(SV_key key)147 make_counter_offer(SV_key key)
148 {
149    return true;   // make counter offer
150 }
151 //-----------------------------------------------------------------------------
152 
153 APL_error_code
assign_value(Coupled_var & var,const string & data)154 assign_value(Coupled_var & var, const string & data)
155 {
156    // check CDR size, type, and shape of data. We expect a char string
157    // for both the CTL and the DAT variable.
158    //
159    if (data.size() < sizeof(CDR_header))   // too short
160       { error_loc = LOC;   return E_LENGTH_ERROR; }
161 
162    delete var.data;
163    var.data = new CDR_string((const uint8_t *)data.c_str(), data.size());
164    handle_var(var);
165    return E_NO_ERROR;
166 }
167 //-----------------------------------------------------------------------------
168 APL_error_code
get_value(Coupled_var & var,string & data)169 get_value(Coupled_var & var, string & data)
170 {
171    if (var.data == 0)   return E_VALUE_ERROR;
172 
173    data = string((const char *)(var.data->get_items()), var.data->size());
174    error_loc = "no_error";   return E_NO_ERROR;
175 }
176 //-----------------------------------------------------------------------------
177 void
retract(Coupled_var & var)178 retract(Coupled_var & var)
179 {
180 SVAR_context * ctx = var.context;
181    if (ctx)
182       {
183         delete ctx;
184       }
185 }
186 
187 //-----------------------------------------------------------------------------
188