xref: /freebsd/contrib/ncurses/menu/m_item_new.c (revision 19261079b74319502c6ffa1249920079f0f69a72)
1 /****************************************************************************
2  * Copyright 2020,2021 Thomas E. Dickey                                     *
3  * Copyright 1998-2010,2012 Free Software Foundation, Inc.                  *
4  *                                                                          *
5  * Permission is hereby granted, free of charge, to any person obtaining a  *
6  * copy of this software and associated documentation files (the            *
7  * "Software"), to deal in the Software without restriction, including      *
8  * without limitation the rights to use, copy, modify, merge, publish,      *
9  * distribute, distribute with modifications, sublicense, and/or sell       *
10  * copies of the Software, and to permit persons to whom the Software is    *
11  * furnished to do so, subject to the following conditions:                 *
12  *                                                                          *
13  * The above copyright notice and this permission notice shall be included  *
14  * in all copies or substantial portions of the Software.                   *
15  *                                                                          *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
17  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
18  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
19  * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
20  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
21  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
22  * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
23  *                                                                          *
24  * Except as contained in this notice, the name(s) of the above copyright   *
25  * holders shall not be used in advertising or otherwise to promote the     *
26  * sale, use or other dealings in this Software without prior written       *
27  * authorization.                                                           *
28  ****************************************************************************/
29 
30 /****************************************************************************
31  *   Author:  Juergen Pfeifer, 1995,1997                                    *
32  ****************************************************************************/
33 
34 /***************************************************************************
35 * Module m_item_new                                                        *
36 * Create and destroy menu items                                            *
37 * Set and get marker string for menu                                       *
38 ***************************************************************************/
39 
40 #include "menu.priv.h"
41 
42 #if USE_WIDEC_SUPPORT
43 #if HAVE_WCTYPE_H
44 #include <wctype.h>
45 #endif
46 #endif
47 
48 MODULE_ID("$Id: m_item_new.c,v 1.37 2021/02/13 19:40:51 tom Exp $")
49 
50 /*---------------------------------------------------------------------------
51 |   Facility      :  libnmenu
52 |   Function      :  bool Is_Printable_String(const char *s)
53 |
54 |   Description   :  Checks whether or not the string contains only printable
55 |                    characters.
56 |
57 |   Return Values :  TRUE     - if string is printable
58 |                    FALSE    - if string contains non-printable characters
59 +--------------------------------------------------------------------------*/
60 static bool
61 Is_Printable_String(const char *s)
62 {
63   int result = TRUE;
64 
65 #if USE_WIDEC_SUPPORT
66   int count = (int)mbstowcs(0, s, 0);
67   wchar_t *temp = 0;
68 
69   assert(s);
70 
71   if (count > 0
72       && (temp = typeCalloc(wchar_t, (2 + (unsigned)count))) != 0)
73     {
74       int n;
75 
76       mbstowcs(temp, s, (unsigned)count);
77       for (n = 0; n < count; ++n)
78 	if (!iswprint((wint_t)temp[n]))
79 	  {
80 	    result = FALSE;
81 	    break;
82 	  }
83       free(temp);
84     }
85 #else
86   assert(s);
87   while (*s)
88     {
89       if (!isprint(UChar(*s)))
90 	{
91 	  result = FALSE;
92 	  break;
93 	}
94       s++;
95     }
96 #endif
97   return result;
98 }
99 
100 /*---------------------------------------------------------------------------
101 |   Facility      :  libnmenu
102 |   Function      :  ITEM *new_item(char *name, char *description)
103 |
104 |   Description   :  Create a new item with name and description. Return
105 |                    a pointer to this new item.
106 |                    N.B.: an item must(!) have a name.
107 |
108 |   Return Values :  The item pointer or NULL if creation failed.
109 +--------------------------------------------------------------------------*/
110 MENU_EXPORT(ITEM *)
111 new_item(const char *name, const char *description)
112 {
113   ITEM *item;
114 
115   T((T_CALLED("new_item(\"%s\", \"%s\")"),
116      name ? name : "",
117      description ? description : ""));
118 
119   if (!name || (*name == '\0') || !Is_Printable_String(name))
120     {
121       item = (ITEM *)0;
122       SET_ERROR(E_BAD_ARGUMENT);
123     }
124   else
125     {
126       item = typeCalloc(ITEM, 1);
127 
128       if (item)
129 	{
130 	  T((T_CREATE("item %p"), (void *)item));
131 	  *item = _nc_Default_Item;	/* hope we have struct assignment */
132 
133 	  item->name.length = (unsigned short)strlen(name);
134 	  item->name.str = name;
135 
136 	  if (description && (*description != '\0') &&
137 	      Is_Printable_String(description))
138 	    {
139 	      item->description.length = (unsigned short)strlen(description);
140 	      item->description.str = description;
141 	    }
142 	  else
143 	    {
144 	      item->description.length = 0;
145 	      item->description.str = (char *)0;
146 	    }
147 	}
148       else
149 	SET_ERROR(E_SYSTEM_ERROR);
150     }
151   returnItem(item);
152 }
153 
154 /*---------------------------------------------------------------------------
155 |   Facility      :  libnmenu
156 |   Function      :  int free_item(ITEM *item)
157 |
158 |   Description   :  Free the allocated storage for this item.
159 |                    N.B.: a connected item can't be freed.
160 |
161 |   Return Values :  E_OK              - success
162 |                    E_BAD_ARGUMENT    - invalid value has been passed
163 |                    E_CONNECTED       - item is still connected to a menu
164 +--------------------------------------------------------------------------*/
165 MENU_EXPORT(int)
166 free_item(ITEM *item)
167 {
168   T((T_CALLED("free_item(%p)"), (void *)item));
169 
170   if (!item)
171     RETURN(E_BAD_ARGUMENT);
172 
173   if (item->imenu)
174     RETURN(E_CONNECTED);
175 
176   free(item);
177 
178   RETURN(E_OK);
179 }
180 
181 /*---------------------------------------------------------------------------
182 |   Facility      :  libnmenu
183 |   Function      :  int set_menu_mark( MENU *menu, const char *mark )
184 |
185 |   Description   :  Set the mark string used to indicate the current
186 |                    item (single-valued menu) or the selected items
187 |                    (multi-valued menu).
188 |                    The mark argument may be NULL, in which case no
189 |                    marker is used.
190 |                    This might be a little bit tricky, because this may
191 |                    affect the geometry of the menu, which we don't allow
192 |                    if it is already posted.
193 |
194 |   Return Values :  E_OK               - success
195 |                    E_BAD_ARGUMENT     - an invalid value has been passed
196 |                    E_SYSTEM_ERROR     - no memory to store mark
197 +--------------------------------------------------------------------------*/
198 MENU_EXPORT(int)
199 set_menu_mark(MENU *menu, const char *mark)
200 {
201   short l;
202 
203   T((T_CALLED("set_menu_mark(%p,%s)"), (void *)menu, _nc_visbuf(mark)));
204 
205   if (mark && (*mark != '\0') && Is_Printable_String(mark))
206     l = (short)strlen(mark);
207   else
208     l = 0;
209 
210   if (menu)
211     {
212       char *old_mark = menu->mark;
213       unsigned short old_status = menu->status;
214 
215       if (menu->status & _POSTED)
216 	{
217 	  /* If the menu is already posted, the geometry is fixed. Then
218 	     we can only accept a mark with exactly the same length */
219 	  if (menu->marklen != l)
220 	    RETURN(E_BAD_ARGUMENT);
221 	}
222       menu->marklen = l;
223       if (l)
224 	{
225 	  menu->mark = strdup(mark);
226 	  if (menu->mark)
227 	    {
228 	      if (menu != &_nc_Default_Menu)
229 		SetStatus(menu, _MARK_ALLOCATED);
230 	    }
231 	  else
232 	    {
233 	      menu->mark = old_mark;
234 	      menu->marklen = (short)((old_mark != 0) ? strlen(old_mark) : 0);
235 	      RETURN(E_SYSTEM_ERROR);
236 	    }
237 	}
238       else
239 	menu->mark = (char *)0;
240 
241       if ((old_status & _MARK_ALLOCATED) && old_mark)
242 	free(old_mark);
243 
244       if (menu->status & _POSTED)
245 	{
246 	  _nc_Draw_Menu(menu);
247 	  _nc_Show_Menu(menu);
248 	}
249       else
250 	{
251 	  /* Recalculate the geometry */
252 	  _nc_Calculate_Item_Length_and_Width(menu);
253 	}
254     }
255   else
256     {
257       returnCode(set_menu_mark(&_nc_Default_Menu, mark));
258     }
259   RETURN(E_OK);
260 }
261 
262 /*---------------------------------------------------------------------------
263 |   Facility      :  libnmenu
264 |   Function      :  char *menu_mark(const MENU *menu)
265 |
266 |   Description   :  Return a pointer to the marker string
267 |
268 |   Return Values :  The marker string pointer or NULL if no marker defined
269 +--------------------------------------------------------------------------*/
270 MENU_EXPORT(const char *)
271 menu_mark(const MENU *menu)
272 {
273   T((T_CALLED("menu_mark(%p)"), (const void *)menu));
274   returnPtr(Normalize_Menu(menu)->mark);
275 }
276 
277 /* m_item_new.c */
278