From c029d90d1975e124d237605f1edb2be16bd05b5d Mon Sep 17 00:00:00 2001 From: Joel Klinghed Date: Tue, 28 Feb 2017 21:50:44 +0100 Subject: Initial commit --- .gitignore | 16 + Makefile.am | 7 + configure.ac | 74 +++ m4/ax_append_compile_flags.m4 | 65 ++ m4/ax_append_flag.m4 | 69 +++ m4/ax_cflags_warn_all.m4 | 122 ++++ m4/ax_check_compile_flag.m4 | 74 +++ m4/ax_gcc_func_attribute.m4 | 226 +++++++ m4/ax_gcc_var_attribute.m4 | 141 +++++ src/.gitignore | 4 + src/Makefile.am | 18 + src/args.cc | 281 +++++++++ src/args.hh | 60 ++ src/buffer.cc | 119 ++++ src/buffer.hh | 30 + src/character.cc | 31 + src/character.hh | 18 + src/chunked.cc | 106 ++++ src/chunked.hh | 23 + src/common.hh | 18 + src/config.cc | 176 ++++++ src/config.hh | 33 + src/http.cc | 657 ++++++++++++++++++++ src/http.hh | 141 +++++ src/io.cc | 90 +++ src/io.hh | 124 ++++ src/logger.cc | 130 ++++ src/logger.hh | 33 + src/looper.cc | 287 +++++++++ src/looper.hh | 41 ++ src/main.cc | 187 ++++++ src/paths.cc | 98 +++ src/paths.hh | 18 + src/proxy.cc | 1373 +++++++++++++++++++++++++++++++++++++++++ src/proxy.hh | 37 ++ src/resolver.cc | 207 +++++++ src/resolver.hh | 28 + src/strings.cc | 94 +++ src/strings.hh | 24 + src/terminal.cc | 20 + src/terminal.hh | 22 + src/url.cc | 901 +++++++++++++++++++++++++++ src/url.hh | 62 ++ src/xdg.cc | 135 ++++ src/xdg.hh | 25 + test/.gitignore | 8 + test/Makefile.am | 25 + test/test-args.cc | 213 +++++++ test/test-http.cc | 477 ++++++++++++++ test/test-paths.cc | 55 ++ test/test-strings.cc | 55 ++ test/test-url.cc | 212 +++++++ test/test-xdg.cc | 60 ++ test/test.hh | 49 ++ 54 files changed, 7599 insertions(+) create mode 100644 .gitignore create mode 100644 Makefile.am create mode 100644 configure.ac create mode 100644 m4/ax_append_compile_flags.m4 create mode 100644 m4/ax_append_flag.m4 create mode 100644 m4/ax_cflags_warn_all.m4 create mode 100644 m4/ax_check_compile_flag.m4 create mode 100644 m4/ax_gcc_func_attribute.m4 create mode 100644 m4/ax_gcc_var_attribute.m4 create mode 100644 src/.gitignore create mode 100644 src/Makefile.am create mode 100644 src/args.cc create mode 100644 src/args.hh create mode 100644 src/buffer.cc create mode 100644 src/buffer.hh create mode 100644 src/character.cc create mode 100644 src/character.hh create mode 100644 src/chunked.cc create mode 100644 src/chunked.hh create mode 100644 src/common.hh create mode 100644 src/config.cc create mode 100644 src/config.hh create mode 100644 src/http.cc create mode 100644 src/http.hh create mode 100644 src/io.cc create mode 100644 src/io.hh create mode 100644 src/logger.cc create mode 100644 src/logger.hh create mode 100644 src/looper.cc create mode 100644 src/looper.hh create mode 100644 src/main.cc create mode 100644 src/paths.cc create mode 100644 src/paths.hh create mode 100644 src/proxy.cc create mode 100644 src/proxy.hh create mode 100644 src/resolver.cc create mode 100644 src/resolver.hh create mode 100644 src/strings.cc create mode 100644 src/strings.hh create mode 100644 src/terminal.cc create mode 100644 src/terminal.hh create mode 100644 src/url.cc create mode 100644 src/url.hh create mode 100644 src/xdg.cc create mode 100644 src/xdg.hh create mode 100644 test/.gitignore create mode 100644 test/Makefile.am create mode 100644 test/test-args.cc create mode 100644 test/test-http.cc create mode 100644 test/test-paths.cc create mode 100644 test/test-strings.cc create mode 100644 test/test-url.cc create mode 100644 test/test-xdg.cc create mode 100644 test/test.hh diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..36d5c19 --- /dev/null +++ b/.gitignore @@ -0,0 +1,16 @@ +.deps +*.o +*.in +*.gcda +*.gcno +Makefile +stamp-h1 +/aclocal.m4 +/autom4te.cache +/compile +/config.* +/configure +/depcomp +/install-sh +/missing +/test-driver \ No newline at end of file diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..770835c --- /dev/null +++ b/Makefile.am @@ -0,0 +1,7 @@ +ACLOCAL_AMFLAGS = -I m4 + +MAINTAINERCLEANFILES = Makefile.in aclocal.m4 config.guess \ + config.sub configure depcomp install-sh ltmain.sh \ + missing config.rpath mkinstalldirs compile + +SUBDIRS = src test diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000..71452a9 --- /dev/null +++ b/configure.ac @@ -0,0 +1,74 @@ +AC_INIT([tp], [0.1], [the_jk@yahoo.com]) +AC_CONFIG_MACRO_DIR([m4]) + +AM_INIT_AUTOMAKE([dist-bzip2 foreign]) +AM_SILENT_RULES([yes]) + +AC_PROG_CXX +AC_PROG_RANLIB +AM_PROG_CC_C_O + +AC_LANG([C++]) + +DEFINES= + +# Test c++11 +OLDCXXFLAGS="$CXXFLAGS" +# Check if it just works with -std=c++11 +# The code below was choosen because if you mix a compiler that is C++11 +# compatible with a libc++ that isn't fully (like clang 3.3 with gcc 4.6 +# libstdcxx) you get errors because of a missing copy constructor for +# std::shared_ptr. Add more tests as we find them. +CXXFLAGS="-std=c++11 $CXXFLAGS" +AC_MSG_CHECKING([for C++11 using (-std=c++11)]) +AC_LINK_IFELSE([AC_LANG_PROGRAM([[ +#include +]],[[ +std::shared_ptr i(new int(5)); +std::shared_ptr j(i); +]])], + [AC_MSG_RESULT([yes]) + DEFINES="$DEFINES -std=c++11"], + [AC_MSG_RESULT([no]) + CXXFLAGS="-std=c++11 -stdlib=libc++ $CXXFLAGS" + AC_MSG_CHECKING([for C++11 using (-std=c++11 -stdlib=libc++)]) + AC_LINK_IFELSE([AC_LANG_PROGRAM([[ +#include +]],[[ +std::shared_ptr i(new int(5)); +std::shared_ptr j(i); +]])], + [AC_MSG_RESULT([yes]) + DEFINES="$DEFINES -std=c++11 -stdlib=libc++"], + [AC_MSG_RESULT([no]) + AC_MSG_ERROR([No working C++11 support])])]) +CXXFLAGS="$OLDCXXFLAGS" + +AX_CXXFLAGS_WARN_ALL([DEFINES]) +AX_APPEND_COMPILE_FLAGS([-fno-rtti -fno-exceptions],DEFINES) +AX_APPEND_COMPILE_FLAGS([-Wextra -Wno-unused-parameter -Wno-missing-field-initializers],DEFINES) +AC_ARG_ENABLE([debug], AC_HELP_STRING([compile with debug options]), + if test "x$enableval" = "xyes"; then + DEFINES="$DEFINES -g -O0 -DDEBUG" + else + DEFINES="$DEFINES -DNDEBUG" + fi) +AC_SUBST([DEFINES]) + +AX_GCC_VAR_ATTRIBUTE([unused]) +AX_GCC_FUNC_ATTRIBUTE([format]) + +AC_CHECK_HEADERS([sys/ioctl.h]) + +# Thread + +THREAD_CFLAGS=-pthread +THREAD_LIBS= + +AC_SUBST([THREAD_CFLAGS]) +AC_SUBST([THREAD_LIBS]) + +# Finish up + +AC_CONFIG_HEADERS([src/config.h]) +AC_OUTPUT([Makefile src/Makefile test/Makefile]) diff --git a/m4/ax_append_compile_flags.m4 b/m4/ax_append_compile_flags.m4 new file mode 100644 index 0000000..1f8e708 --- /dev/null +++ b/m4/ax_append_compile_flags.m4 @@ -0,0 +1,65 @@ +# =========================================================================== +# http://www.gnu.org/software/autoconf-archive/ax_append_compile_flags.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_APPEND_COMPILE_FLAGS([FLAG1 FLAG2 ...], [FLAGS-VARIABLE], [EXTRA-FLAGS]) +# +# DESCRIPTION +# +# For every FLAG1, FLAG2 it is checked whether the compiler works with the +# flag. If it does, the flag is added FLAGS-VARIABLE +# +# If FLAGS-VARIABLE is not specified, the current language's flags (e.g. +# CFLAGS) is used. During the check the flag is always added to the +# current language's flags. +# +# If EXTRA-FLAGS is defined, it is added to the current language's default +# flags (e.g. CFLAGS) when the check is done. The check is thus made with +# the flags: "CFLAGS EXTRA-FLAGS FLAG". This can for example be used to +# force the compiler to issue an error when a bad flag is given. +# +# NOTE: This macro depends on the AX_APPEND_FLAG and +# AX_CHECK_COMPILE_FLAG. Please keep this macro in sync with +# AX_APPEND_LINK_FLAGS. +# +# LICENSE +# +# Copyright (c) 2011 Maarten Bosmans +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation, either version 3 of the License, or (at your +# option) any later version. +# +# This program 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 General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program. If not, see . +# +# As a special exception, the respective Autoconf Macro's copyright owner +# gives unlimited permission to copy, distribute and modify the configure +# scripts that are the output of Autoconf when processing the Macro. You +# need not follow the terms of the GNU General Public License when using +# or distributing such scripts, even though portions of the text of the +# Macro appear in them. The GNU General Public License (GPL) does govern +# all other use of the material that constitutes the Autoconf Macro. +# +# This special exception to the GPL applies to versions of the Autoconf +# Macro released by the Autoconf Archive. When you make and distribute a +# modified version of the Autoconf Macro, you may extend this special +# exception to the GPL to apply to your modified version as well. + +#serial 3 + +AC_DEFUN([AX_APPEND_COMPILE_FLAGS], +[AC_REQUIRE([AX_CHECK_COMPILE_FLAG]) +AC_REQUIRE([AX_APPEND_FLAG]) +for flag in $1; do + AX_CHECK_COMPILE_FLAG([$flag], [AX_APPEND_FLAG([$flag], [$2])], [], [$3]) +done +])dnl AX_APPEND_COMPILE_FLAGS diff --git a/m4/ax_append_flag.m4 b/m4/ax_append_flag.m4 new file mode 100644 index 0000000..1d38b76 --- /dev/null +++ b/m4/ax_append_flag.m4 @@ -0,0 +1,69 @@ +# =========================================================================== +# http://www.gnu.org/software/autoconf-archive/ax_append_flag.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_APPEND_FLAG(FLAG, [FLAGS-VARIABLE]) +# +# DESCRIPTION +# +# FLAG is appended to the FLAGS-VARIABLE shell variable, with a space +# added in between. +# +# If FLAGS-VARIABLE is not specified, the current language's flags (e.g. +# CFLAGS) is used. FLAGS-VARIABLE is not changed if it already contains +# FLAG. If FLAGS-VARIABLE is unset in the shell, it is set to exactly +# FLAG. +# +# NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. +# +# LICENSE +# +# Copyright (c) 2008 Guido U. Draheim +# Copyright (c) 2011 Maarten Bosmans +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation, either version 3 of the License, or (at your +# option) any later version. +# +# This program 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 General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program. If not, see . +# +# As a special exception, the respective Autoconf Macro's copyright owner +# gives unlimited permission to copy, distribute and modify the configure +# scripts that are the output of Autoconf when processing the Macro. You +# need not follow the terms of the GNU General Public License when using +# or distributing such scripts, even though portions of the text of the +# Macro appear in them. The GNU General Public License (GPL) does govern +# all other use of the material that constitutes the Autoconf Macro. +# +# This special exception to the GPL applies to versions of the Autoconf +# Macro released by the Autoconf Archive. When you make and distribute a +# modified version of the Autoconf Macro, you may extend this special +# exception to the GPL to apply to your modified version as well. + +#serial 2 + +AC_DEFUN([AX_APPEND_FLAG], +[AC_PREREQ(2.59)dnl for _AC_LANG_PREFIX +AS_VAR_PUSHDEF([FLAGS], [m4_default($2,_AC_LANG_PREFIX[FLAGS])])dnl +AS_VAR_SET_IF(FLAGS, + [case " AS_VAR_GET(FLAGS) " in + *" $1 "*) + AC_RUN_LOG([: FLAGS already contains $1]) + ;; + *) + AC_RUN_LOG([: FLAGS="$FLAGS $1"]) + AS_VAR_SET(FLAGS, ["AS_VAR_GET(FLAGS) $1"]) + ;; + esac], + [AS_VAR_SET(FLAGS,["$1"])]) +AS_VAR_POPDEF([FLAGS])dnl +])dnl AX_APPEND_FLAG diff --git a/m4/ax_cflags_warn_all.m4 b/m4/ax_cflags_warn_all.m4 new file mode 100644 index 0000000..0fa3e18 --- /dev/null +++ b/m4/ax_cflags_warn_all.m4 @@ -0,0 +1,122 @@ +# =========================================================================== +# http://www.gnu.org/software/autoconf-archive/ax_cflags_warn_all.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_CFLAGS_WARN_ALL [(shellvar [,default, [A/NA]])] +# AX_CXXFLAGS_WARN_ALL [(shellvar [,default, [A/NA]])] +# AX_FCFLAGS_WARN_ALL [(shellvar [,default, [A/NA]])] +# +# DESCRIPTION +# +# Try to find a compiler option that enables most reasonable warnings. +# +# For the GNU compiler it will be -Wall (and -ansi -pedantic) The result +# is added to the shellvar being CFLAGS, CXXFLAGS, or FCFLAGS by default. +# +# Currently this macro knows about the GCC, Solaris, Digital Unix, AIX, +# HP-UX, IRIX, NEC SX-5 (Super-UX 10), Cray J90 (Unicos 10.0.0.8), and +# Intel compilers. For a given compiler, the Fortran flags are much more +# experimental than their C equivalents. +# +# - $1 shell-variable-to-add-to : CFLAGS, CXXFLAGS, or FCFLAGS +# - $2 add-value-if-not-found : nothing +# - $3 action-if-found : add value to shellvariable +# - $4 action-if-not-found : nothing +# +# NOTE: These macros depend on AX_APPEND_FLAG. +# +# LICENSE +# +# Copyright (c) 2008 Guido U. Draheim +# Copyright (c) 2010 Rhys Ulerich +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 3 of the License, or (at your +# option) any later version. +# +# This program 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 General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program. If not, see . +# +# As a special exception, the respective Autoconf Macro's copyright owner +# gives unlimited permission to copy, distribute and modify the configure +# scripts that are the output of Autoconf when processing the Macro. You +# need not follow the terms of the GNU General Public License when using +# or distributing such scripts, even though portions of the text of the +# Macro appear in them. The GNU General Public License (GPL) does govern +# all other use of the material that constitutes the Autoconf Macro. +# +# This special exception to the GPL applies to versions of the Autoconf +# Macro released by the Autoconf Archive. When you make and distribute a +# modified version of the Autoconf Macro, you may extend this special +# exception to the GPL to apply to your modified version as well. + +#serial 14 + +AC_DEFUN([AX_FLAGS_WARN_ALL],[dnl +AS_VAR_PUSHDEF([FLAGS],[_AC_LANG_PREFIX[]FLAGS])dnl +AS_VAR_PUSHDEF([VAR],[ac_cv_[]_AC_LANG_ABBREV[]flags_warn_all])dnl +AC_CACHE_CHECK([m4_ifval($1,$1,FLAGS) for maximum warnings], +VAR,[VAR="no, unknown" +ac_save_[]FLAGS="$[]FLAGS" +for ac_arg dnl +in "-warn all % -warn all" dnl Intel + "-pedantic % -Wall" dnl GCC + "-xstrconst % -v" dnl Solaris C + "-std1 % -verbose -w0 -warnprotos" dnl Digital Unix + "-qlanglvl=ansi % -qsrcmsg -qinfo=all:noppt:noppc:noobs:nocnd" dnl AIX + "-ansi -ansiE % -fullwarn" dnl IRIX + "+ESlit % +w1" dnl HP-UX C + "-Xc % -pvctl[,]fullmsg" dnl NEC SX-5 (Super-UX 10) + "-h conform % -h msglevel 2" dnl Cray C (Unicos) + # +do FLAGS="$ac_save_[]FLAGS "`echo $ac_arg | sed -e 's,%%.*,,' -e 's,%,,'` + AC_COMPILE_IFELSE([AC_LANG_PROGRAM], + [VAR=`echo $ac_arg | sed -e 's,.*% *,,'` ; break]) +done +FLAGS="$ac_save_[]FLAGS" +]) +AS_VAR_POPDEF([FLAGS])dnl +AC_REQUIRE([AX_APPEND_FLAG]) +case ".$VAR" in + .ok|.ok,*) m4_ifvaln($3,$3) ;; + .|.no|.no,*) m4_default($4,[m4_ifval($2,[AX_APPEND_FLAG([$2], [$1])])]) ;; + *) m4_default($3,[AX_APPEND_FLAG([$VAR], [$1])]) ;; +esac +AS_VAR_POPDEF([VAR])dnl +])dnl AX_FLAGS_WARN_ALL +dnl implementation tactics: +dnl the for-argument contains a list of options. The first part of +dnl these does only exist to detect the compiler - usually it is +dnl a global option to enable -ansi or -extrawarnings. All other +dnl compilers will fail about it. That was needed since a lot of +dnl compilers will give false positives for some option-syntax +dnl like -Woption or -Xoption as they think of it is a pass-through +dnl to later compile stages or something. The "%" is used as a +dnl delimiter. A non-option comment can be given after "%%" marks +dnl which will be shown but not added to the respective C/CXXFLAGS. + +AC_DEFUN([AX_CFLAGS_WARN_ALL],[dnl +AC_LANG_PUSH([C]) +AX_FLAGS_WARN_ALL([$1], [$2], [$3], [$4]) +AC_LANG_POP([C]) +]) + +AC_DEFUN([AX_CXXFLAGS_WARN_ALL],[dnl +AC_LANG_PUSH([C++]) +AX_FLAGS_WARN_ALL([$1], [$2], [$3], [$4]) +AC_LANG_POP([C++]) +]) + +AC_DEFUN([AX_FCFLAGS_WARN_ALL],[dnl +AC_LANG_PUSH([Fortran]) +AX_FLAGS_WARN_ALL([$1], [$2], [$3], [$4]) +AC_LANG_POP([Fortran]) +]) diff --git a/m4/ax_check_compile_flag.m4 b/m4/ax_check_compile_flag.m4 new file mode 100644 index 0000000..51df0c0 --- /dev/null +++ b/m4/ax_check_compile_flag.m4 @@ -0,0 +1,74 @@ +# =========================================================================== +# http://www.gnu.org/software/autoconf-archive/ax_check_compile_flag.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_CHECK_COMPILE_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS], [INPUT]) +# +# DESCRIPTION +# +# Check whether the given FLAG works with the current language's compiler +# or gives an error. (Warnings, however, are ignored) +# +# ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on +# success/failure. +# +# If EXTRA-FLAGS is defined, it is added to the current language's default +# flags (e.g. CFLAGS) when the check is done. The check is thus made with +# the flags: "CFLAGS EXTRA-FLAGS FLAG". This can for example be used to +# force the compiler to issue an error when a bad flag is given. +# +# INPUT gives an alternative input source to AC_COMPILE_IFELSE. +# +# NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this +# macro in sync with AX_CHECK_{PREPROC,LINK}_FLAG. +# +# LICENSE +# +# Copyright (c) 2008 Guido U. Draheim +# Copyright (c) 2011 Maarten Bosmans +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation, either version 3 of the License, or (at your +# option) any later version. +# +# This program 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 General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program. If not, see . +# +# As a special exception, the respective Autoconf Macro's copyright owner +# gives unlimited permission to copy, distribute and modify the configure +# scripts that are the output of Autoconf when processing the Macro. You +# need not follow the terms of the GNU General Public License when using +# or distributing such scripts, even though portions of the text of the +# Macro appear in them. The GNU General Public License (GPL) does govern +# all other use of the material that constitutes the Autoconf Macro. +# +# This special exception to the GPL applies to versions of the Autoconf +# Macro released by the Autoconf Archive. When you make and distribute a +# modified version of the Autoconf Macro, you may extend this special +# exception to the GPL to apply to your modified version as well. + +#serial 3 + +AC_DEFUN([AX_CHECK_COMPILE_FLAG], +[AC_PREREQ(2.59)dnl for _AC_LANG_PREFIX +AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_[]_AC_LANG_ABBREV[]flags_$4_$1])dnl +AC_CACHE_CHECK([whether _AC_LANG compiler accepts $1], CACHEVAR, [ + ax_check_save_flags=$[]_AC_LANG_PREFIX[]FLAGS + _AC_LANG_PREFIX[]FLAGS="$[]_AC_LANG_PREFIX[]FLAGS $4 $1" + AC_COMPILE_IFELSE([m4_default([$5],[AC_LANG_PROGRAM()])], + [AS_VAR_SET(CACHEVAR,[yes])], + [AS_VAR_SET(CACHEVAR,[no])]) + _AC_LANG_PREFIX[]FLAGS=$ax_check_save_flags]) +AS_IF([test x"AS_VAR_GET(CACHEVAR)" = xyes], + [m4_default([$2], :)], + [m4_default([$3], :)]) +AS_VAR_POPDEF([CACHEVAR])dnl +])dnl AX_CHECK_COMPILE_FLAGS diff --git a/m4/ax_gcc_func_attribute.m4 b/m4/ax_gcc_func_attribute.m4 new file mode 100644 index 0000000..008bee9 --- /dev/null +++ b/m4/ax_gcc_func_attribute.m4 @@ -0,0 +1,226 @@ +# =========================================================================== +# https://www.gnu.org/software/autoconf-archive/ax_gcc_func_attribute.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_GCC_FUNC_ATTRIBUTE(ATTRIBUTE) +# +# DESCRIPTION +# +# This macro checks if the compiler supports one of GCC's function +# attributes; many other compilers also provide function attributes with +# the same syntax. Compiler warnings are used to detect supported +# attributes as unsupported ones are ignored by default so quieting +# warnings when using this macro will yield false positives. +# +# The ATTRIBUTE parameter holds the name of the attribute to be checked. +# +# If ATTRIBUTE is supported define HAVE_FUNC_ATTRIBUTE_. +# +# The macro caches its result in the ax_cv_have_func_attribute_ +# variable. +# +# The macro currently supports the following function attributes: +# +# alias +# aligned +# alloc_size +# always_inline +# artificial +# cold +# const +# constructor +# constructor_priority for constructor attribute with priority +# deprecated +# destructor +# dllexport +# dllimport +# error +# externally_visible +# flatten +# format +# format_arg +# gnu_inline +# hot +# ifunc +# leaf +# malloc +# noclone +# noinline +# nonnull +# noreturn +# nothrow +# optimize +# pure +# unused +# used +# visibility +# warning +# warn_unused_result +# weak +# weakref +# +# Unsuppored function attributes will be tested with a prototype returning +# an int and not accepting any arguments and the result of the check might +# be wrong or meaningless so use with care. +# +# LICENSE +# +# Copyright (c) 2013 Gabriele Svelto +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 5 + +AC_DEFUN([AX_GCC_FUNC_ATTRIBUTE], [ + AS_VAR_PUSHDEF([ac_var], [ax_cv_have_func_attribute_$1]) + + AC_CACHE_CHECK([for __attribute__(($1))], [ac_var], [ + AC_LINK_IFELSE([AC_LANG_PROGRAM([ + m4_case([$1], + [alias], [ + int foo( void ) { return 0; } + int bar( void ) __attribute__(($1("foo"))); + ], + [aligned], [ + int foo( void ) __attribute__(($1(32))); + ], + [alloc_size], [ + void *foo(int a) __attribute__(($1(1))); + ], + [always_inline], [ + inline __attribute__(($1)) int foo( void ) { return 0; } + ], + [artificial], [ + inline __attribute__(($1)) int foo( void ) { return 0; } + ], + [cold], [ + int foo( void ) __attribute__(($1)); + ], + [const], [ + int foo( void ) __attribute__(($1)); + ], + [constructor_priority], [ + int foo( void ) __attribute__((__constructor__(65535/2))); + ], + [constructor], [ + int foo( void ) __attribute__(($1)); + ], + [deprecated], [ + int foo( void ) __attribute__(($1(""))); + ], + [destructor], [ + int foo( void ) __attribute__(($1)); + ], + [dllexport], [ + __attribute__(($1)) int foo( void ) { return 0; } + ], + [dllimport], [ + int foo( void ) __attribute__(($1)); + ], + [error], [ + int foo( void ) __attribute__(($1(""))); + ], + [externally_visible], [ + int foo( void ) __attribute__(($1)); + ], + [flatten], [ + int foo( void ) __attribute__(($1)); + ], + [format], [ + int foo(const char *p, ...) __attribute__(($1(printf, 1, 2))); + ], + [format_arg], [ + char *foo(const char *p) __attribute__(($1(1))); + ], + [gnu_inline], [ + inline __attribute__(($1)) int foo( void ) { return 0; } + ], + [hot], [ + int foo( void ) __attribute__(($1)); + ], + [ifunc], [ + int my_foo( void ) { return 0; } + static int (*resolve_foo(void))(void) { return my_foo; } + int foo( void ) __attribute__(($1("resolve_foo"))); + ], + [leaf], [ + __attribute__(($1)) int foo( void ) { return 0; } + ], + [malloc], [ + void *foo( void ) __attribute__(($1)); + ], + [noclone], [ + int foo( void ) __attribute__(($1)); + ], + [noinline], [ + __attribute__(($1)) int foo( void ) { return 0; } + ], + [nonnull], [ + int foo(char *p) __attribute__(($1(1))); + ], + [noreturn], [ + void foo( void ) __attribute__(($1)); + ], + [nothrow], [ + int foo( void ) __attribute__(($1)); + ], + [optimize], [ + __attribute__(($1(3))) int foo( void ) { return 0; } + ], + [pure], [ + int foo( void ) __attribute__(($1)); + ], + [returns_nonnull], [ + void *foo( void ) __attribute__(($1)); + ], + [unused], [ + int foo( void ) __attribute__(($1)); + ], + [used], [ + int foo( void ) __attribute__(($1)); + ], + [visibility], [ + int foo_def( void ) __attribute__(($1("default"))); + int foo_hid( void ) __attribute__(($1("hidden"))); + int foo_int( void ) __attribute__(($1("internal"))); + int foo_pro( void ) __attribute__(($1("protected"))); + ], + [warning], [ + int foo( void ) __attribute__(($1(""))); + ], + [warn_unused_result], [ + int foo( void ) __attribute__(($1)); + ], + [weak], [ + int foo( void ) __attribute__(($1)); + ], + [weakref], [ + static int foo( void ) { return 0; } + static int bar( void ) __attribute__(($1("foo"))); + ], + [ + m4_warn([syntax], [Unsupported attribute $1, the test may fail]) + int foo( void ) __attribute__(($1)); + ] + )], []) + ], + dnl GCC doesn't exit with an error if an unknown attribute is + dnl provided but only outputs a warning, so accept the attribute + dnl only if no warning were issued. + [AS_IF([test -s conftest.err], + [AS_VAR_SET([ac_var], [no])], + [AS_VAR_SET([ac_var], [yes])])], + [AS_VAR_SET([ac_var], [no])]) + ]) + + AS_IF([test yes = AS_VAR_GET([ac_var])], + [AC_DEFINE_UNQUOTED(AS_TR_CPP(HAVE_FUNC_ATTRIBUTE_$1), 1, + [Define to 1 if the system has the `$1' function attribute])], []) + + AS_VAR_POPDEF([ac_var]) +]) diff --git a/m4/ax_gcc_var_attribute.m4 b/m4/ax_gcc_var_attribute.m4 new file mode 100644 index 0000000..0b7d2a6 --- /dev/null +++ b/m4/ax_gcc_var_attribute.m4 @@ -0,0 +1,141 @@ +# =========================================================================== +# http://www.gnu.org/software/autoconf-archive/ax_gcc_var_attribute.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_GCC_VAR_ATTRIBUTE(ATTRIBUTE) +# +# DESCRIPTION +# +# This macro checks if the compiler supports one of GCC's variable +# attributes; many other compilers also provide variable attributes with +# the same syntax. Compiler warnings are used to detect supported +# attributes as unsupported ones are ignored by default so quieting +# warnings when using this macro will yield false positives. +# +# The ATTRIBUTE parameter holds the name of the attribute to be checked. +# +# If ATTRIBUTE is supported define HAVE_VAR_ATTRIBUTE_. +# +# The macro caches its result in the ax_cv_have_var_attribute_ +# variable. +# +# The macro currently supports the following variable attributes: +# +# aligned +# cleanup +# common +# nocommon +# deprecated +# mode +# packed +# tls_model +# unused +# used +# vector_size +# weak +# dllimport +# dllexport +# init_priority +# +# Unsupported variable attributes will be tested against a global integer +# variable and without any arguments given to the attribute itself; the +# result of this check might be wrong or meaningless so use with care. +# +# LICENSE +# +# Copyright (c) 2013 Gabriele Svelto +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 4 + +AC_DEFUN([AX_GCC_VAR_ATTRIBUTE], [ + AS_VAR_PUSHDEF([ac_var], [ax_cv_have_var_attribute_$1]) + + AC_CACHE_CHECK([for __attribute__(($1))], [ac_var], [ + AC_LINK_IFELSE([AC_LANG_PROGRAM([ + m4_case([$1], + [aligned], [ + int foo __attribute__(($1(32))); + ], + [cleanup], [ + int bar(int *t) { return *t; }; + ], + [common], [ + int foo __attribute__(($1)); + ], + [nocommon], [ + int foo __attribute__(($1)); + ], + [deprecated], [ + int foo __attribute__(($1)) = 0; + ], + [mode], [ + long foo __attribute__(($1(word))); + ], + [packed], [ + struct bar { + int baz __attribute__(($1)); + }; + ], + [tls_model], [ + __thread int bar1 __attribute__(($1("global-dynamic"))); + __thread int bar2 __attribute__(($1("local-dynamic"))); + __thread int bar3 __attribute__(($1("initial-exec"))); + __thread int bar4 __attribute__(($1("local-exec"))); + ], + [unused], [ + int foo __attribute__(($1)); + ], + [used], [ + int foo __attribute__(($1)); + ], + [vector_size], [ + int foo __attribute__(($1(16))); + ], + [weak], [ + int foo __attribute__(($1)); + ], + [dllimport], [ + int foo __attribute__(($1)); + ], + [dllexport], [ + int foo __attribute__(($1)); + ], + [init_priority], [ + struct bar { bar() {} ~bar() {} }; + bar b __attribute__(($1(65535/2))); + ], + [ + m4_warn([syntax], [Unsupported attribute $1, the test may fail]) + int foo __attribute__(($1)); + ] + )], [ + m4_case([$1], + [cleanup], [ + int foo __attribute__(($1(bar))) = 0; + foo = foo + 1; + ], + [] + )]) + ], + dnl GCC doesn't exit with an error if an unknown attribute is + dnl provided but only outputs a warning, so accept the attribute + dnl only if no warning were issued. + [AS_IF([test -s conftest.err], + [AS_VAR_SET([ac_var], [no])], + [AS_VAR_SET([ac_var], [yes])])], + [AS_VAR_SET([ac_var], [no])]) + ]) + + AS_IF([test yes = AS_VAR_GET([ac_var])], + [AC_DEFINE_UNQUOTED(AS_TR_CPP(HAVE_VAR_ATTRIBUTE_$1), 1, + [Define to 1 if the system has the `$1' variable attribute])], []) + + AS_VAR_POPDEF([ac_var]) +]) diff --git a/src/.gitignore b/src/.gitignore new file mode 100644 index 0000000..7066278 --- /dev/null +++ b/src/.gitignore @@ -0,0 +1,4 @@ +/config.h +/config.h.in~ +/libtp.a +/tp diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 0000000..502c82d --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,18 @@ +MAINTAINERCLEANFILES = Makefile.in config.h.in + +AM_CXXFLAGS = @DEFINES@ + +# Remove ar: `u' modifier ignored since `D' is the default (see `U') +ARFLAGS = cr + +bin_PROGRAMS = tp +noinst_LIBRARIES = libtp.a + +tp_SOURCES = main.cc proxy.cc logger.cc resolver.cc +tp_LDADD = libtp.a @THREAD_LIBS@ +tp_CXXFLAGS = $(AM_CXXFLAGS) -DVERSION='"@VERSION@"' @THREAD_CFLAGS@ + +libtp_a_SOURCES = args.cc xdg.cc terminal.cc http.cc url.cc paths.cc \ + character.cc config.cc strings.cc io.cc looper.cc \ + buffer.cc chunked.cc +libtp_a_CXXFLAGS = $(AM_CXXFLAGS) -DSYSCONFDIR='"@SYSCONFDIR@"' diff --git a/src/args.cc b/src/args.cc new file mode 100644 index 0000000..cde77b0 --- /dev/null +++ b/src/args.cc @@ -0,0 +1,281 @@ +// -*- mode: c++; c-basic-offset: 2; -*- + +#include "common.hh" + +#include +#include +#include +#include + +#include "args.hh" +#include "character.hh" +#include "terminal.hh" + +namespace { + +class ArgsImpl : public Args { +public: + ArgsImpl() + : good_(true) { + } + void add(char short_opt, std::string const& long_opt, + std::string const& argument, std::string const& help) override { + assert(short_opt == '\0' || short_opts_.count(short_opt) == 0); + assert(long_opt.empty() || long_opts_.count(long_opt) == 0); + assert(long_opt.find('=') == std::string::npos); + auto const index = opts_.size(); + opts_.push_back(Option(short_opt, long_opt, argument, help)); + if (short_opt != '\0') { + short_opts_.insert(std::make_pair(short_opt, index)); + } + if (!long_opt.empty()) { + long_opts_.insert(std::make_pair(long_opt, index)); + } + } + + bool run(int argc, char** argv, std::ostream& out) override { + if (argc == 0) { + assert(false); + good_ = false; + return false; + } + auto start = strrchr(argv[0], '/'); + if (!start) { + start = argv[0]; + } else { + start++; + } + return run(start, argc, argv, out); + } + + bool run(std::string const& prg, int argc, char** argv, std::ostream& out) + override { + reset(); + + std::string opt; + for (int a = 1; a < argc; ++a) { + if (argv[a][0] == '-') { + if (argv[a][1] == '-') { + if (argv[a][2] == '\0') { + for (++a; a < argc; ++a) { + args_.push_back(argv[a]); + } + return good_; + } + size_t len = 2; + while (argv[a][len] && argv[a][len] != '=') ++len; + opt.assign(argv[a] + 2, len - 2); + auto i = long_opts_.find(opt); + if (i == long_opts_.end()) { + out << prg << ": unrecognized option '--" << opt << "'\n"; + good_ = false; + continue; + } + if (argv[a][len] == '=') { + if (opts_[i->second].argument.empty()) { + out << prg << ": option '--" << opt << "'" + << " doesn't allow an argument\n"; + good_ = false; + continue; + } else { + opts_[i->second].value = argv[a] + len + 1; + opts_[i->second].is_set = true; + } + } else { + if (opts_[i->second].argument.empty()) { + opts_[i->second].is_set = true; + } else if (a + 1 == argc) { + out << prg << ": option '--" << opt << "'" + << " requires an argument\n"; + good_ = false; + continue; + } else { + opts_[i->second].value = argv[++a]; + opts_[i->second].is_set = true; + } + } + } else { + for (auto opt = argv[a] + 1; *opt; ++opt) { + auto i = short_opts_.find(*opt); + if (i == short_opts_.end()) { + out << prg << ": invalid option -- '" << *opt << "'\n"; + good_ = false; + continue; + } + if (opts_[i->second].argument.empty()) { + opts_[i->second].is_set = true; + } else if (a + 1 == argc) { + out << prg << ": option requires an argument " + << " -- '" << *opt << "'\n"; + good_ = false; + continue; + } else { + opts_[i->second].value = argv[++a]; + opts_[i->second].is_set = true; + } + } + } + } else { + args_.push_back(argv[a]); + } + } + + return good_; + } + bool good() const override { + return good_; + } + + bool is_set(char short_opt) const override { + auto i = short_opts_.find(short_opt); + if (i == short_opts_.end()) return false; + return opts_[i->second].is_set; + } + bool is_set(std::string const& long_opt) const override { + auto i = long_opts_.find(long_opt); + if (i == long_opts_.end()) return false; + return opts_[i->second].is_set; + } + char const* arg(char short_opt, char const* fallback) const override { + auto i = short_opts_.find(short_opt); + if (i == short_opts_.end()) return fallback; + if (!opts_[i->second].is_set) return fallback; + if (opts_[i->second].argument.empty()) return fallback; + return opts_[i->second].value.c_str(); + } + char const* arg(std::string const& long_opt, + char const* fallback) const override { + auto i = long_opts_.find(long_opt); + if (i == long_opts_.end()) return fallback; + if (!opts_[i->second].is_set) return fallback; + if (opts_[i->second].argument.empty()) return fallback; + return opts_[i->second].value.c_str(); + } + + std::vector const& arguments() const override { + return args_; + } + + void print_help(std::ostream& out) const override { + print_help(out, Terminal::size().width); + } + + void print_help(std::ostream& out, size_t width) const override { + size_t left = 0; + for (auto const& opt : opts_) { + size_t l = 0; + if (!opt.long_opt.empty()) { + l += 6 + opt.long_opt.size(); + } else if (opt.short_opt != '\0') { + l += 2; + } else { + continue; + } + if (!opt.argument.empty()) { + l += 1 + opt.argument.size(); + } + if (l > left) left = l; + } + + size_t const need = 2 + 2 + left; + if (need + 10 > width) { + width = need + 10; + } + size_t const right = width - need; + + for (auto const& opt : opts_) { + size_t i = 0; + if (!opt.long_opt.empty()) { + if (opt.short_opt != '\0') { + out << " -" << opt.short_opt << ", "; + } else { + out << " "; + } + out << "--" << opt.long_opt; + i += 8 + opt.long_opt.size(); + } else if (opt.short_opt != '\0') { + out << " -" << opt.short_opt; + i += 4; + } else { + continue; + } + if (!opt.argument.empty()) { + out << '=' << opt.argument; + i += 1 + opt.argument.size(); + } + pad(out, need - i); + if (opt.help.size() < right) { + out << opt.help << '\n'; + } else { + i = right; + while (i > 0 && !Character::isseparator(opt.help, i)) --i; + if (i == 0) i = right; + out << opt.help.substr(0, i) << '\n'; + while (true) { + while (i < opt.help.size() && Character::isspace(opt.help, i)) ++i; + if (i == opt.help.size()) break; + size_t j = right - 2; + pad(out, width - j); + if (i + j >= opt.help.size()) { + out << opt.help.substr(i) << '\n'; + break; + } + while (j > 0 && !Character::isseparator(opt.help, i + j)) --j; + if (j == 0) j = right - 2; + out << opt.help.substr(i, j) << '\n'; + i += j; + } + } + } + } + +private: + struct Option { + char const short_opt; + std::string const long_opt; + std::string const argument; + std::string const help; + + bool is_set; + std::string value; + + Option(char short_opt, std::string const& long_opt, + std::string const& argument, std::string const& help) + : short_opt(short_opt), long_opt(long_opt), argument(argument), + help(help), is_set(false) { + } + }; + bool good_; + std::unordered_map short_opts_; + std::unordered_map long_opts_; + std::vector