1 /*
2  * psql - the PostgreSQL interactive terminal
3  *
4  * Copyright (c) 2000-2017, PostgreSQL Global Development Group
5  *
6  * src/bin/psql/conditional.c
7  */
8 #include "postgres_fe.h"
9 
10 #include "conditional.h"
11 
12 /*
13  * create stack
14  */
15 ConditionalStack
conditional_stack_create(void)16 conditional_stack_create(void)
17 {
18 	ConditionalStack cstack = pg_malloc(sizeof(ConditionalStackData));
19 
20 	cstack->head = NULL;
21 	return cstack;
22 }
23 
24 /*
25  * destroy stack
26  */
27 void
conditional_stack_destroy(ConditionalStack cstack)28 conditional_stack_destroy(ConditionalStack cstack)
29 {
30 	while (conditional_stack_pop(cstack))
31 		continue;
32 	free(cstack);
33 }
34 
35 /*
36  * Create a new conditional branch.
37  */
38 void
conditional_stack_push(ConditionalStack cstack,ifState new_state)39 conditional_stack_push(ConditionalStack cstack, ifState new_state)
40 {
41 	IfStackElem *p = (IfStackElem *) pg_malloc(sizeof(IfStackElem));
42 
43 	p->if_state = new_state;
44 	p->query_len = -1;
45 	p->paren_depth = -1;
46 	p->next = cstack->head;
47 	cstack->head = p;
48 }
49 
50 /*
51  * Destroy the topmost conditional branch.
52  * Returns false if there was no branch to end.
53  */
54 bool
conditional_stack_pop(ConditionalStack cstack)55 conditional_stack_pop(ConditionalStack cstack)
56 {
57 	IfStackElem *p = cstack->head;
58 
59 	if (!p)
60 		return false;
61 	cstack->head = cstack->head->next;
62 	free(p);
63 	return true;
64 }
65 
66 /*
67  * Fetch the current state of the top of the stack.
68  */
69 ifState
conditional_stack_peek(ConditionalStack cstack)70 conditional_stack_peek(ConditionalStack cstack)
71 {
72 	if (conditional_stack_empty(cstack))
73 		return IFSTATE_NONE;
74 	return cstack->head->if_state;
75 }
76 
77 /*
78  * Change the state of the topmost branch.
79  * Returns false if there was no branch state to set.
80  */
81 bool
conditional_stack_poke(ConditionalStack cstack,ifState new_state)82 conditional_stack_poke(ConditionalStack cstack, ifState new_state)
83 {
84 	if (conditional_stack_empty(cstack))
85 		return false;
86 	cstack->head->if_state = new_state;
87 	return true;
88 }
89 
90 /*
91  * True if there are no active \if-blocks.
92  */
93 bool
conditional_stack_empty(ConditionalStack cstack)94 conditional_stack_empty(ConditionalStack cstack)
95 {
96 	return cstack->head == NULL;
97 }
98 
99 /*
100  * True if we should execute commands normally; that is, the current
101  * conditional branch is active, or there is no open \if block.
102  */
103 bool
conditional_active(ConditionalStack cstack)104 conditional_active(ConditionalStack cstack)
105 {
106 	ifState		s = conditional_stack_peek(cstack);
107 
108 	return s == IFSTATE_NONE || s == IFSTATE_TRUE || s == IFSTATE_ELSE_TRUE;
109 }
110 
111 /*
112  * Save current query buffer length in topmost stack entry.
113  */
114 void
conditional_stack_set_query_len(ConditionalStack cstack,int len)115 conditional_stack_set_query_len(ConditionalStack cstack, int len)
116 {
117 	Assert(!conditional_stack_empty(cstack));
118 	cstack->head->query_len = len;
119 }
120 
121 /*
122  * Fetch last-recorded query buffer length from topmost stack entry.
123  * Will return -1 if no stack or it was never saved.
124  */
125 int
conditional_stack_get_query_len(ConditionalStack cstack)126 conditional_stack_get_query_len(ConditionalStack cstack)
127 {
128 	if (conditional_stack_empty(cstack))
129 		return -1;
130 	return cstack->head->query_len;
131 }
132 
133 /*
134  * Save current parenthesis nesting depth in topmost stack entry.
135  */
136 void
conditional_stack_set_paren_depth(ConditionalStack cstack,int depth)137 conditional_stack_set_paren_depth(ConditionalStack cstack, int depth)
138 {
139 	Assert(!conditional_stack_empty(cstack));
140 	cstack->head->paren_depth = depth;
141 }
142 
143 /*
144  * Fetch last-recorded parenthesis nesting depth from topmost stack entry.
145  * Will return -1 if no stack or it was never saved.
146  */
147 int
conditional_stack_get_paren_depth(ConditionalStack cstack)148 conditional_stack_get_paren_depth(ConditionalStack cstack)
149 {
150 	if (conditional_stack_empty(cstack))
151 		return -1;
152 	return cstack->head->paren_depth;
153 }
154