Commit | Line | Data |
---|---|---|
b811d2c2 | 1 | /* Copyright 1999-2020 Free Software Foundation, Inc. |
7c27f15b MC |
2 | |
3 | This file is part of GDB. | |
4 | ||
5 | This program is free software; you can redistribute it and/or modify | |
6 | it under the terms of the GNU General Public License as published by | |
a9762ec7 JB |
7 | the Free Software Foundation; either version 3 of the License, or |
8 | (at your option) any later version. | |
7c27f15b | 9 | |
a9762ec7 JB |
10 | This program is distributed in the hope that it will be useful, |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 | GNU General Public License for more details. | |
7c27f15b MC |
14 | |
15 | You should have received a copy of the GNU General Public License | |
a9762ec7 | 16 | along with this program. If not, see <http://www.gnu.org/licenses/>. */ |
7c27f15b | 17 | |
5a2e8882 | 18 | #include <stdlib.h> |
17f62551 | 19 | #include <string.h> |
5a2e8882 | 20 | |
fb40c209 AC |
21 | struct _simple_struct { |
22 | int integer; | |
23 | unsigned int unsigned_integer; | |
24 | char character; | |
25 | signed char signed_character; | |
26 | char *char_ptr; | |
27 | int array_of_10[10]; | |
28 | }; | |
29 | ||
30 | typedef struct _simple_struct simpleton; | |
31 | ||
32 | simpleton global_simple; | |
33 | ||
34 | enum foo { | |
35 | bar = 1, | |
36 | baz | |
37 | }; | |
38 | ||
39 | typedef enum foo efoo; | |
40 | ||
41 | union named_union | |
42 | { | |
43 | int integer; | |
44 | char *char_ptr; | |
45 | }; | |
46 | ||
47 | typedef struct _struct_decl { | |
48 | int integer; | |
49 | char character; | |
50 | char *char_ptr; | |
51 | long long_int; | |
52 | int **int_ptr_ptr; | |
8be260b6 | 53 | long long_array[10]; |
fb40c209 AC |
54 | |
55 | void (*func_ptr) (void); | |
56 | struct _struct_decl (*func_ptr_struct) (int, char *, long); | |
57 | struct _struct_decl *(*func_ptr_ptr) (int, char *, long); | |
58 | union { | |
59 | int a; | |
60 | char *b; | |
61 | long c; | |
62 | enum foo d; | |
63 | } u1; | |
64 | ||
65 | struct { | |
66 | union { | |
67 | struct { | |
68 | int d; | |
69 | char e[10]; | |
70 | int *(*func) (void); | |
71 | efoo foo; | |
72 | } u1s1; | |
73 | ||
74 | long f; | |
75 | struct { | |
76 | char array_ptr[2]; | |
77 | int (*func) (int, char *); | |
78 | } u1s2; | |
79 | } u2; | |
80 | ||
81 | int g; | |
82 | char h; | |
83 | long i[10]; | |
84 | } s2; | |
85 | } weird_struct; | |
86 | ||
87 | struct _struct_n_pointer { | |
88 | char ****char_ptr; | |
89 | long ****long_ptr; | |
90 | struct _struct_n_pointer *ptrs[3]; | |
91 | struct _struct_n_pointer *next; | |
92 | }; | |
93 | ||
3848a17f KS |
94 | struct anonymous { |
95 | int a; | |
96 | struct { | |
97 | int b; | |
98 | char *c; | |
99 | union { | |
100 | int d; | |
101 | void *e; | |
102 | char f; | |
103 | struct { | |
104 | char g; | |
105 | const char **h; | |
106 | simpleton ***simple; | |
107 | }; | |
108 | }; | |
109 | }; | |
110 | }; | |
111 | ||
fb40c209 AC |
112 | void do_locals_tests (void); |
113 | void do_block_tests (void); | |
114 | void subroutine1 (int, long *); | |
115 | void nothing (void); | |
116 | void do_children_tests (void); | |
117 | void do_special_tests (void); | |
118 | void incr_a (char); | |
119 | ||
120 | void incr_a (char a) | |
121 | { | |
122 | int b; | |
123 | b = a; | |
124 | } | |
125 | ||
acd65feb VP |
126 | int array[] = {1,2,3}; |
127 | int array2[] = {4,5,6}; | |
128 | int *array_ptr = array; | |
129 | ||
fb40c209 AC |
130 | void |
131 | do_locals_tests () | |
132 | { | |
a73bafbc VP |
133 | int linteger = 0; |
134 | int *lpinteger = 0; | |
fef8a650 | 135 | char lcharacter[2] = { 0, 0 }; |
a73bafbc VP |
136 | char *lpcharacter = 0; |
137 | long llong = 0; | |
138 | long *lplong = 0; | |
139 | float lfloat = 0; | |
140 | float *lpfloat = 0; | |
141 | double ldouble = 0; | |
142 | double *lpdouble = 0; | |
30b91c90 JK |
143 | struct _simple_struct lsimple = { 0 }; |
144 | struct _simple_struct *lpsimple = 0; | |
145 | void (*func) (void) = 0; | |
fb40c209 AC |
146 | |
147 | /* Simple assignments */ | |
148 | linteger = 1234; | |
149 | lpinteger = &linteger; | |
fef8a650 DJ |
150 | lcharacter[0] = 'a'; |
151 | lpcharacter = lcharacter; | |
fb40c209 AC |
152 | llong = 2121L; |
153 | lplong = &llong; | |
154 | lfloat = 2.1; | |
155 | lpfloat = &lfloat; | |
156 | ldouble = 2.718281828459045; | |
157 | lpdouble = &ldouble; | |
158 | lsimple.integer = 1234; | |
159 | lsimple.unsigned_integer = 255; | |
160 | lsimple.character = 'a'; | |
161 | lsimple.signed_character = 21; | |
fef8a650 | 162 | lsimple.char_ptr = lcharacter; |
fb40c209 AC |
163 | lpsimple = &lsimple; |
164 | func = nothing; | |
165 | ||
166 | /* Check pointers */ | |
167 | linteger = 4321; | |
fef8a650 | 168 | lcharacter[0] = 'b'; |
fb40c209 AC |
169 | llong = 1212L; |
170 | lfloat = 1.2; | |
171 | ldouble = 5.498548281828172; | |
172 | lsimple.integer = 255; | |
173 | lsimple.unsigned_integer = 4321; | |
174 | lsimple.character = 'b'; | |
175 | lsimple.signed_character = 0; | |
176 | ||
177 | subroutine1 (linteger, &llong); | |
178 | } | |
179 | ||
180 | void | |
181 | nothing () | |
182 | { | |
183 | } | |
184 | ||
4dc06805 YQ |
185 | struct _struct_decl |
186 | nothing1 (int a, char *b, long c) | |
187 | { | |
188 | struct _struct_decl foo; | |
189 | ||
190 | return foo; | |
191 | } | |
192 | ||
193 | struct _struct_decl * | |
194 | nothing2 (int a, char *b, long c) | |
195 | { | |
196 | return (struct _struct_decl *) 0; | |
197 | } | |
198 | ||
fb40c209 AC |
199 | void |
200 | subroutine1 (int i, long *l) | |
201 | { | |
202 | global_simple.integer = i + 3; | |
203 | i = 212; | |
204 | *l = 12; | |
205 | } | |
206 | ||
207 | void | |
208 | do_block_tests () | |
209 | { | |
210 | int cb = 12; | |
211 | ||
212 | { | |
213 | int foo; | |
214 | foo = 123; | |
215 | { | |
216 | int foo2; | |
217 | foo2 = 123; | |
218 | { | |
219 | int foo; | |
220 | foo = 321; | |
221 | } | |
222 | foo2 = 0; | |
223 | } | |
224 | foo = 0; | |
225 | } | |
226 | ||
227 | cb = 21; | |
228 | } | |
229 | ||
230 | void | |
231 | do_children_tests (void) | |
232 | { | |
233 | weird_struct *weird; | |
234 | struct _struct_n_pointer *psnp; | |
235 | struct _struct_n_pointer snp0, snp1, snp2; | |
a73bafbc VP |
236 | char a0[2] = {}, *a1, **a2, ***a3; |
237 | char b0[2] = {}, *b1, **b2, ***b3; | |
238 | char c0[2] = {}, *c1, **c2, ***c3; | |
fb40c209 AC |
239 | long z0, *z1, **z2, ***z3; |
240 | long y0, *y1, **y2, ***y3; | |
241 | long x0, *x1, **x2, ***x3; | |
242 | int *foo; | |
243 | int bar; | |
244 | ||
c7dd36a1 PA |
245 | /* Avoid pointing into NULL, as that is editable on some |
246 | systems. */ | |
247 | int dummy; | |
248 | int *dummy_ptr = &dummy; | |
249 | ||
250 | struct _struct_decl struct_declarations = { 0, 0, NULL, 0, &dummy_ptr }; | |
fb40c209 AC |
251 | weird = &struct_declarations; |
252 | ||
253 | struct_declarations.integer = 123; | |
254 | weird->char_ptr = "hello"; | |
255 | bar = 2121; | |
256 | foo = &bar; | |
257 | struct_declarations.int_ptr_ptr = &foo; | |
258 | weird->long_array[0] = 1234; | |
259 | struct_declarations.long_array[1] = 2345; | |
260 | weird->long_array[2] = 3456; | |
261 | struct_declarations.long_array[3] = 4567; | |
262 | weird->long_array[4] = 5678; | |
263 | struct_declarations.long_array[5] = 6789; | |
264 | weird->long_array[6] = 7890; | |
265 | struct_declarations.long_array[7] = 8901; | |
266 | weird->long_array[8] = 9012; | |
267 | struct_declarations.long_array[9] = 1234; | |
268 | ||
269 | weird->func_ptr = nothing; | |
4dc06805 YQ |
270 | weird->func_ptr_struct = nothing1; |
271 | weird->func_ptr_ptr = nothing2; | |
fb40c209 AC |
272 | |
273 | /* Struct/pointer/array tests */ | |
a73bafbc VP |
274 | a0[0] = '0'; |
275 | a1 = a0; | |
fb40c209 AC |
276 | a2 = &a1; |
277 | a3 = &a2; | |
a73bafbc VP |
278 | b0[0] = '1'; |
279 | b1 = b0; | |
fb40c209 AC |
280 | b2 = &b1; |
281 | b3 = &b2; | |
a73bafbc VP |
282 | c0[0] = '2'; |
283 | c1 = c0; | |
fb40c209 AC |
284 | c2 = &c1; |
285 | c3 = &c2; | |
286 | z0 = 0xdead + 0; | |
287 | z1 = &z0; | |
288 | z2 = &z1; | |
289 | z3 = &z2; | |
290 | y0 = 0xdead + 1; | |
291 | y1 = &y0; | |
292 | y2 = &y1; | |
293 | y3 = &y2; | |
294 | x0 = 0xdead + 2; | |
295 | x1 = &x0; | |
296 | x2 = &x1; | |
297 | x3 = &x2; | |
298 | snp0.char_ptr = &a3; | |
299 | snp0.long_ptr = &z3; | |
300 | snp0.ptrs[0] = &snp0; | |
301 | snp0.ptrs[1] = &snp1; | |
302 | snp0.ptrs[2] = &snp2; | |
303 | snp0.next = &snp1; | |
304 | snp1.char_ptr = &b3; | |
305 | snp1.long_ptr = &y3; | |
306 | snp1.ptrs[0] = &snp0; | |
307 | snp1.ptrs[1] = &snp1; | |
308 | snp1.ptrs[2] = &snp2; | |
309 | snp1.next = &snp2; | |
310 | snp2.char_ptr = &c3; | |
311 | snp2.long_ptr = &x3; | |
312 | snp2.ptrs[0] = &snp0; | |
313 | snp2.ptrs[1] = &snp1; | |
314 | snp2.ptrs[2] = &snp2; | |
315 | snp2.next = 0x0; | |
316 | psnp = &snp0; | |
317 | snp0.char_ptr = &b3; | |
318 | snp1.char_ptr = &c3; | |
319 | snp2.char_ptr = &a3; | |
320 | snp0.long_ptr = &y3; | |
321 | snp1.long_ptr = &x3; | |
322 | snp2.long_ptr = &z3; | |
e1c2defa | 323 | {int a = 0;} |
fb40c209 AC |
324 | } |
325 | ||
326 | void | |
327 | do_special_tests (void) | |
328 | { | |
329 | union named_union u; | |
330 | union { | |
331 | int a; | |
332 | char b; | |
333 | long c; | |
334 | } anonu; | |
335 | struct _simple_struct s; | |
336 | struct { | |
337 | int a; | |
338 | char b; | |
339 | long c; | |
340 | } anons; | |
341 | enum foo e; | |
342 | enum { A, B, C } anone; | |
343 | int array[21]; | |
344 | int a; | |
345 | ||
346 | a = 1; | |
c7e64c9a DJ |
347 | u.integer = a; |
348 | anonu.a = a; | |
349 | s.integer = a; | |
350 | anons.a = a; | |
351 | e = bar; | |
352 | anone = A; | |
fb40c209 AC |
353 | incr_a(2); |
354 | } | |
355 | ||
25d5ea92 VP |
356 | void do_frozen_tests () |
357 | { | |
358 | /*: BEGIN: frozen :*/ | |
359 | struct { | |
360 | int i; | |
361 | struct { | |
362 | int j; | |
363 | int k; | |
364 | } nested; | |
365 | } v1 = {1, {2, 3}}; | |
366 | ||
367 | int v2 = 4; | |
368 | /*: | |
369 | mi_create_varobj V1 v1 "create varobj for v1" | |
370 | mi_create_varobj V2 v2 "create varobj for v2" | |
371 | ||
372 | mi_list_varobj_children "V1" { | |
373 | {"V1.i" "i" "0" "int"} | |
374 | {"V1.nested" "nested" "2" "struct {...}"} | |
375 | } "list children of v1" | |
376 | ||
377 | mi_list_varobj_children "V1.nested" { | |
378 | {"V1.nested.j" "j" "0" "int"} | |
379 | {"V1.nested.k" "k" "0" "int"} | |
380 | } "list children of v1.nested" | |
381 | ||
382 | mi_check_varobj_value V1.i 1 "check V1.i: 1" | |
383 | mi_check_varobj_value V1.nested.j 2 "check V1.nested.j: 2" | |
384 | mi_check_varobj_value V1.nested.k 3 "check V1.nested.k: 3" | |
385 | mi_check_varobj_value V2 4 "check V2: 4" | |
386 | :*/ | |
387 | v2 = 5; | |
388 | /*: | |
389 | mi_varobj_update * {V2} "update varobjs: V2 changed" | |
390 | set_frozen V2 1 | |
391 | :*/ | |
392 | v2 = 6; | |
393 | /*: | |
394 | mi_varobj_update * {} "update varobjs: nothing changed" | |
395 | mi_check_varobj_value V2 5 "check V2: 5" | |
396 | mi_varobj_update V2 {V2} "update V2 explicitly" | |
397 | mi_check_varobj_value V2 6 "check V2: 6" | |
398 | :*/ | |
399 | v1.i = 7; | |
400 | v1.nested.j = 8; | |
401 | v1.nested.k = 9; | |
402 | /*: | |
403 | set_frozen V1 1 | |
404 | mi_varobj_update * {} "update varobjs: nothing changed" | |
405 | mi_check_varobj_value V1.i 1 "check V1.i: 1" | |
406 | mi_check_varobj_value V1.nested.j 2 "check V1.nested.j: 2" | |
407 | mi_check_varobj_value V1.nested.k 3 "check V1.nested.k: 3" | |
408 | # Check that explicit update for elements of structures | |
409 | # works. | |
410 | # Update v1.j | |
411 | mi_varobj_update V1.nested.j {V1.nested.j} "update V1.nested.j" | |
412 | mi_check_varobj_value V1.i 1 "check V1.i: 1" | |
413 | mi_check_varobj_value V1.nested.j 8 "check V1.nested.j: 8" | |
414 | mi_check_varobj_value V1.nested.k 3 "check V1.nested.k: 3" | |
415 | # Update v1.nested, check that children is updated. | |
416 | mi_varobj_update V1.nested {V1.nested.k} "update V1.nested" | |
417 | mi_check_varobj_value V1.i 1 "check V1.i: 1" | |
418 | mi_check_varobj_value V1.nested.j 8 "check V1.nested.j: 8" | |
419 | mi_check_varobj_value V1.nested.k 9 "check V1.nested.k: 9" | |
420 | # Update v1.i | |
421 | mi_varobj_update V1.i {V1.i} "update V1.i" | |
422 | mi_check_varobj_value V1.i 7 "check V1.i: 7" | |
423 | :*/ | |
424 | v1.i = 10; | |
425 | v1.nested.j = 11; | |
426 | v1.nested.k = 12; | |
427 | /*: | |
428 | # Check that unfreeze itself does not updates the values. | |
429 | set_frozen V1 0 | |
430 | mi_check_varobj_value V1.i 7 "check V1.i: 7" | |
431 | mi_check_varobj_value V1.nested.j 8 "check V1.nested.j: 8" | |
432 | mi_check_varobj_value V1.nested.k 9 "check V1.nested.k: 9" | |
433 | mi_varobj_update V1 {V1.i V1.nested.j V1.nested.k} "update V1" | |
434 | mi_check_varobj_value V1.i 10 "check V1.i: 10" | |
435 | mi_check_varobj_value V1.nested.j 11 "check V1.nested.j: 11" | |
436 | mi_check_varobj_value V1.nested.k 12 "check V1.nested.k: 12" | |
437 | :*/ | |
438 | ||
439 | /*: END: frozen :*/ | |
440 | } | |
441 | ||
fcacd99f VP |
442 | void do_at_tests_callee () |
443 | { | |
444 | /* This is a test of wrong DWARF data being assigned to expression. | |
445 | The DWARF location expression is bound to symbol when expression | |
446 | is parsed. So, if we create floating varobj in one function, | |
447 | and then try to reevaluate it in other frame without reparsing | |
448 | the expression, we will access local variables using DWARF | |
449 | location expression from the original frame, and are likely | |
450 | to grab wrong symbol. To reliably reproduce this bug, we need | |
451 | to wrap our variable with a bunch of buffers, so that those | |
452 | buffers are accessed instead of the real one. */ | |
453 | int buffer1 = 10; | |
454 | int buffer2 = 11; | |
455 | int buffer3 = 12; | |
456 | int i = 7; | |
457 | int buffer4 = 13; | |
458 | int buffer5 = 14; | |
459 | int buffer6 = 15; | |
460 | i++; /* breakpoint inside callee */ | |
461 | i++; | |
462 | } | |
463 | ||
464 | void do_at_tests () | |
465 | { | |
466 | int x; | |
467 | /*: BEGIN: floating :*/ | |
468 | int i = 10; | |
469 | int y = 15; | |
470 | /*: | |
471 | mi_create_floating_varobj F i "create floating varobj" | |
472 | :*/ | |
473 | i++; | |
474 | /*: | |
475 | mi_varobj_update F {F} "update F (1)" | |
476 | mi_check_varobj_value F 11 "check F (1)" | |
477 | :*/ | |
478 | i++; | |
479 | { | |
480 | double i = 15; | |
481 | /*: | |
482 | mi_varobj_update_with_type_change F "double" "0" "update F (2)" | |
483 | mi_check_varobj_value F 15 "check F (2)" | |
484 | :*/ | |
485 | i += 2.0; | |
486 | } | |
8e91f023 VP |
487 | { |
488 | float i = 19; | |
489 | /*: | |
490 | mi_gdb_test "-var-update --all-values F" {.*value="19".*} "update F (--all-values)" | |
491 | :*/ | |
492 | i += 2.0; | |
493 | } | |
fcacd99f VP |
494 | i++; |
495 | /*: | |
496 | mi_varobj_update_with_type_change F "int" "0" "update F (3)" | |
497 | mi_check_varobj_value F 13 "check F (3)" | |
498 | :*/ | |
499 | i++; | |
500 | do_at_tests_callee (); | |
501 | i++; | |
502 | /*: END: floating :*/ | |
503 | } | |
504 | ||
9e19b45e VP |
505 | /* Some header appear to define uint already, so apply some |
506 | uglification. Note that without uglification, the compile | |
507 | does not fail, rather, we don't test what we want because | |
508 | something else calls check_typedef on 'uint' already. */ | |
509 | typedef unsigned int uint_for_mi_testing; | |
510 | ||
511 | struct Data { | |
512 | int alloc; | |
513 | uint_for_mi_testing sharable : 4; | |
514 | }; | |
515 | ||
516 | /* Accessing a value of a bitfield whose type is a typed used to | |
517 | result in division by zero. See: | |
518 | ||
519 | http://sourceware.org/bugzilla/show_bug.cgi?id=10884 | |
520 | ||
521 | This tests for this bug. */ | |
522 | ||
523 | void do_bitfield_tests () | |
524 | { | |
525 | /*: BEGIN: bitfield :*/ | |
526 | struct Data d = {0, 3}; | |
527 | /*: | |
528 | mi_create_varobj V d "create varobj for Data" | |
529 | mi_list_varobj_children "V" { | |
530 | {"V.alloc" "alloc" "0" "int"} | |
c54eabfa | 531 | {"V.sharable" "sharable" "0" "uint_for_mi_testing"} |
9e19b45e VP |
532 | } "list children of Data" |
533 | mi_check_varobj_value V.sharable 3 "access bitfield" | |
534 | :*/ | |
535 | return; | |
536 | /*: END: bitfield :*/ | |
537 | } | |
538 | ||
3848a17f KS |
539 | void |
540 | do_anonymous_type_tests (void) | |
541 | { | |
542 | struct anonymous *anon; | |
543 | struct anonymous **ptr; | |
544 | struct | |
545 | { | |
546 | int x; | |
547 | struct | |
548 | { | |
549 | int a; | |
550 | }; | |
551 | struct | |
552 | { | |
553 | int b; | |
554 | }; | |
555 | } v = {1, {2}, {3}}; | |
556 | ||
557 | anon = malloc (sizeof (struct anonymous)); | |
558 | anon->a = 1; | |
559 | anon->b = 2; | |
560 | anon->c = (char *) 3; | |
561 | anon->d = 4; | |
562 | anon->g = '5'; | |
563 | anon->h = (const char **) 6; | |
564 | anon->simple = (simpleton ***) 7; | |
565 | ||
566 | ptr = &anon; | |
567 | free (anon); | |
568 | return; /* anonymous type tests breakpoint */ | |
569 | } | |
570 | ||
9a9a7608 AB |
571 | void |
572 | do_nested_struct_union_tests (void) | |
573 | { | |
574 | struct s_a | |
575 | { | |
576 | int a; | |
577 | }; | |
578 | struct s_b | |
579 | { | |
580 | int b; | |
581 | }; | |
582 | union u_ab | |
583 | { | |
584 | struct s_a a; | |
585 | struct s_b b; | |
586 | }; | |
587 | struct ss | |
588 | { | |
589 | struct s_a a1; | |
590 | struct s_b b1; | |
591 | union u_ab u1; | |
592 | ||
593 | /* Anonymous union. */ | |
594 | union | |
595 | { | |
596 | struct s_a a2; | |
597 | struct s_b b2; | |
598 | }; | |
599 | ||
600 | union | |
601 | { | |
602 | struct s_a a3; | |
603 | struct s_b b3; | |
604 | } u2; | |
605 | }; | |
606 | ||
607 | typedef struct | |
608 | { | |
609 | int a; | |
610 | } td_s_a; | |
611 | ||
612 | typedef struct | |
613 | { | |
614 | int b; | |
615 | } td_s_b; | |
616 | ||
617 | typedef union | |
618 | { | |
619 | td_s_a a; | |
620 | td_s_b b; | |
621 | } td_u_ab; | |
622 | ||
623 | struct ss var; | |
624 | struct | |
625 | { | |
626 | td_u_ab ab; | |
627 | } var2; | |
628 | ||
629 | struct ss *ss_ptr; | |
630 | ||
631 | memset (&var, 0, sizeof (var)); | |
632 | memset (&var2, 0, sizeof (var2)); | |
633 | ss_ptr = &var; | |
634 | ||
635 | return; /* nested struct union tests breakpoint */ | |
636 | } | |
637 | ||
fb40c209 AC |
638 | int |
639 | main (int argc, char *argv []) | |
640 | { | |
641 | do_locals_tests (); | |
642 | do_block_tests (); | |
643 | do_children_tests (); | |
644 | do_special_tests (); | |
25d5ea92 | 645 | do_frozen_tests (); |
fcacd99f | 646 | do_at_tests (); |
9e19b45e | 647 | do_bitfield_tests (); |
3848a17f | 648 | do_anonymous_type_tests (); |
9a9a7608 | 649 | do_nested_struct_union_tests (); |
fb40c209 AC |
650 | exit (0); |
651 | } | |
652 | ||
653 |