logo

utils-std

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

strings.c (4095B)


  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 <ctype.h> /* isprint() */
  6. #include <errno.h> /* errno */
  7. #include <fcntl.h> /* open(), O_RDONLY */
  8. #include <limits.h> /* LONG_MAX */
  9. #include <stdio.h> /* fprintf(), BUFSIZ */
  10. #include <stdlib.h> /* strtol() */
  11. #include <string.h> /* strerror(), strncmp() */
  12. #include <unistd.h> /* read(), write(), close(), getopt(), optarg, optind */
  13. size_t opt_min_strlen = 4;
  14. const char *opt_offset_format = NULL;
  15. int delim = '\n';
  16. static int
  17. print_string(char *buffer, size_t offset)
  18. {
  19. int ret = 0;
  20. if(opt_offset_format == NULL)
  21. {
  22. ret = printf("%s%c", buffer, delim);
  23. }
  24. else
  25. {
  26. ret = printf(opt_offset_format, offset, buffer, delim);
  27. }
  28. if(ret < 0)
  29. {
  30. fprintf(stderr, "strings: error: Failed writing: %s\n", strerror(errno));
  31. errno = 0;
  32. return 1;
  33. }
  34. else
  35. {
  36. return 0;
  37. }
  38. }
  39. static int
  40. concat(int fd, const char *fdname)
  41. {
  42. ssize_t c;
  43. static char read_buf[4096];
  44. static char write_buf[4096];
  45. size_t write_pos = 0;
  46. size_t offset = 0;
  47. while((c = read(fd, read_buf, sizeof(read_buf))) > 0)
  48. {
  49. int read_pos = 0;
  50. char b = 0;
  51. for(; read_pos < c; read_pos++)
  52. {
  53. b = read_buf[read_pos];
  54. if(isprint(b) && write_pos < 4096)
  55. {
  56. write_buf[write_pos++] = b;
  57. }
  58. else
  59. {
  60. if(write_pos >= opt_min_strlen)
  61. {
  62. write_buf[write_pos + 1] = 0;
  63. if(print_string(write_buf, offset) != 0)
  64. {
  65. return 1;
  66. }
  67. }
  68. offset += write_pos;
  69. offset++;
  70. write_pos = 0;
  71. }
  72. }
  73. }
  74. if(c < 0)
  75. {
  76. fprintf(stderr, "strings: error: Failed reading ‘%s’: %s\n", fdname, strerror(errno));
  77. errno = 0;
  78. return 1;
  79. }
  80. return 0;
  81. }
  82. static void
  83. usage(void)
  84. {
  85. fprintf(stderr, "strings: [-az] [-t format] [-n number] [file...]\n");
  86. }
  87. int
  88. main(int argc, char *argv[])
  89. {
  90. int c;
  91. while((c = getopt(argc, argv, ":an:t:z")) != -1)
  92. {
  93. char *endptr = NULL;
  94. switch(c)
  95. {
  96. case 'a':
  97. /* Structure is always ignored */
  98. break;
  99. case 'n':
  100. opt_min_strlen = strtol(optarg, &endptr, 10);
  101. if(endptr && *endptr != 0)
  102. {
  103. // extraneous characters is invalid
  104. errno = EINVAL;
  105. }
  106. if(errno != 0)
  107. {
  108. fprintf(stderr, "strings: error: Option `-n %s`: %s\n", optarg, strerror(errno));
  109. usage();
  110. return 1;
  111. }
  112. if(opt_min_strlen < 1)
  113. {
  114. fprintf(stderr, "strings: error: Option `-n %s` is too small\n", optarg);
  115. usage();
  116. return 1;
  117. }
  118. if(opt_min_strlen == LONG_MAX || opt_min_strlen > 4096)
  119. {
  120. fprintf(stderr, "strings: error: Option `-n %s` is too large\n", optarg);
  121. usage();
  122. return 1;
  123. }
  124. break;
  125. case 't':
  126. if(strnlen(optarg, 2) > 1)
  127. {
  128. usage();
  129. return 1;
  130. }
  131. switch(optarg[0])
  132. {
  133. case 'o':
  134. opt_offset_format = "%zo %s%c";
  135. break;
  136. case 'x':
  137. opt_offset_format = "%zx %s%c";
  138. break;
  139. case 'd':
  140. opt_offset_format = "%zd %s%c";
  141. break;
  142. default:
  143. fprintf(stderr, "strings: error: Unknown format: %s\n", optarg);
  144. usage();
  145. return 1;
  146. }
  147. break;
  148. case 'z':
  149. delim = '\0';
  150. break;
  151. case ':':
  152. fprintf(stderr, "strings: error: Missing operand for option: '-%c'\n", optopt);
  153. usage();
  154. return 1;
  155. case '?':
  156. fprintf(stderr, "strings: error: Unrecognised option: '-%c'\n", optopt);
  157. usage();
  158. return 1;
  159. default:
  160. abort();
  161. }
  162. }
  163. argc -= optind;
  164. argv += optind;
  165. if(argc < 1)
  166. {
  167. return concat(0, "<stdin>");
  168. }
  169. for(int argi = 0; argi < argc; argi++)
  170. {
  171. if(strncmp(argv[argi], "-", 2) == 0)
  172. {
  173. if(concat(0, "<stdin>") != 0)
  174. {
  175. return 1;
  176. }
  177. }
  178. else
  179. {
  180. int fd = open(argv[argi], O_RDONLY);
  181. if(fd <= 0)
  182. {
  183. fprintf(stderr, "strings: error: Failed opening ‘%s’: %s\n", argv[argi], strerror(errno));
  184. return 1;
  185. }
  186. if(concat(fd, argv[argi]) != 0)
  187. {
  188. return 1;
  189. }
  190. if(close(fd) < 0)
  191. {
  192. fprintf(stderr, "strings: error: Failed closing ‘%s’: %s\n", argv[argi], strerror(errno));
  193. return 1;
  194. }
  195. }
  196. }
  197. return 0;
  198. }