1/*	$NetBSD: type_integer.c,v 1.9 2021/04/13 13:13:04 christos Exp $	*/
2
3/*-
4 * Copyright (c) 1998-1999 Brett Lymn
5 *                         (blymn@baea.com.au, brett_lymn@yahoo.com.au)
6 * All rights reserved.
7 *
8 * This code has been donated to The NetBSD Foundation by the Author.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. The name of the author may not be used to endorse or promote products
16 *    derived from this software without specific prior written permission
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 *
29 *
30 */
31
32#include <sys/cdefs.h>
33__RCSID("$NetBSD: type_integer.c,v 1.9 2021/04/13 13:13:04 christos Exp $");
34
35#include <stdlib.h>
36#include <strings.h>
37#include <ctype.h>
38#include "form.h"
39#include "internals.h"
40
41/*
42 * The integer type handling.
43 */
44
45typedef struct
46{
47	unsigned precision;
48	long min;
49	long max;
50} integer_args;
51
52/*
53 * Create the integer arguments structure from the given args.  Return NULL
54 * if the call fails, otherwise return a pointer to the structure allocated.
55 */
56static char *
57create_integer_args(va_list *args)
58{
59	integer_args *new;
60
61	new = malloc(sizeof(*new));
62
63	if (new != NULL) {
64		new->precision = va_arg(*args, unsigned);
65		new->min = va_arg(*args, long);
66		new->max = va_arg(*args, long);
67	}
68
69	return (void *) new;
70}
71
72/*
73 * Copy the integer argument structure.
74 */
75static char *
76copy_integer_args(char *args)
77{
78	integer_args *new;
79
80	new = malloc(sizeof(*new));
81
82	if (new != NULL)
83		memcpy(new, args, sizeof(*new));
84
85	return (void *) new;
86}
87
88/*
89 * Free the allocated storage associated with the type arguments.
90 */
91static void
92free_integer_args(char *args)
93{
94	if (args != NULL)
95		free(args);
96}
97
98/*
99 * Check the contents of the field buffer are digits only.
100 */
101static int
102integer_check_field(FIELD *field, char *args)
103{
104	int cur;
105	long number, max, min;
106	int precision;
107	char *buf, *new_buf;
108
109	if (args == NULL)
110		return FALSE;
111
112	precision = ((integer_args *) (void *) field->args)->precision;
113	min = ((integer_args *) (void *) field->args)->min;
114	max = ((integer_args *) (void *) field->args)->max;
115
116	buf = args;
117	cur = 0;
118
119	  /* skip leading white space */
120	while ((buf[cur] != '\0')
121	       && ((buf[cur] == ' ') || (buf[cur] == '\t')))
122		cur++;
123
124	  /* no good if we have hit the end */
125	if (buf[cur] == '\0')
126		return FALSE;
127
128	  /* find the end of the digits but allow a leading + or - sign */
129	if ((buf[cur] == '-') || (buf[cur] == '+'))
130		cur++;
131
132	while(isdigit((unsigned char)buf[cur]))
133		cur++;
134
135	  /* check there is only trailing whitespace */
136	while ((buf[cur] != '\0')
137	       && ((buf[cur] == ' ') || (buf[cur] == '\t')))
138		cur++;
139
140	  /* no good if we are not at the end of the string */
141	if (buf[cur] != '\0')
142		return FALSE;
143
144	  /* convert and range check the number...*/
145	number = atol(buf);
146	if ((min > max) || ((number < min) || (number > max)))
147		return FALSE;
148
149	if (asprintf(&new_buf, "%.*ld", precision, number) < 0)
150		return FALSE;
151
152	  /* re-set the field buffer to be the reformatted numeric */
153	set_field_buffer(field, 0, new_buf);
154
155	free(new_buf);
156
157	  /* otherwise all was ok */
158	return TRUE;
159}
160
161/*
162 * Check the given character is numeric, return TRUE if it is.
163 */
164static int
165integer_check_char(/* ARGSUSED1 */ int c, char *args)
166{
167	return ((isdigit(c) || (c == '-') || (c == '+')) ? TRUE : FALSE);
168}
169
170static FIELDTYPE builtin_integer = {
171	_TYPE_HAS_ARGS | _TYPE_IS_BUILTIN,  /* flags */
172	0,                                  /* refcount */
173	NULL,                               /* link */
174	create_integer_args,                  /* make_args */
175	copy_integer_args,                    /* copy_args */
176	free_integer_args,                    /* free_args */
177	integer_check_field,                  /* field_check */
178	integer_check_char,                   /* char_check */
179	NULL,                               /* next_choice */
180	NULL                                /* prev_choice */
181};
182
183FIELDTYPE *TYPE_INTEGER = &builtin_integer;
184
185
186