// File: 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
movq %rsp, %rbp
subq $0x2210, %rsp           # imm = 0x2210
movq %rdi, -0x10(%rbp)
movq %rsi, -0x18(%rbp)
movq %rdx, -0x20(%rbp)
cmpq $0x0, -0x10(%rbp)
je 0x768c
cmpq $0x0, -0x18(%rbp)
je 0x768c
cmpq $0x0, -0x20(%rbp)
jne 0x7698
movl $0xffffffea, -0x4(%rbp) # imm = 0xFFFFFFEA
jmp 0x7b9d
movq -0x18(%rbp), %rax
movb $0x0, (%rax)
movl $0x0, -0x214c(%rbp)
leaq -0x1120(%rbp), %rax
movq %rax, -0x2158(%rbp)
movq -0x10(%rbp), %rdi
callq 0x2260
movq -0x2158(%rbp), %rdi
movq %rax, %rcx
movl $0x1000, %esi           # imm = 0x1000
leaq 0x2c72(%rip), %rdx      # 0xa348
movb $0x0, %al
callq 0x2170
leaq -0x1120(%rbp), %rdi
leaq -0x2120(%rbp), %rsi
callq 0x2240
movq %rax, %rcx
xorl %eax, %eax
cmpq %rcx, %rax
jne 0x7706
movl $0xffffffff, -0x4(%rbp) # imm = 0xFFFFFFFF
jmp 0x7b9d
leaq -0x2120(%rbp), %rax
movq %rax, -0x2160(%rbp)
movq -0x10(%rbp), %rdi
callq 0x2260
movq -0x2160(%rbp), %rdi
movq %rax, %rsi
callq 0x23b0
movq %rax, -0x2148(%rbp)
xorl %eax, %eax
cmpq -0x2148(%rbp), %rax
je 0x7780
movl -0x214c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x214c(%rbp)
movq -0x2148(%rbp), %rax
addq $0x1, %rax
movq %rax, -0x2168(%rbp)
movq -0x10(%rbp), %rdi
callq 0x2260
movq -0x2168(%rbp), %rdi
movq %rax, %rsi
callq 0x23b0
movq %rax, -0x2148(%rbp)
jmp 0x7733
leaq -0x2140(%rbp), %rdi
leaq 0x2bcc(%rip), %rsi      # 0xa35a
movl $0x20, %edx
callq 0x2070
movl $0x0, -0x2150(%rbp)
movl -0x2150(%rbp), %eax
cmpl -0x214c(%rbp), %eax
jge 0x7816
leaq -0x2140(%rbp), %rax
movq %rax, -0x2178(%rbp)
leaq -0x2140(%rbp), %rdi
callq 0x2130
movq %rax, %rcx
movq -0x2178(%rbp), %rax
addq %rcx, %rax
movq %rax, -0x2170(%rbp)
leaq -0x2140(%rbp), %rdi
callq 0x2130
movq -0x2170(%rbp), %rdi
movl $0x20, %edx
subq %rax, %rdx
leaq 0x2b5e(%rip), %rsi      # 0xa35e
callq 0x2070
movl -0x2150(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x2150(%rbp)
jmp 0x77a2
leaq -0x1120(%rbp), %rdi
leaq -0x2120(%rbp), %rsi
movl $0x1000, %edx           # imm = 0x1000
callq 0x2070
leaq -0x1120(%rbp), %rax
movq %rax, -0x2190(%rbp)
leaq -0x1120(%rbp), %rdi
callq 0x2130
movq %rax, %rcx
movq -0x2190(%rbp), %rax
addq %rcx, %rax
movq %rax, -0x2188(%rbp)
leaq -0x2140(%rbp), %rax
movq %rax, -0x2180(%rbp)
leaq -0x1120(%rbp), %rdi
callq 0x2130
movq -0x2188(%rbp), %rdi
movq -0x2180(%rbp), %rsi
movl $0x1000, %edx           # imm = 0x1000
subq %rax, %rdx
callq 0x2070
leaq -0x1120(%rbp), %rdi
leaq -0x2120(%rbp), %rsi
callq 0x2240
movq %rax, %rcx
xorl %eax, %eax
cmpq %rcx, %rax
jne 0x78ba
movl $0xffffffff, -0x4(%rbp) # imm = 0xFFFFFFFF
jmp 0x7b9d
leaq -0x2120(%rbp), %rdi
leaq -0x120(%rbp), %rdx
leaq 0x2a93(%rip), %rsi      # 0xa362
movl $0x100, %ecx            # imm = 0x100
callq 0x7bb0
testb $0x1, %al
jne 0x78df
jmp 0x7941
movq -0x18(%rbp), %rax
movq %rax, -0x21a8(%rbp)
movq -0x18(%rbp), %rdi
callq 0x2130
movq %rax, %rcx
movq -0x21a8(%rbp), %rax
addq %rcx, %rax
movq %rax, -0x2198(%rbp)
movq -0x20(%rbp), %rax
movq %rax, -0x21a0(%rbp)
movq -0x18(%rbp), %rdi
callq 0x2130
movq -0x21a0(%rbp), %rsi
movq -0x2198(%rbp), %rdi
subq %rax, %rsi
leaq -0x120(%rbp), %rcx
leaq 0x2a35(%rip), %rdx      # 0xa36f
movb $0x0, %al
callq 0x2170
leaq -0x2120(%rbp), %rdi
leaq -0x120(%rbp), %rdx
leaq 0x2a2c(%rip), %rsi      # 0xa382
movl $0x100, %ecx            # imm = 0x100
callq 0x7bb0
testb $0x1, %al
jne 0x7966
jmp 0x79c8
movq -0x18(%rbp), %rax
movq %rax, -0x21c0(%rbp)
movq -0x18(%rbp), %rdi
callq 0x2130
movq %rax, %rcx
movq -0x21c0(%rbp), %rax
addq %rcx, %rax
movq %rax, -0x21b0(%rbp)
movq -0x20(%rbp), %rax
movq %rax, -0x21b8(%rbp)
movq -0x18(%rbp), %rdi
callq 0x2130
movq -0x21b8(%rbp), %rsi
movq -0x21b0(%rbp), %rdi
subq %rax, %rsi
leaq -0x120(%rbp), %rcx
leaq 0x29c9(%rip), %rdx      # 0xa38a
movb $0x0, %al
callq 0x2170
leaq -0x2120(%rbp), %rdi
leaq -0x120(%rbp), %rdx
leaq 0x29bb(%rip), %rsi      # 0xa398
movl $0x100, %ecx            # imm = 0x100
callq 0x7bb0
testb $0x1, %al
jne 0x79ed
jmp 0x7a4f
movq -0x18(%rbp), %rax
movq %rax, -0x21d8(%rbp)
movq -0x18(%rbp), %rdi
callq 0x2130
movq %rax, %rcx
movq -0x21d8(%rbp), %rax
addq %rcx, %rax
movq %rax, -0x21c8(%rbp)
movq -0x20(%rbp), %rax
movq %rax, -0x21d0(%rbp)
movq -0x18(%rbp), %rdi
callq 0x2130
movq -0x21d0(%rbp), %rsi
movq -0x21c8(%rbp), %rdi
subq %rax, %rsi
leaq -0x120(%rbp), %rcx
leaq 0x295a(%rip), %rdx      # 0xa3a2
movb $0x0, %al
callq 0x2170
leaq -0x2120(%rbp), %rdi
leaq -0x120(%rbp), %rdx
leaq 0x2946(%rip), %rsi      # 0xa3aa
movl $0x100, %ecx            # imm = 0x100
callq 0x7bb0
testb $0x1, %al
jne 0x7a74
jmp 0x7ad6
movq -0x18(%rbp), %rax
movq %rax, -0x21f0(%rbp)
movq -0x18(%rbp), %rdi
callq 0x2130
movq %rax, %rcx
movq -0x21f0(%rbp), %rax
addq %rcx, %rax
movq %rax, -0x21e0(%rbp)
movq -0x20(%rbp), %rax
movq %rax, -0x21e8(%rbp)
movq -0x18(%rbp), %rdi
callq 0x2130
movq -0x21e8(%rbp), %rsi
movq -0x21e0(%rbp), %rdi
subq %rax, %rsi
leaq -0x120(%rbp), %rcx
leaq 0x28e4(%rip), %rdx      # 0xa3b3
movb $0x0, %al
callq 0x2170
leaq -0x2120(%rbp), %rdi
leaq -0x120(%rbp), %rdx
leaq 0x28d0(%rip), %rsi      # 0xa3bb
movl $0x100, %ecx            # imm = 0x100
callq 0x7bb0
testb $0x1, %al
jne 0x7afb
jmp 0x7b5d
movq -0x18(%rbp), %rax
movq %rax, -0x2208(%rbp)
movq -0x18(%rbp), %rdi
callq 0x2130
movq %rax, %rcx
movq -0x2208(%rbp), %rax
addq %rcx, %rax
movq %rax, -0x21f8(%rbp)
movq -0x20(%rbp), %rax
movq %rax, -0x2200(%rbp)
movq -0x18(%rbp), %rdi
callq 0x2130
movq -0x2200(%rbp), %rsi
movq -0x21f8(%rbp), %rdi
subq %rax, %rsi
leaq -0x120(%rbp), %rcx
leaq 0x286c(%rip), %rdx      # 0xa3c2
movb $0x0, %al
callq 0x2170
movq -0x18(%rbp), %rdi
callq 0x2130
movq %rax, %rcx
xorl %eax, %eax
cmpq %rcx, %rax
jae 0x7b96
movq -0x18(%rbp), %rax
movq %rax, -0x2210(%rbp)
movq -0x18(%rbp), %rdi
callq 0x2130
movq %rax, %rcx
movq -0x2210(%rbp), %rax
subq $0x1, %rcx
movb $0x0, (%rax,%rcx)
movl $0x0, -0x4(%rbp)
movl -0x4(%rbp), %eax
addq $0x2210, %rsp           # imm = 0x2210
popq %rbp
retq
nopl (%rax)