| csvtofsv.c - csvtofsv - Convert CSV to FSV (`fs' (0x1c) as FS and `rs' (0x1e) a… | |
| hg clone https://bitbucket.org/iamleot/csvtofsv | |
| Log | |
| Files | |
| Refs | |
| 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 distributio… | |
| 14 * | |
| 15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| 16 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIM… | |
| 17 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTI… | |
| 18 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CON… | |
| 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 BUSIN… | |
| 22 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER … | |
| 23 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWIS… | |
| 24 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED O… | |
| 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 enclose… | |
| 61 * double-quotes.'. This violates that … | |
| 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 } |