4008bb7f5dbdc288bd9c9f8572ce517825d11987
[hw/altusmetrum] / bin / partslist-vendor
1 #!/usr/bin/env nickle
2 #
3 # Convert CSV parts list into vendor import format
4 #
5 # Copyright © 2015 Keith Packard <keithp@keithp.com>, GPL v3+
6 #
7
8 bool    mfg_part = false;
9 string[*]       vendors;
10 string          vendor_list;
11 string[*]       not_vendors;
12 string          not_vendor_list;
13 string  input_name;
14 string  output_name;
15 string  program;
16 int     argi;
17 int     lineno = 0;
18
19 void fatal(string format, poly args ...)
20 {
21         File::fprintf(stderr, format, args...);
22         exit(1);
23 }
24
25 string[*] read_line(file f) {
26         lineno++;
27         string  line = fgets(f);
28
29         return String::parse_csv(line);
30 }
31
32 string[*] header;
33
34 string[*] required_elements = {
35         "quantity",
36         "vendor",
37         "vendor_part_number",
38         "mfg_part_number",
39         "device",
40         "value",
41         "refdes",
42         "loadstatus"
43 };
44
45 bool has_header_member(string member) {
46         for (int i = 0; i < dim(header); i++)
47                 if (header[i] == member)
48                         return true;
49         return false;
50 }
51
52 bool has_vendor(string[*] vendors, string vendor) {
53         for (int i = 0; i < dim(vendors); i++)
54                 if (vendors[i] == vendor)
55                         return true;
56         return false;
57 }
58
59 void read_header(file f) {
60         header = read_line(f);
61
62         for (int i = 0; i < dim(required_elements); i++)
63                 if (!has_header_member(required_elements[i]))
64                         fatal("Missing header element \"%s\"\n", required_elements[i]);
65 }
66
67 string[string] read_entry(file f) {
68         string[*]       elements = read_line(f);
69         string[string]  entry = {};
70
71         if (dim(header) != dim(elements))
72                 fatal("line %d: has %d instead of %d elements (%V)\n",
73                       lineno, dim(elements), dim(header), elements);
74
75         for (int i = 0; i < dim(header); i++) {
76                 if (elements[i] == "")
77                         elements[i] = "unknown";
78                 entry[header[i]] = elements[i];
79         }
80         return entry;
81 }
82
83 string part_number(string[string] entry)
84 {
85         if (mfg_part)
86                 return entry["mfg_part_number"];
87         else
88                 return entry["vendor_part_number"];
89 }
90
91 void process_seeed(string[string] entry)
92 {
93         if (entry["loadstatus"] == "noload")
94                 return;
95
96         static bool start = true;
97         if (start) {
98                 printf("Part/Designator,Manufacturer Part Number/Seeed SKU, Quantity\n");
99                 start = false;
100         }
101
102         string[*] refdes = String::wordsplit(entry["refdes"], " \t");
103         if (dim(refdes) > 1)
104                 printf ("\"");
105         for (int i = 0; i < dim(refdes); i++) {
106                 printf("%s", refdes[i]);
107                 if (i < dim(refdes) - 1)
108                         printf (",");
109         }
110         if (dim(refdes) > 1)
111                 printf ("\"");
112         printf(",%s,%s\n", entry["mfg_part_number"], entry["quantity"]);
113 }
114
115 void process_digikey(string[string] entry)
116 {
117         if (entry["loadstatus"] == "noload")
118                 return;
119         printf("%s,%s,%s %s\n",
120                entry["quantity"],
121                part_number(entry),
122                entry["device"],
123                entry["value"]);
124 }
125
126 void process_mouser(string[string] entry)
127 {
128         if (entry["loadstatus"] == "noload")
129                 return;
130 /*      printf("%s|%s\n", part_number(entry), entry["quantity"]); */
131
132         static bool start = true;
133
134         if (start) {
135                 printf("Mouser Part Number,Manufacturer Part Number,Quantity 1\n");
136                 start = false;
137         }
138
139         printf("%s,%s,%s\n",
140                entry["vendor_part_number"],
141                entry["mfg_part_number"],
142                entry["quantity"]);
143 }
144
145 void process_other(string[string] entry) {
146         if (entry["loadstatus"] == "noload")
147                 return;
148         printf("%s,%s,%s,%s %s\n",
149                entry["vendor"],
150                entry["quantity"],
151                part_number(entry),
152                entry["device"],
153                entry["value"]);
154 }
155
156 void process_file(file f) {
157         read_header(f);
158         while (!File::end(f)) {
159                 string[string] entry = read_entry(f);
160                 string vendor = entry["vendor"];
161                 if (!is_uninit(&vendors) && has_vendor(vendors, "seeed")) {
162                         process_seeed(entry);
163                 } else if ((!is_uninit(&vendors) && has_vendor(vendors, vendor)) ||
164                            (!is_uninit(&not_vendors) && !has_vendor(not_vendors, vendor))) {
165                         switch (entry["vendor"]) {
166                         case "digikey":
167                                 process_digikey(entry);
168                                 break;
169                         case "mouser":
170                                 process_mouser(entry);
171                                 break;
172                         default:
173                                 process_other(entry);
174                                 break;
175                         }
176                 }
177         }
178 }
179
180 ParseArgs::argdesc argd = {
181         .args = {
182                 { .var = { .arg_flag = &mfg_part },
183                   .abbr = 'm',
184                   .name = "mfg",
185                   .desc = "Display manufacturer part number"},
186                 { .var = { .arg_string = &vendor_list },
187                   .abbr = 'v',
188                   .name = "vendor",
189                   .expr_name = "vendors",
190                   .desc = "Vendors to match"},
191                 { .var = { .arg_string = &not_vendor_list },
192                   .abbr = 'n',
193                   .name = "not-vendor",
194                   .expr_name = "not-vendor",
195                   .desc = "Vendors to exclude"},
196         },
197         .unknown = &argi,
198 };
199
200 void main() {
201         ParseArgs::parseargs(&argd, &argv);
202         if (!is_uninit(&vendor_list))
203                 vendors = String::parse_csv(vendor_list);
204
205         if (!is_uninit(&not_vendor_list))
206                 not_vendors = String::parse_csv(not_vendor_list);
207
208         if (!is_uninit(&argi)) {
209                 for (int i = argi; i < dim(argv); i++)
210                         twixt(file f = File::open(argv[i], "r"); File::close(f))
211                                 process_file(f);
212         } else
213                 process_file(stdin);
214 }
215
216 main();