Use calloc, rather than malloc/memset
[openafs.git] / src / gtx / frame.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  *
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 #include <afsconfig.h>
11 #include <afs/param.h>
12 #include <afs/stds.h>
13
14 #include <roken.h>
15
16 #include <lwp.h>
17
18 #include "gtxobjects.h"
19 #include "gtxwindows.h"
20 #include "gtxcurseswin.h"
21 #include "gtxinput.h"
22 #include "gtxkeymap.h"
23 #include "gtxframe.h"
24
25 static struct keymap_map *recursiveMap = 0;
26 static char menubuffer[1024];   /*Buffer for menu selections */
27 int gtxframe_exitValue = 0;     /*Program exit value */
28
29 int
30 gtxframe_CtrlUCmd(void *aparam, void *arock)
31 {
32     struct gwin *awindow = (struct gwin *) aparam;
33     struct gtx_frame *tframe;
34
35     tframe = awindow->w_frame;
36     if (!tframe->defaultLine)
37         return -1;
38     *(tframe->defaultLine) = 0;
39     return 0;
40 }
41
42 int
43 gtxframe_CtrlHCmd(void *aparam, void *arock)
44 {
45     struct gwin *awindow = (struct gwin *) aparam;
46
47     struct gtx_frame *tframe;
48     char *tp;
49     int pos;
50
51     tframe = awindow->w_frame;
52     if (!(tp = tframe->defaultLine))
53         return -1;
54     pos = strlen(tp);
55     if (pos == 0)
56         return 0;               /* rubout at the end of the line */
57     tp[pos - 1] = 0;
58     return 0;
59 }
60
61 int
62 gtxframe_RecursiveEndCmd(void *aparam, void *arock)
63 {
64     struct gwin *awindow = (struct gwin *) aparam;
65
66     struct gtx_frame *tframe;
67
68     tframe = awindow->w_frame;
69     tframe->flags |= GTXFRAME_RECURSIVEEND;
70     tframe->flags &= ~GTXFRAME_RECURSIVEERR;
71     return 0;
72 }
73
74 int
75 gtxframe_RecursiveErrCmd(void *aparam, void *arock)
76 {
77     struct gwin *awindow = (struct gwin *) aparam;
78
79     struct gtx_frame *tframe;
80
81     tframe = awindow->w_frame;
82     tframe->flags |= GTXFRAME_RECURSIVEEND;
83     tframe->flags |= GTXFRAME_RECURSIVEERR;
84     return 0;
85 }
86
87 int
88 gtxframe_SelfInsertCmd(void *aparam, void *rockparam)
89 {
90     struct gwin *awindow = (struct gwin *) aparam;
91
92     int arock = (intptr_t)rockparam;
93
94     struct gtx_frame *tframe;
95     int pos;
96     char *tp;
97
98     tframe = awindow->w_frame;
99     if (!(tp = tframe->defaultLine))
100         return -1;
101     pos = strlen(tp);
102     tp[pos] = arock;            /* arock has char to insert */
103     tp[pos + 1] = 0;            /* null-terminate it, too */
104     return 0;
105 }
106
107 /* save map, setup recursive map and install it */
108 static int
109 SaveMap(struct gtx_frame *aframe)
110 {
111     char tstring[2];
112     int i;
113
114     if (!recursiveMap) {
115         /* setup recursive edit map if not previously done */
116         recursiveMap = keymap_Create();
117         keymap_BindToString(recursiveMap, "\010", gtxframe_CtrlHCmd, NULL,
118                             NULL);
119         keymap_BindToString(recursiveMap, "\177", gtxframe_CtrlHCmd, NULL,
120                             NULL);
121         keymap_BindToString(recursiveMap, "\025", gtxframe_CtrlUCmd, NULL,
122                             NULL);
123         keymap_BindToString(recursiveMap, "\033", gtxframe_RecursiveEndCmd,
124                             NULL, NULL);
125         keymap_BindToString(recursiveMap, "\015", gtxframe_RecursiveEndCmd,
126                             NULL, NULL);
127         keymap_BindToString(recursiveMap, "\012", gtxframe_RecursiveEndCmd,
128                             NULL, NULL);
129         keymap_BindToString(recursiveMap, "\003", gtxframe_RecursiveErrCmd,
130                             NULL, NULL);
131         keymap_BindToString(recursiveMap, "\007", gtxframe_RecursiveErrCmd,
132                             NULL, NULL);
133
134         for (i = 040; i < 0177; i++) {
135             tstring[0] = i;
136             tstring[1] = 0;
137             keymap_BindToString(recursiveMap, tstring, gtxframe_SelfInsertCmd,
138                                 NULL, (void *)(intptr_t)i);
139         }
140     }
141     aframe->savemap = aframe->keymap;
142     aframe->keymap = recursiveMap;
143     keymap_InitState(aframe->keystate, aframe->keymap);
144     return 0;
145 }
146
147 /* Restore map to previous value */
148 static int
149 RestoreMap(struct gtx_frame *aframe)
150 {
151     aframe->keymap = aframe->savemap;
152     aframe->savemap = (struct keymap_map *)0;
153     keymap_InitState(aframe->keystate, aframe->keymap);
154     return 0;
155 }
156
157 int
158 gtxframe_SetFrame(struct gwin *awin, struct gtx_frame *aframe)
159 {
160     if (awin->w_frame) {
161         /* Unthread this frame */
162         awin->w_frame->window = NULL;
163     }
164     awin->w_frame = aframe;
165     aframe->window = awin;      /* Set frame's window ptr */
166     return 0;
167 }
168
169 struct gtx_frame *
170 gtxframe_GetFrame(struct gwin *awin)
171 {
172     return awin->w_frame;
173 }
174
175 /* Add a menu string to display list */
176 int
177 gtxframe_AddMenu(struct gtx_frame *aframe, char *alabel, char *astring)
178 {
179     struct gtxframe_menu *tmenu;
180
181     if (aframe->menus)
182         for (tmenu = aframe->menus; tmenu; tmenu = tmenu->next) {
183             if (strcmp(alabel, tmenu->name) == 0)
184                 break;
185     } else
186         tmenu = (struct gtxframe_menu *)0;
187     if (!tmenu) {
188         /* Handle everything but the command string, which is handled by the
189          * common-case code below */
190         tmenu = calloc(1, sizeof(*tmenu));
191         if (tmenu == (struct gtxframe_menu *)0)
192             return (-1);
193         tmenu->next = aframe->menus;
194         aframe->menus = tmenu;
195         tmenu->name = gtx_CopyString(alabel);
196     }
197
198     /*
199      * Common case: redo the string labels.  Note: at this point, tmenu
200      * points to a valid menu.
201      */
202     if (tmenu->cmdString)
203         free(tmenu->cmdString);
204     tmenu->cmdString = gtx_CopyString(astring);
205     return 0;
206 }
207
208 /* Delete a given menu from a frame*/
209 int
210 gtxframe_DeleteMenu(struct gtx_frame *aframe, char *alabel)
211 {
212     struct gtxframe_menu *tm, **lm;
213
214     for (lm = &aframe->menus, tm = *lm; tm; lm = &tm->next, tm = *lm) {
215         if (strcmp(alabel, tm->name) == 0) {
216             /* found it, remove and return success */
217             *lm = tm->next;     /* unthread from list */
218             free(tm->name);
219             free(tm->cmdString);
220             free(tm);
221             return (0);
222         }
223     }
224     return (-1);                /* failed to find entry to delete */
225 }
226
227 /* Function to remove all known menus */
228 int
229 gtxframe_ClearMenus(struct gtx_frame *aframe)
230 {
231
232     struct gtxframe_menu *tm, *nm;
233
234     if (aframe->menus != (struct gtxframe_menu *)0) {
235         for (tm = aframe->menus; tm; tm = nm) {
236             nm = tm->next;
237             free(tm->name);
238             free(tm->cmdString);
239             free(tm);
240         }
241     }
242
243     aframe->menus = (struct gtxframe_menu *)0;
244     return 0;
245 }
246
247 int
248 gtxframe_AskForString(struct gtx_frame *aframe, char *aprompt,
249                       char *adefault, char *aresult, int aresultSize)
250 {
251     int code;
252     char *tp;
253
254     /* Ensure recursive-edit map is initialized */
255     SaveMap(aframe);
256
257     /* Set up display */
258     if (aframe->promptLine)
259         free(aframe->promptLine);
260     if (aframe->defaultLine)
261         free(aframe->defaultLine);
262     aframe->promptLine = gtx_CopyString(aprompt);
263     tp = aframe->defaultLine = (char *)malloc(1024);
264     if (tp == NULL)
265         return (-1);
266     if (adefault)
267         strcpy(tp, adefault);
268     else
269         *tp = 0;
270
271     /* Do recursive edit */
272     gtx_InputServer(aframe->window);
273     tp = aframe->defaultLine;   /* In case command reallocated it */
274
275     /* Back from recursive edit, check out what's happened */
276     if (aframe->flags & GTXFRAME_RECURSIVEERR) {
277         code = -1;
278         goto done;
279     }
280     code = strlen(tp);
281     if (code + 1 > aresultSize) {
282         code = -2;
283         goto done;
284     }
285     strcpy(aresult, tp);
286     code = 0;
287
288     /* Fall through to cleanup and return code */
289   done:
290     RestoreMap(aframe);
291     if (aframe->promptLine)
292         free(aframe->promptLine);
293     if (aframe->defaultLine)
294         free(aframe->defaultLine);
295     aframe->defaultLine = aframe->promptLine = NULL;
296     if (code)
297         gtxframe_DisplayString(aframe, "[Aborted]");
298     return (code);
299 }
300
301 int
302 gtxframe_DisplayString(struct gtx_frame *aframe, char *amsgLine)
303 {
304     if (aframe->messageLine)
305         free(aframe->messageLine);
306     aframe->messageLine = gtx_CopyString(amsgLine);
307     return 0;
308 }
309
310 /* Called by input processor to try to clear the dude */
311 int
312 gtxframe_ClearMessageLine(struct gtx_frame *aframe)
313 {
314     /* If we haven't shown message long enough yet, just return */
315     if (aframe->flags & GTXFRAME_NEWDISPLAY)
316         return (0);
317     if (aframe->messageLine)
318         free(aframe->messageLine);
319     aframe->messageLine = NULL;
320     return (0);
321 }
322
323 static int
324 ShowMessageLine(struct gtx_frame *aframe)
325 {
326     struct gwin_strparams strparms;
327     struct gwin_sizeparams sizeparms;
328     char *tp;
329
330     if (!aframe->window)
331         return -1;
332
333     /* First, find window size */
334     WOP_GETDIMENSIONS(aframe->window, &sizeparms);
335
336     if (aframe->promptLine) {
337         memset(&strparms, 0, sizeof(strparms));
338         strparms.x = 0;
339         strparms.y = sizeparms.maxy - 1;
340         strparms.highlight = 1;
341         tp = strparms.s = (char *)malloc(1024);
342         strcpy(tp, aframe->promptLine);
343         strcat(tp, aframe->defaultLine);
344         WOP_DRAWSTRING(aframe->window, &strparms);
345         aframe->flags |= GTXFRAME_NEWDISPLAY;
346     } else if (aframe->messageLine) {
347         /* Otherwise we're visible, print the message at the bottom */
348         memset(&strparms, 0, sizeof(strparms));
349         strparms.highlight = 1;
350         strparms.x = 0;
351         strparms.y = sizeparms.maxy - 1;
352         strparms.s = aframe->messageLine;
353         WOP_DRAWSTRING(aframe->window, &strparms);
354         aframe->flags |= GTXFRAME_NEWDISPLAY;
355     }
356     return (0);
357 }
358
359 /* Exit function, returning whatever has been put in its argument */
360 int
361 gtxframe_ExitCmd(void *a_exitValuep, void *arock)
362 {                               /*gtxframe_ExitCmd */
363
364     int exitval;                /*Value we've been asked to exit with */
365
366     /* This next call should be type independent! */
367     gator_cursesgwin_cleanup(&gator_basegwin);
368
369     exitval = *((int *)(a_exitValuep));
370     exit(exitval);
371
372 }                               /*gtxframe_ExitCmd */
373
374 struct gtx_frame *
375 gtxframe_Create(void)
376 {
377     struct gtx_frame *tframe;
378     struct keymap_map *newkeymap;
379     struct keymap_state *newkeystate;
380
381     /*
382      * Allocate all the pieces first: frame, keymap, and key state.
383      */
384     tframe = calloc(1, sizeof(struct gtx_frame));
385     if (tframe == (struct gtx_frame *)0) {
386         return ((struct gtx_frame *)0);
387     }
388
389     newkeymap = keymap_Create();
390     if (newkeymap == (struct keymap_map *)0) {
391         /*
392          * Get rid of the frame before exiting.
393          */
394         free(tframe);
395         return ((struct gtx_frame *)0);
396     }
397
398     newkeystate = (struct keymap_state *)
399         malloc(sizeof(struct keymap_state));
400     if (newkeystate == (struct keymap_state *)0) {
401         /*
402          * Get rid of the frame AND the keymap before exiting.
403          */
404         free(tframe);
405         free(newkeymap);
406         return ((struct gtx_frame *)0);
407     }
408
409     /*
410      * Now that all the pieces exist, fill them in and stick them in
411      * the right places.
412      */
413     tframe->keymap = newkeymap;
414     tframe->keystate = newkeystate;
415     keymap_InitState(tframe->keystate, tframe->keymap);
416     keymap_BindToString(tframe->keymap, "\003", gtxframe_ExitCmd, "ExitCmd",
417                         (char *)(&gtxframe_exitValue));
418
419     /*
420      * At this point, we return successfully.
421      */
422     return (tframe);
423 }
424
425 int
426 gtxframe_Delete(struct gtx_frame *aframe)
427 {
428     keymap_Delete(aframe->keymap);
429     free(aframe->keystate);
430     if (aframe->messageLine)
431         free(aframe->messageLine);
432     free(aframe);
433     return 0;
434 }
435
436 int
437 gtxframe_Display(struct gtx_frame *aframe, struct gwin *awm)
438 {
439     struct gtxframe_dlist *tlist;
440     struct gtxframe_menu *tm;
441     struct gwin_strparams strparms;
442
443     /* Run through the menus, displaying them on the top line */
444     *menubuffer = 0;
445     for (tm = aframe->menus; tm; tm = tm->next) {
446         strcat(menubuffer, tm->name);
447         strcat(menubuffer, ":");
448         strcat(menubuffer, tm->cmdString);
449         strcat(menubuffer, " ");
450     }
451     if (menubuffer[0] != 0) {
452         memset(&strparms, 0, sizeof(strparms));
453         strparms.x = 0;
454         strparms.y = 0;
455         strparms.s = menubuffer;
456         strparms.highlight = 1;
457         WOP_DRAWSTRING(awm, &strparms);
458     }
459
460     /* Run through the display list, displaying all objects */
461     for (tlist = aframe->display; tlist; tlist = tlist->next) {
462         OOP_DISPLAY(((struct onode *)(tlist->data)));
463     }
464
465     /* Finally, show the message line */
466     ShowMessageLine(awm->w_frame);
467     return (0);
468 }
469
470 /* Add an object to a window's display list */
471 int
472 gtxframe_AddToList(struct gtx_frame *aframe, struct onode *aobj)
473 {
474     struct gtxframe_dlist *tlist;
475
476     for (tlist = aframe->display; tlist; tlist = tlist->next) {
477         if (tlist->data == (char *)aobj) {
478             /*
479              * Don't add the same thing twice.
480              */
481             return (-1);
482         }
483     }
484
485     /*
486      * OK, it's not alreadyt there.  Create a new list object, fill it
487      * in, and splice it on.
488      */
489     tlist = (struct gtxframe_dlist *)malloc(sizeof(struct gtxframe_dlist));
490     if (tlist == (struct gtxframe_dlist *)0)
491         return (-1);
492     tlist->data = (char *)aobj;
493     tlist->next = aframe->display;
494     aframe->display = tlist;
495     return (0);
496 }
497
498 /* Remove an object from a display list, if it is already there */
499 int
500 gtxframe_RemoveFromList(struct gtx_frame *aframe, struct onode *aobj)
501 {
502     struct gtxframe_dlist *tlist, **plist;
503
504     plist = &aframe->display;
505     for (tlist = *plist; tlist; plist = &tlist->next, tlist = *plist) {
506         if (tlist->data == (char *)aobj) {
507             *plist = tlist->next;
508             free(tlist);
509             return 0;
510         }
511     }
512     return (-1);                /* Item not found */
513 }
514
515 /* Clear out everything on the display list for the given frame*/
516 int
517 gtxframe_ClearList(struct gtx_frame *aframe)
518 {
519     struct gtxframe_dlist *tlist, *nlist;
520
521     if (aframe->display != (struct gtxframe_dlist *)0) {
522         /*
523          * Throw away each display list structure (we have at least
524          * one).
525          */
526         for (tlist = aframe->display; tlist; tlist = nlist) {
527             nlist = tlist->next;
528             free(tlist);
529         }
530     }
531
532     aframe->display = (struct gtxframe_dlist *)0;
533     return 0;
534 }