HAMMER Utilities: Sync with 60F
[dragonfly.git] / contrib / ncurses-5.4 / test / worm.c
blob651ccc15fba59d074e78038752417b8850b39d9c
1 /*
3 @@@ @@@ @@@@@@@@@@ @@@@@@@@@@@ @@@@@@@@@@@@
4 @@@ @@@ @@@@@@@@@@@@ @@@@@@@@@@@@ @@@@@@@@@@@@@
5 @@@ @@@ @@@@ @@@@ @@@@ @@@@ @@@ @@@@
6 @@@ @@ @@@ @@@ @@@ @@@ @@@ @@@ @@@
7 @@@ @@@@ @@@ @@@ @@@ @@@ @@@ @@@ @@@
8 @@@@ @@@@ @@@@ @@@ @@@ @@@ @@@ @@@ @@@
9 @@@@@@@@@@@@ @@@@ @@@@ @@@ @@@ @@@ @@@
10 @@@@ @@@@ @@@@@@@@@@@@ @@@ @@@ @@@ @@@
11 @@ @@ @@@@@@@@@@ @@@ @@@ @@@ @@@
13 Eric P. Scott
14 Caltech High Energy Physics
15 October, 1980
17 Hacks to turn this into a test frame for cursor movement:
18 Eric S. Raymond <esr@snark.thyrsus.com>
19 January, 1995
21 July 1995 (esr): worms is now in living color! :-)
23 Options:
24 -f fill screen with copies of 'WORM' at start.
25 -l <n> set worm length
26 -n <n> set number of worms
27 -t make worms leave droppings
28 -T <start> <end> set trace interval
29 -S set single-stepping during trace interval
30 -N suppress cursor-movement optimization
32 This program makes a good torture-test for the ncurses cursor-optimization
33 code. You can use -T to set the worm move interval over which movement
34 traces will be dumped. The program stops and waits for one character of
35 input at the beginning and end of the interval.
37 $Id: worm.c,v 1.37 2002/06/29 23:32:18 tom Exp $
40 #include <test.priv.h>
42 static chtype flavor[] =
44 'O', '*', '#', '$', '%', '0', '@',
46 static const short xinc[] =
48 1, 1, 1, 0, -1, -1, -1, 0
49 }, yinc[] =
51 -1, 0, 1, 1, 1, 0, -1, -1
53 static struct worm {
54 int orientation, head;
55 short *xpos, *ypos;
56 } worm[40];
58 static const char *field;
59 static int length = 16, number = 3;
60 static chtype trail = ' ';
62 #ifdef TRACE
63 int generation, trace_start, trace_end, singlestep;
64 #endif /* TRACE */
65 /* *INDENT-OFF* */
66 static const struct options {
67 int nopts;
68 int opts[3];
69 } normal[8]={
70 { 3, { 7, 0, 1 } },
71 { 3, { 0, 1, 2 } },
72 { 3, { 1, 2, 3 } },
73 { 3, { 2, 3, 4 } },
74 { 3, { 3, 4, 5 } },
75 { 3, { 4, 5, 6 } },
76 { 3, { 5, 6, 7 } },
77 { 3, { 6, 7, 0 } }
78 }, upper[8]={
79 { 1, { 1, 0, 0 } },
80 { 2, { 1, 2, 0 } },
81 { 0, { 0, 0, 0 } },
82 { 0, { 0, 0, 0 } },
83 { 0, { 0, 0, 0 } },
84 { 2, { 4, 5, 0 } },
85 { 1, { 5, 0, 0 } },
86 { 2, { 1, 5, 0 } }
87 }, left[8]={
88 { 0, { 0, 0, 0 } },
89 { 0, { 0, 0, 0 } },
90 { 0, { 0, 0, 0 } },
91 { 2, { 2, 3, 0 } },
92 { 1, { 3, 0, 0 } },
93 { 2, { 3, 7, 0 } },
94 { 1, { 7, 0, 0 } },
95 { 2, { 7, 0, 0 } }
96 }, right[8]={
97 { 1, { 7, 0, 0 } },
98 { 2, { 3, 7, 0 } },
99 { 1, { 3, 0, 0 } },
100 { 2, { 3, 4, 0 } },
101 { 0, { 0, 0, 0 } },
102 { 0, { 0, 0, 0 } },
103 { 0, { 0, 0, 0 } },
104 { 2, { 6, 7, 0 } }
105 }, lower[8]={
106 { 0, { 0, 0, 0 } },
107 { 2, { 0, 1, 0 } },
108 { 1, { 1, 0, 0 } },
109 { 2, { 1, 5, 0 } },
110 { 1, { 5, 0, 0 } },
111 { 2, { 5, 6, 0 } },
112 { 0, { 0, 0, 0 } },
113 { 0, { 0, 0, 0 } }
114 }, upleft[8]={
115 { 0, { 0, 0, 0 } },
116 { 0, { 0, 0, 0 } },
117 { 0, { 0, 0, 0 } },
118 { 0, { 0, 0, 0 } },
119 { 0, { 0, 0, 0 } },
120 { 1, { 3, 0, 0 } },
121 { 2, { 1, 3, 0 } },
122 { 1, { 1, 0, 0 } }
123 }, upright[8]={
124 { 2, { 3, 5, 0 } },
125 { 1, { 3, 0, 0 } },
126 { 0, { 0, 0, 0 } },
127 { 0, { 0, 0, 0 } },
128 { 0, { 0, 0, 0 } },
129 { 0, { 0, 0, 0 } },
130 { 0, { 0, 0, 0 } },
131 { 1, { 5, 0, 0 } }
132 }, lowleft[8]={
133 { 3, { 7, 0, 1 } },
134 { 0, { 0, 0, 0 } },
135 { 0, { 0, 0, 0 } },
136 { 1, { 1, 0, 0 } },
137 { 2, { 1, 7, 0 } },
138 { 1, { 7, 0, 0 } },
139 { 0, { 0, 0, 0 } },
140 { 0, { 0, 0, 0 } }
141 }, lowright[8]={
142 { 0, { 0, 0, 0 } },
143 { 1, { 7, 0, 0 } },
144 { 2, { 5, 7, 0 } },
145 { 1, { 5, 0, 0 } },
146 { 0, { 0, 0, 0 } },
147 { 0, { 0, 0, 0 } },
148 { 0, { 0, 0, 0 } },
149 { 0, { 0, 0, 0 } }
151 /* *INDENT-ON* */
153 static void
154 cleanup(void)
156 standend();
157 refresh();
158 curs_set(1);
159 endwin();
162 static RETSIGTYPE
163 onsig(int sig GCC_UNUSED)
165 cleanup();
166 ExitProgram(EXIT_FAILURE);
169 static float
170 ranf(void)
172 long r = (rand() & 077777);
173 return ((float) r / 32768.);
177 main(int argc, char *argv[])
179 short **ref;
180 int x, y;
181 int n;
182 struct worm *w;
183 const struct options *op;
184 int h;
185 short *ip;
186 int last, bottom;
188 setlocale(LC_ALL, "");
190 for (x = 1; x < argc; x++) {
191 char *p;
192 p = argv[x];
193 if (*p == '-')
194 p++;
195 switch (*p) {
196 case 'f':
197 field = "WORM";
198 break;
199 case 'l':
200 if (++x == argc)
201 goto usage;
202 if ((length = atoi(argv[x])) < 2 || length > 1024) {
203 fprintf(stderr, "%s: Invalid length\n", *argv);
204 ExitProgram(EXIT_FAILURE);
206 break;
207 case 'n':
208 if (++x == argc)
209 goto usage;
210 if ((number = atoi(argv[x])) < 1 || number > 40) {
211 fprintf(stderr, "%s: Invalid number of worms\n", *argv);
212 ExitProgram(EXIT_FAILURE);
214 break;
215 case 't':
216 trail = '.';
217 break;
218 #ifdef TRACE
219 case 'S':
220 singlestep = TRUE;
221 break;
222 case 'T':
223 trace_start = atoi(argv[++x]);
224 trace_end = atoi(argv[++x]);
225 break;
226 case 'N':
227 _nc_optimize_enable ^= OPTIMIZE_ALL; /* declared by ncurses */
228 break;
229 #endif /* TRACE */
230 default:
231 usage:
232 fprintf(stderr,
233 "usage: %s [-field] [-length #] [-number #] [-trail]\n", *argv);
234 ExitProgram(EXIT_FAILURE);
238 signal(SIGINT, onsig);
239 initscr();
240 noecho();
241 cbreak();
242 nonl();
244 curs_set(0);
246 bottom = LINES - 1;
247 last = COLS - 1;
249 #ifdef A_COLOR
250 if (has_colors()) {
251 int bg = COLOR_BLACK;
252 start_color();
253 #if HAVE_USE_DEFAULT_COLORS
254 if (use_default_colors() == OK)
255 bg = -1;
256 #endif
258 #define SET_COLOR(num, fg) \
259 init_pair(num+1, fg, bg); \
260 flavor[num] |= COLOR_PAIR(num+1) | A_BOLD
262 SET_COLOR(0, COLOR_GREEN);
263 SET_COLOR(1, COLOR_RED);
264 SET_COLOR(2, COLOR_CYAN);
265 SET_COLOR(3, COLOR_WHITE);
266 SET_COLOR(4, COLOR_MAGENTA);
267 SET_COLOR(5, COLOR_BLUE);
268 SET_COLOR(6, COLOR_YELLOW);
270 #endif /* A_COLOR */
272 ref = typeMalloc(short *, LINES);
273 for (y = 0; y < LINES; y++) {
274 ref[y] = typeMalloc(short, COLS);
275 for (x = 0; x < COLS; x++) {
276 ref[y][x] = 0;
280 #ifdef BADCORNER
281 /* if addressing the lower right corner doesn't work in your curses */
282 ref[bottom][last] = 1;
283 #endif /* BADCORNER */
285 for (n = number, w = &worm[0]; --n >= 0; w++) {
286 w->orientation = w->head = 0;
287 if (!(ip = typeMalloc(short, (length + 1)))) {
288 fprintf(stderr, "%s: out of memory\n", *argv);
289 ExitProgram(EXIT_FAILURE);
291 w->xpos = ip;
292 for (x = length; --x >= 0;)
293 *ip++ = -1;
294 if (!(ip = typeMalloc(short, (length + 1)))) {
295 fprintf(stderr, "%s: out of memory\n", *argv);
296 ExitProgram(EXIT_FAILURE);
298 w->ypos = ip;
299 for (y = length; --y >= 0;)
300 *ip++ = -1;
302 if (field) {
303 const char *p;
304 p = field;
305 for (y = bottom; --y >= 0;) {
306 for (x = COLS; --x >= 0;) {
307 addch((chtype) (*p++));
308 if (!*p)
309 p = field;
313 napms(10);
314 refresh();
315 #ifndef TRACE
316 nodelay(stdscr, TRUE);
317 #endif
319 for (;;) {
320 #ifdef TRACE
321 if (trace_start || trace_end) {
322 if (generation == trace_start) {
323 trace(TRACE_CALLS);
324 getch();
325 } else if (generation == trace_end) {
326 trace(0);
327 getch();
330 if (singlestep && generation > trace_start && generation < trace_end)
331 getch();
333 generation++;
335 #else
336 int ch;
338 if ((ch = getch()) > 0) {
339 #ifdef KEY_RESIZE
340 if (ch == KEY_RESIZE) {
341 if (last != COLS - 1) {
342 for (y = 0; y <= bottom; y++) {
343 ref[y] = typeRealloc(short, COLS, ref[y]);
344 for (x = last + 1; x < COLS; x++)
345 ref[y][x] = 0;
347 last = COLS - 1;
349 if (bottom != LINES - 1) {
350 for (y = LINES; y <= bottom; y++)
351 free(ref[y]);
352 ref = typeRealloc(short *, LINES, ref);
353 for (y = bottom + 1; y < LINES; y++) {
354 ref[y] = typeMalloc(short, COLS);
355 for (x = 0; x < COLS; x++)
356 ref[y][x] = 0;
358 bottom = LINES - 1;
361 #endif
363 * Make it simple to put this into single-step mode, or resume
364 * normal operation -TD
366 if (ch == 'q') {
367 cleanup();
368 ExitProgram(EXIT_SUCCESS);
369 } else if (ch == 's') {
370 nodelay(stdscr, FALSE);
371 } else if (ch == ' ') {
372 nodelay(stdscr, TRUE);
375 #endif /* TRACE */
377 for (n = 0, w = &worm[0]; n < number; n++, w++) {
378 if ((x = w->xpos[h = w->head]) < 0) {
379 move(y = w->ypos[h] = bottom, x = w->xpos[h] = 0);
380 addch(flavor[n % SIZEOF(flavor)]);
381 ref[y][x]++;
382 } else {
383 y = w->ypos[h];
385 if (x > last)
386 x = last;
387 if (y > bottom)
388 y = bottom;
389 if (++h == length)
390 h = 0;
391 if (w->xpos[w->head = h] >= 0) {
392 int x1, y1;
393 x1 = w->xpos[h];
394 y1 = w->ypos[h];
395 if (y1 < LINES
396 && x1 < COLS
397 && --ref[y1][x1] == 0) {
398 move(y1, x1);
399 addch(trail);
402 op = &(x == 0 ? (y == 0 ? upleft : (y == bottom ? lowleft :
403 left)) :
404 (x == last ? (y == 0 ? upright : (y == bottom ? lowright :
405 right)) :
406 (y == 0 ? upper : (y == bottom ? lower : normal))))[w->orientation];
407 switch (op->nopts) {
408 case 0:
409 cleanup();
410 ExitProgram(EXIT_SUCCESS);
411 case 1:
412 w->orientation = op->opts[0];
413 break;
414 default:
415 w->orientation = op->opts[(int) (ranf() * (float) op->nopts)];
417 move(y += yinc[w->orientation], x += xinc[w->orientation]);
419 if (y < 0)
420 y = 0;
421 addch(flavor[n % SIZEOF(flavor)]);
422 ref[w->ypos[h] = y][w->xpos[h] = x]++;
424 napms(10);
425 refresh();