logo

utils-std

Collection of commonly available Unix tools git clone https://anongit.hacktivis.me/git/utils-std.git/

echo.c (2338B)


  1. // utils-std: Collection of commonly available Unix tools
  2. // SPDX-FileCopyrightText: 2017 Haelwenn (lanodan) Monnier <contact+utils@hacktivis.me>
  3. // SPDX-License-Identifier: MPL-2.0
  4. #define _POSIX_C_SOURCE 200809L
  5. #include <stdbool.h>
  6. #include <stdio.h> // perror
  7. #include <string.h> // strlen
  8. #include <unistd.h> // write
  9. static void
  10. unescape(char *str, size_t *len)
  11. {
  12. char *start = str;
  13. char *store = str;
  14. for(; str < (start + *len); ++str, ++store)
  15. {
  16. if(*str != '\\')
  17. {
  18. *store = *str;
  19. continue;
  20. }
  21. switch(*++str)
  22. {
  23. case '\\': // POSIX
  24. default:
  25. *store = *str;
  26. break;
  27. case 'a':
  28. *store = '\a';
  29. break;
  30. case 'b':
  31. *store = '\b';
  32. break;
  33. case 'c':
  34. goto unescape_end;
  35. case 'f':
  36. *store = '\f';
  37. break;
  38. case 'n':
  39. *store = '\n';
  40. break;
  41. case 'r':
  42. *store = '\r';
  43. break;
  44. case 't':
  45. *store = '\t';
  46. break;
  47. case 'v':
  48. *store = '\v';
  49. break;
  50. case '0': /* \0 \0n \0nn \0nnn */
  51. {
  52. int value = 0;
  53. int i = 0;
  54. for(; i < 4 && str[i] >= '0' && str[i] <= '7'; i++)
  55. {
  56. value <<= 3;
  57. value += str[i] - '0';
  58. }
  59. str += (i - 1);
  60. *store = (char)value;
  61. break;
  62. }
  63. }
  64. }
  65. unescape_end:
  66. *store = '\0';
  67. *len = (size_t)(store - start);
  68. }
  69. int
  70. main(int argc, char *argv[])
  71. {
  72. size_t arg_len = 0;
  73. bool opt_n = false, opt_e = false;
  74. argc--;
  75. argv++;
  76. for(; argc > 0;)
  77. {
  78. if(argv[0][0] != '-') break;
  79. /* '-' and '--' needs to be passed as-is so no argc--,argv++ */
  80. if(argv[0][1] == '\0' || (argv[0][1] == '-' && argv[0][2] == '\0')) break;
  81. for(int i = 1; argv[0][i] != '\0'; i++)
  82. {
  83. switch(argv[0][i])
  84. {
  85. case 'n':
  86. opt_n = true;
  87. break;
  88. case 'e':
  89. opt_e = true;
  90. break;
  91. case 'E':
  92. opt_e = false;
  93. break;
  94. default:
  95. break;
  96. }
  97. }
  98. argc--;
  99. argv++;
  100. }
  101. for(int i = 0; i < argc; i++)
  102. {
  103. size_t len = strlen(argv[i]);
  104. argv[i][len] = ' ';
  105. arg_len += len + 1; // str + space
  106. }
  107. if(arg_len == 0)
  108. {
  109. if(opt_n) return 0;
  110. if(write(1, "\n", 1) < 1)
  111. {
  112. perror("echo: error: Failed writing");
  113. return 1;
  114. }
  115. return 0;
  116. }
  117. else
  118. argv[0][arg_len - 1] = '\n';
  119. if(opt_n) arg_len--; // no newline
  120. if(opt_e) unescape(*argv, &arg_len);
  121. ssize_t nwrite = write(1, *argv, arg_len);
  122. if(nwrite < (ssize_t)arg_len)
  123. {
  124. perror("echo: error: Failed writing");
  125. return 1;
  126. }
  127. return 0;
  128. }