echo.c 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304
  1. /*++
  2. Copyright (c) 2013 Minoca Corp. All Rights Reserved
  3. Module Name:
  4. echo.c
  5. Abstract:
  6. This module implements the echo application.
  7. Author:
  8. Evan Green 13-Jun-2013
  9. Environment:
  10. POSIX
  11. --*/
  12. //
  13. // ------------------------------------------------------------------- Includes
  14. //
  15. #include <minoca/lib/types.h>
  16. #include <stdio.h>
  17. #include <string.h>
  18. //
  19. // ---------------------------------------------------------------- Definitions
  20. //
  21. //
  22. // ------------------------------------------------------ Data Type Definitions
  23. //
  24. //
  25. // ----------------------------------------------- Internal Function Prototypes
  26. //
  27. BOOL
  28. EchoIsStringBackslashEscaped (
  29. PSTR String
  30. );
  31. //
  32. // -------------------------------------------------------------------- Globals
  33. //
  34. //
  35. // ------------------------------------------------------------------ Functions
  36. //
  37. INT
  38. EchoMain (
  39. INT ArgumentCount,
  40. CHAR **Arguments
  41. )
  42. /*++
  43. Routine Description:
  44. This routine is the main entry point for the echo program.
  45. Arguments:
  46. ArgumentCount - Supplies the number of command line arguments the program
  47. was invoked with.
  48. Arguments - Supplies a tokenized array of command line arguments.
  49. Return Value:
  50. 0 always.
  51. --*/
  52. {
  53. PSTR Argument;
  54. ULONG ArgumentIndex;
  55. ULONG ArgumentLength;
  56. CHAR Character;
  57. ULONG CharacterIndex;
  58. CHAR DigitCount;
  59. BOOL EscapeProcessing;
  60. BOOL PrintTrailingNewline;
  61. CHAR Value;
  62. BOOL WasBackslash;
  63. EscapeProcessing = FALSE;
  64. PrintTrailingNewline = TRUE;
  65. //
  66. // Loop through processing arguments.
  67. //
  68. for (ArgumentIndex = 1; ArgumentIndex < ArgumentCount; ArgumentIndex += 1) {
  69. Argument = Arguments[ArgumentIndex];
  70. if (Argument[0] != '-') {
  71. break;
  72. }
  73. while (TRUE) {
  74. Argument += 1;
  75. if (Argument[0] == '\0') {
  76. break;
  77. } else if (Argument[0] == 'e') {
  78. EscapeProcessing = TRUE;
  79. } else if (Argument[0] == 'E') {
  80. EscapeProcessing = FALSE;
  81. } else if (Argument[0] == 'n') {
  82. PrintTrailingNewline = FALSE;
  83. } else {
  84. break;
  85. }
  86. }
  87. if (Argument[0] != '\0') {
  88. break;
  89. }
  90. }
  91. //
  92. // Echo out the remainder of the arguments.
  93. //
  94. while (ArgumentIndex < ArgumentCount) {
  95. Argument = Arguments[ArgumentIndex];
  96. ArgumentIndex += 1;
  97. //
  98. // If not processing backslashes or there are none, just print it
  99. // directly and continue.
  100. //
  101. if ((EscapeProcessing == FALSE) ||
  102. (EchoIsStringBackslashEscaped(Argument) == FALSE)) {
  103. printf("%s", Argument);
  104. //
  105. // Escape the darn thing by looping through every character in the
  106. // string.
  107. //
  108. } else {
  109. Value = 0;
  110. DigitCount = 0;
  111. WasBackslash = FALSE;
  112. ArgumentLength = strlen(Argument);
  113. for (CharacterIndex = 0;
  114. CharacterIndex < ArgumentLength;
  115. CharacterIndex += 1) {
  116. Character = Argument[CharacterIndex];
  117. //
  118. // If a \0 was detected, then this is in the process of
  119. // working through \0NNN, where NNN is one to three octal
  120. // characters.
  121. //
  122. if (DigitCount != 0) {
  123. if ((Character >= '0') && (Character <= '7')) {
  124. Value = (Value * 8) + (Character - '0');
  125. DigitCount += 1;
  126. if (DigitCount == 4) {
  127. DigitCount = 0;
  128. printf("%c", Value);
  129. }
  130. //
  131. // This was a digit that counted towards the value, so
  132. // it shouldn't be considered for further printing.
  133. //
  134. continue;
  135. //
  136. // The number ended a bit early, so print it out and
  137. // consider this character for further printing.
  138. //
  139. } else {
  140. DigitCount = 0;
  141. printf("%c", Value);
  142. }
  143. }
  144. if (WasBackslash != FALSE) {
  145. if (Character == 'a') {
  146. } else if (Character == 'b') {
  147. printf("\b");
  148. } else if (Character == 'c') {
  149. PrintTrailingNewline = FALSE;
  150. goto MainEnd;
  151. } else if (Character == 'f') {
  152. printf("\f");
  153. } else if (Character == 'n') {
  154. printf("\n");
  155. } else if (Character == 'r') {
  156. printf("\r");
  157. } else if (Character == 't') {
  158. printf("\t");
  159. } else if (Character == '\\') {
  160. printf("\\");
  161. } else if (Character == '0') {
  162. Value = 0;
  163. DigitCount = 1;
  164. } else {
  165. //
  166. // This backslash escape sequence isn't recognized, so
  167. // just print it out verbatim.
  168. //
  169. printf("\\%c", Character);
  170. }
  171. //
  172. // Just a regular old character, print it out unless it begins
  173. // an escaped sequence.
  174. //
  175. } else if (Character != '\\') {
  176. printf("%c", Character);
  177. }
  178. if (Character == '\\') {
  179. WasBackslash = !WasBackslash;
  180. } else {
  181. WasBackslash = FALSE;
  182. }
  183. }
  184. }
  185. if (ArgumentIndex != ArgumentCount) {
  186. printf(" ");
  187. }
  188. }
  189. MainEnd:
  190. if (PrintTrailingNewline != FALSE) {
  191. printf("\n");
  192. }
  193. return 0;
  194. }
  195. //
  196. // --------------------------------------------------------- Internal Functions
  197. //
  198. BOOL
  199. EchoIsStringBackslashEscaped (
  200. PSTR String
  201. )
  202. /*++
  203. Routine Description:
  204. This routine determines if the given string has a backslash character in it.
  205. Arguments:
  206. String - Supplies a pointer to the null terminated string to check.
  207. Return Value:
  208. TRUE if the string contains a backslash.
  209. FALSE if the string contains no backslashes.
  210. --*/
  211. {
  212. if (strchr(String, '\\') != NULL) {
  213. return TRUE;
  214. }
  215. return FALSE;
  216. }