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