// File: /workspace/github_cpp_makefile_star2_O2/AndreRenaud[P]simple_uart/simple_uart.c
// Function: simple_uart_describe
int simple_uart_describe(const char *uart, char *description, size_t max_desc_len)
{
    if (!uart || !description || max_desc_len == 0)
        return -EINVAL;

#if defined(_WIN32) || defined(__linux__)
    char chrBuf[256]; // help buffer
#endif

    description[0] = '\0'; // empty string

// Windows Implementation
#if defined(_WIN32)
    int intMatchUart = 0; // device on machine matched
    HDEVINFO deviceInfoSet;
    DWORD i;

    /*  Get handle of device information
     *    @see https://learn.microsoft.com/en-us/windows/win32/api/setupapi/nf-setupapi-setupdigetclassdevsa
     *    *A: Ansi Function, *W: Unicode function
     */
    deviceInfoSet = SetupDiGetClassDevsA((const GUID *)&GUID_DEVCLASS_PORTS, NULL, NULL, DIGCF_PRESENT);
    if (INVALID_HANDLE_VALUE == deviceInfoSet) {
        return -1;
    }
    /* get device info */
    SP_DEVINFO_DATA deviceInfoData;
    deviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
    /*  iterate over DEVCLASS_PORTS elements
     *    @see
     * https://learn.microsoft.com/en-us/windows/win32/api/setupapi/nf-setupapi-setupdigetdeviceregistrypropertya
     */
    i = 0;
    while (SetupDiEnumDeviceInfo(deviceInfoSet, i, &deviceInfoData)) {
        /* get user friendly name */
        if (SetupDiGetDeviceRegistryPropertyA(deviceInfoSet, &deviceInfoData, SPDRP_FRIENDLYNAME, NULL, (PBYTE)chrBuf,
                                              sizeof(chrBuf), NULL)) {
            /* match by name */
            if (strstr(chrBuf, uart) != NULL) { // mark as name hit and leave
                intMatchUart = 1;
                break;
            }
        } else {
            return win32_errno();
        }
        ++i;
    }
    /* no match by name */
    if (0 == intMatchUart)
        return 0;
    /*  acquire HW ID
     *    f.e. USB\VID_04D8&PID_FFEE&REV_0100
     */
    if (SetupDiGetDeviceRegistryPropertyA(deviceInfoSet, &deviceInfoData, SPDRP_HARDWAREID, NULL, (PBYTE)chrBuf,
                                          sizeof(chrBuf), NULL)) {
        /* help */
        char chrId[5];     // extract VID/PID from HWID string
        const char *pHelp; // string matching
        /* PID */
        pHelp = strstr(chrBuf, "PID_"); // search for string
        if (NULL != pHelp) {
            strncpy(chrId, pHelp + 4, 4); // copy ID
            chrId[4] = '\0';
            snprintf(description + strlen(description), max_desc_len - strlen(description), "PID=%s,", chrId);
        }
        /* VID */
        pHelp = strstr(chrBuf, "VID_"); // search for string
        if (NULL != pHelp) {
            strncpy(chrId, pHelp + 4, 4); // copy ID
            chrId[4] = '\0';
            snprintf(description + strlen(description), max_desc_len - strlen(description), "VID=%s,", chrId);
        }
    }
    // Append next required property here
// Linux Implementation
#elif defined(__linux__)
    char unresolvedPath[PATH_MAX]; // symbolic path to TTY device
    char basePath[PATH_MAX];       // path to read out file
    char pathUp[32];               // number of hierarchy level ups
    char *ptrHelp;                 // help pointer
    int intCnt = 0;                // counts occurrence of device name
    /* assemble real path */
    snprintf(unresolvedPath, sizeof(unresolvedPath), "/sys/class/tty/%s", basename((char *)uart));
    if (!(NULL != realpath(unresolvedPath, basePath))) { // resolve symbolic link
        return -1;
    }
    // result: /sys/devices/pci0000:00/0000:00:06.0/usb2/2-2/2-2:1.0/tty/ttyACM0
    //         /sys/devices/pci0000:00/0000:00:06.0/usb2/2-2/2-2:1.0/ttyUSB0/tty/ttyUSB0
    /* determine number of dropped subdirs */
    ptrHelp = strstr(basePath, basename((char *)uart));
    while (NULL != ptrHelp) {
        ++intCnt;
        ptrHelp = strstr(ptrHelp + 1, basename((char *)uart));
    }
    strncpy(pathUp, "/../../", sizeof(pathUp));
    for (int i = 0; i < intCnt; i++) {
        strncpy(pathUp + strlen(pathUp), "../", sizeof(pathUp) - strlen(pathUp)); // append '../' for going up
    }
    /* drop counted number of subdirs */
    strncpy(unresolvedPath, basePath, sizeof(unresolvedPath));
    strncpy(unresolvedPath + strlen(unresolvedPath), pathUp, sizeof(unresolvedPath) - strlen(unresolvedPath));
    if (!(NULL != realpath(unresolvedPath, basePath))) { // resolve relative path
        return -1;
    }
    // result: /sys/devices/pci0000:00/0000:00:06.0/usb2/2-2
    /* acquire device specific info */
    if (readfile(basePath, "manufacturer", chrBuf, sizeof(chrBuf))) {
        snprintf(description + strlen(description), max_desc_len - strlen(description), "manufacturer='%s',", chrBuf);
    }
    if (readfile(basePath, "product", chrBuf, sizeof(chrBuf))) {
        snprintf(description + strlen(description), max_desc_len - strlen(description), "product='%s',", chrBuf);
    }
    if (readfile(basePath, "idProduct", chrBuf, sizeof(chrBuf))) {
        snprintf(description + strlen(description), max_desc_len - strlen(description), "PID=%s,", chrBuf);
    }
    if (readfile(basePath, "idVendor", chrBuf, sizeof(chrBuf))) {
        snprintf(description + strlen(description), max_desc_len - strlen(description), "VID=%s,", chrBuf);
    }
    if (readfile(basePath, "serial", chrBuf, sizeof(chrBuf))) {
        snprintf(description + strlen(description), max_desc_len - strlen(description), "serial=%s,", chrBuf);
    }
// MacOS
#else // Volunteers for MacOS wanted

#endif
    /* drop last ',' */
    if (0 < strlen(description)) {
        description[strlen(description) - 1] = '\0';
    }
    /* normal end */
    return 0;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x2138, %rsp           # imm = 0x2138
testq %rdi, %rdi
sete %al
testq %rsi, %rsi
sete %cl
orb %al, %cl
testq %rdx, %rdx
sete %al
orb %cl, %al
je 0x5c57
pushq $-0x16
popq %rbp
jmp 0x5eed
movq %rdx, %r14
movq %rsi, %rbx
movq %rdi, %r15
movb $0x0, (%rsi)
callq 0x2280
leaq 0x2716(%rip), %rdx      # 0x8385
xorl %r13d, %r13d
leaq 0x1130(%rsp), %r12
movl $0x1000, %esi           # imm = 0x1000
movq %r12, %rdi
movq %rax, %rcx
xorl %eax, %eax
callq 0x2190
leaq 0x130(%rsp), %rsi
movq %r12, %rdi
callq 0x2260
pushq $-0x1
popq %rbp
testq %rax, %rax
je 0x5eed
movq %r15, %rdi
callq 0x2280
leaq 0x130(%rsp), %rdi
movq %rax, %rsi
callq 0x23d0
movq %rax, %r12
testq %rax, %rax
je 0x5cdb
incl %r13d
incq %r12
movq %r15, %rdi
callq 0x2280
movq %r12, %rdi
jmp 0x5cb8
movq %r14, 0x8(%rsp)
movups 0x2651(%rip), %xmm0     # 0x8338
leaq 0x10(%rsp), %r15
movaps %xmm0, 0x10(%r15)
movups 0x2630(%rip), %xmm0     # 0x8328
movaps %xmm0, (%r15)
pushq $0x20
popq %r14
leaq 0x2690(%rip), %r12      # 0x8397
subl $0x1, %r13d
jb 0x5d2d
movq %r15, %rdi
callq 0x2150
leaq (%rsp,%rax), %rdi
addq $0x10, %rdi
movq %r14, %rdx
subq %rax, %rdx
movq %r12, %rsi
callq 0x2080
jmp 0x5d07
leaq 0x1130(%rsp), %r15
leaq 0x130(%rsp), %r12
movl $0x1000, %r13d          # imm = 0x1000
movl $0x1000, %edx           # imm = 0x1000
movq %r15, %rdi
movq %r12, %rsi
callq 0x2080
movq %r15, %rdi
callq 0x2150
leaq (%rsp,%rax), %rdi
addq $0x1130, %rdi           # imm = 0x1130
subq %rax, %r13
leaq 0x10(%rsp), %rsi
movq %r13, %rdx
callq 0x2080
movq %r15, %rdi
movq %r12, %rsi
callq 0x2260
testq %rax, %rax
je 0x5eed
leaq 0x260a(%rip), %rsi      # 0x839b
leaq 0x130(%rsp), %rdi
leaq 0x30(%rsp), %rdx
callq 0x5f01
testb %al, %al
movq 0x8(%rsp), %r14
je 0x5dd1
movq %rbx, %rdi
callq 0x2150
leaq (%rbx,%rax), %rdi
movq %r14, %rsi
subq %rax, %rsi
leaq 0x25e3(%rip), %rdx      # 0x83a8
leaq 0x30(%rsp), %rcx
xorl %eax, %eax
callq 0x2190
leaq 0x25e3(%rip), %rsi      # 0x83bb
leaq 0x130(%rsp), %rdi
leaq 0x30(%rsp), %rdx
callq 0x5f01
testb %al, %al
je 0x5e13
movq %rbx, %rdi
callq 0x2150
leaq (%rbx,%rax), %rdi
movq %r14, %rsi
subq %rax, %rsi
leaq 0x25bc(%rip), %rdx      # 0x83c3
leaq 0x30(%rsp), %rcx
xorl %eax, %eax
callq 0x2190
leaq 0x25b7(%rip), %rsi      # 0x83d1
leaq 0x130(%rsp), %rdi
leaq 0x30(%rsp), %rdx
callq 0x5f01
testb %al, %al
je 0x5e55
movq %rbx, %rdi
callq 0x2150
leaq (%rbx,%rax), %rdi
movq %r14, %rsi
subq %rax, %rsi
leaq 0x2592(%rip), %rdx      # 0x83db
leaq 0x30(%rsp), %rcx
xorl %eax, %eax
callq 0x2190
leaq 0x2587(%rip), %rsi      # 0x83e3
leaq 0x130(%rsp), %rdi
leaq 0x30(%rsp), %rdx
callq 0x5f01
testb %al, %al
je 0x5e97
movq %rbx, %rdi
callq 0x2150
leaq (%rbx,%rax), %rdi
movq %r14, %rsi
subq %rax, %rsi
leaq 0x2561(%rip), %rdx      # 0x83ec
leaq 0x30(%rsp), %rcx
xorl %eax, %eax
callq 0x2190
leaq 0x2556(%rip), %rsi      # 0x83f4
leaq 0x130(%rsp), %rdi
leaq 0x30(%rsp), %rdx
callq 0x5f01
testb %al, %al
je 0x5ed9
movq %rbx, %rdi
callq 0x2150
leaq (%rbx,%rax), %rdi
subq %rax, %r14
leaq 0x2531(%rip), %rdx      # 0x83fb
leaq 0x30(%rsp), %rcx
movq %r14, %rsi
xorl %eax, %eax
callq 0x2190
movq %rbx, %rdi
callq 0x2150
xorl %ebp, %ebp
testq %rax, %rax
je 0x5eed
movb $0x0, -0x1(%rbx,%rax)
movl %ebp, %eax
addq $0x2138, %rsp           # imm = 0x2138
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq