Scippy

SCIP

Solving Constraint Integer Programs

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