logo

utils-std

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

paste.c (6048B)


  1. /*-
  2. * SPDX-License-Identifier: BSD-3-Clause
  3. *
  4. * Copyright (c) 1989, 1993
  5. * The Regents of the University of California. All rights reserved.
  6. *
  7. * This code is derived from software contributed to Berkeley by
  8. * Adam S. Moskowitz of Menlo Consulting.
  9. *
  10. * Redistribution and use in source and binary forms, with or without
  11. * modification, are permitted provided that the following conditions
  12. * are met:
  13. * 1. Redistributions of source code must retain the above copyright
  14. * notice, this list of conditions and the following disclaimer.
  15. * 2. Redistributions in binary form must reproduce the above copyright
  16. * notice, this list of conditions and the following disclaimer in the
  17. * documentation and/or other materials provided with the distribution.
  18. * 3. Neither the name of the University nor the names of its contributors
  19. * may be used to endorse or promote products derived from this software
  20. * without specific prior written permission.
  21. *
  22. * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  23. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  24. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  25. * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  26. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  27. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  28. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  29. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  30. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  31. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  32. * SUCH DAMAGE.
  33. */
  34. #include <err.h>
  35. #include <errno.h>
  36. #include <limits.h>
  37. #include <locale.h>
  38. #include <stdint.h> // SIZE_MAX
  39. #include <stdio.h>
  40. #include <stdlib.h>
  41. #include <string.h>
  42. #include <sys/types.h>
  43. #include <unistd.h>
  44. #include <wchar.h>
  45. static wchar_t *delim;
  46. static int delimcnt;
  47. static wint_t linedelim = L'\n';
  48. static wchar_t tab[] = L"\t";
  49. const char *argv0 = "paste";
  50. typedef struct _list
  51. {
  52. struct _list *next;
  53. FILE *fp;
  54. int cnt;
  55. char *name;
  56. } LIST;
  57. static int
  58. parallel(char **argv)
  59. {
  60. LIST *lp;
  61. int cnt;
  62. wint_t ich;
  63. wchar_t ch;
  64. char *p;
  65. LIST *head, *tmp;
  66. int opencnt, output;
  67. for(cnt = 0, head = tmp = NULL; (p = *argv); ++argv, ++cnt)
  68. {
  69. if((lp = malloc(sizeof(LIST))) == NULL) err(1, NULL);
  70. if(p[0] == '-' && !p[1])
  71. lp->fp = stdin;
  72. else if(!(lp->fp = fopen(p, "r")))
  73. err(1, "error: %s", p);
  74. lp->next = NULL;
  75. lp->cnt = cnt;
  76. lp->name = p;
  77. if(!head)
  78. head = tmp = lp;
  79. else
  80. {
  81. tmp->next = lp;
  82. tmp = lp;
  83. }
  84. }
  85. for(opencnt = cnt; opencnt;)
  86. {
  87. for(output = 0, lp = head; lp; lp = lp->next)
  88. {
  89. if(!lp->fp)
  90. {
  91. if(output && lp->cnt && (ch = delim[(lp->cnt - 1) % delimcnt])) putwchar(ch);
  92. continue;
  93. }
  94. if((ich = getwc(lp->fp)) == WEOF)
  95. {
  96. if(!--opencnt) break;
  97. lp->fp = NULL;
  98. if(output && lp->cnt && (ch = delim[(lp->cnt - 1) % delimcnt])) putwchar(ch);
  99. continue;
  100. }
  101. /*
  102. * make sure that we don't print any delimiters
  103. * unless there's a non-empty file.
  104. */
  105. if(!output)
  106. {
  107. output = 1;
  108. for(cnt = 0; cnt < lp->cnt; ++cnt)
  109. if((ch = delim[cnt % delimcnt])) putwchar(ch);
  110. }
  111. else if((ch = delim[(lp->cnt - 1) % delimcnt]))
  112. putwchar(ch);
  113. if(ich == linedelim) continue;
  114. do
  115. {
  116. putwchar(ich);
  117. } while((ich = getwc(lp->fp)) != WEOF && ich != linedelim);
  118. }
  119. if(output) putwchar(linedelim);
  120. }
  121. return (0);
  122. }
  123. static int
  124. sequential(char **argv)
  125. {
  126. FILE *fp;
  127. int cnt, failed, needdelim;
  128. wint_t ch;
  129. char *p;
  130. failed = 0;
  131. for(; (p = *argv); ++argv)
  132. {
  133. if(p[0] == '-' && !p[1])
  134. fp = stdin;
  135. else if(!(fp = fopen(p, "r")))
  136. {
  137. warn("%s", p);
  138. failed = 1;
  139. continue;
  140. }
  141. cnt = needdelim = 0;
  142. while((ch = getwc(fp)) != WEOF)
  143. {
  144. if(needdelim)
  145. {
  146. needdelim = 0;
  147. if(delim[cnt] != '\0') putwchar(delim[cnt]);
  148. if(++cnt == delimcnt) cnt = 0;
  149. }
  150. if(ch != linedelim)
  151. putwchar(ch);
  152. else
  153. needdelim = 1;
  154. }
  155. if(needdelim) putwchar(linedelim);
  156. if(fp != stdin) (void)fclose(fp);
  157. }
  158. return (failed != 0);
  159. }
  160. static int
  161. tr(wchar_t *arg)
  162. {
  163. int cnt;
  164. wchar_t ch, *p;
  165. for(p = arg, cnt = 0; (ch = *p++); ++arg, ++cnt)
  166. if(ch == '\\') switch(ch = *p++)
  167. {
  168. case 'n':
  169. *arg = '\n';
  170. break;
  171. case 't':
  172. *arg = '\t';
  173. break;
  174. case '0':
  175. *arg = '\0';
  176. break;
  177. default:
  178. *arg = ch;
  179. break;
  180. }
  181. else
  182. *arg = ch;
  183. if(!cnt) errx(1, "error: no delimiters specified");
  184. return (cnt);
  185. }
  186. static void
  187. usage(void)
  188. {
  189. (void)fprintf(stderr, "usage: paste [-sz] [-d delimiters] [file...]\n");
  190. exit(1);
  191. }
  192. int
  193. main(int argc, char *argv[])
  194. {
  195. errno = 0;
  196. setlocale(LC_ALL, "");
  197. if(errno != 0)
  198. {
  199. fprintf(stderr, "%s: warning: Failed to initialize locales: %s\n", argv0, strerror(errno));
  200. errno = 0;
  201. }
  202. int c = -1, seq = 0;
  203. while((c = getopt(argc, argv, ":d:sz")) != -1)
  204. {
  205. switch(c)
  206. {
  207. case 'd':
  208. {
  209. const char *arg = optarg;
  210. size_t len = mbsrtowcs(NULL, &arg, 0, NULL);
  211. if(len == (size_t)-1) err(1, "error: delimiters");
  212. if(len == SIZE_MAX) err(1, NULL);
  213. wchar_t *warg = calloc((len + 1), sizeof(*warg));
  214. if(warg == NULL) err(1, NULL);
  215. arg = optarg;
  216. len = mbsrtowcs(warg, &arg, len + 1, NULL);
  217. if(len == (size_t)-1) err(1, "error: delimiters");
  218. delimcnt = tr(delim = warg);
  219. break;
  220. }
  221. case 's':
  222. seq = 1;
  223. break;
  224. case 'z':
  225. linedelim = L'\0';
  226. break;
  227. case ':':
  228. fprintf(stderr, "%s: error: Missing operand for option: '-%c'\n", argv0, optopt);
  229. usage();
  230. return 1;
  231. case '?':
  232. fprintf(stderr, "%s: error: Unrecognised option: '-%c'\n", argv0, optopt);
  233. usage();
  234. return 1;
  235. default:
  236. abort();
  237. }
  238. }
  239. argc -= optind;
  240. argv += optind;
  241. char *dash[] = {(char *)"-", NULL};
  242. char **args = argc > 0 ? argv : dash;
  243. if(!delim)
  244. {
  245. delimcnt = 1;
  246. delim = tab;
  247. }
  248. if(seq)
  249. return sequential(args);
  250. else
  251. return parallel(args);
  252. }