From fede382191f2a2044687e83dfb427892d197f6d5 Mon Sep 17 00:00:00 2001 From: Joakim Soderberg Date: Fri, 11 Aug 2017 02:32:45 +0200 Subject: [PATCH 1/3] Port to windows + CMake project - Ported and tested to run on Windows, built using Visual Studio - Created a CMake project that has been tested to work on Windows + OSX - Included support to build the "other" servers only for Linux (should work but did not have access to Linux at the time of writing). --- CMakeLists.txt | 175 ++++++++++++ README.md | 38 ++- cmake/FindGLUT.cmake | 132 +++++++++ src/compat.h | 29 ++ src/dummy_client.c | 26 +- src/gl_server.c | 49 +++- src/opc_client.c | 73 +++-- src/opc_server.c | 71 +++-- src/win32/getopt.h | 651 +++++++++++++++++++++++++++++++++++++++++++ 9 files changed, 1195 insertions(+), 49 deletions(-) create mode 100644 CMakeLists.txt create mode 100644 cmake/FindGLUT.cmake create mode 100644 src/compat.h create mode 100644 src/win32/getopt.h diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..235db48 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,175 @@ +cmake_minimum_required(VERSION 2.8) +project(openpixelprotocol) + +# We use a newer version of FindGLUT that findws windows DLLs +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake) + +if (WIN32) + set(GLUT_DIR "" CACHE PATH "Path to the directory where the GLUT binaries can be found, glut32.lib, glut32.dll, glut.h" ) +endif() + +if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux") + set(LINUX 1) +endif() + +option(WITH_DUMMY_CLIENT "Compile the Dummy client" ON) +option(WITH_DUMMY_SERVER "Compile the Dummy server" ON) +option(WITH_GL_SERVER "GL Server (Requires GLUT)" ON) + +if (LINUX) + option(WITH_TCL_SERVER "Compile TCL server" ON) + option(WITH_APA102_SERVER "Compile APA102 server" ON) + option(WITH_WS2801_SERVER "Compile WS2801 server" ON) + option(WITH_LPD8806_SERVER "Compile LPD8806 server" ON) +endif() + +# Set some nicer output dirs. +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin) +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib) +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib) + +if (MSVC) + add_definitions("/W3 /D_CRT_SECURE_NO_WARNINGS /wd4005 /wd4996 /nologo") + set(CMAKE_EXE_LINKER_FLAGS "/SAFESEH:NO") +endif() + +if (APPLE) + set(CMAKE_C_FLAGS "-Wdeprecated-declarations") +endif() + +if (WITH_DUMMY_CLIENT) + set(DUMMY_CLIENT_SRCS + ${PROJECT_SOURCE_DIR}/src/dummy_client.c + ${PROJECT_SOURCE_DIR}/src/opc_client.c) + + set(DUMMY_CLIENT_HDRS + ${PROJECT_SOURCE_DIR}/src/types.h + ${PROJECT_SOURCE_DIR}/src/opc.h + ${PROJECT_SOURCE_DIR}/src/compat.h) + + source_group("Headers" FILES ${DUMMY_CLIENT_HDRS}) + source_group("Sources" FILES ${DUMMY_CLIENT_SRCS}) + + add_executable(dummy_client ${DUMMY_CLIENT_SRCS} ${DUMMY_CLIENT_HDRS}) + + if (WIN32) + target_link_libraries(dummy_client ws2_32.lib) + endif() +endif() + +if (WITH_DUMMY_SERVER) + set(DUMMY_SERVER_SRCS + ${PROJECT_SOURCE_DIR}/src/dummy_server.c + ${PROJECT_SOURCE_DIR}/src/opc_server.c) + + set(DUMMY_SERVER_HDRS + ${PROJECT_SOURCE_DIR}/src/types.h + ${PROJECT_SOURCE_DIR}/src/opc.h) + + source_group("Headers" FILES ${DUMMY_SERVER_HDRS}) + source_group("Sources" FILES ${DUMMY_SERVER_SRCS}) + + add_executable(dummy_server ${DUMMY_SERVER_SRCS} ${DUMMY_SERVER_HDRS}) + + if (WIN32) + target_link_libraries(dummy_server ws2_32.lib) + endif() +endif() + +if (WITH_GL_SERVER) + set(GL_SERVER_SRCS + ${PROJECT_SOURCE_DIR}/src/gl_server.c + ${PROJECT_SOURCE_DIR}/src/opc_server.c + ${PROJECT_SOURCE_DIR}/src/cJSON.c) + + set(GL_SERVER_HDRS + ${PROJECT_SOURCE_DIR}/src/cJSON.h + ${PROJECT_SOURCE_DIR}/src/types.h + ${PROJECT_SOURCE_DIR}/src/opc.h + ${PROJECT_SOURCE_DIR}/src/win32/getopt.h + ${PROJECT_SOURCE_DIR}/src/compat.h) + + source_group("Headers" FILES ${GL_SERVER_HDRS}) + source_group("Sources" FILES ${GL_SERVER_SRCS}) + + if (WIN32 AND GLUT_DIR) + set(GLUT_FOUND ON) + set(GLUT_INCLUDE_DIRS "${GLUT_DIR}") + set(GLUT_LIBRARIES "${GLUT_DIR}/glut32.lib") + set(GLUT_RUNTIME_LIBRARY_DIRS "${GLUT_DIR}") + set(GLUT_RUNTIME_LIBRARY "${GLUT_DIR}/glut32.dll") + else() + find_package(GLUT) + + if (NOT GLUT_FOUND) + if (WIN32) + message(FATAL_ERROR "Set cmake -DGLUT_DIR=. Run 'cmake -LH .' for details") + else() + message(FATAL_ERROR "GLUT is required, please install it") + endif() + endif() + endif() + + add_executable(glserver ${GL_SERVER_SRCS} ${GL_SERVER_HDRS}) + target_link_libraries(glserver ${GLUT_LIBRARIES}) + message("GLUT Include dir: ${GLUT_INCLUDE_DIRS}") + include_directories("${GLUT_INCLUDE_DIRS}") + + if (WIN32) + target_link_libraries(glserver ws2_32.lib) + + # Copy GLUT DLL to binary dir. + add_custom_command(TARGET glserver POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different + ${GLUT_RUNTIME_LIBRARY} + $) + endif() + + if (LINUX) + target_link_libraries(glserver m) + endif() +endif() + +if (LINUX) + set(SERVER_LIST "") + + set(SERVER_COMMON_SRCS + "${PROJECT_SOURCE_DIR}/src/opc_server.c" + "${PROJECT_SOURCE_DIR}/src/spi.c" + "${PROJECT_SOURCE_DIR}/src/cli.c") + + set(SERVER_COMMON_HDRS + "${PROJECT_SOURCE_DIR}/src/spi.h" + "${PROJECT_SOURCE_DIR}/src/opc.h" + "${PROJECT_SOURCE_DIR}/src/types.h" + "${PROJECT_SOURCE_DIR}/src/cli.h" + ) + + source_group("Headers" FILES ${SERVER_COMMON_HDRS}) + + if (WITH_TCL_SERVER) + list(APPEND SERVER_LIST "tcl_server") + endif() + + if (WITH_APA102_SERVER) + list(APPEND SERVER_LIST "apa102_server") + endif() + + if (WITH_WS2801_SERVER) + list(APPEND SERVER_LIST "ws2801_server") + endif() + + if (WITH_LPD8806_SERVER) + list(APPEND SERVER_LIST "lpd8806_server") + endif() + + macro(create_server ) + + foreach (SERVER ${SERVER_LIST}) + set(SRCS ${SERVER}.c ${SERVER_COMMON_SRCS}) + source_group("Sources" FILES ${SRCS}) + + add_executable(${SERVER} ${SRCS} ${HDRS}) + target_link_libraries(${GLUT_LIBRARIES} m) + endforeach() +endif() diff --git a/README.md b/README.md index 335b559..5f567a2 100644 --- a/README.md +++ b/README.md @@ -32,11 +32,11 @@ repository includes these programs: To build these programs, run "make" and then look in the bin/ directory. -Quickstart (simulator) ----------------------- +Quickstart (simulator on Linux/OSX) +----------------------------------- **Step 1.** If you're using Linux, first get the dependencies you need -(Mac users skip to step 2): +(**OSX users skip to step 2**): apt-get install mesa-common-dev freeglut3-dev @@ -50,6 +50,38 @@ Quickstart (simulator) python/raver_plaid.py +Quickstart (simulator on Windows) +--------------------------------- + +Install CMake: https://cmake.org/ +Install Visual Studio: https://www.visualstudio.com/ + +NOTE! Assuming use of **git bash** below, but normal **cmd.exe** works as well. + +**Step 1.** Download and unpack GLUT in a known path (For example `c:\glut\`): + +https://www.opengl.org/resources/libraries/glut/glutdlls37beta.zip +Or google for "glut windows" if above URL is out of date. You want `glut32.lib`, `glut32.dll` and `glut.h`. + +**Step 2.** Generate the CMake project, specify the **full absolute path** to the directory were you unpacked GLUT: + + mkdir build + cd build + cmake -DGLUT_DIR=c:/glut/ .. # NOTE that you should use / not \ for the paths! + +**Step 3.** Open the Visual Studio Solution and build: + + start openpixelcontrol.sln + +**Step 4.** After compiling you can run it in the terminal window (assuming default build type Debug): + + bin/Debug/gl_server.exe -l ../layout/freespace.json + +**Step 6.** In another terminal window, send colors to the simulator: + + python/raver_plaid.py + + Quickstart (Beaglebone) ----------------------- diff --git a/cmake/FindGLUT.cmake b/cmake/FindGLUT.cmake new file mode 100644 index 0000000..f76902d --- /dev/null +++ b/cmake/FindGLUT.cmake @@ -0,0 +1,132 @@ +# - try to find glut library and include files +# GLUT_INCLUDE_DIRS, where to find GL/glut.h, etc. +# GLUT_LIBRARIES, the libraries to link against +# GLUT_FOUND, If false, do not try to use GLUT. +# GLUT_RUNTIME_LIBRARY_DIRS, path to DLL on Windows for runtime use. +# GLUT_RUNTIME_LIBRARY, dll on Windows, for installation purposes +# +# Also defined, but not for general use are: +# GLUT_INCLUDE_DIR, where to find GL/glut.h, etc. +# GLUT_glut_LIBRARY = the full path to the glut library. + +#============================================================================= +# Copyright 2001-2009 Kitware, Inc. +# Copyright 2009-2010 Iowa State University +# (Author: Ryan Pavlik ) +# +# Distributed under the OSI-approved BSD License (the "License"); +# see below. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# * 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. +# +# * Neither the names of Kitware, Inc., the Insight Software Consortium, +# nor the names of their contributors may be used to endorse or promote +# products derived from this software without specific prior written +# permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT +# HOLDER 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. +#============================================================================= + +if(GLUT_FIND_QUIETLY) + find_package(OpenGL QUIET) +else() + find_package(OpenGL) +endif() + +if(OPENGL_FOUND) + get_filename_component(_ogl_libdir ${OPENGL_gl_LIBRARY} PATH) + find_path(GLUT_INCLUDE_DIR + NAMES + GL/glut.h + GLUT/glut.h + glut.h + PATHS + ${_ogl_libdir}/../include + ${GLUT_ROOT_PATH} + ${GLUT_ROOT_PATH}/include + /usr/include/GL + /usr/openwin/share/include + /usr/openwin/include + /opt/graphics/OpenGL/include + /opt/graphics/OpenGL/contrib/libglut) + + find_library(GLUT_glut_LIBRARY + NAMES + glut + glut32 + GLUT + freeglut + PATHS + ${_ogl_libdir} + ${GLUT_ROOT_PATH} + ${GLUT_ROOT_PATH}/Release + /usr/openwin/lib) + +endif() + +# handle the QUIETLY and REQUIRED arguments and set xxx_FOUND to TRUE if +# all listed variables are TRUE +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(GLUT + DEFAULT_MSG + GLUT_glut_LIBRARY + GLUT_INCLUDE_DIR + OPENGL_FOUND) + +if(GLUT_FOUND) + set(GLUT_LIBRARIES ${GLUT_glut_LIBRARY} ${OPENGL_LIBRARIES}) + set(GLUT_INCLUDE_DIRS ${GLUT_INCLUDE_DIR} ${OPENGL_INCLUDE_DIR}) + + if(WIN32) + get_filename_component(_basename "${GLUT_glut_LIBRARY}" NAME_WE) + get_filename_component(_libpath "${GLUT_glut_LIBRARY}" PATH) + find_path(GLUT_RUNTIME_LIBRARY + NAMES + ${_basename}.dll + glut.dll + glut32.dll + freeglut.dll + HINTS + ${_libpath} + ${_libpath}/../bin) + if(GLUT_RUNTIME_LIBRARY) + get_filename_component(GLUT_RUNTIME_LIBRARY_DIRS + "${GLUT_RUNTIME_LIBRARY}" + PATH) + else() + set(GLUT_RUNTIME_LIBRARY_DIRS) + endif() + endif() + + #The following deprecated settings are for backwards compatibility with CMake1.4 + set(GLUT_LIBRARY ${GLUT_LIBRARIES}) + set(GLUT_INCLUDE_PATH ${GLUT_INCLUDE_DIR}) +endif() + +mark_as_advanced(GLUT_INCLUDE_DIR + GLUT_glut_LIBRARY + GLUT_RUNTIME_LIBRARY) \ No newline at end of file diff --git a/src/compat.h b/src/compat.h new file mode 100644 index 0000000..24fb18a --- /dev/null +++ b/src/compat.h @@ -0,0 +1,29 @@ +/* Copyright 2016 Ka-Ping Yee + +Licensed under the Apache License, Version 2.0 (the "License"); you may not +use this file except in compliance with the License. You may obtain a copy +of the License at: http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software distributed +under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +CONDITIONS OF ANY KIND, either express or implied. See the License for the +specific language governing permissions and limitations under the License. */ + +#ifndef __COMPAT_H__ +#define __COMPAT_H__ + +#ifdef _WIN32 +#define bzero(b,len) (memset((b), '\0', (len)), (void) 0) +#define bcopy(b1,b2,len) (memmove((b2), (b1), (len)), (void) 0) + +#include +typedef SSIZE_T ssize_t; + +typedef SOCKET sock_t; +#else +typedef int sock_t; +#define SOCKET_ERROR 0xFFFFFFFF +#define INVALID_SOCKET 0xFFFFFFFF +#endif + +#endif // __COMPAT_H__ diff --git a/src/dummy_client.c b/src/dummy_client.c index 66e6436..e7797b7 100644 --- a/src/dummy_client.c +++ b/src/dummy_client.c @@ -22,19 +22,34 @@ int main(int argc, char** argv) { char buffer[MAX_INPUT_LENGTH]; char* token; pixel pixels[MAX_PIXELS]; - int c, chars; + int c, chars = 0; u32 hex; u16 count; - u16 port; opc_sink s; int i; char* sep; + int ret = 0; if (argc < 2) { fprintf(stderr, "Usage: %s [:]\n", argv[0]); return 1; } +#ifdef _WIN32 + // Init winsock + { + WORD wVersionRequested; + WSADATA wsaData; + int err; + wVersionRequested = MAKEWORD(2, 2); + err = WSAStartup(wVersionRequested, &wsaData); + if (err != 0) { + printf("WSAStartup failed with error: %d\n", err); + ret = -1; goto fail; + } + } +#endif + s = opc_new_sink(argv[1]); buffer[0] = 0; while (s >= 0 && fgets(buffer, MAX_INPUT_LENGTH, stdin)) { @@ -45,7 +60,7 @@ int main(int argc, char** argv) { count = 0; token = strtok(buffer + c, " \t\r\n"); while (token) { - c += chars; + c += chars; // TODO: Fix bug, chars is never initialized or used anywhere else? if (strlen(token) == 3) { hex = strtol(token, NULL, 16); pixels[count].r = ((hex & 0xf00) >> 8) * 0x11; @@ -75,4 +90,9 @@ int main(int argc, char** argv) { opc_put_pixels(s, channel, count, pixels); buffer[0] = 0; } +fail: +#ifdef _WIN32 + WSACleanup(); +#endif + return ret; } diff --git a/src/gl_server.c b/src/gl_server.c index 41ac131..f62bec9 100644 --- a/src/gl_server.c +++ b/src/gl_server.c @@ -9,17 +9,29 @@ under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ -#include #include #include + +#define _USE_MATH_DEFINES +#include + +#ifdef _WIN32 +#include +#include "win32/getopt.h" +#else #include +#endif // !_WIN32 + #include #include + #ifdef __APPLE__ #include #include #include #include +#elif _WIN32 +#include #else #include #endif @@ -177,7 +189,7 @@ void draw_axes() { glEnd(); } -void display() { +void display(void) { int i; shape* sh; @@ -273,7 +285,7 @@ void receive_frames() { } } -void idle() { +void idle(void) { receive_frames(); } @@ -415,7 +427,8 @@ void usage(char* prog_name) { } int main(int argc, char** argv) { - u16 port; + u16 port = 0; + int ret = 0; glutInit(&argc, argv); @@ -460,8 +473,27 @@ int main(int argc, char** argv) { usage(argv[0]); } init(layouts, num_channels); + +#ifdef _WIN32 + // Init winsock + { + WORD wVersionRequested; + WSADATA wsaData; + int err; + wVersionRequested = MAKEWORD(2, 2); + err = WSAStartup(wVersionRequested, &wsaData); + if (err != 0) { + printf("WSAStartup failed with error: %d\n", err); + ret = -1; goto fail; + } + } +#endif + port = port ? port : OPC_DEFAULT_PORT; - source = opc_new_source(port); + if ((source = opc_new_source(port) < 0)) { + fprintf(stderr, "Failed to start server\n"); + ret = -1; goto fail; + } glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH); glutCreateWindow("OPC"); @@ -482,5 +514,10 @@ int main(int argc, char** argv) { #endif glutMainLoop(); - return 0; + +fail: +#ifdef _WIN32 + WSACleanup(); +#endif + return ret; } diff --git a/src/opc_client.c b/src/opc_client.c index 1afad7d..3df3c4a 100644 --- a/src/opc_client.c +++ b/src/opc_client.c @@ -9,19 +9,29 @@ under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ -#include +#include +#include +#include #include + +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN 1 +#include +#include +#include +#else +#include #include #include #include -#include -#include -#include + #include #include #include #include #include +#endif +#include "compat.h" #include "opc.h" /* Wait at most 0.5 second for a connection or a write. */ @@ -38,16 +48,15 @@ static opc_sink_info opc_sinks[OPC_MAX_SINKS]; static opc_sink opc_next_sink = 0; int opc_resolve(char* s, struct sockaddr_in* address, u16 default_port) { - struct hostent* host; struct addrinfo* addr; struct addrinfo* ai; - long port = 0; + u_short port = 0; char* name = strdup(s); char* colon = strchr(name, ':'); if (colon) { *colon = 0; - port = strtol(colon + 1, NULL, 10); + port = (u_short)strtol(colon + 1, NULL, 10); } getaddrinfo(colon == name ? "localhost" : name, NULL, NULL, &addr); free(name); @@ -74,7 +83,7 @@ opc_sink opc_new_sink(char* hostport) { info = &opc_sinks[opc_next_sink]; /* Resolve the server address. */ - info->sock = -1; + info->sock = INVALID_SOCKET; if (!opc_resolve(hostport, &(info->address), OPC_DEFAULT_PORT)) { fprintf(stderr, "OPC: Host not found: %s\n", hostport); return -1; @@ -90,7 +99,7 @@ opc_sink opc_new_sink(char* hostport) { /* Makes one attempt to open the connection for a sink if needed, timing out */ /* after timeout_ms. Returns 1 if connected, 0 if the timeout expired. */ static u8 opc_connect(opc_sink sink, u32 timeout_ms) { - int sock; + sock_t sock; struct timeval timeout; opc_sink_info* info = &opc_sinks[sink]; fd_set writefds; @@ -107,12 +116,25 @@ static u8 opc_connect(opc_sink sink, u32 timeout_ms) { /* Do a non-blocking connect so we can control the timeout. */ sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); + + #ifdef _WIN32 + { + u_long val = 1; + ioctlsocket(sock, FIONBIO, &val); + } + #else fcntl(sock, F_SETFL, O_NONBLOCK); + #endif + if (connect(sock, (struct sockaddr*) &(info->address), sizeof(info->address)) < 0 && errno != EINPROGRESS) { fprintf(stderr, "OPC: Failed to connect to %s: ", info->address_string); perror(NULL); + #ifdef _WIN32 + closesocket(sock); + #else close(sock); + #endif return 0; } @@ -124,7 +146,7 @@ static u8 opc_connect(opc_sink sink, u32 timeout_ms) { select(sock + 1, NULL, &writefds, NULL, &timeout); if (FD_ISSET(sock, &writefds)) { opt_errno = 0; - getsockopt(sock, SOL_SOCKET, SO_ERROR, &opt_errno, &len); + getsockopt(sock, SOL_SOCKET, SO_ERROR, (void *)&opt_errno, &len); if (opt_errno == 0) { fprintf(stderr, "OPC: Connected to %s\n", info->address_string); info->sock = sock; @@ -132,9 +154,17 @@ static u8 opc_connect(opc_sink sink, u32 timeout_ms) { } else { fprintf(stderr, "OPC: Failed to connect to %s: %s\n", info->address_string, strerror(opt_errno)); + #ifdef _WIN32 + closesocket(sock); + #else close(sock); + #endif if (opt_errno == ECONNREFUSED) { - usleep(timeout_ms*1000); + #ifdef _WIN32 + Sleep(timeout_ms); + #else + usleep(timeout_ms * 1000); + #endif } return 0; } @@ -152,9 +182,13 @@ static void opc_close(opc_sink sink) { fprintf(stderr, "OPC: Sink %d does not exist\n", sink); return; } - if (info->sock >= 0) { + if (info->sock != INVALID_SOCKET) { + #ifdef _WIN32 + closesocket(info->sock); + #else close(info->sock); - info->sock = -1; + #endif + info->sock = INVALID_SOCKET; fprintf(stderr, "OPC: Closed connection to %s\n", info->address_string); } } @@ -167,7 +201,9 @@ static u8 opc_send(opc_sink sink, const u8* data, ssize_t len, u32 timeout_ms) { struct timeval timeout; ssize_t total_sent = 0; ssize_t sent; + #ifndef _WIN32 sig_t pipe_sig; + #endif if (sink < 0 || sink >= opc_next_sink) { fprintf(stderr, "OPC: Sink %d does not exist\n", sink); @@ -178,11 +214,16 @@ static u8 opc_send(opc_sink sink, const u8* data, ssize_t len, u32 timeout_ms) { } timeout.tv_sec = timeout_ms/1000; timeout.tv_usec = timeout_ms % 1000; - setsockopt(info->sock, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout)); + setsockopt(info->sock, SOL_SOCKET, SO_SNDTIMEO, (const void *)&timeout, sizeof(timeout)); while (total_sent < len) { + #ifndef _WIN32 pipe_sig = signal(SIGPIPE, SIG_IGN); + #endif sent = send(info->sock, data + total_sent, len - total_sent, 0); - signal(SIGPIPE, pipe_sig); + #ifndef _WIN32 + signal(SIGPIPE, pipe_sig); + #endif + if (sent <= 0) { perror("OPC: Error sending data"); opc_close(sink); @@ -205,7 +246,7 @@ u8 opc_put_pixels(opc_sink sink, u8 channel, u16 count, pixel* pixels) { header[0] = channel; header[1] = OPC_SET_PIXELS; - header[2] = len >> 8; + header[2] = (u8)(len >> 8); header[3] = len & 0xff; return opc_send(sink, header, 4, OPC_SEND_TIMEOUT_MS) && opc_send(sink, (u8*) pixels, len, OPC_SEND_TIMEOUT_MS); diff --git a/src/opc_server.c b/src/opc_server.c index c9d76d5..75dc5cc 100644 --- a/src/opc_server.c +++ b/src/opc_server.c @@ -9,22 +9,31 @@ under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ -#include #include + +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN 1 +#include +#include +#include +#else #include +#include #include #include #include #include #include #include +#endif // !_WIN32 +#include "compat.h" #include "opc.h" /* Internal structure for a source. sock >= 0 iff the connection is open. */ typedef struct { u16 port; - int listen_sock; - int sock; + sock_t listen_sock; + sock_t sock; u16 header_length; u8 header[4]; u16 payload_length; @@ -34,26 +43,34 @@ typedef struct { static opc_source_info opc_sources[OPC_MAX_SOURCES]; static int opc_next_source = 0; -int opc_listen(u16 port) { +sock_t opc_listen(u16 port) { struct sockaddr_in address; - int sock; + sock_t sock; int one = 1; sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); - setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)); + setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const void *)&one, sizeof(one)); address.sin_family = AF_INET; address.sin_port = htons(port); bzero(&address.sin_addr, sizeof(address.sin_addr)); - if (bind(sock, (struct sockaddr*) &address, sizeof(address)) != 0) { + if (bind(sock, (struct sockaddr*) &address, sizeof(address)) == SOCKET_ERROR) { fprintf(stderr, "OPC: Could not bind to port %d: ", port); - perror(NULL); - return -1; + #ifdef _WIN32 + fprintf(stderr, "Error %d\n", WSAGetLastError()); + #else + perror(NULL); + #endif + return INVALID_SOCKET; } if (listen(sock, 0) != 0) { fprintf(stderr, "OPC: Could not listen on port %d: ", port); - perror(NULL); - return -1; + #ifdef _WIN32 + fprintf(stderr, "Error %d\n", WSAGetLastError()); + #else + perror(NULL); + #endif + return INVALID_SOCKET; } return sock; } @@ -71,7 +88,7 @@ opc_source opc_new_source(u16 port) { /* Listen on the specified port. */ info->port = port; info->listen_sock = opc_listen(port); - if (info->listen_sock < 0) { + if (info->listen_sock == INVALID_SOCKET) { return -1; } @@ -98,33 +115,37 @@ u8 opc_receive(opc_source source, opc_handler* handler, u32 timeout_ms) { /* Select for inbound data or connections. */ FD_ZERO(&readfds); - if (info->listen_sock >= 0) { + if (info->listen_sock != INVALID_SOCKET) { FD_SET(info->listen_sock, &readfds); nfds = info->listen_sock + 1; - } else if (info->sock >= 0) { + } else if (info->sock != INVALID_SOCKET) { FD_SET(info->sock, &readfds); nfds = info->sock + 1; } timeout.tv_sec = timeout_ms/1000; timeout.tv_usec = (timeout_ms % 1000)*1000; select(nfds, &readfds, NULL, NULL, &timeout); - if (info->listen_sock >= 0 && FD_ISSET(info->listen_sock, &readfds)) { + if ((info->listen_sock != INVALID_SOCKET) && FD_ISSET(info->listen_sock, &readfds)) { /* Handle an inbound connection. */ info->sock = accept( info->listen_sock, (struct sockaddr*) &(address), &address_len); inet_ntop(AF_INET, &(address.sin_addr), buffer, 64); fprintf(stderr, "OPC: Client connected from %s\n", buffer); + #ifdef _WIN32 + closesocket(info->listen_sock); + #else close(info->listen_sock); - info->listen_sock = -1; + #endif + info->listen_sock = INVALID_SOCKET; info->header_length = 0; info->payload_length = 0; - } else if (info->sock >= 0 && FD_ISSET(info->sock, &readfds)) { + } else if ((info->sock != INVALID_SOCKET) && FD_ISSET(info->sock, &readfds)) { /* Handle inbound data on an existing connection. */ if (info->header_length < 4) { /* need header */ received = recv(info->sock, info->header + info->header_length, 4 - info->header_length, 0); if (received > 0) { - info->header_length += received; + info->header_length += (u16)received; } } if (info->header_length == 4) { /* header complete */ @@ -133,7 +154,7 @@ u8 opc_receive(opc_source source, opc_handler* handler, u32 timeout_ms) { received = recv(info->sock, info->payload + info->payload_length, payload_expected - info->payload_length, 0); if (received > 0) { - info->payload_length += received; + info->payload_length += (u16)received; } } if (info->header_length == 4 && @@ -149,8 +170,12 @@ u8 opc_receive(opc_source source, opc_handler* handler, u32 timeout_ms) { if (received <= 0) { /* Connection was closed; wait for more connections. */ fprintf(stderr, "OPC: Client closed connection\n"); + #ifdef _WIN32 + closesocket(info->sock); + #else close(info->sock); - info->sock = -1; + #endif + info->sock = INVALID_SOCKET; info->listen_sock = opc_listen(info->port); } } else { @@ -169,8 +194,12 @@ void opc_reset_source(opc_source source) { if (info->sock >= 0) { fprintf(stderr, "OPC: Closed connection\n"); + #ifdef _WIN32 + closesocket(info->sock); + #else close(info->sock); - info->sock = -1; + #endif + info->sock = INVALID_SOCKET; info->listen_sock = opc_listen(info->port); } } diff --git a/src/win32/getopt.h b/src/win32/getopt.h new file mode 100644 index 0000000..520cc6a --- /dev/null +++ b/src/win32/getopt.h @@ -0,0 +1,651 @@ +#ifndef __GETOPT_H__ +/** + * DISCLAIMER + * This file is part of the mingw-w64 runtime package. + * + * The mingw-w64 runtime package and its code is distributed in the hope that it + * will be useful but WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESSED OR + * IMPLIED ARE HEREBY DISCLAIMED. This includes but is not limited to + * warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + */ + /* + * Copyright (c) 2002 Todd C. Miller + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Sponsored in part by the Defense Advanced Research Projects + * Agency (DARPA) and Air Force Research Laboratory, Air Force + * Materiel Command, USAF, under agreement number F39502-99-1-0512. + */ +/*- + * Copyright (c) 2000 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Dieter Baron and Thomas Klausner. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ + +#define __GETOPT_H__ + +/* All the headers include this file. */ +#include +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define REPLACE_GETOPT /* use this getopt as the system getopt(3) */ + +#ifdef REPLACE_GETOPT +int opterr = 1; /* if error message should be printed */ +int optind = 1; /* index into parent argv vector */ +int optopt = '?'; /* character checked for validity */ +#undef optreset /* see getopt.h */ +#define optreset __mingw_optreset +int optreset; /* reset getopt */ +char *optarg; /* argument associated with option */ +#endif + +//extern int optind; /* index of first non-option in argv */ +//extern int optopt; /* single option character, as parsed */ +//extern int opterr; /* flag to enable built-in diagnostics... */ +// /* (user may set to zero, to suppress) */ +// +//extern char *optarg; /* pointer to argument of current option */ + +#define PRINT_ERROR ((opterr) && (*options != ':')) + +#define FLAG_PERMUTE 0x01 /* permute non-options to the end of argv */ +#define FLAG_ALLARGS 0x02 /* treat non-options as args to option "-1" */ +#define FLAG_LONGONLY 0x04 /* operate as getopt_long_only */ + +/* return values */ +#define BADCH (int)'?' +#define BADARG ((*options == ':') ? (int)':' : (int)'?') +#define INORDER (int)1 + +#ifndef __CYGWIN__ +#define __progname __argv[0] +#else +extern char __declspec(dllimport) *__progname; +#endif + +#ifdef __CYGWIN__ +static char EMSG[] = ""; +#else +#define EMSG "" +#endif + +static int getopt_internal(int, char * const *, const char *, + const struct option *, int *, int); +static int parse_long_options(char * const *, const char *, + const struct option *, int *, int); +static int gcd(int, int); +static void permute_args(int, int, int, char * const *); + +static char *place = EMSG; /* option letter processing */ + +/* XXX: set optreset to 1 rather than these two */ +static int nonopt_start = -1; /* first non option argument (for permute) */ +static int nonopt_end = -1; /* first option after non options (for permute) */ + +/* Error messages */ +static const char recargchar[] = "option requires an argument -- %c"; +static const char recargstring[] = "option requires an argument -- %s"; +static const char ambig[] = "ambiguous option -- %.*s"; +static const char noarg[] = "option doesn't take an argument -- %.*s"; +static const char illoptchar[] = "unknown option -- %c"; +static const char illoptstring[] = "unknown option -- %s"; + +static void +_vwarnx(const char *fmt,va_list ap) +{ + (void)fprintf(stderr,"%s: ",__progname); + if (fmt != NULL) + (void)vfprintf(stderr,fmt,ap); + (void)fprintf(stderr,"\n"); +} + +static void +warnx(const char *fmt,...) +{ + va_list ap; + va_start(ap,fmt); + _vwarnx(fmt,ap); + va_end(ap); +} + +/* + * Compute the greatest common divisor of a and b. + */ +static int +gcd(int a, int b) +{ + int c; + + c = a % b; + while (c != 0) { + a = b; + b = c; + c = a % b; + } + + return (b); +} + +/* + * Exchange the block from nonopt_start to nonopt_end with the block + * from nonopt_end to opt_end (keeping the same order of arguments + * in each block). + */ +static void +permute_args(int panonopt_start, int panonopt_end, int opt_end, + char * const *nargv) +{ + int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos; + char *swap; + + /* + * compute lengths of blocks and number and size of cycles + */ + nnonopts = panonopt_end - panonopt_start; + nopts = opt_end - panonopt_end; + ncycle = gcd(nnonopts, nopts); + cyclelen = (opt_end - panonopt_start) / ncycle; + + for (i = 0; i < ncycle; i++) { + cstart = panonopt_end+i; + pos = cstart; + for (j = 0; j < cyclelen; j++) { + if (pos >= panonopt_end) + pos -= nnonopts; + else + pos += nopts; + swap = nargv[pos]; + /* LINTED const cast */ + ((char **) nargv)[pos] = nargv[cstart]; + /* LINTED const cast */ + ((char **)nargv)[cstart] = swap; + } + } +} + +#ifdef REPLACE_GETOPT +/* + * getopt -- + * Parse argc/argv argument vector. + * + * [eventually this will replace the BSD getopt] + */ +int +getopt(int nargc, char * const *nargv, const char *options) +{ + + /* + * We don't pass FLAG_PERMUTE to getopt_internal() since + * the BSD getopt(3) (unlike GNU) has never done this. + * + * Furthermore, since many privileged programs call getopt() + * before dropping privileges it makes sense to keep things + * as simple (and bug-free) as possible. + */ + return (getopt_internal(nargc, nargv, options, NULL, NULL, 0)); +} +#endif /* REPLACE_GETOPT */ + +//extern int getopt(int nargc, char * const *nargv, const char *options); + +#ifdef _BSD_SOURCE +/* + * BSD adds the non-standard `optreset' feature, for reinitialisation + * of `getopt' parsing. We support this feature, for applications which + * proclaim their BSD heritage, before including this header; however, + * to maintain portability, developers are advised to avoid it. + */ +# define optreset __mingw_optreset +extern int optreset; +#endif +#ifdef __cplusplus +} +#endif +/* + * POSIX requires the `getopt' API to be specified in `unistd.h'; + * thus, `unistd.h' includes this header. However, we do not want + * to expose the `getopt_long' or `getopt_long_only' APIs, when + * included in this manner. Thus, close the standard __GETOPT_H__ + * declarations block, and open an additional __GETOPT_LONG_H__ + * specific block, only when *not* __UNISTD_H_SOURCED__, in which + * to declare the extended API. + */ +#endif /* !defined(__GETOPT_H__) */ + +#if !defined(__UNISTD_H_SOURCED__) && !defined(__GETOPT_LONG_H__) +#define __GETOPT_LONG_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +struct option /* specification for a long form option... */ +{ + const char *name; /* option name, without leading hyphens */ + int has_arg; /* does it take an argument? */ + int *flag; /* where to save its status, or NULL */ + int val; /* its associated status value */ +}; + +enum /* permitted values for its `has_arg' field... */ +{ + no_argument = 0, /* option never takes an argument */ + required_argument, /* option always requires an argument */ + optional_argument /* option may take an argument */ +}; + +/* + * parse_long_options -- + * Parse long options in argc/argv argument vector. + * Returns -1 if short_too is set and the option does not match long_options. + */ +static int +parse_long_options(char * const *nargv, const char *options, + const struct option *long_options, int *idx, int short_too) +{ + char *current_argv, *has_equal; + size_t current_argv_len; + int i, ambiguous, match; + +#define IDENTICAL_INTERPRETATION(_x, _y) \ + (long_options[(_x)].has_arg == long_options[(_y)].has_arg && \ + long_options[(_x)].flag == long_options[(_y)].flag && \ + long_options[(_x)].val == long_options[(_y)].val) + + current_argv = place; + match = -1; + ambiguous = 0; + + optind++; + + if ((has_equal = strchr(current_argv, '=')) != NULL) { + /* argument found (--option=arg) */ + current_argv_len = has_equal - current_argv; + has_equal++; + } else + current_argv_len = strlen(current_argv); + + for (i = 0; long_options[i].name; i++) { + /* find matching long option */ + if (strncmp(current_argv, long_options[i].name, + current_argv_len)) + continue; + + if (strlen(long_options[i].name) == current_argv_len) { + /* exact match */ + match = i; + ambiguous = 0; + break; + } + /* + * If this is a known short option, don't allow + * a partial match of a single character. + */ + if (short_too && current_argv_len == 1) + continue; + + if (match == -1) /* partial match */ + match = i; + else if (!IDENTICAL_INTERPRETATION(i, match)) + ambiguous = 1; + } + if (ambiguous) { + /* ambiguous abbreviation */ + if (PRINT_ERROR) + warnx(ambig, (int)current_argv_len, + current_argv); + optopt = 0; + return (BADCH); + } + if (match != -1) { /* option found */ + if (long_options[match].has_arg == no_argument + && has_equal) { + if (PRINT_ERROR) + warnx(noarg, (int)current_argv_len, + current_argv); + /* + * XXX: GNU sets optopt to val regardless of flag + */ + if (long_options[match].flag == NULL) + optopt = long_options[match].val; + else + optopt = 0; + return (BADARG); + } + if (long_options[match].has_arg == required_argument || + long_options[match].has_arg == optional_argument) { + if (has_equal) + optarg = has_equal; + else if (long_options[match].has_arg == + required_argument) { + /* + * optional argument doesn't use next nargv + */ + optarg = nargv[optind++]; + } + } + if ((long_options[match].has_arg == required_argument) + && (optarg == NULL)) { + /* + * Missing argument; leading ':' indicates no error + * should be generated. + */ + if (PRINT_ERROR) + warnx(recargstring, + current_argv); + /* + * XXX: GNU sets optopt to val regardless of flag + */ + if (long_options[match].flag == NULL) + optopt = long_options[match].val; + else + optopt = 0; + --optind; + return (BADARG); + } + } else { /* unknown option */ + if (short_too) { + --optind; + return (-1); + } + if (PRINT_ERROR) + warnx(illoptstring, current_argv); + optopt = 0; + return (BADCH); + } + if (idx) + *idx = match; + if (long_options[match].flag) { + *long_options[match].flag = long_options[match].val; + return (0); + } else + return (long_options[match].val); +#undef IDENTICAL_INTERPRETATION +} + +/* + * getopt_internal -- + * Parse argc/argv argument vector. Called by user level routines. + */ +static int +getopt_internal(int nargc, char * const *nargv, const char *options, + const struct option *long_options, int *idx, int flags) +{ + char *oli; /* option letter list index */ + int optchar, short_too; + static int posixly_correct = -1; + + if (options == NULL) + return (-1); + + /* + * XXX Some GNU programs (like cvs) set optind to 0 instead of + * XXX using optreset. Work around this braindamage. + */ + if (optind == 0) + optind = optreset = 1; + + /* + * Disable GNU extensions if POSIXLY_CORRECT is set or options + * string begins with a '+'. + * + * CV, 2009-12-14: Check POSIXLY_CORRECT anew if optind == 0 or + * optreset != 0 for GNU compatibility. + */ + if (posixly_correct == -1 || optreset != 0) + posixly_correct = (getenv("POSIXLY_CORRECT") != NULL); + if (*options == '-') + flags |= FLAG_ALLARGS; + else if (posixly_correct || *options == '+') + flags &= ~FLAG_PERMUTE; + if (*options == '+' || *options == '-') + options++; + + optarg = NULL; + if (optreset) + nonopt_start = nonopt_end = -1; +start: + if (optreset || !*place) { /* update scanning pointer */ + optreset = 0; + if (optind >= nargc) { /* end of argument vector */ + place = EMSG; + if (nonopt_end != -1) { + /* do permutation, if we have to */ + permute_args(nonopt_start, nonopt_end, + optind, nargv); + optind -= nonopt_end - nonopt_start; + } + else if (nonopt_start != -1) { + /* + * If we skipped non-options, set optind + * to the first of them. + */ + optind = nonopt_start; + } + nonopt_start = nonopt_end = -1; + return (-1); + } + if (*(place = nargv[optind]) != '-' || + (place[1] == '\0' && strchr(options, '-') == NULL)) { + place = EMSG; /* found non-option */ + if (flags & FLAG_ALLARGS) { + /* + * GNU extension: + * return non-option as argument to option 1 + */ + optarg = nargv[optind++]; + return (INORDER); + } + if (!(flags & FLAG_PERMUTE)) { + /* + * If no permutation wanted, stop parsing + * at first non-option. + */ + return (-1); + } + /* do permutation */ + if (nonopt_start == -1) + nonopt_start = optind; + else if (nonopt_end != -1) { + permute_args(nonopt_start, nonopt_end, + optind, nargv); + nonopt_start = optind - + (nonopt_end - nonopt_start); + nonopt_end = -1; + } + optind++; + /* process next argument */ + goto start; + } + if (nonopt_start != -1 && nonopt_end == -1) + nonopt_end = optind; + + /* + * If we have "-" do nothing, if "--" we are done. + */ + if (place[1] != '\0' && *++place == '-' && place[1] == '\0') { + optind++; + place = EMSG; + /* + * We found an option (--), so if we skipped + * non-options, we have to permute. + */ + if (nonopt_end != -1) { + permute_args(nonopt_start, nonopt_end, + optind, nargv); + optind -= nonopt_end - nonopt_start; + } + nonopt_start = nonopt_end = -1; + return (-1); + } + } + + /* + * Check long options if: + * 1) we were passed some + * 2) the arg is not just "-" + * 3) either the arg starts with -- we are getopt_long_only() + */ + if (long_options != NULL && place != nargv[optind] && + (*place == '-' || (flags & FLAG_LONGONLY))) { + short_too = 0; + if (*place == '-') + place++; /* --foo long option */ + else if (*place != ':' && strchr(options, *place) != NULL) + short_too = 1; /* could be short option too */ + + optchar = parse_long_options(nargv, options, long_options, + idx, short_too); + if (optchar != -1) { + place = EMSG; + return (optchar); + } + } + + if ((optchar = (int)*place++) == (int)':' || + (optchar == (int)'-' && *place != '\0') || + (oli = (char*)strchr(options, optchar)) == NULL) { + /* + * If the user specified "-" and '-' isn't listed in + * options, return -1 (non-option) as per POSIX. + * Otherwise, it is an unknown option character (or ':'). + */ + if (optchar == (int)'-' && *place == '\0') + return (-1); + if (!*place) + ++optind; + if (PRINT_ERROR) + warnx(illoptchar, optchar); + optopt = optchar; + return (BADCH); + } + if (long_options != NULL && optchar == 'W' && oli[1] == ';') { + /* -W long-option */ + if (*place) /* no space */ + /* NOTHING */; + else if (++optind >= nargc) { /* no arg */ + place = EMSG; + if (PRINT_ERROR) + warnx(recargchar, optchar); + optopt = optchar; + return (BADARG); + } else /* white space */ + place = nargv[optind]; + optchar = parse_long_options(nargv, options, long_options, + idx, 0); + place = EMSG; + return (optchar); + } + if (*++oli != ':') { /* doesn't take argument */ + if (!*place) + ++optind; + } else { /* takes (optional) argument */ + optarg = NULL; + if (*place) /* no white space */ + optarg = place; + else if (oli[1] != ':') { /* arg not optional */ + if (++optind >= nargc) { /* no arg */ + place = EMSG; + if (PRINT_ERROR) + warnx(recargchar, optchar); + optopt = optchar; + return (BADARG); + } else + optarg = nargv[optind]; + } + place = EMSG; + ++optind; + } + /* dump back option letter */ + return (optchar); +} + +/* + * getopt_long -- + * Parse argc/argv argument vector. + */ +int +getopt_long(int nargc, char * const *nargv, const char *options, + const struct option *long_options, int *idx) +{ + + return (getopt_internal(nargc, nargv, options, long_options, idx, + FLAG_PERMUTE)); +} + +/* + * getopt_long_only -- + * Parse argc/argv argument vector. + */ +int +getopt_long_only(int nargc, char * const *nargv, const char *options, + const struct option *long_options, int *idx) +{ + + return (getopt_internal(nargc, nargv, options, long_options, idx, + FLAG_PERMUTE|FLAG_LONGONLY)); +} + +//extern int getopt_long(int nargc, char * const *nargv, const char *options, +// const struct option *long_options, int *idx); +//extern int getopt_long_only(int nargc, char * const *nargv, const char *options, +// const struct option *long_options, int *idx); +/* + * Previous MinGW implementation had... + */ +#ifndef HAVE_DECL_GETOPT +/* + * ...for the long form API only; keep this for compatibility. + */ +# define HAVE_DECL_GETOPT 1 +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* !defined(__UNISTD_H_SOURCED__) && !defined(__GETOPT_LONG_H__) */ From 21686314f30cb464adff96c24d6f989098a7240b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joakim=20S=C3=B6derberg?= Date: Sat, 12 Aug 2017 01:56:16 +0200 Subject: [PATCH 2/3] Fix Linux build --- CMakeLists.txt | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 235db48..9ab1fca 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -163,13 +163,14 @@ if (LINUX) list(APPEND SERVER_LIST "lpd8806_server") endif() - macro(create_server ) - foreach (SERVER ${SERVER_LIST}) - set(SRCS ${SERVER}.c ${SERVER_COMMON_SRCS}) + set(SRCS + "${PROJECT_SOURCE_DIR}/src/${SERVER}.c" + ${SERVER_COMMON_SRCS}) + source_group("Sources" FILES ${SRCS}) add_executable(${SERVER} ${SRCS} ${HDRS}) - target_link_libraries(${GLUT_LIBRARIES} m) + target_link_libraries(${SERVER} m) endforeach() endif() From ab6de0cab3e590dd517e00ca7fc77115a425a9d3 Mon Sep 17 00:00:00 2001 From: Joakim Soderberg Date: Wed, 6 Sep 2017 23:52:55 +0200 Subject: [PATCH 3/3] Fix dummy client --- src/dummy_client.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/dummy_client.c b/src/dummy_client.c index e7797b7..b102ddc 100644 --- a/src/dummy_client.c +++ b/src/dummy_client.c @@ -13,6 +13,12 @@ specific language governing permissions and limitations under the License. */ #include #include #include "opc.h" +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN 1 +#include +#include +#include +#endif // _WIN32 #define MAX_PIXELS (65535/3) #define MAX_INPUT_LENGTH (MAX_PIXELS*8)