From 1f6f68dba4aed30e55dd521e92eaf2fd8522ce8e Mon Sep 17 00:00:00 2001 From: Wirtos_new Date: Wed, 16 Jun 2021 11:36:26 +0300 Subject: [PATCH 1/4] initial work on removing posix and gcc dependencies and adding cmake with vcpkg --- .clang-format | 66 ++ .gitignore | 1 + app/CMakeLists.txt | 42 + app/src/cli.c | 1 - app/src/command.c | 5 +- app/src/config.h.in | 62 ++ app/src/decoder.c | 1 - app/src/device_msg.c | 2 +- app/src/device_msg.h | 3 +- app/src/fps_counter.h | 3 +- app/src/main.c | 2 +- app/src/receiver.c | 8 +- app/src/stream.c | 2 +- app/src/sys/unix/command.c | 2 +- app/src/sys/win/getopt.c | 1274 +++++++++++++++++++++++ app/src/sys/win/getopt.h | 193 ++++ app/src/util/cbuf.h | 41 +- app/src/util/net.c | 10 +- app/src/util/net.h | 8 +- app/tests/test_device_msg_deserialize.c | 4 +- app/vcpkg.json | 17 + 21 files changed, 1701 insertions(+), 46 deletions(-) create mode 100644 .clang-format create mode 100644 app/CMakeLists.txt create mode 100644 app/src/config.h.in create mode 100644 app/src/sys/win/getopt.c create mode 100644 app/src/sys/win/getopt.h create mode 100644 app/vcpkg.json diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000000..5a42ed7c09 --- /dev/null +++ b/.clang-format @@ -0,0 +1,66 @@ +# Generated from CLion C/C++ Code Style settings +BasedOnStyle: LLVM +AccessModifierOffset: -4 +AlignAfterOpenBracket: Align +AlignConsecutiveAssignments: None +AlignOperands: Align +AllowAllArgumentsOnNextLine: false +AllowAllConstructorInitializersOnNextLine: false +AllowAllParametersOfDeclarationOnNextLine: false +AllowShortBlocksOnASingleLine: Always +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: All +AllowShortIfStatementsOnASingleLine: Always +AllowShortLambdasOnASingleLine: All +AllowShortLoopsOnASingleLine: true +AlwaysBreakAfterReturnType: None +AlwaysBreakTemplateDeclarations: Yes +BreakBeforeBraces: Custom +BraceWrapping: + AfterCaseLabel: false + AfterClass: false + AfterControlStatement: Never + AfterEnum: false + AfterFunction: false + AfterNamespace: false + AfterUnion: false + BeforeCatch: false + BeforeElse: false + IndentBraces: false + SplitEmptyFunction: false + SplitEmptyRecord: true +BreakBeforeBinaryOperators: None +BreakBeforeTernaryOperators: true +BreakConstructorInitializers: BeforeColon +BreakInheritanceList: BeforeColon +ColumnLimit: 0 +CompactNamespaces: false +ContinuationIndentWidth: 4 +IndentCaseLabels: true +IndentPPDirectives: None +IndentWidth: 4 +KeepEmptyLinesAtTheStartOfBlocks: true +MaxEmptyLinesToKeep: 2 +NamespaceIndentation: All +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: true +PointerAlignment: Right +ReflowComments: false +SpaceAfterCStyleCast: true +SpaceAfterLogicalNot: false +SpaceAfterTemplateKeyword: false +SpaceBeforeAssignmentOperators: true +SpaceBeforeCpp11BracedList: false +SpaceBeforeCtorInitializerColon: true +SpaceBeforeInheritanceColon: true +SpaceBeforeParens: ControlStatements +SpaceBeforeRangeBasedForLoopColon: true +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 0 +SpacesInAngles: false +SpacesInCStyleCastParentheses: false +SpacesInContainerLiterals: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +TabWidth: 4 +UseTab: Never diff --git a/.gitignore b/.gitignore index 2829d835f2..01e4d0caf5 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ build/ .gradle/ /x/ local.properties +cmake-build-*/ diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt new file mode 100644 index 0000000000..979ddb9895 --- /dev/null +++ b/app/CMakeLists.txt @@ -0,0 +1,42 @@ +cmake_minimum_required(VERSION 3.14) +project(scrcpy C) + +configure_file(src/config.h.in ${CMAKE_CURRENT_BINARY_DIR}/config.h) + +add_executable(scrcpy + src/main.c + src/cli.c + src/command.c + src/control_msg.c + src/controller.c + src/decoder.c + src/device.c + src/device_msg.c + src/event_converter.c + src/file_handler.c + src/fps_counter.c + src/input_manager.c + src/opengl.c + src/receiver.c + src/recorder.c + src/scrcpy.c + src/screen.c + src/server.c + src/stream.c + src/tiny_xpm.c + src/video_buffer.c + src/util/net.c + src/util/str_util.c + $<$: + ${CMAKE_CURRENT_LIST_DIR}/src/sys/win/getopt.c + >) + +find_package(SDL2 CONFIG REQUIRED) +find_package(FFMPEG COMPONENTS avformat avcodec avutil REQUIRED) + +target_include_directories(scrcpy + PRIVATE + ${CMAKE_CURRENT_BINARY_DIR} + ${FFMPEG_INCLUDE_DIRS} + $<$:${CMAKE_CURRENT_LIST_DIR}/src/sys/win/>) +target_link_libraries(scrcpy SDL2::SDL2 SDL2::SDL2main ${FFMPEG_LIBRARIES}) \ No newline at end of file diff --git a/app/src/cli.c b/app/src/cli.c index 5d5bcf1050..a6fa3c7134 100644 --- a/app/src/cli.c +++ b/app/src/cli.c @@ -4,7 +4,6 @@ #include #include #include -#include #include "config.h" #include "scrcpy.h" diff --git a/app/src/command.c b/app/src/command.c index 81047b7a32..273b655a98 100644 --- a/app/src/command.c +++ b/app/src/command.c @@ -104,7 +104,7 @@ show_adb_err_msg(enum process_result err, const char *const argv[]) { process_t adb_execute(const char *serial, const char *const adb_cmd[], size_t len) { - const char *cmd[len + 4]; + const char **cmd = malloc(sizeof(*cmd) * (len + 4)); int i; process_t process; cmd[0] = get_adb_command(); @@ -121,8 +121,9 @@ adb_execute(const char *serial, const char *const adb_cmd[], size_t len) { enum process_result r = cmd_execute(cmd, &process); if (r != PROCESS_SUCCESS) { show_adb_err_msg(r, cmd); - return PROCESS_NONE; + process = PROCESS_NONE; } + free(cmd); return process; } diff --git a/app/src/config.h.in b/app/src/config.h.in new file mode 100644 index 0000000000..aab6d366f9 --- /dev/null +++ b/app/src/config.h.in @@ -0,0 +1,62 @@ +#ifndef SCRCPY_CONFIG_H_IN_H +#define SCRCPY_CONFIG_H_IN_H + + +// expose the build type +/*conf.set('NDEBUG', get_option('buildtype') != 'debug')*/ + +// the version, updated on release +#define SCRCPY_VERSION "${SCRCPY_VERSION}" +// the prefix used during configuration (meson --prefix=PREFIX) +#define PREFIX "${PREFIX}" + +// build a "portable" version (with scrcpy-server accessible from the same +// directory as the executable) +#cmakedefine01 PORTABLE + +// the default client TCP port range for the "adb reverse" tunnel +// overridden by option --port +#cmakedefine DEFAULT_LOCAL_PORT_RANGE_FIRST ${DEFAULT_LOCAL_PORT_RANGE_FIRST} +#ifndef DEFAULT_LOCAL_PORT_RANGE_FIRST + #define DEFAULT_LOCAL_PORT_RANGE_FIRST 27183 +#endif + +#cmakedefine DEFAULT_LOCAL_PORT_RANGE_LAST ${DEFAULT_LOCAL_PORT_RANGE_LAST} +#ifndef DEFAULT_LOCAL_PORT_RANGE_LAST + #define DEFAULT_LOCAL_PORT_RANGE_LAST 27199 +#endif + + +// the default max video size for both dimensions, in pixels +// overridden by option --max-size +#cmakedefine DEFAULT_MAX_SIZE ${DEFAULT_MAX_SIZE} +#ifndef DEFAULT_MAX_SIZE + #define DEFAULT_MAX_SIZE 0 /* 0 - unlimited */ +#endif + +// the default video orientation +// natural device orientation is 0 and each increment adds 90 degrees +// counterclockwise +// overridden by option --lock-video-orientation +#cmakedefine DEFAULT_LOCK_VIDEO_ORIENTATION ${DEFAULT_LOCK_VIDEO_ORIENTATION} +#ifndef DEFAULT_LOCK_VIDEO_ORIENTATION + #define DEFAULT_LOCK_VIDEO_ORIENTATION -1 /* -1 - unlocked */ +#endif + +// the default video bitrate, in bits/second +// overridden by option --bit-rate +#cmakedefine DEFAULT_BIT_RATE ${DEFAULT_BIT_RATE} +#ifndef DEFAULT_BIT_RATE + #define DEFAULT_BIT_RATE 8000000 // 8Mbps +#endif +// enable High DPI support +#define HIDPI_SUPPORT ${HIDPI_SUPPORT} + +// run a server debugger and wait for a client to be attached +#define SERVER_DEBUGGER ${SERVER_DEBUGGER} + +// select the debugger method ('old' for Android < 9, 'new' for Android >= 9) +#cmakedefine01 SERVER_DEBUGGER_METHOD_NEW + + +#endif //SCRCPY_CONFIG_H_IN_H diff --git a/app/src/decoder.c b/app/src/decoder.c index 49d4ce86f8..8aa27ddd8c 100644 --- a/app/src/decoder.c +++ b/app/src/decoder.c @@ -5,7 +5,6 @@ #include #include #include -#include #include "config.h" #include "compat.h" diff --git a/app/src/device_msg.c b/app/src/device_msg.c index 09e6893674..48a1f4f8b4 100644 --- a/app/src/device_msg.c +++ b/app/src/device_msg.c @@ -6,7 +6,7 @@ #include "util/buffer_util.h" #include "util/log.h" -ssize_t +size_t device_msg_deserialize(const unsigned char *buf, size_t len, struct device_msg *msg) { if (len < 5) { diff --git a/app/src/device_msg.h b/app/src/device_msg.h index 4b681e2c37..1341ff17b9 100644 --- a/app/src/device_msg.h +++ b/app/src/device_msg.h @@ -3,7 +3,6 @@ #include #include -#include #include "config.h" @@ -25,7 +24,7 @@ struct device_msg { }; // return the number of bytes consumed (0 for no msg available, -1 on error) -ssize_t +size_t device_msg_deserialize(const unsigned char *buf, size_t len, struct device_msg *msg); diff --git a/app/src/fps_counter.h b/app/src/fps_counter.h index 52157172ac..801cb7db1e 100644 --- a/app/src/fps_counter.h +++ b/app/src/fps_counter.h @@ -1,11 +1,12 @@ #ifndef FPSCOUNTER_H #define FPSCOUNTER_H -#include #include #include #include #include +/* todo: this */ +#define atomic_bool bool #include "config.h" diff --git a/app/src/main.c b/app/src/main.c index 71125673b2..82ce632802 100644 --- a/app/src/main.c +++ b/app/src/main.c @@ -2,7 +2,7 @@ #include #include -#include +#include #include #define SDL_MAIN_HANDLED // avoid link error on Linux Windows Subsystem #include diff --git a/app/src/receiver.c b/app/src/receiver.c index 307eb5d580..ab4b23c684 100644 --- a/app/src/receiver.c +++ b/app/src/receiver.c @@ -41,12 +41,12 @@ process_msg(struct device_msg *msg) { } } -static ssize_t +static size_t process_msgs(const unsigned char *buf, size_t len) { size_t head = 0; for (;;) { struct device_msg msg; - ssize_t r = device_msg_deserialize(&buf[head], len - head, &msg); + size_t r = device_msg_deserialize(&buf[head], len - head, &msg); if (r == -1) { return -1; } @@ -74,7 +74,7 @@ run_receiver(void *data) { for (;;) { assert(head < DEVICE_MSG_MAX_SIZE); - ssize_t r = net_recv(receiver->control_socket, buf + head, + size_t r = net_recv(receiver->control_socket, buf + head, DEVICE_MSG_MAX_SIZE - head); if (r <= 0) { LOGD("Receiver stopped"); @@ -82,7 +82,7 @@ run_receiver(void *data) { } head += r; - ssize_t consumed = process_msgs(buf, head); + size_t consumed = process_msgs(buf, head); if (consumed == -1) { // an error occurred break; diff --git a/app/src/stream.c b/app/src/stream.c index dd2dbd763e..f6c71b9911 100644 --- a/app/src/stream.c +++ b/app/src/stream.c @@ -36,7 +36,7 @@ stream_recv_packet(struct stream *stream, AVPacket *packet) { // It is followed by bytes containing the packet/frame. uint8_t header[HEADER_SIZE]; - ssize_t r = net_recv_all(stream->socket, header, HEADER_SIZE); + size_t r = net_recv_all(stream->socket, header, HEADER_SIZE); if (r < HEADER_SIZE) { return false; } diff --git a/app/src/sys/unix/command.c b/app/src/sys/unix/command.c index c4c262e484..1241ce0619 100644 --- a/app/src/sys/unix/command.c +++ b/app/src/sys/unix/command.c @@ -155,7 +155,7 @@ get_executable_path(void) { // #ifdef __linux__ char buf[PATH_MAX + 1]; // +1 for the null byte - ssize_t len = readlink("/proc/self/exe", buf, PATH_MAX); + size_t len = readlink("/proc/self/exe", buf, PATH_MAX); if (len == -1) { perror("readlink"); return NULL; diff --git a/app/src/sys/win/getopt.c b/app/src/sys/win/getopt.c new file mode 100644 index 0000000000..948c72f583 --- /dev/null +++ b/app/src/sys/win/getopt.c @@ -0,0 +1,1274 @@ +/* Getopt for GNU. +NOTE: getopt is now part of the C library, so if you don't know what +"Keep this file name-space clean" means, talk to drepper@gnu.org +before changing it! +Copyright (C) 1987,88,89,90,91,92,93,94,95,96,98,99,2000,2001 +Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with the GNU C Library; if not, write to the Free +Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +02111-1307 USA. */ + +/* This tells Alpha OSF/1 not to define a getopt prototype in . +Ditto for AIX 3.2 and . */ +#ifndef _NO_PROTO +# define _NO_PROTO +#endif + +#ifdef HAVE_CONFIG_H +# include +#endif + +#if !defined __STDC__ || !__STDC__ +/* This is a separate conditional since some stdc systems +reject `defined (const)'. */ +# ifndef const +# define const +# endif +#endif + +#include + +/* Comment out all this code if we are using the GNU C Library, and are not +actually compiling the library itself. This code is part of the GNU C +Library, but also included in many other GNU distributions. Compiling +and linking in this code is a waste when using the GNU C library +(especially if it is a shared library). Rather than having every GNU +program understand `configure --with-gnu-libc' and omit the object files, +it is simpler to just do this in the source for each such file. */ + +#define GETOPT_INTERFACE_VERSION 2 +#if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2 +# include +# if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION +# define ELIDE_CODE +# endif +#endif + +#ifndef ELIDE_CODE + + +/* This needs to come after some library #include +to get __GNU_LIBRARY__ defined. */ +#ifdef __GNU_LIBRARY__ +/* Don't include stdlib.h for non-GNU C libraries because some of them +contain conflicting prototypes for getopt. */ +# include +# include +#endif /* GNU C library. */ + +#ifdef VMS +# include +# if HAVE_STRING_H - 0 +# include +# endif +#endif + +#ifndef _ +/* This is for other GNU distributions with internationalized messages. */ +# if (HAVE_LIBINTL_H && ENABLE_NLS) || defined _LIBC +# include +# ifndef _ +# define _(msgid) gettext (msgid) +# endif +# else +# define _(msgid) (msgid) +# endif +# if defined _LIBC && defined USE_IN_LIBIO +# include +# endif +#endif + +/* This version of `getopt' appears to the caller like standard Unix `getopt' +but it behaves differently for the user, since it allows the user +to intersperse the options with the other arguments. + +As `getopt' works, it permutes the elements of ARGV so that, +when it is done, all the options precede everything else. Thus +all application programs are extended to handle flexible argument order. + +Setting the environment variable POSIXLY_CORRECT disables permutation. +Then the behavior is completely standard. + +GNU application programs can use a third alternative mode in which +they can distinguish the relative order of options and other arguments. */ + +#include "getopt.h" + +/* For communication from `getopt' to the caller. +When `getopt' finds an option that takes an argument, +the argument value is returned here. +Also, when `ordering' is RETURN_IN_ORDER, +each non-option ARGV-element is returned here. */ + +char *optarg; + +/* Index in ARGV of the next element to be scanned. +This is used for communication to and from the caller +and for communication between successive calls to `getopt'. + +On entry to `getopt', zero means this is the first call; initialize. + +When `getopt' returns -1, this is the index of the first of the +non-option elements that the caller should itself scan. + +Otherwise, `optind' communicates from one call to the next +how much of ARGV has been scanned so far. */ + +/* 1003.2 says this must be 1 before any call. */ +int optind = 1; + +/* Formerly, initialization of getopt depended on optind==0, which +causes problems with re-calling getopt as programs generally don't +know that. */ + +int __getopt_initialized; + +/* The next char to be scanned in the option-element +in which the last option character we returned was found. +This allows us to pick up the scan where we left off. + +If this is zero, or a null string, it means resume the scan +by advancing to the next ARGV-element. */ + +static char *nextchar; + +/* Callers store zero here to inhibit the error message +for unrecognized options. */ + +int opterr = 1; + +/* Set to an option character which was unrecognized. +This must be initialized on some systems to avoid linking in the +system's own getopt implementation. */ + +int optopt = '?'; + +/* Describe how to deal with options that follow non-option ARGV-elements. + +If the caller did not specify anything, +the default is REQUIRE_ORDER if the environment variable +POSIXLY_CORRECT is defined, PERMUTE otherwise. + +REQUIRE_ORDER means don't recognize them as options; +stop option processing when the first non-option is seen. +This is what Unix does. +This mode of operation is selected by either setting the environment +variable POSIXLY_CORRECT, or using `+' as the first character +of the list of option characters. + +PERMUTE is the default. We permute the contents of ARGV as we scan, +so that eventually all the non-options are at the end. This allows options +to be given in any order, even with programs that were not written to +expect this. + +RETURN_IN_ORDER is an option available to programs that were written +to expect options and other ARGV-elements in any order and that care about +the ordering of the two. We describe each non-option ARGV-element +as if it were the argument of an option with character code 1. +Using `-' as the first character of the list of option characters +selects this mode of operation. + +The special argument `--' forces an end of option-scanning regardless +of the value of `ordering'. In the case of RETURN_IN_ORDER, only +`--' can cause `getopt' to return -1 with `optind' != ARGC. */ + +static enum +{ + REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER +} ordering; + +/* Value of POSIXLY_CORRECT environment variable. */ +static char *posixly_correct; + +#ifdef __GNU_LIBRARY__ +/* We want to avoid inclusion of string.h with non-GNU libraries +because there are many ways it can cause trouble. +On some systems, it contains special magic macros that don't work +in GCC. */ +# include +# define my_index strchr +#else + +#define HAVE_STRING_H 1 +# if HAVE_STRING_H +# include +# else +# include +# endif + +/* Avoid depending on library functions or files +whose names are inconsistent. */ + +#ifndef getenv +extern char *getenv(); +#endif + +static char * +my_index(str, chr) +const char *str; +int chr; +{ + while (*str) + { + if (*str == chr) + return (char *)str; + str++; + } + return 0; +} + +/* If using GCC, we can safely declare strlen this way. +If not using GCC, it is ok not to declare it. */ +#ifdef __GNUC__ +/* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h. +That was relevant to code that was here before. */ +# if (!defined __STDC__ || !__STDC__) && !defined strlen +/* gcc with -traditional declares the built-in strlen to return int, +and has done so at least since version 2.4.5. -- rms. */ +extern int strlen(const char *); +# endif /* not __STDC__ */ +#endif /* __GNUC__ */ + +#endif /* not __GNU_LIBRARY__ */ + +/* Handle permutation of arguments. */ + +/* Describe the part of ARGV that contains non-options that have +been skipped. `first_nonopt' is the index in ARGV of the first of them; +`last_nonopt' is the index after the last of them. */ + +static int first_nonopt; +static int last_nonopt; + +#ifdef _LIBC +/* Stored original parameters. +XXX This is no good solution. We should rather copy the args so +that we can compare them later. But we must not use malloc(3). */ +extern int __libc_argc; +extern char **__libc_argv; + +/* Bash 2.0 gives us an environment variable containing flags +indicating ARGV elements that should not be considered arguments. */ + +# ifdef USE_NONOPTION_FLAGS +/* Defined in getopt_init.c */ +extern char *__getopt_nonoption_flags; + +static int nonoption_flags_max_len; +static int nonoption_flags_len; +# endif + +# ifdef USE_NONOPTION_FLAGS +# define SWAP_FLAGS(ch1, ch2) \ +if (nonoption_flags_len > 0) \ +{ \ + char __tmp = __getopt_nonoption_flags[ch1]; \ + __getopt_nonoption_flags[ch1] = __getopt_nonoption_flags[ch2]; \ + __getopt_nonoption_flags[ch2] = __tmp; \ +} +# else +# define SWAP_FLAGS(ch1, ch2) +# endif +#else /* !_LIBC */ +# define SWAP_FLAGS(ch1, ch2) +#endif /* _LIBC */ + +/* Exchange two adjacent subsequences of ARGV. +One subsequence is elements [first_nonopt,last_nonopt) +which contains all the non-options that have been skipped so far. +The other is elements [last_nonopt,optind), which contains all +the options processed since those non-options were skipped. + +`first_nonopt' and `last_nonopt' are relocated so that they describe +the new indices of the non-options in ARGV after they are moved. */ + +#if defined __STDC__ && __STDC__ +static void exchange(char **); +#endif + +static void +exchange(argv) +char **argv; +{ + int bottom = first_nonopt; + int middle = last_nonopt; + int top = optind; + char *tem; + + /* Exchange the shorter segment with the far end of the longer segment. + That puts the shorter segment into the right place. + It leaves the longer segment in the right place overall, + but it consists of two parts that need to be swapped next. */ + +#if defined _LIBC && defined USE_NONOPTION_FLAGS + /* First make sure the handling of the `__getopt_nonoption_flags' + string can work normally. Our top argument must be in the range + of the string. */ + if (nonoption_flags_len > 0 && top >= nonoption_flags_max_len) + { + /* We must extend the array. The user plays games with us and + presents new arguments. */ + char *new_str = malloc(top + 1); + if (new_str == NULL) + nonoption_flags_len = nonoption_flags_max_len = 0; + else + { + memset(__mempcpy(new_str, __getopt_nonoption_flags, + nonoption_flags_max_len), + '\0', top + 1 - nonoption_flags_max_len); + nonoption_flags_max_len = top + 1; + __getopt_nonoption_flags = new_str; + } + } +#endif + + while (top > middle && middle > bottom) + { + if (top - middle > middle - bottom) + { + /* Bottom segment is the short one. */ + int len = middle - bottom; + register int i; + + /* Swap it with the top part of the top segment. */ + for (i = 0; i < len; i++) + { + tem = argv[bottom + i]; + argv[bottom + i] = argv[top - (middle - bottom) + i]; + argv[top - (middle - bottom) + i] = tem; + SWAP_FLAGS(bottom + i, top - (middle - bottom) + i); + } + /* Exclude the moved bottom segment from further swapping. */ + top -= len; + } + else + { + /* Top segment is the short one. */ + int len = top - middle; + register int i; + + /* Swap it with the bottom part of the bottom segment. */ + for (i = 0; i < len; i++) + { + tem = argv[bottom + i]; + argv[bottom + i] = argv[middle + i]; + argv[middle + i] = tem; + SWAP_FLAGS(bottom + i, middle + i); + } + /* Exclude the moved top segment from further swapping. */ + bottom += len; + } + } + + /* Update records for the slots the non-options now occupy. */ + + first_nonopt += (optind - last_nonopt); + last_nonopt = optind; +} + +/* Initialize the internal data when the first call is made. */ + +#if defined __STDC__ && __STDC__ +static const char *_getopt_initialize(int, char *const *, const char *); +#endif +static const char * +_getopt_initialize(argc, argv, optstring) +int argc; +char *const *argv; +const char *optstring; +{ + /* Start processing options with ARGV-element 1 (since ARGV-element 0 + is the program name); the sequence of previously skipped + non-option ARGV-elements is empty. */ + + first_nonopt = last_nonopt = optind; + + nextchar = NULL; + + posixly_correct = getenv("POSIXLY_CORRECT"); + + /* Determine how to handle the ordering of options and nonoptions. */ + + if (optstring[0] == '-') + { + ordering = RETURN_IN_ORDER; + ++optstring; + } + else if (optstring[0] == '+') + { + ordering = REQUIRE_ORDER; + ++optstring; + } + else if (posixly_correct != NULL) + ordering = REQUIRE_ORDER; + else + ordering = PERMUTE; + +#if defined _LIBC && defined USE_NONOPTION_FLAGS + if (posixly_correct == NULL + && argc == __libc_argc && argv == __libc_argv) + { + if (nonoption_flags_max_len == 0) + { + if (__getopt_nonoption_flags == NULL + || __getopt_nonoption_flags[0] == '\0') + nonoption_flags_max_len = -1; + else + { + const char *orig_str = __getopt_nonoption_flags; + int len = nonoption_flags_max_len = strlen(orig_str); + if (nonoption_flags_max_len < argc) + nonoption_flags_max_len = argc; + __getopt_nonoption_flags = + (char *)malloc(nonoption_flags_max_len); + if (__getopt_nonoption_flags == NULL) + nonoption_flags_max_len = -1; + else + memset(__mempcpy(__getopt_nonoption_flags, orig_str, len), + '\0', nonoption_flags_max_len - len); + } + } + nonoption_flags_len = nonoption_flags_max_len; + } + else + nonoption_flags_len = 0; +#endif + + return optstring; +} + +/* Scan elements of ARGV (whose length is ARGC) for option characters +given in OPTSTRING. + +If an element of ARGV starts with '-', and is not exactly "-" or "--", +then it is an option element. The characters of this element +(aside from the initial '-') are option characters. If `getopt' +is called repeatedly, it returns successively each of the option characters +from each of the option elements. + +If `getopt' finds another option character, it returns that character, +updating `optind' and `nextchar' so that the next call to `getopt' can +resume the scan with the following option character or ARGV-element. + +If there are no more option characters, `getopt' returns -1. +Then `optind' is the index in ARGV of the first ARGV-element +that is not an option. (The ARGV-elements have been permuted +so that those that are not options now come last.) + +OPTSTRING is a string containing the legitimate option characters. +If an option character is seen that is not listed in OPTSTRING, +return '?' after printing an error message. If you set `opterr' to +zero, the error message is suppressed but we still return '?'. + +If a char in OPTSTRING is followed by a colon, that means it wants an arg, +so the following text in the same ARGV-element, or the text of the following +ARGV-element, is returned in `optarg'. Two colons mean an option that +wants an optional arg; if there is text in the current ARGV-element, +it is returned in `optarg', otherwise `optarg' is set to zero. + +If OPTSTRING starts with `-' or `+', it requests different methods of +handling the non-option ARGV-elements. +See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above. + +Long-named options begin with `--' instead of `-'. +Their names may be abbreviated as long as the abbreviation is unique +or is an exact match for some defined option. If they have an +argument, it follows the option name in the same ARGV-element, separated +from the option name by a `=', or else the in next ARGV-element. +When `getopt' finds a long-named option, it returns 0 if that option's +`flag' field is nonzero, the value of the option's `val' field +if the `flag' field is zero. + +The elements of ARGV aren't really const, because we permute them. +But we pretend they're const in the prototype to be compatible +with other systems. + +LONGOPTS is a vector of `struct option' terminated by an +element containing a name which is zero. + +LONGIND returns the index in LONGOPT of the long-named option found. +It is only valid when a long-named option has been found by the most +recent call. + +If LONG_ONLY is nonzero, '-' as well as '--' can introduce +long-named options. */ + +int +_getopt_internal(argc, argv, optstring, longopts, longind, long_only) +int argc; +char *const *argv; +const char *optstring; +const struct option *longopts; +int *longind; +int long_only; +{ + int print_errors = opterr; + if (optstring[0] == ':') + print_errors = 0; + + if (argc < 1) + return -1; + + optarg = NULL; + + if (optind == 0 || !__getopt_initialized) + { + if (optind == 0) + optind = 1; /* Don't scan ARGV[0], the program name. */ + optstring = _getopt_initialize(argc, argv, optstring); + __getopt_initialized = 1; + } + + /* Test whether ARGV[optind] points to a non-option argument. + Either it does not have option syntax, or there is an environment flag + from the shell indicating it is not an option. The later information + is only used when the used in the GNU libc. */ +#if defined _LIBC && defined USE_NONOPTION_FLAGS +# define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0' \ + || (optind < nonoption_flags_len \ + && __getopt_nonoption_flags[optind] == '1')) +#else +# define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0') +#endif + + if (nextchar == NULL || *nextchar == '\0') + { + /* Advance to the next ARGV-element. */ + + /* Give FIRST_NONOPT & LAST_NONOPT rational values if OPTIND has been + moved back by the user (who may also have changed the arguments). */ + if (last_nonopt > optind) + last_nonopt = optind; + if (first_nonopt > optind) + first_nonopt = optind; + + if (ordering == PERMUTE) + { + /* If we have just processed some options following some non-options, + exchange them so that the options come first. */ + + if (first_nonopt != last_nonopt && last_nonopt != optind) + exchange((char **)argv); + else if (last_nonopt != optind) + first_nonopt = optind; + + /* Skip any additional non-options + and extend the range of non-options previously skipped. */ + + while (optind < argc && NONOPTION_P) + optind++; + last_nonopt = optind; + } + + /* The special ARGV-element `--' means premature end of options. + Skip it like a null option, + then exchange with previous non-options as if it were an option, + then skip everything else like a non-option. */ + + if (optind != argc && !strcmp(argv[optind], "--")) + { + optind++; + + if (first_nonopt != last_nonopt && last_nonopt != optind) + exchange((char **)argv); + else if (first_nonopt == last_nonopt) + first_nonopt = optind; + last_nonopt = argc; + + optind = argc; + } + + /* If we have done all the ARGV-elements, stop the scan + and back over any non-options that we skipped and permuted. */ + + if (optind == argc) + { + /* Set the next-arg-index to point at the non-options + that we previously skipped, so the caller will digest them. */ + if (first_nonopt != last_nonopt) + optind = first_nonopt; + return -1; + } + + /* If we have come to a non-option and did not permute it, + either stop the scan or describe it to the caller and pass it by. */ + + if (NONOPTION_P) + { + if (ordering == REQUIRE_ORDER) + return -1; + optarg = argv[optind++]; + return 1; + } + + /* We have found another option-ARGV-element. + Skip the initial punctuation. */ + + nextchar = (argv[optind] + 1 + + (longopts != NULL && argv[optind][1] == '-')); + } + + /* Decode the current option-ARGV-element. */ + + /* Check whether the ARGV-element is a long option. + + If long_only and the ARGV-element has the form "-f", where f is + a valid short option, don't consider it an abbreviated form of + a long option that starts with f. Otherwise there would be no + way to give the -f short option. + + On the other hand, if there's a long option "fubar" and + the ARGV-element is "-fu", do consider that an abbreviation of + the long option, just like "--fu", and not "-f" with arg "u". + + This distinction seems to be the most useful approach. */ + + if (longopts != NULL + && (argv[optind][1] == '-' + || (long_only && (argv[optind][2] || !my_index(optstring, argv[optind][1]))))) + { + char *nameend; + const struct option *p; + const struct option *pfound = NULL; + int exact = 0; + int ambig = 0; + int indfound = -1; + int option_index; + + for (nameend = nextchar; *nameend && *nameend != '='; nameend++) + /* Do nothing. */; + + /* Test all long options for either exact match + or abbreviated matches. */ + for (p = longopts, option_index = 0; p->name; p++, option_index++) + if (!strncmp(p->name, nextchar, nameend - nextchar)) + { + if ((unsigned int)(nameend - nextchar) + == (unsigned int)strlen(p->name)) + { + /* Exact match found. */ + pfound = p; + indfound = option_index; + exact = 1; + break; + } + else if (pfound == NULL) + { + /* First nonexact match found. */ + pfound = p; + indfound = option_index; + } + else if (long_only + || pfound->has_arg != p->has_arg + || pfound->flag != p->flag + || pfound->val != p->val) + /* Second or later nonexact match found. */ + ambig = 1; + } + + if (ambig && !exact) + { + if (print_errors) + { +#if defined _LIBC && defined USE_IN_LIBIO + char *buf; + + __asprintf(&buf, _("%s: option `%s' is ambiguous\n"), + argv[0], argv[optind]); + + if (_IO_fwide(stderr, 0) > 0) + __fwprintf(stderr, L"%s", buf); + else + fputs(buf, stderr); + + free(buf); +#else + fprintf(stderr, _("%s: option `%s' is ambiguous\n"), + argv[0], argv[optind]); +#endif + } + nextchar += strlen(nextchar); + optind++; + optopt = 0; + return '?'; + } + + if (pfound != NULL) + { + option_index = indfound; + optind++; + if (*nameend) + { + /* Don't test has_arg with >, because some C compilers don't + allow it to be used on enums. */ + if (pfound->has_arg) + optarg = nameend + 1; + else + { + if (print_errors) + { +#if defined _LIBC && defined USE_IN_LIBIO + char *buf; +#endif + + if (argv[optind - 1][1] == '-') + { + /* --option */ +#if defined _LIBC && defined USE_IN_LIBIO + __asprintf(&buf, _("\ + %s: option `--%s' doesn't allow an argument\n"), + argv[0], pfound->name); +#else + fprintf(stderr, _("\ + %s: option `--%s' doesn't allow an argument\n"), + argv[0], pfound->name); +#endif + } + else + { + /* +option or -option */ +#if defined _LIBC && defined USE_IN_LIBIO + __asprintf(&buf, _("\ + %s: option `%c%s' doesn't allow an argument\n"), + argv[0], argv[optind - 1][0], + pfound->name); +#else + fprintf(stderr, _("\ + %s: option `%c%s' doesn't allow an argument\n"), + argv[0], argv[optind - 1][0], pfound->name); +#endif + } + +#if defined _LIBC && defined USE_IN_LIBIO + if (_IO_fwide(stderr, 0) > 0) + __fwprintf(stderr, L"%s", buf); + else + fputs(buf, stderr); + + free(buf); +#endif + } + + nextchar += strlen(nextchar); + + optopt = pfound->val; + return '?'; + } + } + else if (pfound->has_arg == 1) + { + if (optind < argc) + optarg = argv[optind++]; + else + { + if (print_errors) + { +#if defined _LIBC && defined USE_IN_LIBIO + char *buf; + + __asprintf(&buf, + _("%s: option `%s' requires an argument\n"), + argv[0], argv[optind - 1]); + + if (_IO_fwide(stderr, 0) > 0) + __fwprintf(stderr, L"%s", buf); + else + fputs(buf, stderr); + + free(buf); +#else + fprintf(stderr, + _("%s: option `%s' requires an argument\n"), + argv[0], argv[optind - 1]); +#endif + } + nextchar += strlen(nextchar); + optopt = pfound->val; + return optstring[0] == ':' ? ':' : '?'; + } + } + nextchar += strlen(nextchar); + if (longind != NULL) + *longind = option_index; + if (pfound->flag) + { + *(pfound->flag) = pfound->val; + return 0; + } + return pfound->val; + } + + /* Can't find it as a long option. If this is not getopt_long_only, + or the option starts with '--' or is not a valid short + option, then it's an error. + Otherwise interpret it as a short option. */ + if (!long_only || argv[optind][1] == '-' + || my_index(optstring, *nextchar) == NULL) + { + if (print_errors) + { +#if defined _LIBC && defined USE_IN_LIBIO + char *buf; +#endif + + if (argv[optind][1] == '-') + { + /* --option */ +#if defined _LIBC && defined USE_IN_LIBIO + __asprintf(&buf, _("%s: unrecognized option `--%s'\n"), + argv[0], nextchar); +#else + fprintf(stderr, _("%s: unrecognized option `--%s'\n"), + argv[0], nextchar); +#endif + } + else + { + /* +option or -option */ +#if defined _LIBC && defined USE_IN_LIBIO + __asprintf(&buf, _("%s: unrecognized option `%c%s'\n"), + argv[0], argv[optind][0], nextchar); +#else + fprintf(stderr, _("%s: unrecognized option `%c%s'\n"), + argv[0], argv[optind][0], nextchar); +#endif + } + +#if defined _LIBC && defined USE_IN_LIBIO + if (_IO_fwide(stderr, 0) > 0) + __fwprintf(stderr, L"%s", buf); + else + fputs(buf, stderr); + + free(buf); +#endif + } + nextchar = (char *) ""; + optind++; + optopt = 0; + return '?'; + } + } + + /* Look at and handle the next short option-character. */ + + { + char c = *nextchar++; + char *temp = my_index(optstring, c); + + /* Increment `optind' when we start to process its last character. */ + if (*nextchar == '\0') + ++optind; + + if (temp == NULL || c == ':') + { + if (print_errors) + { +#if defined _LIBC && defined USE_IN_LIBIO + char *buf; +#endif + + if (posixly_correct) + { + /* 1003.2 specifies the format of this message. */ +#if defined _LIBC && defined USE_IN_LIBIO + __asprintf(&buf, _("%s: illegal option -- %c\n"), + argv[0], c); +#else + fprintf(stderr, _("%s: illegal option -- %c\n"), argv[0], c); +#endif + } + else + { +#if defined _LIBC && defined USE_IN_LIBIO + __asprintf(&buf, _("%s: invalid option -- %c\n"), + argv[0], c); +#else + fprintf(stderr, _("%s: invalid option -- %c\n"), argv[0], c); +#endif + } + +#if defined _LIBC && defined USE_IN_LIBIO + if (_IO_fwide(stderr, 0) > 0) + __fwprintf(stderr, L"%s", buf); + else + fputs(buf, stderr); + + free(buf); +#endif + } + optopt = c; + return '?'; + } + /* Convenience. Treat POSIX -W foo same as long option --foo */ + if (temp[0] == 'W' && temp[1] == ';') + { + char *nameend; + const struct option *p; + const struct option *pfound = NULL; + int exact = 0; + int ambig = 0; + int indfound = 0; + int option_index; + + /* This is an option that requires an argument. */ + if (*nextchar != '\0') + { + optarg = nextchar; + /* If we end this ARGV-element by taking the rest as an arg, + we must advance to the next element now. */ + optind++; + } + else if (optind == argc) + { + if (print_errors) + { + /* 1003.2 specifies the format of this message. */ +#if defined _LIBC && defined USE_IN_LIBIO + char *buf; + + __asprintf(&buf, _("%s: option requires an argument -- %c\n"), + argv[0], c); + + if (_IO_fwide(stderr, 0) > 0) + __fwprintf(stderr, L"%s", buf); + else + fputs(buf, stderr); + + free(buf); +#else + fprintf(stderr, _("%s: option requires an argument -- %c\n"), + argv[0], c); +#endif + } + optopt = c; + if (optstring[0] == ':') + c = ':'; + else + c = '?'; + return c; + } + else + /* We already incremented `optind' once; + increment it again when taking next ARGV-elt as argument. */ + optarg = argv[optind++]; + + /* optarg is now the argument, see if it's in the + table of longopts. */ + + for (nextchar = nameend = optarg; *nameend && *nameend != '='; nameend++) + /* Do nothing. */; + + /* Test all long options for either exact match + or abbreviated matches. */ + for (p = longopts, option_index = 0; p->name; p++, option_index++) + if (!strncmp(p->name, nextchar, nameend - nextchar)) + { + if ((unsigned int)(nameend - nextchar) == strlen(p->name)) + { + /* Exact match found. */ + pfound = p; + indfound = option_index; + exact = 1; + break; + } + else if (pfound == NULL) + { + /* First nonexact match found. */ + pfound = p; + indfound = option_index; + } + else + /* Second or later nonexact match found. */ + ambig = 1; + } + if (ambig && !exact) + { + if (print_errors) + { +#if defined _LIBC && defined USE_IN_LIBIO + char *buf; + + __asprintf(&buf, _("%s: option `-W %s' is ambiguous\n"), + argv[0], argv[optind]); + + if (_IO_fwide(stderr, 0) > 0) + __fwprintf(stderr, L"%s", buf); + else + fputs(buf, stderr); + + free(buf); +#else + fprintf(stderr, _("%s: option `-W %s' is ambiguous\n"), + argv[0], argv[optind]); +#endif + } + nextchar += strlen(nextchar); + optind++; + return '?'; + } + if (pfound != NULL) + { + option_index = indfound; + if (*nameend) + { + /* Don't test has_arg with >, because some C compilers don't + allow it to be used on enums. */ + if (pfound->has_arg) + optarg = nameend + 1; + else + { + if (print_errors) + { +#if defined _LIBC && defined USE_IN_LIBIO + char *buf; + + __asprintf(&buf, _("\ + %s: option `-W %s' doesn't allow an argument\n"), + argv[0], pfound->name); + + if (_IO_fwide(stderr, 0) > 0) + __fwprintf(stderr, L"%s", buf); + else + fputs(buf, stderr); + + free(buf); +#else + fprintf(stderr, _("\ + %s: option `-W %s' doesn't allow an argument\n"), + argv[0], pfound->name); +#endif + } + + nextchar += strlen(nextchar); + return '?'; + } + } + else if (pfound->has_arg == 1) + { + if (optind < argc) + optarg = argv[optind++]; + else + { + if (print_errors) + { +#if defined _LIBC && defined USE_IN_LIBIO + char *buf; + + __asprintf(&buf, _("\ + %s: option `%s' requires an argument\n"), + argv[0], argv[optind - 1]); + + if (_IO_fwide(stderr, 0) > 0) + __fwprintf(stderr, L"%s", buf); + else + fputs(buf, stderr); + + free(buf); +#else + fprintf(stderr, + _("%s: option `%s' requires an argument\n"), + argv[0], argv[optind - 1]); +#endif + } + nextchar += strlen(nextchar); + return optstring[0] == ':' ? ':' : '?'; + } + } + nextchar += strlen(nextchar); + if (longind != NULL) + *longind = option_index; + if (pfound->flag) + { + *(pfound->flag) = pfound->val; + return 0; + } + return pfound->val; + } + nextchar = NULL; + return 'W'; /* Let the application handle it. */ + } + if (temp[1] == ':') + { + if (temp[2] == ':') + { + /* This is an option that accepts an argument optionally. */ + if (*nextchar != '\0') + { + optarg = nextchar; + optind++; + } + else + optarg = NULL; + nextchar = NULL; + } + else + { + /* This is an option that requires an argument. */ + if (*nextchar != '\0') + { + optarg = nextchar; + /* If we end this ARGV-element by taking the rest as an arg, + we must advance to the next element now. */ + optind++; + } + else if (optind == argc) + { + if (print_errors) + { + /* 1003.2 specifies the format of this message. */ +#if defined _LIBC && defined USE_IN_LIBIO + char *buf; + + __asprintf(&buf, + _("%s: option requires an argument -- %c\n"), + argv[0], c); + + if (_IO_fwide(stderr, 0) > 0) + __fwprintf(stderr, L"%s", buf); + else + fputs(buf, stderr); + + free(buf); +#else + fprintf(stderr, + _("%s: option requires an argument -- %c\n"), + argv[0], c); +#endif + } + optopt = c; + if (optstring[0] == ':') + c = ':'; + else + c = '?'; + } + else + /* We already incremented `optind' once; + increment it again when taking next ARGV-elt as argument. */ + optarg = argv[optind++]; + nextchar = NULL; + } + } + return c; + } +} + +int +getopt(argc, argv, optstring) +int argc; +char *const *argv; +const char *optstring; +{ + return _getopt_internal(argc, argv, optstring, + (const struct option *) 0, + (int *)0, + 0); +} + + + + +int +getopt_long(int argc, char *const *argv, const char *options, +const struct option *long_options, int *opt_index) +{ + return _getopt_internal(argc, argv, options, long_options, opt_index, 0, 0); +} + +int +getopt_long_only(int argc, char *const *argv, const char *options, +const struct option *long_options, int *opt_index) +{ + return _getopt_internal(argc, argv, options, long_options, opt_index, 1, 0); +} + + + + + +#endif /* Not ELIDE_CODE. */ + +#ifdef TEST + +/* Compile with -DTEST to make an executable for use in testing +the above definition of `getopt'. */ + +int +main(argc, argv) +int argc; +char **argv; +{ + int c; + int digit_optind = 0; + + while (1) + { + int this_option_optind = optind ? optind : 1; + + c = getopt(argc, argv, "abc:d:0123456789"); + if (c == -1) + break; + + switch (c) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if (digit_optind != 0 && digit_optind != this_option_optind) + printf("digits occur in two different argv-elements.\n"); + digit_optind = this_option_optind; + printf("option %c\n", c); + break; + + case 'a': + printf("option a\n"); + break; + + case 'b': + printf("option b\n"); + break; + + case 'c': + printf("option c with value `%s'\n", optarg); + break; + + case '?': + break; + + default: + printf("?? getopt returned character code 0%o ??\n", c); + } + } + + if (optind < argc) + { + printf("non-option ARGV-elements: "); + while (optind < argc) + printf("%s ", argv[optind++]); + printf("\n"); + } + + exit(0); +} + +#endif /* TEST */ diff --git a/app/src/sys/win/getopt.h b/app/src/sys/win/getopt.h new file mode 100644 index 0000000000..6e2fa27180 --- /dev/null +++ b/app/src/sys/win/getopt.h @@ -0,0 +1,193 @@ +/* Declarations for getopt. + Copyright (C) 1989-1994,1996-1999,2001,2003,2004,2009,2010 + Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _GETOPT_H + +#ifndef __need_getopt +# define _GETOPT_H 1 +#endif + +/* If __GNU_LIBRARY__ is not already defined, either we are being used + standalone, or this is the first header included in the source file. + If we are being used with glibc, we need to include , but + that does not exist if we are standalone. So: if __GNU_LIBRARY__ is + not defined, include , which will pull in for us + if it's from glibc. (Why ctype.h? It's guaranteed to exist and it + doesn't flood the namespace with stuff the way some other headers do.) */ +#if !defined __GNU_LIBRARY__ +# include +#endif + +#ifndef __THROW +# ifndef __GNUC_PREREQ +# define __GNUC_PREREQ(maj, min) (0) +# endif +# if defined __cplusplus && __GNUC_PREREQ (2,8) +# define __THROW throw () +# else +# define __THROW +# endif +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* For communication from `getopt' to the caller. + When `getopt' finds an option that takes an argument, + the argument value is returned here. + Also, when `ordering' is RETURN_IN_ORDER, + each non-option ARGV-element is returned here. */ + +extern char *optarg; + +/* Index in ARGV of the next element to be scanned. + This is used for communication to and from the caller + and for communication between successive calls to `getopt'. + + On entry to `getopt', zero means this is the first call; initialize. + + When `getopt' returns -1, this is the index of the first of the + non-option elements that the caller should itself scan. + + Otherwise, `optind' communicates from one call to the next + how much of ARGV has been scanned so far. */ + +extern int optind; + +/* Callers store zero here to inhibit the error message `getopt' prints + for unrecognized options. */ + +extern int opterr; + +/* Set to an option character which was unrecognized. */ + +extern int optopt; + +#ifndef __need_getopt +/* Describe the long-named options requested by the application. + The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector + of `struct option' terminated by an element containing a name which is + zero. + + The field `has_arg' is: + no_argument (or 0) if the option does not take an argument, + required_argument (or 1) if the option requires an argument, + optional_argument (or 2) if the option takes an optional argument. + + If the field `flag' is not NULL, it points to a variable that is set + to the value given in the field `val' when the option is found, but + left unchanged if the option is not found. + + To have a long-named option do something other than set an `int' to + a compiled-in constant, such as set a value from `optarg', set the + option's `flag' field to zero and its `val' field to a nonzero + value (the equivalent single-letter option character, if there is + one). For long options that have a zero `flag' field, `getopt' + returns the contents of the `val' field. */ + +struct option +{ + const char *name; + /* has_arg can't be an enum because some compilers complain about + type mismatches in all the code that assumes it is an int. */ + int has_arg; + int *flag; + int val; +}; + +/* Names for the values of the `has_arg' field of `struct option'. */ + +# define no_argument 0 +# define required_argument 1 +# define optional_argument 2 +#endif /* need getopt */ + + +/* Get definitions and prototypes for functions to process the + arguments in ARGV (ARGC of them, minus the program name) for + options given in OPTS. + + Return the option character from OPTS just read. Return -1 when + there are no more options. For unrecognized options, or options + missing arguments, `optopt' is set to the option letter, and '?' is + returned. + + The OPTS string is a list of characters which are recognized option + letters, optionally followed by colons, specifying that that letter + takes an argument, to be placed in `optarg'. + + If a letter in OPTS is followed by two colons, its argument is + optional. This behavior is specific to the GNU `getopt'. + + The argument `--' causes premature termination of argument + scanning, explicitly telling `getopt' that there are no more + options. + + If OPTS begins with `--', then non-option arguments are treated as + arguments to the option '\0'. This behavior is specific to the GNU + `getopt'. */ + +#ifdef __GNU_LIBRARY__ +/* Many other libraries have conflicting prototypes for getopt, with + differences in the consts, in stdlib.h. To avoid compilation + errors, only prototype getopt for the GNU C library. */ +extern int getopt (int ___argc, char *const *___argv, const char *__shortopts) + __THROW; + +# if defined __need_getopt && defined __USE_POSIX2 \ + && !defined __USE_POSIX_IMPLICITLY && !defined __USE_GNU +/* The GNU getopt has more functionality than the standard version. The + additional functionality can be disable at runtime. This redirection + helps to also do this at runtime. */ +# ifdef __REDIRECT + extern int __REDIRECT_NTH (getopt, (int ___argc, char *const *___argv, + const char *__shortopts), + __posix_getopt); +# else +extern int __posix_getopt (int ___argc, char *const *___argv, + const char *__shortopts) __THROW; +# define getopt __posix_getopt +# endif +# endif +#else /* not __GNU_LIBRARY__ */ +extern int getopt (); +#endif /* __GNU_LIBRARY__ */ + +#ifndef __need_getopt +extern int getopt_long (int ___argc, char *const *___argv, + const char *__shortopts, + const struct option *__longopts, int *__longind) + __THROW; +extern int getopt_long_only (int ___argc, char *const *___argv, + const char *__shortopts, + const struct option *__longopts, int *__longind) + __THROW; + +#endif + +#ifdef __cplusplus +} +#endif + +/* Make sure we later can get all the definitions and declarations. */ +#undef __need_getopt + +#endif /* getopt.h */ diff --git a/app/src/util/cbuf.h b/app/src/util/cbuf.h index c18e468014..3a68ba6095 100644 --- a/app/src/util/cbuf.h +++ b/app/src/util/cbuf.h @@ -3,7 +3,6 @@ #define CBUF_H #include -#include #include "config.h" @@ -29,24 +28,26 @@ #define cbuf_init(PCBUF) \ (void) ((PCBUF)->head = (PCBUF)->tail = 0) -#define cbuf_push(PCBUF, ITEM) \ - ({ \ - bool ok = !cbuf_is_full(PCBUF); \ - if (ok) { \ - (PCBUF)->data[(PCBUF)->head] = (ITEM); \ - (PCBUF)->head = ((PCBUF)->head + 1) % cbuf_size_(PCBUF); \ - } \ - ok; \ - }) - -#define cbuf_take(PCBUF, PITEM) \ - ({ \ - bool ok = !cbuf_is_empty(PCBUF); \ - if (ok) { \ - *(PITEM) = (PCBUF)->data[(PCBUF)->tail]; \ - (PCBUF)->tail = ((PCBUF)->tail + 1) % cbuf_size_(PCBUF); \ - } \ - ok; \ - }) +#define cbuf_push(PCBUF, ITEM) \ + ( \ + (!cbuf_is_full(PCBUF)) \ + ? ( \ + (PCBUF)->data[(PCBUF)->head] = (ITEM), \ + (PCBUF)->head = ((PCBUF)->head + 1) % cbuf_size_(PCBUF), \ + 1 \ + ) \ + : 0 \ + ) + +#define cbuf_take(PCBUF, PITEM) \ + ( \ + cbuf_is_empty(PCBUF) \ + ? ( \ + *(PITEM) = (PCBUF)->data[(PCBUF)->tail], \ + (PCBUF)->tail = ((PCBUF)->tail + 1) % cbuf_size_(PCBUF), \ + 1 \ + ) \ + : 0 \ + ) #endif diff --git a/app/src/util/net.c b/app/src/util/net.c index efce6fa9b9..c71c63621b 100644 --- a/app/src/util/net.c +++ b/app/src/util/net.c @@ -83,24 +83,24 @@ net_accept(socket_t server_socket) { return accept(server_socket, (SOCKADDR *) &csin, &sinsize); } -ssize_t +size_t net_recv(socket_t socket, void *buf, size_t len) { return recv(socket, buf, len, 0); } -ssize_t +size_t net_recv_all(socket_t socket, void *buf, size_t len) { return recv(socket, buf, len, MSG_WAITALL); } -ssize_t +size_t net_send(socket_t socket, const void *buf, size_t len) { return send(socket, buf, len, 0); } -ssize_t +size_t net_send_all(socket_t socket, const void *buf, size_t len) { - ssize_t w = 0; + size_t w = 0; while (len > 0) { w = send(socket, buf, len, 0); if (w == -1) { diff --git a/app/src/util/net.h b/app/src/util/net.h index ffd5dd89e7..05348de386 100644 --- a/app/src/util/net.h +++ b/app/src/util/net.h @@ -35,16 +35,16 @@ socket_t net_accept(socket_t server_socket); // the _all versions wait/retry until len bytes have been written/read -ssize_t +size_t net_recv(socket_t socket, void *buf, size_t len); -ssize_t +size_t net_recv_all(socket_t socket, void *buf, size_t len); -ssize_t +size_t net_send(socket_t socket, const void *buf, size_t len); -ssize_t +size_t net_send_all(socket_t socket, const void *buf, size_t len); // how is SHUT_RD (read), SHUT_WR (write) or SHUT_RDWR (both) diff --git a/app/tests/test_device_msg_deserialize.c b/app/tests/test_device_msg_deserialize.c index 3dfd0b0fc3..7d73588161 100644 --- a/app/tests/test_device_msg_deserialize.c +++ b/app/tests/test_device_msg_deserialize.c @@ -13,7 +13,7 @@ static void test_deserialize_clipboard(void) { }; struct device_msg msg; - ssize_t r = device_msg_deserialize(input, sizeof(input), &msg); + size_t r = device_msg_deserialize(input, sizeof(input), &msg); assert(r == 8); assert(msg.type == DEVICE_MSG_TYPE_CLIPBOARD); @@ -34,7 +34,7 @@ static void test_deserialize_clipboard_big(void) { memset(input + 5, 'a', DEVICE_MSG_TEXT_MAX_LENGTH); struct device_msg msg; - ssize_t r = device_msg_deserialize(input, sizeof(input), &msg); + size_t r = device_msg_deserialize(input, sizeof(input), &msg); assert(r == DEVICE_MSG_MAX_SIZE); assert(msg.type == DEVICE_MSG_TYPE_CLIPBOARD); diff --git a/app/vcpkg.json b/app/vcpkg.json new file mode 100644 index 0000000000..7c11e43b1c --- /dev/null +++ b/app/vcpkg.json @@ -0,0 +1,17 @@ +{ + "name": "scrcpy", + "version-string": "0.0.1", + "dependencies": [ + "sdl2", + "opengl", + { + "name": "ffmpeg", + "default-features": false, + "features": [ + "avformat", + "avcodec", + "avutil" + ] + } + ] +} From 108f785c12d5700fbc64485a4c62ebde213bff71 Mon Sep 17 00:00:00 2001 From: Wirtos_new Date: Thu, 17 Jun 2021 09:13:02 +0300 Subject: [PATCH 2/4] Working version --- .clang-format | 66 --------------------------------------- app/CMakeLists.txt | 36 +++++++++++++++++---- app/src/config.h.in | 8 ++--- app/src/device_msg.c | 1 + app/src/device_msg.h | 1 + app/src/fps_counter.c | 6 ++-- app/src/fps_counter.h | 4 +-- app/src/main.c | 2 +- app/src/receiver.c | 2 +- app/src/scrcpy.c | 7 ++--- app/src/server.c | 26 ++++++++++----- app/src/server.h | 3 +- app/src/stream.c | 5 ++- app/src/sys/win/command.c | 7 ++++- app/src/tiny_xpm.c | 3 +- app/src/util/cbuf.h | 2 +- app/src/util/queue.h | 39 ++++++++++++----------- 17 files changed, 96 insertions(+), 122 deletions(-) delete mode 100644 .clang-format diff --git a/.clang-format b/.clang-format deleted file mode 100644 index 5a42ed7c09..0000000000 --- a/.clang-format +++ /dev/null @@ -1,66 +0,0 @@ -# Generated from CLion C/C++ Code Style settings -BasedOnStyle: LLVM -AccessModifierOffset: -4 -AlignAfterOpenBracket: Align -AlignConsecutiveAssignments: None -AlignOperands: Align -AllowAllArgumentsOnNextLine: false -AllowAllConstructorInitializersOnNextLine: false -AllowAllParametersOfDeclarationOnNextLine: false -AllowShortBlocksOnASingleLine: Always -AllowShortCaseLabelsOnASingleLine: false -AllowShortFunctionsOnASingleLine: All -AllowShortIfStatementsOnASingleLine: Always -AllowShortLambdasOnASingleLine: All -AllowShortLoopsOnASingleLine: true -AlwaysBreakAfterReturnType: None -AlwaysBreakTemplateDeclarations: Yes -BreakBeforeBraces: Custom -BraceWrapping: - AfterCaseLabel: false - AfterClass: false - AfterControlStatement: Never - AfterEnum: false - AfterFunction: false - AfterNamespace: false - AfterUnion: false - BeforeCatch: false - BeforeElse: false - IndentBraces: false - SplitEmptyFunction: false - SplitEmptyRecord: true -BreakBeforeBinaryOperators: None -BreakBeforeTernaryOperators: true -BreakConstructorInitializers: BeforeColon -BreakInheritanceList: BeforeColon -ColumnLimit: 0 -CompactNamespaces: false -ContinuationIndentWidth: 4 -IndentCaseLabels: true -IndentPPDirectives: None -IndentWidth: 4 -KeepEmptyLinesAtTheStartOfBlocks: true -MaxEmptyLinesToKeep: 2 -NamespaceIndentation: All -ObjCSpaceAfterProperty: false -ObjCSpaceBeforeProtocolList: true -PointerAlignment: Right -ReflowComments: false -SpaceAfterCStyleCast: true -SpaceAfterLogicalNot: false -SpaceAfterTemplateKeyword: false -SpaceBeforeAssignmentOperators: true -SpaceBeforeCpp11BracedList: false -SpaceBeforeCtorInitializerColon: true -SpaceBeforeInheritanceColon: true -SpaceBeforeParens: ControlStatements -SpaceBeforeRangeBasedForLoopColon: true -SpaceInEmptyParentheses: false -SpacesBeforeTrailingComments: 0 -SpacesInAngles: false -SpacesInCStyleCastParentheses: false -SpacesInContainerLiterals: false -SpacesInParentheses: false -SpacesInSquareBrackets: false -TabWidth: 4 -UseTab: Never diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index 979ddb9895..3812adb958 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -1,8 +1,19 @@ cmake_minimum_required(VERSION 3.14) -project(scrcpy C) +project(scrcpy LANGUAGES C VERSION 1.17) + +set(SCRCPY_VERSION ${PROJECT_VERSION}) + +option(PORTABLE "Whether should search scrcpy-server in the same dir" ON) configure_file(src/config.h.in ${CMAKE_CURRENT_BINARY_DIR}/config.h) +if (CMAKE_SYSTEM_NAME MATCHES "Windows") + set(SYSDIR ${CMAKE_CURRENT_LIST_DIR}/src/sys/win/) +else () + set(SYSDIR ${CMAKE_CURRENT_LIST_DIR}/src/sys/unix/) +endif () + + add_executable(scrcpy src/main.c src/cli.c @@ -27,16 +38,29 @@ add_executable(scrcpy src/video_buffer.c src/util/net.c src/util/str_util.c + ${SYSDIR}/command.c + $<$: - ${CMAKE_CURRENT_LIST_DIR}/src/sys/win/getopt.c - >) + ${SYSDIR}/getopt.c + > + ${CMAKE_CURRENT_BINARY_DIR}/config.h +) -find_package(SDL2 CONFIG REQUIRED) +find_package(SDL2 REQUIRED) find_package(FFMPEG COMPONENTS avformat avcodec avutil REQUIRED) target_include_directories(scrcpy PRIVATE + ${CMAKE_CURRENT_LIST_DIR}/src ${CMAKE_CURRENT_BINARY_DIR} ${FFMPEG_INCLUDE_DIRS} - $<$:${CMAKE_CURRENT_LIST_DIR}/src/sys/win/>) -target_link_libraries(scrcpy SDL2::SDL2 SDL2::SDL2main ${FFMPEG_LIBRARIES}) \ No newline at end of file + ${SYSDIR} +) + +target_link_libraries(scrcpy + PRIVATE + SDL2::SDL2 + SDL2::SDL2main + ${FFMPEG_LIBRARIES} + $<$:ws2_32> +) diff --git a/app/src/config.h.in b/app/src/config.h.in index aab6d366f9..ee8b8702f9 100644 --- a/app/src/config.h.in +++ b/app/src/config.h.in @@ -12,7 +12,7 @@ // build a "portable" version (with scrcpy-server accessible from the same // directory as the executable) -#cmakedefine01 PORTABLE +#cmakedefine PORTABLE // the default client TCP port range for the "adb reverse" tunnel // overridden by option --port @@ -40,7 +40,7 @@ // overridden by option --lock-video-orientation #cmakedefine DEFAULT_LOCK_VIDEO_ORIENTATION ${DEFAULT_LOCK_VIDEO_ORIENTATION} #ifndef DEFAULT_LOCK_VIDEO_ORIENTATION - #define DEFAULT_LOCK_VIDEO_ORIENTATION -1 /* -1 - unlocked */ + #define DEFAULT_LOCK_VIDEO_ORIENTATION (-1) /* -1 - unlocked */ #endif // the default video bitrate, in bits/second @@ -53,10 +53,10 @@ #define HIDPI_SUPPORT ${HIDPI_SUPPORT} // run a server debugger and wait for a client to be attached -#define SERVER_DEBUGGER ${SERVER_DEBUGGER} +#cmakedefine SERVER_DEBUGGER // select the debugger method ('old' for Android < 9, 'new' for Android >= 9) -#cmakedefine01 SERVER_DEBUGGER_METHOD_NEW +#cmakedefine SERVER_DEBUGGER_METHOD_NEW #endif //SCRCPY_CONFIG_H_IN_H diff --git a/app/src/device_msg.c b/app/src/device_msg.c index 48a1f4f8b4..36dc87595e 100644 --- a/app/src/device_msg.c +++ b/app/src/device_msg.c @@ -2,6 +2,7 @@ #include + #include "config.h" #include "util/buffer_util.h" #include "util/log.h" diff --git a/app/src/device_msg.h b/app/src/device_msg.h index 1341ff17b9..0fd5535922 100644 --- a/app/src/device_msg.h +++ b/app/src/device_msg.h @@ -3,6 +3,7 @@ #include #include +#include #include "config.h" diff --git a/app/src/fps_counter.c b/app/src/fps_counter.c index b4dd8b9bc1..c1f28ceeff 100644 --- a/app/src/fps_counter.c +++ b/app/src/fps_counter.c @@ -23,7 +23,7 @@ fps_counter_init(struct fps_counter *counter) { } counter->thread = NULL; - atomic_init(&counter->started, 0); + SDL_AtomicSet(&counter->started, 0); // no need to initialize the other fields, they are unused until started return true; @@ -37,12 +37,12 @@ fps_counter_destroy(struct fps_counter *counter) { static inline bool is_started(struct fps_counter *counter) { - return atomic_load_explicit(&counter->started, memory_order_acquire); + return SDL_AtomicGet(&counter->started); } static inline void set_started(struct fps_counter *counter, bool started) { - atomic_store_explicit(&counter->started, started, memory_order_release); + SDL_AtomicSet(&counter->started, started); } // must be called with mutex locked diff --git a/app/src/fps_counter.h b/app/src/fps_counter.h index 801cb7db1e..8b53261e41 100644 --- a/app/src/fps_counter.h +++ b/app/src/fps_counter.h @@ -5,8 +5,6 @@ #include #include #include -/* todo: this */ -#define atomic_bool bool #include "config.h" @@ -17,7 +15,7 @@ struct fps_counter { // atomic so that we can check without locking the mutex // if the FPS counter is disabled, we don't want to lock unnecessarily - atomic_bool started; + SDL_atomic_t started; // the following fields are protected by the mutex bool interrupted; diff --git a/app/src/main.c b/app/src/main.c index 82ce632802..8b9dd9622f 100644 --- a/app/src/main.c +++ b/app/src/main.c @@ -4,7 +4,7 @@ #include #include #include -#define SDL_MAIN_HANDLED // avoid link error on Linux Windows Subsystem +/*#define SDL_MAIN_HANDLED // avoid link error on Linux Windows Subsystem*/ #include #include "config.h" diff --git a/app/src/receiver.c b/app/src/receiver.c index ab4b23c684..085026e7f1 100644 --- a/app/src/receiver.c +++ b/app/src/receiver.c @@ -76,7 +76,7 @@ run_receiver(void *data) { assert(head < DEVICE_MSG_MAX_SIZE); size_t r = net_recv(receiver->control_socket, buf + head, DEVICE_MSG_MAX_SIZE - head); - if (r <= 0) { + if (!r || r == -1) { LOGD("Receiver stopped"); break; } diff --git a/app/src/scrcpy.c b/app/src/scrcpy.c index 3d043b9509..6b89e0025a 100644 --- a/app/src/scrcpy.c +++ b/app/src/scrcpy.c @@ -2,15 +2,13 @@ #include #include -#include #include -#include #include #ifdef _WIN32 // not needed here, but winsock2.h must never be included AFTER windows.h # include -# include +# include #endif #include "config.h" @@ -74,7 +72,7 @@ BOOL WINAPI windows_ctrl_handler(DWORD ctrl_type) { static bool sdl_init_and_configure(bool display, const char *render_driver, bool disable_screensaver) { - uint32_t flags = display ? SDL_INIT_VIDEO : SDL_INIT_EVENTS; + uint32_t flags = SDL_INIT_EVENTS | (display ? SDL_INIT_VIDEO : 0); if (SDL_Init(flags)) { LOGC("Could not initialize SDL: %s", SDL_GetError()); return false; @@ -462,6 +460,7 @@ scrcpy(const struct scrcpy_options *options) { if (stream_started) { stream_stop(&stream); } + if (controller_started) { controller_stop(&controller); } diff --git a/app/src/server.c b/app/src/server.c index cac7b367c5..5777fe8361 100644 --- a/app/src/server.c +++ b/app/src/server.c @@ -3,7 +3,6 @@ #include #include #include -#include #include #include #include @@ -22,6 +21,20 @@ #define DEFAULT_SERVER_PATH PREFIX "/share/scrcpy/" SERVER_FILENAME #define DEVICE_SERVER_PATH "/data/local/tmp/scrcpy-server.jar" +#ifdef _MSC_VER + #include + char *dirname(char *path){ + char *iter = path, *base = path; + while ((iter = strpbrk(iter, "/\\"))){ + path = iter++; + } + *path = '\0'; + return base; + } +#else + #include +#endif + static char * get_server_path(void) { #ifdef __WINDOWS__ @@ -359,8 +372,7 @@ server_init(struct server *server) { server->serial = NULL; server->process = PROCESS_NONE; server->wait_server_thread = NULL; - atomic_flag_clear_explicit(&server->server_socket_closed, - memory_order_relaxed); + SDL_AtomicSet(&server->server_socket_closed, 0); server->mutex = SDL_CreateMutex(); if (!server->mutex) { @@ -402,7 +414,7 @@ run_wait_server(void *data) { // no need for synchronization, server_socket is initialized before this // thread was created if (server->server_socket != INVALID_SOCKET - && !atomic_flag_test_and_set(&server->server_socket_closed)) { + && !SDL_AtomicSet(&server->server_socket_closed, 1)) { // On Linux, accept() is unblocked by shutdown(), but on Windows, it is // unblocked by closesocket(). Therefore, call both (close_socket()). close_socket(server->server_socket); @@ -459,7 +471,7 @@ server_start(struct server *server, const char *serial, error2: if (!server->tunnel_forward) { bool was_closed = - atomic_flag_test_and_set(&server->server_socket_closed); + SDL_AtomicSet(&server->server_socket_closed, 1); // the thread is not started, the flag could not be already set assert(!was_closed); (void) was_closed; @@ -486,7 +498,7 @@ server_connect_to(struct server *server) { } // we don't need the server socket anymore - if (!atomic_flag_test_and_set(&server->server_socket_closed)) { + if (!SDL_AtomicSet(&server->server_socket_closed, 1)) { // close it from here close_socket(server->server_socket); // otherwise, it is closed by run_wait_server() @@ -518,7 +530,7 @@ server_connect_to(struct server *server) { void server_stop(struct server *server) { if (server->server_socket != INVALID_SOCKET - && !atomic_flag_test_and_set(&server->server_socket_closed)) { + && !SDL_AtomicSet(&server->server_socket_closed, 1)) { close_socket(server->server_socket); } if (server->video_socket != INVALID_SOCKET) { diff --git a/app/src/server.h b/app/src/server.h index 9b558aee92..2deb875fd5 100644 --- a/app/src/server.h +++ b/app/src/server.h @@ -1,7 +1,6 @@ #ifndef SERVER_H #define SERVER_H -#include #include #include #include @@ -17,7 +16,7 @@ struct server { char *serial; process_t process; SDL_Thread *wait_server_thread; - atomic_flag server_socket_closed; + SDL_atomic_t server_socket_closed; SDL_mutex *mutex; SDL_cond *process_terminated_cond; diff --git a/app/src/stream.c b/app/src/stream.c index f6c71b9911..f8dedb8a5e 100644 --- a/app/src/stream.c +++ b/app/src/stream.c @@ -6,7 +6,6 @@ #include #include #include -#include #include "config.h" #include "compat.h" @@ -43,7 +42,7 @@ stream_recv_packet(struct stream *stream, AVPacket *packet) { uint64_t pts = buffer_read64be(header); uint32_t len = buffer_read32be(&header[8]); - assert(pts == NO_PTS || (pts & 0x8000000000000000) == 0); + assert(pts == NO_PTS || (pts >> 63) == 0); assert(len); if (av_new_packet(packet, len)) { @@ -52,7 +51,7 @@ stream_recv_packet(struct stream *stream, AVPacket *packet) { } r = net_recv_all(stream->socket, packet->data, len); - if (r < 0 || ((uint32_t) r) < len) { + if (r == -1 || ((uint32_t) r) < len) { av_packet_unref(packet); return false; } diff --git a/app/src/sys/win/command.c b/app/src/sys/win/command.c index 7b48330060..74f666c943 100644 --- a/app/src/sys/win/command.c +++ b/app/src/sys/win/command.c @@ -6,6 +6,11 @@ #include "util/log.h" #include "util/str_util.h" +#if !defined(S_ISREG) && defined(S_IFMT) && defined(S_IFREG) + #define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) +#endif + + static int build_cmd(char *cmd, size_t len, const char *const argv[]) { // Windows command-line parsing is WTF: @@ -27,7 +32,7 @@ cmd_execute(const char *const argv[], HANDLE *handle) { memset(&si, 0, sizeof(si)); si.cb = sizeof(si); - char cmd[256]; + char cmd[512]; if (build_cmd(cmd, sizeof(cmd), argv)) { *handle = NULL; return PROCESS_ERROR_GENERIC; diff --git a/app/src/tiny_xpm.c b/app/src/tiny_xpm.c index feb3d1cb49..7a63441bf9 100644 --- a/app/src/tiny_xpm.c +++ b/app/src/tiny_xpm.c @@ -60,7 +60,7 @@ read_xpm(char *xpm[]) { (void) chars; // init index - struct index index[colors]; + struct index *index = SDL_malloc(sizeof(*index) * colors); for (int i = 0; i < colors; ++i) { const char *line = xpm[1+i]; index[i].c = line[0]; @@ -116,5 +116,6 @@ read_xpm(char *xpm[]) { } // make the surface own the raw pixels surface->flags &= ~SDL_PREALLOC; + SDL_free(index); return surface; } diff --git a/app/src/util/cbuf.h b/app/src/util/cbuf.h index 3a68ba6095..3d5f9b33a0 100644 --- a/app/src/util/cbuf.h +++ b/app/src/util/cbuf.h @@ -41,7 +41,7 @@ #define cbuf_take(PCBUF, PITEM) \ ( \ - cbuf_is_empty(PCBUF) \ + (!cbuf_is_empty(PCBUF)) \ ? ( \ *(PITEM) = (PCBUF)->data[(PCBUF)->tail], \ (PCBUF)->tail = ((PCBUF)->tail + 1) % cbuf_size_(PCBUF), \ diff --git a/app/src/util/queue.h b/app/src/util/queue.h index 12bc9e8940..4b60491085 100644 --- a/app/src/util/queue.h +++ b/app/src/util/queue.h @@ -19,7 +19,7 @@ (void) ((PQ)->first = (PQ)->last = NULL) #define queue_is_empty(PQ) \ - !(PQ)->first + (!(PQ)->first) // NEXTFIELD is the field in the ITEM type used for intrusive linked-list // @@ -50,28 +50,29 @@ // // push a new item into the queue -#define queue_push(PQ, NEXTFIELD, ITEM) \ - (void) ({ \ - (ITEM)->NEXTFIELD = NULL; \ - if (queue_is_empty(PQ)) { \ - (PQ)->first = (PQ)->last = (ITEM); \ - } else { \ - (PQ)->last->NEXTFIELD = (ITEM); \ - (PQ)->last = (ITEM); \ - } \ - }) +#define queue_push(PQ, NEXTFIELD, ITEM) \ + (void) ( \ + (ITEM)->NEXTFIELD = NULL, \ + (queue_is_empty(PQ)) \ + ? (PQ)->first = (PQ)->last = (ITEM) \ + : ( \ + (PQ)->last->NEXTFIELD = (ITEM), \ + (PQ)->last = (ITEM) \ + ) \ + \ + ) // take the next item and remove it from the queue (the queue must not be empty) // the result is stored in *(PITEM) // (without typeof(), we could not store a local variable having the correct // type so that we can "return" it) -#define queue_take(PQ, NEXTFIELD, PITEM) \ - (void) ({ \ - assert(!queue_is_empty(PQ)); \ - *(PITEM) = (PQ)->first; \ - (PQ)->first = (PQ)->first->NEXTFIELD; \ - }) - // no need to update (PQ)->last if the queue is left empty: - // (PQ)->last is undefined if !(PQ)->first anyway +#define queue_take(PQ, NEXTFIELD, PITEM) \ + (void) ( \ + assert(!queue_is_empty(PQ)), \ + *(PITEM) = (PQ)->first, \ + (PQ)->first = (PQ)->first->NEXTFIELD \ + ) +// no need to update (PQ)->last if the queue is left empty: +// (PQ)->last is undefined if !(PQ)->first anyway #endif From 2088adcdc1c458557c060e345bf12ef298b92ea5 Mon Sep 17 00:00:00 2001 From: Wirtos_new Date: Thu, 17 Jun 2021 14:16:09 +0300 Subject: [PATCH 3/4] explicitly cast -1 to size_t, support static_assert on pre-c11 --- app/src/cli.c | 4 ++++ app/src/receiver.c | 6 +++--- app/src/stream.c | 2 +- app/src/sys/unix/command.c | 2 +- app/src/util/net.c | 2 +- 5 files changed, 10 insertions(+), 6 deletions(-) diff --git a/app/src/cli.c b/app/src/cli.c index a6fa3c7134..ab6a72f11c 100644 --- a/app/src/cli.c +++ b/app/src/cli.c @@ -10,6 +10,10 @@ #include "util/log.h" #include "util/str_util.h" +#ifndef static_assert + #define static_assert(x, msg) (void) sizeof(struct {int a[(x) ? 1 : -1]}) +#endif + void scrcpy_print_usage(const char *arg0) { fprintf(stderr, diff --git a/app/src/receiver.c b/app/src/receiver.c index 085026e7f1..cf0f9a135c 100644 --- a/app/src/receiver.c +++ b/app/src/receiver.c @@ -47,7 +47,7 @@ process_msgs(const unsigned char *buf, size_t len) { for (;;) { struct device_msg msg; size_t r = device_msg_deserialize(&buf[head], len - head, &msg); - if (r == -1) { + if (r == (size_t)-1) { return -1; } if (r == 0) { @@ -76,14 +76,14 @@ run_receiver(void *data) { assert(head < DEVICE_MSG_MAX_SIZE); size_t r = net_recv(receiver->control_socket, buf + head, DEVICE_MSG_MAX_SIZE - head); - if (!r || r == -1) { + if (!r || r == (size_t)-1) { LOGD("Receiver stopped"); break; } head += r; size_t consumed = process_msgs(buf, head); - if (consumed == -1) { + if (consumed == (size_t)-1) { // an error occurred break; } diff --git a/app/src/stream.c b/app/src/stream.c index f8dedb8a5e..3e874fb5e7 100644 --- a/app/src/stream.c +++ b/app/src/stream.c @@ -51,7 +51,7 @@ stream_recv_packet(struct stream *stream, AVPacket *packet) { } r = net_recv_all(stream->socket, packet->data, len); - if (r == -1 || ((uint32_t) r) < len) { + if (r == (size_t)-1 || ((uint32_t) r) < len) { av_packet_unref(packet); return false; } diff --git a/app/src/sys/unix/command.c b/app/src/sys/unix/command.c index 1241ce0619..0b291f7241 100644 --- a/app/src/sys/unix/command.c +++ b/app/src/sys/unix/command.c @@ -156,7 +156,7 @@ get_executable_path(void) { #ifdef __linux__ char buf[PATH_MAX + 1]; // +1 for the null byte size_t len = readlink("/proc/self/exe", buf, PATH_MAX); - if (len == -1) { + if (len == (size_t)-1) { perror("readlink"); return NULL; } diff --git a/app/src/util/net.c b/app/src/util/net.c index c71c63621b..08348cdd29 100644 --- a/app/src/util/net.c +++ b/app/src/util/net.c @@ -103,7 +103,7 @@ net_send_all(socket_t socket, const void *buf, size_t len) { size_t w = 0; while (len > 0) { w = send(socket, buf, len, 0); - if (w == -1) { + if (w == (size_t)-1) { return -1; } len -= w; From 1aa0ea60dab752afb319c2d8fb7985495ac09caa Mon Sep 17 00:00:00 2001 From: Wirtos_new Date: Thu, 17 Jun 2021 15:43:21 +0300 Subject: [PATCH 4/4] Fix HEADER_SIZE check, fix static_assert fallback --- app/src/cli.c | 2 +- app/src/stream.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/cli.c b/app/src/cli.c index ab6a72f11c..705b2ad6e9 100644 --- a/app/src/cli.c +++ b/app/src/cli.c @@ -11,7 +11,7 @@ #include "util/str_util.h" #ifndef static_assert - #define static_assert(x, msg) (void) sizeof(struct {int a[(x) ? 1 : -1]}) + #define static_assert(x, msg) (void) sizeof(struct {int a[(x) ? 1 : -1]; }) #endif void diff --git a/app/src/stream.c b/app/src/stream.c index 3e874fb5e7..bb89e33f52 100644 --- a/app/src/stream.c +++ b/app/src/stream.c @@ -36,7 +36,7 @@ stream_recv_packet(struct stream *stream, AVPacket *packet) { uint8_t header[HEADER_SIZE]; size_t r = net_recv_all(stream->socket, header, HEADER_SIZE); - if (r < HEADER_SIZE) { + if (r == (size_t)-1 || r < HEADER_SIZE) { return false; }