[host] added option parsing to application

This commit is contained in:
Geoffrey McRae 2017-11-16 20:53:22 +11:00
parent 71c6e5d317
commit 6eb40a1897
15 changed files with 462 additions and 94 deletions

View File

@ -18,11 +18,7 @@ Place, Suite 330, Boston, MA 02111-1307 USA
#include <stdio.h> #include <stdio.h>
#ifdef DEBUG #define DEBUG_PRINT(type, fmt, ...) do {fprintf(stderr, type " %20s:%-5u | %-24s | " fmt "\n", __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__);} while (0)
#define DEBUG_PRINT(type, fmt, ...) do {fprintf(stderr, type " %20s:%-5u | %-24s | " fmt "\n", __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__);} while (0)
#else
#define DEBUG_PRINT(type, fmt, ...) do {} while(0)
#endif
#define DEBUG_INFO(fmt, ...) DEBUG_PRINT("[I]", fmt, ##__VA_ARGS__) #define DEBUG_INFO(fmt, ...) DEBUG_PRINT("[I]", fmt, ##__VA_ARGS__)
#define DEBUG_WARN(fmt, ...) DEBUG_PRINT("[W]", fmt, ##__VA_ARGS__) #define DEBUG_WARN(fmt, ...) DEBUG_PRINT("[W]", fmt, ##__VA_ARGS__)

View File

@ -22,6 +22,7 @@ using namespace Capture;
#include "common\debug.h" #include "common\debug.h"
DXGI::DXGI() : DXGI::DXGI() :
m_options(NULL),
m_initialized(false), m_initialized(false),
m_dxgiFactory(NULL), m_dxgiFactory(NULL),
m_device(NULL), m_device(NULL),
@ -37,11 +38,12 @@ DXGI::~DXGI()
} }
bool DXGI::Initialize() bool DXGI::Initialize(CaptureOptions * options)
{ {
if (m_initialized) if (m_initialized)
DeInitialize(); DeInitialize();
m_options = options;
HRESULT status; HRESULT status;
status = CreateDXGIFactory1(__uuidof(IDXGIFactory1), (void **)(&m_dxgiFactory)); status = CreateDXGIFactory1(__uuidof(IDXGIFactory1), (void **)(&m_dxgiFactory));
@ -208,7 +210,7 @@ bool DXGI::ReInitialize()
*/ */
Sleep(200); Sleep(200);
return Initialize(); return Initialize(m_options);
} }
FrameType DXGI::GetFrameType() FrameType DXGI::GetFrameType()

View File

@ -33,7 +33,10 @@ namespace Capture
public: public:
DXGI(); DXGI();
~DXGI(); ~DXGI();
bool Initialize();
const char * GetName() { return "DXGI"; }
bool Initialize(CaptureOptions * options);
void DeInitialize(); void DeInitialize();
enum FrameType GetFrameType(); enum FrameType GetFrameType();
enum FrameComp GetFrameCompression(); enum FrameComp GetFrameCompression();
@ -41,6 +44,8 @@ namespace Capture
bool GrabFrame(struct FrameInfo & frame); bool GrabFrame(struct FrameInfo & frame);
private: private:
CaptureOptions * m_options;
bool ReInitialize(); bool ReInitialize();
bool m_initialized; bool m_initialized;

View File

@ -31,6 +31,8 @@ using namespace Capture;
#endif #endif
NvFBC::NvFBC() : NvFBC::NvFBC() :
m_options(NULL),
m_optNoCrop(false),
m_initialized(false), m_initialized(false),
m_hDLL(NULL), m_hDLL(NULL),
m_nvFBC(NULL) m_nvFBC(NULL)
@ -41,11 +43,18 @@ NvFBC::~NvFBC()
{ {
} }
bool NvFBC::Initialize() bool NvFBC::Initialize(CaptureOptions * options)
{ {
if (m_initialized) if (m_initialized)
DeInitialize(); DeInitialize();
m_options = options;
m_optNoCrop = false;
for (CaptureOptions::const_iterator it = options->begin(); it != options->end(); ++it)
{
if (_strcmpi(*it, "nocrop") == 0) { m_optNoCrop = true; continue; }
}
std::string nvfbc = Util::GetSystemRoot() + "\\" + NVFBC_LIBRARY_NAME; std::string nvfbc = Util::GetSystemRoot() + "\\" + NVFBC_LIBRARY_NAME;
m_hDLL = LoadLibraryA(nvfbc.c_str()); m_hDLL = LoadLibraryA(nvfbc.c_str());
if (!m_hDLL) if (!m_hDLL)
@ -221,15 +230,30 @@ bool NvFBC::GrabFrame(struct FrameInfo & frame)
NVFBCRESULT status = m_nvFBC->NvFBCToSysGrabFrame(&m_grabFrameParams); NVFBCRESULT status = m_nvFBC->NvFBCToSysGrabFrame(&m_grabFrameParams);
if (status == NVFBC_SUCCESS) if (status == NVFBC_SUCCESS)
{ {
const unsigned int realHeight = min(m_grabInfo.dwHeight, desktop.bottom - desktop.top ); unsigned int dataWidth;
const unsigned int realWidth = min(m_grabInfo.dwWidth , desktop.right - desktop.left); unsigned int dataOffset;
const unsigned int dataWidth = realWidth * 3;
const unsigned int dataOffset = if (m_optNoCrop)
(((m_grabInfo.dwHeight - realHeight) >> 1) * m_grabInfo.dwBufferWidth + {
((m_grabInfo.dwWidth - realWidth ) >> 1)) * 3; dataWidth = m_grabInfo.dwWidth * 3;
dataOffset = 0;
frame.width = m_grabInfo.dwWidth;
frame.height = m_grabInfo.dwHeight;
}
else
{
const unsigned int realHeight = min(m_grabInfo.dwHeight, (unsigned int)(desktop.bottom - desktop.top));
const unsigned int realWidth = min(m_grabInfo.dwWidth , (unsigned int)(desktop.right - desktop.left));
dataWidth = realWidth * 3;
dataOffset =
(((m_grabInfo.dwHeight - realHeight) >> 1) * m_grabInfo.dwBufferWidth +
((m_grabInfo.dwWidth - realWidth ) >> 1)) * 3;
frame.width = realWidth;
frame.height = realHeight;
}
frame.width = realWidth;
frame.height = realHeight;
frame.stride = frame.width; frame.stride = frame.width;
frame.outSize = frame.width * frame.height * 3; frame.outSize = frame.width * frame.height * 3;
@ -251,7 +275,7 @@ bool NvFBC::GrabFrame(struct FrameInfo & frame)
{ {
DEBUG_WARN("Session was invalidated, attempting to restart"); DEBUG_WARN("Session was invalidated, attempting to restart");
DeInitialize(); DeInitialize();
if (!Initialize()) if (!Initialize(m_options))
{ {
DEBUG_ERROR("Failed to re-iniaialize"); DEBUG_ERROR("Failed to re-iniaialize");
return false; return false;

View File

@ -33,7 +33,9 @@ namespace Capture
NvFBC(); NvFBC();
~NvFBC(); ~NvFBC();
bool Initialize(); const char * GetName() { return "NvFBC"; }
bool Initialize(CaptureOptions * options);
void DeInitialize(); void DeInitialize();
enum FrameType GetFrameType(); enum FrameType GetFrameType();
enum FrameComp GetFrameCompression(); enum FrameComp GetFrameCompression();
@ -41,6 +43,9 @@ namespace Capture
bool GrabFrame(struct FrameInfo & frame); bool GrabFrame(struct FrameInfo & frame);
private: private:
CaptureOptions * m_options;
bool m_optNoCrop;
bool m_initialized; bool m_initialized;
HMODULE m_hDLL; HMODULE m_hDLL;

View File

@ -20,6 +20,7 @@ Place, Suite 330, Boston, MA 02111-1307 USA
#define W32_LEAN_AND_MEAN #define W32_LEAN_AND_MEAN
#include <Windows.h> #include <Windows.h>
#include <vector>
#include "common\debug.h" #include "common\debug.h"
#include "ICapture.h" #include "ICapture.h"
@ -29,29 +30,61 @@ Place, Suite 330, Boston, MA 02111-1307 USA
class CaptureFactory class CaptureFactory
{ {
public: public:
static ICapture * GetCaptureDevice() typedef std::vector<ICapture *> DeviceList;
static DeviceList & GetDevices()
{ {
ICapture *dev; static DeviceList devices;
if (!devices.empty())
return devices;
dev = new Capture::NvFBC(); devices.push_back(new Capture::NvFBC());
if (dev->Initialize()) devices.push_back(new Capture::DXGI ());
return devices;
}
static ICapture * GetDevice(const char * name, CaptureOptions * options)
{
DeviceList devices = GetDevices();
for (DeviceList::const_iterator it = devices.begin(); it != devices.end(); ++it)
{ {
DEBUG_INFO("Using NvFBC"); ICapture * device = *it;
return dev; if (_strcmpi(name, device->GetName()) != 0)
} continue;
dev->DeInitialize();
delete dev;
dev = new Capture::DXGI(); if (device->Initialize(options))
if (dev->Initialize()) {
DEBUG_INFO("Using %s", device->GetName());
return device;
}
device->DeInitialize();
DEBUG_ERROR("Failed to initialize %s", device->GetName());
return NULL;
}
DEBUG_ERROR("No such device: %s", name);
return NULL;
}
static ICapture * DetectDevice(CaptureOptions * options)
{
DeviceList devices = GetDevices();
for (DeviceList::const_iterator it = devices.begin(); it != devices.end(); ++it)
{ {
DEBUG_INFO("Using DXGI"); ICapture * device = *it;
return dev;
}
dev->DeInitialize();
delete dev;
DEBUG_ERROR("Failed to initialize a compatible capture device"); DEBUG_INFO("Trying %s", device->GetName());
if (device->Initialize(options))
{
DEBUG_INFO("Using %s", device->GetName());
return device;
}
device->DeInitialize();
}
DEBUG_ERROR("Failed to initialize a capture device");
return NULL; return NULL;
} }
}; };

View File

@ -19,6 +19,7 @@ Place, Suite 330, Boston, MA 02111-1307 USA
#pragma once #pragma once
#include "common/KVMGFXHeader.h" #include "common/KVMGFXHeader.h"
#include <vector>
struct FrameInfo struct FrameInfo
{ {
@ -30,10 +31,14 @@ struct FrameInfo
size_t outSize; size_t outSize;
}; };
typedef std::vector<const char *> CaptureOptions;
__interface ICapture __interface ICapture
{ {
public: public:
bool Initialize(); const char * GetName();
bool Initialize(CaptureOptions * options);
void DeInitialize(); void DeInitialize();
enum FrameType GetFrameType(); enum FrameType GetFrameType();
enum FrameComp GetFrameCompression(); enum FrameComp GetFrameCompression();

View File

@ -40,19 +40,12 @@ Service::~Service()
{ {
} }
bool Service::Initialize() bool Service::Initialize(ICapture * captureDevice)
{ {
if (m_initialized) if (m_initialized)
DeInitialize(); DeInitialize();
m_capture = CaptureFactory::GetCaptureDevice(); m_capture = captureDevice;
if (!m_capture)
{
DEBUG_ERROR("Failed to initialize capture interface");
DeInitialize();
return false;
}
if (!m_ivshmem->Initialize()) if (!m_ivshmem->Initialize())
{ {
DEBUG_ERROR("IVSHMEM failed to initalize"); DEBUG_ERROR("IVSHMEM failed to initalize");

View File

@ -35,7 +35,7 @@ public:
return m_instance; return m_instance;
} }
bool Initialize(); bool Initialize(ICapture * captureDevice);
void DeInitialize(); void DeInitialize();
bool Process(); bool Process();

View File

@ -160,6 +160,7 @@
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="..\vendor\getopt\getopt.c" />
<ClCompile Include="Capture\DXGI.cpp" /> <ClCompile Include="Capture\DXGI.cpp" />
<ClCompile Include="Capture\NvFBC.cpp" /> <ClCompile Include="Capture\NvFBC.cpp" />
<ClCompile Include="ivshmem.cpp" /> <ClCompile Include="ivshmem.cpp" />

View File

@ -39,6 +39,9 @@
<ClCompile Include="Capture\DXGI.cpp"> <ClCompile Include="Capture\DXGI.cpp">
<Filter>Source Files\Capture</Filter> <Filter>Source Files\Capture</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\vendor\getopt\getopt.c">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="ivshmem.h"> <ClInclude Include="ivshmem.h">

View File

@ -17,70 +17,244 @@ Place, Suite 330, Boston, MA 02111-1307 USA
*/ */
#include <Windows.h> #include <Windows.h>
#include "common\debug.h" #include <Shlwapi.h>
#include "common\debug.h"
#include "vendor\getopt\getopt.h"
#include "CaptureFactory.h"
#include "Service.h" #include "Service.h"
#ifdef DEBUG
#include <io.h> #include <io.h>
#include <fcntl.h> #include <fcntl.h>
#include <iostream> #include <iostream>
#endif
int parseArgs(struct StartupArgs & args);
int run(struct StartupArgs & args);
void doHelp();
void doLicense();
bool consoleActive = false;
void setupConsole();
struct StartupArgs
{
bool foreground;
const char * captureDevice;
CaptureOptions captureOptions;
};
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdParam, int iCmdShow) int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdParam, int iCmdShow)
{ {
#ifdef DEBUG struct StartupArgs args;
ZeroMemory(&args, sizeof(struct StartupArgs));
int ret = parseArgs(args);
if (ret == 0)
{ {
HANDLE _handle; ret = run(args);
int _conout; if (ret != 0)
FILE * fp; {
if (!args.foreground)
AllocConsole(); {
setupConsole();
CONSOLE_SCREEN_BUFFER_INFO conInfo; fprintf(stderr, "An error occurred, re-run in forground mode (-f) for more information\n");
GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &conInfo); }
conInfo.dwSize.Y = 500; }
SetConsoleScreenBufferSize(GetStdHandle(STD_OUTPUT_HANDLE), conInfo.dwSize);
_handle = GetStdHandle(STD_INPUT_HANDLE);
_conout = _open_osfhandle((intptr_t)_handle, _O_TEXT);
fp = _fdopen(_conout, "r");
freopen_s(&fp, "CONIN$", "r", stdin);
_handle = GetStdHandle(STD_OUTPUT_HANDLE);
_conout = _open_osfhandle((intptr_t)_handle, _O_TEXT);
fp = _fdopen(_conout, "w");
freopen_s(&fp, "CONOUT$", "w", stdout);
_handle = GetStdHandle(STD_ERROR_HANDLE);
_conout = _open_osfhandle((intptr_t)_handle, _O_TEXT);
fp = _fdopen(_conout, "w");
freopen_s(&fp, "CONOUT$", "w", stderr);
std::ios::sync_with_stdio();
std::wcout.clear();
std::cout.clear();
std::wcerr.clear();
std::cerr.clear();
std::wcin.clear();
std::cin.clear();
} }
#endif
Service *svc = svc->Get(); if (consoleActive)
if (!svc->Initialize())
{ {
DEBUG_ERROR("Failed to initialize service"); fprintf(stderr, "\nPress enter to terminate...");
fflush(stderr);
getc(stdin);
}
return ret;
}
int run(struct StartupArgs & args)
{
if (args.foreground)
setupConsole();
ICapture * captureDevice;
if (args.captureDevice == NULL)
captureDevice = CaptureFactory::DetectDevice(&args.captureOptions);
else
{
captureDevice = CaptureFactory::GetDevice(args.captureDevice, &args.captureOptions);
if (!captureDevice)
{
setupConsole();
fprintf(stderr, "Failed to configure requested capture device\n");
return -1;
}
}
if (!captureDevice)
{
setupConsole();
fprintf(stderr, "Unable to configure a capture device\n");
return -1; return -1;
} }
Service *svc = svc->Get();
if (!svc->Initialize(captureDevice))
return -1;
while (true) while (true)
if (!svc->Process()) if (!svc->Process())
break; break;
svc->DeInitialize(); svc->DeInitialize();
#ifdef DEBUG
getc(stdin);
#endif
return 0; return 0;
} }
int parseArgs(struct StartupArgs & args)
{
int c;
while((c = getopt(__argc, __argv, "hc:o:fl")) != -1)
{
switch (c)
{
case '?':
case 'h':
doHelp();
return -1;
case 'c':
{
const CaptureFactory::DeviceList deviceList = CaptureFactory::GetDevices();
bool found = false;
if (strcmp(optarg, "?") != 0)
{
for (CaptureFactory::DeviceList::const_iterator it = deviceList.begin(); it != deviceList.end(); ++it)
{
if (_strcmpi(optarg, (*it)->GetName()) == 0)
{
args.captureDevice = (*it)->GetName();
found = true;
break;
}
}
if (!found)
{
setupConsole();
fprintf(stderr, "Invalid capture device: %s\n\n", optarg);
}
}
if (!found)
{
setupConsole();
fprintf(stderr, "Available Capture Devices:\n\n");
for (CaptureFactory::DeviceList::const_iterator it = deviceList.begin(); it != deviceList.end(); ++it)
fprintf(stderr, " %s\n", (*it)->GetName());
return -1;
}
break;
}
case 'o':
{
args.captureOptions.push_back(optarg);
break;
}
case 'f':
args.foreground = true;
break;
case 'l':
doLicense();
return -1;
}
}
return 0;
}
void doHelp()
{
setupConsole();
const char *app = PathFindFileNameA(__argv[0]);
fprintf(stderr,
"Usage: %s [OPTION]...\n"
"Example: %s -c ?\n"
"\n"
" -h Print out this help\n"
" -c Specify the capture device to use or ? to list availble (device is probed if not specified)\n"
" -o Option to pass to the capture device, may be specified multiple times for extra options\n"
" -f Foreground mode\n"
" -l License information\n",
app,
app
);
}
void doLicense()
{
setupConsole();
fprintf(stderr,
"KVMGFX Client - A KVM Client for VGA Passthrough\n"
"Copyright(C) 2017 Geoffrey McRae <geoff@hostfission.com>\n"
"\n"
"This program is free software; you can redistribute it and / or modify it under\n"
"the terms of the GNU General Public License as published by the Free Software\n"
"Foundation; either version 2 of the License, or (at your option) any later\n"
"version.\n"
"\n"
"This program is distributed in the hope that it will be useful, but WITHOUT ANY\n"
"WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A\n"
"PARTICULAR PURPOSE.See the GNU General Public License for more details.\n"
"\n"
"You should have received a copy of the GNU General Public License along with\n"
"this program; if not, write to the Free Software Foundation, Inc., 59 Temple\n"
"Place, Suite 330, Boston, MA 02111 - 1307 USA\n"
);
}
void setupConsole()
{
if (consoleActive)
return;
HANDLE _handle;
int _conout;
FILE * fp;
AllocConsole();
CONSOLE_SCREEN_BUFFER_INFO conInfo;
GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &conInfo);
conInfo.dwSize.Y = 500;
SetConsoleScreenBufferSize(GetStdHandle(STD_OUTPUT_HANDLE), conInfo.dwSize);
_handle = GetStdHandle(STD_INPUT_HANDLE);
_conout = _open_osfhandle((intptr_t)_handle, _O_TEXT);
fp = _fdopen(_conout, "r");
freopen_s(&fp, "CONIN$", "r", stdin);
_handle = GetStdHandle(STD_OUTPUT_HANDLE);
_conout = _open_osfhandle((intptr_t)_handle, _O_TEXT);
fp = _fdopen(_conout, "w");
freopen_s(&fp, "CONOUT$", "w", stdout);
_handle = GetStdHandle(STD_ERROR_HANDLE);
_conout = _open_osfhandle((intptr_t)_handle, _O_TEXT);
fp = _fdopen(_conout, "w");
freopen_s(&fp, "CONOUT$", "w", stderr);
std::ios::sync_with_stdio();
std::wcout.clear();
std::cout.clear();
std::wcerr.clear();
std::cerr.clear();
std::wcin.clear();
std::cin.clear();
consoleActive = true;
}

1
vendor/getopt/README.txt vendored Normal file
View File

@ -0,0 +1 @@
This source comes from: https://gist.github.com/superwills/5815344

106
vendor/getopt/getopt.c vendored Normal file
View File

@ -0,0 +1,106 @@
#include "getopt.h"
/*
* Copyright (c) 1987, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <string.h>
#include <stdio.h>
int opterr = 1, /* if error message should be printed */
optind = 1, /* index into parent argv vector */
optopt, /* character checked for validity */
optreset; /* reset getopt */
char *optarg; /* argument associated with option */
#define BADCH (int)'?'
#define BADARG (int)':'
#define EMSG ""
/*
* getopt --
* Parse argc/argv argument vector.
*/
int getopt(int nargc, char * const nargv[], const char *ostr)
{
static char *place = EMSG; /* option letter processing */
const char *oli; /* option letter list index */
if (optreset || !*place) { /* update scanning pointer */
optreset = 0;
if (optind >= nargc || *(place = nargv[optind]) != '-') {
place = EMSG;
return (-1);
}
if (place[1] && *++place == '-') { /* found "--" */
++optind;
place = EMSG;
return (-1);
}
} /* option letter okay? */
if ((optopt = (int)*place++) == (int)':' ||
!(oli = strchr(ostr, optopt))) {
/*
* if the user didn't specify '-' as an option,
* assume it means -1.
*/
if (optopt == (int)'-')
return (-1);
if (!*place)
++optind;
if (opterr && *ostr != ':')
(void)printf("illegal option -- %c\n", optopt);
return (BADCH);
}
if (*++oli != ':') { /* don't need argument */
optarg = NULL;
if (!*place)
++optind;
}
else { /* need an argument */
if (*place) /* no white space */
optarg = place;
else if (nargc <= ++optind) { /* no arg */
place = EMSG;
if (*ostr == ':')
return (BADARG);
if (opterr)
(void)printf("option requires an argument -- %c\n", optopt);
return (BADCH);
}
else /* white space */
optarg = nargv[optind];
place = EMSG;
++optind;
}
return (optopt); /* dump back option letter */
}

20
vendor/getopt/getopt.h vendored Normal file
View File

@ -0,0 +1,20 @@
#ifndef GETOPT_H
#define GETOPT_H
#ifdef __cplusplus
extern "C" {
#endif
extern int opterr; /* if error message should be printed */
extern int optind; /* index into parent argv vector */
extern int optopt; /* character checked for validity */
extern int optreset; /* reset getopt */
extern char *optarg; /* argument associated with option */
int getopt(int nargc, char * const nargv[], const char *ostr);
#ifdef __cplusplus
}
#endif
#endif