1 /*-
2  * Copyright (c) 2012-2017 Dag-Erling Smørgrav
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. The name of the author may not be used to endorse or promote
14  *    products derived from this software without specific prior written
15  *    permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  * $OpenPAM: t_openpam_readword.c 938 2017-04-30 21:34:42Z des $
30  */
31 
32 #ifdef HAVE_CONFIG_H
33 # include "config.h"
34 #endif
35 
36 #include <err.h>
37 #include <stdint.h>
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <unistd.h>
42 
43 #include <cryb/test.h>
44 
45 #include <security/pam_appl.h>
46 #include <security/openpam.h>
47 
48 #define T_FUNC(n, d)							\
49 	static const char *t_ ## n ## _desc = d;			\
50 	static int t_ ## n ## _func(OPENPAM_UNUSED(char **desc),	\
51 	    OPENPAM_UNUSED(void *arg))
52 
53 #define T(n)								\
54 	t_add_test(&t_ ## n ## _func, NULL, "%s", t_ ## n ## _desc)
55 
56 /*
57  * Read a word from the temp file and verify that the result matches our
58  * expectations: whether a word was read at all, how many lines were read
59  * (in case of quoted or escaped newlines), whether we reached the end of
60  * the file and whether we reached the end of the line.
61  */
62 static int
63 orw_expect(struct t_file *tf, const char *expected, int lines, int eof, int eol)
64 {
65 	int ch, lineno = 0;
66 	char *got;
67 	size_t len;
68 	int ret;
69 
70 	got = openpam_readword(tf->file, &lineno, &len);
71 	ret = 1;
72 	if (t_ferror(tf))
73 		err(1, "%s(): %s", __func__, tf->name);
74 	if (expected != NULL && got == NULL) {
75 		t_printv("expected <<%s>>, got nothing\n", expected);
76 		ret = 0;
77 	} else if (expected == NULL && got != NULL) {
78 		t_printv("expected nothing, got <<%s>>\n", got);
79 		ret = 0;
80 	} else if (expected != NULL && got != NULL && strcmp(expected, got) != 0) {
81 		t_printv("expected <<%s>>, got <<%s>>\n", expected, got);
82 		ret = 0;
83 	}
84 	free(got);
85 	if (lineno != lines) {
86 		t_printv("expected to advance %d lines, advanced %d lines\n",
87 		    lines, lineno);
88 		ret = 0;
89 	}
90 	if (eof && !t_feof(tf)) {
91 		t_printv("expected EOF, but didn't get it\n");
92 		ret = 0;
93 	}
94 	if (!eof && t_feof(tf)) {
95 		t_printv("didn't expect EOF, but got it anyway\n");
96 		ret = 0;
97 	}
98 	ch = fgetc(tf->file);
99 	if (t_ferror(tf))
100 		err(1, "%s(): %s", __func__, tf->name);
101 	if (eol && ch != '\n') {
102 		t_printv("expected EOL, but didn't get it\n");
103 		ret = 0;
104 	} else if (!eol && ch == '\n') {
105 		t_printv("didn't expect EOL, but got it anyway\n");
106 		ret = 0;
107 	}
108 	if (ch != EOF)
109 		ungetc(ch, tf->file);
110 	return (ret);
111 }
112 
113 
114 /***************************************************************************
115  * Lines without words
116  */
117 
118 T_FUNC(empty_input, "empty input")
119 {
120 	struct t_file *tf;
121 	int ret;
122 
123 	tf = t_fopen(NULL);
124 	ret = orw_expect(tf, NULL, 0 /*lines*/, 1 /*eof*/, 0 /*eol*/);
125 	t_fclose(tf);
126 	return (ret);
127 }
128 
129 T_FUNC(empty_line, "empty line")
130 {
131 	struct t_file *tf;
132 	int ret;
133 
134 	tf = t_fopen(NULL);
135 	t_fprintf(tf, "\n");
136 	t_frewind(tf);
137 	ret = orw_expect(tf, NULL, 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
138 	t_fclose(tf);
139 	return (ret);
140 }
141 
142 T_FUNC(unterminated_line, "unterminated line")
143 {
144 	struct t_file *tf;
145 	int ret;
146 
147 	tf = t_fopen(NULL);
148 	t_fprintf(tf, " ");
149 	t_frewind(tf);
150 	ret = orw_expect(tf, NULL, 0 /*lines*/, 1 /*eof*/, 0 /*eol*/);
151 	t_fclose(tf);
152 	return (ret);
153 }
154 
155 T_FUNC(single_whitespace, "single whitespace")
156 {
157 	struct t_file *tf;
158 	int ret;
159 
160 	tf = t_fopen(NULL);
161 	t_fprintf(tf, " \n");
162 	t_frewind(tf);
163 	ret = orw_expect(tf, NULL, 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
164 	t_fclose(tf);
165 	return (ret);
166 }
167 
168 T_FUNC(multiple_whitespace, "multiple whitespace")
169 {
170 	struct t_file *tf;
171 	int ret;
172 
173 	tf = t_fopen(NULL);
174 	t_fprintf(tf, " \t\r\n");
175 	t_frewind(tf);
176 	ret = orw_expect(tf, NULL, 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
177 	t_fclose(tf);
178 	return (ret);
179 }
180 
181 T_FUNC(comment, "comment")
182 {
183 	struct t_file *tf;
184 	int ret;
185 
186 	tf = t_fopen(NULL);
187 	t_fprintf(tf, "# comment\n");
188 	t_frewind(tf);
189 	ret = orw_expect(tf, NULL, 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
190 	t_fclose(tf);
191 	return (ret);
192 }
193 
194 T_FUNC(whitespace_before_comment, "whitespace before comment")
195 {
196 	struct t_file *tf;
197 	int ret;
198 
199 	tf = t_fopen(NULL);
200 	t_fprintf(tf, " # comment\n");
201 	t_frewind(tf);
202 	ret = orw_expect(tf, NULL, 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
203 	t_fclose(tf);
204 	return (ret);
205 }
206 
207 T_FUNC(single_quoted_comment, "single-quoted comment")
208 {
209 	struct t_file *tf;
210 	int ret;
211 
212 	tf = t_fopen(NULL);
213 	t_fprintf(tf, " '# comment'\n");
214 	t_frewind(tf);
215 	ret = orw_expect(tf, "# comment", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
216 	t_fclose(tf);
217 	return (ret);
218 }
219 
220 T_FUNC(double_quoted_comment, "double-quoted comment")
221 {
222 	struct t_file *tf;
223 	int ret;
224 
225 	tf = t_fopen(NULL);
226 	t_fprintf(tf, " \"# comment\"\n");
227 	t_frewind(tf);
228 	ret = orw_expect(tf, "# comment", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
229 	t_fclose(tf);
230 	return (ret);
231 }
232 
233 T_FUNC(comment_at_eof, "comment at end of file")
234 {
235 	struct t_file *tf;
236 	int ret;
237 
238 	tf = t_fopen(NULL);
239 	t_fprintf(tf, "# comment");
240 	t_frewind(tf);
241 	ret = orw_expect(tf, NULL, 0 /*lines*/, 1 /*eof*/, 0 /*eol*/);
242 	t_fclose(tf);
243 	return (ret);
244 }
245 
246 
247 /***************************************************************************
248  * Simple cases - no quotes or escapes
249  */
250 
251 T_FUNC(single_word, "single word")
252 {
253 	const char *word = "hello";
254 	struct t_file *tf;
255 	int ret;
256 
257 	tf = t_fopen(NULL);
258 	t_fprintf(tf, "%s\n", word);
259 	t_frewind(tf);
260 	ret = orw_expect(tf, word, 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
261 	t_fclose(tf);
262 	return (ret);
263 }
264 
265 T_FUNC(single_whitespace_before_word, "single whitespace before word")
266 {
267 	const char *word = "hello";
268 	struct t_file *tf;
269 	int ret;
270 
271 	tf = t_fopen(NULL);
272 	t_fprintf(tf, " %s\n", word);
273 	t_frewind(tf);
274 	ret = orw_expect(tf, word, 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
275 	t_fclose(tf);
276 	return (ret);
277 }
278 
279 T_FUNC(double_whitespace_before_word, "double whitespace before word")
280 {
281 	const char *word = "hello";
282 	struct t_file *tf;
283 	int ret;
284 
285 	tf = t_fopen(NULL);
286 	t_fprintf(tf, "  %s\n", word);
287 	t_frewind(tf);
288 	ret = orw_expect(tf, word, 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
289 	t_fclose(tf);
290 	return (ret);
291 }
292 
293 T_FUNC(single_whitespace_after_word, "single whitespace after word")
294 {
295 	const char *word = "hello";
296 	struct t_file *tf;
297 	int ret;
298 
299 	tf = t_fopen(NULL);
300 	t_fprintf(tf, "%s \n", word);
301 	t_frewind(tf);
302 	ret = orw_expect(tf, word, 0 /*lines*/, 0 /*eof*/, 0 /*eol*/);
303 	t_fclose(tf);
304 	return (ret);
305 }
306 
307 T_FUNC(double_whitespace_after_word, "double whitespace after word")
308 {
309 	const char *word = "hello";
310 	struct t_file *tf;
311 	int ret;
312 
313 	tf = t_fopen(NULL);
314 	t_fprintf(tf, "%s  \n", word);
315 	t_frewind(tf);
316 	ret = orw_expect(tf, word, 0 /*lines*/, 0 /*eof*/, 0 /*eol*/);
317 	t_fclose(tf);
318 	return (ret);
319 }
320 
321 T_FUNC(comment_after_word, "comment after word")
322 {
323 	const char *word = "hello";
324 	struct t_file *tf;
325 	int ret;
326 
327 	tf = t_fopen(NULL);
328 	t_fprintf(tf, "%s # comment\n", word);
329 	t_frewind(tf);
330 	ret = orw_expect(tf, word, 0 /*lines*/, 0 /*eof*/, 0 /*eol*/) &&
331 	    orw_expect(tf, NULL, 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
332 	t_fclose(tf);
333 	return (ret);
334 }
335 
336 T_FUNC(word_containing_hash, "word containing hash")
337 {
338 	const char *word = "hello#world";
339 	struct t_file *tf;
340 	int ret;
341 
342 	tf = t_fopen(NULL);
343 	t_fprintf(tf, "%s\n", word);
344 	t_frewind(tf);
345 	ret = orw_expect(tf, word, 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
346 	t_fclose(tf);
347 	return (ret);
348 }
349 
350 T_FUNC(two_words, "two words")
351 {
352 	const char *word[] = { "hello", "world" };
353 	struct t_file *tf;
354 	int ret;
355 
356 	tf = t_fopen(NULL);
357 	t_fprintf(tf, "%s %s\n", word[0], word[1]);
358 	t_frewind(tf);
359 	ret = orw_expect(tf, word[0], 0 /*lines*/, 0 /*eof*/, 0 /*eol*/) &&
360 	    orw_expect(tf, word[1], 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
361 	t_fclose(tf);
362 	return (ret);
363 }
364 
365 
366 /***************************************************************************
367  * Escapes
368  */
369 
370 T_FUNC(naked_escape, "naked escape")
371 {
372 	struct t_file *tf;
373 	int ret;
374 
375 	tf = t_fopen(NULL);
376 	t_fprintf(tf, "\\");
377 	t_frewind(tf);
378 	ret = orw_expect(tf, NULL, 0 /*lines*/, 1 /*eof*/, 0 /*eol*/);
379 	t_fclose(tf);
380 	return (ret);
381 }
382 
383 T_FUNC(escaped_escape, "escaped escape")
384 {
385 	struct t_file *tf;
386 	int ret;
387 
388 	tf = t_fopen(NULL);
389 	t_fprintf(tf, "\\\\\n");
390 	t_frewind(tf);
391 	ret = orw_expect(tf, "\\", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
392 	t_fclose(tf);
393 	return (ret);
394 }
395 
396 T_FUNC(escaped_whitespace, "escaped whitespace")
397 {
398 	struct t_file *tf;
399 	int ret;
400 
401 	tf = t_fopen(NULL);
402 	t_fprintf(tf, "\\  \\\t \\\r \\\n\n");
403 	t_frewind(tf);
404 	ret = orw_expect(tf, " ", 0 /*lines*/, 0 /*eof*/, 0 /*eol*/) &&
405 	    orw_expect(tf, "\t", 0 /*lines*/, 0 /*eof*/, 0 /*eol*/) &&
406 	    orw_expect(tf, "\r", 0 /*lines*/, 0 /*eof*/, 0 /*eol*/) &&
407 	    /* this last one is a line continuation */
408 	    orw_expect(tf, NULL, 1 /*lines*/, 0 /*eof*/, 1 /*eol*/);
409 	t_fclose(tf);
410 	return (ret);
411 }
412 
413 T_FUNC(escaped_newline_before_word, "escaped newline before word")
414 {
415 	struct t_file *tf;
416 	int ret;
417 
418 	tf = t_fopen(NULL);
419 	t_fprintf(tf, "\\\nhello world\n");
420 	t_frewind(tf);
421 	ret = orw_expect(tf, "hello", 1 /*lines*/, 0 /*eof*/, 0 /*eol*/);
422 	t_fclose(tf);
423 	return (ret);
424 }
425 
426 T_FUNC(escaped_newline_within_word, "escaped newline within word")
427 {
428 	struct t_file *tf;
429 	int ret;
430 
431 	tf = t_fopen(NULL);
432 	t_fprintf(tf, "hello\\\nworld\n");
433 	t_frewind(tf);
434 	ret = orw_expect(tf, "helloworld", 1 /*lines*/, 0 /*eof*/, 1 /*eol*/);
435 	t_fclose(tf);
436 	return (ret);
437 }
438 
439 T_FUNC(escaped_newline_after_word, "escaped newline after word")
440 {
441 	struct t_file *tf;
442 	int ret;
443 
444 	tf = t_fopen(NULL);
445 	t_fprintf(tf, "hello\\\n world\n");
446 	t_frewind(tf);
447 	ret = orw_expect(tf, "hello", 1 /*lines*/, 0 /*eof*/, 0 /*eol*/);
448 	t_fclose(tf);
449 	return (ret);
450 }
451 
452 T_FUNC(escaped_letter, "escaped letter")
453 {
454 	struct t_file *tf;
455 	int ret;
456 
457 	tf = t_fopen(NULL);
458 	t_fprintf(tf, "\\z\n");
459 	t_frewind(tf);
460 	ret = orw_expect(tf, "z", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
461 	t_fclose(tf);
462 	return (ret);
463 }
464 
465 T_FUNC(escaped_comment, "escaped comment")
466 {
467 	struct t_file *tf;
468 	int ret;
469 
470 	tf = t_fopen(NULL);
471 	t_fprintf(tf, " \\# comment\n");
472 	t_frewind(tf);
473 	ret = orw_expect(tf, "#", 0 /*lines*/, 0 /*eof*/, 0 /*eol*/) &&
474 	    orw_expect(tf, "comment", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
475 	t_fclose(tf);
476 	return (ret);
477 }
478 
479 T_FUNC(escape_at_eof, "escape at end of file")
480 {
481 	struct t_file *tf;
482 	int ret;
483 
484 	tf = t_fopen(NULL);
485 	t_fprintf(tf, "z\\");
486 	t_frewind(tf);
487 	ret = orw_expect(tf, NULL, 0 /*lines*/, 1 /*eof*/, 0 /*eol*/);
488 	t_fclose(tf);
489 	return (ret);
490 }
491 
492 
493 /***************************************************************************
494  * Quotes
495  */
496 
497 T_FUNC(naked_single_quote, "naked single quote")
498 {
499 	struct t_file *tf;
500 	int ret;
501 
502 	tf = t_fopen(NULL);
503 	t_fprintf(tf, "'");
504 	t_frewind(tf);
505 	ret = orw_expect(tf, NULL, 0 /*lines*/, 1 /*eof*/, 0 /*eol*/);
506 	t_fclose(tf);
507 	return (ret);
508 }
509 
510 T_FUNC(naked_double_quote, "naked double quote")
511 {
512 	struct t_file *tf;
513 	int ret;
514 
515 	tf = t_fopen(NULL);
516 	t_fprintf(tf, "\"");
517 	t_frewind(tf);
518 	ret = orw_expect(tf, NULL, 0 /*lines*/, 1 /*eof*/, 0 /*eol*/);
519 	t_fclose(tf);
520 	return (ret);
521 }
522 
523 T_FUNC(empty_single_quotes, "empty single quotes")
524 {
525 	struct t_file *tf;
526 	int ret;
527 
528 	tf = t_fopen(NULL);
529 	t_fprintf(tf, "''\n");
530 	t_frewind(tf);
531 	ret = orw_expect(tf, "", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
532 	t_fclose(tf);
533 	return (ret);
534 }
535 
536 T_FUNC(empty_double_quotes, "empty double quotes")
537 {
538 	struct t_file *tf;
539 	int ret;
540 
541 	tf = t_fopen(NULL);
542 	t_fprintf(tf, "\"\"\n");
543 	t_frewind(tf);
544 	ret = orw_expect(tf, "", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
545 	t_fclose(tf);
546 	return (ret);
547 }
548 
549 T_FUNC(single_quotes_within_double_quotes, "single quotes within double quotes")
550 {
551 	struct t_file *tf;
552 	int ret;
553 
554 	tf = t_fopen(NULL);
555 	t_fprintf(tf, "\"' '\"\n");
556 	t_frewind(tf);
557 	ret = orw_expect(tf, "' '", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
558 	t_fclose(tf);
559 	return (ret);
560 }
561 
562 T_FUNC(double_quotes_within_single_quotes, "double quotes within single quotes")
563 {
564 	struct t_file *tf;
565 	int ret;
566 
567 	tf = t_fopen(NULL);
568 	t_fprintf(tf, "'\" \"'\n");
569 	t_frewind(tf);
570 	ret = orw_expect(tf, "\" \"", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
571 	t_fclose(tf);
572 	return (ret);
573 }
574 
575 T_FUNC(single_quoted_whitespace, "single-quoted whitespace")
576 {
577 	struct t_file *tf;
578 	int ret;
579 
580 	tf = t_fopen(NULL);
581 	t_fprintf(tf, "' ' '\t' '\r' '\n'\n");
582 	t_frewind(tf);
583 	ret = orw_expect(tf, " ", 0 /*lines*/, 0 /*eof*/, 0 /*eol*/) &&
584 	    orw_expect(tf, "\t", 0 /*lines*/, 0 /*eof*/, 0 /*eol*/) &&
585 	    orw_expect(tf, "\r", 0 /*lines*/, 0 /*eof*/, 0 /*eol*/) &&
586 	    orw_expect(tf, "\n", 1 /*lines*/, 0 /*eof*/, 1 /*eol*/);
587 	t_fclose(tf);
588 	return (ret);
589 }
590 
591 T_FUNC(double_quoted_whitespace, "double-quoted whitespace")
592 {
593 	struct t_file *tf;
594 	int ret;
595 
596 	tf = t_fopen(NULL);
597 	t_fprintf(tf, "\" \" \"\t\" \"\r\" \"\n\"\n");
598 	t_frewind(tf);
599 	ret = orw_expect(tf, " ", 0 /*lines*/, 0 /*eof*/, 0 /*eol*/) &&
600 	    orw_expect(tf, "\t", 0 /*lines*/, 0 /*eof*/, 0 /*eol*/) &&
601 	    orw_expect(tf, "\r", 0 /*lines*/, 0 /*eof*/, 0 /*eol*/) &&
602 	    orw_expect(tf, "\n", 1 /*lines*/, 0 /*eof*/, 1 /*eol*/);
603 	t_fclose(tf);
604 	return (ret);
605 }
606 
607 T_FUNC(single_quoted_words, "single-quoted words")
608 {
609 	struct t_file *tf;
610 	int ret;
611 
612 	tf = t_fopen(NULL);
613 	t_fprintf(tf, "'hello world'\n");
614 	t_frewind(tf);
615 	ret = orw_expect(tf, "hello world", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
616 	t_fclose(tf);
617 	return (ret);
618 }
619 
620 T_FUNC(double_quoted_words, "double-quoted words")
621 {
622 	struct t_file *tf;
623 	int ret;
624 
625 	tf = t_fopen(NULL);
626 	t_fprintf(tf, "\"hello world\"\n");
627 	t_frewind(tf);
628 	ret = orw_expect(tf, "hello world", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
629 	t_fclose(tf);
630 	return (ret);
631 }
632 
633 
634 /***************************************************************************
635  * Combinations of quoted and unquoted text
636  */
637 
638 T_FUNC(single_quote_before_word, "single quote before word")
639 {
640 	struct t_file *tf;
641 	int ret;
642 
643 	tf = t_fopen(NULL);
644 	t_fprintf(tf, "'hello 'world\n");
645 	t_frewind(tf);
646 	ret = orw_expect(tf, "hello world", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
647 	t_fclose(tf);
648 	return (ret);
649 }
650 
651 T_FUNC(double_quote_before_word, "double quote before word")
652 {
653 	struct t_file *tf;
654 	int ret;
655 
656 	tf = t_fopen(NULL);
657 	t_fprintf(tf, "\"hello \"world\n");
658 	t_frewind(tf);
659 	ret = orw_expect(tf, "hello world", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
660 	t_fclose(tf);
661 	return (ret);
662 }
663 
664 T_FUNC(single_quote_within_word, "single quote within word")
665 {
666 	struct t_file *tf;
667 	int ret;
668 
669 	tf = t_fopen(NULL);
670 	t_fprintf(tf, "hello' 'world\n");
671 	t_frewind(tf);
672 	ret = orw_expect(tf, "hello world", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
673 	t_fclose(tf);
674 	return (ret);
675 }
676 
677 T_FUNC(double_quote_within_word, "double quote within word")
678 {
679 	struct t_file *tf;
680 	int ret;
681 
682 	tf = t_fopen(NULL);
683 	t_fprintf(tf, "hello\" \"world\n");
684 	t_frewind(tf);
685 	ret = orw_expect(tf, "hello world", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
686 	t_fclose(tf);
687 	return (ret);
688 }
689 
690 T_FUNC(single_quote_after_word, "single quote after word")
691 {
692 	struct t_file *tf;
693 	int ret;
694 
695 	tf = t_fopen(NULL);
696 	t_fprintf(tf, "hello' world'\n");
697 	t_frewind(tf);
698 	ret = orw_expect(tf, "hello world", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
699 	t_fclose(tf);
700 	return (ret);
701 }
702 
703 T_FUNC(double_quote_after_word, "double quote after word")
704 {
705 	struct t_file *tf;
706 	int ret;
707 
708 	tf = t_fopen(NULL);
709 	t_fprintf(tf, "hello\" world\"\n");
710 	t_frewind(tf);
711 	ret = orw_expect(tf, "hello world", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
712 	t_fclose(tf);
713 	return (ret);
714 }
715 
716 
717 /***************************************************************************
718  * Combinations of escape and quotes
719  */
720 
721 T_FUNC(escaped_single_quote,
722     "escaped single quote")
723 {
724 	struct t_file *tf;
725 	int ret;
726 
727 	tf = t_fopen(NULL);
728 	t_fprintf(tf, "\\'\n");
729 	t_frewind(tf);
730 	ret = orw_expect(tf, "'", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
731 	t_fclose(tf);
732 	return (ret);
733 }
734 
735 T_FUNC(escaped_double_quote,
736     "escaped double quote")
737 {
738 	struct t_file *tf;
739 	int ret;
740 
741 	tf = t_fopen(NULL);
742 	t_fprintf(tf, "\\\"\n");
743 	t_frewind(tf);
744 	ret = orw_expect(tf, "\"", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
745 	t_fclose(tf);
746 	return (ret);
747 }
748 
749 T_FUNC(escaped_whitespace_within_single_quotes,
750     "escaped whitespace within single quotes")
751 {
752 	struct t_file *tf;
753 	int ret;
754 
755 	tf = t_fopen(NULL);
756 	t_fprintf(tf, "'\\ ' '\\\t' '\\\r' '\\\n'\n");
757 	t_frewind(tf);
758 	ret = orw_expect(tf, "\\ ", 0 /*lines*/, 0 /*eof*/, 0 /*eol*/) &&
759 	    orw_expect(tf, "\\\t", 0 /*lines*/, 0 /*eof*/, 0 /*eol*/) &&
760 	    orw_expect(tf, "\\\r", 0 /*lines*/, 0 /*eof*/, 0 /*eol*/) &&
761 	    orw_expect(tf, "\\\n", 1 /*lines*/, 0 /*eof*/, 1 /*eol*/);
762 	t_fclose(tf);
763 	return (ret);
764 }
765 
766 T_FUNC(escaped_whitespace_within_double_quotes,
767     "escaped whitespace within double quotes")
768 {
769 	struct t_file *tf;
770 	int ret;
771 
772 	tf = t_fopen(NULL);
773 	t_fprintf(tf, "\"\\ \" \"\\\t\" \"\\\r\" \"\\\n\"\n");
774 	t_frewind(tf);
775 	ret = orw_expect(tf, "\\ ", 0 /*lines*/, 0 /*eof*/, 0 /*eol*/) &&
776 	    orw_expect(tf, "\\\t", 0 /*lines*/, 0 /*eof*/, 0 /*eol*/) &&
777 	    orw_expect(tf, "\\\r", 0 /*lines*/, 0 /*eof*/, 0 /*eol*/) &&
778 	    /* this last one is a line continuation */
779 	    orw_expect(tf, "", 1 /*lines*/, 0 /*eof*/, 1 /*eol*/);
780 	t_fclose(tf);
781 	return (ret);
782 }
783 
784 T_FUNC(escaped_letter_within_single_quotes,
785     "escaped letter within single quotes")
786 {
787 	struct t_file *tf;
788 	int ret;
789 
790 	tf = t_fopen(NULL);
791 	t_fprintf(tf, "'\\z'\n");
792 	t_frewind(tf);
793 	ret = orw_expect(tf, "\\z", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
794 	t_fclose(tf);
795 	return (ret);
796 }
797 
798 T_FUNC(escaped_letter_within_double_quotes,
799     "escaped letter within double quotes")
800 {
801 	struct t_file *tf;
802 	int ret;
803 
804 	tf = t_fopen(NULL);
805 	t_fprintf(tf, "\"\\z\"\n");
806 	t_frewind(tf);
807 	ret = orw_expect(tf, "\\z", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
808 	t_fclose(tf);
809 	return (ret);
810 }
811 
812 T_FUNC(escaped_escape_within_single_quotes,
813     "escaped escape within single quotes")
814 {
815 	struct t_file *tf;
816 	int ret;
817 
818 	tf = t_fopen(NULL);
819 	t_fprintf(tf, "'\\\\'\n");
820 	t_frewind(tf);
821 	ret = orw_expect(tf, "\\\\", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
822 	t_fclose(tf);
823 	return (ret);
824 }
825 
826 T_FUNC(escaped_escape_within_double_quotes,
827     "escaped escape within double quotes")
828 {
829 	struct t_file *tf;
830 	int ret;
831 
832 	tf = t_fopen(NULL);
833 	t_fprintf(tf, "\"\\\\\"\n");
834 	t_frewind(tf);
835 	ret = orw_expect(tf, "\\", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
836 	t_fclose(tf);
837 	return (ret);
838 }
839 
840 T_FUNC(escaped_single_quote_within_single_quotes,
841     "escaped single quote within single quotes")
842 {
843 	struct t_file *tf;
844 	int ret;
845 
846 	tf = t_fopen(NULL);
847 	t_fprintf(tf, "'\\''\n");
848 	t_frewind(tf);
849 	ret = orw_expect(tf, NULL, 1 /*lines*/, 1 /*eof*/, 0 /*eol*/);
850 	t_fclose(tf);
851 	return (ret);
852 }
853 
854 T_FUNC(escaped_double_quote_within_single_quotes,
855     "escaped double quote within single quotes")
856 {
857 	struct t_file *tf;
858 	int ret;
859 
860 	tf = t_fopen(NULL);
861 	t_fprintf(tf, "'\\\"'\n");
862 	t_frewind(tf);
863 	ret = orw_expect(tf, "\\\"", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
864 	t_fclose(tf);
865 	return (ret);
866 }
867 
868 T_FUNC(escaped_single_quote_within_double_quotes,
869     "escaped single quote within double quotes")
870 {
871 	struct t_file *tf;
872 	int ret;
873 
874 	tf = t_fopen(NULL);
875 	t_fprintf(tf, "\"\\'\"\n");
876 	t_frewind(tf);
877 	ret = orw_expect(tf, "\\'", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
878 	t_fclose(tf);
879 	return (ret);
880 }
881 
882 T_FUNC(escaped_double_quote_within_double_quotes,
883     "escaped double quote within double quotes")
884 {
885 	struct t_file *tf;
886 	int ret;
887 
888 	tf = t_fopen(NULL);
889 	t_fprintf(tf, "\"\\\"\"\n");
890 	t_frewind(tf);
891 	ret = orw_expect(tf, "\"", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
892 	t_fclose(tf);
893 	return (ret);
894 }
895 
896 
897 /***************************************************************************
898  * Line continuation
899  */
900 
901 T_FUNC(line_continuation_within_whitespace, "line continuation within whitespace")
902 {
903 	struct t_file *tf;
904 	int ret;
905 
906 	tf = t_fopen(NULL);
907 	t_fprintf(tf, "hello \\\n world\n");
908 	t_frewind(tf);
909 	ret = orw_expect(tf, "hello", 0 /*lines*/, 0 /*eof*/, 0 /*eol*/) &&
910 	    orw_expect(tf, "world", 1 /*lines*/, 0 /*eof*/, 1 /*eol*/);
911 	t_fclose(tf);
912 	return (ret);
913 }
914 
915 T_FUNC(line_continuation_before_whitespace, "line continuation before whitespace")
916 {
917 	struct t_file *tf;
918 	int ret;
919 
920 	tf = t_fopen(NULL);
921 	t_fprintf(tf, "hello\\\n world\n");
922 	t_frewind(tf);
923 	ret = orw_expect(tf, "hello", 1 /*lines*/, 0 /*eof*/, 0 /*eol*/) &&
924 	    orw_expect(tf, "world", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
925 	t_fclose(tf);
926 	return (ret);
927 }
928 
929 T_FUNC(line_continuation_after_whitespace, "line continuation after whitespace")
930 {
931 	struct t_file *tf;
932 	int ret;
933 
934 	tf = t_fopen(NULL);
935 	t_fprintf(tf, "hello \\\nworld\n");
936 	t_frewind(tf);
937 	ret = orw_expect(tf, "hello", 0 /*lines*/, 0 /*eof*/, 0 /*eol*/) &&
938 	    orw_expect(tf, "world", 1 /*lines*/, 0 /*eof*/, 1 /*eol*/);
939 	t_fclose(tf);
940 	return (ret);
941 }
942 
943 T_FUNC(line_continuation_within_word, "line continuation within word")
944 {
945 	struct t_file *tf;
946 	int ret;
947 
948 	tf = t_fopen(NULL);
949 	t_fprintf(tf, "hello\\\nworld\n");
950 	t_frewind(tf);
951 	ret = orw_expect(tf, "helloworld", 1 /*lines*/, 0 /*eof*/, 1 /*eol*/);
952 	t_fclose(tf);
953 	return (ret);
954 }
955 
956 
957 /***************************************************************************
958  * Boilerplate
959  */
960 
961 static int
962 t_prepare(int argc, char *argv[])
963 {
964 
965 	(void)argc;
966 	(void)argv;
967 
968 	T(empty_input);
969 	T(empty_line);
970 	T(unterminated_line);
971 	T(single_whitespace);
972 	T(multiple_whitespace);
973 	T(comment);
974 	T(whitespace_before_comment);
975 	T(single_quoted_comment);
976 	T(double_quoted_comment);
977 	T(comment_at_eof);
978 
979 	T(single_word);
980 	T(single_whitespace_before_word);
981 	T(double_whitespace_before_word);
982 	T(single_whitespace_after_word);
983 	T(double_whitespace_after_word);
984 	T(comment_after_word);
985 	T(word_containing_hash);
986 	T(two_words);
987 
988 	T(naked_escape);
989 	T(escaped_escape);
990 	T(escaped_whitespace);
991 	T(escaped_newline_before_word);
992 	T(escaped_newline_within_word);
993 	T(escaped_newline_after_word);
994 	T(escaped_letter);
995 	T(escaped_comment);
996 	T(escape_at_eof);
997 
998 	T(naked_single_quote);
999 	T(naked_double_quote);
1000 	T(empty_single_quotes);
1001 	T(empty_double_quotes);
1002 	T(single_quotes_within_double_quotes);
1003 	T(double_quotes_within_single_quotes);
1004 	T(single_quoted_whitespace);
1005 	T(double_quoted_whitespace);
1006 	T(single_quoted_words);
1007 	T(double_quoted_words);
1008 
1009 	T(single_quote_before_word);
1010 	T(double_quote_before_word);
1011 	T(single_quote_within_word);
1012 	T(double_quote_within_word);
1013 	T(single_quote_after_word);
1014 	T(double_quote_after_word);
1015 
1016 	T(escaped_single_quote);
1017 	T(escaped_double_quote);
1018 	T(escaped_whitespace_within_single_quotes);
1019 	T(escaped_whitespace_within_double_quotes);
1020 	T(escaped_letter_within_single_quotes);
1021 	T(escaped_letter_within_double_quotes);
1022 	T(escaped_escape_within_single_quotes);
1023 	T(escaped_escape_within_double_quotes);
1024 	T(escaped_single_quote_within_single_quotes);
1025 	T(escaped_double_quote_within_single_quotes);
1026 	T(escaped_single_quote_within_double_quotes);
1027 	T(escaped_double_quote_within_double_quotes);
1028 
1029 	T(line_continuation_within_whitespace);
1030 	T(line_continuation_before_whitespace);
1031 	T(line_continuation_after_whitespace);
1032 	T(line_continuation_within_word);
1033 
1034 	return (0);
1035 }
1036 
1037 int
1038 main(int argc, char *argv[])
1039 {
1040 
1041 	t_main(t_prepare, NULL, argc, argv);
1042 }
1043