interactive testing
[gnucap-felix.git] / src / main.cc
blobc8387c1726a064d48c9ec198862d4b02545c9812
1 /*$Id: main.cc 2016/09/11 al $ -*- C++ -*-
2 * Copyright (C) 2001 Albert Davis
3 * Author: Albert Davis <aldavis@gnu.org>
5 * This file is part of "Gnucap", the Gnu Circuit Analysis Package
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, or (at your option)
10 * any later version.
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.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20 * 02110-1301, USA.
21 *------------------------------------------------------------------
22 * top level module
23 * it all starts here
25 #include "globals.h"
26 #include "u_prblst.h"
27 #include "u_sim_data.h"
28 #include "e_cardlist.h"
29 #include "u_lang.h"
30 #include "ap.h"
31 #include "patchlev.h"
32 #include "c_comand.h"
33 #include "declare.h" /* plclose */
34 #include "config.h"
35 #include "startup.h"
36 // #define COMMENT_CHAR "*"
37 using namespace std;
38 /*--------------------------------------------------------------------------*/
39 extern char *optarg;
40 extern int optind, opterr, optopt;
41 #include <getopt.h>
43 /*--------------------------------------------------------------------------*/
44 struct JMP_BUF{
45 sigjmp_buf p;
46 } env;
47 /*--------------------------------------------------------------------------*/
48 static void sign_on(void)
50 if (OPT::quiet) return;
51 IO::mstdout <<
52 "Gnucap : The Gnu Circuit Analysis Package\n"
53 "Never trust any version less than 1.0\n"
54 "Copyright 1982-2015, Albert Davis\n"
55 "Copyright 2009-2015, Felix Salfelder\n"
56 "Gnucap comes with ABSOLUTELY NO WARRANTY\n"
57 "This is free software, and you are welcome\n"
58 "to redistribute it under the terms of \n"
59 "the GNU General Public License, version 3 or later.\n"
60 "See the file \"COPYING\" for details.\n"
61 #ifdef HAVE_GIT_REPO
62 "main version: " PATCHLEVEL "\n"
63 #else
64 "main version: " VERSION "\n"
65 #endif
66 "core-lib version: " << lib_version() << "\n";
68 /*--------------------------------------------------------------------------*/
69 void read_startup_files(void)
71 trace0("read_startup_files");
72 string name = findfile(SYSTEMSTARTFILE, SYSTEMSTARTPATH, R_OK);
73 if (name != "") {untested();
74 trace1("read_startup_files", name);
75 try{
76 CMD::command("get " + name, &CARD_LIST::card_list);
77 } catch(Exception e){
78 error(bDANGER, "%s\n",e.message().c_str());
80 }else{ itested();
81 CMD::command(std::string("load " DEFAULT_PLUGINS), &CARD_LIST::card_list);
83 if (!startup_recursive()) {
84 trace1("read_startup_files, no cwd", name);
85 name = findfile(USERSTARTFILE, USERSTARTPATH, R_OK);
86 if (name != "") {
87 try{
88 CMD::command("get " + name, &CARD_LIST::card_list);
89 } catch(Exception e){
90 error(bDANGER, "%s\n",e.message().c_str());
92 }else{
95 trace0("clear");
96 try{
97 CMD::command("clear", &CARD_LIST::card_list);
98 } catch(Exception e){
99 error(bDANGER, "%s\n",e.message().c_str());
101 if (!OPT::language) {
102 try{
103 CMD::command(std::string("options lang=") + DEFAULT_LANGUAGE, &CARD_LIST::card_list);
104 } catch(Exception e){
105 error(bDANGER, "%s\n",e.message().c_str());
107 }else{
110 /*--------------------------------------------------------------------------*/
111 /* sig_abrt: trap asserts
113 extern "C" {
114 static void sig_abrt(SIGNALARGS)
116 signal(SIGINT,sig_abrt);
117 static int count = 10;
118 if (--count > 0) {
119 error(bDANGER, "\n");
120 }else{untested();
121 exit(1);
125 /*--------------------------------------------------------------------------*/
126 /* sig_int: what to do on receipt of interrupt signal (SIGINT)
127 * cancel batch files, then back to command mode.
128 * (actually, control-c trap)
130 extern "C" {
131 static void sig_int(SIGNALARGS)
133 signal(SIGINT,sig_int);
134 if (ENV::run_mode == rBATCH) {
135 exit(1);
136 }else{
137 IO::error << '\n';
138 siglongjmp(env.p,1);
142 /*--------------------------------------------------------------------------*/
143 extern "C" {
144 static void sig_fpe(SIGNALARGS)
146 untested();
147 signal(SIGFPE,sig_fpe);
148 error(bDANGER, "floating point error\n");
151 /*--------------------------------------------------------------------------*/
152 static void setup_traps(void)
154 signal(SIGFPE,sig_fpe);
155 signal(SIGINT,sig_int);
156 signal(SIGABRT,sig_abrt);
158 /*--------------------------------------------------------------------------*/
159 /* finish: clean up after a command
160 * deallocates space, closes plot windows, resets i/o redirection, etc.
161 * This is done separately for exception handling.
162 * If a command aborts, clean-up is still done, leaving a consistent state.
163 * //BUG// It is a function to call as a remnant of old C code.
164 * Should be in a destructor, so it doesn't need to be explicitly called.
166 static void finish(void)
168 plclose();
169 IO::mstdout.outreset();
171 /*--------------------------------------------------------------------------*/
173 static void do_getopt(int argc, char * const * argv)
175 int opt;
176 int nsecs, tfnd=0;
178 nsecs = 0;
179 while ((opt = getopt(argc, argv, "a:c:b:i:qt:")) != -1) {
180 switch (opt) {
181 case 'q':
182 OPT::quiet = true;
183 break;
184 case 't':
185 nsecs = atoi(optarg);
186 tfnd = 1;
187 break;
188 case 'a':
189 case 'b':
190 case 'c':
191 case 'i':
192 break;
193 default: /* '?' */
194 fprintf(stderr, "Usage: %s [-q] name\n", argv[0]); }
197 // printf("flags=%d; tfnd=%d; optind=%d, argc=%i\n", flags, tfnd, optind, argc);
199 if (optind > argc) {
200 fprintf(stderr, "Expected argument after options\n");
201 exit(EXIT_FAILURE);
203 USE(tfnd); USE(nsecs);
206 /*--------------------------------------------------------------------------*/
207 static void process_cmd_line(int argc, char *const *argv)
209 for (int ii = 1; ii < argc; /*inside*/) {
210 try {
211 if ( !strcasecmp(argv[ii], "-v") ){
212 // FIXME. use git hash for development versions.
213 cout << PACKAGE << " " << VERSION << endl;
214 exit(1);
215 } else if ( !strcasecmp(argv[ii], "-E")
216 || !strcasecmp(argv[ii], "-e") ) {
217 ++ii;
219 if (ii < argc) {
220 string v = "";
221 if ( !strcasecmp(argv[ii], "-E") )
222 v="verbose ";
223 // dashier startet den OPT::language modus
224 CMD::command(string("expect ") + v + argv[ii++], &CARD_LIST::card_list);
225 } else {
226 incomplete();
228 }else if (strcasecmp(argv[ii], "-q") == 0) {
229 ++ii;
230 // doesnt do anything.
231 }else if (strcasecmp(argv[ii], "-i") == 0) {
232 ++ii;
233 if (ii < argc) {
234 CMD::command(std::string("include ") + argv[ii++], &CARD_LIST::card_list);
235 }else{untested();
237 }else if (strcasecmp(argv[ii], "-c") == 0) { itested();
238 ++ii;
239 if (ii < argc) { itested();
240 CS cmd(CS::_STRING, argv[ii++]); // command line
241 CMD::cmdproc(cmd, &CARD_LIST::card_list);
242 }else{untested();
244 }else if (strcasecmp(argv[ii], "-b") == 0) {
245 try {
246 ++ii;
247 // set languacge to spice (since we have defined acs as default.
248 // this is a hack and might be a bug as well.
249 CMD::command("spice", &CARD_LIST::card_list);
250 if (ii < argc) {
251 // dashier startet den OPT::language modus
252 trace2("-b...", OPT::language, argv[ii]);
253 CMD::command(std::string("< ") + argv[ii++], &CARD_LIST::card_list);
254 }else{untested();
255 CMD::command(std::string("< /dev/stdin"), &CARD_LIST::card_list);
257 }catch (Exception& e) {
258 error(bDANGER, e.message() + '\n');
259 throw(Exception("error processing batch file"));
260 finish();
262 if (ii >= argc) {
263 CMD::command("end", &CARD_LIST::card_list);
264 }else{untested();
266 }else if (strcasecmp(argv[ii], "-a") == 0) { itested();
267 ++ii;
268 if (ii < argc) { itested();
269 CMD::command(std::string("attach ") + argv[ii++], &CARD_LIST::card_list);
270 }else{untested();
272 }else{
273 CMD::command(std::string("include ") + argv[ii++], &CARD_LIST::card_list);
275 }catch (Exception& e) {
276 // hmmm
277 throw(e);
281 /*--------------------------------------------------------------------------*/
282 int main(int argc, char * const * argv)
284 CKT_BASE::_sim = new SIM_DATA;
285 CKT_BASE::_probe_lists = new PROBE_LISTS;
286 ENV::error = 0;
288 // parse -v and -q _now_
289 do_getopt(argc,argv);
290 // sigsetjmp unneeded here (isnt it?)
292 // FIXME: use getopt
294 CMD::command("options lang=acs", &CARD_LIST::card_list);
295 assert(OPT::language);
296 read_startup_files();
297 sign_on();
300 SET_RUN_MODE xx(rBATCH);
301 trace0("batch mode");
302 if (!sigsetjmp(env.p, true)) {
303 try {
304 trace0("... ");
305 setup_traps();
306 trace0("done traps");
307 process_cmd_line(argc,argv);
308 trace0("done cmdline mode");
309 }catch (Exception& e) {
310 ENV::error++;
311 std::cerr << e.message() << std::endl;
312 finish(); /* error clean up (from longjmp()) */
313 CMD::command("quit", &CARD_LIST::card_list);
314 unreachable();
315 exit(1);
317 }else{
318 trace0("finish batch");
319 finish(); /* error clean up (from longjmp()) */
320 CMD::command("quit", &CARD_LIST::card_list);
321 exit(0);
325 SET_RUN_MODE xx(rINTERACTIVE);
326 trace0("interactive mode");
327 CS cmd(CS::_STDIN);
328 for (;;) {
329 if (!sigsetjmp(env.p, true)) {
330 try {
331 if (OPT::language) {
332 OPT::language->parse_top_item(cmd, &CARD_LIST::card_list);
333 }else{
334 CMD::cmdproc(cmd.get_line(I_PROMPT), &CARD_LIST::card_list);
336 }catch (Exception_End_Of_Input& e) {
337 error(bDANGER, e.message() + '\n');
338 finish();
339 CMD::command("quit", &CARD_LIST::card_list);
340 exit(0);
341 }catch (Exception& e) {
342 error(bDANGER, e.message() + '\n');
343 ENV::error++;
344 finish();
346 }else{
347 finish(); /* error clean up (from longjmp()) */
351 unreachable();
352 return 1;
354 /*--------------------------------------------------------------------------*/
355 /*--------------------------------------------------------------------------*/
356 // vim:ts=8:sw=2:et: