Home | History | Annotate | Download | only in posix
      1 /* echo.c - echo supporting -n and -e.
      2  *
      3  * Copyright 2007 Rob Landley <rob (at) landley.net>
      4  *
      5  * See http://opengroup.org/onlinepubs/9699919799/utilities/echo.html
      6  *
      7  * Deviations from posix: we parse command line options, as Linux has
      8  * consistently done since 1992. Posix defaults -e to on, we require -e.
      9  * We also honor -- to _stop_ option parsing (bash doesn't, we go with
     10  * consistency over compatibility here).
     11 
     12 USE_ECHO(NEWTOY(echo, "^?en", TOYFLAG_BIN))
     13 
     14 config ECHO
     15   bool "echo"
     16   default y
     17   help
     18     usage: echo [-ne] [args...]
     19 
     20     Write each argument to stdout, with one space between each, followed
     21     by a newline.
     22 
     23     -n	No trailing newline
     24     -e	Process the following escape sequences:
     25     	\\	backslash
     26     	\0NNN	octal values (1 to 3 digits)
     27     	\a	alert (beep/flash)
     28     	\b	backspace
     29     	\c	stop output here (avoids trailing newline)
     30     	\f	form feed
     31     	\n	newline
     32     	\r	carriage return
     33     	\t	horizontal tab
     34     	\v	vertical tab
     35     	\xHH	hexadecimal values (1 to 2 digits)
     36 */
     37 
     38 #define FOR_echo
     39 #include "toys.h"
     40 
     41 void echo_main(void)
     42 {
     43   int i = 0, out;
     44   char *arg, *c;
     45 
     46   for (;;) {
     47     arg = toys.optargs[i];
     48     if (!arg) break;
     49     if (i++) putchar(' ');
     50 
     51     // Should we output arg verbatim?
     52 
     53     if (!(toys.optflags & FLAG_e)) {
     54       xprintf("%s", arg);
     55       continue;
     56     }
     57 
     58     // Handle -e
     59 
     60     for (c = arg;;) {
     61       if (!(out = *(c++))) break;
     62 
     63       // handle \escapes
     64       if (out == '\\' && *c) {
     65         int slash = *(c++), n = unescape(slash);
     66 
     67         if (n) out = n;
     68         else if (slash=='c') goto done;
     69         else if (slash=='0') {
     70           out = 0;
     71           while (*c>='0' && *c<='7' && n++<3) out = (out*8)+*(c++)-'0';
     72         } else if (slash=='x') {
     73           out = 0;
     74           while (n++<2) {
     75             if (*c>='0' && *c<='9') out = (out*16)+*(c++)-'0';
     76             else {
     77               int temp = tolower(*c);
     78               if (temp>='a' && temp<='f') {
     79                 out = (out*16)+temp-'a'+10;
     80                 c++;
     81               } else break;
     82             }
     83           }
     84         // Slash in front of unknown character, print literal.
     85         } else c--;
     86       }
     87       putchar(out);
     88     }
     89   }
     90 
     91   // Output "\n" if no -n
     92   if (!(toys.optflags&FLAG_n)) putchar('\n');
     93 done:
     94   xflush();
     95 }
     96