csvtofsv.c - csvtofsv - Convert CSV to FSV (`fs' (0x1c) as FS and `rs' (0x1e) as RS)
(HTM) hg clone https://bitbucket.org/iamleot/csvtofsv
(DIR) Log
(DIR) Files
(DIR) Refs
(DIR) README
---
csvtofsv.c
---
1 /*-
2 * Copyright (c) 2019 Leonardo Taccari
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
17 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS
19 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25 * POSSIBILITY OF SUCH DAMAGE.
26 */
27
28
29 #include <stdbool.h>
30 #include <stdio.h>
31
32
33 #define FS 034
34 #define RS 036
35
36
37 /*
38 * Convert a CSV from stdin to FSV with `fs' ASCII char (0x1c) as field
39 * separator and `rs' ASCII char (0x1e) as record separator.
40 */
41 int
42 main(int argc, char *argv[])
43 {
44 int c, nc, pc;
45 bool first, quoted;
46
47 first = true;
48 quoted = false;
49 pc = '\0';
50 while ((c = getchar()) != EOF) {
51 pc = c;
52 switch (c) {
53 case '"':
54 if (first) {
55 quoted = true;
56 first = false;
57 } else if (!quoted) {
58 /*
59 * RFC 4180 says: `Fields containing [...]
60 * double quotes [...] should be enclosed in
61 * double-quotes.'. This violates that by
62 * printing alone `"' as-is.
63 */
64 putchar(c);
65 } else if ((nc = getchar()) != EOF) {
66 pc = nc;
67 if (nc == '"') {
68 putchar('"');
69 } else if (nc == ',') {
70 putchar(FS);
71 first = true;
72 quoted = false;
73 } else if ((nc == '\n') ||
74 ((nc == '\r') &&
75 ((nc = getchar()) == '\n'))) {
76 pc = nc;
77 putchar(RS);
78 first = true;
79 quoted = false;
80 } else {
81 ungetc(nc, stdin);
82 }
83 }
84 break;
85 case ',':
86 if (quoted) {
87 putchar(',');
88 } else {
89 putchar(FS);
90 first = true;
91 }
92 break;
93 case '\n':
94 if (quoted) {
95 putchar('\n');
96 } else {
97 putchar(RS);
98 first = true;
99 }
100 break;
101 case '\r':
102 /* ignore */
103 break;
104 case FS:
105 fprintf(stderr, "FS character found, stopping.\n");
106 return 1;
107 break; /* NOTREACHED */
108 case RS:
109 fprintf(stderr, "RS character found, stopping.\n");
110 return 1;
111 break; /* NOTREACHED */
112 default:
113 putchar(c);
114 break;
115 }
116 }
117
118 if (pc != '\0' && pc != '\n')
119 putchar(RS);
120
121 return 0;
122 }