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 */
62static int
63orw_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
118T_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
129T_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
142T_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
155T_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
168T_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
181T_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
194T_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
207T_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
220T_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
233T_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
251T_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
265T_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
279T_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
293T_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
307T_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
321T_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
336T_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
350T_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
370T_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
383T_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
396T_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
413T_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
426T_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
439T_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
452T_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
465T_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
479T_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
497T_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
510T_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
523T_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
536T_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
549T_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
562T_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
575T_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
591T_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
607T_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
620T_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
638T_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
651T_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
664T_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
677T_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
690T_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
703T_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
721T_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
735T_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
749T_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
766T_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
784T_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
798T_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
812T_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
826T_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
840T_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
854T_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
868T_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
882T_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
901T_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
915T_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
929T_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
943T_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
961static int
962t_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
1037int
1038main(int argc, char *argv[])
1039{
1040
1041	t_main(t_prepare, NULL, argc, argv);
1042}
1043