1 /* $Id: command.c,v 1.22 2016/12/04 15:22:16 tom Exp $ */
2 
3 #include <cdk_test.h>
4 
5 #ifdef HAVE_XCURSES
6 char *XCursesProgramName = "command";
7 #endif
8 
9 /* Define some global variables. */
10 #define MAXHISTORY	5000
11 static const char *introductionMessage[] =
12 {
13    "<C></B/16>Little Command Interface", "",
14    "<C>Written by Mike Glover", "",
15    "<C>Type </B>help<!B> to get help."};
16 
17 /* This structure is used for keeping command history. */
18 struct history_st
19 {
20    int count;
21    int current;
22    char *command[MAXHISTORY];
23 };
24 
25 /* Define some local prototypes. */
26 char *uc (char *word);
27 void help (CDKENTRY *entry);
28 static BINDFN_PROTO (historyUpCB);
29 static BINDFN_PROTO (historyDownCB);
30 static BINDFN_PROTO (viewHistoryCB);
31 static BINDFN_PROTO (listHistoryCB);
32 static BINDFN_PROTO (jumpWindowCB);
33 
34 /*
35  * Written by:	Mike Glover
36  * Purpose:
37  *		This creates a very simple command interface.
38  */
main(int argc,char ** argv)39 int main (int argc, char **argv)
40 {
41    /* *INDENT-EQLS* */
42    CDKSCREEN *cdkscreen         = 0;
43    CDKSWINDOW *commandOutput    = 0;
44    CDKENTRY *commandEntry       = 0;
45    chtype *convert              = 0;
46    const char *prompt           = "</B/24>Command >";
47    const char *title            = "<C></B/5>Command Output Window";
48    int promptLen                = 0;
49    int commandFieldWidth        = 0;
50    struct history_st history;
51    char temp[600];
52    int junk;
53 
54    /* Set up the history. */
55    history.current = 0;
56    history.count = 0;
57 
58    /* Check the command line for options. */
59    while (1)
60    {
61       int ret;
62 
63       /* Are there any more command line options to parse. */
64       if ((ret = getopt (argc, argv, "t:p:")) == -1)
65       {
66 	 break;
67       }
68       switch (ret)
69       {
70       case 'p':
71 	 prompt = copyChar (optarg);
72 	 break;
73 
74       case 't':
75 	 title = copyChar (optarg);
76 	 break;
77 
78       default:
79 	 break;
80       }
81    }
82 
83    cdkscreen = initCDKScreen (NULL);
84 
85    /* Start color. */
86    initCDKColor ();
87 
88    /* Create the scrolling window. */
89    commandOutput = newCDKSwindow (cdkscreen, CENTER, TOP, -8, -2,
90 				  title, 1000, TRUE, FALSE);
91 
92    /* Convert the prompt to a chtype and determine its length. */
93    convert = char2Chtype (prompt, &promptLen, &junk);
94    commandFieldWidth = COLS - promptLen - 4;
95    freeChtype (convert);
96 
97    /* Create the entry field. */
98    commandEntry = newCDKEntry (cdkscreen, CENTER, BOTTOM,
99 			       0, prompt,
100 			       A_BOLD | COLOR_PAIR (8),
101 			       COLOR_PAIR (24) | '_',
102 			       vMIXED, commandFieldWidth, 1, 512, FALSE, FALSE);
103 
104    /* Create the key bindings. */
105    bindCDKObject (vENTRY, commandEntry, KEY_UP, historyUpCB, &history);
106    bindCDKObject (vENTRY, commandEntry, KEY_DOWN, historyDownCB, &history);
107    bindCDKObject (vENTRY, commandEntry, KEY_TAB, viewHistoryCB, commandOutput);
108    bindCDKObject (vENTRY, commandEntry, CTRL ('^'), listHistoryCB, &history);
109    bindCDKObject (vENTRY, commandEntry, CTRL ('G'), jumpWindowCB, commandOutput);
110 
111    /* Draw the screen. */
112    refreshCDKScreen (cdkscreen);
113 
114    /* Show them who wrote this and how to get help. */
115    popupLabel (cdkscreen, (CDK_CSTRING2)introductionMessage, 5);
116    eraseCDKEntry (commandEntry);
117 
118    /* Do this forever. */
119    for (;;)
120    {
121       char *command = 0;
122       char *upper;
123 
124       /* Get the command. */
125       drawCDKEntry (commandEntry, ObjOf (commandEntry)->box);
126       command = activateCDKEntry (commandEntry, 0);
127       upper = uc (command);
128 
129       /* Check the output of the command. */
130       if (strcmp (upper, "QUIT") == 0 ||
131 	  strcmp (upper, "EXIT") == 0 ||
132 	  strcmp (upper, "Q") == 0 ||
133 	  strcmp (upper, "E") == 0 ||
134 	  commandEntry->exitType == vESCAPE_HIT)
135       {
136 	 /* All done. */
137 	 freeChar (upper);
138 
139 	 while (history.count-- > 0)
140 	    free (history.command[history.count]);
141 
142 	 destroyCDKEntry (commandEntry);
143 	 destroyCDKSwindow (commandOutput);
144 	 destroyCDKScreen (cdkscreen);
145 
146 	 endCDK ();
147 
148 	 ExitProgram (EXIT_SUCCESS);
149       }
150       else if (strcmp (command, "clear") == 0)
151       {
152 	 /* Keep the history. */
153 	 history.command[history.count] = copyChar (command);
154 	 history.count++;
155 	 history.current = history.count;
156 	 cleanCDKSwindow (commandOutput);
157 	 cleanCDKEntry (commandEntry);
158       }
159       else if (strcmp (command, "history") == 0)
160       {
161 	 /* Display the history list. */
162 	 listHistoryCB (vENTRY, commandEntry, &history, 0);
163 
164 	 /* Keep the history. */
165 	 history.command[history.count] = copyChar (command);
166 	 history.count++;
167 	 history.current = history.count;
168       }
169       else if (strcmp (command, "help") == 0)
170       {
171 	 /* Keep the history. */
172 	 history.command[history.count] = copyChar (command);
173 	 history.count++;
174 	 history.current = history.count;
175 
176 	 /* Display the help. */
177 	 help (commandEntry);
178 
179 	 /* Clean the entry field. */
180 	 cleanCDKEntry (commandEntry);
181 	 eraseCDKEntry (commandEntry);
182       }
183       else
184       {
185 	 /* Keep the history. */
186 	 history.command[history.count] = copyChar (command);
187 	 history.count++;
188 	 history.current = history.count;
189 
190 	 /* Jump to the bottom of the scrolling window. */
191 	 jumpToLineCDKSwindow (commandOutput, BOTTOM);
192 
193 	 /* Insert a line providing the command. */
194 	 sprintf (temp, "Command: </R>%s", command);
195 	 addCDKSwindow (commandOutput, temp, BOTTOM);
196 
197 	 /* Run the command. */
198 	 execCDKSwindow (commandOutput, command, BOTTOM);
199 
200 	 /* Clean out the entry field. */
201 	 cleanCDKEntry (commandEntry);
202       }
203 
204       /* Clean up a little. */
205       freeChar (upper);
206    }
207 }
208 
209 /*
210  * This is the callback for the down arrow.
211  */
historyUpCB(EObjectType cdktype GCC_UNUSED,void * object,void * clientData,chtype key GCC_UNUSED)212 static int historyUpCB (EObjectType cdktype GCC_UNUSED, void *object,
213 			void *clientData,
214 			chtype key GCC_UNUSED)
215 {
216    CDKENTRY *entry = (CDKENTRY *)object;
217    struct history_st *history = (struct history_st *)clientData;
218 
219    /* Make sure we don't go out of bounds. */
220    if (history->current == 0)
221    {
222       Beep ();
223       return (FALSE);
224    }
225 
226    /* Decrement the counter. */
227    history->current--;
228 
229    /* Display the command. */
230    setCDKEntryValue (entry, history->command[history->current]);
231    drawCDKEntry (entry, ObjOf (entry)->box);
232    return (FALSE);
233 }
234 
235 /*
236  * This is the callback for the down arrow.
237  */
historyDownCB(EObjectType cdktype GCC_UNUSED,void * object,void * clientData,chtype key GCC_UNUSED)238 static int historyDownCB (EObjectType cdktype GCC_UNUSED, void *object,
239 			  void *clientData,
240 			  chtype key GCC_UNUSED)
241 {
242    CDKENTRY *entry = (CDKENTRY *)object;
243    struct history_st *history = (struct history_st *)clientData;
244 
245    /* Make sure we don't go out of bounds. */
246    if (history->current == history->count)
247    {
248       Beep ();
249       return (FALSE);
250    }
251 
252    /* Increment the counter... */
253    history->current++;
254 
255    /* If we are at the end, clear the entry field. */
256    if (history->current == history->count)
257    {
258       cleanCDKEntry (entry);
259       drawCDKEntry (entry, ObjOf (entry)->box);
260       return (FALSE);
261    }
262 
263    /* Display the command. */
264    setCDKEntryValue (entry, history->command[history->current]);
265    drawCDKEntry (entry, ObjOf (entry)->box);
266    return (FALSE);
267 }
268 
269 /*
270  * This callback allows the user to play with the scrolling window.
271  */
viewHistoryCB(EObjectType cdktype GCC_UNUSED,void * object,void * clientData,chtype key GCC_UNUSED)272 static int viewHistoryCB (EObjectType cdktype GCC_UNUSED, void *object,
273 			  void *clientData,
274 			  chtype key GCC_UNUSED)
275 {
276    CDKSWINDOW *swindow = (CDKSWINDOW *)clientData;
277    CDKENTRY *entry = (CDKENTRY *)object;
278 
279    /* Let them play... */
280    activateCDKSwindow (swindow, 0);
281 
282    /* Redraw the entry field. */
283    drawCDKEntry (entry, ObjOf (entry)->box);
284    return (FALSE);
285 }
286 
287 /*
288  * This callback jumps to a line in the scrolling window.
289  */
jumpWindowCB(EObjectType cdktype GCC_UNUSED,void * object,void * clientData,chtype key GCC_UNUSED)290 static int jumpWindowCB (EObjectType cdktype GCC_UNUSED, void *object,
291 			 void *clientData,
292 			 chtype key GCC_UNUSED)
293 {
294    CDKENTRY *entry = (CDKENTRY *)object;
295    CDKSWINDOW *swindow = (CDKSWINDOW *)clientData;
296    CDKSCALE *scale = 0;
297    int line;
298 
299    /* Ask them which line they want to jump to. */
300    scale = newCDKScale (ScreenOf (entry), CENTER, CENTER,
301 			"<C>Jump To Which Line",
302 			"Line",
303 			A_NORMAL, 5,
304 			0, 0, swindow->listSize, 1, 2, TRUE, FALSE);
305 
306    /* Get the line. */
307    line = activateCDKScale (scale, 0);
308 
309    /* Clean up. */
310    destroyCDKScale (scale);
311 
312    /* Jump to the line. */
313    jumpToLineCDKSwindow (swindow, line);
314 
315    /* Redraw the widgets. */
316    drawCDKEntry (entry, ObjOf (entry)->box);
317    return (FALSE);
318 }
319 
320 /*
321  * This callback allows the user to pick from the history list from a
322  * scrolling list.
323  */
listHistoryCB(EObjectType cdktype GCC_UNUSED,void * object,void * clientData,chtype key GCC_UNUSED)324 static int listHistoryCB (EObjectType cdktype GCC_UNUSED, void *object,
325 			  void *clientData,
326 			  chtype key GCC_UNUSED)
327 {
328    CDKENTRY *entry = (CDKENTRY *)object;
329    struct history_st *history = (struct history_st *)clientData;
330    CDKSCROLL *scrollList;
331    int height = (history->count < 10 ? history->count + 3 : 13);
332    int selection;
333 
334    /* No history, no list. */
335    if (history->count == 0)
336    {
337       /* Popup a little window telling the user there are no commands. */
338       const char *mesg[] =
339       {
340 	 "<C></B/16>No Commands Entered",
341 	 "<C>No History"
342       };
343       popupLabel (ScreenOf (entry), (CDK_CSTRING2)mesg, 2);
344 
345       /* Redraw the screen. */
346       eraseCDKEntry (entry);
347       drawCDKScreen (ScreenOf (entry));
348 
349       /* And leave... */
350       return (FALSE);
351    }
352 
353    /* Create the scrolling list of previous commands. */
354    scrollList = newCDKScroll (ScreenOf (entry), CENTER, CENTER, RIGHT,
355 			      height, 20, "<C></B/29>Command History",
356 			      (CDK_CSTRING2)history->command,
357 			      history->count,
358 			      NUMBERS, A_REVERSE, TRUE, FALSE);
359 
360    /* Get the command to execute. */
361    selection = activateCDKScroll (scrollList, 0);
362    destroyCDKScroll (scrollList);
363 
364    /* Check the results of the selection. */
365    if (selection >= 0)
366    {
367       /* Get the command and stick it back in the entry field. */
368       setCDKEntryValue (entry, history->command[selection]);
369    }
370 
371    /* Redraw the screen. */
372    eraseCDKEntry (entry);
373    drawCDKScreen (ScreenOf (entry));
374    return (FALSE);
375 }
376 
377 /*
378  * This function displays help.
379  */
help(CDKENTRY * entry)380 void help (CDKENTRY *entry)
381 {
382    const char *mesg[25];
383 
384    /* Create the help message. */
385    mesg[0] = "<C></B/29>Help";
386    mesg[1] = "";
387    mesg[2] = "</B/24>When in the command line.";
388    mesg[3] = "<B=history   > Displays the command history.";
389    mesg[4] = "<B=Ctrl-^    > Displays the command history.";
390    mesg[5] = "<B=Up Arrow  > Scrolls back one command.";
391    mesg[6] = "<B=Down Arrow> Scrolls forward one command.";
392    mesg[7] = "<B=Tab       > Activates the scrolling window.";
393    mesg[8] = "<B=help      > Displays this help window.";
394    mesg[9] = "";
395    mesg[10] = "</B/24>When in the scrolling window.";
396    mesg[11] = "<B=l or L    > Loads a file into the window.";
397    mesg[12] = "<B=s or S    > Saves the contents of the window to a file.";
398    mesg[13] = "<B=Up Arrow  > Scrolls up one line.";
399    mesg[14] = "<B=Down Arrow> Scrolls down one line.";
400    mesg[15] = "<B=Page Up   > Scrolls back one page.";
401    mesg[16] = "<B=Page Down > Scrolls forward one page.";
402    mesg[17] = "<B=Tab/Escape> Returns to the command line.";
403    mesg[18] = "";
404    mesg[19] = "<C> (</B/24>Refer to the scrolling window online manual for more help<!B!24>.)";
405    popupLabel (ScreenOf (entry), (CDK_CSTRING2)mesg, 20);
406 }
407 
408 /*
409  * This converts a word to upper case.
410  */
uc(char * word)411 char *uc (char *word)
412 {
413    char *upper = 0;
414    int length = 0;
415    int x;
416 
417    /* Make sure the word is not null. */
418    if (word == 0)
419    {
420       return 0;
421    }
422    length = (int)strlen (word);
423 
424    /* Get the memory for the new word. */
425    upper = (char *)malloc (sizeof (char) * (size_t) (length + 2));
426    if (upper == 0)
427    {
428       return (word);
429    }
430 
431    /* Start converting the case. */
432    for (x = 0; x < length; x++)
433    {
434       int ch = (unsigned char)(word[x]);
435       if (isalpha (ch))
436       {
437 	 upper[x] = (char)toupper (ch);
438       }
439       else
440       {
441 	 upper[x] = word[x];
442       }
443    }
444    upper[length] = '\0';
445    return upper;
446 }
447