int ParseLaunchArguments()

in src/adu-shell/src/main.cpp [59:228]


int ParseLaunchArguments(const int argc, char** argv, ADUShell_LaunchArguments* launchArgs)
{
    if (launchArgs == nullptr)
    {
        return -1;
    }

    int result = 0;
    launchArgs->updateType = nullptr;
    launchArgs->updateAction = nullptr;
    launchArgs->targetData = nullptr;
    launchArgs->logFile = nullptr;
    launchArgs->showVersion = false;

#if _ADU_DEBUG
    launchArgs->logLevel = ADUC_LOG_DEBUG;
#else
    launchArgs->logLevel = ADUC_LOG_INFO;
#endif

    launchArgs->argc = argc;
    launchArgs->argv = argv;

    launchArgs->configFolder = ADUC_CONF_FOLDER;

    while (result == 0)
    {
        // clang-format off

        // "--version"           |   Show adu-shell version number.
        //
        // "--update-type"       |   An ADU Update Type.
        //                             e.g., "microsoft/apt", "microsoft/script", "common".
        //
        // "--update-action"     |   An action to perform.
        //                             e.g., "initialize", "download", "install", "apply", "cancel", "rollback", "reboot".
        //
        // "--target-data"       |   A string contains data for a target command.
        //                             e.g., for microsoft/apt download action, this is a single-quoted string
        //                             contains space-delimited list of package names.
        //
        // "--target-options"    |   Additional options for a target command.
        //
        // "--target-log-folder" |   Some target command requires specific logs storage.
        //
        // "--log-level"         |   Log verbosity level.
        //
        // "--config-folder"     |   Path to the folder containing the ADU configuration files.
        //
        static struct option long_options[] =
        {
            { "version",           no_argument,       nullptr, 'v' },
            { "update-type",       required_argument, nullptr, 't' },
            { "update-action",     required_argument, nullptr, 'a' },
            { "target-data",       required_argument, nullptr, 'd' },
            { "target-options",    required_argument, nullptr, 'o' },
            { "target-log-folder", required_argument, nullptr, 'f' },
            { "log-level",         required_argument, nullptr, 'l' },
            { "config-folder",     required_argument, nullptr, 'F' },
            { nullptr, 0, nullptr, 0 }
        };

        // clang-format on

        /* getopt_long stores the option index here. */
        int option_index = 0;
        int option = getopt_long(argc, argv, "vt:a:d:o:f:l:F;", long_options, &option_index);

        /* Detect the end of the options. */
        if (option == -1)
        {
            break;
        }

        switch (option)
        {
        case 'v':
            launchArgs->showVersion = true;
            break;

        case 't':
            launchArgs->updateType = optarg;
            break;

        case 'F':
            launchArgs->configFolder = optarg;
            break;

        case 'a':
            launchArgs->updateAction = optarg;
            launchArgs->action = ADUShellActionFromString(launchArgs->updateAction);
            break;

        case 'd':
            launchArgs->targetData = optarg;
            break;

        case 'o':
            launchArgs->targetOptions.emplace_back(optarg);
            break;

        case 'f':
            launchArgs->logFile = optarg;
            break;

        case 'l': {
            char* endptr;
            errno = 0; /* To distinguish success/failure after call */
            int64_t logLevel = strtol(optarg, &endptr, 10);
            if (errno != 0 || endptr == optarg || logLevel < ADUC_LOG_DEBUG || logLevel > ADUC_LOG_ERROR)
            {
                printf("Invalid log level after '--log-level' or '-l' option. Expected value: 0-3.");
                result = -1;
            }
            else
            {
                launchArgs->logLevel = static_cast<ADUC_LOG_SEVERITY>(logLevel);
            }

            break;
        }

        case '?':
            switch (optopt)
            {
            case 't':
                printf("Missing an Update Type string after '--update-type' or '-t' option.");
                break;
            case 'd':
                printf("Missing a target data string after '--target-data' or '-d' option. Expected quoted string.");
                break;
            case 'o':
                printf(
                    "Missing a target options string after '--target-options' or '-o' option. Expected quoted string.");
                break;
            case 'l':
                printf("Invalid log level after '--log-level' or '-l' option. Expected value: 0-3.");
                break;
            case 'f':
                printf("Missing a log folder path after '--target-log-folder' or '-f' option.");
                break;
            case 'F':
                printf("Missing a config folder path after '--config-folder' or '-c' option.");
                break;
            default:
                printf("Missing an option value after -%c.\n", optopt);
                break;
            }
            result = -1;
            break;

        default:
            printf("Ignoring unknown argument: character code %d", option);
        }
    }

    if (launchArgs->updateType == nullptr)
    {
        printf("Missing --update-type option.\n");
        result = -1;
    }

    if (launchArgs->updateAction == nullptr)
    {
        printf("Missing --update-action option.\n");
        result = -1;
    }

    return result;
}