logo

utils

~/.local/bin tools and git-hooks git clone https://hacktivis.me/git/utils.git

cat.c (2222B)


  1. // Collection of Unix tools, comparable to coreutils
  2. // SPDX-FileCopyrightText: 2017-2023 Haelwenn (lanodan) Monnier <contact+utils@hacktivis.me>
  3. // SPDX-License-Identifier: MPL-2.0
  4. #define _POSIX_C_SOURCE 200809L
  5. #include <errno.h> /* errno */
  6. #include <fcntl.h> /* open(), O_RDONLY */
  7. #include <stdio.h> /* fprintf(), BUFSIZ */
  8. #include <string.h> /* strerror(), strncmp() */
  9. #include <unistd.h> /* read(), write(), close() */
  10. int
  11. concat(int fd, const char *fdname)
  12. {
  13. ssize_t c;
  14. char buf[BUFSIZ];
  15. while((c = read(fd, buf, sizeof(buf))) > 0)
  16. {
  17. if(write(1, buf, (size_t)c) < 0)
  18. {
  19. fprintf(stderr, "cat: Error writing: %s\n", strerror(errno));
  20. return 1;
  21. }
  22. }
  23. if(c < 0)
  24. {
  25. fprintf(stderr, "cat: Error reading ‘%s’: %s\n", fdname, strerror(errno));
  26. return 1;
  27. }
  28. return 0;
  29. }
  30. // FreeBSD also has sendfile(2) but it's only for sockets
  31. #ifdef __linux__
  32. #include <sys/sendfile.h>
  33. // Grabbed from /usr/src/hare/stdlib/io/+linux/platform_file.ha
  34. #ifndef SENDFILE_MAX
  35. #define SENDFILE_MAX 2147479552
  36. #endif // SENDFILE_MAX
  37. int
  38. fd_copy(int fd, const char *fdname)
  39. {
  40. ssize_t c = 0;
  41. off_t off = 0;
  42. while((c = sendfile(1, fd, &off, SENDFILE_MAX)) > 0)
  43. ;
  44. if(c < 0)
  45. {
  46. if(errno == EINVAL && off == 0)
  47. {
  48. return concat(fd, fdname);
  49. }
  50. fprintf(stderr, "cat: Error copying ‘%s’: %s\n", fdname, strerror(errno));
  51. return 1;
  52. }
  53. return 0;
  54. }
  55. #else // __linux__
  56. #define fd_copy concat
  57. #endif // __linux__
  58. int
  59. main(int argc, char *argv[])
  60. {
  61. if(argc <= 1)
  62. {
  63. return concat(0, "<stdin>");
  64. }
  65. // For POSIX compatibility
  66. if(strncmp(argv[1], "-u", 3) == 0)
  67. {
  68. argc--;
  69. argv++;
  70. }
  71. for(int argi = 1; argi < argc; argi++)
  72. {
  73. if(strncmp(argv[argi], "-", 2) == 0)
  74. {
  75. if(concat(0, "<stdin>") != 0)
  76. {
  77. return 1;
  78. }
  79. }
  80. else if(strncmp(argv[argi], "--", 3) == 0)
  81. {
  82. continue;
  83. }
  84. else
  85. {
  86. int fd = open(argv[argi], O_RDONLY);
  87. if(fd < 0)
  88. {
  89. fprintf(stderr, "cat: Error opening ‘%s’: %s\n", argv[argi], strerror(errno));
  90. return 1;
  91. }
  92. if(fd_copy(fd, argv[argi]) != 0)
  93. {
  94. return 1;
  95. }
  96. if(close(fd) < 0)
  97. {
  98. fprintf(stderr, "cat: Error closing ‘%s’: %s\n", argv[argi], strerror(errno));
  99. return 1;
  100. }
  101. }
  102. }
  103. return 0;
  104. }