1 1.31 kre /* $NetBSD: worms.c,v 1.31 2023/05/12 13:29:41 kre Exp $ */ 2 1.6 cgd 3 1.1 cgd /* 4 1.6 cgd * Copyright (c) 1980, 1993 5 1.6 cgd * The Regents of the University of California. All rights reserved. 6 1.1 cgd * 7 1.1 cgd * Redistribution and use in source and binary forms, with or without 8 1.1 cgd * modification, are permitted provided that the following conditions 9 1.1 cgd * are met: 10 1.1 cgd * 1. Redistributions of source code must retain the above copyright 11 1.1 cgd * notice, this list of conditions and the following disclaimer. 12 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 cgd * notice, this list of conditions and the following disclaimer in the 14 1.1 cgd * documentation and/or other materials provided with the distribution. 15 1.12 agc * 3. Neither the name of the University nor the names of its contributors 16 1.1 cgd * may be used to endorse or promote products derived from this software 17 1.1 cgd * without specific prior written permission. 18 1.1 cgd * 19 1.1 cgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 1.1 cgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 1.1 cgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 1.1 cgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 1.1 cgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 1.1 cgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 1.1 cgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 1.1 cgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 1.1 cgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 1.1 cgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 1.1 cgd * SUCH DAMAGE. 30 1.1 cgd */ 31 1.1 cgd 32 1.9 lukem #include <sys/cdefs.h> 33 1.1 cgd #ifndef lint 34 1.18 lukem __COPYRIGHT("@(#) Copyright (c) 1980, 1993\ 35 1.18 lukem The Regents of the University of California. All rights reserved."); 36 1.1 cgd #endif /* not lint */ 37 1.1 cgd 38 1.1 cgd #ifndef lint 39 1.6 cgd #if 0 40 1.6 cgd static char sccsid[] = "@(#)worms.c 8.1 (Berkeley) 5/31/93"; 41 1.6 cgd #else 42 1.31 kre __RCSID("$NetBSD: worms.c,v 1.31 2023/05/12 13:29:41 kre Exp $"); 43 1.6 cgd #endif 44 1.1 cgd #endif /* not lint */ 45 1.1 cgd 46 1.1 cgd /* 47 1.1 cgd * 48 1.1 cgd * @@@ @@@ @@@@@@@@@@ @@@@@@@@@@@ @@@@@@@@@@@@ 49 1.1 cgd * @@@ @@@ @@@@@@@@@@@@ @@@@@@@@@@@@ @@@@@@@@@@@@@ 50 1.1 cgd * @@@ @@@ @@@@ @@@@ @@@@ @@@@ @@@ @@@@ 51 1.1 cgd * @@@ @@ @@@ @@@ @@@ @@@ @@@ @@@ @@@ 52 1.1 cgd * @@@ @@@@ @@@ @@@ @@@ @@@ @@@ @@@ @@@ 53 1.1 cgd * @@@@ @@@@ @@@@ @@@ @@@ @@@ @@@ @@@ @@@ 54 1.1 cgd * @@@@@@@@@@@@ @@@@ @@@@ @@@ @@@ @@@ @@@ 55 1.1 cgd * @@@@ @@@@ @@@@@@@@@@@@ @@@ @@@ @@@ @@@ 56 1.1 cgd * @@ @@ @@@@@@@@@@ @@@ @@@ @@@ @@@ 57 1.1 cgd * 58 1.1 cgd * Eric P. Scott 59 1.1 cgd * Caltech High Energy Physics 60 1.1 cgd * October, 1980 61 1.1 cgd * 62 1.1 cgd */ 63 1.1 cgd #include <sys/types.h> 64 1.6 cgd 65 1.26 kre #include <ctype.h> 66 1.11 hubertf #include <curses.h> 67 1.11 hubertf #include <err.h> 68 1.26 kre #include <limits.h> 69 1.6 cgd #include <signal.h> 70 1.27 kre #include <stdbool.h> 71 1.1 cgd #include <stdio.h> 72 1.2 mycroft #include <stdlib.h> 73 1.26 kre #include <strings.h> 74 1.30 kre #include <term.h> 75 1.6 cgd #include <unistd.h> 76 1.1 cgd 77 1.11 hubertf static const struct options { 78 1.1 cgd int nopts; 79 1.1 cgd int opts[3]; 80 1.1 cgd } 81 1.1 cgd normal[8] = { 82 1.1 cgd { 3, { 7, 0, 1 } }, 83 1.1 cgd { 3, { 0, 1, 2 } }, 84 1.1 cgd { 3, { 1, 2, 3 } }, 85 1.1 cgd { 3, { 2, 3, 4 } }, 86 1.1 cgd { 3, { 3, 4, 5 } }, 87 1.1 cgd { 3, { 4, 5, 6 } }, 88 1.1 cgd { 3, { 5, 6, 7 } }, 89 1.1 cgd { 3, { 6, 7, 0 } } 90 1.30 kre }, 91 1.30 kre upper[8] = { 92 1.1 cgd { 1, { 1, 0, 0 } }, 93 1.1 cgd { 2, { 1, 2, 0 } }, 94 1.1 cgd { 0, { 0, 0, 0 } }, 95 1.1 cgd { 0, { 0, 0, 0 } }, 96 1.1 cgd { 0, { 0, 0, 0 } }, 97 1.1 cgd { 2, { 4, 5, 0 } }, 98 1.1 cgd { 1, { 5, 0, 0 } }, 99 1.1 cgd { 2, { 1, 5, 0 } } 100 1.1 cgd }, 101 1.1 cgd left[8] = { 102 1.1 cgd { 0, { 0, 0, 0 } }, 103 1.1 cgd { 0, { 0, 0, 0 } }, 104 1.1 cgd { 0, { 0, 0, 0 } }, 105 1.1 cgd { 2, { 2, 3, 0 } }, 106 1.1 cgd { 1, { 3, 0, 0 } }, 107 1.1 cgd { 2, { 3, 7, 0 } }, 108 1.1 cgd { 1, { 7, 0, 0 } }, 109 1.1 cgd { 2, { 7, 0, 0 } } 110 1.1 cgd }, 111 1.1 cgd right[8] = { 112 1.1 cgd { 1, { 7, 0, 0 } }, 113 1.1 cgd { 2, { 3, 7, 0 } }, 114 1.1 cgd { 1, { 3, 0, 0 } }, 115 1.1 cgd { 2, { 3, 4, 0 } }, 116 1.1 cgd { 0, { 0, 0, 0 } }, 117 1.1 cgd { 0, { 0, 0, 0 } }, 118 1.1 cgd { 0, { 0, 0, 0 } }, 119 1.1 cgd { 2, { 6, 7, 0 } } 120 1.1 cgd }, 121 1.1 cgd lower[8] = { 122 1.1 cgd { 0, { 0, 0, 0 } }, 123 1.1 cgd { 2, { 0, 1, 0 } }, 124 1.1 cgd { 1, { 1, 0, 0 } }, 125 1.1 cgd { 2, { 1, 5, 0 } }, 126 1.1 cgd { 1, { 5, 0, 0 } }, 127 1.1 cgd { 2, { 5, 6, 0 } }, 128 1.1 cgd { 0, { 0, 0, 0 } }, 129 1.1 cgd { 0, { 0, 0, 0 } } 130 1.1 cgd }, 131 1.1 cgd upleft[8] = { 132 1.1 cgd { 0, { 0, 0, 0 } }, 133 1.1 cgd { 0, { 0, 0, 0 } }, 134 1.1 cgd { 0, { 0, 0, 0 } }, 135 1.1 cgd { 0, { 0, 0, 0 } }, 136 1.1 cgd { 0, { 0, 0, 0 } }, 137 1.1 cgd { 1, { 3, 0, 0 } }, 138 1.1 cgd { 2, { 1, 3, 0 } }, 139 1.1 cgd { 1, { 1, 0, 0 } } 140 1.1 cgd }, 141 1.1 cgd upright[8] = { 142 1.1 cgd { 2, { 3, 5, 0 } }, 143 1.1 cgd { 1, { 3, 0, 0 } }, 144 1.1 cgd { 0, { 0, 0, 0 } }, 145 1.1 cgd { 0, { 0, 0, 0 } }, 146 1.1 cgd { 0, { 0, 0, 0 } }, 147 1.1 cgd { 0, { 0, 0, 0 } }, 148 1.1 cgd { 0, { 0, 0, 0 } }, 149 1.1 cgd { 1, { 5, 0, 0 } } 150 1.1 cgd }, 151 1.1 cgd lowleft[8] = { 152 1.1 cgd { 3, { 7, 0, 1 } }, 153 1.1 cgd { 0, { 0, 0, 0 } }, 154 1.1 cgd { 0, { 0, 0, 0 } }, 155 1.1 cgd { 1, { 1, 0, 0 } }, 156 1.1 cgd { 2, { 1, 7, 0 } }, 157 1.1 cgd { 1, { 7, 0, 0 } }, 158 1.1 cgd { 0, { 0, 0, 0 } }, 159 1.1 cgd { 0, { 0, 0, 0 } } 160 1.1 cgd }, 161 1.1 cgd lowright[8] = { 162 1.1 cgd { 0, { 0, 0, 0 } }, 163 1.1 cgd { 1, { 7, 0, 0 } }, 164 1.1 cgd { 2, { 5, 7, 0 } }, 165 1.1 cgd { 1, { 5, 0, 0 } }, 166 1.1 cgd { 0, { 0, 0, 0 } }, 167 1.1 cgd { 0, { 0, 0, 0 } }, 168 1.1 cgd { 0, { 0, 0, 0 } }, 169 1.1 cgd { 0, { 0, 0, 0 } } 170 1.1 cgd }; 171 1.11 hubertf static const char flavor[] = { 172 1.30 kre 'O', '*', '#', '$', '%', '0', 'o', '~', 173 1.30 kre '+', 'x', ':', '^', '_', '&', '@', 'w' 174 1.1 cgd }; 175 1.30 kre static const int flavors = __arraycount(flavor); 176 1.31 kre static const char eyeball[] = { 177 1.31 kre '0', 'X', '@', 'S', 'X', '@', 'O', '=', 178 1.31 kre '#', '*', '=', 'v', 'L', '@', 'o', 'm' 179 1.31 kre }; 180 1.31 kre __CTASSERT(sizeof(flavor) == sizeof(eyeball)); 181 1.30 kre 182 1.11 hubertf static const short xinc[] = { 183 1.1 cgd 1, 1, 1, 0, -1, -1, -1, 0 184 1.1 cgd }, yinc[] = { 185 1.1 cgd -1, 0, 1, 1, 1, 0, -1, -1 186 1.1 cgd }; 187 1.1 cgd static struct worm { 188 1.30 kre int orientation, head, len; 189 1.1 cgd short *xpos, *ypos; 190 1.31 kre chtype ch, eye, attr; 191 1.1 cgd } *worm; 192 1.1 cgd 193 1.30 kre static volatile sig_atomic_t sig_caught; 194 1.11 hubertf 195 1.30 kre static int initclr(int**); 196 1.20 dholland static void nomem(void) __dead; 197 1.20 dholland static void onsig(int); 198 1.30 kre static int worm_length(int, int); 199 1.2 mycroft 200 1.6 cgd int 201 1.22 dholland main(int argc, char *argv[]) 202 1.1 cgd { 203 1.30 kre int CO, LI, last, bottom, ch, number, trail; 204 1.30 kre int x, y, h, n, nc; 205 1.30 kre int maxlength, minlength; 206 1.30 kre unsigned int seed, delay; 207 1.30 kre const struct options *op; 208 1.9 lukem struct worm *w; 209 1.30 kre short **ref; 210 1.9 lukem short *ip; 211 1.11 hubertf const char *field; 212 1.26 kre char *ep; 213 1.30 kre unsigned long ul, up; 214 1.27 kre bool argerror = false; 215 1.30 kre bool docolour = false; /* -C, use coloured worms */ 216 1.30 kre bool docaput = false; /* -H, show which end of worm is head */ 217 1.30 kre int *ctab = NULL; 218 1.1 cgd 219 1.30 kre delay = 20000; 220 1.30 kre maxlength = minlength = 16; 221 1.1 cgd number = 3; 222 1.30 kre seed = 0; 223 1.1 cgd trail = ' '; 224 1.1 cgd field = NULL; 225 1.30 kre 226 1.30 kre if ((ep = getenv("WORMS")) != NULL) { 227 1.30 kre ul = up = 0; 228 1.30 kre while ((ch = *ep++) != '\0') { 229 1.30 kre switch (ch) { 230 1.30 kre case 'C': 231 1.30 kre docolour = !docolour; 232 1.30 kre continue; 233 1.30 kre case 'f': 234 1.30 kre if (field) 235 1.30 kre field = NULL; 236 1.30 kre else 237 1.30 kre field = "WORM"; 238 1.30 kre continue; 239 1.30 kre case 'H': 240 1.30 kre docaput = !docaput; 241 1.30 kre continue; 242 1.30 kre case 'r': 243 1.30 kre minlength = 5; 244 1.30 kre maxlength = 0; 245 1.30 kre continue; 246 1.30 kre case 't': 247 1.30 kre if (trail == ' ') 248 1.30 kre trail = '.'; 249 1.30 kre else 250 1.30 kre trail = ' '; 251 1.30 kre continue; 252 1.30 kre case '0': case '1': case '2': case '3': case '4': 253 1.30 kre case '5': case '6': case '7': case '8': case '9': 254 1.30 kre if (up > 1) 255 1.30 kre continue; 256 1.30 kre if (ul >= 100000) /* 1/10 second, in us */ 257 1.30 kre continue; 258 1.30 kre ul *= 10; 259 1.30 kre ul += (ch - '0'); 260 1.30 kre up = 1; 261 1.30 kre continue; 262 1.30 kre case 'm': 263 1.30 kre if (up == 1 && ul <= 1000) 264 1.30 kre ul *= 1000; 265 1.30 kre up += 2; 266 1.30 kre continue; 267 1.30 kre default: 268 1.30 kre continue; 269 1.30 kre } 270 1.30 kre } 271 1.30 kre if ((up & 1) != 0) /* up == 1 || up == 3 */ 272 1.30 kre delay = ul; 273 1.30 kre } 274 1.30 kre 275 1.30 kre while ((ch = getopt(argc, argv, "Cd:fHl:n:rS:t")) != -1) { 276 1.1 cgd switch(ch) { 277 1.30 kre case 'C': 278 1.30 kre docolour = !docolour; 279 1.30 kre continue; 280 1.11 hubertf case 'd': 281 1.26 kre ul = strtoul(optarg, &ep, 10); 282 1.26 kre if (ep != optarg) { 283 1.26 kre while (isspace(*(unsigned char *)ep)) 284 1.26 kre ep++; 285 1.26 kre } 286 1.26 kre if (ep == optarg || 287 1.26 kre (*ep != '\0' && 288 1.26 kre ( ep[1] == '\0' ? (*ep != 'm' && *ep != 'u') : 289 1.26 kre ( strcasecmp(ep, "ms") != 0 && 290 1.26 kre strcasecmp(ep, "us") != 0 )) )) { 291 1.26 kre errx(1, "-d: invalid delay (%s)", optarg); 292 1.26 kre } 293 1.26 kre /* 294 1.26 kre * if ul >= INT_MAX/1000 we don't need the *1000, 295 1.26 kre * as even without that it will exceed the limit 296 1.26 kre * just below and be treated as an error. 297 1.26 kre * (This does assume >=32 bit int, but so does POSIX) 298 1.26 kre */ 299 1.26 kre if (*ep != 'u' && ul < INT_MAX / 1000) 300 1.26 kre ul *= 1000; /* ms -> us */ 301 1.26 kre if (ul > 1000*1000) { 302 1.26 kre errx(1, 303 1.28 kre "-d: delay (%s) out of range [0 - 1000]", 304 1.26 kre optarg); 305 1.26 kre } 306 1.26 kre delay = (unsigned int)ul; 307 1.27 kre continue; 308 1.1 cgd case 'f': 309 1.30 kre if (field == NULL) 310 1.30 kre field = "WORM"; 311 1.30 kre else 312 1.30 kre field = NULL; 313 1.30 kre continue; 314 1.30 kre case 'H': 315 1.30 kre docaput = !docaput; 316 1.27 kre continue; 317 1.1 cgd case 'l': 318 1.30 kre up = ul = strtoul(optarg, &ep, 10); 319 1.30 kre if (ep != optarg) { 320 1.30 kre while (isspace(*(unsigned char *)ep)) 321 1.30 kre ep++; 322 1.30 kre if (*ep == '-') 323 1.30 kre up = strtoul(++ep, &ep, 10); 324 1.30 kre } 325 1.26 kre if (ep == optarg || *ep != '\0' || 326 1.30 kre ul < 2 || up < ul || up > 1024) { 327 1.26 kre errx(1, "-l: invalid length (%s) [%d - %d].", 328 1.26 kre optarg, 2, 1024); 329 1.1 cgd } 330 1.30 kre minlength = (int)ul; 331 1.30 kre maxlength = (int)up; 332 1.27 kre continue; 333 1.1 cgd case 'n': 334 1.26 kre ul = strtoul(optarg, &ep, 10); 335 1.26 kre if (ep == optarg || *ep != '\0' || 336 1.26 kre ul < 1 || ul > INT_MAX / 10 ) { 337 1.26 kre errx(1, "-n: invalid number of worms (%s).", 338 1.26 kre optarg); 339 1.1 cgd } 340 1.26 kre /* upper bound is further limited later */ 341 1.26 kre number = (int)ul; 342 1.27 kre continue; 343 1.30 kre case 'r': 344 1.30 kre minlength = 5; 345 1.30 kre maxlength = 0; 346 1.30 kre continue; 347 1.27 kre case 'S': 348 1.27 kre ul = strtoul(optarg, &ep, 0); 349 1.27 kre if (ep == optarg || *ep != '\0' || 350 1.27 kre ul > UINT_MAX ) { 351 1.27 kre errx(1, "-S: invalid seed (%s).", optarg); 352 1.27 kre } 353 1.27 kre seed = (unsigned int)ul; 354 1.27 kre continue; 355 1.1 cgd case 't': 356 1.30 kre if (trail == ' ') 357 1.30 kre trail = '.'; 358 1.30 kre else 359 1.30 kre trail = ' '; 360 1.27 kre continue; 361 1.1 cgd case '?': 362 1.1 cgd default: 363 1.27 kre argerror = true; 364 1.27 kre break; 365 1.1 cgd } 366 1.27 kre break; 367 1.27 kre } 368 1.27 kre 369 1.27 kre if (argerror || argc > optind) 370 1.27 kre errx(1, 371 1.30 kre "Usage: worms [-CfHrt] [-d delay] [-l length] [-n number]"); 372 1.27 kre /* -S omitted deliberately, not useful often enough */ 373 1.1 cgd 374 1.19 drochner if (!initscr()) 375 1.26 kre errx(1, "couldn't initialize screen"); 376 1.14 jsm curs_set(0); 377 1.30 kre nc = docolour ? initclr(&ctab) : 0; 378 1.11 hubertf CO = COLS; 379 1.11 hubertf LI = LINES; 380 1.26 kre 381 1.27 kre if (CO == 0 || LI == 0) { 382 1.27 kre endwin(); 383 1.27 kre errx(1, "screen must be a rectangle, not (%dx%d)", CO, LI); 384 1.27 kre } 385 1.30 kre 386 1.30 kre /* 387 1.30 kre * The "sizeof(short *)" noise is to abslutely guarantee 388 1.30 kre * that a LI * CO * sizeof(short *) cannot overflow an int 389 1.30 kre */ 390 1.30 kre if (CO >= (int)(INT_MAX / (2 * sizeof(short *)) / LI)) { 391 1.27 kre endwin(); 392 1.27 kre errx(1, "screen (%dx%d) too large for worms", CO, LI); 393 1.27 kre } 394 1.27 kre 395 1.27 kre /* now known that LI*CO cannot overflow an int => also not a long */ 396 1.27 kre 397 1.27 kre if (LI < 3 || CO < 3 || LI * CO < 40) { 398 1.27 kre /* 399 1.27 kre * The placement algorithm is too weak for dimensions < 3. 400 1.27 kre * Need at least 40 spaces so we can have (n > 1) worms 401 1.27 kre * of a reasonable length, and still leave empty space. 402 1.27 kre */ 403 1.27 kre endwin(); 404 1.27 kre errx(1, "screen (%dx%d) too small for worms", CO, LI); 405 1.27 kre } 406 1.27 kre 407 1.30 kre if (maxlength == 0) 408 1.30 kre maxlength = minlength + (CO * LI / 40); 409 1.30 kre 410 1.27 kre ul = (unsigned long)CO * LI; 411 1.30 kre if ((unsigned long)maxlength > ul / 20) { 412 1.27 kre endwin(); 413 1.29 kre errx(1, "-l: worms too long (%d) for screen; max: %lu", 414 1.30 kre maxlength, ul / 20); 415 1.30 kre } 416 1.30 kre 417 1.30 kre ul /= maxlength * 3; /* no more than 33% arena occupancy */ 418 1.30 kre 419 1.30 kre if ((unsigned long)(unsigned)number > ul && maxlength > minlength) { 420 1.30 kre maxlength = CO * LI / 3 / number; 421 1.30 kre if (maxlength < minlength) 422 1.30 kre maxlength = minlength; 423 1.30 kre ul = (CO * LI) / ((minlength + maxlength)/2 * 3);; 424 1.26 kre } 425 1.26 kre 426 1.26 kre if ((unsigned long)(unsigned)number > ul) { 427 1.26 kre endwin(); 428 1.26 kre errx(1, "-n: too many worms (%d) max: %lu", number, ul); 429 1.26 kre } 430 1.26 kre if (!(worm = calloc((size_t)number, sizeof(struct worm)))) 431 1.26 kre nomem(); 432 1.26 kre 433 1.30 kre srandom(seed ? seed : arc4random()); 434 1.30 kre 435 1.4 mycroft last = CO - 1; 436 1.4 mycroft bottom = LI - 1; 437 1.30 kre 438 1.30 kre if (!(ip = calloc(LI * CO, sizeof(short)))) 439 1.1 cgd nomem(); 440 1.30 kre if (!(ref = malloc((size_t)LI * sizeof(short *)))) 441 1.1 cgd nomem(); 442 1.1 cgd for (n = 0; n < LI; ++n) { 443 1.1 cgd ref[n] = ip; 444 1.1 cgd ip += CO; 445 1.1 cgd } 446 1.30 kre 447 1.1 cgd for (n = number, w = &worm[0]; --n >= 0; w++) { 448 1.30 kre int i; 449 1.30 kre 450 1.1 cgd w->orientation = w->head = 0; 451 1.30 kre w->len = worm_length(minlength, maxlength); 452 1.30 kre w->attr = nc ? ctab[n % nc] : 0; 453 1.30 kre i = (nc && number > flavors ? n / nc : n) % flavors; 454 1.30 kre w->ch = flavor[i]; 455 1.31 kre w->eye = eyeball[i]; 456 1.30 kre 457 1.30 kre if (!(ip = malloc((size_t)(w->len * sizeof(short))))) 458 1.1 cgd nomem(); 459 1.1 cgd w->xpos = ip; 460 1.30 kre for (x = w->len; --x >= 0;) 461 1.1 cgd *ip++ = -1; 462 1.30 kre if (!(ip = malloc((size_t)(w->len * sizeof(short))))) 463 1.1 cgd nomem(); 464 1.1 cgd w->ypos = ip; 465 1.30 kre for (y = w->len; --y >= 0;) 466 1.1 cgd *ip++ = -1; 467 1.1 cgd } 468 1.30 kre free(ctab); /* not needed any more */ 469 1.1 cgd 470 1.1 cgd (void)signal(SIGHUP, onsig); 471 1.1 cgd (void)signal(SIGINT, onsig); 472 1.1 cgd (void)signal(SIGQUIT, onsig); 473 1.30 kre (void)signal(SIGTERM, onsig); 474 1.1 cgd (void)signal(SIGTSTP, onsig); 475 1.30 kre (void)signal(SIGWINCH, onsig); 476 1.1 cgd 477 1.1 cgd if (field) { 478 1.11 hubertf const char *p = field; 479 1.1 cgd 480 1.11 hubertf for (y = LI; --y >= 0;) { 481 1.1 cgd for (x = CO; --x >= 0;) { 482 1.11 hubertf addch(*p++); 483 1.1 cgd if (!*p) 484 1.1 cgd p = field; 485 1.1 cgd } 486 1.1 cgd } 487 1.1 cgd } 488 1.30 kre 489 1.1 cgd for (;;) { 490 1.11 hubertf refresh(); 491 1.11 hubertf if (sig_caught) { 492 1.11 hubertf endwin(); 493 1.11 hubertf exit(0); 494 1.11 hubertf } 495 1.15 hubertf if (delay) { 496 1.15 hubertf if (delay % 1000000 != 0) 497 1.15 hubertf usleep(delay % 1000000); 498 1.15 hubertf if (delay >= 1000000) 499 1.15 hubertf sleep(delay / 1000000); 500 1.15 hubertf } 501 1.1 cgd for (n = 0, w = &worm[0]; n < number; n++, w++) { 502 1.31 kre chtype c = docaput ? w->eye : w->ch; 503 1.30 kre 504 1.1 cgd if ((x = w->xpos[h = w->head]) < 0) { 505 1.11 hubertf mvaddch(y = w->ypos[h] = bottom, 506 1.30 kre x = w->xpos[h] = 0, c | w->attr); 507 1.1 cgd ref[y][x]++; 508 1.30 kre } else 509 1.1 cgd y = w->ypos[h]; 510 1.30 kre if (++h == w->len) 511 1.1 cgd h = 0; 512 1.1 cgd if (w->xpos[w->head = h] >= 0) { 513 1.9 lukem int x1, y1; 514 1.1 cgd 515 1.1 cgd x1 = w->xpos[h]; 516 1.1 cgd y1 = w->ypos[h]; 517 1.30 kre if (--ref[y1][x1] == 0) 518 1.11 hubertf mvaddch(y1, x1, trail); 519 1.1 cgd } 520 1.25 kre 521 1.25 kre op = &(!x 522 1.25 kre ? (!y 523 1.25 kre ? upleft 524 1.25 kre : (y == bottom ? lowleft : left)) 525 1.25 kre : (x == last 526 1.25 kre ? (!y ? upright 527 1.25 kre : (y == bottom ? lowright : right)) 528 1.25 kre : (!y ? upper 529 1.25 kre : (y == bottom ? lower : normal))) 530 1.25 kre )[w->orientation]; 531 1.25 kre 532 1.1 cgd switch (op->nopts) { 533 1.1 cgd case 0: 534 1.27 kre endwin(); 535 1.1 cgd abort(); 536 1.27 kre /* NOTREACHED */ 537 1.1 cgd case 1: 538 1.1 cgd w->orientation = op->opts[0]; 539 1.1 cgd break; 540 1.1 cgd default: 541 1.1 cgd w->orientation = 542 1.1 cgd op->opts[(int)random() % op->nopts]; 543 1.1 cgd } 544 1.11 hubertf mvaddch(y += yinc[w->orientation], 545 1.11 hubertf x += xinc[w->orientation], 546 1.30 kre c | w->attr); 547 1.1 cgd ref[w->ypos[h] = y][w->xpos[h] = x]++; 548 1.30 kre if (docaput && w->len > 1) { 549 1.30 kre int prev = (h ? h : w->len) - 1; 550 1.30 kre 551 1.30 kre mvaddch(w->ypos[prev], w->xpos[prev], 552 1.30 kre w->ch | w->attr); 553 1.30 kre } 554 1.30 kre } 555 1.30 kre } 556 1.30 kre } 557 1.30 kre 558 1.30 kre static int 559 1.30 kre initclr(int** ctab) 560 1.30 kre { 561 1.30 kre int *ip, clr[] = { 562 1.30 kre COLOR_BLACK, COLOR_RED, COLOR_GREEN, COLOR_YELLOW, 563 1.30 kre COLOR_BLUE, COLOR_MAGENTA, COLOR_CYAN, COLOR_WHITE 564 1.30 kre }, attr[] = { 565 1.30 kre A_NORMAL, A_BOLD, A_DIM 566 1.30 kre }; 567 1.30 kre int nattr = __arraycount(attr); 568 1.30 kre int nclr = __arraycount(clr); 569 1.30 kre int nc = 0; 570 1.30 kre 571 1.30 kre /* terminfo first */ 572 1.30 kre char* s; 573 1.30 kre bool canbold = (s = tigetstr("bold")) != (char* )-1 && s != NULL; 574 1.30 kre bool candim = (s = tigetstr("dim")) != (char* )-1 && s != NULL; 575 1.30 kre 576 1.30 kre #ifdef DO_TERMCAP 577 1.30 kre /* termcap if terminfo fails */ 578 1.30 kre canbold = canbold || (s = tgetstr("md", NULL)) != NULL; 579 1.30 kre candim = candim || (s = tgetstr("mh", NULL)) != NULL; 580 1.30 kre #endif 581 1.30 kre 582 1.30 kre if (has_colors() == FALSE) 583 1.30 kre return 0; 584 1.30 kre use_default_colors(); 585 1.30 kre if (start_color() == ERR) 586 1.30 kre return 0; 587 1.30 kre if ((*ctab = calloc(COLOR_PAIRS, sizeof(int))) == NULL) 588 1.30 kre nomem(); 589 1.30 kre ip = *ctab; 590 1.30 kre 591 1.30 kre for (int i = 0; i < nattr; i++) { 592 1.30 kre if (!canbold && attr[i] == A_BOLD) 593 1.30 kre continue; 594 1.30 kre if (!candim && attr[i] == A_DIM) 595 1.30 kre continue; 596 1.30 kre 597 1.30 kre for (int j = 0; j < nclr; j++) { 598 1.30 kre if (clr[j] == COLOR_BLACK && attr[i] != A_BOLD) 599 1.30 kre continue; /* invisible */ 600 1.30 kre if (nc + 1 >= COLOR_PAIRS) 601 1.30 kre break; 602 1.30 kre if (init_pair(nc + 1, clr[j], -1) == ERR) 603 1.30 kre break; 604 1.30 kre *ip++ = COLOR_PAIR(nc + 1) | attr[i]; 605 1.30 kre nc++; 606 1.1 cgd } 607 1.1 cgd } 608 1.30 kre 609 1.30 kre return nc; 610 1.30 kre } 611 1.30 kre 612 1.30 kre static int 613 1.30 kre worm_length(int low, int high) 614 1.30 kre { 615 1.30 kre if (low >= high) 616 1.30 kre return low; 617 1.30 kre 618 1.30 kre return low + (random() % (high - low + 1)); 619 1.1 cgd } 620 1.1 cgd 621 1.20 dholland static void 622 1.22 dholland onsig(int signo __unused) 623 1.6 cgd { 624 1.11 hubertf sig_caught = 1; 625 1.1 cgd } 626 1.1 cgd 627 1.26 kre /* This is never called before curses is initialised */ 628 1.20 dholland static void 629 1.22 dholland nomem(void) 630 1.1 cgd { 631 1.26 kre endwin(); 632 1.11 hubertf errx(1, "not enough memory."); 633 1.1 cgd } 634