[scripting] While with break and continue
[people/lynusvaz/gpxe.git] / src / hci / commands / if_cmd.c
1 #include <stdio.h>
2 #include <unistd.h>
3 #include <gpxe/command.h>
4 #include <gpxe/gen_stack.h>
5 #include <gpxe/init.h>
6
7 struct generic_stack if_stack;
8 struct generic_stack else_stack;
9 static struct generic_stack loop_stack;
10 struct generic_stack command_list;
11 int prog_ctr;
12 int isnum ( char *string, long *num );
13
14 int system ( const char * );
15
16 struct while_info {
17         int loop_start;
18         int if_pos;
19         int is_continue;
20 };
21
22 static int if_exec ( int argc, char **argv ) {
23         long cond;
24         int zero = 0;
25         if ( argc != 2 ) {
26                 printf ( "Syntax: if <condition>\n" );
27                 return 1;
28         }
29         
30         if ( !isnum ( argv[1], &cond ) ) {
31                 printf ( "non-numeric condition: %s\n", argv[1] );
32                 return 1;
33         }
34         cond = TOP_GEN_STACK_INT ( &if_stack ) ? ( cond ? 1 : 0 ) : 0;
35         if ( ( push_generic_stack ( &else_stack, &zero, 0 ) < 0 ) || ( push_generic_stack ( &if_stack, &cond, 0 ) < 0 ) ) {
36                 free_generic_stack ( &if_stack, 0 );
37                 free_generic_stack ( &else_stack, 0 );
38                 return 1;
39         }
40
41         return 0;
42 }
43
44 struct command if_command __command = {
45         .name = "if",
46         .exec = if_exec,
47 };
48
49 static int fi_exec ( int argc, char **argv ) {
50         int cond;
51         if ( argc != 1 ) {
52                 printf ( "Syntax: %s\n", argv[0] );
53                 return 1;
54         }
55         
56         if ( if_stack.tos > 0 ) {       
57                 if ( pop_generic_stack ( &if_stack, &cond ) < 0 )
58                         return 1;
59         } else {
60                 printf ( "fi without if\n" );
61                 return 1;
62         }
63         return 0;               
64 }
65
66
67 struct command fi_command __command = {
68         .name = "fi",
69         .exec = fi_exec,
70 };
71
72 static int else_exec ( int argc, char **argv ) {
73         if ( argc != 1 ) {
74                 printf ( "Syntax: %s\n", argv[0] );
75                 return 1;
76         }
77
78         if ( TOP_GEN_STACK_INT ( &else_stack ) != 0 ) {
79                 printf ( "else without if\n" );
80                 return 1;
81         }
82         
83         if ( ELEMENT_GEN_STACK_INT ( &if_stack, if_stack.tos - 1 ) )
84                 TOP_GEN_STACK_INT ( &if_stack ) = !TOP_GEN_STACK_INT ( &if_stack );
85         
86         return 0;
87 }
88
89 struct command else_command __command = {
90         .name = "else",
91         .exec = else_exec,
92 };
93
94 void init_if ( void ) {
95         int one = 1;
96         init_generic_stack ( &if_stack, sizeof ( int ) );
97         init_generic_stack ( &else_stack, sizeof ( int ) );
98         init_generic_stack ( &loop_stack, sizeof ( struct while_info ) );
99         init_generic_stack ( &command_list, sizeof ( char * ) );
100         prog_ctr = 0;
101         push_generic_stack ( &if_stack, &one, 0 );
102         push_generic_stack ( &else_stack, &one, 0 );
103         return;
104 }
105
106 struct init_fn initialise_if __init_fn ( INIT_NORMAL ) = {
107         .initialise = init_if,
108 };
109
110 static int while_exec ( int argc, char **argv ) {
111         struct while_info w;
112         if ( argc != 2 ) {
113                 printf ( "Syntax: while <condition>\n" );
114                 return 1;
115         }
116         if ( if_exec ( argc, argv ) != 0 )
117                 return 1;
118         TOP_GEN_STACK_INT ( &else_stack ) = 1;
119         
120         w.loop_start = prog_ctr;
121         w.if_pos = if_stack.tos;
122         w.is_continue = 0;
123         
124         push_generic_stack ( &loop_stack, &w, 0 );
125         //printf ( "pc = %d. size of loop_stack = %d\n", prog_ctr, SIZE_GEN_STACK ( &loop_stack ) );
126         return 0;
127 }
128
129 struct command while_command __command = {
130         .name = "while",
131         .exec = while_exec,
132 };
133
134 static int done_exec ( int argc, char **argv ) {
135         int cond;
136         int tmp_pc;
137         struct while_info pot;
138         int rc = 0;
139         if ( argc != 1 ) {
140                 printf ( "Syntax: %s\n", argv[0] );
141                 return 1;
142         }
143         
144         //printf ( "size of if_stack = %d. size of loop stack = %d\n", SIZE_GEN_STACK ( &if_stack ), SIZE_GEN_STACK ( &loop_stack ) );
145         
146         if ( SIZE_GEN_STACK ( &loop_stack ) == 0 ) {
147                 printf ( "done outside a loop\n" );
148                 return 1;
149         }
150         
151         pop_generic_stack ( &if_stack, &cond );
152         pop_generic_stack ( &loop_stack, &pot );
153         
154         while ( cond || pot.is_continue ) {
155                 tmp_pc = prog_ctr;
156                 prog_ctr = pot.loop_start;
157                 while ( prog_ctr < tmp_pc ) {
158                         if ( ( rc = system ( ELEMENT_GEN_STACK_STRING ( &command_list, prog_ctr ) ) ) ) 
159                                 return rc;
160                 }
161                 pop_generic_stack ( &if_stack, &cond );
162                 pop_generic_stack ( &loop_stack, &pot );
163         }
164         return rc;
165 }
166
167 struct command done_command __command = {
168         .name = "done",
169         .exec = done_exec,
170 };
171
172 static int break_exec ( int argc, char **argv ) {
173         int pos;
174         struct while_info *w;
175         if ( argc != 1 ) {
176                 printf ( "Syntax: %s\n", argv[0] );
177                 return 1;
178         }
179         w = ( ( struct while_info * ) loop_stack.ptr + ( loop_stack.tos ) );
180         for ( pos = w->if_pos; pos < SIZE_GEN_STACK ( &if_stack ); pos++ )
181                 ELEMENT_GEN_STACK_INT ( &if_stack, pos ) = 0;
182         return 0;
183 }
184
185 struct command break_command __command = {
186         .name = "break",
187         .exec = break_exec,
188 };
189
190 static int continue_exec ( int argc, char **argv ) {
191         struct while_info *w;
192         if ( argc != 1 ) {
193                 printf ( "Syntax: %s\n", argv[0] );
194                 return 1;
195         }
196         if ( break_exec ( argc, argv ) )
197                 return 1;
198         w = ( ( struct while_info * ) loop_stack.ptr + ( loop_stack.tos ) );
199         w->is_continue = 1;
200         return 0;
201 }
202
203 struct command continue_command __command = {
204         .name = "continue",
205         .exec = continue_exec,
206 };