Adjust oshpark targets. Add seeed targets
[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 };
43
44 bool has_header_member(string member) {
45         for (int i = 0; i < dim(header); i++)
46                 if (header[i] == member)
47                         return true;
48         return false;
49 }
50
51 bool has_vendor(string[*] vendors, string vendor) {
52         for (int i = 0; i < dim(vendors); i++)
53                 if (vendors[i] == vendor)
54                         return true;
55         return false;
56 }
57
58 void read_header(file f) {
59         header = read_line(f);
60
61         for (int i = 0; i < dim(required_elements); i++)
62                 if (!has_header_member(required_elements[i]))
63                         fatal("Missing header element \"%s\"\n", required_elements[i]);
64 }
65
66 string[string] read_entry(file f) {
67         string[*]       elements = read_line(f);
68         string[string]  entry = {};
69
70         if (dim(header) != dim(elements))
71                 fatal("line %d: has %d instead of %d elements (%V)\n",
72                       lineno, dim(elements), dim(header), elements);
73
74         for (int i = 0; i < dim(header); i++) {
75                 if (elements[i] == "")
76                         elements[i] = "unknown";
77                 entry[header[i]] = elements[i];
78         }
79         return entry;
80 }
81
82 string part_number(string[string] entry)
83 {
84         if (mfg_part)
85                 return entry["mfg_part_number"];
86         else
87                 return entry["vendor_part_number"];
88 }
89
90 void process_seeed(string[string] entry)
91 {
92
93         if (entry["loadstatus"] != "smt")
94                 return;
95
96         static bool start = true;
97         if (start) {
98                 printf("Part/Designator,Manufacturer Part Number/Seeed SKU, Quantity");
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         printf("%s,%s,%s %s\n",
118                entry["quantity"],
119                part_number(entry),
120                entry["device"],
121                entry["value"]);
122 }
123
124 void process_other(string[string] entry) {
125         printf("%s,%s,%s,%s %s\n",
126                entry["vendor"],
127                entry["quantity"],
128                part_number(entry),
129                entry["device"],
130                entry["value"]);
131 }
132
133 void process_file(file f) {
134         read_header(f);
135         while (!File::end(f)) {
136                 string[string] entry = read_entry(f);
137                 string vendor = entry["vendor"];
138                 if (!is_uninit(&vendors) && has_vendor(vendors, "seeed")) {
139                         process_seeed(entry);
140                 } else if ((!is_uninit(&vendors) && has_vendor(vendors, vendor)) ||
141                            (!is_uninit(&not_vendors) && !has_vendor(not_vendors, vendor))) {
142                         switch (entry["vendor"]) {
143                         case "digikey":
144                                 process_digikey(entry);
145                                 break;
146                         default:
147                                 process_other(entry);
148                                 break;
149                         }
150                 }
151         }
152 }
153
154 ParseArgs::argdesc argd = {
155         .args = {
156                 { .var = { .arg_flag = &mfg_part },
157                   .abbr = 'm',
158                   .name = "mfg",
159                   .desc = "Display manufacturer part number"},
160                 { .var = { .arg_string = &vendor_list },
161                   .abbr = 'v',
162                   .name = "vendor",
163                   .expr_name = "vendors",
164                   .desc = "Vendors to match"},
165                 { .var = { .arg_string = &not_vendor_list },
166                   .abbr = 'n',
167                   .name = "not-vendor",
168                   .expr_name = "not-vendor",
169                   .desc = "Vendors to exclude"},
170         },
171         .unknown = &argi,
172 };
173
174 void main() {
175         ParseArgs::parseargs(&argd, &argv);
176         if (!is_uninit(&vendor_list))
177                 vendors = String::parse_csv(vendor_list);
178
179         if (!is_uninit(&not_vendor_list))
180                 not_vendors = String::parse_csv(not_vendor_list);
181
182         if (!is_uninit(&argi)) {
183                 for (int i = argi; i < dim(argv); i++)
184                         twixt(file f = File::open(argv[i], "r"); File::close(f))
185                                 process_file(f);
186         } else
187                 process_file(stdin);
188 }
189
190 main();