Command history: Save in file before each execution to avoid to lose it in case of...
[scilab.git] / scilab / modules / history_manager / src / cpp / HistoryManager.cpp
1 /*
2 * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3 * Copyright (C) 2007-2008 - INRIA - Allan CORNET
4 * Copyright (C) 2010 - DIGITEO - Vincent COUVERT
5 * Copyright (C) 2011 - DIGITEO - Allan CORNET
6 *
7  * Copyright (C) 2012 - 2016 - Scilab Enterprises
8  *
9  * This file is hereby licensed under the terms of the GNU GPL v2.0,
10  * pursuant to article 5.3.4 of the CeCILL v.2.1.
11  * This file was originally licensed under the terms of the CeCILL v2.1,
12  * and continues to be available under such terms.
13  * For more information, see the COPYING file which you should have received
14  * along with this program.
15 *
16 */
17
18 /*------------------------------------------------------------------------*/
19 #include <iostream>
20 #include "HistoryManager.hxx"
21 /*------------------------------------------------------------------------*/
22 extern "C"
23 {
24 #include <stdio.h>
25 #include <string.h>
26 #include <stdlib.h>
27 #include "sciprint.h"
28 #include "sci_home.h"
29 #include "InitializeHistoryManager.h"
30 #include "TerminateHistoryManager.h"
31 #include "freeArrayOfString.h"
32 #include "os_string.h"
33 #include "CommandHistory_Wrap.h"
34 #include "localization.h"
35 #include "getCommentDateSession.h"
36 #include "sci_malloc.h"
37 #include "HistoryManager.h"
38 };
39 /*------------------------------------------------------------------------*/
40 #define MAXBUF  1024
41 /*------------------------------------------------------------------------*/
42 HistoryManager* HistoryManager::m_pHM = NULL;
43 /*------------------------------------------------------------------------*/
44 HistoryManager* HistoryManager::getInstance()
45 {
46     if (m_pHM == NULL)
47     {
48         m_pHM = new HistoryManager();
49
50         /* add date & time @ begin session */
51         char *commentbeginsession = getCommentDateSession(FALSE);
52         if (commentbeginsession)
53         {
54             appendLineToScilabHistory(commentbeginsession);
55             FREE(commentbeginsession);
56             commentbeginsession = NULL;
57         }
58
59         m_pHM->setToken("");
60
61     }
62     return m_pHM;
63 }
64 /*------------------------------------------------------------------------*/
65 void HistoryManager::killInstance(void)
66 {
67     if (m_pHM)
68     {
69         delete m_pHM;
70         m_pHM = NULL;
71     }
72 }
73 /*------------------------------------------------------------------------*/
74 BOOL historyIsEnabled(void)
75 {
76     return HistoryManager::historyIsEnabled();
77 }
78 /*------------------------------------------------------------------------*/
79 BOOL InitializeHistoryManager(void)
80 {
81     if (HistoryManager::getInstance())
82     {
83         return TRUE;
84     }
85     return FALSE;
86 }
87 /*------------------------------------------------------------------------*/
88 BOOL TerminateHistoryManager(void)
89 {
90     HistoryManager::getInstance()->killInstance();
91     return TRUE;
92 }
93 /*------------------------------------------------------------------------*/
94 BOOL setSearchedTokenInScilabHistory(char* _pstToken)
95 {
96     return HistoryManager::getInstance()->setToken(_pstToken);
97 }
98 /*------------------------------------------------------------------------*/
99 BOOL resetSearchedTokenInScilabHistory(void)
100 {
101     return HistoryManager::getInstance()->resetToken();
102 }
103 /*------------------------------------------------------------------------*/
104 char* getSearchedTokenInScilabHistory(void)
105 {
106     return HistoryManager::getInstance()->getToken();
107 }
108 /*------------------------------------------------------------------------*/
109 BOOL appendLineToScilabHistory(char* _pstLine)
110 {
111     return HistoryManager::getInstance()->appendLine(_pstLine);
112 }
113 /*------------------------------------------------------------------------*/
114 BOOL appendLinesToScilabHistory(char** _pstLines, int _iLines)
115 {
116     for (int i = 0 ; i < _iLines ; i++)
117     {
118         if (HistoryManager::getInstance()->appendLine(_pstLines[i]) == FALSE)
119         {
120             return FALSE;
121         }
122     }
123     return TRUE;
124 }
125 /*------------------------------------------------------------------------*/
126 void displayScilabHistory(void)
127 {
128     HistoryManager::getInstance()->displayHistory();
129 }
130 /*------------------------------------------------------------------------*/
131 BOOL saveScilabHistoryToFile()
132 {
133     return HistoryManager::getInstance()->writeToFile();
134 }
135 /*------------------------------------------------------------------------*/
136 BOOL writeScilabHistoryToFile(char* _pstFilename)
137 {
138     return HistoryManager::getInstance()->writeToFile(_pstFilename);
139 }
140 /*------------------------------------------------------------------------*/
141 BOOL loadScilabHistoryFromFile(char* _pstFilename)
142 {
143     return HistoryManager::getInstance()->loadFromFile(_pstFilename);
144 }
145 /*------------------------------------------------------------------------*/
146 BOOL isScilabHistoryTruncated(void)
147 {
148     return HistoryManager::getInstance()->isTruncated();
149 }
150 /*------------------------------------------------------------------------*/
151 BOOL setFilenameScilabHistory(char* _pstFilename)
152 {
153     return HistoryManager::getInstance()->setFilename(_pstFilename);
154 }
155 /*------------------------------------------------------------------------*/
156 char* getFilenameScilabHistory(void)
157 {
158     return HistoryManager::getInstance()->getFilename();
159 }
160 /*------------------------------------------------------------------------*/
161 BOOL setDefaultFilenameScilabHistory(void)
162 {
163     return HistoryManager::getInstance()->setDefaultFilename();
164 }
165 /*------------------------------------------------------------------------*/
166 BOOL resetScilabHistory(void)
167 {
168     return HistoryManager::getInstance()->reset();
169 }
170 /*------------------------------------------------------------------------*/
171 char** getAllLinesOfScilabHistory(void)
172 {
173     int iItems = 0;
174     return HistoryManager::getInstance()->getAllLines(&iItems);
175 }
176 /*------------------------------------------------------------------------*/
177 int getSizeAllLinesOfScilabHistory(void)
178 {
179     return HistoryManager::getInstance()->getNumberOfLines();
180 }
181 /*------------------------------------------------------------------------*/
182 char* getLastLineInScilabHistory(void)
183 {
184     return HistoryManager::getInstance()->getLastLine();
185 }
186 /*------------------------------------------------------------------------*/
187 char* getPreviousLineInScilabHistory(void)
188 {
189     return HistoryManager::getInstance()->getPreviousLine();
190 }
191 /*------------------------------------------------------------------------*/
192 char* getNextLineInScilabHistory(void)
193 {
194     return HistoryManager::getInstance()->getNextLine();
195 }
196 /*------------------------------------------------------------------------*/
197 int getNumberOfLinesInScilabHistory(void)
198 {
199     return HistoryManager::getInstance()->getNumberOfLines();
200 }
201 /*------------------------------------------------------------------------*/
202 void setSaveConsecutiveDuplicateLinesInScilabHistory(BOOL _bAllow)
203 {
204     HistoryManager::getInstance()->setSaveConsecutiveDuplicateLines(_bAllow);
205 }
206 /*------------------------------------------------------------------------*/
207 BOOL getSaveConsecutiveDuplicateLinesInScilabHistory(void)
208 {
209     return HistoryManager::getInstance()->getSaveConsecutiveDuplicateLines();
210 }
211 /*------------------------------------------------------------------------*/
212 void setAfterHowManyLinesScilabHistoryIsSaved(int _iNum)
213 {
214     HistoryManager::getInstance()->setAfterHowManyLinesHistoryIsSaved(_iNum);
215 }
216 /*------------------------------------------------------------------------*/
217 int getAfterHowManyLinesScilabHistoryIsSaved(void)
218 {
219     return HistoryManager::getInstance()->getAfterHowManyLinesHistoryIsSaved();
220 }
221 /*------------------------------------------------------------------------*/
222 char* getNthLineInScilabHistory(int _iLine)
223 {
224     return HistoryManager::getInstance()->getNthLine(_iLine);
225 }
226 /*------------------------------------------------------------------------*/
227 BOOL deleteNthLineScilabHistory(int _iLine)
228 {
229     return HistoryManager::getInstance()->deleteNthLine(_iLine);
230 }
231 /*------------------------------------------------------------------------*/
232 int getSizeScilabHistory(void)
233 {
234     return (HistoryManager::getInstance()->getNumberOfLines() - 1);
235 }
236 /*------------------------------------------------------------------------*/
237 BOOL setSizeMaxScilabHistory(int _iMaxLines)
238 {
239     return HistoryManager::getInstance()->setNumberOfLinesMax(_iMaxLines);
240 }
241 /*------------------------------------------------------------------------*/
242 int getSizeMaxScilabHistory(void)
243 {
244     return HistoryManager::getInstance()->getNumberOfLinesMax();
245 }
246 /*------------------------------------------------------------------------*/
247 HistoryManager::HistoryManager()
248 {
249     m_bTruncated                = FALSE;
250     m_bAllowConsecutiveCommand  = FALSE;
251     m_iSaveLimit                = 0;
252     m_iSavedLines               = 0;
253     m_Commands.clear();
254
255     CommandHistoryInitialize();
256 }
257 /*------------------------------------------------------------------------*/
258 HistoryManager::~HistoryManager()
259 {
260     m_Commands.clear();
261 }
262 /*------------------------------------------------------------------------*/
263 BOOL HistoryManager::historyIsEnabled(void)
264 {
265     if (m_pHM)
266     {
267         return TRUE;
268     }
269     return FALSE;
270 }
271 /*------------------------------------------------------------------------*/
272 BOOL HistoryManager::appendLine(char* _pstLine)
273 {
274     BOOL bOK = FALSE;
275     if (_pstLine)
276     {
277         int i                   = 0;
278         int len                 = 0;
279         char* pstCleanedLine    = NULL;
280
281         /* remove space & carriage return at the end of line */
282         len = (int)strlen(_pstLine);
283         pstCleanedLine = (char*) MALLOC(len + 1);
284         memcpy(pstCleanedLine, _pstLine, len + 1);
285
286         /* remove carriage return at the end of line */
287         for (i = len ; i > 0 ; i--)
288         {
289             if (pstCleanedLine[i] == '\n')
290             {
291                 pstCleanedLine[i] = '\0';
292                 len = i - 1;
293                 break;
294             }
295         }
296
297         /* remove spaces at the end of line */
298         i = len;
299         while (i >= 0)
300         {
301             if (pstCleanedLine[i] == ' ')
302             {
303                 pstCleanedLine[i] = '\0';
304             }
305             else
306             {
307                 break;
308             }
309             i--;
310         }
311
312         if (strlen(pstCleanedLine) == 0)
313         {
314             FREE(pstCleanedLine);
315             return TRUE;
316         }
317
318         // append
319         if (m_bAllowConsecutiveCommand)
320         {
321             m_Commands.push_back(pstCleanedLine);
322             m_iSavedLines++;
323             bOK = TRUE;
324             CommandHistoryAppendLine(pstCleanedLine);
325         }
326         else
327         {
328             char* pstPreviousLine = getLastLine();
329             if (pstPreviousLine && strcmp(pstPreviousLine, pstCleanedLine) == 0)
330             {
331                 bOK = TRUE;
332             }
333             else
334             {
335                 m_Commands.push_back(pstCleanedLine);
336                 m_iSavedLines++;
337                 bOK = TRUE;
338
339                 CommandHistoryAppendLine(pstCleanedLine);
340             }
341             if (pstPreviousLine)
342             {
343                 FREE(pstPreviousLine);
344                 pstPreviousLine = NULL;
345             }
346         }
347
348         if (m_iSaveLimit != 0)
349         {
350             if (m_iSavedLines >= m_iSaveLimit)
351             {
352                 m_HF.setHistory(m_Commands);
353                 m_HF.writeToFile();
354                 m_iSavedLines = 0;
355             }
356         }
357         else
358         {
359             m_iSavedLines = 0;
360         }
361
362         FREE(pstCleanedLine);
363         pstCleanedLine = NULL;
364     }
365
366     return bOK;
367 }
368 /*------------------------------------------------------------------------*/
369 BOOL HistoryManager::appendLines(char** _pstLines, int _iLines)
370 {
371     for (int i = 0 ; i < _iLines ; i++)
372     {
373         if (appendLine(_pstLines[i]) == FALSE)
374         {
375             return FALSE;
376         }
377     }
378     return TRUE;
379 }
380 /*------------------------------------------------------------------------*/
381 void HistoryManager::displayHistory(void)
382 {
383     int nbline = 0;
384     std::list<std::string>::const_iterator it;
385     for (it = m_Commands.begin() ; it != m_Commands.end() ; it++)
386     {
387         sciprint(_("%d : %s\n"), nbline++, (*it).c_str());
388     }
389 }
390 /*------------------------------------------------------------------------*/
391 char* HistoryManager::getFilename(void)
392 {
393     if (m_HF.getFilename().empty() == false)
394     {
395         return os_strdup(m_HF.getFilename().c_str());
396     }
397     return NULL;
398 }
399 /*------------------------------------------------------------------------*/
400 BOOL HistoryManager::setFilename(char* _pstFilename)
401 {
402     if (_pstFilename)
403     {
404         m_HF.setFilename(_pstFilename);
405         return TRUE;
406     }
407     return FALSE;
408 }
409 /*------------------------------------------------------------------------*/
410 BOOL HistoryManager::setDefaultFilename(void)
411 {
412     return m_HF.setDefaultFilename();
413 }
414 /*------------------------------------------------------------------------*/
415 BOOL HistoryManager::writeToFile(char* _pstFilename)
416 {
417     if (_pstFilename)
418     {
419         m_HF.setHistory(m_Commands);
420         return m_HF.writeToFile(_pstFilename);
421     }
422     return FALSE;
423 }
424 /*------------------------------------------------------------------------*/
425 BOOL HistoryManager::writeToFile()
426 {
427         m_HF.setHistory(m_Commands);
428         return m_HF.writeToFile();
429 }
430 /*------------------------------------------------------------------------*/
431 BOOL HistoryManager::loadFromFile(char* _pstFilename)
432 {
433     if (_pstFilename)
434     {
435         char* pstCommentBeginSession = NULL;
436         if (m_HF.loadFromFile(_pstFilename) == HISTORY_TRUNCATED)
437         {
438             m_bTruncated = TRUE;
439         }
440
441         m_Commands.clear();
442         m_Commands = m_HF.getHistory();
443
444         if (m_Commands.size() > 0)
445         {
446             char* pstFirstLine = getFirstLine();
447             if (pstFirstLine)
448             {
449                 if (!isBeginningSessionLine(pstFirstLine))
450                 {
451                     fixHistorySession();
452                 }
453                 FREE(pstFirstLine);
454                 pstFirstLine = NULL;
455             }
456         }
457
458         /* add date & time @ begin session */
459         pstCommentBeginSession = getCommentDateSession(FALSE);
460         appendLine(pstCommentBeginSession);
461         FREE(pstCommentBeginSession);
462         pstCommentBeginSession = NULL;
463
464         CommandHistoryLoadFromFile();
465
466         return TRUE;
467     }
468     return FALSE;
469 }
470 /*--------------------------------------------------------------------------*/
471 BOOL HistoryManager::reset(void)
472 {
473     char* pstCommentBeginSession = NULL;
474
475     m_Commands.clear();
476
477     m_HF.reset();
478     m_HF.setDefaultFilename();
479
480     m_HS.reset();
481
482     m_bAllowConsecutiveCommand  = FALSE;
483     m_iSaveLimit                = 0;
484     m_iSavedLines               = 0;
485
486     CommandHistoryReset();
487
488     /* Add date & time begin session */
489     pstCommentBeginSession = getCommentDateSession(FALSE);
490     if (pstCommentBeginSession)
491     {
492         appendLine(pstCommentBeginSession);
493         FREE(pstCommentBeginSession);
494         pstCommentBeginSession = NULL;
495         return TRUE;
496     }
497
498     return FALSE;
499 }
500 /*--------------------------------------------------------------------------*/
501 char** HistoryManager::getAllLines(int* _piLines)
502 {
503     char** pstLines = NULL;
504     *_piLines       = 0;
505
506     if (m_Commands.empty())
507     {
508         return pstLines;
509     }
510     else
511     {
512         std::list<std::string>::const_iterator it;
513
514         pstLines = (char**)MALLOC((int)(m_Commands.size() + 1) * (sizeof(char*)));
515         for (it = m_Commands.begin() ; it != m_Commands.end(); ++it)
516         {
517             pstLines[(*_piLines)++] = os_strdup((*it).c_str());
518         }
519
520         /* SWIG need array finish with NULL */
521         pstLines[(*_piLines)] = NULL;
522     }
523     return pstLines;
524 }
525 /*--------------------------------------------------------------------------*/
526 char* HistoryManager::getFirstLine(void)
527 {
528     if (m_Commands.empty() == false)
529     {
530         return os_strdup(m_Commands.front().c_str());
531     }
532     return NULL;
533 }
534 /*--------------------------------------------------------------------------*/
535 char* HistoryManager::getLastLine(void)
536 {
537     if (m_Commands.empty() == false)
538     {
539         return os_strdup(m_Commands.back().c_str());
540     }
541     return NULL;
542 }
543 /*--------------------------------------------------------------------------*/
544 int HistoryManager::getNumberOfLines(void)
545 {
546     return (int)m_Commands.size();
547 }
548 /*--------------------------------------------------------------------------*/
549 char* HistoryManager::getNthLine(int _iLine)
550 {
551     if (_iLine < 0)
552     {
553         //reverse search Oo
554         _iLine = getNumberOfLines() + _iLine;
555     }
556
557     if (_iLine >= 0 && _iLine <= getNumberOfLines())
558     {
559         int i = 0;
560         std::list<std::string>::const_iterator it;
561         for (it = m_Commands.begin() ; it != m_Commands.end() ; it++)
562         {
563             if (i == _iLine)
564             {
565                 return os_strdup((*it).c_str());
566             }
567             i++;
568         }
569     }
570
571     return NULL;
572 }
573 /*--------------------------------------------------------------------------*/
574 BOOL HistoryManager::deleteNthLine(int _iLine)
575 {
576     if (_iLine >= 0 && _iLine <= getNumberOfLines())
577     {
578         int i = 0;
579         std::list<std::string>::iterator it;
580         for (it = m_Commands.begin() ; it != m_Commands.end(); it++)
581         {
582             if (i == _iLine)
583             {
584                 m_Commands.erase(it);
585                 // After a remove , we update search
586                 m_HS.setHistory(m_Commands);
587                 m_HS.setToken("");
588
589                 CommandHistoryDeleteLine(_iLine);
590                 return TRUE;
591             }
592             i++;
593         }
594     }
595     return FALSE;
596 }
597 /*--------------------------------------------------------------------------*/
598 void HistoryManager::setSaveConsecutiveDuplicateLines(BOOL _bAllow)
599 {
600     m_bAllowConsecutiveCommand = _bAllow;
601 }
602 /*--------------------------------------------------------------------------*/
603 BOOL HistoryManager::getSaveConsecutiveDuplicateLines(void)
604 {
605     return m_bAllowConsecutiveCommand;
606 }
607 /*--------------------------------------------------------------------------*/
608 void HistoryManager::setAfterHowManyLinesHistoryIsSaved(int _iSaveLimit)
609 {
610     if (_iSaveLimit >= 0)
611     {
612         m_iSaveLimit    = _iSaveLimit;
613         m_iSavedLines   = 0;
614     }
615 }
616 /*--------------------------------------------------------------------------*/
617 int HistoryManager::getAfterHowManyLinesHistoryIsSaved(void)
618 {
619     return m_iSaveLimit;
620 }
621 /*--------------------------------------------------------------------------*/
622 char* HistoryManager::getPreviousLine(void)
623 {
624     if (m_HS.getSize() > 0)
625     {
626         std::string stLine = m_HS.getPreviousLine();
627         if (stLine.empty() == false)
628         {
629             return os_strdup(stLine.c_str());
630         }
631     }
632     return NULL;
633 }
634 /*--------------------------------------------------------------------------*/
635 char* HistoryManager::getNextLine(void)
636 {
637     if (m_HS.getSize() > 0)
638     {
639         std::string stLine = m_HS.getNextLine();
640         return os_strdup(stLine.c_str());
641     }
642     return NULL;
643 }
644 /*--------------------------------------------------------------------------*/
645 BOOL HistoryManager::setToken(const char* _pstToken)
646 {
647     m_HS.setHistory(m_Commands);
648
649     if (_pstToken)
650     {
651         return m_HS.setToken(_pstToken);
652     }
653     else
654     {
655         return m_HS.setToken("");
656     }
657 }
658 /*--------------------------------------------------------------------------*/
659 char* HistoryManager::getToken(void)
660 {
661     std::string stToken = m_HS.getToken();
662     if (stToken.empty() == false)
663     {
664         return os_strdup(stToken.c_str());
665     }
666     return NULL;
667 }
668 /*--------------------------------------------------------------------------*/
669 BOOL HistoryManager::resetToken(void)
670 {
671     return m_HS.reset();
672 }
673 /*--------------------------------------------------------------------------*/
674 BOOL HistoryManager::isBeginningSessionLine(char* _pstLine)
675 {
676     if (_pstLine)
677     {
678         if (strlen(_pstLine) > strlen(SESSION_PRAGMA_BEGIN) + strlen(SESSION_PRAGMA_END))
679         {
680             if ((strncmp(   _pstLine,
681                             SESSION_PRAGMA_BEGIN,
682                             strlen(SESSION_PRAGMA_BEGIN)) == 0) &&
683                     (strncmp(    _pstLine + strlen(_pstLine) - strlen(SESSION_PRAGMA_END),
684                                  SESSION_PRAGMA_END,
685                                  strlen(SESSION_PRAGMA_END)) == 0))
686             {
687                 return TRUE;
688             }
689         }
690     }
691     return FALSE;
692 }
693 /*--------------------------------------------------------------------------*/
694 void HistoryManager::fixHistorySession(void)
695 {
696     /* add date & time @ begin session */
697     char* pstCommentBeginSession = getCommentDateSession(FALSE);
698     if (pstCommentBeginSession)
699     {
700         m_Commands.push_front(pstCommentBeginSession);
701         FREE(pstCommentBeginSession);
702         pstCommentBeginSession = NULL;
703     }
704 }
705 /*--------------------------------------------------------------------------*/
706 BOOL HistoryManager::isTruncated(void)
707 {
708     return m_bTruncated;
709 }
710 /*--------------------------------------------------------------------------*/
711 BOOL HistoryManager::setNumberOfLinesMax(int _iMaxLines)
712 {
713     return m_HF.setDefaultMaxNbLines(_iMaxLines);
714 }
715 /*--------------------------------------------------------------------------*/
716 int HistoryManager::getNumberOfLinesMax(void)
717 {
718     return m_HF.getDefaultMaxNbLines();
719 }
720 /*--------------------------------------------------------------------------*/