[mucurses] Avoid potential division by zero
[ipxe.git] / src / hci / mucurses / slk.c
1 #include <curses.h>
2 #include <stddef.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include <assert.h>
6 #include "mucurses.h"
7 #include "cursor.h"
8
9 /** @file
10 *
11 * Soft label key functions
12 */
13
14 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
15
16 #define MIN_SPACE_SIZE 2
17
18 #define SLK_MAX_LABEL_LEN 8
19
20 #define SLK_MAX_NUM_LABELS 12
21
22 #define SLK_MAX_NUM_SPACES 2
23
24 struct _softlabel {
25 // label string
26 char label[SLK_MAX_LABEL_LEN];
27 /* Format of soft label
28 0: left justify
29 1: centre justify
30 2: right justify
31 */
32 unsigned int fmt;
33 };
34
35 struct _softlabelkeys {
36 struct _softlabel fkeys[SLK_MAX_NUM_LABELS];
37 attr_t attrs;
38 /* Soft label layout format
39 0: 3-2-3
40 1: 4-4
41 2: 4-4-4
42 3: 4-4-4 with index line
43 */
44 unsigned int fmt;
45 unsigned int max_label_len;
46 unsigned int maj_space_len;
47 unsigned int num_labels;
48 unsigned int num_spaces;
49 unsigned int spaces[SLK_MAX_NUM_SPACES];
50 struct cursor_pos saved_cursor;
51 attr_t saved_attrs;
52 short saved_pair;
53 };
54
55 static struct _softlabelkeys *slks;
56
57 /*
58 I either need to break the primitives here, or write a collection of
59 functions specifically for SLKs that directly access the screen
60 functions - since this technically isn't part of stdscr, I think
61 this should be ok...
62 */
63
64 static void _enter_slk ( void ) {
65 _store_curs_pos ( stdscr, &slks->saved_cursor );
66 wattr_get ( stdscr, &slks->saved_attrs, &slks->saved_pair, NULL );
67 LINES++;
68 wmove ( stdscr, LINES, 0 );
69 wattrset ( stdscr, slks->attrs );
70 }
71
72 static void _leave_slk ( void ) {
73 LINES--;
74 wattr_set ( stdscr, slks->saved_attrs, slks->saved_pair, NULL );
75 _restore_curs_pos ( stdscr, &slks->saved_cursor );
76 }
77
78 static void _print_label ( struct _softlabel sl ) {
79 int space_ch;
80 char str[SLK_MAX_LABEL_LEN + 1];
81
82 assert ( slks->max_label_len <= SLK_MAX_LABEL_LEN );
83 space_ch = ' ';
84 memset ( str, 0, sizeof ( str ) );
85
86 // protect against gaps in the soft label keys array
87 if ( ! sl.label[0] ) {
88 memset( str, space_ch, (size_t)(slks->max_label_len) );
89 } else {
90 /* we need to pad the label with varying amounts of leading
91 pad depending on the format of the label */
92 if ( sl.fmt == 1 ) {
93 memset( str, space_ch,
94 (size_t)(slks->max_label_len
95 - strlen(sl.label)) / 2 );
96 }
97 if ( sl.fmt == 2 ) {
98 memset( str, space_ch,
99 (size_t)(slks->max_label_len
100 - strlen(sl.label)) );
101 }
102 strcat(str,sl.label);
103
104 // post-padding
105 memset(str+strlen(str), space_ch,
106 (size_t)(slks->max_label_len - strlen(str)) );
107 }
108
109 // print the formatted label
110 _wputstr ( stdscr, str, NOWRAP, slks->max_label_len );
111 }
112
113 /**
114 * Return the attribute used for the soft function keys
115 *
116 * @ret attrs the current attributes of the soft function keys
117 */
118 attr_t slk_attr ( void ) {
119 return ( slks == NULL ? 0 : slks->attrs );
120 }
121
122 /**
123 * Turn off soft function key attributes
124 *
125 * @v attrs attribute bit mask
126 * @ret rc return status code
127 */
128 int slk_attroff ( const chtype attrs ) {
129 if ( slks == NULL )
130 return ERR;
131 slks->attrs &= ~( attrs & A_ATTRIBUTES );
132 return OK;
133 }
134
135 /**
136 * Turn on soft function key attributes
137 *
138 * @v attrs attribute bit mask
139 * @ret rc return status code
140 */
141 int slk_attron ( const chtype attrs ) {
142 if ( slks == NULL )
143 return ERR;
144 slks->attrs |= ( attrs & A_ATTRIBUTES );
145 return OK;
146 }
147
148 /**
149 * Set soft function key attributes
150 *
151 * @v attrs attribute bit mask
152 * @ret rc return status code
153 */
154 int slk_attrset ( const chtype attrs ) {
155 if ( slks == NULL )
156 return ERR;
157 slks->attrs = ( attrs & A_ATTRIBUTES );
158 return OK;
159 }
160
161 /**
162 * Turn off soft function key attributes
163 *
164 * @v attrs attribute bit mask
165 * @v *opts undefined (for future implementation)
166 * @ret rc return status code
167 */
168 int slk_attr_off ( const attr_t attrs, void *opts __unused ) {
169 return slk_attroff( attrs );
170 }
171
172 /**
173 * Turn on soft function key attributes
174 *
175 * @v attrs attribute bit mask
176 * @v *opts undefined (for future implementation)
177 * @ret rc return status code
178 */
179 int slk_attr_on ( attr_t attrs, void *opts __unused ) {
180 return slk_attron( attrs );
181 }
182
183 /**
184 * Set soft function key attributes
185 *
186 * @v attrs attribute bit mask
187 * @v colour_pair_number colour pair integer
188 * @v *opts undefined (for future implementation)
189 * @ret rc return status code
190 */
191 int slk_attr_set ( const attr_t attrs, short colour_pair_number,
192 void *opts __unused ) {
193 if ( slks == NULL )
194 return ERR;
195
196 if ( ( unsigned short )colour_pair_number > COLORS )
197 return ERR;
198
199 slks->attrs = ( (unsigned short)colour_pair_number << CPAIR_SHIFT ) |
200 ( attrs & A_ATTRIBUTES );
201 return OK;
202 }
203
204 /**
205 * Clear the soft function key labels from the screen
206 *
207 * @ret rc return status code
208 */
209 int slk_clear ( void ) {
210 if ( slks == NULL )
211 return ERR;
212
213 _enter_slk();
214 wclrtoeol ( stdscr );
215 _leave_slk();
216
217 return OK;
218 }
219
220 /**
221 * Set soft label colour pair
222 */
223 int slk_colour ( short colour_pair_number ) {
224 if ( slks == NULL )
225 return ERR;
226 if ( ( unsigned short )colour_pair_number > COLORS )
227 return ERR;
228
229 slks->attrs = ( (unsigned short)colour_pair_number << CPAIR_SHIFT )
230 | ( slks->attrs & A_ATTRIBUTES );
231
232 return OK;
233 }
234
235 /**
236 * Initialise the soft function keys
237 *
238 * @v fmt format of keys
239 * @ret rc return status code
240 */
241 int slk_init ( int fmt ) {
242 unsigned short nmaj, nmin, nblocks, available_width;
243
244 if ( (unsigned)fmt > 3 ) {
245 return ERR;
246 }
247
248 /* There seems to be no API call to free this data structure... */
249 if ( ! slks )
250 slks = calloc(1,sizeof(*slks));
251 if ( ! slks )
252 return ERR;
253
254 slks->attrs = A_DEFAULT;
255 slks->fmt = fmt;
256 switch(fmt) {
257 case 0:
258 nblocks = 8; nmaj = 2; nmin = 5;
259 slks->spaces[0] = 2; slks->spaces[1] = 4;
260 break;
261 case 1:
262 nblocks = 8; nmaj = 1; nmin = 6;
263 slks->spaces[0] = 3;
264 break;
265 case 2:
266 // same allocations as format 3
267 case 3:
268 nblocks = 12; nmaj = 2; nmin = 9;
269 slks->spaces[0] = 3; slks->spaces[1] = 7;
270 break;
271 default:
272 return ERR;
273 }
274
275 // determine maximum label length and major space size
276 available_width = COLS - ( ( MIN_SPACE_SIZE * nmaj ) + nmin );
277 slks->max_label_len = available_width / nblocks;
278 slks->maj_space_len = MIN_SPACE_SIZE +
279 ( available_width % nblocks ) / nmaj;
280 slks->num_spaces = nmaj;
281 slks->num_labels = nblocks;
282
283 // strip a line from the screen
284 LINES -= 1;
285
286 return OK;
287 }
288
289 /**
290 * Return the label for the specified soft key
291 *
292 * @v labnum soft key identifier
293 * @ret label return label
294 */
295 char* slk_label ( int labnum ) {
296 if ( slks == NULL )
297 return NULL;
298
299 return slks->fkeys[labnum].label;
300 }
301
302 /**
303 * Restore soft function key labels to the screen
304 *
305 * @ret rc return status code
306 */
307 int slk_restore ( void ) {
308 unsigned int i, j, pos_x,
309 *next_space, *last_space;
310 chtype space_ch;
311
312 if ( slks == NULL )
313 return ERR;
314
315 pos_x = 0;
316
317 _enter_slk();
318
319 space_ch = (chtype)' ' | slks->attrs;
320 next_space = &(slks->spaces[0]);
321 last_space = &(slks->spaces[slks->num_spaces-1]);
322
323 for ( i = 0; i < slks->num_labels ; i++ ) {
324 _print_label( slks->fkeys[i] );
325 pos_x += slks->max_label_len;
326
327 if ( i == *next_space ) {
328 for ( j = 0; j < slks->maj_space_len; j++, pos_x++ )
329 _wputch ( stdscr, space_ch, NOWRAP );
330 if ( next_space < last_space )
331 next_space++;
332 } else {
333 if ( pos_x < COLS )
334 _wputch ( stdscr, space_ch, NOWRAP );
335 pos_x++;
336 }
337 }
338
339 _leave_slk();
340
341 return OK;
342 }
343
344 /**
345 * Configure specified soft key
346 *
347 * @v labnum soft label position to configure
348 * @v *label string to use as soft key label
349 * @v fmt justification format of label
350 * @ret rc return status code
351 */
352 int slk_set ( int labnum, const char *label, int fmt ) {
353 if ( slks == NULL )
354 return ERR;
355 if ( (unsigned short)labnum >= slks->num_labels )
356 return ERR;
357 if ( (unsigned short)fmt >= 3 )
358 return ERR;
359
360 strncpy(slks->fkeys[labnum].label, label,
361 (sizeof(slks->fkeys[labnum].label) - 1));
362 slks->fkeys[labnum].fmt = fmt;
363
364 return OK;
365 }