#!/usr/bin/env nickle # # Convert CSV parts list into vendor import format # # Copyright © 2015 Keith Packard , GPL v3+ # bool mfg_part = false; string[*] vendors; string vendor_list; string[*] not_vendors; string not_vendor_list; string input_name; string output_name; string program; int argi; int lineno = 0; void fatal(string format, poly args ...) { File::fprintf(stderr, format, args...); exit(1); } string[*] read_line(file f) { lineno++; string line = fgets(f); string[*] elts = String::parse_csv(line); for (int i = 0; i < dim(elts); i++) if (String::length(elts[i]) > 0 && elts[i][0] == '"') elts[i] = String::dequote(elts[i]); return elts; } string[*] header; string[*] required_elements = { "quantity", "vendor", "vendor_part_number", "mfg_part_number", "device", "value", "refdes", "loadstatus" }; bool has_header_member(string member) { for (int i = 0; i < dim(header); i++) if (header[i] == member) return true; return false; } bool has_vendor(string[*] vendors, string vendor) { for (int i = 0; i < dim(vendors); i++) if (vendors[i] == vendor) return true; return false; } void read_header(file f) { header = read_line(f); for (int i = 0; i < dim(required_elements); i++) if (!has_header_member(required_elements[i])) fatal("Missing header element \"%s\"\n", required_elements[i]); } string[string] read_entry(file f) { string[*] elements = read_line(f); string[string] entry = {}; if (dim(header) != dim(elements)) fatal("line %d: has %d instead of %d elements (%V)\n", lineno, dim(elements), dim(header), elements); for (int i = 0; i < dim(header); i++) { if (elements[i] == "") elements[i] = "unknown"; entry[header[i]] = elements[i]; } return entry; } string part_number(string[string] entry) { if (mfg_part) return entry["mfg_part_number"]; else return entry["vendor_part_number"]; } string quoted(string v) { if (String::index(v, "\"") >= 0 || String::index(v, ",") >= 0) { if (String::index(v, "\"") >= 0) { string ret = "\""; for (int i = 0; i < String::length(v); i++) { if (v[i] == '"') ret = ret + "\""; ret = ret + String::new(v[i]); } ret = ret + "\""; return ret; } else { return "\"" + v + "\""; } } else { return v; } } void process_seeed(string[string] entry) { if (entry["loadstatus"] == "noload") return; static bool start = true; if (start) { printf("Part/Designator,Manufacturer Part Number/Seeed SKU, Quantity\n"); start = false; } string[*] refdes = String::wordsplit(entry["refdes"], " \t"); if (dim(refdes) > 1) printf ("\""); for (int i = 0; i < dim(refdes); i++) { printf("%s", refdes[i]); if (i < dim(refdes) - 1) printf (","); } if (dim(refdes) > 1) printf ("\""); printf(",%s,%s\n", quoted(entry["mfg_part_number"]), entry["quantity"]); } void process_goldphoenix(string[string] entry) { int units = 1000; if (entry["loadstatus"] == "noload") return; static int item = 1; static bool start = true; if (start) { printf("#Item,Description,Designator,Package,Manufacturer,Manufacturer Part Number#,Supplier,Supplier Part #,QTY/BOARD,Order QTY,Unit Price, Subtotal \n"); start = false; } string[*] refdes = String::wordsplit(entry["refdes"], " \t"); printf("%d,", item); /* description */ printf("%s %s,", quoted(entry["device"]), quoted(entry["value"])); /* designators */ if (dim(refdes) > 1) printf ("\""); for (int i = 0; i < dim(refdes); i++) { printf("%s", refdes[i]); if (i < dim(refdes) - 1) printf (","); } if (dim(refdes) > 1) printf ("\""); /* rest */ printf(",%s,%s,%s,%s,%s,%s,%d\n", quoted(entry["footprint"]), quoted(entry["mfg"]), quoted(entry["mfg_part_number"]), quoted(entry["vendor"]), quoted(entry["vendor_part_number"]), entry["quantity"], dim(refdes) * units); item++; } void process_digikey(string[string] entry) { if (entry["loadstatus"] == "noload") return; printf("%s,%s,%s %s\n", entry["quantity"], quoted(part_number(entry)), quoted(entry["device"]), quoted(entry["value"])); } void process_mouser(string[string] entry) { if (entry["loadstatus"] == "noload") return; /* printf("%s|%s\n", part_number(entry), entry["quantity"]); */ static bool start = true; if (start) { printf("Mouser Part Number,Manufacturer Part Number,Quantity\n"); start = false; } printf("%s,%s,%s\n", quoted(entry["vendor_part_number"]), quoted(entry["mfg_part_number"]), entry["quantity"]); } void process_other(string[string] entry) { if (entry["loadstatus"] == "noload") return; printf("%s,%s,%s,%s %s\n", entry["vendor"], entry["quantity"], quoted(part_number(entry)), quoted(entry["device"]), entry["value"]); } void process_file(file f) { read_header(f); while (!File::end(f)) { string[string] entry = read_entry(f); string vendor = entry["vendor"]; if (!is_uninit(&vendors) && has_vendor(vendors, "seeed")) { process_seeed(entry); } else if (!is_uninit(&vendors) && has_vendor(vendors, "goldphoenix")) { process_goldphoenix(entry); } else if ((!is_uninit(&vendors) && has_vendor(vendors, vendor)) || (!is_uninit(¬_vendors) && !has_vendor(not_vendors, vendor))) { switch (entry["vendor"]) { case "digikey": process_digikey(entry); break; case "mouser": process_mouser(entry); break; default: process_other(entry); break; } } } } ParseArgs::argdesc argd = { .args = { { .var = { .arg_flag = &mfg_part }, .abbr = 'm', .name = "mfg", .desc = "Display manufacturer part number"}, { .var = { .arg_string = &vendor_list }, .abbr = 'v', .name = "vendor", .expr_name = "vendors", .desc = "Vendors to match"}, { .var = { .arg_string = ¬_vendor_list }, .abbr = 'n', .name = "not-vendor", .expr_name = "not-vendor", .desc = "Vendors to exclude"}, }, .unknown = &argi, }; void main() { ParseArgs::parseargs(&argd, &argv); if (!is_uninit(&vendor_list)) vendors = String::parse_csv(vendor_list); if (!is_uninit(¬_vendor_list)) not_vendors = String::parse_csv(not_vendor_list); if (!is_uninit(&argi)) { for (int i = argi; i < dim(argv); i++) twixt(file f = File::open(argv[i], "r"); File::close(f)) process_file(f); } else process_file(stdin); } main();