xref: /netbsd-src/usr.bin/dc/stack.c (revision fc8ee2f577a06855648d534cfaeafda777e59180)
1*fc8ee2f5Schristos /*	$NetBSD: stack.c,v 1.2 2017/04/10 16:37:48 christos Exp $	*/
27d0b3229Schristos /*	$OpenBSD: stack.c,v 1.14 2016/03/27 15:55:13 otto Exp $	*/
37d0b3229Schristos 
47d0b3229Schristos /*
57d0b3229Schristos  * Copyright (c) 2003, Otto Moerbeek <otto@drijf.net>
67d0b3229Schristos  *
77d0b3229Schristos  * Permission to use, copy, modify, and distribute this software for any
87d0b3229Schristos  * purpose with or without fee is hereby granted, provided that the above
97d0b3229Schristos  * copyright notice and this permission notice appear in all copies.
107d0b3229Schristos  *
117d0b3229Schristos  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
127d0b3229Schristos  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
137d0b3229Schristos  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
147d0b3229Schristos  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
157d0b3229Schristos  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
167d0b3229Schristos  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
177d0b3229Schristos  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
187d0b3229Schristos  */
19*fc8ee2f5Schristos #include <sys/cdefs.h>
20*fc8ee2f5Schristos __RCSID("$NetBSD: stack.c,v 1.2 2017/04/10 16:37:48 christos Exp $");
217d0b3229Schristos 
227d0b3229Schristos #include <err.h>
237d0b3229Schristos #include <stdlib.h>
247d0b3229Schristos #include <string.h>
257d0b3229Schristos 
267d0b3229Schristos #include "extern.h"
277d0b3229Schristos 
287d0b3229Schristos static __inline bool	stack_empty(const struct stack *);
297d0b3229Schristos static void		stack_grow(struct stack *);
307d0b3229Schristos static struct array	*array_new(void);
317d0b3229Schristos static __inline void	array_free(struct array *);
327d0b3229Schristos static struct array *	array_dup(const struct array *);
337d0b3229Schristos static __inline void	array_grow(struct array *, size_t);
347d0b3229Schristos static __inline void	array_assign(struct array *, size_t, const struct value *);
357d0b3229Schristos static __inline struct value	*array_retrieve(const struct array *, size_t);
367d0b3229Schristos 
377d0b3229Schristos void
stack_init(struct stack * stack)387d0b3229Schristos stack_init(struct stack *stack)
397d0b3229Schristos {
407d0b3229Schristos 	stack->size = 0;
417d0b3229Schristos 	stack->sp = -1;
427d0b3229Schristos 	stack->stack = NULL;
437d0b3229Schristos }
447d0b3229Schristos 
457d0b3229Schristos static __inline bool
stack_empty(const struct stack * stack)467d0b3229Schristos stack_empty(const struct stack *stack)
477d0b3229Schristos {
487d0b3229Schristos 	bool empty = stack->sp == -1;
497d0b3229Schristos 	if (empty)
507d0b3229Schristos 		warnx("stack empty");
517d0b3229Schristos 	return empty;
527d0b3229Schristos }
537d0b3229Schristos 
547d0b3229Schristos /* Clear number or string, but leave value itself */
557d0b3229Schristos void
stack_free_value(struct value * v)567d0b3229Schristos stack_free_value(struct value *v)
577d0b3229Schristos {
587d0b3229Schristos 	switch (v->type) {
597d0b3229Schristos 	case BCODE_NONE:
607d0b3229Schristos 		break;
617d0b3229Schristos 	case BCODE_NUMBER:
627d0b3229Schristos 		free_number(v->u.num);
637d0b3229Schristos 		break;
647d0b3229Schristos 	case BCODE_STRING:
657d0b3229Schristos 		free(v->u.string);
667d0b3229Schristos 		break;
677d0b3229Schristos 	}
687d0b3229Schristos 	array_free(v->array);
697d0b3229Schristos 	v->array = NULL;
707d0b3229Schristos }
717d0b3229Schristos 
727d0b3229Schristos /* Copy number or string content into already allocated target */
737d0b3229Schristos struct value *
stack_dup_value(const struct value * a,struct value * copy)747d0b3229Schristos stack_dup_value(const struct value *a, struct value *copy)
757d0b3229Schristos {
767d0b3229Schristos 	copy->type = a->type;
777d0b3229Schristos 
787d0b3229Schristos 	switch (a->type) {
797d0b3229Schristos 	case BCODE_NONE:
807d0b3229Schristos 		break;
817d0b3229Schristos 	case BCODE_NUMBER:
827d0b3229Schristos 		copy->u.num = dup_number(a->u.num);
837d0b3229Schristos 		break;
847d0b3229Schristos 	case BCODE_STRING:
857d0b3229Schristos 		copy->u.string = strdup(a->u.string);
867d0b3229Schristos 		if (copy->u.string == NULL)
877d0b3229Schristos 			err(1, NULL);
887d0b3229Schristos 		break;
897d0b3229Schristos 	}
907d0b3229Schristos 
917d0b3229Schristos 	copy->array = a->array == NULL ? NULL : array_dup(a->array);
927d0b3229Schristos 
937d0b3229Schristos 	return copy;
947d0b3229Schristos }
957d0b3229Schristos 
967d0b3229Schristos size_t
stack_size(const struct stack * stack)977d0b3229Schristos stack_size(const struct stack *stack)
987d0b3229Schristos {
99*fc8ee2f5Schristos 	return (size_t)(stack->sp + 1);
1007d0b3229Schristos }
1017d0b3229Schristos 
1027d0b3229Schristos void
stack_dup(struct stack * stack)1037d0b3229Schristos stack_dup(struct stack *stack)
1047d0b3229Schristos {
1057d0b3229Schristos 	struct value	*value;
1067d0b3229Schristos 	struct value	copy;
1077d0b3229Schristos 
1087d0b3229Schristos 	value = stack_tos(stack);
1097d0b3229Schristos 	if (value == NULL) {
1107d0b3229Schristos 		warnx("stack empty");
1117d0b3229Schristos 		return;
1127d0b3229Schristos 	}
1137d0b3229Schristos 	stack_push(stack, stack_dup_value(value, &copy));
1147d0b3229Schristos }
1157d0b3229Schristos 
1167d0b3229Schristos void
stack_swap(struct stack * stack)1177d0b3229Schristos stack_swap(struct stack *stack)
1187d0b3229Schristos {
1197d0b3229Schristos 	struct value	copy;
1207d0b3229Schristos 
1217d0b3229Schristos 	if (stack->sp < 1) {
1227d0b3229Schristos 		warnx("stack empty");
1237d0b3229Schristos 		return;
1247d0b3229Schristos 	}
1257d0b3229Schristos 	copy = stack->stack[stack->sp];
1267d0b3229Schristos 	stack->stack[stack->sp] = stack->stack[stack->sp-1];
1277d0b3229Schristos 	stack->stack[stack->sp-1] = copy;
1287d0b3229Schristos }
1297d0b3229Schristos 
1307d0b3229Schristos static void
stack_grow(struct stack * stack)1317d0b3229Schristos stack_grow(struct stack *stack)
1327d0b3229Schristos {
1337d0b3229Schristos 	size_t new_size;
1347d0b3229Schristos 
135*fc8ee2f5Schristos 	if ((size_t)++stack->sp == stack->size) {
1367d0b3229Schristos 		new_size = stack->size * 2 + 1;
1377d0b3229Schristos 		stack->stack = breallocarray(stack->stack,
1387d0b3229Schristos 		    new_size, sizeof(*stack->stack));
1397d0b3229Schristos 		stack->size = new_size;
1407d0b3229Schristos 	}
1417d0b3229Schristos }
1427d0b3229Schristos 
1437d0b3229Schristos void
stack_pushnumber(struct stack * stack,struct number * b)1447d0b3229Schristos stack_pushnumber(struct stack *stack, struct number *b)
1457d0b3229Schristos {
1467d0b3229Schristos 	stack_grow(stack);
1477d0b3229Schristos 	stack->stack[stack->sp].type = BCODE_NUMBER;
1487d0b3229Schristos 	stack->stack[stack->sp].u.num = b;
1497d0b3229Schristos 	stack->stack[stack->sp].array = NULL;
1507d0b3229Schristos }
1517d0b3229Schristos 
1527d0b3229Schristos void
stack_pushstring(struct stack * stack,char * string)1537d0b3229Schristos stack_pushstring(struct stack *stack, char *string)
1547d0b3229Schristos {
1557d0b3229Schristos 	stack_grow(stack);
1567d0b3229Schristos 	stack->stack[stack->sp].type = BCODE_STRING;
1577d0b3229Schristos 	stack->stack[stack->sp].u.string = string;
1587d0b3229Schristos 	stack->stack[stack->sp].array = NULL;
1597d0b3229Schristos }
1607d0b3229Schristos 
1617d0b3229Schristos void
stack_push(struct stack * stack,struct value * v)1627d0b3229Schristos stack_push(struct stack *stack, struct value *v)
1637d0b3229Schristos {
1647d0b3229Schristos 	switch (v->type) {
1657d0b3229Schristos 	case BCODE_NONE:
1667d0b3229Schristos 		stack_grow(stack);
1677d0b3229Schristos 		stack->stack[stack->sp].type = BCODE_NONE;
1687d0b3229Schristos 		break;
1697d0b3229Schristos 	case BCODE_NUMBER:
1707d0b3229Schristos 		stack_pushnumber(stack, v->u.num);
1717d0b3229Schristos 		break;
1727d0b3229Schristos 	case BCODE_STRING:
1737d0b3229Schristos 		stack_pushstring(stack, v->u.string);
1747d0b3229Schristos 		break;
1757d0b3229Schristos 	}
1767d0b3229Schristos 	stack->stack[stack->sp].array = v->array == NULL ?
1777d0b3229Schristos 	    NULL : array_dup(v->array);
1787d0b3229Schristos }
1797d0b3229Schristos 
1807d0b3229Schristos struct value *
stack_tos(const struct stack * stack)1817d0b3229Schristos stack_tos(const struct stack *stack)
1827d0b3229Schristos {
1837d0b3229Schristos 	if (stack->sp == -1)
1847d0b3229Schristos 		return NULL;
1857d0b3229Schristos 	return &stack->stack[stack->sp];
1867d0b3229Schristos }
1877d0b3229Schristos 
1887d0b3229Schristos void
stack_set_tos(struct stack * stack,struct value * v)1897d0b3229Schristos stack_set_tos(struct stack *stack, struct value *v)
1907d0b3229Schristos {
1917d0b3229Schristos 	if (stack->sp == -1)
1927d0b3229Schristos 		stack_push(stack, v);
1937d0b3229Schristos 	else {
1947d0b3229Schristos 		stack_free_value(&stack->stack[stack->sp]);
1957d0b3229Schristos 		stack->stack[stack->sp] = *v;
1967d0b3229Schristos 		stack->stack[stack->sp].array = v->array == NULL ?
1977d0b3229Schristos 		    NULL : array_dup(v->array);
1987d0b3229Schristos 	}
1997d0b3229Schristos }
2007d0b3229Schristos 
2017d0b3229Schristos struct value *
stack_pop(struct stack * stack)2027d0b3229Schristos stack_pop(struct stack *stack)
2037d0b3229Schristos {
2047d0b3229Schristos 	if (stack_empty(stack))
2057d0b3229Schristos 		return NULL;
2067d0b3229Schristos 	return &stack->stack[stack->sp--];
2077d0b3229Schristos }
2087d0b3229Schristos 
2097d0b3229Schristos struct number *
stack_popnumber(struct stack * stack)2107d0b3229Schristos stack_popnumber(struct stack *stack)
2117d0b3229Schristos {
2127d0b3229Schristos 	if (stack_empty(stack))
2137d0b3229Schristos 		return NULL;
2147d0b3229Schristos 	array_free(stack->stack[stack->sp].array);
2157d0b3229Schristos 	stack->stack[stack->sp].array = NULL;
2167d0b3229Schristos 	if (stack->stack[stack->sp].type != BCODE_NUMBER) {
2177d0b3229Schristos 		warnx("not a number"); /* XXX remove */
2187d0b3229Schristos 		return NULL;
2197d0b3229Schristos 	}
2207d0b3229Schristos 	return stack->stack[stack->sp--].u.num;
2217d0b3229Schristos }
2227d0b3229Schristos 
2237d0b3229Schristos char *
stack_popstring(struct stack * stack)2247d0b3229Schristos stack_popstring(struct stack *stack)
2257d0b3229Schristos {
2267d0b3229Schristos 	if (stack_empty(stack))
2277d0b3229Schristos 		return NULL;
2287d0b3229Schristos 	array_free(stack->stack[stack->sp].array);
2297d0b3229Schristos 	stack->stack[stack->sp].array = NULL;
2307d0b3229Schristos 	if (stack->stack[stack->sp].type != BCODE_STRING) {
2317d0b3229Schristos 		warnx("not a string"); /* XXX remove */
2327d0b3229Schristos 		return NULL;
2337d0b3229Schristos 	}
2347d0b3229Schristos 	return stack->stack[stack->sp--].u.string;
2357d0b3229Schristos }
2367d0b3229Schristos 
2377d0b3229Schristos void
stack_clear(struct stack * stack)2387d0b3229Schristos stack_clear(struct stack *stack)
2397d0b3229Schristos {
2407d0b3229Schristos 	while (stack->sp >= 0)
2417d0b3229Schristos 		stack_free_value(&stack->stack[stack->sp--]);
2427d0b3229Schristos 	free(stack->stack);
2437d0b3229Schristos 	stack_init(stack);
2447d0b3229Schristos }
2457d0b3229Schristos 
2467d0b3229Schristos void
stack_print(FILE * f,const struct stack * stack,const char * prefix,u_int base)2477d0b3229Schristos stack_print(FILE *f, const struct stack *stack, const char *prefix, u_int base)
2487d0b3229Schristos {
2497d0b3229Schristos 	ssize_t i;
2507d0b3229Schristos 
2517d0b3229Schristos 	for (i = stack->sp; i >= 0; i--) {
2527d0b3229Schristos 		print_value(f, &stack->stack[i], prefix, base);
2537d0b3229Schristos 		(void)putc('\n', f);
2547d0b3229Schristos 	}
2557d0b3229Schristos }
2567d0b3229Schristos 
2577d0b3229Schristos 
2587d0b3229Schristos static struct array *
array_new(void)2597d0b3229Schristos array_new(void)
2607d0b3229Schristos {
2617d0b3229Schristos 	struct array *a;
2627d0b3229Schristos 
2637d0b3229Schristos 	a = bmalloc(sizeof(*a));
2647d0b3229Schristos 	a->data = NULL;
2657d0b3229Schristos 	a->size = 0;
2667d0b3229Schristos 	return a;
2677d0b3229Schristos }
2687d0b3229Schristos 
2697d0b3229Schristos static __inline void
array_free(struct array * a)2707d0b3229Schristos array_free(struct array *a)
2717d0b3229Schristos {
2727d0b3229Schristos 	size_t i;
2737d0b3229Schristos 
2747d0b3229Schristos 	if (a == NULL)
2757d0b3229Schristos 		return;
2767d0b3229Schristos 	for (i = 0; i < a->size; i++)
2777d0b3229Schristos 		stack_free_value(&a->data[i]);
2787d0b3229Schristos 	free(a->data);
2797d0b3229Schristos 	free(a);
2807d0b3229Schristos }
2817d0b3229Schristos 
2827d0b3229Schristos static struct array *
array_dup(const struct array * a)2837d0b3229Schristos array_dup(const struct array *a)
2847d0b3229Schristos {
2857d0b3229Schristos 	struct array	*n;
2867d0b3229Schristos 	size_t		i;
2877d0b3229Schristos 
2887d0b3229Schristos 	if (a == NULL)
2897d0b3229Schristos 		return NULL;
2907d0b3229Schristos 	n = array_new();
2917d0b3229Schristos 	array_grow(n, a->size);
2927d0b3229Schristos 	for (i = 0; i < a->size; i++)
2937d0b3229Schristos 		(void)stack_dup_value(&a->data[i], &n->data[i]);
2947d0b3229Schristos 	return n;
2957d0b3229Schristos }
2967d0b3229Schristos 
2977d0b3229Schristos static __inline void
array_grow(struct array * array,size_t newsize)2987d0b3229Schristos array_grow(struct array *array, size_t newsize)
2997d0b3229Schristos {
3007d0b3229Schristos 	size_t i;
3017d0b3229Schristos 
3027d0b3229Schristos 	array->data = breallocarray(array->data, newsize, sizeof(*array->data));
3037d0b3229Schristos 	for (i = array->size; i < newsize; i++) {
3047d0b3229Schristos 		array->data[i].type = BCODE_NONE;
3057d0b3229Schristos 		array->data[i].array = NULL;
3067d0b3229Schristos 	}
3077d0b3229Schristos 	array->size = newsize;
3087d0b3229Schristos }
3097d0b3229Schristos 
3107d0b3229Schristos static __inline void
array_assign(struct array * array,size_t index,const struct value * v)3117d0b3229Schristos array_assign(struct array *array, size_t index, const struct value *v)
3127d0b3229Schristos {
3137d0b3229Schristos 	if (index >= array->size)
3147d0b3229Schristos 		array_grow(array, index+1);
3157d0b3229Schristos 	stack_free_value(&array->data[index]);
3167d0b3229Schristos 	array->data[index] = *v;
3177d0b3229Schristos }
3187d0b3229Schristos 
3197d0b3229Schristos static __inline struct value *
array_retrieve(const struct array * array,size_t index)3207d0b3229Schristos array_retrieve(const struct array *array, size_t index)
3217d0b3229Schristos {
3227d0b3229Schristos 	if (index >= array->size)
3237d0b3229Schristos 		return NULL;
3247d0b3229Schristos 	return &array->data[index];
3257d0b3229Schristos }
3267d0b3229Schristos 
3277d0b3229Schristos void
frame_assign(struct stack * stack,size_t index,const struct value * v)3287d0b3229Schristos frame_assign(struct stack *stack, size_t index, const struct value *v)
3297d0b3229Schristos {
3307d0b3229Schristos 	struct array *a;
3317d0b3229Schristos 	struct value n;
3327d0b3229Schristos 
3337d0b3229Schristos 	if (stack->sp == -1) {
3347d0b3229Schristos 		n.type = BCODE_NONE;
3357d0b3229Schristos 		n.array = NULL;
3367d0b3229Schristos 		stack_push(stack, &n);
3377d0b3229Schristos 	}
3387d0b3229Schristos 
3397d0b3229Schristos 	a = stack->stack[stack->sp].array;
3407d0b3229Schristos 	if (a == NULL)
3417d0b3229Schristos 		a = stack->stack[stack->sp].array = array_new();
3427d0b3229Schristos 	array_assign(a, index, v);
3437d0b3229Schristos }
3447d0b3229Schristos 
3457d0b3229Schristos struct value *
frame_retrieve(const struct stack * stack,size_t index)3467d0b3229Schristos frame_retrieve(const struct stack *stack, size_t index)
3477d0b3229Schristos {
3487d0b3229Schristos 	struct array *a;
3497d0b3229Schristos 
3507d0b3229Schristos 	if (stack->sp == -1)
3517d0b3229Schristos 		return NULL;
3527d0b3229Schristos 	a = stack->stack[stack->sp].array;
3537d0b3229Schristos 	if (a == NULL)
3547d0b3229Schristos 		a = stack->stack[stack->sp].array = array_new();
3557d0b3229Schristos 	return array_retrieve(a, index);
3567d0b3229Schristos }
357