Home | History | Annotate | Line # | Download | only in t
t_openpam_readword.c revision 1.1.1.1
      1 /*	$NetBSD: t_openpam_readword.c,v 1.1.1.1 2013/04/06 01:23:33 christos Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 2012 Dag-Erling Smrgrav
      5  * All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer
     12  *    in this position and unchanged.
     13  * 2. Redistributions in binary form must reproduce the above copyright
     14  *    notice, this list of conditions and the following disclaimer in the
     15  *    documentation and/or other materials provided with the distribution.
     16  * 3. The name of the author may not be used to endorse or promote
     17  *    products derived from this software without specific prior written
     18  *    permission.
     19  *
     20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
     21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     30  * SUCH DAMAGE.
     31  *
     32  * Id: t_openpam_readword.c 584 2012-04-07 22:47:16Z des
     33  */
     34 
     35 #ifdef HAVE_CONFIG_H
     36 # include "config.h"
     37 #endif
     38 
     39 #include <err.h>
     40 #include <errno.h>
     41 #include <fcntl.h>
     42 #include <stdio.h>
     43 #include <stdlib.h>
     44 #include <string.h>
     45 #include <unistd.h>
     46 
     47 #include <security/pam_appl.h>
     48 #include <security/openpam.h>
     49 
     50 #include "t.h"
     51 
     52 static char filename[1024];
     53 static FILE *f;
     54 
     55 /*
     56  * Open the temp file and immediately unlink it so it doesn't leak in case
     57  * of premature exit.
     58  */
     59 static void
     60 orw_open(void)
     61 {
     62 	int fd;
     63 
     64 	if ((fd = open(filename, O_RDWR|O_CREAT|O_TRUNC, 0600)) < 0)
     65 		err(1, "%s(): %s", __func__, filename);
     66 	if ((f = fdopen(fd, "r+")) == NULL)
     67 		err(1, "%s(): %s", __func__, filename);
     68 	if (unlink(filename) < 0)
     69 		err(1, "%s(): %s", __func__, filename);
     70 }
     71 
     72 /*
     73  * Write text to the temp file.
     74  */
     75 static void
     76 orw_output(const char *fmt, ...)
     77 {
     78 	va_list ap;
     79 
     80 	va_start(ap, fmt);
     81 	vfprintf(f, fmt, ap);
     82 	va_end(ap);
     83 	if (ferror(f))
     84 		err(1, "%s", filename);
     85 }
     86 
     87 /*
     88  * Rewind the temp file.
     89  */
     90 static void
     91 orw_rewind(void)
     92 {
     93 
     94 	errno = 0;
     95 	rewind(f);
     96 	if (errno != 0)
     97 		err(1, "%s(): %s", __func__, filename);
     98 }
     99 
    100 /*
    101  * Read a word from the temp file and verify that the result matches our
    102  * expectations: whether a word was read at all, how many lines were read
    103  * (in case of quoted or escaped newlines), whether we reached the end of
    104  * the file and whether we reached the end of the line.
    105  */
    106 static int
    107 orw_expect(const char *expected, int lines, int eof, int eol)
    108 {
    109 	int ch, lineno = 0;
    110 	char *got;
    111 	size_t len;
    112 
    113 	got = openpam_readword(f, &lineno, &len);
    114 	if (ferror(f))
    115 		err(1, "%s(): %s", __func__, filename);
    116 	if (expected != NULL && got == NULL) {
    117 		t_verbose("expected <<%s>>, got nothing\n", expected);
    118 		return (0);
    119 	}
    120 	if (expected == NULL && got != NULL) {
    121 		t_verbose("expected nothing, got <<%s>>\n", got);
    122 		return (0);
    123 	}
    124 	if (expected != NULL && got != NULL && strcmp(expected, got) != 0) {
    125 		t_verbose("expected <<%s>>, got <<%s>>\n", expected, got);
    126 		return (0);
    127 	}
    128 	if (lineno != lines) {
    129 		t_verbose("expected to advance %d lines, advanced %d lines\n",
    130 		    lines, lineno);
    131 		return (0);
    132 	}
    133 	if (eof && !feof(f)) {
    134 		t_verbose("expected EOF, but didn't get it\n");
    135 		return (0);
    136 	}
    137 	if (!eof && feof(f)) {
    138 		t_verbose("didn't expect EOF, but got it anyway\n");
    139 		return (0);
    140 	}
    141 	ch = fgetc(f);
    142 	if (ferror(f))
    143 		err(1, "%s(): %s", __func__, filename);
    144 	if (eol && ch != '\n') {
    145 		t_verbose("expected EOL, but didn't get it\n");
    146 		return (0);
    147 	}
    148 	if (!eol && ch == '\n') {
    149 		t_verbose("didn't expect EOL, but got it anyway\n");
    150 		return (0);
    151 	}
    152 	if (ch != EOF)
    153 		ungetc(ch, f);
    154 	return (1);
    155 }
    156 
    157 /*
    158  * Close the temp file.
    159  */
    160 void
    161 orw_close(void)
    162 {
    163 
    164 	if (fclose(f) != 0)
    165 		err(1, "%s(): %s", __func__, filename);
    166 	f = NULL;
    167 }
    168 
    169 
    170 /***************************************************************************
    172  * Lines without words
    173  */
    174 
    175 T_FUNC(empty_input, "empty input")
    176 {
    177 	int ret;
    178 
    179 	orw_open();
    180 	ret = orw_expect(NULL, 0 /*lines*/, 1 /*eof*/, 0 /*eol*/);
    181 	orw_close();
    182 	return (ret);
    183 }
    184 
    185 T_FUNC(empty_line, "empty line")
    186 {
    187 	int ret;
    188 
    189 	orw_open();
    190 	orw_output("\n");
    191 	orw_rewind();
    192 	ret = orw_expect(NULL, 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
    193 	orw_close();
    194 	return (ret);
    195 }
    196 
    197 T_FUNC(unterminated_line, "unterminated line")
    198 {
    199 	int ret;
    200 
    201 	orw_open();
    202 	orw_output(" ");
    203 	orw_rewind();
    204 	ret = orw_expect(NULL, 0 /*lines*/, 1 /*eof*/, 0 /*eol*/);
    205 	orw_close();
    206 	return (ret);
    207 }
    208 
    209 T_FUNC(single_whitespace, "single whitespace")
    210 {
    211 	int ret;
    212 
    213 	orw_open();
    214 	orw_output(" \n");
    215 	orw_rewind();
    216 	ret = orw_expect(NULL, 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
    217 	orw_close();
    218 	return (ret);
    219 }
    220 
    221 T_FUNC(multiple_whitespace, "multiple whitespace")
    222 {
    223 	int ret;
    224 
    225 	orw_open();
    226 	orw_output(" \t\r\n");
    227 	orw_rewind();
    228 	ret = orw_expect(NULL, 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
    229 	orw_close();
    230 	return (ret);
    231 }
    232 
    233 T_FUNC(comment, "comment")
    234 {
    235 	int ret;
    236 
    237 	orw_open();
    238 	orw_output("# comment\n");
    239 	orw_rewind();
    240 	ret = orw_expect(NULL, 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
    241 	orw_close();
    242 	return (ret);
    243 }
    244 
    245 T_FUNC(whitespace_before_comment, "whitespace before comment")
    246 {
    247 	int ret;
    248 
    249 	orw_open();
    250 	orw_output(" # comment\n");
    251 	orw_rewind();
    252 	ret = orw_expect(NULL, 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
    253 	orw_close();
    254 	return (ret);
    255 }
    256 
    257 
    258 /***************************************************************************
    260  * Simple cases - no quotes or escapes
    261  */
    262 
    263 T_FUNC(single_word, "single word")
    264 {
    265 	const char *word = "hello";
    266 	int ret;
    267 
    268 	orw_open();
    269 	orw_output("%s\n", word);
    270 	orw_rewind();
    271 	ret = orw_expect(word, 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
    272 	orw_close();
    273 	return (ret);
    274 }
    275 
    276 T_FUNC(single_whitespace_before_word, "single whitespace before word")
    277 {
    278 	const char *word = "hello";
    279 	int ret;
    280 
    281 	orw_open();
    282 	orw_output(" %s\n", word);
    283 	orw_rewind();
    284 	ret = orw_expect(word, 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
    285 	orw_close();
    286 	return (ret);
    287 }
    288 
    289 T_FUNC(double_whitespace_before_word, "double whitespace before word")
    290 {
    291 	const char *word = "hello";
    292 	int ret;
    293 
    294 	orw_open();
    295 	orw_output("  %s\n", word);
    296 	orw_rewind();
    297 	ret = orw_expect(word, 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
    298 	orw_close();
    299 	return (ret);
    300 }
    301 
    302 T_FUNC(single_whitespace_after_word, "single whitespace after word")
    303 {
    304 	const char *word = "hello";
    305 	int ret;
    306 
    307 	orw_open();
    308 	orw_output("%s \n", word);
    309 	orw_rewind();
    310 	ret = orw_expect(word, 0 /*lines*/, 0 /*eof*/, 0 /*eol*/);
    311 	orw_close();
    312 	return (ret);
    313 }
    314 
    315 T_FUNC(double_whitespace_after_word, "double whitespace after word")
    316 {
    317 	const char *word = "hello";
    318 	int ret;
    319 
    320 	orw_open();
    321 	orw_output("%s  \n", word);
    322 	orw_rewind();
    323 	ret = orw_expect(word, 0 /*lines*/, 0 /*eof*/, 0 /*eol*/);
    324 	orw_close();
    325 	return (ret);
    326 }
    327 
    328 T_FUNC(comment_after_word, "comment after word")
    329 {
    330 	const char *word = "hello";
    331 	int ret;
    332 
    333 	orw_open();
    334 	orw_output("%s # comment\n", word);
    335 	orw_rewind();
    336 	ret = orw_expect(word, 0 /*lines*/, 0 /*eof*/, 0 /*eol*/) &&
    337 	    orw_expect(NULL, 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
    338 	orw_close();
    339 	return (ret);
    340 }
    341 
    342 T_FUNC(word_containing_hash, "word containing hash")
    343 {
    344 	const char *word = "hello#world";
    345 	int ret;
    346 
    347 	orw_open();
    348 	orw_output("%s\n", word);
    349 	orw_rewind();
    350 	ret = orw_expect(word, 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
    351 	orw_close();
    352 	return (ret);
    353 }
    354 
    355 T_FUNC(two_words, "two words")
    356 {
    357 	const char *word[] = { "hello", "world" };
    358 	int ret;
    359 
    360 	orw_open();
    361 	orw_output("%s %s\n", word[0], word[1]);
    362 	orw_rewind();
    363 	ret = orw_expect(word[0], 0 /*lines*/, 0 /*eof*/, 0 /*eol*/) &&
    364 	    orw_expect(word[1], 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
    365 	orw_close();
    366 	return (ret);
    367 }
    368 
    369 
    370 /***************************************************************************
    372  * Escapes
    373  */
    374 
    375 T_FUNC(naked_escape, "naked escape")
    376 {
    377 	int ret;
    378 
    379 	orw_open();
    380 	orw_output("\\");
    381 	orw_rewind();
    382 	ret = orw_expect(NULL, 0 /*lines*/, 1 /*eof*/, 0 /*eol*/);
    383 	orw_close();
    384 	return (ret);
    385 }
    386 
    387 T_FUNC(escaped_escape, "escaped escape")
    388 {
    389 	int ret;
    390 
    391 	orw_open();
    392 	orw_output("\\\\\n");
    393 	orw_rewind();
    394 	ret = orw_expect("\\", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
    395 	orw_close();
    396 	return (ret);
    397 }
    398 
    399 T_FUNC(escaped_whitespace, "escaped whitespace")
    400 {
    401 	int ret;
    402 
    403 	orw_open();
    404 	orw_output("\\  \\\t \\\r \\\n\n");
    405 	orw_rewind();
    406 	ret = orw_expect(" ", 0 /*lines*/, 0 /*eof*/, 0 /*eol*/) &&
    407 	    orw_expect("\t", 0 /*lines*/, 0 /*eof*/, 0 /*eol*/) &&
    408 	    orw_expect("\r", 0 /*lines*/, 0 /*eof*/, 0 /*eol*/) &&
    409 	    /* this last one is a line continuation */
    410 	    orw_expect(NULL, 1 /*lines*/, 0 /*eof*/, 1 /*eol*/);
    411 	orw_close();
    412 	return (ret);
    413 }
    414 
    415 T_FUNC(escaped_newline_before_word, "escaped newline before word")
    416 {
    417 	int ret;
    418 
    419 	orw_open();
    420 	orw_output("\\\nhello world\n");
    421 	orw_rewind();
    422 	ret = orw_expect("hello", 1 /*lines*/, 0 /*eof*/, 0 /*eol*/);
    423 	orw_close();
    424 	return (ret);
    425 }
    426 
    427 T_FUNC(escaped_newline_within_word, "escaped newline within word")
    428 {
    429 	int ret;
    430 
    431 	orw_open();
    432 	orw_output("hello\\\nworld\n");
    433 	orw_rewind();
    434 	ret = orw_expect("helloworld", 1 /*lines*/, 0 /*eof*/, 1 /*eol*/);
    435 	orw_close();
    436 	return (ret);
    437 }
    438 
    439 T_FUNC(escaped_newline_after_word, "escaped newline after word")
    440 {
    441 	int ret;
    442 
    443 	orw_open();
    444 	orw_output("hello\\\n world\n");
    445 	orw_rewind();
    446 	ret = orw_expect("hello", 1 /*lines*/, 0 /*eof*/, 0 /*eol*/);
    447 	orw_close();
    448 	return (ret);
    449 }
    450 
    451 T_FUNC(escaped_letter, "escaped letter")
    452 {
    453 	int ret;
    454 
    455 	orw_open();
    456 	orw_output("\\z\n");
    457 	orw_rewind();
    458 	ret = orw_expect("z", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
    459 	orw_close();
    460 	return (ret);
    461 }
    462 
    463 
    464 /***************************************************************************
    466  * Quotes
    467  */
    468 
    469 T_FUNC(naked_single_quote, "naked single quote")
    470 {
    471 	int ret;
    472 
    473 	orw_open();
    474 	orw_output("'");
    475 	orw_rewind();
    476 	ret = orw_expect(NULL, 0 /*lines*/, 1 /*eof*/, 0 /*eol*/);
    477 	orw_close();
    478 	return (ret);
    479 }
    480 
    481 T_FUNC(naked_double_quote, "naked double quote")
    482 {
    483 	int ret;
    484 
    485 	orw_open();
    486 	orw_output("\"");
    487 	orw_rewind();
    488 	ret = orw_expect(NULL, 0 /*lines*/, 1 /*eof*/, 0 /*eol*/);
    489 	orw_close();
    490 	return (ret);
    491 }
    492 
    493 T_FUNC(empty_single_quotes, "empty single quotes")
    494 {
    495 	int ret;
    496 
    497 	orw_open();
    498 	orw_output("''\n");
    499 	orw_rewind();
    500 	ret = orw_expect("", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
    501 	orw_close();
    502 	return (ret);
    503 }
    504 
    505 T_FUNC(empty_double_quotes, "empty double quotes")
    506 {
    507 	int ret;
    508 
    509 	orw_open();
    510 	orw_output("\"\"\n");
    511 	orw_rewind();
    512 	ret = orw_expect("", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
    513 	orw_close();
    514 	return (ret);
    515 }
    516 
    517 T_FUNC(single_quotes_within_double_quotes, "single quotes within double quotes")
    518 {
    519 	int ret;
    520 
    521 	orw_open();
    522 	orw_output("\"' '\"\n");
    523 	orw_rewind();
    524 	ret = orw_expect("' '", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
    525 	orw_close();
    526 	return (ret);
    527 }
    528 
    529 T_FUNC(double_quotes_within_single_quotes, "double quotes within single quotes")
    530 {
    531 	int ret;
    532 
    533 	orw_open();
    534 	orw_output("'\" \"'\n");
    535 	orw_rewind();
    536 	ret = orw_expect("\" \"", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
    537 	orw_close();
    538 	return (ret);
    539 }
    540 
    541 T_FUNC(single_quoted_whitespace, "single-quoted whitespace")
    542 {
    543 	int ret;
    544 
    545 	orw_open();
    546 	orw_output("' ' '\t' '\r' '\n'\n");
    547 	orw_rewind();
    548 	ret = orw_expect(" ", 0 /*lines*/, 0 /*eof*/, 0 /*eol*/) &&
    549 	    orw_expect("\t", 0 /*lines*/, 0 /*eof*/, 0 /*eol*/) &&
    550 	    orw_expect("\r", 0 /*lines*/, 0 /*eof*/, 0 /*eol*/) &&
    551 	    orw_expect("\n", 1 /*lines*/, 0 /*eof*/, 1 /*eol*/);
    552 	orw_close();
    553 	return (ret);
    554 }
    555 
    556 T_FUNC(double_quoted_whitespace, "double-quoted whitespace")
    557 {
    558 	int ret;
    559 
    560 	orw_open();
    561 	orw_output("\" \" \"\t\" \"\r\" \"\n\"\n");
    562 	orw_rewind();
    563 	ret = orw_expect(" ", 0 /*lines*/, 0 /*eof*/, 0 /*eol*/) &&
    564 	    orw_expect("\t", 0 /*lines*/, 0 /*eof*/, 0 /*eol*/) &&
    565 	    orw_expect("\r", 0 /*lines*/, 0 /*eof*/, 0 /*eol*/) &&
    566 	    orw_expect("\n", 1 /*lines*/, 0 /*eof*/, 1 /*eol*/);
    567 	orw_close();
    568 	return (ret);
    569 }
    570 
    571 T_FUNC(single_quoted_words, "single-quoted words")
    572 {
    573 	int ret;
    574 
    575 	orw_open();
    576 	orw_output("'hello world'\n");
    577 	orw_rewind();
    578 	ret = orw_expect("hello world", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
    579 	orw_close();
    580 	return (ret);
    581 }
    582 
    583 T_FUNC(double_quoted_words, "double-quoted words")
    584 {
    585 	int ret;
    586 
    587 	orw_open();
    588 	orw_output("\"hello world\"\n");
    589 	orw_rewind();
    590 	ret = orw_expect("hello world", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
    591 	orw_close();
    592 	return (ret);
    593 }
    594 
    595 
    596 /***************************************************************************
    598  * Combinations of escape and quotes
    599  */
    600 
    601 T_FUNC(escaped_single_quote,
    602     "escaped single quote")
    603 {
    604 	int ret;
    605 
    606 	orw_open();
    607 	orw_output("\\'\n");
    608 	orw_rewind();
    609 	ret = orw_expect("'", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
    610 	orw_close();
    611 	return (ret);
    612 }
    613 
    614 T_FUNC(escaped_double_quote,
    615     "escaped double quote")
    616 {
    617 	int ret;
    618 
    619 	orw_open();
    620 	orw_output("\\\"\n");
    621 	orw_rewind();
    622 	ret = orw_expect("\"", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
    623 	orw_close();
    624 	return (ret);
    625 }
    626 
    627 T_FUNC(escaped_whitespace_within_single_quotes,
    628     "escaped whitespace within single quotes")
    629 {
    630 	int ret;
    631 
    632 	orw_open();
    633 	orw_output("'\\ ' '\\\t' '\\\r' '\\\n'\n");
    634 	orw_rewind();
    635 	ret = orw_expect("\\ ", 0 /*lines*/, 0 /*eof*/, 0 /*eol*/) &&
    636 	    orw_expect("\\\t", 0 /*lines*/, 0 /*eof*/, 0 /*eol*/) &&
    637 	    orw_expect("\\\r", 0 /*lines*/, 0 /*eof*/, 0 /*eol*/) &&
    638 	    orw_expect("\\\n", 1 /*lines*/, 0 /*eof*/, 1 /*eol*/);
    639 	orw_close();
    640 	return (ret);
    641 }
    642 
    643 T_FUNC(escaped_whitespace_within_double_quotes,
    644     "escaped whitespace within double quotes")
    645 {
    646 	int ret;
    647 
    648 	orw_open();
    649 	orw_output("\"\\ \" \"\\\t\" \"\\\r\" \"\\\n\"\n");
    650 	orw_rewind();
    651 	ret = orw_expect("\\ ", 0 /*lines*/, 0 /*eof*/, 0 /*eol*/) &&
    652 	    orw_expect("\\\t", 0 /*lines*/, 0 /*eof*/, 0 /*eol*/) &&
    653 	    orw_expect("\\\r", 0 /*lines*/, 0 /*eof*/, 0 /*eol*/) &&
    654 	    /* this last one is a line continuation */
    655 	    orw_expect("", 1 /*lines*/, 0 /*eof*/, 1 /*eol*/);
    656 	orw_close();
    657 	return (ret);
    658 }
    659 
    660 T_FUNC(escaped_letter_within_single_quotes,
    661     "escaped letter within single quotes")
    662 {
    663 	int ret;
    664 
    665 	orw_open();
    666 	orw_output("'\\z'\n");
    667 	orw_rewind();
    668 	ret = orw_expect("\\z", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
    669 	orw_close();
    670 	return (ret);
    671 }
    672 
    673 T_FUNC(escaped_letter_within_double_quotes,
    674     "escaped letter within double quotes")
    675 {
    676 	int ret;
    677 
    678 	orw_open();
    679 	orw_output("\"\\z\"\n");
    680 	orw_rewind();
    681 	ret = orw_expect("\\z", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
    682 	orw_close();
    683 	return (ret);
    684 }
    685 
    686 T_FUNC(escaped_escape_within_single_quotes,
    687     "escaped escape within single quotes")
    688 {
    689 	int ret;
    690 
    691 	orw_open();
    692 	orw_output("'\\\\'\n");
    693 	orw_rewind();
    694 	ret = orw_expect("\\\\", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
    695 	orw_close();
    696 	return (ret);
    697 }
    698 
    699 T_FUNC(escaped_escape_within_double_quotes,
    700     "escaped escape within double quotes")
    701 {
    702 	int ret;
    703 
    704 	orw_open();
    705 	orw_output("\"\\\\\"\n");
    706 	orw_rewind();
    707 	ret = orw_expect("\\", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
    708 	orw_close();
    709 	return (ret);
    710 }
    711 
    712 T_FUNC(escaped_single_quote_within_single_quotes,
    713     "escaped single quote within single quotes")
    714 {
    715 	int ret;
    716 
    717 	orw_open();
    718 	orw_output("'\\''\n");
    719 	orw_rewind();
    720 	ret = orw_expect(NULL, 1 /*lines*/, 1 /*eof*/, 0 /*eol*/);
    721 	orw_close();
    722 	return (ret);
    723 }
    724 
    725 T_FUNC(escaped_double_quote_within_single_quotes,
    726     "escaped double quote within single quotes")
    727 {
    728 	int ret;
    729 
    730 	orw_open();
    731 	orw_output("'\\\"'\n");
    732 	orw_rewind();
    733 	ret = orw_expect("\\\"", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
    734 	orw_close();
    735 	return (ret);
    736 }
    737 
    738 T_FUNC(escaped_single_quote_within_double_quotes,
    739     "escaped single quote within double quotes")
    740 {
    741 	int ret;
    742 
    743 	orw_open();
    744 	orw_output("\"\\'\"\n");
    745 	orw_rewind();
    746 	ret = orw_expect("\\'", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
    747 	orw_close();
    748 	return (ret);
    749 }
    750 
    751 T_FUNC(escaped_double_quote_within_double_quotes,
    752     "escaped double quote within double quotes")
    753 {
    754 	int ret;
    755 
    756 	orw_open();
    757 	orw_output("\"\\\"\"\n");
    758 	orw_rewind();
    759 	ret = orw_expect("\"", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
    760 	orw_close();
    761 	return (ret);
    762 }
    763 
    764 
    765 /***************************************************************************
    767  * Boilerplate
    768  */
    769 
    770 const struct t_test *t_plan[] = {
    771 	T(empty_input),
    772 	T(empty_line),
    773 	T(single_whitespace),
    774 	T(multiple_whitespace),
    775 	T(comment),
    776 	T(whitespace_before_comment),
    777 
    778 	T(single_word),
    779 	T(single_whitespace_before_word),
    780 	T(double_whitespace_before_word),
    781 	T(single_whitespace_after_word),
    782 	T(double_whitespace_after_word),
    783 	T(comment_after_word),
    784 	T(word_containing_hash),
    785 	T(two_words),
    786 
    787 	T(naked_escape),
    788 	T(escaped_escape),
    789 	T(escaped_whitespace),
    790 	T(escaped_newline_before_word),
    791 	T(escaped_newline_within_word),
    792 	T(escaped_newline_after_word),
    793 	T(escaped_letter),
    794 
    795 	T(naked_single_quote),
    796 	T(naked_double_quote),
    797 	T(empty_single_quotes),
    798 	T(empty_double_quotes),
    799 	T(single_quotes_within_double_quotes),
    800 	T(double_quotes_within_single_quotes),
    801 	T(single_quoted_whitespace),
    802 	T(double_quoted_whitespace),
    803 	T(single_quoted_words),
    804 	T(double_quoted_words),
    805 
    806 	T(escaped_single_quote),
    807 	T(escaped_double_quote),
    808 	T(escaped_whitespace_within_single_quotes),
    809 	T(escaped_whitespace_within_double_quotes),
    810 	T(escaped_letter_within_single_quotes),
    811 	T(escaped_letter_within_double_quotes),
    812 	T(escaped_escape_within_single_quotes),
    813 	T(escaped_escape_within_double_quotes),
    814 	T(escaped_single_quote_within_single_quotes),
    815 	T(escaped_double_quote_within_single_quotes),
    816 	T(escaped_single_quote_within_double_quotes),
    817 	T(escaped_double_quote_within_double_quotes),
    818 
    819 	NULL
    820 };
    821 
    822 const struct t_test **
    823 t_prepare(int argc, char *argv[])
    824 {
    825 
    826 	(void)argc;
    827 	(void)argv;
    828 	snprintf(filename, sizeof filename, "%s.%d.tmp", t_progname, getpid());
    829 	if (filename == NULL)
    830 		err(1, "asprintf()");
    831 	return (t_plan);
    832 }
    833 
    834 void
    835 t_cleanup(void)
    836 {
    837 }
    838