logo

utils-std

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

paste.c (5545B)


  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 <stdio.h>
  39. #include <stdlib.h>
  40. #include <string.h>
  41. #include <sys/types.h>
  42. #include <unistd.h>
  43. #include <wchar.h>
  44. static wchar_t *delim;
  45. static int delimcnt;
  46. static int parallel(char **);
  47. static int sequential(char **);
  48. static int tr(wchar_t *);
  49. static void usage(void);
  50. static wchar_t tab[] = L"\t";
  51. int
  52. main(int argc, char *argv[])
  53. {
  54. int ch, rval, seq;
  55. wchar_t *warg;
  56. const char *arg;
  57. size_t len;
  58. setlocale(LC_CTYPE, "");
  59. seq = 0;
  60. while((ch = getopt(argc, argv, "d:s")) != -1)
  61. switch(ch)
  62. {
  63. case 'd':
  64. arg = optarg;
  65. len = mbsrtowcs(NULL, &arg, 0, NULL);
  66. if(len == (size_t)-1) err(1, "delimiters");
  67. warg = calloc((len + 1), sizeof(*warg));
  68. if(warg == NULL) err(1, NULL);
  69. arg = optarg;
  70. len = mbsrtowcs(warg, &arg, len + 1, NULL);
  71. if(len == (size_t)-1) err(1, "delimiters");
  72. delimcnt = tr(delim = warg);
  73. break;
  74. case 's':
  75. seq = 1;
  76. break;
  77. case '?':
  78. default:
  79. usage();
  80. }
  81. argc -= optind;
  82. argv += optind;
  83. if(*argv == NULL) usage();
  84. if(!delim)
  85. {
  86. delimcnt = 1;
  87. delim = tab;
  88. }
  89. if(seq)
  90. rval = sequential(argv);
  91. else
  92. rval = parallel(argv);
  93. exit(rval);
  94. }
  95. typedef struct _list
  96. {
  97. struct _list *next;
  98. FILE *fp;
  99. int cnt;
  100. char *name;
  101. } LIST;
  102. static int
  103. parallel(char **argv)
  104. {
  105. LIST *lp;
  106. int cnt;
  107. wint_t ich;
  108. wchar_t ch;
  109. char *p;
  110. LIST *head, *tmp;
  111. int opencnt, output;
  112. for(cnt = 0, head = tmp = NULL; (p = *argv); ++argv, ++cnt)
  113. {
  114. if((lp = malloc(sizeof(LIST))) == NULL) err(1, NULL);
  115. if(p[0] == '-' && !p[1])
  116. lp->fp = stdin;
  117. else if(!(lp->fp = fopen(p, "r")))
  118. err(1, "%s", p);
  119. lp->next = NULL;
  120. lp->cnt = cnt;
  121. lp->name = p;
  122. if(!head)
  123. head = tmp = lp;
  124. else
  125. {
  126. tmp->next = lp;
  127. tmp = lp;
  128. }
  129. }
  130. for(opencnt = cnt; opencnt;)
  131. {
  132. for(output = 0, lp = head; lp; lp = lp->next)
  133. {
  134. if(!lp->fp)
  135. {
  136. if(output && lp->cnt && (ch = delim[(lp->cnt - 1) % delimcnt])) putwchar(ch);
  137. continue;
  138. }
  139. if((ich = getwc(lp->fp)) == WEOF)
  140. {
  141. if(!--opencnt) break;
  142. lp->fp = NULL;
  143. if(output && lp->cnt && (ch = delim[(lp->cnt - 1) % delimcnt])) putwchar(ch);
  144. continue;
  145. }
  146. /*
  147. * make sure that we don't print any delimiters
  148. * unless there's a non-empty file.
  149. */
  150. if(!output)
  151. {
  152. output = 1;
  153. for(cnt = 0; cnt < lp->cnt; ++cnt)
  154. if((ch = delim[cnt % delimcnt])) putwchar(ch);
  155. }
  156. else if((ch = delim[(lp->cnt - 1) % delimcnt]))
  157. putwchar(ch);
  158. if(ich == '\n') continue;
  159. do
  160. {
  161. putwchar(ich);
  162. } while((ich = getwc(lp->fp)) != WEOF && ich != '\n');
  163. }
  164. if(output) putwchar('\n');
  165. }
  166. return (0);
  167. }
  168. static int
  169. sequential(char **argv)
  170. {
  171. FILE *fp;
  172. int cnt, failed, needdelim;
  173. wint_t ch;
  174. char *p;
  175. failed = 0;
  176. for(; (p = *argv); ++argv)
  177. {
  178. if(p[0] == '-' && !p[1])
  179. fp = stdin;
  180. else if(!(fp = fopen(p, "r")))
  181. {
  182. warn("%s", p);
  183. failed = 1;
  184. continue;
  185. }
  186. cnt = needdelim = 0;
  187. while((ch = getwc(fp)) != WEOF)
  188. {
  189. if(needdelim)
  190. {
  191. needdelim = 0;
  192. if(delim[cnt] != '\0') putwchar(delim[cnt]);
  193. if(++cnt == delimcnt) cnt = 0;
  194. }
  195. if(ch != '\n')
  196. putwchar(ch);
  197. else
  198. needdelim = 1;
  199. }
  200. if(needdelim) putwchar('\n');
  201. if(fp != stdin) (void)fclose(fp);
  202. }
  203. return (failed != 0);
  204. }
  205. static int
  206. tr(wchar_t *arg)
  207. {
  208. int cnt;
  209. wchar_t ch, *p;
  210. for(p = arg, cnt = 0; (ch = *p++); ++arg, ++cnt)
  211. if(ch == '\\') switch(ch = *p++)
  212. {
  213. case 'n':
  214. *arg = '\n';
  215. break;
  216. case 't':
  217. *arg = '\t';
  218. break;
  219. case '0':
  220. *arg = '\0';
  221. break;
  222. default:
  223. *arg = ch;
  224. break;
  225. }
  226. else
  227. *arg = ch;
  228. if(!cnt) errx(1, "no delimiters specified");
  229. return (cnt);
  230. }
  231. static void
  232. usage(void)
  233. {
  234. (void)fprintf(stderr, "usage: paste [-s] [-d delimiters] file ...\n");
  235. exit(1);
  236. }