Import upstream version 0.1~git20220315.cb74358c2896+git20220406.1.8a8d673
Debian Janitor
2 years ago
28 | 28 | $(CXX) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) $(WARN_FLAGS) -g $(sha) $(date) -o $@ $(SOURCES) -lm |
29 | 29 | |
30 | 30 | edid-decode.js: $(SOURCES) edid-decode.h oui.h Makefile |
31 | $(EMXX) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) $(WARN_FLAGS) $(sha) $(date) -s EXPORTED_FUNCTIONS='["_parse_edid"]' -s EXTRA_EXPORTED_RUNTIME_METHODS='["ccall", "cwrap"]' -o $@ $(SOURCES) -lm | |
31 | $(EMXX) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) $(WARN_FLAGS) $(sha) $(date) -s EXPORTED_FUNCTIONS='["_parse_edid"]' -s EXPORTED_RUNTIME_METHODS='["ccall", "cwrap"]' -o $@ $(SOURCES) -lm | |
32 | 32 | |
33 | 33 | clean: |
34 | rm -f edid-decode | |
34 | rm -f edid-decode edid-decode.js edid-decode.wasm | |
35 | 35 | |
36 | 36 | install: |
37 | 37 | mkdir -p $(DESTDIR)$(bindir) |
76 | 76 | |
77 | 77 | static char options[OptLast]; |
78 | 78 | |
79 | #ifndef __EMSCRIPTEN__ | |
79 | 80 | static struct option long_options[] = { |
80 | 81 | { "help", no_argument, 0, OptHelp }, |
81 | 82 | { "output-format", required_argument, 0, OptOutputFormat }, |
191 | 192 | " --list-rid-timings <rid> List all timings for RID <rid> or all known RIDs if <rid> is 0.\n" |
192 | 193 | " -h, --help Display this help message.\n"); |
193 | 194 | } |
195 | #endif | |
194 | 196 | |
195 | 197 | static std::string s_msgs[EDID_MAX_BLOCKS + 1][2]; |
196 | 198 | |
233 | 235 | } |
234 | 236 | |
235 | 237 | |
236 | void do_checksum(const char *prefix, const unsigned char *x, size_t len) | |
238 | void do_checksum(const char *prefix, const unsigned char *x, size_t len, unsigned unused_bytes) | |
237 | 239 | { |
238 | 240 | unsigned char check = x[len - 1]; |
239 | 241 | unsigned char sum = 0; |
245 | 247 | sum += x[i]; |
246 | 248 | |
247 | 249 | if ((unsigned char)(check + sum) != 0) { |
248 | printf(" (should be 0x%02x)\n", -sum & 0xff); | |
250 | printf(" (should be 0x%02x)", -sum & 0xff); | |
249 | 251 | fail("Invalid checksum 0x%02x (should be 0x%02x).\n", |
250 | 252 | check, -sum & 0xff); |
251 | return; | |
252 | } | |
253 | } | |
254 | if (unused_bytes) | |
255 | printf(" Unused space in Extension Block: %u byte%s", | |
256 | unused_bytes, unused_bytes > 1 ? "s" : ""); | |
253 | 257 | printf("\n"); |
254 | 258 | } |
255 | 259 | |
1023 | 1027 | return true; |
1024 | 1028 | } |
1025 | 1029 | |
1026 | static unsigned char crc_calc(const unsigned char *b) | |
1027 | { | |
1028 | unsigned char sum = 0; | |
1029 | unsigned i; | |
1030 | ||
1031 | for (i = 0; i < 127; i++) | |
1032 | sum += b[i]; | |
1033 | return 256 - sum; | |
1034 | } | |
1035 | ||
1036 | static int crc_ok(const unsigned char *b) | |
1037 | { | |
1038 | return crc_calc(b) == b[127]; | |
1039 | } | |
1040 | ||
1041 | static void hexdumpedid(FILE *f, const unsigned char *edid, unsigned size) | |
1042 | { | |
1043 | unsigned b, i, j; | |
1044 | ||
1045 | for (b = 0; b < size / 128; b++) { | |
1046 | const unsigned char *buf = edid + 128 * b; | |
1047 | ||
1048 | if (b) | |
1049 | fprintf(f, "\n"); | |
1050 | for (i = 0; i < 128; i += 0x10) { | |
1051 | fprintf(f, "%02x", buf[i]); | |
1052 | for (j = 1; j < 0x10; j++) { | |
1053 | fprintf(f, " %02x", buf[i + j]); | |
1054 | } | |
1055 | fprintf(f, "\n"); | |
1056 | } | |
1057 | if (!crc_ok(buf)) | |
1058 | fprintf(f, "Block %u has a checksum error (should be 0x%02x).\n", | |
1059 | b, crc_calc(buf)); | |
1060 | } | |
1061 | } | |
1062 | ||
1063 | static void carraydumpedid(FILE *f, const unsigned char *edid, unsigned size) | |
1064 | { | |
1065 | unsigned b, i, j; | |
1066 | ||
1067 | fprintf(f, "const unsigned char edid[] = {\n"); | |
1068 | for (b = 0; b < size / 128; b++) { | |
1069 | const unsigned char *buf = edid + 128 * b; | |
1070 | ||
1071 | if (b) | |
1072 | fprintf(f, "\n"); | |
1073 | for (i = 0; i < 128; i += 8) { | |
1074 | fprintf(f, "\t0x%02x,", buf[i]); | |
1075 | for (j = 1; j < 8; j++) { | |
1076 | fprintf(f, " 0x%02x,", buf[i + j]); | |
1077 | } | |
1078 | fprintf(f, "\n"); | |
1079 | } | |
1080 | if (!crc_ok(buf)) | |
1081 | fprintf(f, "\t/* Block %u has a checksum error (should be 0x%02x). */\n", | |
1082 | b, crc_calc(buf)); | |
1083 | } | |
1084 | fprintf(f, "};\n"); | |
1085 | } | |
1086 | ||
1087 | // This format can be read by the QuantumData EDID editor | |
1088 | static void xmldumpedid(FILE *f, const unsigned char *edid, unsigned size) | |
1089 | { | |
1090 | fprintf(f, "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n"); | |
1091 | fprintf(f, "<DATAOBJ>\n"); | |
1092 | fprintf(f, " <HEADER TYPE=\"DID\" VERSION=\"1.0\"/>\n"); | |
1093 | fprintf(f, " <DATA>\n"); | |
1094 | for (unsigned b = 0; b < size / 128; b++) { | |
1095 | const unsigned char *buf = edid + 128 * b; | |
1096 | ||
1097 | fprintf(f, " <BLOCK%u>", b); | |
1098 | for (unsigned i = 0; i < 128; i++) | |
1099 | fprintf(f, "%02X", buf[i]); | |
1100 | fprintf(f, "</BLOCK%u>\n", b); | |
1101 | } | |
1102 | fprintf(f, " </DATA>\n"); | |
1103 | fprintf(f, "</DATAOBJ>\n"); | |
1104 | } | |
1105 | ||
1106 | ||
1107 | static int edid_to_file(const char *to_file, enum output_format out_fmt) | |
1108 | { | |
1109 | FILE *out; | |
1110 | ||
1111 | if (!strcmp(to_file, "-")) { | |
1112 | to_file = "stdout"; | |
1113 | out = stdout; | |
1114 | } else if ((out = fopen(to_file, "w")) == NULL) { | |
1115 | perror(to_file); | |
1116 | return -1; | |
1117 | } | |
1118 | if (out_fmt == OUT_FMT_DEFAULT) | |
1119 | out_fmt = out == stdout ? OUT_FMT_HEX : OUT_FMT_RAW; | |
1120 | ||
1121 | switch (out_fmt) { | |
1122 | default: | |
1123 | case OUT_FMT_HEX: | |
1124 | hexdumpedid(out, edid, state.edid_size); | |
1125 | break; | |
1126 | case OUT_FMT_RAW: | |
1127 | fwrite(edid, state.edid_size, 1, out); | |
1128 | break; | |
1129 | case OUT_FMT_CARRAY: | |
1130 | carraydumpedid(out, edid, state.edid_size); | |
1131 | break; | |
1132 | case OUT_FMT_XML: | |
1133 | xmldumpedid(out, edid, state.edid_size); | |
1134 | break; | |
1135 | } | |
1136 | ||
1137 | if (out != stdout) | |
1138 | fclose(out); | |
1139 | return 0; | |
1140 | } | |
1141 | ||
1142 | 1030 | static int edid_from_file(const char *from_file, FILE *error) |
1143 | 1031 | { |
1144 | 1032 | #ifdef O_BINARY |
1269 | 1157 | { |
1270 | 1158 | block = block_name(x[0]); |
1271 | 1159 | data_block.clear(); |
1160 | unused_bytes = 0; | |
1272 | 1161 | |
1273 | 1162 | printf("\n"); |
1274 | 1163 | if (block_nr && x[0] == 0) |
1306 | 1195 | } |
1307 | 1196 | |
1308 | 1197 | data_block.clear(); |
1309 | do_checksum("", x, EDID_PAGE_SIZE); | |
1198 | do_checksum("", x, EDID_PAGE_SIZE, unused_bytes); | |
1310 | 1199 | } |
1311 | 1200 | |
1312 | 1201 | void edid_state::print_preferred_timings() |
1549 | 1438 | return failures ? -2 : 0; |
1550 | 1439 | } |
1551 | 1440 | |
1441 | #ifndef __EMSCRIPTEN__ | |
1442 | ||
1443 | static unsigned char crc_calc(const unsigned char *b) | |
1444 | { | |
1445 | unsigned char sum = 0; | |
1446 | unsigned i; | |
1447 | ||
1448 | for (i = 0; i < 127; i++) | |
1449 | sum += b[i]; | |
1450 | return 256 - sum; | |
1451 | } | |
1452 | ||
1453 | static int crc_ok(const unsigned char *b) | |
1454 | { | |
1455 | return crc_calc(b) == b[127]; | |
1456 | } | |
1457 | ||
1458 | static void hexdumpedid(FILE *f, const unsigned char *edid, unsigned size) | |
1459 | { | |
1460 | unsigned b, i, j; | |
1461 | ||
1462 | for (b = 0; b < size / 128; b++) { | |
1463 | const unsigned char *buf = edid + 128 * b; | |
1464 | ||
1465 | if (b) | |
1466 | fprintf(f, "\n"); | |
1467 | for (i = 0; i < 128; i += 0x10) { | |
1468 | fprintf(f, "%02x", buf[i]); | |
1469 | for (j = 1; j < 0x10; j++) { | |
1470 | fprintf(f, " %02x", buf[i + j]); | |
1471 | } | |
1472 | fprintf(f, "\n"); | |
1473 | } | |
1474 | if (!crc_ok(buf)) | |
1475 | fprintf(f, "Block %u has a checksum error (should be 0x%02x).\n", | |
1476 | b, crc_calc(buf)); | |
1477 | } | |
1478 | } | |
1479 | ||
1480 | static void carraydumpedid(FILE *f, const unsigned char *edid, unsigned size) | |
1481 | { | |
1482 | unsigned b, i, j; | |
1483 | ||
1484 | fprintf(f, "const unsigned char edid[] = {\n"); | |
1485 | for (b = 0; b < size / 128; b++) { | |
1486 | const unsigned char *buf = edid + 128 * b; | |
1487 | ||
1488 | if (b) | |
1489 | fprintf(f, "\n"); | |
1490 | for (i = 0; i < 128; i += 8) { | |
1491 | fprintf(f, "\t0x%02x,", buf[i]); | |
1492 | for (j = 1; j < 8; j++) { | |
1493 | fprintf(f, " 0x%02x,", buf[i + j]); | |
1494 | } | |
1495 | fprintf(f, "\n"); | |
1496 | } | |
1497 | if (!crc_ok(buf)) | |
1498 | fprintf(f, "\t/* Block %u has a checksum error (should be 0x%02x). */\n", | |
1499 | b, crc_calc(buf)); | |
1500 | } | |
1501 | fprintf(f, "};\n"); | |
1502 | } | |
1503 | ||
1504 | // This format can be read by the QuantumData EDID editor | |
1505 | static void xmldumpedid(FILE *f, const unsigned char *edid, unsigned size) | |
1506 | { | |
1507 | fprintf(f, "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n"); | |
1508 | fprintf(f, "<DATAOBJ>\n"); | |
1509 | fprintf(f, " <HEADER TYPE=\"DID\" VERSION=\"1.0\"/>\n"); | |
1510 | fprintf(f, " <DATA>\n"); | |
1511 | for (unsigned b = 0; b < size / 128; b++) { | |
1512 | const unsigned char *buf = edid + 128 * b; | |
1513 | ||
1514 | fprintf(f, " <BLOCK%u>", b); | |
1515 | for (unsigned i = 0; i < 128; i++) | |
1516 | fprintf(f, "%02X", buf[i]); | |
1517 | fprintf(f, "</BLOCK%u>\n", b); | |
1518 | } | |
1519 | fprintf(f, " </DATA>\n"); | |
1520 | fprintf(f, "</DATAOBJ>\n"); | |
1521 | } | |
1522 | ||
1523 | static int edid_to_file(const char *to_file, enum output_format out_fmt) | |
1524 | { | |
1525 | FILE *out; | |
1526 | ||
1527 | if (!strcmp(to_file, "-")) { | |
1528 | to_file = "stdout"; | |
1529 | out = stdout; | |
1530 | } else if ((out = fopen(to_file, "w")) == NULL) { | |
1531 | perror(to_file); | |
1532 | return -1; | |
1533 | } | |
1534 | if (out_fmt == OUT_FMT_DEFAULT) | |
1535 | out_fmt = out == stdout ? OUT_FMT_HEX : OUT_FMT_RAW; | |
1536 | ||
1537 | switch (out_fmt) { | |
1538 | default: | |
1539 | case OUT_FMT_HEX: | |
1540 | hexdumpedid(out, edid, state.edid_size); | |
1541 | break; | |
1542 | case OUT_FMT_RAW: | |
1543 | fwrite(edid, state.edid_size, 1, out); | |
1544 | break; | |
1545 | case OUT_FMT_CARRAY: | |
1546 | carraydumpedid(out, edid, state.edid_size); | |
1547 | break; | |
1548 | case OUT_FMT_XML: | |
1549 | xmldumpedid(out, edid, state.edid_size); | |
1550 | break; | |
1551 | } | |
1552 | ||
1553 | if (out != stdout) | |
1554 | fclose(out); | |
1555 | return 0; | |
1556 | } | |
1557 | ||
1552 | 1558 | enum cvt_opts { |
1553 | 1559 | CVT_WIDTH = 0, |
1554 | 1560 | CVT_HEIGHT, |
2118 | 2124 | return ret ? ret : state.parse_edid(); |
2119 | 2125 | } |
2120 | 2126 | |
2121 | #ifdef __EMSCRIPTEN__ | |
2127 | #else | |
2128 | ||
2122 | 2129 | /* |
2123 | 2130 | * The surrounding JavaScript implementation will call this function |
2124 | 2131 | * each time it wants to decode an EDID. So this should reset all the |
2137 | 2144 | int ret = edid_from_file(input, stderr); |
2138 | 2145 | return ret ? ret : state.parse_edid(); |
2139 | 2146 | } |
2147 | ||
2140 | 2148 | #endif |
158 | 158 | base.sec_gtf_start_freq = 0; |
159 | 159 | base.C = base.M = base.K = base.J = 0; |
160 | 160 | base.max_pos_neg_hor_freq_khz = 0; |
161 | base.uses_srgb = false; | |
161 | 162 | base.detailed_block_cnt = base.dtd_cnt = 0; |
162 | 163 | |
163 | 164 | base.min_display_hor_freq_hz = base.max_display_hor_freq_hz = |
167 | 168 | |
168 | 169 | // CTA-861 block state |
169 | 170 | cta.has_vic_1 = cta.first_svd_might_be_preferred = cta.has_sldb = |
170 | cta.has_hdmi = cta.has_vcdb = cta.has_vfpdb = false; | |
171 | cta.has_hdmi = cta.has_vcdb = cta.has_vfpdb = cta.has_cdb = false; | |
171 | 172 | cta.previous_cta_tag = 0xfff; |
172 | 173 | cta.have_hf_vsdb = cta.have_hf_scdb = false; |
173 | 174 | cta.image_width = cta.image_height = 0; |
208 | 209 | unsigned block_nr; |
209 | 210 | std::string block; |
210 | 211 | std::string data_block; |
212 | unsigned unused_bytes; | |
211 | 213 | bool has_cta; |
212 | 214 | bool has_dispid; |
213 | 215 | bool hide_serial_numbers; |
242 | 244 | double C, M, K, J; |
243 | 245 | bool supports_cvt; |
244 | 246 | bool has_spwg; |
247 | bool uses_srgb; | |
245 | 248 | unsigned detailed_block_cnt; |
246 | 249 | unsigned dtd_cnt; |
247 | 250 | bool seen_non_detailed_descriptor; |
281 | 284 | bool has_hdmi; |
282 | 285 | bool has_vcdb; |
283 | 286 | bool has_vfpdb; |
287 | bool has_cdb; | |
284 | 288 | unsigned preparsed_speaker_count; |
285 | 289 | bool preparsed_sld_has_coord; |
286 | 290 | bool preparsed_sld; |
383 | 387 | void cta_rcdb(const unsigned char *x, unsigned length); |
384 | 388 | void cta_sldb(const unsigned char *x, unsigned length); |
385 | 389 | void cta_preparse_sldb(const unsigned char *x, unsigned length); |
390 | void cta_colorimetry_block(const unsigned char *x, unsigned length); | |
386 | 391 | void cta_hdmi_block(const unsigned char *x, unsigned length); |
387 | 392 | void cta_displayid_type_7(const unsigned char *x, unsigned length); |
388 | 393 | void cta_displayid_type_8(const unsigned char *x, unsigned length); |
495 | 500 | |
496 | 501 | #endif |
497 | 502 | |
498 | void do_checksum(const char *prefix, const unsigned char *x, size_t len); | |
503 | void do_checksum(const char *prefix, const unsigned char *x, size_t len, unsigned unused_bytes = 0); | |
499 | 504 | std::string utohex(unsigned char x); |
500 | 505 | std::string ouitohex(unsigned oui); |
501 | 506 | std::string containerid2s(const unsigned char *x); |
978 | 978 | switch ((flags & 0x18) >> 3) { |
979 | 979 | case 0x00: |
980 | 980 | s_flags = "analog composite"; |
981 | [[clang::fallthrough]]; | |
981 | 982 | /* fall-through */ |
982 | 983 | case 0x01: |
983 | 984 | if (s_flags.empty()) |
1495 | 1496 | fail("sRGB is signaled, but the chromaticities do not match.\n"); |
1496 | 1497 | if (x[0x17] != 120) |
1497 | 1498 | warn("sRGB is signaled, but the gamma != 2.2.\n"); |
1499 | base.uses_srgb = true; | |
1498 | 1500 | } else if (!memcmp(x + 0x19, srgb_chromaticity, sizeof(srgb_chromaticity))) { |
1499 | 1501 | fail("The chromaticities match sRGB, but sRGB is not signaled.\n"); |
1502 | base.uses_srgb = true; | |
1500 | 1503 | } |
1501 | 1504 | |
1502 | 1505 | if (base.edid_minor >= 4) { |
2073 | 2073 | "ST2113RGB", |
2074 | 2074 | }; |
2075 | 2075 | |
2076 | static void cta_colorimetry_block(const unsigned char *x, unsigned length) | |
2076 | void edid_state::cta_colorimetry_block(const unsigned char *x, unsigned length) | |
2077 | 2077 | { |
2078 | 2078 | unsigned i; |
2079 | 2079 | |
2089 | 2089 | for (i = 0; i < ARRAY_SIZE(colorimetry2_map); i++) |
2090 | 2090 | if (x[1] & (1 << i)) |
2091 | 2091 | printf(" %s\n", colorimetry2_map[i]); |
2092 | // The sRGB bit (added in CTA-861.6) allows sources to explicitly | |
2093 | // signal sRGB colorimetry. Without this the default colorimetry | |
2094 | // of an RGB video is either sRGB or defaultRGB. It depends on the | |
2095 | // Source which is used, and the Sink has no idea what it is getting. | |
2096 | // | |
2097 | // For proper compatibility with PCs enabling sRGB support is | |
2098 | // desirable. | |
2099 | if (!base.uses_srgb && !(x[1] & 0x20)) | |
2100 | warn("Set the sRGB colorimetry bit to avoid interop issues.\n"); | |
2092 | 2101 | } |
2093 | 2102 | |
2094 | 2103 | static const char *eotf_map[] = { |
2560 | 2569 | case 0x07: |
2561 | 2570 | if (x[i + 1] == 0x0d) |
2562 | 2571 | cta.has_vfpdb = true; |
2572 | if (x[i + 1] == 0x05) | |
2573 | cta.has_cdb = true; | |
2563 | 2574 | if (x[i + 1] == 0x13 && (x[i + 2] & 0x40)) { |
2564 | 2575 | cta.preparsed_speaker_count = 1 + (x[i + 2] & 0x1f); |
2565 | 2576 | cta.preparsed_sld = x[i + 2] & 0x20; |
2576 | 2587 | if (x[i + 1] != 0x0e) |
2577 | 2588 | continue; |
2578 | 2589 | for_ycbcr420 = true; |
2590 | [[clang::fallthrough]]; | |
2579 | 2591 | /* fall-through */ |
2580 | 2592 | case 0x02: |
2581 | 2593 | for (unsigned j = 1 + for_ycbcr420; j <= (x[i] & 0x1f); j++) { |
2689 | 2701 | } |
2690 | 2702 | detailed_block(detailed); |
2691 | 2703 | } |
2692 | if (!memchk(detailed, x + 127 - detailed)) { | |
2704 | unused_bytes = x + 127 - detailed; | |
2705 | if (!memchk(detailed, unused_bytes)) { | |
2693 | 2706 | data_block = "Padding"; |
2694 | fail("CTA-861 padding contains non-zero bytes.\n"); | |
2707 | fail("Contains non-zero bytes.\n"); | |
2695 | 2708 | } |
2696 | 2709 | } while (0); |
2697 | 2710 | |
2706 | 2719 | fail("HDMI VIC Codes must have their CTA-861 VIC equivalents in the VSB.\n"); |
2707 | 2720 | if (!cta.has_vcdb) |
2708 | 2721 | fail("Missing VCDB, needed for Set Selectable RGB Quantization to avoid interop issues.\n"); |
2722 | if (!base.uses_srgb && !cta.has_cdb) | |
2723 | warn("Add a Colorimetry Data Block with the sRGB colorimetry bit set to avoid interop issues.\n"); | |
2709 | 2724 | } |
2710 | 2725 | |
2711 | 2726 | void edid_state::cta_resolve_svr(vec_timings_ext::iterator iter) |
2021 | 2021 | data_block.clear(); |
2022 | 2022 | do_checksum(" ", x + 1, x[2] + 5); |
2023 | 2023 | |
2024 | if (!memchk(x + 1 + x[2] + 5, 0x7f - (1 + x[2] + 5))) { | |
2024 | unused_bytes = 0x7f - (1 + x[2] + 5); | |
2025 | if (!memchk(x + 1 + x[2] + 5, unused_bytes)) { | |
2025 | 2026 | data_block = "Padding"; |
2026 | fail("DisplayID padding contains non-zero bytes.\n"); | |
2027 | fail("Contains non-zero bytes.\n"); | |
2027 | 2028 | } |
2028 | 2029 | dispid.is_base_block = false; |
2029 | 2030 | } |
63 | 63 | parse_string_table(x + 1); |
64 | 64 | x += x[0]; |
65 | 65 | } |
66 | if (!memchk(x, orig + 127 - x)) { | |
66 | unused_bytes = orig + 127 - x; | |
67 | if (!memchk(x, unused_bytes)) { | |
67 | 68 | data_block.clear(); |
68 | 69 | fail("Non-zero values in unused space.\n"); |
69 | 70 | } |
54 | 54 | print_standard_timing(" ", x[0], x[1], true); |
55 | 55 | } |
56 | 56 | } |
57 | unused_bytes = y - x; | |
58 | if (!memchk(x, unused_bytes)) { | |
59 | data_block = "Padding"; | |
60 | fail("Contains non-zero bytes.\n"); | |
61 | } | |
57 | 62 | } |
20 | 20 | <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> |
21 | 21 | <ConfigurationType>Application</ConfigurationType> |
22 | 22 | <UseDebugLibraries>true</UseDebugLibraries> |
23 | <PlatformToolset>v142</PlatformToolset> | |
23 | <PlatformToolset>v143</PlatformToolset> | |
24 | 24 | <CharacterSet>Unicode</CharacterSet> |
25 | 25 | </PropertyGroup> |
26 | 26 | <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> |
27 | 27 | <ConfigurationType>Application</ConfigurationType> |
28 | 28 | <UseDebugLibraries>false</UseDebugLibraries> |
29 | <PlatformToolset>v142</PlatformToolset> | |
29 | <PlatformToolset>v143</PlatformToolset> | |
30 | 30 | <WholeProgramOptimization>true</WholeProgramOptimization> |
31 | 31 | <CharacterSet>Unicode</CharacterSet> |
32 | 32 | </PropertyGroup> |
84 | 84 | <ConformanceMode>true</ConformanceMode> |
85 | 85 | <AdditionalIncludeDirectories>$(ProjectDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> |
86 | 86 | <DisableSpecificWarnings>4244; 4018; 4267; 4996; 26451; 6385; 6001</DisableSpecificWarnings> |
87 | <RuntimeLibrary>MultiThreaded</RuntimeLibrary> | |
87 | 88 | </ClCompile> |
88 | 89 | <Link> |
89 | 90 | <SubSystem>Console</SubSystem> |
93 | 94 | </Link> |
94 | 95 | </ItemDefinitionGroup> |
95 | 96 | <ItemGroup> |
97 | <ClCompile Include="..\calc-gtf-cvt.cpp" /> | |
98 | <ClCompile Include="..\calc-ovt.cpp" /> | |
96 | 99 | <ClCompile Include="getopt.c" /> |
97 | 100 | <ClCompile Include="..\edid-decode.cpp" /> |
98 | 101 | <ClCompile Include="..\parse-base-block.cpp" /> |
101 | 104 | <ClCompile Include="..\parse-displayid-block.cpp" /> |
102 | 105 | <ClCompile Include="..\parse-ls-ext-block.cpp" /> |
103 | 106 | <ClCompile Include="..\parse-vtb-ext-block.cpp" /> |
107 | <ClCompile Include="getsubopt.c" /> | |
104 | 108 | </ItemGroup> |
105 | 109 | <ItemGroup> |
110 | <ClInclude Include="..\oui.h" /> | |
106 | 111 | <ClInclude Include="getopt.h" /> |
107 | 112 | <ClInclude Include="unistd.h" /> |
108 | 113 | <ClInclude Include="..\edid-decode.h" /> |
33 | 33 | <ClCompile Include="..\edid-decode.cpp"> |
34 | 34 | <Filter>edid-decode</Filter> |
35 | 35 | </ClCompile> |
36 | <ClCompile Include="getsubopt.c"> | |
37 | <Filter>windows-unix</Filter> | |
38 | </ClCompile> | |
39 | <ClCompile Include="..\calc-gtf-cvt.cpp"> | |
40 | <Filter>edid-decode</Filter> | |
41 | </ClCompile> | |
42 | <ClCompile Include="..\calc-ovt.cpp"> | |
43 | <Filter>edid-decode</Filter> | |
44 | </ClCompile> | |
36 | 45 | </ItemGroup> |
37 | 46 | <ItemGroup> |
38 | 47 | <ClInclude Include="..\edid-decode.h"> |
44 | 53 | <ClInclude Include="unistd.h"> |
45 | 54 | <Filter>windows-unix</Filter> |
46 | 55 | </ClInclude> |
56 | <ClInclude Include="..\oui.h"> | |
57 | <Filter>edid-decode</Filter> | |
58 | </ClInclude> | |
47 | 59 | </ItemGroup> |
48 | 60 | </Project>⏎ |
89 | 89 | |
90 | 90 | extern int getopt_long( int, char * const [], const char *, const struct option *, int * ); |
91 | 91 | extern int getopt_long_only( int, char * const [], const char *, const struct option *, int * ); |
92 | ||
93 | extern int getsubopt(char** opt, char* const* keys, char** val); | |
94 | ||
92 | 95 | /* |
93 | 96 | * Previous MinGW implementation had... |
94 | 97 | */ |
0 | /** | |
1 | * Copyright © 2005-2020 Rich Felker, et al. | |
2 | * | |
3 | * Permission is hereby granted, free of charge, to any person obtaining | |
4 | * a copy of this software and associated documentation files (the | |
5 | * "Software"), to deal in the Software without restriction, including | |
6 | * without limitation the rights to use, copy, modify, merge, publish, | |
7 | * distribute, sublicense, and/or sell copies of the Software, and to | |
8 | * permit persons to whom the Software is furnished to do so, subject to | |
9 | * the following conditions: | |
10 | * | |
11 | * The above copyright notice and this permission notice shall be | |
12 | * included in all copies or substantial portions of the Software. | |
13 | * | |
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | |
15 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |
16 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | |
17 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY | |
18 | * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, | |
19 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE | |
20 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | |
21 | */ | |
22 | ||
23 | #include <stdlib.h> | |
24 | #include <string.h> | |
25 | ||
26 | int getsubopt(char** opt, char* const* keys, char** val) | |
27 | { | |
28 | char* s = *opt; | |
29 | int i; | |
30 | ||
31 | *val = NULL; | |
32 | *opt = strchr(s, ','); | |
33 | if (*opt) *(*opt)++ = 0; | |
34 | else *opt = s + strlen(s); | |
35 | ||
36 | for (i = 0; keys[i]; i++) { | |
37 | size_t l = strlen(keys[i]); | |
38 | if (strncmp(keys[i], s, l)) continue; | |
39 | if (s[l] == '=') | |
40 | *val = s + l + 1; | |
41 | else if (s[l]) continue; | |
42 | return i; | |
43 | } | |
44 | return -1; | |
45 | } |