Home | History | Annotate | Line # | Download | only in t
t_openpam_readword.c revision 1.1.1.4
      1 /*-
      2  * Copyright (c) 2012-2017 Dag-Erling Smrgrav
      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 /***************************************************************************
    116  * Lines without words
    117  */
    118 
    119 T_FUNC(empty_input, "empty input")
    120 {
    121 	struct t_file *tf;
    122 	int ret;
    123 
    124 	tf = t_fopen(NULL);
    125 	ret = orw_expect(tf, NULL, 0 /*lines*/, 1 /*eof*/, 0 /*eol*/);
    126 	t_fclose(tf);
    127 	return (ret);
    128 }
    129 
    130 T_FUNC(empty_line, "empty line")
    131 {
    132 	struct t_file *tf;
    133 	int ret;
    134 
    135 	tf = t_fopen(NULL);
    136 	t_fprintf(tf, "\n");
    137 	t_frewind(tf);
    138 	ret = orw_expect(tf, NULL, 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
    139 	t_fclose(tf);
    140 	return (ret);
    141 }
    142 
    143 T_FUNC(unterminated_line, "unterminated line")
    144 {
    145 	struct t_file *tf;
    146 	int ret;
    147 
    148 	tf = t_fopen(NULL);
    149 	t_fprintf(tf, " ");
    150 	t_frewind(tf);
    151 	ret = orw_expect(tf, NULL, 0 /*lines*/, 1 /*eof*/, 0 /*eol*/);
    152 	t_fclose(tf);
    153 	return (ret);
    154 }
    155 
    156 T_FUNC(single_whitespace, "single whitespace")
    157 {
    158 	struct t_file *tf;
    159 	int ret;
    160 
    161 	tf = t_fopen(NULL);
    162 	t_fprintf(tf, " \n");
    163 	t_frewind(tf);
    164 	ret = orw_expect(tf, NULL, 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
    165 	t_fclose(tf);
    166 	return (ret);
    167 }
    168 
    169 T_FUNC(multiple_whitespace, "multiple whitespace")
    170 {
    171 	struct t_file *tf;
    172 	int ret;
    173 
    174 	tf = t_fopen(NULL);
    175 	t_fprintf(tf, " \t\r\n");
    176 	t_frewind(tf);
    177 	ret = orw_expect(tf, NULL, 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
    178 	t_fclose(tf);
    179 	return (ret);
    180 }
    181 
    182 T_FUNC(comment, "comment")
    183 {
    184 	struct t_file *tf;
    185 	int ret;
    186 
    187 	tf = t_fopen(NULL);
    188 	t_fprintf(tf, "# comment\n");
    189 	t_frewind(tf);
    190 	ret = orw_expect(tf, NULL, 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
    191 	t_fclose(tf);
    192 	return (ret);
    193 }
    194 
    195 T_FUNC(whitespace_before_comment, "whitespace before comment")
    196 {
    197 	struct t_file *tf;
    198 	int ret;
    199 
    200 	tf = t_fopen(NULL);
    201 	t_fprintf(tf, " # comment\n");
    202 	t_frewind(tf);
    203 	ret = orw_expect(tf, NULL, 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
    204 	t_fclose(tf);
    205 	return (ret);
    206 }
    207 
    208 T_FUNC(single_quoted_comment, "single-quoted comment")
    209 {
    210 	struct t_file *tf;
    211 	int ret;
    212 
    213 	tf = t_fopen(NULL);
    214 	t_fprintf(tf, " '# comment'\n");
    215 	t_frewind(tf);
    216 	ret = orw_expect(tf, "# comment", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
    217 	t_fclose(tf);
    218 	return (ret);
    219 }
    220 
    221 T_FUNC(double_quoted_comment, "double-quoted comment")
    222 {
    223 	struct t_file *tf;
    224 	int ret;
    225 
    226 	tf = t_fopen(NULL);
    227 	t_fprintf(tf, " \"# comment\"\n");
    228 	t_frewind(tf);
    229 	ret = orw_expect(tf, "# comment", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
    230 	t_fclose(tf);
    231 	return (ret);
    232 }
    233 
    234 T_FUNC(comment_at_eof, "comment at end of file")
    235 {
    236 	struct t_file *tf;
    237 	int ret;
    238 
    239 	tf = t_fopen(NULL);
    240 	t_fprintf(tf, "# comment");
    241 	t_frewind(tf);
    242 	ret = orw_expect(tf, NULL, 0 /*lines*/, 1 /*eof*/, 0 /*eol*/);
    243 	t_fclose(tf);
    244 	return (ret);
    245 }
    246 
    247 
    248 /***************************************************************************
    250  * Simple cases - no quotes or escapes
    251  */
    252 
    253 T_FUNC(single_word, "single word")
    254 {
    255 	const char *word = "hello";
    256 	struct t_file *tf;
    257 	int ret;
    258 
    259 	tf = t_fopen(NULL);
    260 	t_fprintf(tf, "%s\n", word);
    261 	t_frewind(tf);
    262 	ret = orw_expect(tf, word, 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
    263 	t_fclose(tf);
    264 	return (ret);
    265 }
    266 
    267 T_FUNC(single_whitespace_before_word, "single whitespace before word")
    268 {
    269 	const char *word = "hello";
    270 	struct t_file *tf;
    271 	int ret;
    272 
    273 	tf = t_fopen(NULL);
    274 	t_fprintf(tf, " %s\n", word);
    275 	t_frewind(tf);
    276 	ret = orw_expect(tf, word, 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
    277 	t_fclose(tf);
    278 	return (ret);
    279 }
    280 
    281 T_FUNC(double_whitespace_before_word, "double whitespace before word")
    282 {
    283 	const char *word = "hello";
    284 	struct t_file *tf;
    285 	int ret;
    286 
    287 	tf = t_fopen(NULL);
    288 	t_fprintf(tf, "  %s\n", word);
    289 	t_frewind(tf);
    290 	ret = orw_expect(tf, word, 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
    291 	t_fclose(tf);
    292 	return (ret);
    293 }
    294 
    295 T_FUNC(single_whitespace_after_word, "single whitespace after word")
    296 {
    297 	const char *word = "hello";
    298 	struct t_file *tf;
    299 	int ret;
    300 
    301 	tf = t_fopen(NULL);
    302 	t_fprintf(tf, "%s \n", word);
    303 	t_frewind(tf);
    304 	ret = orw_expect(tf, word, 0 /*lines*/, 0 /*eof*/, 0 /*eol*/);
    305 	t_fclose(tf);
    306 	return (ret);
    307 }
    308 
    309 T_FUNC(double_whitespace_after_word, "double whitespace after word")
    310 {
    311 	const char *word = "hello";
    312 	struct t_file *tf;
    313 	int ret;
    314 
    315 	tf = t_fopen(NULL);
    316 	t_fprintf(tf, "%s  \n", word);
    317 	t_frewind(tf);
    318 	ret = orw_expect(tf, word, 0 /*lines*/, 0 /*eof*/, 0 /*eol*/);
    319 	t_fclose(tf);
    320 	return (ret);
    321 }
    322 
    323 T_FUNC(comment_after_word, "comment after word")
    324 {
    325 	const char *word = "hello";
    326 	struct t_file *tf;
    327 	int ret;
    328 
    329 	tf = t_fopen(NULL);
    330 	t_fprintf(tf, "%s # comment\n", word);
    331 	t_frewind(tf);
    332 	ret = orw_expect(tf, word, 0 /*lines*/, 0 /*eof*/, 0 /*eol*/) &&
    333 	    orw_expect(tf, NULL, 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
    334 	t_fclose(tf);
    335 	return (ret);
    336 }
    337 
    338 T_FUNC(word_containing_hash, "word containing hash")
    339 {
    340 	const char *word = "hello#world";
    341 	struct t_file *tf;
    342 	int ret;
    343 
    344 	tf = t_fopen(NULL);
    345 	t_fprintf(tf, "%s\n", word);
    346 	t_frewind(tf);
    347 	ret = orw_expect(tf, word, 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
    348 	t_fclose(tf);
    349 	return (ret);
    350 }
    351 
    352 T_FUNC(two_words, "two words")
    353 {
    354 	const char *word[] = { "hello", "world" };
    355 	struct t_file *tf;
    356 	int ret;
    357 
    358 	tf = t_fopen(NULL);
    359 	t_fprintf(tf, "%s %s\n", word[0], word[1]);
    360 	t_frewind(tf);
    361 	ret = orw_expect(tf, word[0], 0 /*lines*/, 0 /*eof*/, 0 /*eol*/) &&
    362 	    orw_expect(tf, word[1], 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
    363 	t_fclose(tf);
    364 	return (ret);
    365 }
    366 
    367 
    368 /***************************************************************************
    370  * Escapes
    371  */
    372 
    373 T_FUNC(naked_escape, "naked escape")
    374 {
    375 	struct t_file *tf;
    376 	int ret;
    377 
    378 	tf = t_fopen(NULL);
    379 	t_fprintf(tf, "\\");
    380 	t_frewind(tf);
    381 	ret = orw_expect(tf, NULL, 0 /*lines*/, 1 /*eof*/, 0 /*eol*/);
    382 	t_fclose(tf);
    383 	return (ret);
    384 }
    385 
    386 T_FUNC(escaped_escape, "escaped escape")
    387 {
    388 	struct t_file *tf;
    389 	int ret;
    390 
    391 	tf = t_fopen(NULL);
    392 	t_fprintf(tf, "\\\\\n");
    393 	t_frewind(tf);
    394 	ret = orw_expect(tf, "\\", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
    395 	t_fclose(tf);
    396 	return (ret);
    397 }
    398 
    399 T_FUNC(escaped_whitespace, "escaped whitespace")
    400 {
    401 	struct t_file *tf;
    402 	int ret;
    403 
    404 	tf = t_fopen(NULL);
    405 	t_fprintf(tf, "\\  \\\t \\\r \\\n\n");
    406 	t_frewind(tf);
    407 	ret = orw_expect(tf, " ", 0 /*lines*/, 0 /*eof*/, 0 /*eol*/) &&
    408 	    orw_expect(tf, "\t", 0 /*lines*/, 0 /*eof*/, 0 /*eol*/) &&
    409 	    orw_expect(tf, "\r", 0 /*lines*/, 0 /*eof*/, 0 /*eol*/) &&
    410 	    /* this last one is a line continuation */
    411 	    orw_expect(tf, NULL, 1 /*lines*/, 0 /*eof*/, 1 /*eol*/);
    412 	t_fclose(tf);
    413 	return (ret);
    414 }
    415 
    416 T_FUNC(escaped_newline_before_word, "escaped newline before word")
    417 {
    418 	struct t_file *tf;
    419 	int ret;
    420 
    421 	tf = t_fopen(NULL);
    422 	t_fprintf(tf, "\\\nhello world\n");
    423 	t_frewind(tf);
    424 	ret = orw_expect(tf, "hello", 1 /*lines*/, 0 /*eof*/, 0 /*eol*/);
    425 	t_fclose(tf);
    426 	return (ret);
    427 }
    428 
    429 T_FUNC(escaped_newline_within_word, "escaped newline within word")
    430 {
    431 	struct t_file *tf;
    432 	int ret;
    433 
    434 	tf = t_fopen(NULL);
    435 	t_fprintf(tf, "hello\\\nworld\n");
    436 	t_frewind(tf);
    437 	ret = orw_expect(tf, "helloworld", 1 /*lines*/, 0 /*eof*/, 1 /*eol*/);
    438 	t_fclose(tf);
    439 	return (ret);
    440 }
    441 
    442 T_FUNC(escaped_newline_after_word, "escaped newline after word")
    443 {
    444 	struct t_file *tf;
    445 	int ret;
    446 
    447 	tf = t_fopen(NULL);
    448 	t_fprintf(tf, "hello\\\n world\n");
    449 	t_frewind(tf);
    450 	ret = orw_expect(tf, "hello", 1 /*lines*/, 0 /*eof*/, 0 /*eol*/);
    451 	t_fclose(tf);
    452 	return (ret);
    453 }
    454 
    455 T_FUNC(escaped_letter, "escaped letter")
    456 {
    457 	struct t_file *tf;
    458 	int ret;
    459 
    460 	tf = t_fopen(NULL);
    461 	t_fprintf(tf, "\\z\n");
    462 	t_frewind(tf);
    463 	ret = orw_expect(tf, "z", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
    464 	t_fclose(tf);
    465 	return (ret);
    466 }
    467 
    468 T_FUNC(escaped_comment, "escaped comment")
    469 {
    470 	struct t_file *tf;
    471 	int ret;
    472 
    473 	tf = t_fopen(NULL);
    474 	t_fprintf(tf, " \\# comment\n");
    475 	t_frewind(tf);
    476 	ret = orw_expect(tf, "#", 0 /*lines*/, 0 /*eof*/, 0 /*eol*/) &&
    477 	    orw_expect(tf, "comment", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
    478 	t_fclose(tf);
    479 	return (ret);
    480 }
    481 
    482 T_FUNC(escape_at_eof, "escape at end of file")
    483 {
    484 	struct t_file *tf;
    485 	int ret;
    486 
    487 	tf = t_fopen(NULL);
    488 	t_fprintf(tf, "z\\");
    489 	t_frewind(tf);
    490 	ret = orw_expect(tf, NULL, 0 /*lines*/, 1 /*eof*/, 0 /*eol*/);
    491 	t_fclose(tf);
    492 	return (ret);
    493 }
    494 
    495 
    496 /***************************************************************************
    498  * Quotes
    499  */
    500 
    501 T_FUNC(naked_single_quote, "naked single quote")
    502 {
    503 	struct t_file *tf;
    504 	int ret;
    505 
    506 	tf = t_fopen(NULL);
    507 	t_fprintf(tf, "'");
    508 	t_frewind(tf);
    509 	ret = orw_expect(tf, NULL, 0 /*lines*/, 1 /*eof*/, 0 /*eol*/);
    510 	t_fclose(tf);
    511 	return (ret);
    512 }
    513 
    514 T_FUNC(naked_double_quote, "naked double quote")
    515 {
    516 	struct t_file *tf;
    517 	int ret;
    518 
    519 	tf = t_fopen(NULL);
    520 	t_fprintf(tf, "\"");
    521 	t_frewind(tf);
    522 	ret = orw_expect(tf, NULL, 0 /*lines*/, 1 /*eof*/, 0 /*eol*/);
    523 	t_fclose(tf);
    524 	return (ret);
    525 }
    526 
    527 T_FUNC(empty_single_quotes, "empty single quotes")
    528 {
    529 	struct t_file *tf;
    530 	int ret;
    531 
    532 	tf = t_fopen(NULL);
    533 	t_fprintf(tf, "''\n");
    534 	t_frewind(tf);
    535 	ret = orw_expect(tf, "", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
    536 	t_fclose(tf);
    537 	return (ret);
    538 }
    539 
    540 T_FUNC(empty_double_quotes, "empty double quotes")
    541 {
    542 	struct t_file *tf;
    543 	int ret;
    544 
    545 	tf = t_fopen(NULL);
    546 	t_fprintf(tf, "\"\"\n");
    547 	t_frewind(tf);
    548 	ret = orw_expect(tf, "", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
    549 	t_fclose(tf);
    550 	return (ret);
    551 }
    552 
    553 T_FUNC(single_quotes_within_double_quotes, "single quotes within double quotes")
    554 {
    555 	struct t_file *tf;
    556 	int ret;
    557 
    558 	tf = t_fopen(NULL);
    559 	t_fprintf(tf, "\"' '\"\n");
    560 	t_frewind(tf);
    561 	ret = orw_expect(tf, "' '", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
    562 	t_fclose(tf);
    563 	return (ret);
    564 }
    565 
    566 T_FUNC(double_quotes_within_single_quotes, "double quotes within single quotes")
    567 {
    568 	struct t_file *tf;
    569 	int ret;
    570 
    571 	tf = t_fopen(NULL);
    572 	t_fprintf(tf, "'\" \"'\n");
    573 	t_frewind(tf);
    574 	ret = orw_expect(tf, "\" \"", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
    575 	t_fclose(tf);
    576 	return (ret);
    577 }
    578 
    579 T_FUNC(single_quoted_whitespace, "single-quoted whitespace")
    580 {
    581 	struct t_file *tf;
    582 	int ret;
    583 
    584 	tf = t_fopen(NULL);
    585 	t_fprintf(tf, "' ' '\t' '\r' '\n'\n");
    586 	t_frewind(tf);
    587 	ret = orw_expect(tf, " ", 0 /*lines*/, 0 /*eof*/, 0 /*eol*/) &&
    588 	    orw_expect(tf, "\t", 0 /*lines*/, 0 /*eof*/, 0 /*eol*/) &&
    589 	    orw_expect(tf, "\r", 0 /*lines*/, 0 /*eof*/, 0 /*eol*/) &&
    590 	    orw_expect(tf, "\n", 1 /*lines*/, 0 /*eof*/, 1 /*eol*/);
    591 	t_fclose(tf);
    592 	return (ret);
    593 }
    594 
    595 T_FUNC(double_quoted_whitespace, "double-quoted whitespace")
    596 {
    597 	struct t_file *tf;
    598 	int ret;
    599 
    600 	tf = t_fopen(NULL);
    601 	t_fprintf(tf, "\" \" \"\t\" \"\r\" \"\n\"\n");
    602 	t_frewind(tf);
    603 	ret = orw_expect(tf, " ", 0 /*lines*/, 0 /*eof*/, 0 /*eol*/) &&
    604 	    orw_expect(tf, "\t", 0 /*lines*/, 0 /*eof*/, 0 /*eol*/) &&
    605 	    orw_expect(tf, "\r", 0 /*lines*/, 0 /*eof*/, 0 /*eol*/) &&
    606 	    orw_expect(tf, "\n", 1 /*lines*/, 0 /*eof*/, 1 /*eol*/);
    607 	t_fclose(tf);
    608 	return (ret);
    609 }
    610 
    611 T_FUNC(single_quoted_words, "single-quoted words")
    612 {
    613 	struct t_file *tf;
    614 	int ret;
    615 
    616 	tf = t_fopen(NULL);
    617 	t_fprintf(tf, "'hello world'\n");
    618 	t_frewind(tf);
    619 	ret = orw_expect(tf, "hello world", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
    620 	t_fclose(tf);
    621 	return (ret);
    622 }
    623 
    624 T_FUNC(double_quoted_words, "double-quoted words")
    625 {
    626 	struct t_file *tf;
    627 	int ret;
    628 
    629 	tf = t_fopen(NULL);
    630 	t_fprintf(tf, "\"hello world\"\n");
    631 	t_frewind(tf);
    632 	ret = orw_expect(tf, "hello world", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
    633 	t_fclose(tf);
    634 	return (ret);
    635 }
    636 
    637 
    638 /***************************************************************************
    640  * Combinations of quoted and unquoted text
    641  */
    642 
    643 T_FUNC(single_quote_before_word, "single quote before word")
    644 {
    645 	struct t_file *tf;
    646 	int ret;
    647 
    648 	tf = t_fopen(NULL);
    649 	t_fprintf(tf, "'hello 'world\n");
    650 	t_frewind(tf);
    651 	ret = orw_expect(tf, "hello world", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
    652 	t_fclose(tf);
    653 	return (ret);
    654 }
    655 
    656 T_FUNC(double_quote_before_word, "double quote before word")
    657 {
    658 	struct t_file *tf;
    659 	int ret;
    660 
    661 	tf = t_fopen(NULL);
    662 	t_fprintf(tf, "\"hello \"world\n");
    663 	t_frewind(tf);
    664 	ret = orw_expect(tf, "hello world", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
    665 	t_fclose(tf);
    666 	return (ret);
    667 }
    668 
    669 T_FUNC(single_quote_within_word, "single quote within word")
    670 {
    671 	struct t_file *tf;
    672 	int ret;
    673 
    674 	tf = t_fopen(NULL);
    675 	t_fprintf(tf, "hello' 'world\n");
    676 	t_frewind(tf);
    677 	ret = orw_expect(tf, "hello world", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
    678 	t_fclose(tf);
    679 	return (ret);
    680 }
    681 
    682 T_FUNC(double_quote_within_word, "double quote within word")
    683 {
    684 	struct t_file *tf;
    685 	int ret;
    686 
    687 	tf = t_fopen(NULL);
    688 	t_fprintf(tf, "hello\" \"world\n");
    689 	t_frewind(tf);
    690 	ret = orw_expect(tf, "hello world", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
    691 	t_fclose(tf);
    692 	return (ret);
    693 }
    694 
    695 T_FUNC(single_quote_after_word, "single quote after word")
    696 {
    697 	struct t_file *tf;
    698 	int ret;
    699 
    700 	tf = t_fopen(NULL);
    701 	t_fprintf(tf, "hello' world'\n");
    702 	t_frewind(tf);
    703 	ret = orw_expect(tf, "hello world", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
    704 	t_fclose(tf);
    705 	return (ret);
    706 }
    707 
    708 T_FUNC(double_quote_after_word, "double quote after word")
    709 {
    710 	struct t_file *tf;
    711 	int ret;
    712 
    713 	tf = t_fopen(NULL);
    714 	t_fprintf(tf, "hello\" world\"\n");
    715 	t_frewind(tf);
    716 	ret = orw_expect(tf, "hello world", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
    717 	t_fclose(tf);
    718 	return (ret);
    719 }
    720 
    721 
    722 /***************************************************************************
    724  * Combinations of escape and quotes
    725  */
    726 
    727 T_FUNC(escaped_single_quote,
    728     "escaped single quote")
    729 {
    730 	struct t_file *tf;
    731 	int ret;
    732 
    733 	tf = t_fopen(NULL);
    734 	t_fprintf(tf, "\\'\n");
    735 	t_frewind(tf);
    736 	ret = orw_expect(tf, "'", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
    737 	t_fclose(tf);
    738 	return (ret);
    739 }
    740 
    741 T_FUNC(escaped_double_quote,
    742     "escaped double quote")
    743 {
    744 	struct t_file *tf;
    745 	int ret;
    746 
    747 	tf = t_fopen(NULL);
    748 	t_fprintf(tf, "\\\"\n");
    749 	t_frewind(tf);
    750 	ret = orw_expect(tf, "\"", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
    751 	t_fclose(tf);
    752 	return (ret);
    753 }
    754 
    755 T_FUNC(escaped_whitespace_within_single_quotes,
    756     "escaped whitespace within single quotes")
    757 {
    758 	struct t_file *tf;
    759 	int ret;
    760 
    761 	tf = t_fopen(NULL);
    762 	t_fprintf(tf, "'\\ ' '\\\t' '\\\r' '\\\n'\n");
    763 	t_frewind(tf);
    764 	ret = orw_expect(tf, "\\ ", 0 /*lines*/, 0 /*eof*/, 0 /*eol*/) &&
    765 	    orw_expect(tf, "\\\t", 0 /*lines*/, 0 /*eof*/, 0 /*eol*/) &&
    766 	    orw_expect(tf, "\\\r", 0 /*lines*/, 0 /*eof*/, 0 /*eol*/) &&
    767 	    orw_expect(tf, "\\\n", 1 /*lines*/, 0 /*eof*/, 1 /*eol*/);
    768 	t_fclose(tf);
    769 	return (ret);
    770 }
    771 
    772 T_FUNC(escaped_whitespace_within_double_quotes,
    773     "escaped whitespace within double quotes")
    774 {
    775 	struct t_file *tf;
    776 	int ret;
    777 
    778 	tf = t_fopen(NULL);
    779 	t_fprintf(tf, "\"\\ \" \"\\\t\" \"\\\r\" \"\\\n\"\n");
    780 	t_frewind(tf);
    781 	ret = orw_expect(tf, "\\ ", 0 /*lines*/, 0 /*eof*/, 0 /*eol*/) &&
    782 	    orw_expect(tf, "\\\t", 0 /*lines*/, 0 /*eof*/, 0 /*eol*/) &&
    783 	    orw_expect(tf, "\\\r", 0 /*lines*/, 0 /*eof*/, 0 /*eol*/) &&
    784 	    /* this last one is a line continuation */
    785 	    orw_expect(tf, "", 1 /*lines*/, 0 /*eof*/, 1 /*eol*/);
    786 	t_fclose(tf);
    787 	return (ret);
    788 }
    789 
    790 T_FUNC(escaped_letter_within_single_quotes,
    791     "escaped letter within single quotes")
    792 {
    793 	struct t_file *tf;
    794 	int ret;
    795 
    796 	tf = t_fopen(NULL);
    797 	t_fprintf(tf, "'\\z'\n");
    798 	t_frewind(tf);
    799 	ret = orw_expect(tf, "\\z", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
    800 	t_fclose(tf);
    801 	return (ret);
    802 }
    803 
    804 T_FUNC(escaped_letter_within_double_quotes,
    805     "escaped letter within double quotes")
    806 {
    807 	struct t_file *tf;
    808 	int ret;
    809 
    810 	tf = t_fopen(NULL);
    811 	t_fprintf(tf, "\"\\z\"\n");
    812 	t_frewind(tf);
    813 	ret = orw_expect(tf, "\\z", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
    814 	t_fclose(tf);
    815 	return (ret);
    816 }
    817 
    818 T_FUNC(escaped_escape_within_single_quotes,
    819     "escaped escape within single quotes")
    820 {
    821 	struct t_file *tf;
    822 	int ret;
    823 
    824 	tf = t_fopen(NULL);
    825 	t_fprintf(tf, "'\\\\'\n");
    826 	t_frewind(tf);
    827 	ret = orw_expect(tf, "\\\\", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
    828 	t_fclose(tf);
    829 	return (ret);
    830 }
    831 
    832 T_FUNC(escaped_escape_within_double_quotes,
    833     "escaped escape within double quotes")
    834 {
    835 	struct t_file *tf;
    836 	int ret;
    837 
    838 	tf = t_fopen(NULL);
    839 	t_fprintf(tf, "\"\\\\\"\n");
    840 	t_frewind(tf);
    841 	ret = orw_expect(tf, "\\", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
    842 	t_fclose(tf);
    843 	return (ret);
    844 }
    845 
    846 T_FUNC(escaped_single_quote_within_single_quotes,
    847     "escaped single quote within single quotes")
    848 {
    849 	struct t_file *tf;
    850 	int ret;
    851 
    852 	tf = t_fopen(NULL);
    853 	t_fprintf(tf, "'\\''\n");
    854 	t_frewind(tf);
    855 	ret = orw_expect(tf, NULL, 1 /*lines*/, 1 /*eof*/, 0 /*eol*/);
    856 	t_fclose(tf);
    857 	return (ret);
    858 }
    859 
    860 T_FUNC(escaped_double_quote_within_single_quotes,
    861     "escaped double quote within single quotes")
    862 {
    863 	struct t_file *tf;
    864 	int ret;
    865 
    866 	tf = t_fopen(NULL);
    867 	t_fprintf(tf, "'\\\"'\n");
    868 	t_frewind(tf);
    869 	ret = orw_expect(tf, "\\\"", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
    870 	t_fclose(tf);
    871 	return (ret);
    872 }
    873 
    874 T_FUNC(escaped_single_quote_within_double_quotes,
    875     "escaped single quote within double quotes")
    876 {
    877 	struct t_file *tf;
    878 	int ret;
    879 
    880 	tf = t_fopen(NULL);
    881 	t_fprintf(tf, "\"\\'\"\n");
    882 	t_frewind(tf);
    883 	ret = orw_expect(tf, "\\'", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
    884 	t_fclose(tf);
    885 	return (ret);
    886 }
    887 
    888 T_FUNC(escaped_double_quote_within_double_quotes,
    889     "escaped double quote within double quotes")
    890 {
    891 	struct t_file *tf;
    892 	int ret;
    893 
    894 	tf = t_fopen(NULL);
    895 	t_fprintf(tf, "\"\\\"\"\n");
    896 	t_frewind(tf);
    897 	ret = orw_expect(tf, "\"", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
    898 	t_fclose(tf);
    899 	return (ret);
    900 }
    901 
    902 
    903 /***************************************************************************
    905  * Line continuation
    906  */
    907 
    908 T_FUNC(line_continuation_within_whitespace, "line continuation within whitespace")
    909 {
    910 	struct t_file *tf;
    911 	int ret;
    912 
    913 	tf = t_fopen(NULL);
    914 	t_fprintf(tf, "hello \\\n world\n");
    915 	t_frewind(tf);
    916 	ret = orw_expect(tf, "hello", 0 /*lines*/, 0 /*eof*/, 0 /*eol*/) &&
    917 	    orw_expect(tf, "world", 1 /*lines*/, 0 /*eof*/, 1 /*eol*/);
    918 	t_fclose(tf);
    919 	return (ret);
    920 }
    921 
    922 T_FUNC(line_continuation_before_whitespace, "line continuation before whitespace")
    923 {
    924 	struct t_file *tf;
    925 	int ret;
    926 
    927 	tf = t_fopen(NULL);
    928 	t_fprintf(tf, "hello\\\n world\n");
    929 	t_frewind(tf);
    930 	ret = orw_expect(tf, "hello", 1 /*lines*/, 0 /*eof*/, 0 /*eol*/) &&
    931 	    orw_expect(tf, "world", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
    932 	t_fclose(tf);
    933 	return (ret);
    934 }
    935 
    936 T_FUNC(line_continuation_after_whitespace, "line continuation after whitespace")
    937 {
    938 	struct t_file *tf;
    939 	int ret;
    940 
    941 	tf = t_fopen(NULL);
    942 	t_fprintf(tf, "hello \\\nworld\n");
    943 	t_frewind(tf);
    944 	ret = orw_expect(tf, "hello", 0 /*lines*/, 0 /*eof*/, 0 /*eol*/) &&
    945 	    orw_expect(tf, "world", 1 /*lines*/, 0 /*eof*/, 1 /*eol*/);
    946 	t_fclose(tf);
    947 	return (ret);
    948 }
    949 
    950 T_FUNC(line_continuation_within_word, "line continuation within word")
    951 {
    952 	struct t_file *tf;
    953 	int ret;
    954 
    955 	tf = t_fopen(NULL);
    956 	t_fprintf(tf, "hello\\\nworld\n");
    957 	t_frewind(tf);
    958 	ret = orw_expect(tf, "helloworld", 1 /*lines*/, 0 /*eof*/, 1 /*eol*/);
    959 	t_fclose(tf);
    960 	return (ret);
    961 }
    962 
    963 
    964 /***************************************************************************
    966  * Boilerplate
    967  */
    968 
    969 static int
    970 t_prepare(int argc, char *argv[])
    971 {
    972 
    973 	(void)argc;
    974 	(void)argv;
    975 
    976 	T(empty_input);
    977 	T(empty_line);
    978 	T(unterminated_line);
    979 	T(single_whitespace);
    980 	T(multiple_whitespace);
    981 	T(comment);
    982 	T(whitespace_before_comment);
    983 	T(single_quoted_comment);
    984 	T(double_quoted_comment);
    985 	T(comment_at_eof);
    986 
    987 	T(single_word);
    988 	T(single_whitespace_before_word);
    989 	T(double_whitespace_before_word);
    990 	T(single_whitespace_after_word);
    991 	T(double_whitespace_after_word);
    992 	T(comment_after_word);
    993 	T(word_containing_hash);
    994 	T(two_words);
    995 
    996 	T(naked_escape);
    997 	T(escaped_escape);
    998 	T(escaped_whitespace);
    999 	T(escaped_newline_before_word);
   1000 	T(escaped_newline_within_word);
   1001 	T(escaped_newline_after_word);
   1002 	T(escaped_letter);
   1003 	T(escaped_comment);
   1004 	T(escape_at_eof);
   1005 
   1006 	T(naked_single_quote);
   1007 	T(naked_double_quote);
   1008 	T(empty_single_quotes);
   1009 	T(empty_double_quotes);
   1010 	T(single_quotes_within_double_quotes);
   1011 	T(double_quotes_within_single_quotes);
   1012 	T(single_quoted_whitespace);
   1013 	T(double_quoted_whitespace);
   1014 	T(single_quoted_words);
   1015 	T(double_quoted_words);
   1016 
   1017 	T(single_quote_before_word);
   1018 	T(double_quote_before_word);
   1019 	T(single_quote_within_word);
   1020 	T(double_quote_within_word);
   1021 	T(single_quote_after_word);
   1022 	T(double_quote_after_word);
   1023 
   1024 	T(escaped_single_quote);
   1025 	T(escaped_double_quote);
   1026 	T(escaped_whitespace_within_single_quotes);
   1027 	T(escaped_whitespace_within_double_quotes);
   1028 	T(escaped_letter_within_single_quotes);
   1029 	T(escaped_letter_within_double_quotes);
   1030 	T(escaped_escape_within_single_quotes);
   1031 	T(escaped_escape_within_double_quotes);
   1032 	T(escaped_single_quote_within_single_quotes);
   1033 	T(escaped_double_quote_within_single_quotes);
   1034 	T(escaped_single_quote_within_double_quotes);
   1035 	T(escaped_double_quote_within_double_quotes);
   1036 
   1037 	T(line_continuation_within_whitespace);
   1038 	T(line_continuation_before_whitespace);
   1039 	T(line_continuation_after_whitespace);
   1040 	T(line_continuation_within_word);
   1041 
   1042 	return (0);
   1043 }
   1044 
   1045 int
   1046 main(int argc, char *argv[])
   1047 {
   1048 
   1049 	t_main(t_prepare, NULL, argc, argv);
   1050 }
   1051