[rtems commit] termios: Ignore carriage return early if desired

Sebastian Huber sebh at rtems.org
Tue Feb 28 08:43:15 UTC 2017


Module:    rtems
Branch:    master
Commit:    9f69ac2a9dead44b62842081c8357b4dcd23dcaa
Changeset: http://git.rtems.org/rtems/commit/?id=9f69ac2a9dead44b62842081c8357b4dcd23dcaa

Author:    Sebastian Huber <sebastian.huber at embedded-brains.de>
Date:      Thu Feb 23 10:35:16 2017 +0100

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(-)

diff --git a/cpukit/libcsupport/src/termios.c b/cpukit/libcsupport/src/termios.c
index f88494f..c1d6cd5 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 9ff4394..286875d 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 8e74b3e..4e82caf 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 0000000..18714de
--- /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 at .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 0000000..6e651bf
--- /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
+ *  <rtems at embedded-brains.de>
+ *
+ * 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 <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+#include <termios.h>
+#include <unistd.h>
+
+#include <rtems/termiostypes.h>
+
+#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 <rtems/confdefs.h>
diff --git a/testsuites/libtests/termios09/termios09.doc b/testsuites/libtests/termios09/termios09.doc
new file mode 100644
index 0000000..d2c0be4
--- /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 0000000..5e0d17d
--- /dev/null
+++ b/testsuites/libtests/termios09/termios09.scn
@@ -0,0 +1,2 @@
+*** BEGIN OF TEST TERMIOS 9 ***
+*** END OF TEST TERMIOS 9 ***




More information about the vc mailing list