From 9f69ac2a9dead44b62842081c8357b4dcd23dcaa Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Thu, 23 Feb 2017 10:35:16 +0100 Subject: termios: Ignore carriage return early if desired In case carriage return characters should be ignored in the input (IGNCR), then drop them early before they reach the raw input buffer. This makes it easier to calculate the content size of the raw input buffer. --- cpukit/libcsupport/src/termios.c | 25 ++- testsuites/libtests/Makefile.am | 1 + testsuites/libtests/configure.ac | 1 + testsuites/libtests/termios09/Makefile.am | 19 ++ testsuites/libtests/termios09/init.c | 269 ++++++++++++++++++++++++++++ testsuites/libtests/termios09/termios09.doc | 11 ++ testsuites/libtests/termios09/termios09.scn | 2 + 7 files changed, 322 insertions(+), 6 deletions(-) create mode 100644 testsuites/libtests/termios09/Makefile.am create mode 100644 testsuites/libtests/termios09/init.c create mode 100644 testsuites/libtests/termios09/termios09.doc create mode 100644 testsuites/libtests/termios09/termios09.scn diff --git a/cpukit/libcsupport/src/termios.c b/cpukit/libcsupport/src/termios.c index f88494f15d..c1d6cd5297 100644 --- a/cpukit/libcsupport/src/termios.c +++ b/cpukit/libcsupport/src/termios.c @@ -1295,12 +1295,11 @@ iproc (unsigned char c, struct rtems_termios_tty *tty) c = tolower (c); if (c == '\r') { - if (tty->termios.c_iflag & IGNCR) - return 0; if (tty->termios.c_iflag & ICRNL) c = '\n'; - } else if ((c == '\n') && (tty->termios.c_iflag & INLCR)) { - c = '\r'; + } else if (c == '\n') { + if (tty->termios.c_iflag & INLCR) + c = '\r'; } if ((c != '\0') && (tty->termios.c_lflag & ICANON)) { @@ -1366,6 +1365,16 @@ siproc (unsigned char c, struct rtems_termios_tty *tty) return i; } +static int +siprocPoll (unsigned char c, rtems_termios_tty *tty) +{ + if (c == '\r' && (tty->termios.c_iflag & IGNCR) != 0) { + return 0; + } + + return siproc (c, tty); +} + /* * Fill the input buffer by polling the device */ @@ -1380,7 +1389,7 @@ fillBufferPoll (struct rtems_termios_tty *tty) if (n < 0) { rtems_task_wake_after (1); } else { - if (siproc (n, tty)) + if (siprocPoll (n, tty)) break; } } @@ -1408,7 +1417,7 @@ fillBufferPoll (struct rtems_termios_tty *tty) } rtems_task_wake_after (1); } else { - siproc (n, tty); + siprocPoll (n, tty); if (tty->ccount >= tty->termios.c_cc[VMIN]) break; if (tty->termios.c_cc[VMIN] && tty->termios.c_cc[VTIME]) @@ -1637,6 +1646,10 @@ rtems_termios_enqueue_raw_characters (void *ttyp, const char *buf, int len) unsigned int oldTail; unsigned int newTail; + if (c == '\r' && (tty->termios.c_iflag & IGNCR) != 0) { + continue; + } + rtems_termios_device_lock_acquire (ctx, &lock_context); head = tty->rawInBuf.Head; diff --git a/testsuites/libtests/Makefile.am b/testsuites/libtests/Makefile.am index 9ff4394f9e..286875d143 100644 --- a/testsuites/libtests/Makefile.am +++ b/testsuites/libtests/Makefile.am @@ -1,6 +1,7 @@ ACLOCAL_AMFLAGS = -I ../aclocal _SUBDIRS = POSIX +_SUBDIRS += termios09 _SUBDIRS += libfdt01 _SUBDIRS += defaultconfig01 _SUBDIRS += pwdgrp02 diff --git a/testsuites/libtests/configure.ac b/testsuites/libtests/configure.ac index 8e74b3e979..4e82caff18 100644 --- a/testsuites/libtests/configure.ac +++ b/testsuites/libtests/configure.ac @@ -172,6 +172,7 @@ termios05/Makefile termios06/Makefile termios07/Makefile termios08/Makefile +termios09/Makefile top/Makefile tztest/Makefile capture01/Makefile diff --git a/testsuites/libtests/termios09/Makefile.am b/testsuites/libtests/termios09/Makefile.am new file mode 100644 index 0000000000..18714de490 --- /dev/null +++ b/testsuites/libtests/termios09/Makefile.am @@ -0,0 +1,19 @@ +rtems_tests_PROGRAMS = termios09 +termios09_SOURCES = init.c + +dist_rtems_tests_DATA = termios09.scn termios09.doc + +include $(RTEMS_ROOT)/make/custom/@RTEMS_BSP@.cfg +include $(top_srcdir)/../automake/compile.am +include $(top_srcdir)/../automake/leaf.am + +AM_CPPFLAGS += -I$(top_srcdir)/../support/include + +LINK_OBJS = $(termios09_OBJECTS) +LINK_LIBS = $(termios09_LDLIBS) + +termios09$(EXEEXT): $(termios09_OBJECTS) $(termios09_DEPENDENCIES) + @rm -f termios09$(EXEEXT) + $(make-exe) + +include $(top_srcdir)/../automake/local.am diff --git a/testsuites/libtests/termios09/init.c b/testsuites/libtests/termios09/init.c new file mode 100644 index 0000000000..6e651bfafa --- /dev/null +++ b/testsuites/libtests/termios09/init.c @@ -0,0 +1,269 @@ +/* + * Copyright (c) 2017 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Dornierstr. 4 + * 82178 Puchheim + * Germany + * + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include + +#include + +#include "tmacros.h" + +const char rtems_test_name[] = "TERMIOS 9"; + +#define INTERRUPT 0 + +#define POLLED 1 + +#define DEVICE_COUNT 2 + +#define OUTPUT_BUFFER_SIZE 64 + +static const char * const paths[DEVICE_COUNT] = { + "/interrupt", + "/polled" +}; + +typedef struct { + rtems_termios_device_context base; + rtems_termios_tty *tty; + size_t output_pending; + size_t output_count; + char output_buf[OUTPUT_BUFFER_SIZE]; + int input_char; +} device_context; + +typedef struct { + device_context devices[DEVICE_COUNT]; + int fds[DEVICE_COUNT]; + struct termios term[DEVICE_COUNT]; +} test_context; + +static test_context test_instance = { + .devices = { + { + .base = RTEMS_TERMIOS_DEVICE_CONTEXT_INITIALIZER("Interrupt") + }, { + .base = RTEMS_TERMIOS_DEVICE_CONTEXT_INITIALIZER("Polled"), + .input_char = -1 + } + } +}; + +static bool first_open( + rtems_termios_tty *tty, + rtems_termios_device_context *base, + struct termios *term, + rtems_libio_open_close_args_t *args +) +{ + device_context *dev = (device_context *) base; + + dev->tty = tty; + + return true; +} + +static void write_polled( + rtems_termios_device_context *base, + const char *buf, + size_t len +) +{ + device_context *dev = (device_context *) base; + + rtems_test_assert(dev->output_count + len <= OUTPUT_BUFFER_SIZE); + memcpy(&dev->output_buf[dev->output_count], buf, len); + dev->output_count += len; +} + +static void write_interrupt( + rtems_termios_device_context *base, + const char *buf, + size_t len +) +{ + device_context *dev = (device_context *) base; + + write_polled(base, buf, len); + dev->output_pending = len; +} + +static int read_polled(rtems_termios_device_context *base) +{ + device_context *dev = (device_context *) base; + int c = dev->input_char; + + dev->input_char = -1; + + return c; +} + +static const rtems_termios_device_handler handlers[DEVICE_COUNT] = { + { + .first_open = first_open, + .write = write_interrupt, + .mode = TERMIOS_IRQ_DRIVEN + }, { + .first_open = first_open, + .write = write_polled, + .poll_read = read_polled, + .mode = TERMIOS_POLLED + } +}; + +static void set_term(test_context *ctx, size_t i) +{ + int rv; + + rv = tcsetattr(ctx->fds[i], TCSANOW, &ctx->term[i]); + rtems_test_assert(rv == 0); +} + +static void init_term(test_context *ctx, size_t i) +{ + int rv; + + rv = tcgetattr(ctx->fds[i], &ctx->term[i]); + rtems_test_assert(rv == 0); + + ctx->term[i].c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP + | INLCR | IGNCR | ICRNL | IXON); + ctx->term[i].c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); + ctx->term[i].c_cflag &= ~(CSIZE | PARENB); + ctx->term[i].c_cflag |= CS8; + ctx->term[i].c_oflag &= ~(OPOST | ONLRET | ONLCR | OCRNL | ONLRET + | TABDLY | OLCUC); + + ctx->term[i].c_cc[VMIN] = 0; + ctx->term[i].c_cc[VTIME] = 0; + + set_term(ctx, i); +} + +static void setup(test_context *ctx) +{ + rtems_status_code sc; + size_t i; + + rtems_termios_initialize(); + + for (i = 0; i < DEVICE_COUNT; ++i) { + sc = rtems_termios_device_install( + paths[i], + &handlers[i], + NULL, + &ctx->devices[i].base + ); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); + + ctx->fds[i] = open(paths[i], O_RDWR); + rtems_test_assert(ctx->fds[i] >= 0); + + init_term(ctx, i); + } +} + +static void input(test_context *ctx, size_t i, char c) +{ + switch (i) { + case INTERRUPT: + rtems_termios_enqueue_raw_characters(ctx->devices[i].tty, &c, sizeof(c)); + break; + case POLLED: + ctx->devices[i].input_char = (unsigned char) c; + break; + default: + rtems_test_assert(0); + } +} + +static void clear_set_iflag( + test_context *ctx, + size_t i, + tcflag_t clear, + tcflag_t set +) +{ + ctx->term[i].c_iflag &= ~clear; + ctx->term[i].c_iflag |= set; + set_term(ctx, i); +} + +static void test_igncr(test_context *ctx) +{ + size_t i; + + for (i = 0; i < DEVICE_COUNT; ++i) { + ssize_t n; + char c; + + c = 'x'; + + clear_set_iflag(ctx, i, 0, IGNCR); + + n = read(ctx->fds[i], &c, sizeof(c)); + rtems_test_assert(n == 0); + rtems_test_assert(c == 'x'); + + input(ctx, i, '\r'); + + n = read(ctx->fds[i], &c, sizeof(c)); + rtems_test_assert(n == 0); + rtems_test_assert(c == 'x'); + + clear_set_iflag(ctx, i, IGNCR, 0); + input(ctx, i, '\r'); + + n = read(ctx->fds[i], &c, sizeof(c)); + rtems_test_assert(n == 1); + rtems_test_assert(c == '\r'); + } +} + +static void Init(rtems_task_argument arg) +{ + test_context *ctx = &test_instance; + + TEST_BEGIN(); + + setup(ctx); + test_igncr(ctx); + + TEST_END(); + rtems_test_exit(0); +} + +#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER +#define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER + +#define CONFIGURE_LIBIO_MAXIMUM_FILE_DESCRIPTORS 5 + +#define CONFIGURE_MAXIMUM_TASKS 1 + +#define CONFIGURE_MAXIMUM_SEMAPHORES 7 + +#define CONFIGURE_INITIAL_EXTENSIONS RTEMS_TEST_INITIAL_EXTENSION + +#define CONFIGURE_RTEMS_INIT_TASKS_TABLE + +#define CONFIGURE_INIT + +#include diff --git a/testsuites/libtests/termios09/termios09.doc b/testsuites/libtests/termios09/termios09.doc new file mode 100644 index 0000000000..d2c0be4336 --- /dev/null +++ b/testsuites/libtests/termios09/termios09.doc @@ -0,0 +1,11 @@ +This file describes the directives and concepts tested by this test set. + +test set name: termios09 + +directives: + + - Termios + +concepts: + + - Ensure that carriage return characters are ignored if desired (IGNCR). diff --git a/testsuites/libtests/termios09/termios09.scn b/testsuites/libtests/termios09/termios09.scn new file mode 100644 index 0000000000..5e0d17d757 --- /dev/null +++ b/testsuites/libtests/termios09/termios09.scn @@ -0,0 +1,2 @@ +*** BEGIN OF TEST TERMIOS 9 *** +*** END OF TEST TERMIOS 9 *** -- cgit v1.2.3