1    	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2    	/*                                                                           */
3    	/*                  This file is part of the program and library             */
4    	/*         SCIP --- Solving Constraint Integer Programs                      */
5    	/*                                                                           */
6    	/*  Copyright (c) 2002-2023 Zuse Institute Berlin (ZIB)                      */
7    	/*                                                                           */
8    	/*  Licensed under the Apache License, Version 2.0 (the "License");          */
9    	/*  you may not use this file except in compliance with the License.         */
10   	/*  You may obtain a copy of the License at                                  */
11   	/*                                                                           */
12   	/*      http://www.apache.org/licenses/LICENSE-2.0                           */
13   	/*                                                                           */
14   	/*  Unless required by applicable law or agreed to in writing, software      */
15   	/*  distributed under the License is distributed on an "AS IS" BASIS,        */
16   	/*  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
17   	/*  See the License for the specific language governing permissions and      */
18   	/*  limitations under the License.                                           */
19   	/*                                                                           */
20   	/*  You should have received a copy of the Apache-2.0 license                */
21   	/*  along with SCIP; see the file LICENSE. If not visit scipopt.org.         */
22   	/*                                                                           */
23   	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
24   	
25   	/**@file   dialog.c
26   	 * @ingroup OTHER_CFILES
27   	 * @brief  methods for user interface dialog
28   	 * @author Tobias Achterberg
29   	 */
30   	
31   	/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
32   	
33   	#include <assert.h>
34   	#include <string.h>
35   	#include <ctype.h>
36   	
37   	#include "scip/scip.h"
38   	#include "scip/def.h"
39   	#include "blockmemshell/memory.h"
40   	#include "scip/set.h"
41   	#include "scip/pub_misc.h"
42   	#include "scip/dialog.h"
43   	
44   	#include "scip/struct_dialog.h"
45   	
46   	#ifdef SCIP_WITH_READLINE
47   	#include <stdio.h>
48   	#include <readline/readline.h>
49   	#include <readline/history.h>
50   	#endif
51   	
52   	
53   	
54   	/*
55   	 * read line methods
56   	 */
57   	
58   	#ifdef SCIP_WITH_READLINE
59   	
60   	/** reads a line of input from stdin */
61   	static
62   	SCIP_RETCODE readLine(
63   	   SCIP_DIALOGHDLR*      dialoghdlr,         /**< dialog handler */
64   	   const char*           prompt,             /**< prompt to display */
65   	   SCIP_Bool*            endoffile           /**< pointer to store whether the end of the input file was reached */
66   	   )
67   	{
68   	   char* s;
69   	
70   	   assert(endoffile != NULL);
71   	
72   	   s = readline(prompt);
73   	   if( s != NULL )
74   	   {
75   	      (void)SCIPstrncpy(&dialoghdlr->buffer[dialoghdlr->bufferpos], s, dialoghdlr->buffersize - dialoghdlr->bufferpos);
76   	      free(s);
77   	      *endoffile = FALSE;
78   	   }
79   	   else
80   	      *endoffile = TRUE;
81   	
82   	   return SCIP_OKAY;
83   	}
84   	
85   	/** puts the given string on the command history */
86   	static
87   	SCIP_RETCODE addHistory(
88   	   const char*           s                   /**< string to add to the command history */
89   	   )
90   	{
91   	   add_history(s);
92   	
93   	   return SCIP_OKAY;
94   	}
95   	
96   	/** returns the current length of the history list */
97   	static
98   	int getHistoryLength(
99   	   void
100  	   )
101  	{
102  	#ifndef NO_REMOVE_HISTORY
103  	   return history_length;
104  	#else
105  	   return 0;
106  	#endif
107  	}
108  	
109  	/** removes a single element from the history list */
110  	static
111  	SCIP_RETCODE removeHistory(
112  	   int                   pos                 /**< list position of history entry to remove */
113  	   )
114  	{
115  	#ifndef NO_REMOVE_HISTORY
116  	   HIST_ENTRY* entry;
117  	
118  	   entry = remove_history(pos);
119  	
120  	   /* Free readline/history storage: there seem to be differences in the versions (and the amount of
121  	    * data to be freed). The following should be a good approximation; if it doesn't work define
122  	    * NO_REMOVE_HISTORY - see the INSTALL file. This will produce minor memory leaks.
123  	    */
124  	#if RL_VERSION_MAJOR >= 5
125  	   (void)free_history_entry(entry);
126  	#else
127  	   if( entry != NULL )
128  	   {
129  	      free((void*)entry->line);
130  	      free(entry);
131  	   }
132  	#endif
133  	#endif
134  	
135  	   return SCIP_OKAY;
136  	}
137  	
138  	/** writes command history into file of the specified name */
139  	static
140  	SCIP_RETCODE writeHistory(
141  	   const char*           filename            /**< name of file to (over)write history to */
142  	   )
143  	{
144  	   int retval = write_history(filename);
145  	
146  	   if( retval == 0 )
147  	      return SCIP_OKAY;
148  	   else
149  	      return SCIP_FILECREATEERROR;
150  	}
151  	
152  	#else
153  	
154  	/** reads a line of input from stdin */
155  	static
156  	SCIP_RETCODE readLine(
157  	   SCIP_DIALOGHDLR*      dialoghdlr,         /**< dialog handler */
158  	   const char*           prompt,             /**< prompt to display */
159  	   SCIP_Bool*            endoffile           /**< pointer to store whether the end of the input file was reached */
160  	   )
161  	{
162  	   char* s;
163  	
164  	   assert(dialoghdlr != NULL);
165  	   assert(dialoghdlr->buffer != NULL);
166  	   assert(dialoghdlr->bufferpos < dialoghdlr->buffersize);
167  	   assert(dialoghdlr->buffer[dialoghdlr->bufferpos] == '\0');
168  	   assert(endoffile != NULL);
169  	
170  	   /* check for EOF (due to CTRL-D or unexpected end of piped-in file) */
171  	   if( feof(stdin) )
172  	      *endoffile = TRUE;
173  	   else
174  	   {
175  	      char* result;
176  	
177  	      /* display prompt */
178  	      printf("%s", prompt);
179  	
180  	      /* read line from stdin */
181  	      result = fgets(&dialoghdlr->buffer[dialoghdlr->bufferpos], dialoghdlr->buffersize - dialoghdlr->bufferpos, stdin);
182  	      assert(result != NULL);
183  	      (void) result; /* disable compiler warning [-Wunused-result] */
184  	
185  	      /* replace newline with \0 */
186  	      s = strchr(&dialoghdlr->buffer[dialoghdlr->bufferpos], '\n');
187  	      if( s != NULL )
188  	         *s = '\0';
189  	      *endoffile = FALSE;
190  	   }
191  	
192  	   return SCIP_OKAY;
193  	}
194  	
195  	/** puts the given string on the command history */ /*lint -e715*/
196  	static
197  	SCIP_RETCODE addHistory(
198  	   const char*           s                   /**< string to add to the command history */
199  	   )
200  	{  /*lint --e{715}*/
201  	   /* nothing to do here */
202  	   return SCIP_OKAY;
203  	}
204  	
205  	/** returns the current length of the history list */
206  	static
207  	int getHistoryLength(
208  	   void
209  	   )
210  	{
211  	   return 0;
212  	}
213  	
214  	/** removes a single element from the history list */ /*lint -e715*/
215  	static
216  	SCIP_RETCODE removeHistory(
217  	   int                   pos                 /**< list position of history entry to remove */
218  	   )
219  	{  /*lint --e{715}*/
220  	   /* nothing to do here */
221  	   return SCIP_OKAY;
222  	}
223  	
224  	
225  	/** writes command history into file of the specified name */
226  	static
227  	SCIP_RETCODE writeHistory(
228  	   const char*           filename            /**< name of file to (over)write history to */
229  	   )
230  	{  /*lint --e{715}*/
231  	   assert(filename != NULL);
232  	
233  	   /* nothing to do here */
234  	   return SCIP_OKAY;
235  	}
236  	
237  	#endif
238  	
239  	/** frees a single linelist entry, but not its successors */
240  	static
241  	void linelistFree(
242  	   SCIP_LINELIST**       linelist            /**< pointer to line list */
243  	   )
244  	{
245  	   assert(linelist != NULL);
246  	
247  	   BMSfreeMemoryArray(&(*linelist)->inputline);
248  	   BMSfreeMemory(linelist);
249  	}
250  	
251  	/** frees a linelist entry and all of its successors */
252  	static
253  	void linelistFreeAll(
254  	   SCIP_LINELIST**       linelist            /**< pointer to line list */
255  	   )
256  	{
257  	   assert(linelist != NULL);
258  	
259  	   while( *linelist != NULL )
260  	   {
261  	      SCIP_LINELIST* nextline;
262  	
263  	      nextline = (*linelist)->nextline;
264  	      linelistFree(linelist);
265  	      *linelist = nextline;
266  	   }
267  	}
268  	
269  	/** reads a line of input from stdin or from the stored input lines in the input list */
270  	static
271  	SCIP_RETCODE readInputLine(
272  	   SCIP_DIALOGHDLR*      dialoghdlr,         /**< dialog handler */
273  	   const char*           prompt,             /**< prompt to display */
274  	   SCIP_Bool*            endoffile           /**< pointer to store whether the end of the input file was reached */
275  	   )
276  	{
277  	   assert(dialoghdlr != NULL);
278  	   assert(dialoghdlr->buffer != NULL);
279  	   assert(dialoghdlr->bufferpos < dialoghdlr->buffersize);
280  	   assert(dialoghdlr->buffer[dialoghdlr->bufferpos] == '\0');
281  	   assert(endoffile != NULL);
282  	
283  	   *endoffile = FALSE;
284  	
285  	   if( dialoghdlr->inputlist == NULL )
286  	   {
287  	      /* read a line from stdin */
288  	      SCIP_CALL( readLine(dialoghdlr, prompt, endoffile) );
289  	   }
290  	   else
291  	   {
292  	      SCIP_LINELIST* nextline;
293  	
294  	      /* copy the next input line into the input buffer */
295  	      (void)SCIPstrncpy(&dialoghdlr->buffer[dialoghdlr->bufferpos], dialoghdlr->inputlist->inputline, dialoghdlr->buffersize - dialoghdlr->bufferpos);
296  	
297  	      /* free the input line */
298  	      nextline = dialoghdlr->inputlist->nextline;
299  	      if( dialoghdlr->inputlistptr == &(dialoghdlr->inputlist->nextline) )
300  	         dialoghdlr->inputlistptr = &dialoghdlr->inputlist;
301  	      linelistFree(&dialoghdlr->inputlist);
302  	      dialoghdlr->inputlist = nextline;
303  	      assert(dialoghdlr->inputlistptr != NULL);
304  	      assert(*dialoghdlr->inputlistptr == NULL);
305  	   }
306  	
307  	   return SCIP_OKAY;
308  	}
309  	
310  	
311  	
312  	
313  	/*
314  	 * dialog handler
315  	 */
316  	
317  	/** copies the given dialog to a new scip */
318  	SCIP_RETCODE SCIPdialogCopyInclude(
319  	   SCIP_DIALOG*          dialog,             /**< dialog */
320  	   SCIP_SET*             set                 /**< SCIP_SET of SCIP to copy to */
321  	   )
322  	{
323  	   assert(dialog != NULL);
324  	   assert(set != NULL);
325  	   assert(set->scip != NULL);
326  	
327  	   if( dialog->dialogcopy != NULL )
328  	   {
329  	      SCIPsetDebugMsg(set, "including dialog %s in subscip %p\n", SCIPdialogGetName(dialog), (void*)set->scip);
330  	      SCIP_CALL( dialog->dialogcopy(set->scip, dialog) );
331  	   }
332  	   return SCIP_OKAY;
333  	}
334  	
335  	/** creates a dialog handler */
336  	SCIP_RETCODE SCIPdialoghdlrCreate(
337  	   SCIP_SET*             set,                /**< global SCIP settings */
338  	   SCIP_DIALOGHDLR**     dialoghdlr          /**< pointer to store dialog handler */
339  	   )
340  	{  /*lint --e{715}*/
341  	#ifdef SCIP_WITH_READLINE
342  	   char readlineversion[20];
343  	#endif
344  	
345  	   assert(set != NULL);
346  	   assert(dialoghdlr != NULL);
347  	
348  	   SCIP_ALLOC( BMSallocMemory(dialoghdlr) );
349  	   (*dialoghdlr)->rootdialog = NULL;
350  	   (*dialoghdlr)->inputlist = NULL;
351  	   (*dialoghdlr)->inputlistptr = &(*dialoghdlr)->inputlist;
352  	   (*dialoghdlr)->buffersize = SCIP_MAXSTRLEN;
353  	   (*dialoghdlr)->nprotectedhistelems = -1;
354  	   SCIP_ALLOC( BMSallocMemoryArray(&(*dialoghdlr)->buffer, (*dialoghdlr)->buffersize) );
355  	
356  	   SCIPdialoghdlrClearBuffer(*dialoghdlr);
357  	
358  	#ifdef SCIP_WITH_READLINE
359  	   (void) SCIPsnprintf(readlineversion, (int)sizeof(readlineversion), "Readline %s", rl_library_version);
360  	   SCIP_CALL( SCIPsetIncludeExternalCode(set, readlineversion, "GNU library for command line editing (gnu.org/s/readline)") );
361  	#endif
362  	
363  	   return SCIP_OKAY;
364  	}
365  	
366  	/** frees a dialog handler and it's dialog tree */
367  	SCIP_RETCODE SCIPdialoghdlrFree(
368  	   SCIP*                 scip,               /**< SCIP data structure */
369  	   SCIP_DIALOGHDLR**     dialoghdlr          /**< pointer to dialog handler */
370  	   )
371  	{
372  	   assert(dialoghdlr != NULL);
373  	   if( *dialoghdlr == NULL )
374  	      return SCIP_OKAY;
375  	
376  	   SCIP_CALL( SCIPdialoghdlrSetRoot(scip, *dialoghdlr, NULL) );
377  	   linelistFreeAll(&(*dialoghdlr)->inputlist);
378  	   BMSfreeMemoryArray(&(*dialoghdlr)->buffer);
379  	   BMSfreeMemory(dialoghdlr);
380  	
381  	   return SCIP_OKAY;
382  	}
383  	
384  	/** executes the root dialog of the dialog handler */
385  	SCIP_RETCODE SCIPdialoghdlrExec(
386  	   SCIP_DIALOGHDLR*      dialoghdlr,         /**< dialog handler */
387  	   SCIP_SET*             set                 /**< global SCIP settings */
388  	   )
389  	{
390  	   SCIP_DIALOG* dialog;
391  	
392  	   assert(dialoghdlr != NULL);
393  	   assert(dialoghdlr->buffer != NULL);
394  	
395  	   /* clear the buffer, start with the root dialog */
396  	   SCIPdialoghdlrClearBuffer(dialoghdlr);
397  	   dialog = dialoghdlr->rootdialog;
398  	
399  	   /* execute dialogs until a NULL is returned as next dialog */
400  	   while( dialog != NULL )
401  	   {
402  	      SCIP_CALL( SCIPdialogExec(dialog, set, dialoghdlr, &dialog) );
403  	
404  	      /* reset buffer, it is was consumed completely */
405  	      if( dialoghdlr->buffer[dialoghdlr->bufferpos] == '\0' )
406  	         SCIPdialoghdlrClearBuffer(dialoghdlr);
407  	   }
408  	
409  	   return SCIP_OKAY;
410  	}
411  	
412  	/** makes given dialog the root dialog of dialog handler; captures dialog and releases former root dialog */
413  	SCIP_RETCODE SCIPdialoghdlrSetRoot(
414  	   SCIP*                 scip,               /**< SCIP data structure */
415  	   SCIP_DIALOGHDLR*      dialoghdlr,         /**< dialog handler */
416  	   SCIP_DIALOG*          dialog              /**< dialog to be the root */
417  	   )
418  	{
419  	   assert(dialoghdlr != NULL);
420  	
421  	   if( dialoghdlr->rootdialog != NULL )
422  	   {
423  	      SCIP_CALL( SCIPdialogRelease(scip, &dialoghdlr->rootdialog) );
424  	   }
425  	   assert(dialoghdlr->rootdialog == NULL);
426  	
427  	   dialoghdlr->rootdialog = dialog;
428  	
429  	   if( dialog != NULL )
430  	      SCIPdialogCapture(dialog);
431  	
432  	   return SCIP_OKAY;
433  	}
434  	
435  	/** returns the root dialog of the dialog handler */
436  	SCIP_DIALOG* SCIPdialoghdlrGetRoot(
437  	   SCIP_DIALOGHDLR*      dialoghdlr          /**< dialog handler */
438  	   )
439  	{
440  	   assert(dialoghdlr != NULL);
441  	
442  	   return dialoghdlr->rootdialog;
443  	}
444  	
445  	/** clears the input command buffer of the dialog handler */
446  	void SCIPdialoghdlrClearBuffer(
447  	   SCIP_DIALOGHDLR*      dialoghdlr          /**< dialog handler */
448  	   )
449  	{
450  	   assert(dialoghdlr != NULL);
451  	
452  	   dialoghdlr->buffer[0] = '\0';
453  	   dialoghdlr->bufferpos = 0;
454  	}
455  	
456  	/** returns TRUE iff input command buffer is empty */
457  	SCIP_Bool SCIPdialoghdlrIsBufferEmpty(
458  	   SCIP_DIALOGHDLR*      dialoghdlr          /**< dialog handler */
459  	   )
460  	{
461  	   assert(dialoghdlr != NULL);
462  	   assert(dialoghdlr->bufferpos < dialoghdlr->buffersize);
463  	
464  	   return (dialoghdlr->buffer[dialoghdlr->bufferpos] == '\0');
465  	}
466  	
467  	/** returns the next line in the handler's command buffer; if the buffer is empty, displays the given prompt or the
468  	 *  current dialog's path and asks the user for further input; the user must not free or modify the returned string
469  	 */
470  	SCIP_RETCODE SCIPdialoghdlrGetLine(
471  	   SCIP_DIALOGHDLR*      dialoghdlr,         /**< dialog handler */
472  	   SCIP_DIALOG*          dialog,             /**< current dialog */
473  	   const char*           prompt,             /**< prompt to display, or NULL to display the current dialog's path */
474  	   char**                inputline,          /**< pointer to store the complete line in the handler's command buffer */
475  	   SCIP_Bool*            endoffile           /**< pointer to store whether the end of the input file was reached */
476  	   )
477  	{
478  	   char path[SCIP_MAXSTRLEN+1];
479  	   char p[SCIP_MAXSTRLEN];
480  	
481  	   assert(dialoghdlr != NULL);
482  	   assert(dialoghdlr->buffer != NULL);
483  	   assert(dialoghdlr->bufferpos < dialoghdlr->buffersize);
484  	   assert(inputline != NULL);
485  	
486  	   /* get input from the user, if the buffer is empty */
487  	   if( SCIPdialoghdlrIsBufferEmpty(dialoghdlr) )
488  	   {
489  	      int len;
490  	
491  	      /* clear the buffer */
492  	      SCIPdialoghdlrClearBuffer(dialoghdlr);
493  	
494  	      if( prompt == NULL )
495  	      {
496  	         /* use current dialog's path as prompt */
497  	         SCIPdialogGetPath(dialog, '/', path);
498  	         (void) SCIPsnprintf(p, SCIP_MAXSTRLEN, "%s> ", path);
499  	         prompt = p;
500  	      }
501  	
502  	      /* read command line from stdin or from the input line list */
503  	      SCIP_CALL( readInputLine(dialoghdlr, prompt, endoffile) );
504  	
505  	      /* strip trailing spaces */
506  	      len = (int)strlen(&dialoghdlr->buffer[dialoghdlr->bufferpos]);
507  	      if( len > 0 )
508  	      {
509  	         while( isspace((unsigned char)dialoghdlr->buffer[dialoghdlr->bufferpos + len - 1]) )
510  	         {
511  	            dialoghdlr->buffer[dialoghdlr->bufferpos + len - 1] = '\0';
512  	            len--;
513  	         }
514  	      }
515  	
516  	      /* insert command in command history */
517  	      if( dialoghdlr->buffer[dialoghdlr->bufferpos] != '\0' )
518  	      {
519  	         SCIP_CALL( SCIPdialoghdlrAddHistory(dialoghdlr, NULL, &dialoghdlr->buffer[dialoghdlr->bufferpos], FALSE) );
520  	      }
521  	   }
522  	
523  	   /* the last character in the buffer must be a '\0' */
524  	   dialoghdlr->buffer[dialoghdlr->buffersize-1] = '\0';
525  	
526  	   /* skip leading spaces: find start of first word */
527  	   while( isspace((unsigned char)dialoghdlr->buffer[dialoghdlr->bufferpos]) )
528  	      dialoghdlr->bufferpos++;
529  	
530  	   /* copy the complete line */
531  	   *inputline = &dialoghdlr->buffer[dialoghdlr->bufferpos];
532  	
533  	   /* go to the end of the line */
534  	   dialoghdlr->bufferpos += (int)strlen(&dialoghdlr->buffer[dialoghdlr->bufferpos]);
535  	
536  	   if( dialoghdlr->buffer[dialoghdlr->buffersize-1] == '\0' )
537  	      *endoffile = TRUE;
538  	
539  	   return SCIP_OKAY;
540  	}
541  	
542  	
543  	/** returns the next word in the handler's command buffer; if the buffer is empty, displays the given prompt or the
544  	 *  current dialog's path and asks the user for further input; the user must not free or modify the returned string
545  	 */
546  	SCIP_RETCODE SCIPdialoghdlrGetWord(
547  	   SCIP_DIALOGHDLR*      dialoghdlr,         /**< dialog handler */
548  	   SCIP_DIALOG*          dialog,             /**< current dialog */
549  	   const char*           prompt,             /**< prompt to display, or NULL to display the current dialog's path */
550  	   char**                inputword,          /**< pointer to store the next word in the handler's command buffer */
551  	   SCIP_Bool*            endoffile           /**< pointer to store whether the end of the input file was reached */
552  	   )
553  	{
554  	   char path[SCIP_MAXSTRLEN+1];
555  	   char p[SCIP_MAXSTRLEN];
556  	   char* firstword;
557  	   int pos;
558  	
559  	   assert(dialoghdlr != NULL);
560  	   assert(dialoghdlr->buffer != NULL);
561  	   assert(dialoghdlr->bufferpos < dialoghdlr->buffersize);
562  	   assert(inputword != NULL);
563  	   assert(endoffile != NULL);
564  	
565  	   *endoffile = FALSE;
566  	
567  	   /* get input from the user, if the buffer is empty */
568  	   if( SCIPdialoghdlrIsBufferEmpty(dialoghdlr) )
569  	   {
570  	      int len;
571  	
572  	      /* clear the buffer */
573  	      SCIPdialoghdlrClearBuffer(dialoghdlr);
574  	
575  	      if( prompt == NULL )
576  	      {
577  	         /* use current dialog's path as prompt */
578  	         SCIPdialogGetPath(dialog, '/', path);
579  	         (void) SCIPsnprintf(p, SCIP_MAXSTRLEN, "%s> ", path);
580  	         prompt = p;
581  	      }
582  	
583  	      /* read command line from stdin or from the input line list */
584  	      SCIP_CALL( readInputLine(dialoghdlr, prompt, endoffile) );
585  	
586  	      /* strip trailing spaces */
587  	      len = (int)strlen(&dialoghdlr->buffer[dialoghdlr->bufferpos]);
588  	      if( len > 0 )
589  	      {
590  	         while( isspace((unsigned char)dialoghdlr->buffer[dialoghdlr->bufferpos + len - 1]) )
591  	         {
592  	            dialoghdlr->buffer[dialoghdlr->bufferpos + len - 1] = '\0';
593  	            len--;
594  	         }
595  	      }
596  	
597  	      /* insert command in command history */
598  	      if( dialoghdlr->buffer[dialoghdlr->bufferpos] != '\0' )
599  	      {
600  	         SCIP_CALL( SCIPdialoghdlrAddHistory(dialoghdlr, NULL, &dialoghdlr->buffer[dialoghdlr->bufferpos], FALSE) );
601  	      }
602  	   }
603  	
604  	   /* the last character in the buffer must be a '\0' */
605  	   dialoghdlr->buffer[dialoghdlr->buffersize-1] = '\0';
606  	
607  	   /* skip leading spaces: find start of first word */
608  	   while( isspace((unsigned char)dialoghdlr->buffer[dialoghdlr->bufferpos]) )
609  	      dialoghdlr->bufferpos++;
610  	   firstword = &dialoghdlr->buffer[dialoghdlr->bufferpos];
611  	
612  	   pos = dialoghdlr->bufferpos;
613  	   while( dialoghdlr->buffer[dialoghdlr->bufferpos] != '\0' && !isspace((unsigned char)dialoghdlr->buffer[dialoghdlr->bufferpos]) )
614  	   {
615  	      assert(pos <= dialoghdlr->bufferpos);
616  	
617  	      switch( dialoghdlr->buffer[dialoghdlr->bufferpos] )
618  	      {
619  	      case '"':
620  	         dialoghdlr->bufferpos++;
621  	         /* read characters as they are until the next " */
622  	         while( dialoghdlr->buffer[dialoghdlr->bufferpos] != '\0' && dialoghdlr->buffer[dialoghdlr->bufferpos] != '"' )
623  	         {
624  	            /* watch out for \" and \\ which should be treated as " and \, respectively */
625  	            if( dialoghdlr->buffer[dialoghdlr->bufferpos] == '\\'
626  	               && (dialoghdlr->buffer[dialoghdlr->bufferpos+1] == '"'
627  	                  || dialoghdlr->buffer[dialoghdlr->bufferpos+1] == '\\') )
628  	            {
629  	               dialoghdlr->bufferpos++;
630  	            }
631  	            dialoghdlr->buffer[pos] = dialoghdlr->buffer[dialoghdlr->bufferpos];
632  	            pos++;
633  	            dialoghdlr->bufferpos++;
634  	         }
635  	         if( dialoghdlr->buffer[dialoghdlr->bufferpos] == '"' )
636  	            dialoghdlr->bufferpos++; /* skip final " */
637  	         break;
638  	      case '\'':
639  	         dialoghdlr->bufferpos++;
640  	         /* read characters as they are until the next ' */
641  	         while( dialoghdlr->buffer[dialoghdlr->bufferpos] != '\0' && dialoghdlr->buffer[dialoghdlr->bufferpos] != '\'' )
642  	         {
643  	            /* watch out for \' and \\ which should be treated as ' and \, respectively */
644  	            if( dialoghdlr->buffer[dialoghdlr->bufferpos] == '\\'
645  	               && (dialoghdlr->buffer[dialoghdlr->bufferpos+1] == '\''
646  	                  || dialoghdlr->buffer[dialoghdlr->bufferpos+1] == '\\') )
647  	            {
648  	               dialoghdlr->bufferpos++;
649  	            }
650  	            dialoghdlr->buffer[pos] = dialoghdlr->buffer[dialoghdlr->bufferpos];
651  	            pos++;
652  	            dialoghdlr->bufferpos++;
653  	         }
654  	         if( dialoghdlr->buffer[dialoghdlr->bufferpos] == '\'' )
655  	            dialoghdlr->bufferpos++; /* skip final ' */
656  	         break;
657  	      case '\\':
658  	         /* if the next character is a space, a ", or a ', read next character as it is;
659  	          * otherwise, treat the \ as normal character
660  	          */
661  	         if( dialoghdlr->buffer[dialoghdlr->bufferpos+1] == ' '
662  	            || dialoghdlr->buffer[dialoghdlr->bufferpos+1] == '"'
663  	            || dialoghdlr->buffer[dialoghdlr->bufferpos+1] == '\'' )
664  	         {
665  	            dialoghdlr->bufferpos++;
666  	         }
667  	         /*lint -fallthrough*/
668  	      default:
669  	         dialoghdlr->buffer[pos] = dialoghdlr->buffer[dialoghdlr->bufferpos];
670  	         pos++;
671  	         dialoghdlr->bufferpos++;
672  	         break;
673  	      }
674  	   }
675  	   assert(pos <= dialoghdlr->bufferpos);
676  	
677  	   /* move buffer to the next position */
678  	   if( dialoghdlr->buffer[dialoghdlr->bufferpos] != '\0' )
679  	      dialoghdlr->bufferpos++;
680  	
681  	   /* truncate the command word in the buffer */
682  	   if( dialoghdlr->buffer[pos] != '\0' )
683  	      dialoghdlr->buffer[pos] = '\0';
684  	
685  	   /* remove additional spaces */
686  	   while( isspace((unsigned char)dialoghdlr->buffer[dialoghdlr->bufferpos]) )
687  	      dialoghdlr->bufferpos++;
688  	
689  	   *inputword = firstword;
690  	
691  	   SCIPdebugMessage("next word: <%s>\n", *inputword);
692  	
693  	   return SCIP_OKAY;
694  	}
695  	
696  	/** adds a single line of input to the dialog handler which is treated as if the user entered the command line */
697  	SCIP_RETCODE SCIPdialoghdlrAddInputLine(
698  	   SCIP_DIALOGHDLR*      dialoghdlr,         /**< dialog handler */
699  	   const char*           inputline           /**< input line to add */
700  	   )
701  	{
702  	   SCIP_LINELIST* linelist;
703  	   SCIP_RETCODE retcode = SCIP_OKAY;
704  	
705  	   assert(dialoghdlr != NULL);
706  	   assert(dialoghdlr->inputlistptr != NULL);
707  	   assert(*dialoghdlr->inputlistptr == NULL);
708  	   assert(inputline != NULL);
709  	
710  	   SCIP_ALLOC( BMSallocMemory(&linelist) );
711  	   SCIP_ALLOC_TERMINATE( retcode, BMSduplicateMemoryArray(&linelist->inputline, inputline, strlen(inputline)+1), TERMINATE );
712  	   linelist->nextline = NULL;
713  	   *dialoghdlr->inputlistptr = linelist;
714  	   dialoghdlr->inputlistptr = &linelist->nextline;
715  	
716  	 TERMINATE:
717  	   if( retcode != SCIP_OKAY )
718  	      BMSfreeMemory(&linelist);
719  	
720  	   return retcode;
721  	}
722  	
723  	/** adds a command to the command history of the dialog handler; if a dialog is given, the command is preceeded
724  	 *  by the dialog's command path; if no command is given, only the path to the dialog is added to the command history
725  	 */
726  	SCIP_RETCODE SCIPdialoghdlrAddHistory(
727  	   SCIP_DIALOGHDLR*      dialoghdlr,         /**< dialog handler */
728  	   SCIP_DIALOG*          dialog,             /**< current dialog, or NULL */
729  	   const char*           command,            /**< command string to add to the command history, or NULL */
730  	   SCIP_Bool             escapecommand       /**< should special characters in command be prefixed by an escape char? */
731  	   )
732  	{
733  	   char s[SCIP_MAXSTRLEN];
734  	   char h[SCIP_MAXSTRLEN+1];
735  	   SCIP_Bool cleanuphistory;
736  	
737  	   assert(dialoghdlr != NULL);
738  	
739  	   /* the current history list should be cleaned up if a dialog is given (i.e. the command is not partial) */
740  	   cleanuphistory = (dialog != NULL);
741  	
742  	   /* generate the string to add to the history */
743  	   s[SCIP_MAXSTRLEN-1] = '\0';
744  	
745  	   if( command != NULL )
746  	   {
747  	      if( escapecommand )
748  	         SCIPescapeString(h, SCIP_MAXSTRLEN, command);
749  	      else
750  	         (void)SCIPstrncpy(h, command, SCIP_MAXSTRLEN);
751  	   }
752  	   else
753  	      h[0] = '\0';
754  	
755  	   while( dialog != NULL && dialog != dialoghdlr->rootdialog )
756  	   {
757  	      if( h[0] == '\0' )
758  	         (void)SCIPstrncpy(h, dialog->name, SCIP_MAXSTRLEN);
759  	      else
760  	      {
761  	         (void)SCIPsnprintf(s, SCIP_MAXSTRLEN, "%s %s", dialog->name, h);
762  	         (void)SCIPstrncpy(h, s, SCIP_MAXSTRLEN);
763  	      }
764  	      dialog = dialog->parent;
765  	   }
766  	
767  	   /* clean up the unmarked history entries */
768  	   if( cleanuphistory )
769  	   {
770  	      int i;
771  	
772  	      for( i = getHistoryLength()-1; i >= dialoghdlr->nprotectedhistelems; --i )
773  	      {
774  	         SCIP_CALL( removeHistory(i) );
775  	      }
776  	   }
777  	
778  	   /* add command to history */
779  	   if( h[0] != '\0' )
780  	   {
781  	      SCIP_CALL( addHistory(h) );
782  	   }
783  	
784  	   /* if the history string was a full command line, protect the history entry from future cleanups */
785  	   if( cleanuphistory )
786  	   {
787  	      dialoghdlr->nprotectedhistelems = getHistoryLength();
788  	   }
789  	
790  	   return SCIP_OKAY;
791  	}
792  	
793  	
794  	
795  	
796  	/*
797  	 * dialog
798  	 */
799  	
800  	/** ensures, that sub-dialogs array can store at least the given number of sub-dialogs */
801  	static
802  	SCIP_RETCODE ensureSubdialogMem(
803  	   SCIP_DIALOG*          dialog,             /**< dialog */
804  	   SCIP_SET*             set,                /**< global SCIP settings */
805  	   int                   num                 /**< minimal storage size for sub-dialogs */
806  	   )
807  	{
808  	   assert(dialog != NULL);
809  	
810  	   if( num > dialog->subdialogssize )
811  	   {
812  	      int newsize;
813  	
814  	      newsize = SCIPsetCalcMemGrowSize(set, num);
815  	      SCIP_ALLOC( BMSreallocMemoryArray(&(dialog->subdialogs), newsize) );
816  	      dialog->subdialogssize = newsize;
817  	   }
818  	   assert(num <= dialog->subdialogssize);
819  	
820  	   return SCIP_OKAY;
821  	}
822  	
823  	/** creates and captures a user interface dialog */
824  	SCIP_RETCODE SCIPdialogCreate(
825  	   SCIP_DIALOG**         dialog,             /**< pointer to store the dialog */
826  	   SCIP_DECL_DIALOGCOPY  ((*dialogcopy)),    /**< copy method of dialog or NULL if you don't want to copy your plugin into sub-SCIPs */
827  	   SCIP_DECL_DIALOGEXEC  ((*dialogexec)),    /**< execution method of dialog */
828  	   SCIP_DECL_DIALOGDESC  ((*dialogdesc)),    /**< description output method of dialog, or NULL */
829  	   SCIP_DECL_DIALOGFREE  ((*dialogfree)),    /**< destructor of dialog to free user data, or NULL */
830  	   const char*           name,               /**< name of dialog: command name appearing in parent's dialog menu */
831  	   const char*           desc,               /**< description of dialog used if description output method is NULL */
832  	   SCIP_Bool             issubmenu,          /**< is the dialog a sub-menu? */
833  	   SCIP_DIALOGDATA*      dialogdata          /**< user defined dialog data */
834  	   )
835  	{
836  	   SCIP_RETCODE retcode;
837  	
838  	   assert(dialog != NULL);
839  	   assert(name != NULL);
840  	
841  	   retcode = SCIP_OKAY;
842  	
843  	   SCIP_ALLOC( BMSallocMemory(dialog) );
844  	   (*dialog)->dialogcopy = dialogcopy;
845  	   (*dialog)->dialogexec = dialogexec;
846  	   (*dialog)->dialogdesc = dialogdesc;
847  	   (*dialog)->dialogfree = dialogfree;
848  	
849  	   SCIP_ALLOC_TERMINATE( retcode, BMSduplicateMemoryArray(&(*dialog)->name, name, strlen(name)+1), TERMINATE );
850  	   if( desc != NULL )
851  	   {
852  	      SCIP_ALLOC_TERMINATE( retcode, BMSduplicateMemoryArray(&(*dialog)->desc, desc, strlen(desc)+1), TERMINATE );
853  	   }
854  	   else
855  	      (*dialog)->desc = NULL;
856  	
857  	   (*dialog)->issubmenu = issubmenu;
858  	   (*dialog)->parent = NULL;
859  	   (*dialog)->subdialogs = NULL;
860  	   (*dialog)->nsubdialogs = 0;
861  	   (*dialog)->subdialogssize = 0;
862  	   (*dialog)->nuses = 0;
863  	   (*dialog)->dialogdata = dialogdata;
864  	
865  	   /* capture dialog */
866  	   SCIPdialogCapture(*dialog);
867  	
868  	 TERMINATE:
869  	   if( retcode != SCIP_OKAY )
870  	   {
871  	      BMSfreeMemoryArrayNull(&(*dialog)->name);
872  	      BMSfreeMemory(dialog);
873  	   }
874  	
875  	   return retcode;
876  	}
877  	
878  	/** frees dialog and all of its sub-dialogs */
879  	static
880  	SCIP_RETCODE dialogFree(
881  	   SCIP*                 scip,               /**< SCIP data structure */
882  	   SCIP_DIALOG**         dialog              /**< pointer to dialog */
883  	   )
884  	{
885  	   int i;
886  	
887  	   assert(dialog != NULL);
888  	   assert(*dialog != NULL);
889  	   assert((*dialog)->nuses == 0);
890  	
891  	   /* call destructor of dialog */
892  	   if( (*dialog)->dialogfree != NULL )
893  	   {
894  	      SCIP_CALL( (*dialog)->dialogfree(scip, *dialog) );
895  	   }
896  	
897  	   /* release sub-dialogs */
898  	   for( i = 0; i < (*dialog)->nsubdialogs; ++i )
899  	   {
900  	      SCIP_CALL( SCIPdialogRelease(scip, &(*dialog)->subdialogs[i]) );
901  	   }
902  	   BMSfreeMemoryArrayNull(&(*dialog)->subdialogs);
903  	
904  	   BMSfreeMemoryArrayNull(&(*dialog)->name);
905  	   BMSfreeMemoryArrayNull(&(*dialog)->desc);
906  	   BMSfreeMemory(dialog);
907  	
908  	   return SCIP_OKAY;
909  	}
910  	
911  	/** captures a dialog */
912  	void SCIPdialogCapture(
913  	   SCIP_DIALOG*          dialog              /**< dialog */
914  	   )
915  	{
916  	   assert(dialog != NULL);
917  	
918  	   dialog->nuses++;
919  	}
920  	
921  	/** releases a dialog */
922  	SCIP_RETCODE SCIPdialogRelease(
923  	   SCIP*                 scip,               /**< SCIP data structure */
924  	   SCIP_DIALOG**         dialog              /**< pointer to dialog */
925  	   )
926  	{
927  	   assert(dialog != NULL);
928  	
929  	   (*dialog)->nuses--;
930  	   if( (*dialog)->nuses == 0 )
931  	   {
932  	      SCIP_CALL( dialogFree(scip, dialog) );
933  	   }
934  	
935  	   return SCIP_OKAY;
936  	}
937  	
938  	/** executes dialog */
939  	SCIP_RETCODE SCIPdialogExec(
940  	   SCIP_DIALOG*          dialog,             /**< dialog */
941  	   SCIP_SET*             set,                /**< global SCIP settings */
942  	   SCIP_DIALOGHDLR*      dialoghdlr,         /**< dialog handler */
943  	   SCIP_DIALOG**         nextdialog          /**< pointer to store the next dialog to process */
944  	   )
945  	{
946  	   assert(dialog != NULL);
947  	   assert(dialog->dialogexec != NULL);
948  	   assert(set != NULL);
949  	   assert(nextdialog != NULL);
950  	
951  	   SCIP_CALL( dialog->dialogexec(set->scip, dialog, dialoghdlr, nextdialog) );
952  	
953  	   return SCIP_OKAY;
954  	}
955  	
956  	/** comparison method for sorting dialogs w.r.t. to their name */
957  	static
958  	SCIP_DECL_SORTPTRCOMP(dialogComp)
959  	{
960  	   return strcmp( SCIPdialogGetName((SCIP_DIALOG*)elem1), SCIPdialogGetName((SCIP_DIALOG*)elem2) );
961  	}
962  	
963  	/** adds a sub-dialog to the given dialog as menu entry and captures the sub-dialog */
964  	SCIP_RETCODE SCIPdialogAddEntry(
965  	   SCIP_DIALOG*          dialog,             /**< dialog */
966  	   SCIP_SET*             set,                /**< global SCIP settings */
967  	   SCIP_DIALOG*          subdialog           /**< sub-dialog to add as menu entry in dialog */
968  	   )
969  	{
970  	   assert(dialog != NULL);
971  	   assert(subdialog != NULL);
972  	
973  	   /* check, if sub-dialog already exists */
974  	   if( SCIPdialogHasEntry(dialog, SCIPdialogGetName(subdialog)) )
975  	   {
976  	      SCIPerrorMessage("dialog entry with name <%s> already exists in dialog <%s>\n",
977  	         SCIPdialogGetName(subdialog), SCIPdialogGetName(dialog));
978  	      return SCIP_INVALIDDATA;
979  	   }
980  	
981  	   /* resize the sub-dialogs array */
982  	   SCIP_CALL( ensureSubdialogMem(dialog, set, dialog->nsubdialogs+1) );
983  	
984  	   /* link the dialogs as parent-child pair; the sub-dialogs are sorted non-decreasing w.r.t. their name */
985  	   SCIPsortedvecInsertPtr((void**)dialog->subdialogs, dialogComp, (void*)subdialog, &dialog->nsubdialogs, NULL);
986  	   subdialog->parent = dialog;
987  	
988  	   /* capture sub-dialog */
989  	   SCIPdialogCapture(subdialog);
990  	
991  	   return SCIP_OKAY;
992  	}
993  	
994  	/** returns TRUE iff a dialog entry matching exactly the given name is existing in the given dialog */
995  	SCIP_Bool SCIPdialogHasEntry(
996  	   SCIP_DIALOG*          dialog,             /**< dialog */
997  	   const char*           entryname           /**< name of the dialog entry to find */
998  	   )
999  	{
1000 	   SCIP_DIALOG** subdialogs;
1001 	   int nsubdialogs;
1002 	   int i;
1003 	
1004 	   assert(dialog != NULL);
1005 	   assert(entryname != NULL);
1006 	
1007 	   /* check entryname w.r.t. available dialog options */
1008 	   subdialogs = SCIPdialogGetSubdialogs(dialog);
1009 	   nsubdialogs = SCIPdialogGetNSubdialogs(dialog);
1010 	   for( i = 0; i < nsubdialogs; ++i )
1011 	   {
1012 	      /* check, if the sub-dialog's name matches entryname */
1013 	      if( strcmp(entryname, SCIPdialogGetName(subdialogs[i])) == 0 )
1014 	         return TRUE;
1015 	   }
1016 	
1017 	   return FALSE;
1018 	}
1019 	
1020 	/** searches the dialog for entries corresponding to the given name;
1021 	 *  If a complete match is found, the entry is returned as "subdialog" and
1022 	 *  the return value is 1.
1023 	 *  If no dialog entry completely matches the given "entryname", the number
1024 	 *  of entries with names beginning with "entryname" is returned. If this
1025 	 *  number is 1, the single match is returned as "subdialog". Otherwise,
1026 	 *  "subdialog" is set to NULL.
1027 	 */
1028 	int SCIPdialogFindEntry(
1029 	   SCIP_DIALOG*          dialog,             /**< dialog */
1030 	   const char*           entryname,          /**< name of the dialog entry to find */
1031 	   SCIP_DIALOG**         subdialog           /**< pointer to store the found dialog entry */
1032 	   )
1033 	{
1034 	   SCIP_DIALOG** subdialogs;
1035 	   unsigned int namelen;
1036 	   int nsubdialogs;
1037 	   int nfound;
1038 	   int i;
1039 	
1040 	   assert(dialog != NULL);
1041 	   assert(entryname != NULL);
1042 	   assert(subdialog != NULL);
1043 	
1044 	   *subdialog = NULL;
1045 	
1046 	   /* check entryname w.r.t. available dialog options */
1047 	   subdialogs = SCIPdialogGetSubdialogs(dialog);
1048 	   nsubdialogs = SCIPdialogGetNSubdialogs(dialog);
1049 	   namelen = (unsigned int) strlen(entryname);
1050 	   nfound = 0;
1051 	   for( i = 0; i < nsubdialogs; ++i )
1052 	   {
1053 	      /* check, if the beginning of the sub-dialog's name matches entryname */
1054 	      if( strncmp(entryname, SCIPdialogGetName(subdialogs[i]), namelen) == 0 )
1055 	      {
1056 	         *subdialog = subdialogs[i];
1057 	         nfound++;
1058 	
1059 	         /* if entryname exactly matches the sub-dialog's name, use this sub-dialog */
1060 	         if( namelen == (unsigned int) strlen(SCIPdialogGetName(subdialogs[i])) )
1061 	            return 1;
1062 	      }
1063 	   }
1064 	
1065 	   if( nfound != 1 )
1066 	      *subdialog = NULL;
1067 	
1068 	   return nfound;
1069 	}
1070 	
1071 	/** displays the dialog's menu */
1072 	SCIP_RETCODE SCIPdialogDisplayMenu(
1073 	   SCIP_DIALOG*          dialog,             /**< dialog */
1074 	   SCIP*                 scip                /**< SCIP data structure */   
1075 	   )
1076 	{
1077 	   int i;
1078 	
1079 	   assert(dialog != NULL);
1080 	
1081 	   /* display the dialog's sub menus */
1082 	   for( i = 0; i < dialog->nsubdialogs; ++i )
1083 	   {
1084 	      if( SCIPdialogIsSubmenu(dialog->subdialogs[i]) )
1085 	      {
1086 	         SCIP_CALL( SCIPdialogDisplayMenuEntry(dialog->subdialogs[i], scip) );
1087 	      }
1088 	   }
1089 	
1090 	   /* display the dialog's menu options */
1091 	   for( i = 0; i < dialog->nsubdialogs; ++i )
1092 	   {
1093 	      if( !SCIPdialogIsSubmenu(dialog->subdialogs[i]) )
1094 	      {
1095 	         SCIP_CALL( SCIPdialogDisplayMenuEntry(dialog->subdialogs[i], scip) );
1096 	      }
1097 	   }
1098 	
1099 	   if( dialog->nsubdialogs == 0 )
1100 	      SCIPdialogMessage(scip, NULL, "<no options available>\n");
1101 	
1102 	   return SCIP_OKAY;
1103 	}
1104 	
1105 	/** displays the entry for the dialog in it's parent's menu */
1106 	SCIP_RETCODE SCIPdialogDisplayMenuEntry(
1107 	   SCIP_DIALOG*          dialog,             /**< dialog */
1108 	   SCIP*                 scip                /**< SCIP data structure */   
1109 	   )
1110 	{
1111 	   char name[SCIP_MAXSTRLEN];
1112 	
1113 	   assert(dialog != NULL);
1114 	
1115 	   /* display the dialog's name */
1116 	   if( dialog->issubmenu )
1117 	      (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "<%s>", dialog->name);
1118 	   else
1119 	      (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s", dialog->name);
1120 	   SCIPdialogMessage(scip, NULL, "  %-21s ", name);
1121 	   if( strlen(name) > 21 )
1122 	   {
1123 	      /* break the line, and start the description in the next line */
1124 	      SCIPdialogMessage(scip, NULL, "\n                   -->  ");
1125 	   }
1126 	
1127 	   /* display the dialog's description */
1128 	   if( dialog->dialogdesc != NULL )
1129 	   {
1130 	      SCIP_CALL( dialog->dialogdesc(scip, dialog) );
1131 	   }
1132 	   else
1133 	      SCIPdialogMessage(scip, NULL, "%s",dialog->desc);
1134 	   SCIPdialogMessage(scip, NULL, "\n");
1135 	
1136 	   return SCIP_OKAY;
1137 	}
1138 	
1139 	/** displays all dialog entries with names starting with the given "entryname" */
1140 	SCIP_RETCODE SCIPdialogDisplayCompletions(
1141 	   SCIP_DIALOG*          dialog,             /**< dialog */
1142 	   SCIP*                 scip,               /**< SCIP data structure */   
1143 	   const char*           entryname           /**< name of the dialog entry to find */
1144 	   )
1145 	{
1146 	   SCIP_DIALOG** subdialogs;
1147 	   unsigned int namelen;
1148 	   int nsubdialogs;
1149 	   int i;
1150 	
1151 	   assert(dialog != NULL);
1152 	   assert(entryname != NULL);
1153 	
1154 	   /* check entryname w.r.t. available dialog options */
1155 	   subdialogs = SCIPdialogGetSubdialogs(dialog);
1156 	   nsubdialogs = SCIPdialogGetNSubdialogs(dialog);
1157 	   namelen = (unsigned int) strlen(entryname);
1158 	   for( i = 0; i < nsubdialogs; ++i )
1159 	   {
1160 	      /* check, if the beginning of the sub-dialog's name matches entryname */
1161 	      if( strncmp(entryname, SCIPdialogGetName(subdialogs[i]), namelen) == 0 )
1162 	      {
1163 	         SCIP_CALL( SCIPdialogDisplayMenuEntry(subdialogs[i], scip) );
1164 	      }
1165 	   }
1166 	
1167 	   return SCIP_OKAY;
1168 	}
1169 	
1170 	/** gets the name of the current path in the dialog tree, separated by the given character */
1171 	void SCIPdialogGetPath(
1172 	   SCIP_DIALOG*          dialog,             /**< dialog */
1173 	   const char            sepchar,            /**< separation character to insert in path */
1174 	   char*                 path                /**< string buffer to store the path */
1175 	   )
1176 	{
1177 	   char s[SCIP_MAXSTRLEN];
1178 	
1179 	   assert(dialog != NULL);
1180 	
1181 	   (void)SCIPstrncpy(path, dialog->name, SCIP_MAXSTRLEN);
1182 	
1183 	   dialog = dialog->parent;
1184 	   while( dialog != NULL )
1185 	   {
1186 	      (void)SCIPsnprintf(s, SCIP_MAXSTRLEN, "%s%c%s", dialog->name, sepchar, path);
1187 	      (void)SCIPstrncpy(path, s, SCIP_MAXSTRLEN);
1188 	      dialog = dialog->parent;
1189 	   }
1190 	}
1191 	
1192 	/** gets the command name of the dialog */
1193 	const char* SCIPdialogGetName(
1194 	   SCIP_DIALOG*          dialog              /**< dialog */
1195 	   )
1196 	{
1197 	   assert(dialog != NULL);
1198 	
1199 	   return dialog->name;
1200 	}
1201 	
1202 	/** gets the description of the dialog */
1203 	const char* SCIPdialogGetDesc(
1204 	   SCIP_DIALOG*          dialog              /**< dialog */
1205 	   )
1206 	{
1207 	   assert(dialog != NULL);
1208 	
1209 	   return dialog->desc;
1210 	}
1211 	
1212 	/** returns whether the dialog is a sub menu */
1213 	SCIP_Bool SCIPdialogIsSubmenu(
1214 	   SCIP_DIALOG*          dialog              /**< dialog */
1215 	   )
1216 	{
1217 	   assert(dialog != NULL);
1218 	
1219 	   return dialog->issubmenu;
1220 	}
1221 	
1222 	/** gets the parent dialog of the given dialog */
1223 	SCIP_DIALOG* SCIPdialogGetParent(
1224 	   SCIP_DIALOG*          dialog              /**< dialog */
1225 	   )
1226 	{
1227 	   assert(dialog != NULL);
1228 	
1229 	   return dialog->parent;
1230 	}
1231 	
1232 	/** gets the array of sub-dialogs associated with the given dialog */
1233 	SCIP_DIALOG** SCIPdialogGetSubdialogs(
1234 	   SCIP_DIALOG*          dialog              /**< dialog */
1235 	   )
1236 	{
1237 	   assert(dialog != NULL);
1238 	
1239 	   return dialog->subdialogs;
1240 	}
1241 	
1242 	/** gets the number of sub-dialogs associated with the given dialog */
1243 	int SCIPdialogGetNSubdialogs(
1244 	   SCIP_DIALOG*          dialog              /**< dialog */
1245 	   )
1246 	{
1247 	   assert(dialog != NULL);
1248 	
1249 	   return dialog->nsubdialogs;
1250 	}
1251 	
1252 	/** gets the user defined data associated with the given dialog */
1253 	SCIP_DIALOGDATA* SCIPdialogGetData(
1254 	   SCIP_DIALOG*          dialog              /**< dialog */
1255 	   )
1256 	{
1257 	   assert(dialog != NULL);
1258 	
1259 	   return dialog->dialogdata;
1260 	}
1261 	
1262 	/** sets user data of dialog; user has to free old data in advance! */
1263 	void SCIPdialogSetData(
1264 	   SCIP_DIALOG*          dialog,             /**< dialog */
1265 	   SCIP_DIALOGDATA*      dialogdata          /**< new dialog user data */
1266 	   )
1267 	{
1268 	   assert(dialog != NULL);
1269 	
1270 	   dialog->dialogdata = dialogdata;
1271 	}
1272 	
1273 	/** writes command history to specified filename */
1274 	SCIP_RETCODE SCIPdialogWriteHistory(
1275 	   const char*           filename            /**< file name for (over)writing history */
1276 	   )
1277 	{
1278 	   return writeHistory(filename);
1279 	}
1280