]>
git.cameronkatri.com Git - bsdgames-darwin.git/blob - cgram/cgram.c
1 /* $NetBSD: cgram.c,v 1.23 2021/05/01 20:29:23 rillig Exp $ */
4 * Copyright (c) 2013, 2021 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by David A. Holland and Roland Illig.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
32 #include <sys/cdefs.h>
33 #if defined(__RCSID) && !defined(lint)
34 __RCSID("$NetBSD: cgram.c,v 1.23 2021/05/01 20:29:23 rillig Exp $");
47 #include "pathnames.h"
53 return isspace((unsigned char)ch
) != 0;
59 return ch
>= 'a' && ch
<= 'z';
65 return ch
>= 'A' && ch
<= 'Z';
71 return ch_islower(ch
) || ch_isupper(ch
);
77 return ch_islower(ch
) ? (char)(ch
- 'a' + 'A') : ch
;
83 return ch_isupper(ch
) ? (char)(ch
- 'A' + 'a') : ch
;
98 ////////////////////////////////////////////////////////////
112 string_init(struct string
*s
)
120 string_add(struct string
*s
, char ch
)
122 if (s
->len
>= s
->cap
) {
123 s
->cap
= 2 * s
->cap
+ 16;
124 s
->s
= realloc(s
->s
, s
->cap
);
126 errx(1, "Out of memory");
132 string_finish(struct string
*s
)
139 stringarray_init(struct stringarray
*a
)
146 stringarray_done(struct stringarray
*a
)
148 for (size_t i
= 0; i
< a
->num
; i
++)
154 stringarray_add(struct stringarray
*a
, struct string
*s
)
156 size_t num
= a
->num
++;
157 a
->v
= realloc(a
->v
, a
->num
* sizeof a
->v
[0]);
159 errx(1, "Out of memory");
164 stringarray_dup(struct stringarray
*dst
, const struct stringarray
*src
)
166 assert(dst
->num
== 0);
167 for (size_t i
= 0; i
< src
->num
; i
++) {
170 for (const char *p
= src
->v
[i
].s
; *p
!= '\0'; p
++)
171 string_add(&str
, *p
);
173 stringarray_add(dst
, &str
);
177 ////////////////////////////////////////////////////////////
179 static struct stringarray lines
;
180 static struct stringarray sollines
;
192 return (int)lines
.v
[cursor_y
].len
;
202 char_left_of_cursor(void)
205 return lines
.v
[cursor_y
].s
[cursor_x
- 1];
206 assert(cursor_y
> 0);
207 return '\n'; /* eol of previous line */
213 if (cursor_x
== cur_max_x())
215 return lines
.v
[cursor_y
].s
[cursor_x
];
225 while ((ch
= fgetc(f
)) != EOF
) {
227 string_finish(&line
);
228 stringarray_add(&lines
, &line
);
230 } else if (ch
== '\t') {
231 string_add(&line
, ' ');
232 while (line
.len
% 8 != 0)
233 string_add(&line
, ' ');
234 } else if (ch
== '\b') {
238 string_add(&line
, (char)ch
);
242 stringarray_dup(&sollines
, &lines
);
244 extent_y
= (int)lines
.num
;
245 for (int i
= 0; i
< extent_y
; i
++)
246 extent_x
= imax(extent_x
, (int)lines
.v
[i
].len
);
250 readfile(const char *name
)
252 FILE *f
= fopen(name
, "r");
266 FILE *f
= popen(_PATH_FORTUNE
, "r");
268 err(1, "%s", _PATH_FORTUNE
);
273 exit(1); /* error message must come from child process */
281 for (int i
= 0; i
< 26; i
++)
284 for (int i
= 26; i
> 1; i
--) {
285 int c
= (int)(random() % i
);
291 for (int y
= 0; y
< extent_y
; y
++) {
292 for (char *p
= lines
.v
[y
].s
; *p
!= '\0'; p
++) {
294 *p
= (char)('a' + key
[*p
- 'a']);
296 *p
= (char)('A' + key
[*p
- 'A']);
302 substitute(char a
, char b
)
304 char la
= ch_tolower(a
);
305 char ua
= ch_toupper(a
);
306 char lb
= ch_tolower(b
);
307 char ub
= ch_toupper(b
);
309 for (int y
= 0; y
< (int)lines
.num
; y
++) {
310 for (char *p
= lines
.v
[y
].s
; *p
!= '\0'; p
++) {
326 for (size_t i
= 0; i
< lines
.num
; i
++)
327 if (strcmp(lines
.v
[i
].s
, sollines
.v
[i
].s
) != 0)
332 ////////////////////////////////////////////////////////////
339 int max_y
= imin(LINES
- 1, extent_y
- offset_y
);
340 for (int y
= 0; y
< max_y
; y
++) {
343 int len
= (int)lines
.v
[offset_y
+ y
].len
;
344 int max_x
= imin(COLS
- 1, len
- offset_x
);
345 const char *line
= lines
.v
[offset_y
+ y
].s
;
346 const char *solline
= sollines
.v
[offset_y
+ y
].s
;
348 for (int x
= 0; x
< max_x
; x
++) {
349 char ch
= line
[offset_x
+ x
];
350 bool bold
= hinting
&&
351 (ch
== solline
[offset_x
+ x
] || !ch_isalpha(ch
));
363 addstr("~ to quit, * to cheat, ^pnfb to move");
366 if (extent_y
+ 1 - offset_y
< LINES
- 2)
367 move(extent_y
+ 1 - offset_y
, 0);
370 attron(A_BOLD
| A_STANDOUT
);
372 attroff(A_BOLD
| A_STANDOUT
);
375 move(cursor_y
- offset_y
, cursor_x
- offset_x
);
380 ////////////////////////////////////////////////////////////
383 saturate_cursor(void)
385 cursor_y
= imax(cursor_y
, 0);
386 cursor_y
= imin(cursor_y
, cur_max_y());
388 assert(cursor_x
>= 0);
389 cursor_x
= imin(cursor_x
, cur_max_x());
393 scroll_into_view(void)
395 if (cursor_x
< offset_x
)
397 if (cursor_x
> offset_x
+ COLS
- 1)
398 offset_x
= cursor_x
- (COLS
- 1);
400 if (cursor_y
< offset_y
)
402 if (cursor_y
> offset_y
+ LINES
- 2)
403 offset_y
= cursor_y
- (LINES
- 2);
409 return cursor_y
> 0 ||
410 (cursor_y
== 0 && cursor_x
> 0);
416 return cursor_y
< cur_max_y() ||
417 (cursor_y
== cur_max_y() && cursor_x
< cur_max_x());
421 go_to_prev_line(void)
424 cursor_x
= cur_max_x();
428 go_to_next_line(void)
439 else if (cursor_y
> 0)
446 if (cursor_x
< cur_max_x())
448 else if (cursor_y
< cur_max_y())
453 go_to_prev_word(void)
455 while (can_go_left() && ch_isspace(char_left_of_cursor()))
458 while (can_go_left() && !ch_isspace(char_left_of_cursor()))
463 go_to_next_word(void)
465 while (can_go_right() && !ch_isspace(char_at_cursor()))
468 while (can_go_right() && ch_isspace(char_at_cursor()))
473 can_substitute_here(int ch
)
475 return isascii(ch
) &&
476 ch_isalpha((char)ch
) &&
477 cursor_x
< cur_max_x() &&
478 ch_isalpha(char_at_cursor());
482 handle_char_input(int ch
)
484 if (ch
== char_at_cursor())
486 else if (can_substitute_here(ch
)) {
487 substitute(char_at_cursor(), (char)ch
);
509 cursor_x
= cur_max_x();
536 cursor_y
-= LINES
- 2;
539 cursor_y
+= LINES
- 2;
549 handle_char_input(ch
);
556 init(const char *filename
)
558 stringarray_init(&lines
);
559 stringarray_init(&sollines
);
560 srandom((unsigned int)time(NULL
));
561 if (filename
!= NULL
) {
571 keypad(stdscr
, true);
591 stringarray_done(&sollines
);
592 stringarray_done(&lines
);
600 fprintf(stderr
, "usage: %s [file]\n", getprogname());
605 main(int argc
, char *argv
[])
608 setprogname(argv
[0]);
609 if (argc
!= 1 && argc
!= 2)
612 init(argc
> 1 ? argv
[1] : NULL
);