Merge branch 'testing-uf' into master-uf
[gnucap-felix.git] / lib / ap_construct.cc
blob05d3d2b13d31723cf9ef0a76c52763c32e26a3ac
1 /* -*- 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 * construction, copy, etc.
25 #ifdef HAVE_CONFIG_H
26 # include "config.h"
27 #endif
29 #include "u_opt.h"
30 #include "ap.h"
31 #include <ios>
32 #include <iostream>
33 #include <fstream>
34 #include <vector>
35 #include <string>
36 #ifdef HAVE_BOOST
37 # include <boost/algorithm/string.hpp>
38 # include <boost/algorithm/string/split.hpp>
39 #endif
40 #include "u_lang.h"
42 #ifdef HAVE_LIBREADLINE
43 #include <readline/readline.h>
44 #include <readline/history.h>
45 #endif
46 /*--------------------------------------------------------------------------*/
47 // static std::string getlines(FILE*);
48 OMSTREAM mout; // > file bitmap //BUG//encapsulation
49 OMSTREAM mlog; // log file bitmap
50 /*--------------------------------------------------------------------------*/
51 CS::CS(CS::STDIN)
52 :_file(stdin),
53 _name(),
54 _cmd(),
55 _cnt(0),
56 _length(0),
57 _begin_match(0),
58 _end_match(0),
59 _ok(true),
60 _line_number(0)
63 #ifdef HAVE_LIBREADLINE
64 std::string gh = std::string(getenv("HOME")) + "/.gnucap_history";
65 char str[BUFLEN];
66 std::ifstream file;
67 file.open(gh.c_str());
68 if( file )
69 while(file.getline(str, BUFLEN)) {
70 add_history(str);
72 file.close();
73 #endif
75 // add history
78 CS::~CS()
80 if (_file==stdin){
84 if (is_file()) {fclose(_file);}
87 /*--------------------------------------------------------------------------
88 bool search_file( std::string &name ){
89 const char* h ="HOME";
90 const char* home= getenv(h);
92 if (name[0] == '/') return true; // fixme
94 std::string pathlist[4] = { OPT::libpath , "./", LIBDIR,
95 std::string(home) + std::string("/.gnucap/lib/") };
97 // FIXME. use libpath
99 for(int i=1; i<4 ; i++) {
100 if ( FILE* tmp = fopen( (pathlist[i] + "/" + name).c_str(), "r" ) ) {
101 fclose(tmp);
102 name = pathlist[i]+"/"+name;
103 return true;
105 trace0( (" not found " + pathlist[i] + "/" + name).c_str());
107 return false;
110 --------------------------------------------------------------------------*/
111 CS::CS(CS::INC_FILE, const std::string& name)
112 :_name(name),
113 _cmd(),
114 _cnt(0),
115 _length(0),
116 _begin_match(0),
117 _end_match(0),
118 _ok(true),
119 _line_number(0)
122 #ifdef HAVE_BOOST
123 if(name[0]=='/' || name[0]=='~')
124 #else
125 if(1)
126 #endif
128 trace0(("CS::CS(inc, absulute " + name).c_str());
129 _file = fopen(name.c_str(), "r");
130 }else{
132 std::vector< std::string > pathlist;
133 std::string includepath = OPT::includepath;
134 #ifdef HAVE_BOOST
135 boost::algorithm::split(pathlist, includepath, boost::is_any_of(":"));
136 for(std::vector< std::string >::iterator i=pathlist.begin(); i!=pathlist.end() ; ++i) {
137 std::string fn = (*i + "/" + name);
138 trace1("CS::CS inc, trying ", fn.c_str());
139 if (( _file = fopen( fn.c_str(), "r" ) ) ) {
140 break;
141 }else{
142 trace0("no file");
145 #endif
148 if (!_file) {itested();
149 throw Exception_File_Open(name + ':' + strerror(errno));
150 }else{
153 /*--------------------------------------------------------------------------*/
154 CS::CS(CS::WHOLE_FILE, const std::string& name)
155 :_file(NULL),
156 _name(name),
157 _cmd(),
158 _cnt(0),
159 _length(0),
160 _begin_match(0),
161 _end_match(0),
162 _ok(true),
163 _line_number(0)
165 int f = open(name.c_str(), O_RDONLY);
166 if (f == EOF) {itested();
167 throw Exception_File_Open(name + ':' + strerror(errno));
168 }else{
170 _length = static_cast<unsigned>(lseek(f, off_t(0), SEEK_END));
171 lseek(f, off_t(0), SEEK_SET);
173 char* cmd = new char[_length+2];
174 read(f, cmd, _length);
175 cmd[_length++] = '\0';
176 _cmd = cmd;
178 close(f);
180 /*--------------------------------------------------------------------------*/
181 CS::CS(CS::STRING, const std::string& s)
182 :_file(NULL),
183 _name(),
184 _cmd(s),
185 _cnt(0),
186 _length(static_cast<unsigned>(s.length())),
187 _begin_match(0),
188 _end_match(0),
189 _ok(true),
190 _line_number(0)
193 /*--------------------------------------------------------------------------*/
194 #if 0
195 CS::CS(const CS& p)
196 :_file(NULL),
197 _name(p._name),
198 _cmd(p._cmd),
199 _cnt(p._cnt),
200 _length(p._length),
201 _begin_match(0),
202 _end_match(0),
203 _ms(p._ms),
204 _ok(p._ok),
205 _line_number(0)
206 {untested();
208 #endif
209 /*--------------------------------------------------------------------------*/
210 CS& CS::operator=(const std::string& s)
211 {untested();
212 assert(!_file);
213 _cmd = s;
214 _cnt = 0;
215 _ok = true;
216 _length = static_cast<unsigned>(s.length());
217 return *this;
219 /*--------------------------------------------------------------------------*/
220 #if 0
221 CS& CS::operator=(const CS& p)
222 {untested();
223 assert(&p != this);
224 _name = p._name;
225 _file = p._file;
226 _cmd = p._cmd;
227 _cnt = p._cnt;
228 _ok = p._ok;
229 _length = p._length;
230 return *this;
232 #endif
233 /*--------------------------------------------------------------------------*/
234 bool CS::eat_lines()
237 bool ret=false;
239 skipbl();
240 while(_file && !tailsize()){
241 ret=true;
243 get_line( string());
244 skipbl();
247 return ret;
250 /*--------------------------------------------------------------------------*/
251 CS& CS::get_line(const std::string& prompt)
253 ++_line_number;
254 if (!_file) { // assume string or something
255 _cnt = 0;
256 _length = 0;
257 throw Exception_End_Of_Input("EOF on string/whatever");
258 }else if (is_file() ) {
259 assert(OPT::language);
260 // BUG!?
261 // CS must know its language.
262 _cmd = OPT::language->getlines(_file);
263 trace2("getlines got", _cmd, OPT::language->name());
264 _cnt = 0;
265 _length = static_cast<unsigned>(_cmd.length());
266 _ok = true;
267 }else{itested();
268 trace1("", _file);
269 assert(_file == stdin);
270 char cmdbuf[BUFLEN];
271 // trace0("CS::get_line " + std::string(cmdbuf));
272 getcmd(prompt.c_str(), cmdbuf, BUFLEN);
273 _cmd = cmdbuf;
274 _cnt = 0;
275 _length = static_cast<unsigned>(_cmd.length());
276 _ok = true;
279 if (OPT::listing) {
280 IO::mstdout << "\"" << fullstring() << "\"\n";
281 }else{
283 return *this;
285 /*--------------------------------------------------------------------------*/
286 /* getcmd: get a command.
287 * if "fin" is stdin, display a prompt first.
288 * Also, actually do logging, echo, etc.
290 char *getcmd(const char *prompt, char *buffer, int buflen)
292 assert(prompt);
293 assert(buffer);
294 if (isatty(fileno(stdin))) {
295 // stdin is keyboard
296 #ifdef HAVE_LIBREADLINE
297 if (OPT::edit) {
298 char* line_read = readline(prompt);
299 if (!line_read) {itested();
300 throw Exception_End_Of_Input("EOF on stdin");
301 }else{
303 // readline gets a new buffer every time, so copy it to where we want it
304 char* end_of_line = (char*)memccpy(buffer, line_read, 0, static_cast<size_t>(buflen-1));
305 if (!end_of_line) {
306 buffer[buflen-1] = '\0';
307 }else{
308 *end_of_line = '\0';
310 free(line_read);
312 if (*buffer) {
313 trace1("adding history", std::string(buffer));
314 add_history(buffer);
316 std::string gh = std::string(getenv("HOME")) + "/.gnucap_history";
317 std::ofstream file;
318 file.open(gh.c_str(),std::ios_base::app);
319 if( file )
320 file << buffer << "\n";
321 file.close();
323 }else{
325 }else
326 #endif
328 IO::mstdout << prompt; /* prompt & flush buffer */
329 if (!fgets(buffer, buflen, stdin)) {untested(); /* read line */
330 throw Exception_End_Of_Input("EOF on stdin");
331 }else{
334 (IO::mstdout - mout) << '\r'; /* reset col counter */
335 trim(buffer);
336 (mlog + mout) << buffer << '\n';
337 return buffer;
338 }else{
339 // stdin is file
340 if (!fgets(buffer, buflen, stdin)) {itested(); /* read line */
341 throw Exception_End_Of_Input("EOF on stdin");
342 }else{
344 trim(buffer);
345 (mlog + mout) << buffer << '\n';
346 return buffer;
349 /*--------------------------------------------------------------------------*/
350 static std::string getlines(FILE *fileptr)
352 assert(fileptr);
353 const int buffer_size = BIGBUFLEN;
354 std::string s;
356 bool need_to_get_more = true; // get another line (extend)
357 while (need_to_get_more) {
358 char buffer[buffer_size+1];
359 char* got_something = fgets(buffer, buffer_size, fileptr);
360 if (!got_something) { // probably end of file
361 need_to_get_more = false;
362 if (s == "") {
363 throw Exception_End_Of_Input("");
364 }else{untested();
366 }else{
367 trim(buffer);
368 size_t count = strlen(buffer);
369 if (buffer[count-1] == '\\') {
370 buffer[count-1] = '\0';
371 }else{
372 // look ahead at next line
373 //int c = fgetc(fileptr);
374 int c;
375 while (isspace(c = fgetc(fileptr))) {
376 // skip
378 if (c == '+') {
379 need_to_get_more = true;
380 }else if (c == '\n') {unreachable();
381 need_to_get_more = true;
382 ungetc(c,fileptr);
383 }else{
384 need_to_get_more = false;
385 ungetc(c,fileptr);
388 s += buffer;
389 s += ' ';
392 return s;
394 /*--------------------------------------------------------------------------*/
395 /*--------------------------------------------------------------------------*/
396 // vim:ts=8:sw=2:et: