1 /***************************************************************************
2 gdlhelp.cpp - GDL help procedure
3 -------------------
4 begin : July 22 2002
5 copyright : (C) 2002 by Marc Schellens
6 email : m_schellens@users.sf.net
7
8 - Numerous enhancements by Alain Coulais
9 - May 2015 code cleanup by Greg Jung:
10 * gdlhelp.cpp, gdlhelp.hpp for HELP and DELVAR
11 * OUTPUT= and NAMES= keywords implemented for help.
12 * /COMMON to list all common blocks anywhere
13 * Undefined variables normally not listed.
14 ***************************************************************************/
15
16 /***************************************************************************
17 * *
18 * This program is free software; you can redistribute it and/or modify *
19 * it under the terms of the GNU General Public License as published by *
20 * the Free Software Foundation; either version 2 of the License, or *
21 * (at your option) any later version. *
22 * *
23 ***************************************************************************/
24
25 #include "includefirst.hpp"
26
27 #include <sys/types.h>
28
29 #include <string>
30 #include <fstream>
31 #include <memory>
32
33 #include <set>
34 #include <iterator>
35
36 #ifndef _WIN32
37 //#include <regex.h> // stregex
38 #include <fnmatch.h>
39
40 #else
41 #include <shlwapi.h>
42 #endif
43
44 #ifndef _WIN32
45 #include <termios.h>
46 #include <unistd.h>
47 #endif
48
49 // used to defined GDL_TMPDIR: may have trouble on MSwin, help welcome
50 #ifndef _WIN32
51 #include <paths.h>
52 #endif
53
54
55 #ifndef _MSC_VER
56 # include <dirent.h>
57 #else
58 // MSC workaround implementation in file.cpp
59 /*
60 Declaration of POSIX directory browsing functions and types for Win32.
61
62 Author: Kevlin Henney (kevlin@acm.org, kevlin@curbralan.com)
63 History: Created March 1997. Updated June 2003.
64 Rights: See end of file.
65 */
66 extern "C" {
67
68 typedef struct DIR DIR;
69
70 struct dirent {
71 char *d_name;
72 };
73
74 DIR *opendir(const char *);
75 int closedir(DIR *);
76 struct dirent *readdir(DIR *);
77 void rewinddir(DIR *);
78
79 /*
80 Copyright Kevlin Henney, 1997, 2003. All rights reserved.
81
82 Permission to use, copy, modify, and distribute this software and its
83 documentation for any purpose is hereby granted without fee, provided
84 that this copyright and permissions notice appear in all copies and
85 derivatives.
86
87 This software is supplied "as is" without express or implied warranty.
88
89 But that said, if there are any problems please get in touch.
90 */
91
92 } // extern "C"
93 #endif
94
95 #if 0
96 #ifdef __APPLE__
97 # include <crt_externs.h>
98 # define environ (*_NSGetEnviron())
99 #else
100 #ifdef _WIN32
101 #include <direct.h>
102 #include <io.h>
103 #define R_OK 4 /* Test for read permission. */
104 #define W_OK 2 /* Test for write permission. */
105 #define F_OK 0 /* Test for existence. */
106 #else
107 #include <unistd.h>
108 #endif
109 #endif
110 #endif
111
112
113 #include "dinterpreter.hpp"
114 #include "datatypes.hpp"
115 #include "envt.hpp"
116 #include "dpro.hpp"
117
118
119 #include "graphicsdevice.hpp"
120 #include "dcommon.hpp"
121 #include "dpro.hpp"
122
123 #include "gdlhelp.hpp"
124 #include "nullgdl.hpp"
125 #include "terminfo.hpp"
126
127
128 // for sorting compiled pro/fun lists by name
129 struct CompFunName: public std::binary_function< DFun*, DFun*, bool>
130 {
operator ()CompFunName131 bool operator() ( DFun* f1, DFun* f2) const
132 {
133 return f1->ObjectName() < f2->ObjectName();
134 }
135 };
136
137 struct CompProName: public std::binary_function< DPro*, DPro*, bool>
138 {
operator ()CompProName139 bool operator() ( DPro* f1, DPro* f2) const
140 {
141 return f1->ObjectName() < f2->ObjectName();
142 }
143 };
144
CompareWithJokers(string names,string sourceFiles)145 static bool CompareWithJokers(string names, string sourceFiles) {
146
147 #ifdef _WIN32
148 WCHAR wnames[MAX_PATH];
149 WCHAR wsourceFiles[MAX_PATH];
150
151 const char* cnames = names.c_str();
152 const char* csourceFiles = sourceFiles.c_str();
153
154 MultiByteToWideChar(CP_UTF8, 0, cnames, -1,
155 (LPWSTR) wnames, MAX_PATH);
156 MultiByteToWideChar(CP_UTF8, 0, csourceFiles, -1,
157 (LPWSTR) wsourceFiles, MAX_PATH);
158 int match = 1 - PathMatchSpecW(wsourceFiles, wnames);
159 #else
160 int match = fnmatch(names.c_str(), sourceFiles.c_str(), 0 );
161 #endif
162 if ( match == 0) return true;
163 else return false;
164 }
165 extern GDLFileListT fileUnits;
166
167 using namespace std;
168 // (static = internal) helper routines serving the lib:: routines called out in
169 // gdlhelper.hpp
170
171
help_files(ostream & os,EnvT * e)172 static void help_files(ostream& os, EnvT* e) {
173 // AC 2020-04-28
174 // see https://github.com/gnudatalanguage/gdl/issues/743
175 // pb1 : why maxUserLun ?? pb2 : no return for -1, 0, 1
176 cout << " maxUserLun : " << maxUserLun << " fileUnits.size() : " << fileUnits.size() << '\n';
177
178 for( DLong lun=maxUserLun+1; lun <= fileUnits.size(); ++lun)
179 if( fileUnits[ lun-1].InUse() || fileUnits[ lun-1].GetGetLunLock())
180 {
181 os << " lun "<< lun << ": "+fileUnits[lun-1].Name() << '\n';
182 }
183 return;
184 }
185
186 // AC 2020-04-28 derivated work from get_kbrd().
187 // Not sure what happen without ReadLine
my_get_kbrd()188 char my_get_kbrd()
189 {
190 #if defined(HAVE_LIBREADLINE)
191 #include <readline/readline.h>
192 rl_prep_terminal (0);
193 #endif
194
195 char c='\0'; //initialize is never a bad idea...
196
197 int fd=fileno(stdin);
198 #ifndef _WIN32
199 struct termios orig, get;
200 #endif
201 // Get terminal setup to revert to it at end.
202 #ifndef _WIN32
203 (void)tcgetattr(fd, &orig);
204 // New terminal setup, non-canonical.
205 get.c_lflag = ISIG;
206 #endif
207 // will wait for a character
208 #ifndef _WIN32
209 get.c_cc[VTIME]=0;
210 get.c_cc[VMIN]=1;
211 (void)tcsetattr(fd, TCSANOW, &get);
212 #endif
213 cin.get(c);
214
215 // Restore original terminal settings.
216 #ifndef _WIN32
217 (void)tcsetattr(fd, TCSANOW, &orig);
218 #endif
219 #if defined(HAVE_LIBREADLINE)
220 rl_deprep_terminal ();
221 #endif
222 return c;
223 }
224
help_keys(ostream & ostr)225 static void help_keys(ostream& ostr)
226 {
227 ostr << "GDL is using Readline to manage keys shortcuts, few useful listed below." << '\n';
228 ostr << "A summary can be read here : http://www.bigsmoke.us/readline/shortcuts " << '\n';
229 ostr << '\n';
230 ostr << "Moving in the command line :"<< '\n';
231 ostr << " Ctrl-a : going to the beginning of the line"<< '\n';
232 ostr << " Ctrl-e : going to the end of the line"<< '\n';
233 ostr << " Ctrl-u : removing from here to the beginning of the line"<< '\n';
234 ostr << " Ctrl-k : removing from here to the end of the line"<< '\n';
235 ostr << " Ctrl-RightArrow : jumping one word on the right"<< '\n';
236 ostr << " Ctrl-LeftArrow : jumping one word on the left"<< '\n';
237 ostr << '\n';
238 ostr << "Moving in the history :"<< '\n';
239 ostr << " HELP, /recall : listing the whole history" << '\n';
240 ostr << " Ctrl-p or UpArrow : previous entry in history" << '\n';
241 ostr << " Ctrl-n or DownArrow : next entry in history" << '\n';
242 ostr << '\n';
243 return;
244 }
245
help_info()246 static void help_info()
247 {
248
249 cout << "* Homepage: https://gnudatalanguage.github.io/" << '\n';
250 cout << '\n';
251 cout << "* #NameOfRoutine for list of params and keywords"
252 " for a given NameOfRoutine (internal or compiled pro/func)" << '\n';
253 cout << '\n';
254 cout << "* ?NameOfRoutine for starting a browser to access online doc"
255 " for a given routine (if exists ! internal or compiled pro/func)" ;
256 cout << '\n'; cout << '\n';
257 cout << "* HELP, /INTERNAL_LIB_GDL for a list of all internal library "
258 "functions/procedures." << '\n';
259 cout << "* HELP, /LIB Additional subroutines are written in GDL language, "
260 "look for *.pro files (e.g. in CVS in src/pro/)." << '\n';
261 cout << '\n';
262 cout << "* HELP, /KEYS for useful CLI keys shortcuts." << '\n';
263 cout << '\n';
264 return;
265 }
help_sysvar(ostream & os,bool briefKW=true)266 static void help_sysvar(ostream& os , bool briefKW=true)
267 {
268 std::map<std::string, DVar*>list;
269 for (SizeT v = 0; v < sysVarList.size(); ++v) list.insert(std::pair<std::string, DVar*>(" !" +sysVarList[ v]->Name(), sysVarList[ v]));
270 if (briefKW) {
271 for (std::map<std::string, DVar*>::iterator it=list.begin(); it!=list.end(); ++it) { os << it->first << '\n';}
272 } else {
273 for (std::map<std::string, DVar*>::iterator it=list.begin(); it!=list.end(); ++it) {
274 DVar* v=it->second;
275 BaseGDL* var= v->Data();
276 lib::help_item(os, var , it->first, false);
277 }
278 }
279 return;
280 }
281
help_Output(BaseGDL ** outputKW,ostringstream & ostr,SizeT & nlines,bool doOutput=true)282 static void help_Output(BaseGDL** outputKW, ostringstream& ostr, SizeT &nlines, bool doOutput=true)
283 {
284 // Setup output return variable ostream& os, int &lines_count
285
286 std::string s = ostr.rdbuf()->str().erase(ostr.rdbuf()->str().length(),1);
287 char delimiter = '\n';
288 SizeT nOut = 0;
289 size_t found=0;
290 if(doOutput) {
291
292 do {
293 ++nOut;
294 found=s.find( delimiter,found);
295 } while( (found++ != std::string::npos) );
296
297 nlines = --nOut; if(nlines == 0) return;
298 if (*outputKW!=NULL) GDLDelete((*outputKW));
299 dimension dim(&nlines, (size_t) 1);
300 *outputKW = new DStringGDL(dim, BaseGDL::NOZERO);
301 }
302 size_t pos = 0;
303 nOut = 0;
304 std::string token;
305 while ((found = s.find(delimiter,pos)) != std::string::npos) {
306 token = s.substr(pos, found-pos);
307 if( doOutput and (nOut not_eq nlines)) (*(DStringGDL *) *outputKW)[nOut] = token;
308 else cout << token << '\n';
309 ++nOut;
310 pos = found+1;
311 }
312 ostr.str("");
313 // if( nOut not_eq nlines and debug) cout <<
314 // " help_Output: Error counting lines -" <<
315 // " nOut: "<<nOut<<" OutputLines:"<<nlines<<'\n';
316 }
317
318 // showing HELP, /path_cache
help_path_cached(ostream & ostr,SizeT & lines_count)319 void help_path_cached(ostream& ostr, SizeT &lines_count) {
320
321 struct dirent *dp;
322 const char *ProSuffix = ".pro";
323 int ProSuffixLen = strlen(ProSuffix);
324
325 string tmp_fname;
326 size_t found;
327
328 StrArr path = SysVar::GDLPath();
329
330 std::sort(path.begin(),path.end());
331 ostr << "!PATH (Disabled, "<< path.size() <<" directories)" << '\n';
332 lines_count = 1;
333
334 for (StrArr::iterator CurrentDir = path.begin(); CurrentDir != path.end(); ++CurrentDir) {
335 // cout << "1>>" << (*CurrentDir).c_str() << "<<" <<'\n';
336 DIR* dirp = opendir((*CurrentDir).c_str());
337 //cout << "2>>" << dirp << "<<" <<'\n';
338 if (dirp != NULL) {
339 int NbProFilesInCurrentDir = 0;
340 while ((dp = readdir(dirp)) != NULL) {
341 tmp_fname = dp->d_name;
342 found = tmp_fname.rfind(ProSuffix);
343 if (found != std::string::npos) {
344 if ((found + ProSuffixLen) == tmp_fname.length())
345 ++NbProFilesInCurrentDir;
346 }
347 }
348 closedir(dirp);
349 ++lines_count;
350 ostr << *CurrentDir << " (" << NbProFilesInCurrentDir << " files)" << '\n';
351 }
352 }
353 }
354
355 // a simplification of codes (DebugMsg & DumpStack) in GDLInterpreter.cpp
356 // ProgNodeP cN = e->CallingNode();
357 // DInterpreter::DebugMsg(cN, "At ");
358 // DInterpreter::DumpStack(3);
359
SimpleDumpStack(EnvT * e,ostream & ost=std::cerr)360 static void SimpleDumpStack(EnvT* e, ostream& ost=std::cerr) {
361
362 EnvStackT& callStack = e->Interpreter()->CallStack();
363
364 // simple way to manage the first line : exception
365 SizeT w = 0;
366 string msgPrefix = "% At ";
367
368 long actIx = callStack.size() - 1;
369 for (; actIx >= 0; --actIx) {
370 EnvStackT::pointer_type upEnv = callStack[actIx];
371
372 ost << msgPrefix << std::right << std::setw(w) << "";
373 // simple way to manage the first line : exception
374 msgPrefix = "";
375 w = 5;
376 ost << std::left << std::setw(16) << upEnv->GetProName();
377
378 std::string file = upEnv->GetFilename();
379 if (file != "") {
380 int lineNumber = upEnv->GetLineNumber();
381 if (lineNumber != 0) {
382 ost << std::right << std::setw(6) << lineNumber;
383 } else {
384 ost << std::right << std::setw(6) << "";
385 }
386 ost << std::left << " " << file;
387 }
388 ost << '\n';
389 }
390 return;
391 }
help_object(std::ostream * ostrp,DStructDesc * objDesc,bool verbose=false)392 static void help_object(std::ostream* ostrp, DStructDesc* objDesc, bool verbose = false)
393 {
394 FunListT& funlist = objDesc->FunList();
395 ProListT& prolist = objDesc->ProList();
396 int num_methods = funlist.size() + prolist.size();
397 int numpar = objDesc->GetNumberOfParents();
398 if (numpar==1) *ostrp << "** Object class " << objDesc->Name() << ", " << numpar << " direct superclass, " << num_methods << " known methods" << '\n';
399 else *ostrp << "** Object class " << objDesc->Name() << ", " << numpar << " direct superclasses, " << num_methods << " known methods" << '\n';
400 if (numpar > 0) {
401 *ostrp << " Superclasses:\n";
402 std::set< std::string> pNames;
403 objDesc->GetParentNames(pNames);
404 for (std::set<string>::iterator j = pNames.begin(); j != pNames.end(); ++j) *ostrp << " " << (*j) << " <Direct>\n";
405 //find all ancestors
406 pNames.clear();
407 objDesc->GetAncestorsNames(pNames);
408 for (std::set<string>::iterator j = pNames.begin(); j != pNames.end(); ++j) *ostrp << " " << (*j) << "\n";
409 }
410 if (num_methods > 0) {
411 if (funlist.size() > 0) {
412 *ostrp << " Known Function Methods:\n";
413 for (int j = 0; j < funlist.size(); ++j) *ostrp << " " << objDesc->Name() << "::" << funlist[j]->Name() << "\n";
414 }
415 if (prolist.size() > 0) {
416 *ostrp << " Known Procedure Methods:\n";
417 for (int j = 0; j < prolist.size(); ++j) *ostrp << " " << objDesc->Name() << "::" << prolist[j]->Name() << "\n";
418 }
419
420 if (!verbose) return;
421 DStructGDL* dumm = new DStructGDL(objDesc, dimension());
422 Guard<DStructGDL> guard(dumm);
423 lib::help_struct(*ostrp, dumm, 0, false);
424 }
425 }
426
help_ListLib(const DString names,ostream & ostr,bool internal=true)427 static void help_ListLib(const DString names, ostream& ostr, bool internal=true)
428 {
429 bool searchbyname;
430 searchbyname = (names != "");
431 vector<DString> subList;
432 // for( libProListT::iterator i=libProList.begin(); i != libProList.end(); i++)
433 for( SizeT i = 0; i<libProList.size(); ++i) {
434 if( internal == libProList[ i]->GetHideHelp()) {
435 if(searchbyname and not
436 CompareWithJokers(names, libProList[i]->Name())) continue;
437 subList.push_back(libProList[ i]->ToString());
438 }
439 }
440 sort( subList.begin(), subList.end());
441 if(internal) ostr << "Internal l";
442 else ostr << "L";
443 ostr << "ibrary procedures ("
444 << subList.size() <<"):" << '\n';
445 for( SizeT i = 0; i<subList.size(); ++i)
446 ostr << subList[ i] << '\n';
447
448 subList.clear();
449
450 // for( libFunListT::iterator i=libFunList.begin(); i != libFunList.end(); i++)
451 for( SizeT i = 0; i<libFunList.size(); ++i)
452 {
453 if( internal == libFunList[ i]->GetHideHelp()) {
454 if(searchbyname and not
455 CompareWithJokers(names, libFunList[i]->Name())) continue;
456 subList.push_back(libFunList[ i]->ToString());
457 }
458 }
459 sort( subList.begin(), subList.end());
460
461 if(internal) ostr << "Internal l";
462 else ostr << "L";
463 ostr << "ibrary functions ("
464 << subList.size() <<"):" << '\n';
465 for( SizeT i = 0; i<subList.size(); ++i)
466 ostr << subList[ i] << '\n';
467 subList.clear();
468
469 }
470
help_heap_obj_ptr_head(EnvT * e,ostream & ostr)471 static void help_heap_obj_ptr_head(EnvT* e, ostream& ostr)
472 {
473 SizeT numPtr = e->Interpreter()->HeapSize();
474 SizeT numObj = e->Interpreter()->ObjHeapSize();
475 ostr << "Heap Variables:" << '\n';
476 ostr << " # Pointer: " << numPtr << '\n';
477 ostr << " # Object : " << numObj << '\n'<<'\n';
478 }
479
480
help_mix_heap_and_obj(EnvT * e,ostream & ostr)481 static void help_mix_heap_and_obj(EnvT* e, ostream& ostr)
482 {
483 std::vector<DObj>* objheap = e->Interpreter()->GetAllObjHeapSTL();
484 Guard< std::vector<DObj> > heap_objguard(objheap);
485 SizeT nobjH = objheap->size();
486 std::vector<DPtr>* heap = e->Interpreter()->GetAllHeapSTL();
487 Guard< std::vector<DPtr> > heap_guard(heap);
488 SizeT nH = heap->size();
489 SizeT tot=nH+nobjH;
490 if (tot <= 0) return;
491 // objHeap and heap contain different, globally increasing, integers.
492 // to show them in incresing order like in IDL one needs to put them in an ordered fashion:
493 std::set<DPtr> myHeapIndex;
494 SizeT k=0;
495 for (SizeT i=0; i<nobjH; ++i) myHeapIndex.insert((*objheap)[i]);
496 for (SizeT i=0; i<nH; ++i) myHeapIndex.insert((*heap)[i]);
497
498 std::set<DPtr>::iterator it;
499 for (it = myHeapIndex.begin(); it!=myHeapIndex.end(); ++it) {
500 DPtr h=(*it);
501 if (e->Interpreter()->ObjValid(h))
502 {
503 BaseGDL* hV = BaseGDL::interpreter->GetObjHeap(h);
504 SizeT refc = BaseGDL::interpreter->RefCountHeapObj(h);
505 lib::help_item(ostr, hV, DString("<ObjHeapVar") + i2s(h) + "> refcount=" + i2s(refc), false);
506 } else {
507 if (e->Interpreter()->PtrValid(h))
508 {
509 BaseGDL* hV = BaseGDL::interpreter->GetHeap(h);
510 SizeT refc = BaseGDL::interpreter->RefCountHeap(h);
511 lib::help_item(ostr, hV, DString("<PtrHeapVar") + i2s(h) + "> refcount=" + i2s(refc), false);
512 }
513 }
514 }
515 return;
516 }
517
518
help_lastmsg(EnvT * e)519 static void help_lastmsg(EnvT* e)
520 {
521 // if LAST_MESSAGE is present, it is the only output.
522 // All other kw are ignored *EXCEPT 'output'*.
523 BaseGDL** outputKW = NULL;
524
525 DStructGDL* errorState = SysVar::Error_State();
526 static unsigned msgTag = errorState->Desc()->TagIndex( "MSG");
527
528 static int outputIx = e->KeywordIx( "OUTPUT");
529 if (e->KeywordPresent( outputIx))
530 { // Setup output return variable
531 outputKW = &e->GetKW( outputIx);
532 GDLDelete((*outputKW));
533 *outputKW = static_cast<DStringGDL*>((errorState->GetTag( msgTag))
534 ->Convert2( GDL_STRING, BaseGDL::COPY));
535 return;
536 }
537 else {
538 cout << (*static_cast<DStringGDL*>( errorState->GetTag( msgTag)))[0]<< '\n';
539 return;
540 }
541 }
542
recall_commands_internal()543 static DStringGDL* recall_commands_internal()
544 {
545
546 #if defined(HAVE_LIBREADLINE)
547 // http://cnswww.cns.cwru.edu/php/chet/readline/history.html#IDX14
548 HIST_ENTRY **the_list;
549 // cout << "history_length" << history_length << '\n';
550 the_list = history_list();
551
552 if (the_list) {
553 DStringGDL* retVal = new DStringGDL(history_length, BaseGDL::NOZERO);
554 for (SizeT i = 0; i < history_length; ++i)
555 (*retVal)[history_length-i-1] = the_list[i]->line;
556 return retVal;
557 } else return new DStringGDL("");
558 #else
559 Message("RECALL_COMMANDS: nothing done, because compiled without READLINE");
560 return new DStringGDL("");
561 #endif
562 }
563
564 namespace lib {
565
566 using namespace std;
567
568
recall_commands(EnvT * e)569 BaseGDL* recall_commands( EnvT* e)
570 {
571 return recall_commands_internal();
572 }
573
574
575 // display help for one variable or one structure tag
576
help_item(ostream & ostr,BaseGDL * par,DString parString,bool doIndentation=false)577 void help_item(ostream& ostr,
578 BaseGDL* par, DString parString,
579 bool doIndentation = false)
580 {
581 static volatile bool debug(false);
582 if (debug and (par not_eq NULL)) {
583 cout << par->Type() << " :"
584 << par->TypeStr() << " :"
585 // << &par->TypeStr() << ": "
586 << parString << '\n';
587 }
588
589 if (doIndentation) ostr << " ";
590
591 // Name display
592 ostr.width(16);
593 ostr << left << parString;
594 if (parString.length() >= 16) {
595 ostr << '\n'; // for cmsv compatible output (uses help,OUTPUT)
596 ostr.width(doIndentation ? 19 : 16);
597 ostr << "";
598 }
599
600 // Type display (we have two "null" : defined !null and undefined variables ...
601 if (par == NULL) {
602 ostr << "UNDEFINED = <Undefined>" << '\n';
603 return;
604 }
605 if (par == NullGDL::GetSingleInstance()) {
606 ostr << "UNDEFINED = !NULL" << '\n';
607 return;
608 }
609 ostr.width(10);
610 bool doTypeString = true;
611
612 // Data display
613 if (par->Type() == GDL_STRUCT) {
614 ostr << par->TypeStr() << right;
615 if (!doIndentation) ostr << "= ";
616 doTypeString = false;
617
618 DStructGDL* s = static_cast<DStructGDL*> (par);
619 ostr << "-> ";
620 ostr << (s->Desc()->IsUnnamed() ? "<Anonymous>" : s->Desc()->Name());
621 ostr << " ";
622 } else if (par->Dim(0) == 0) {
623 if (par->Type() == GDL_STRING) {
624 ostr << par->TypeStr() << right;
625 if (!doIndentation) ostr << "= ";
626 doTypeString = false;
627
628 // trim string larger than $COLUMNS- characters
629 DString dataString = (*static_cast<DStringGDL*> (par))[0];
630 int ncols=max(39,TermWidth()-12-29); //29 as this is the position where the string is writte, 11 for '... plus blank on rght
631 ostr << "'" << StrMid(dataString, 0,ncols, 0) << "'";
632 if (dataString.length() > ncols) ostr << "...";
633 } else if (par->Type() == GDL_OBJ && par->StrictScalar()) {
634 DObj s = (*static_cast<DObjGDL*> (par))[0]; // is StrictScalar()
635 if (s != 0) // no overloads for null object
636 {
637 DStructGDL* oStructGDL = GDLInterpreter::GetObjHeapNoThrow(s);
638 if (oStructGDL != NULL) // if object not valid -> default behaviour
639 {
640 DStructDesc* desc = oStructGDL->Desc();
641 static DString listName("LIST");
642 if (desc->IsParent(listName)) {
643 ostr << desc->Name();
644
645 unsigned nListTag = desc->TagIndex("NLIST");
646 DLong nList = (*static_cast<DLongGDL*> (oStructGDL->GetTag(nListTag, 0)))[0];
647 ostr << left;
648 ostr << "<ID=";
649 ostr << i2s(s) << " N_ELEMENTS=" << i2s(nList) << ">";
650
651 doTypeString = false;
652 }
653 static DString hashName("HASH");
654 if (desc->IsParent(hashName)) {
655 ostr << desc->Name();
656
657 unsigned nListTag = desc->TagIndex("TABLE_COUNT");
658 DLong nList = (*static_cast<DLongGDL*> (oStructGDL->GetTag(nListTag, 0)))[0];
659 ostr << left;
660 ostr << "<ID=";
661 ostr << i2s(s) << " N_ELEMENTS=" << i2s(nList) << ">";
662
663 doTypeString = false;
664 }
665 }
666 }
667 }
668 if (doTypeString) {
669 ostr << par->TypeStr() << right;
670 if (!doIndentation) ostr << "= ";
671 doTypeString = false;
672
673 par->ToStream(ostr);
674 }
675 }
676
677 if (doTypeString) {
678 ostr << par->TypeStr() << right;
679 if (!doIndentation) ostr << "= ";
680 if (par->IsAssoc())
681 par->ToStream(ostr);
682 }
683
684 // Dimension display
685 if (par->Dim(0) != 0) ostr << par->Dim();
686
687 // End of line
688 ostr << '\n';
689 }
690
help_struct(ostream & ostr,BaseGDL * par,int indent=0,bool debug=false)691 void help_struct(ostream& ostr, BaseGDL* par, int indent = 0, bool debug = false)
692 {
693 // STRUCTURES
694 DStructGDL* s = static_cast<DStructGDL*> (par);
695 SizeT nTags = s->Desc()->NTags();
696
697 for (int i = 0; i < indent; ++i) ostr << " ";
698 ostr << "** Structure ";
699 ostr << (s->Desc()->IsUnnamed() ? "<Anonymous>" : s->Desc()->Name());
700 ostr << ", " << nTags << " tags";
701 if (indent == 0) {
702 ostr << ",memsize =" << s->Sizeof();
703 ostr << ", data length=" << s->NBytesToTransfer()
704 // << "/" << s->RealBytes() ; GJ has this but only applied here.
705 << "/" << s->SizeofTags();
706 }
707 ostr << ":" << '\n';
708
709 for (SizeT t = 0; t < nTags; ++t) {
710 for (int i = 0; i < indent; ++i) ostr << " ";
711 if (debug) ostr.width(18);
712 if (debug) ostr << "dbg: OFFSET=" << s->Desc()->Offset(t);
713 help_item(ostr, s->GetTag(t), s->Desc()->TagName(t), true);
714 // only one level visible in "help".
715 // if(s->GetTag(t)->Type() == GDL_STRUCT) help_struct(ostr, s->GetTag(t), indent+1);
716 }
717 // lines_count += nTags;
718 }
719 #if 0
720 void help_struct(ostream& ostr, DStructDesc* dsc)
721 {
722
723 SizeT nTags = dsc->NTags();
724 ostr << "** Structure ";
725 ostr << (dsc->IsUnnamed() ? "<Anonymous>" : dsc->Name());
726 ostr << ", " << nTags << " tags";
727 ostr << ",length =" << dsc->NBytes();
728 for (SizeT t=0; t < nTags; ++t) {
729 help_item( ostr, dsc->GetTag(t), dsc->TagName(t), true);
730 if(dsc->GetTag(t)->Type() == GDL_STRUCT)
731 help_struct(ostr, dsc->GetTag(t)->Desc());
732 }
733 ostr << ":" << '\n';
734 }
735 #endif
736
help_help(EnvT * e)737 void help_help(EnvT* e)
738 {
739 string inline_help[]={"Usage: "+e->GetProName()+", expr1, ..., exprN,",
740 " /ALL_KEYS, /BRIEF, /CALLS, /FUNCTIONS, /HELP, /INFO,",
741 " /INTERNAL_LIB_GDL, /KEYS, /LAST_MESSAGE, /LIB, /MEMORY,",
742 " NAMES=string_filter, OUTPUT=res, /PATH_CACHE, /FILES, ",
743 " /PREFERENCES, /PROCEDURES, /RECALL_COMMANDS, /ROUTINES,",
744 " /SOURCE_FILES, /STRUCTURES, /SYSTEM_VARIABLES, /TRACEBACK"};
745 int size_of_s = sizeof(inline_help) / sizeof(inline_help[0]);
746 e->Help(inline_help, size_of_s);
747 return;
748 }
749
SortAndPrintStream(ostringstream & oss)750 void SortAndPrintStream(ostringstream& oss) {
751 std::string delimiter = "\n";
752 std::string s = oss.rdbuf()->str().erase(oss.rdbuf()->str().length(), 1);
753 size_t pos = 0;
754 vector<std::string> stringList;
755
756 while ((pos = s.find(delimiter)) != std::string::npos) {
757 stringList.push_back(s.substr(0, pos));
758 s.erase(0, pos + delimiter.length());
759 }
760 oss.str("");
761 sort(stringList.begin(), stringList.end());
762 vector<std::string>::iterator it = stringList.begin();
763 while (it != stringList.end()) std::cout << *it++;
764 std::cout << '\n';
765 }
766
StreamToGDLString(ostringstream & oss,bool sorted=false)767 DStringGDL* StreamToGDLString(ostringstream& oss, bool sorted=false) {
768
769 std::string delimiter = "\n";
770 int nlines = 0;
771 size_t pos = 0;
772 while ((pos = oss.str().find(delimiter, pos + 1)) != std::string::npos) {
773 ++nlines;
774 }
775 if (!nlines) return new DStringGDL("");
776
777 dimension dim(nlines, (size_t) 1);
778 DStringGDL* out = new DStringGDL(dim, BaseGDL::NOZERO);
779
780 std::string s = oss.rdbuf()->str().erase(oss.rdbuf()->str().length(), 1);
781 pos = 0;
782 vector<std::string> stringList;
783 SizeT nOut = 0;
784
785 while ((pos = s.find(delimiter)) != std::string::npos) {
786 stringList.push_back(s.substr(0, pos));
787 s.erase(0, pos + delimiter.length());
788 }
789 oss.str("");
790
791 if (sorted) sort(stringList.begin(), stringList.end());
792 vector<std::string>::iterator it = stringList.begin();
793 while (it != stringList.end()) (*out)[nOut++] = *it++;
794
795 return out;
796 }
797
help_pro(EnvT * e)798 void help_pro(EnvT* e)
799 {
800 // in order of priority
801 bool kw = false;
802 static int lastmKWIx = e->KeywordIx("LAST_MESSAGE");
803 bool lastmKW = e->KeywordPresent(lastmKWIx);
804 if (lastmKW) {
805 help_lastmsg(e);
806 return;
807 }
808 SizeT nParam = e->NParam();
809
810 BaseGDL** outputKW = NULL;
811 static int outputIx = e->KeywordIx("OUTPUT");
812 bool doOutput = e->KeywordPresent(outputIx);
813
814 if (doOutput) { // Setup output return variable
815 outputKW = &e->GetKW(outputIx);
816 GDLDelete((*outputKW));
817 }
818 static SizeT OutputLines;
819 OutputLines = 0;
820
821 std::ostringstream ostr;
822 // Use mostly ostrp* << from here on and then push onto outputKW if need be.
823 std::ostream* ostrp = (doOutput) ? &ostr : &cout;
824
825 static int helpIx = e->KeywordIx("HELP");
826 if (e->KeywordSet(helpIx)) {
827 help_help(e);
828 return;
829 }
830
831 static int allkeysIx = e->KeywordIx("ALL_KEYS");
832 static int keysIx = e->KeywordIx("KEYS");
833 if (e->KeywordSet(allkeysIx) || e->KeywordSet(keysIx)) // ALL_KEYS is an obsolete keyword
834 {
835 help_keys(ostr);
836 if (doOutput) (*outputKW) = StreamToGDLString(ostr);
837 else cout << ostr.str();
838 return;
839 }
840
841 static volatile bool debugKW(false);
842 static int debugIx = e->KeywordIx("DEBUG");
843 if (e->KeywordSet(debugIx)) {
844 debugKW = !debugKW;
845 cout << " Help debug option set/reset: " << debugKW << '\n';
846 return;
847 }
848
849 static int pathIx = e->KeywordIx("PATH_CACHE");
850 if (e->KeywordSet(pathIx)) { // exercising two methods
851 help_path_cached(ostr, OutputLines);
852 if (debugKW) {
853 cout << OutputLines << '\n';
854 cout << "begin" << ostr.rdbuf()->str() << "end" << '\n';
855 }
856 help_Output(outputKW, ostr, OutputLines, doOutput);
857 return;
858 }
859 // if keyword /TraceBack then we return
860 static int tracebackKWIx = e->KeywordIx("TRACEBACK");
861 bool tracebackKW = e->KeywordSet(tracebackKWIx);
862
863 if (tracebackKW) {
864 SimpleDumpStack(e, ostr);
865 if (doOutput) (*outputKW) = StreamToGDLString(ostr);
866 else cout << ostr.str();
867 return;
868 }
869
870 static int briefKWIx = e->KeywordIx("BRIEF");
871 bool briefKW = e->KeywordSet(briefKWIx);
872 // briefKw should be default usage with DLM HEAP_VARIABLES
873 // also MESSAGES OBJECTS ROUTINES SOURCE_FILES STRUCTURES SYSTEM_VARIABLES
874 static int fullKWIx = e->KeywordIx("FULL");
875 bool fullKW = e->KeywordSet(fullKWIx);
876
877 // AC 14-08-11 : detailed info (display size, deep ...) are missing
878 static int deviceKWIx = e->KeywordIx("DEVICE");
879 bool deviceKW = e->KeywordPresent(deviceKWIx);
880 if (deviceKW) {
881 GraphicsDevice::ListDevice(ostr);
882 DString name = (*static_cast<DStringGDL*> (SysVar::D()->GetTag(SysVar::D()->Desc()->TagIndex("NAME"), 0)))[0];
883 ostr << "Current graphics device: " << name << '\n';
884 if (doOutput) (*outputKW) = StreamToGDLString(ostr, true);
885 else cout << ostr.str();
886 return;
887 }
888
889 static int heapIx = e->KeywordIx("HEAP");
890 if (e->KeywordSet(heapIx)) {
891 help_heap_obj_ptr_head(e, *ostrp);
892 if (briefKW) return;
893 help_mix_heap_and_obj(e, *ostrp);
894 if (doOutput) (*outputKW) = StreamToGDLString(ostr, true);
895 else SortAndPrintStream(ostr);
896 return;
897 }
898
899 static int namesIx = e->KeywordIx("NAMES");
900 bool isKWSetNames = e->KeywordPresent(namesIx);
901
902 static int sysvarIx = e->KeywordIx("SYSTEM_VARIABLES");
903 if (e->KeywordSet(sysvarIx)) {
904 help_sysvar(*ostrp, briefKW);
905 if (doOutput) (*outputKW) = StreamToGDLString(ostr, true);
906 else SortAndPrintStream(ostr);
907 return;
908 }
909 /*
910 OBJECTS
911 Set this keyword to display information on defined object classes.
912 * If no arguments are provided, all currently-defined object classes are shown.
913 * If arguments are provided, the definition of the object class
914 * for the heap variables referred to is displayed.
915
916 */
917 static int objectsIx = e->KeywordIx("OBJECTS");
918 if (e->KeywordSet(objectsIx)) {
919 if (nParam == 0) {
920 //sort alphabetically object names...
921 std::set< std::string> objNames;
922 for (SizeT i = 0; i < structList.size(); ++i) {
923 if ((structList[i]->FunList().size() + structList[i]->ProList().size()) == 0) continue;
924 objNames.insert(structList[i]->Name());
925 }
926 SizeT nObj = objNames.size();
927 if (nObj < 1) return;
928
929 //these are objects that have at least one method.
930 //sort alphabetically
931
932 for (std::set<string>::iterator iobj = objNames.begin(); iobj != objNames.end(); ++iobj) {
933 DStructDesc* objDesc = FindObjectInStructList(structList, *iobj);
934 if (objDesc != NULL) help_object(ostrp, objDesc, fullKW);
935 }
936 } else {
937 for (SizeT i = 0; i < nParam; ++i) {
938 BaseGDL*& par = e->GetPar(i);
939 if (par!=NULL && e->GetPar(i)->Type() == GDL_OBJ) {
940 DObjGDL* myObj = static_cast<DObjGDL*> (e->GetParDefined(i));
941 DStructDesc* objDesc = (BaseGDL::interpreter->GetObjHeap( (*myObj)[0]))->Desc();
942 if (objDesc != NULL) help_object(ostrp, objDesc, fullKW);
943 }
944 }
945 }
946 if (doOutput) (*outputKW) = StreamToGDLString(ostr, true);
947 return;
948 }
949
950 DString names = "";
951 if (isKWSetNames) {
952 e->AssureStringScalarKWIfPresent(namesIx, names);
953 // since routines and var. are stored in Maj, we convert ...
954 names = StrUpCase(names);
955 }
956
957 static int sourceFilesKWIx = e->KeywordIx("SOURCE_FILES");
958 bool sourceFilesKW = e->KeywordPresent(sourceFilesKWIx);
959
960 static int routinesKWIx = e->KeywordIx("ROUTINES");
961 bool routinesKW = e->KeywordSet(routinesKWIx);
962
963 static int ProceduresIx = e->KeywordIx("PROCEDURES");
964 bool isKWSetProcedures = e->KeywordSet(ProceduresIx);
965
966 static int FunctionsIx = e->KeywordIx("FUNCTIONS");
967 bool isKWSetFunctions = e->KeywordSet(FunctionsIx);
968
969
970 if (sourceFilesKW) {
971 if (!isKWSetFunctions) {
972 // AC 2018-01-09 : Duplicating the pro list to avoid messing up the order of "proList"
973 // otherwise, a call to HELP,/source created in future calls
974 // e.g. of crashing sequence : TEST_TV & HELP, /source & TEST_TV
975 //
976 ProListT proList_tmp;
977 proList_tmp = proList;
978 sort(proList_tmp.begin(), proList_tmp.end(), CompProName());
979 *ostrp << "Compiled Procedures:" << '\n';
980 *ostrp << "$MAIN$" << '\n';
981 OutputLines += 2;
982 for (SizeT i = 0; i < proList_tmp.size(); ++i) {
983 if (proList_tmp[i]->isHidden() and !fullKW) continue;
984 if (isKWSetNames and
985 !(CompareWithJokers(names, proList_tmp[i]->ObjectName()))) continue;
986 *ostrp << setw(25) << left << proList_tmp[i]->ObjectName() << setw(0);
987 *ostrp << proList_tmp[i]->GetFilename() << '\n';
988 }
989 }
990
991 if (!isKWSetProcedures) {
992 if (!isKWSetFunctions) *ostrp << '\n';
993 // AC 2018-01-09 : Duplicating the fun list to avoid messing up the order of "funList"
994 // see above in (do_pro).
995 FunListT funList_tmp;
996 funList_tmp = funList;
997 sort(funList_tmp.begin(), funList_tmp.end(), CompFunName());
998 *ostrp << "Compiled Functions:" << '\n';
999 ++OutputLines;
1000 for (SizeT i = 0; i < funList_tmp.size(); ++i) {
1001 if (funList_tmp[i]->isHidden() and !fullKW) continue;
1002 if (isKWSetNames and
1003 !(CompareWithJokers(names, funList_tmp[i]->ObjectName()))) continue;
1004 *ostrp << setw(25) << left << funList_tmp[i]->ObjectName() << setw(0);
1005 *ostrp << funList_tmp[i]->GetFilename() << '\n';
1006 ++OutputLines;
1007 }
1008 }
1009 if (doOutput) (*outputKW) = StreamToGDLString(ostr, true);
1010 else cout << ostr.str();
1011 return;
1012 }
1013
1014 // Compiled Procedures & Functions
1015
1016 vector<DString> fList;
1017 static volatile int npro = 0, nfun = 0;
1018 for (FunListT::iterator i = funList.begin(); i != funList.end(); ++i)
1019 if (fullKW or !((*i)->isHidden())) {
1020 fList.push_back((*i)->ObjectName());
1021 ++nfun;
1022 }
1023 sort(fList.begin(), fList.end());
1024 if (debugKW) cout << " #functions=" << nfun;
1025
1026 vector<DString> pList;
1027 pList.push_back("$MAIN$");
1028 for (ProListT::iterator i = proList.begin(); i != proList.end(); ++i)
1029 if (fullKW or !((*i)->isHidden())) {
1030 pList.push_back((*i)->ObjectName());
1031 ++npro;
1032 }
1033 sort(pList.begin(), pList.end());
1034 if (debugKW) cout << " #procedures=" << npro;
1035 if (debugKW) cout << " #env:" << e->Caller()->EnvSize() << '\n';
1036
1037 static int callsKWIx = e->KeywordIx("CALLS");
1038 bool callsKW = e->KeywordPresent(callsKWIx);
1039
1040 if (callsKW) {
1041
1042 // this is a code derived from SimpleDumpStack() above
1043 EnvStackT& callStack = e->Interpreter()->CallStack();
1044 long actIx = callStack.size() - 1;
1045 DStringGDL* retVal = new DStringGDL(dimension(actIx + 1), BaseGDL::NOZERO);
1046 SizeT rIx = 0;
1047 for (; actIx >= 0; --actIx) {
1048 EnvStackT::pointer_type upEnv = callStack[actIx];
1049 DString actString = upEnv->GetProName();
1050 std::string file = upEnv->GetFilename();
1051 if (file != "") {
1052 actString += " <" + file + "(";
1053 actString += i2s(upEnv->GetLineNumber(), 4);
1054 actString += ")>";
1055 }
1056 (*retVal)[rIx++] = actString;
1057 }
1058 e->SetKW(callsKWIx, retVal);
1059 return;
1060 }
1061 static int filesIx = e->KeywordIx("FILES");
1062 if (e->KeywordPresent(filesIx)) {
1063 help_files(ostr, e);
1064 if (doOutput) (*outputKW) = StreamToGDLString(ostr, true);
1065 else cout << ostr.str();
1066 return;
1067 }
1068
1069 static int infoIx = e->KeywordIx("INFO");
1070 if (e->KeywordSet(infoIx)) {
1071 kw = true;
1072 help_info();
1073 }
1074
1075 static int libIx = e->KeywordIx("LIB");
1076 // internal library functions
1077 static int INTERNAL_LIB_GDLIx = e->KeywordIx("INTERNAL_LIB_GDL");
1078 bool kwLibInternal = e->KeywordSet(INTERNAL_LIB_GDLIx);
1079 if (kwLibInternal) {
1080 cout << "NOTE: Internal subroutines are subject to change without notice." << '\n';
1081 cout << "They should never be called directly from a GDL program." << '\n';
1082 }
1083 if (e->KeywordSet(libIx)) {
1084 kw = true;
1085 help_ListLib(names, *ostrp, kwLibInternal);
1086 }
1087
1088 static int STRUCTURESIx = e->KeywordIx("STRUCTURES");
1089 bool isKWSetStructures = e->KeywordSet(STRUCTURESIx);
1090 static int RECALL_COMMANDSIx = e->KeywordIx("RECALL_COMMANDS");
1091 bool isKWSetRecall = e->KeywordSet(RECALL_COMMANDSIx);
1092 static int MEMORYIx = e->KeywordIx("MEMORY");
1093 bool isKWSetMemory = e->KeywordSet(MEMORYIx);
1094 static int PREFERENCESIx = e->KeywordIx("PREFERENCES");
1095 bool isKWSetPreferences = e->KeywordSet("PREFERENCES");
1096 if (isKWSetStructures) kw = true;
1097
1098 if ((isKWSetStructures or isKWSetRecall or isKWSetMemory or
1099 isKWSetPreferences) and (isKWSetProcedures or isKWSetFunctions))
1100 e->Throw("Conflicting keywords.");
1101
1102 if (isKWSetRecall) {
1103 DStringGDL *previous_commands;
1104 previous_commands = recall_commands_internal();
1105 SizeT nEl2 = previous_commands->N_Elements();
1106 cout << "Recall buffer length: " << nEl2 << '\n';
1107
1108 char ctmp;
1109 int nb_lines=TermHeight();
1110
1111 for (SizeT i = 0; i < nEl2; ++i) {
1112 if (isKWSetNames and
1113 !CompareWithJokers(names, (*previous_commands)[i])) continue;
1114 *ostrp << i + 1 << " " << (*previous_commands)[i] << '\n';
1115 if (( i > 0) && (i % (nb_lines-4)) == 0) {
1116 *ostrp << " < Press q or Q to quit, any key to continue, ? for help >" << '\n';
1117 ctmp=my_get_kbrd();
1118 nb_lines=TermHeight();
1119 if ((tolower(ctmp) == 'h') || (ctmp == '?')) {
1120 *ostrp << "--------------------------------------------------- " << '\n';
1121 *ostrp << "<space> Display next page of text." << '\n';
1122 *ostrp << "<return> Display next line of text. (TBD)" << '\n';
1123 *ostrp << "q or Q Quit" << '\n';
1124 *ostrp << "h, H, or ? Display this message." << '\n';
1125 *ostrp << "---------------------------------------------------" << '\n';
1126 ctmp=my_get_kbrd();
1127 nb_lines=TermHeight();
1128 }
1129 if (tolower(ctmp) == 'q') break;
1130 }
1131 }
1132
1133 GDLDelete(previous_commands);
1134 if (doOutput) (*outputKW) = StreamToGDLString(ostr);
1135 else cout << ostr.str();
1136 return;
1137 }
1138 if (isKWSetMemory) {
1139 ostr << "heap memory used: ";
1140 ostr << MemStats::GetCurrent();
1141 ostr << ", max: ";
1142 ostr << MemStats::GetHighWater();
1143 ostr << ", gets: ";
1144 ostr << MemStats::GetNumAlloc();
1145 ostr << ", frees: ";
1146 ostr << MemStats::GetNumFree() << '\n';
1147 if (doOutput) (*outputKW) = StreamToGDLString(ostr);
1148 else cout << ostr.str();
1149 return;
1150 }
1151 if (isKWSetPreferences) {
1152 //cout << "ici 1 " << isKWSetPreferences << '\n';
1153 *ostrp << "Preferences: this is not ready ..." << '\n';
1154 //*ostrp << GDL_GR_X_QSCREEN::GetValue();
1155 if (doOutput) help_Output(outputKW, ostr, OutputLines);
1156
1157 return;
1158 }
1159 // switch to dec output (might be changed from formatted output)
1160
1161 if (!doOutput) cout << dec;
1162
1163 if ((nParam == 0 and !isKWSetMemory) or
1164 isKWSetFunctions or isKWSetProcedures) {
1165
1166 if (nParam == 0 and !isKWSetFunctions and
1167 !isKWSetProcedures and !routinesKW)
1168 SimpleDumpStack(e, *ostrp);
1169
1170 if (isKWSetProcedures or routinesKW) {
1171 *ostrp << "Compiled Procedures:" << '\n' << "$MAIN$" << '\n';
1172 OutputLines += 2;
1173 for (SizeT i = 1; i < pList.size(); ++i) {
1174
1175 // Find DPro pointer for pList[i]
1176 ProListT::iterator p = std::find_if(proList.begin(), proList.end(),
1177 Is_eq<DPro>(pList[i]));
1178 if (p == proList.end()) continue;
1179 DPro *pro = *p;
1180
1181 if (isKWSetNames and
1182 !CompareWithJokers(names, pro->ObjectName())) continue;
1183 *ostrp << setw(25) << left << pro->ObjectName() << setw(0);
1184
1185 int nPar = pro->NPar();
1186 int nKey = pro->NKey();
1187 // Loop through parameters and keywords
1188 for (SizeT j = 0; j < pro->NPar(); ++j)
1189 *ostrp << StrLowCase(pro->GetVarName(nKey + j)) << " ";
1190 for (SizeT j = 0; j < pro->NKey(); ++j)
1191 *ostrp << StrUpCase(pro->GetVarName(j)) << " ";
1192 *ostrp << '\n';
1193 ++OutputLines;
1194 }
1195 }
1196
1197 if (isKWSetFunctions or routinesKW) {
1198 *ostrp << "Compiled Functions:" << '\n';
1199 ++OutputLines;
1200 // Loop through functions
1201 for (SizeT i = 0; i < fList.size(); ++i) {
1202 // Find DFun pointer for fList[i]
1203 FunListT::iterator p = std::find_if(funList.begin(), funList.end(),
1204 Is_eq<DFun>(fList[i]));
1205 if (p == funList.end()) continue;
1206 DFun *pro = *p;
1207 if (isKWSetNames and
1208 !CompareWithJokers(names, pro->ObjectName())) continue;
1209 int nPar = pro->NPar();
1210 int nKey = pro->NKey();
1211 *ostrp << setw(25) << left << pro->ObjectName() << setw(0);
1212
1213 for (SizeT j = 0; j < nPar; ++j)
1214 *ostrp << StrLowCase(pro->GetVarName(nKey + j)) << " ";
1215 for (SizeT j = 0; j < nKey; ++j)
1216 *ostrp << StrUpCase(pro->GetVarName(j)) << " ";
1217 *ostrp << '\n';
1218 OutputLines++;
1219 }
1220 }
1221 if (isKWSetProcedures or isKWSetFunctions) {
1222 if (doOutput) help_Output(outputKW, ostr, OutputLines);
1223 return;
1224 }
1225 }
1226
1227 // Excluding keywords which are exclusive is not finished ...
1228
1229 if (isKWSetPreferences) {
1230 //cout << "ici 1 " << isKWSetPreferences << '\n';
1231 *ostrp << "Preferences: this is not ready ..." << '\n';
1232 //*ostrp << GDL_GR_X_QSCREEN::GetValue();
1233 if (doOutput) help_Output(outputKW, ostr, OutputLines);
1234
1235 return;
1236 }
1237 static int commonIx = e->KeywordIx("COMMON");
1238 if (e->KeywordSet(commonIx)) { // list in internal order
1239 CommonListT::iterator it;
1240 for (it = commonList.begin(); it != commonList.end(); ++it) {
1241 SizeT nVar = (*it)->NVar();
1242 if (nVar == 0) continue;
1243 *ostrp << " Common block (" << (*it)->Name() <<
1244 ") listed in internal order:" << '\n';
1245 for (SizeT vIx = 0; vIx < nVar; ++vIx) {
1246 DString parString = (*it)->VarName(vIx) + " (" + (*it)->Name() + ')';
1247 DVar* var = (*it)->Var(vIx);
1248 if (var->Data() not_eq NULL || fullKW)
1249 help_item(*ostrp, var->Data(), parString, false);
1250 }
1251 }
1252 if (doOutput) (*outputKW) = StreamToGDLString(ostr);
1253 else cout << ostr.str();
1254 if (nParam == 0) return;
1255 }
1256
1257 if (debugKW) std::cout << " help_pro: nParam=" << nParam;
1258 for (SizeT i = 0; i < nParam; ++i) {
1259 BaseGDL*& par = e->GetPar(i);
1260 DString parString = e->Caller()->GetString(par, true); //= string(" ??? ");
1261 if (debugKW) std::cout << ". ";
1262 if (par == NULL) {
1263 if (debugKW) std::cout << " par ==(NULL)" << '\n';
1264 if (!briefKW) help_item(ostr, par, parString, false);
1265 continue;
1266 }
1267
1268 // NON-STRUCTURES except if one and only one param is a Struct.
1269 if (par->Type() == GDL_STRUCT && !briefKW ) {
1270 if (((par->N_Elements()==1) && nParam==1 ) || isKWSetStructures) {
1271 help_struct(ostr, par, 0, debugKW);
1272 continue;
1273 }
1274 }
1275 help_item(ostr, par, parString, false);
1276 if (nParam != 1) continue;
1277 else if (par->Type() == GDL_OBJ and par->StrictScalar()) {
1278 DObj s = (*static_cast<DObjGDL*> (par))[0];
1279 DStructGDL* oStructGDL;
1280 if (s != 0) oStructGDL = GDLInterpreter::GetObjHeapNoThrow(s);
1281 if (s != 0 and (isKWSetStructures or fullKW))
1282 help_struct(ostr, oStructGDL, 0, debugKW);
1283 } else if (par->Type() == GDL_OBJ) {
1284 SizeT nObj = par->N_Elements();
1285 if (debugKW) std::cout << "nObj=" << nObj;
1286 for (SizeT iobj = 0; iobj < nObj; ++iobj) {
1287 if (debugKW) std::cout << "-";
1288 DObj s = (*static_cast<DObjGDL*> (par))[iobj];
1289 // object_help( ostr, s, false);
1290 DStructGDL* oStructGDL;
1291 DString classname;
1292 DString nameobj = " [" + i2s(iobj) + "] ";
1293 if (s != 0) {
1294 // Name display
1295 if (debugKW) std::cout << "-";
1296 std::vector< std::string> pNames;
1297 ostr.width(16);
1298 ostr << left << nameobj;
1299 oStructGDL = GDLInterpreter::GetObjHeapNoThrow(s);
1300 if (oStructGDL == NULL) continue;
1301 if (debugKW) std::cout << ".";
1302 classname = oStructGDL->Desc()->Name();
1303 oStructGDL->Desc()->GetParentNames(pNames);
1304 ostr.width(10);
1305 ostr << classname << right;
1306 ostr << left << "<ID=" << i2s(s) << "> " << right;
1307 DString parents;
1308 if (pNames.size() == 0) parents = "";
1309 else if (pNames.size() == 1) parents = " parent:";
1310 else parents = " parents:";
1311 ostr << left << parents;
1312 for (SizeT i = 0; i < pNames.size(); ++i) ostr << " " << pNames[i];
1313 ostr << '\n';
1314 } else
1315 help_item(ostr, NULL, nameobj, false);
1316 }
1317 }
1318
1319 }
1320 if (debugKW) std::cout << " :=:" << '\n';
1321 if (nParam > 0) {
1322 if (doOutput) (*outputKW) = StreamToGDLString(ostr);
1323 else cout << ostr.str();
1324 return;
1325 }
1326
1327
1328 static int levelIx = e->KeywordIx("LEVEL");
1329 if (e->KeywordPresent(levelIx)) {
1330 std::ostringstream parameters_ostringstream;
1331 DLongGDL* level = e->IfDefGetKWAs<DLongGDL>(levelIx);
1332
1333 //will list (all) variables, incl. common defined, at desired level.
1334 EnvStackT& callStack = e->Interpreter()->CallStack();
1335 DLong curlevnum = callStack.size();
1336 DLong desiredlevnum = curlevnum;
1337 if (level != NULL) {
1338 desiredlevnum = (*level)[0];
1339 if (desiredlevnum <= 0) desiredlevnum += curlevnum;
1340 if (desiredlevnum < 1) desiredlevnum = 0;
1341 if (desiredlevnum > curlevnum) desiredlevnum = curlevnum;
1342 }
1343
1344 DSubUD* pro = static_cast<DSubUD*> (callStack[desiredlevnum - 1]->GetPro());
1345
1346 SizeT nVar = pro->Size(); // # var in GDL for desired level
1347 SizeT nComm = pro->CommonsSize(); // # has commons?
1348 SizeT nTotVar = nVar + nComm; //All the variables availables at that lev.
1349 if (debugKW) cout << " Level section: nTotVar=" << nTotVar << '\n';
1350 if (nTotVar > 0) {
1351 set<string> helpStr; // "Sorted List"
1352 if (nVar > 0) {
1353 for (SizeT i = 0; i < nVar; ++i) {
1354 BaseGDL*& par = (static_cast<EnvUDT*> (callStack[desiredlevnum - 1]))->GetKW(i);
1355 if (par != NULL) {
1356 stringstream ss;
1357 string parName = pro->GetVarName(i);
1358 help_item(ss, par, parName, false);
1359 helpStr.insert(ss.str());
1360 }
1361 }
1362 }
1363
1364 if (nComm > 0) {
1365 DStringGDL* list = static_cast<DStringGDL*> (pro->GetCommonVarNameList());
1366 for (SizeT i = 0; i < list->N_Elements(); ++i) {
1367 BaseGDL** par = pro->GetCommonVarPtr((*list)[i]);
1368 DCommonBase* common = pro->FindCommon((*list)[i]);
1369 DString parName = (*list)[i] + " (" + common->Name() + ')';
1370 stringstream ss;
1371 help_item(ss, (*par), parName, false);
1372 helpStr.insert(ss.str());
1373 }
1374 }
1375 copy(helpStr.begin(), helpStr.end(), ostream_iterator<string>(parameters_ostringstream));
1376 }
1377 }
1378 // if /brief and /routines then no var. to be shown
1379 if (routinesKW and briefKW) kw = true;
1380
1381 if (nParam == 0 and !kw) {
1382 routinesKW = true;
1383 briefKW = true;
1384
1385 // list all variables of caller
1386 EnvBaseT* caller = e->Caller();
1387
1388 SizeT nEnv = caller->EnvSize();
1389
1390 //cout << "EnvSize() " << nEnv << '\n';
1391
1392 set<string> helpStr; // "Sorted List"
1393 stringstream ss;
1394
1395 for (int i = 0; i < nEnv; ++i) {
1396 BaseGDL*& par = caller->GetKW(i);
1397
1398 if (par == NULL && !fullKW) continue;
1399 // if( par == NULL) continue;
1400
1401 DString parString = caller->GetString(par, true);
1402 if (debugKW) cout << " GetKW(i)->GetString(par) " << parString;
1403 if (isKWSetNames and
1404 !CompareWithJokers(names, parString)) continue;
1405 help_item(ss, par, parString, false);
1406 helpStr.insert(ss.str());
1407 ss.str("");
1408 }
1409 if (debugKW) cout << '\n';
1410 std::vector<DCommonBase*> cptr;
1411 DSubUD* proUD = dynamic_cast<DSubUD*> (caller->GetPro());
1412 proUD->commonPtrs(cptr);
1413 std::vector<DCommonBase*>::iterator ic;
1414 for (ic = cptr.begin(); ic != cptr.end(); ++ic) {
1415 SizeT nVar = (*ic)->NVar();
1416 for (SizeT vIx = 0; vIx < nVar; ++vIx) {
1417 DString parString = (*ic)->VarName(vIx) + " (" + (*ic)->Name() + ')';
1418 if (isKWSetNames and
1419 !CompareWithJokers(names, parString)) continue;
1420 DVar* var = (*ic)->Var(vIx);
1421 if ((var->Data() not_eq NULL) || fullKW) {
1422 help_item(ss, var->Data(), parString, false);
1423 helpStr.insert(ss.str());
1424 ss.str("");
1425 }
1426 }
1427 }
1428
1429 copy(helpStr.begin(), helpStr.end(),
1430 ostream_iterator<string>(*ostrp));
1431 OutputLines += helpStr.size();
1432
1433 } // if( nParam == 0 and !kw)
1434 if (routinesKW and briefKW) {
1435 // Display compiled procedures & functions
1436 if (!isKWSetProcedures and !isKWSetFunctions) {
1437
1438 *ostrp << "Compiled Procedures:" << '\n';
1439 for (SizeT i = 0; i < pList.size(); ++i) *ostrp << pList[i] << " ";
1440 *ostrp << '\n' << '\n';
1441 *ostrp << "Compiled Functions:" << '\n';
1442 for (SizeT i = 0; i < fList.size(); ++i) *ostrp << fList[i] << " ";
1443 *ostrp << '\n';
1444 OutputLines += 4;
1445 }
1446 }
1447 if (doOutput) help_Output(outputKW, ostr, OutputLines);
1448 return;
1449 }
1450
1451 } // namespace
1452