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