├── .popt ├── tests ├── test3-data │ ├── 02.answer │ ├── 01.input │ ├── 01.answer │ ├── 02.input │ ├── 03.answer │ └── 03.input ├── test-poptrc.in ├── CMakeLists.txt ├── test3.c ├── tdict.c ├── test2.c ├── testit.sh └── test1.c ├── popt.pdf ├── .github ├── CODEOWNERS └── workflows │ └── linux.yml ├── cmake ├── poptConfig.cmake.in └── popt.pc.in ├── ci └── Dockerfile ├── .gitignore ├── README ├── doc └── CMakeLists.txt ├── CREDITS ├── COPYING ├── src ├── libpopt.vers ├── system.h ├── CMakeLists.txt ├── poptint.h ├── poptint.c ├── poptparse.c ├── poptconfig.c ├── popt.h ├── popthelp.c └── lookup3.c ├── CMakeLists.txt └── popt.3 /.popt: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/test3-data/02.answer: -------------------------------------------------------------------------------- 1 | cannot parse test3-data/02.input. ret=-18 2 | -------------------------------------------------------------------------------- /popt.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rpm-software-management/popt/HEAD/popt.pdf -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # By default, everything goes to rpm-team 2 | * @rpm-software-management/rpm-team 3 | -------------------------------------------------------------------------------- /cmake/poptConfig.cmake.in: -------------------------------------------------------------------------------- 1 | @PACKAGE_INIT@ 2 | 3 | include ("${CMAKE_CURRENT_LIST_DIR}/poptTargets.cmake") 4 | -------------------------------------------------------------------------------- /tests/test3-data/01.input: -------------------------------------------------------------------------------- 1 | # this line is ignored 2 | # this one too 3 | aaa 4 | bbb 5 | ccc 6 | bla=bla 7 | 8 | this_is = fdsafdas 9 | bad_line= 10 | really bad line 11 | really bad line = again 12 | 5555= 55555 13 | test = with lots of spaces 14 | -------------------------------------------------------------------------------- /tests/test3-data/01.answer: -------------------------------------------------------------------------------- 1 | single string: ' --aaa --bbb --ccc --bla="bla" --this_is="fdsafdas" --5555="55555" --test="with lots of spaces"' 2 | popt array: size=7 3 | '--aaa' 4 | '--bbb' 5 | '--ccc' 6 | '--bla=bla' 7 | '--this_is=fdsafdas' 8 | '--5555=55555' 9 | '--test=with lots of spaces' 10 | 11 | -------------------------------------------------------------------------------- /cmake/popt.pc.in: -------------------------------------------------------------------------------- 1 | prefix=@CMAKE_INSTALL_PREFIX@ 2 | exec_prefix=${prefix} 3 | libdir=${exec_prefix}/@CMAKE_INSTALL_LIBDIR@ 4 | includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@ 5 | 6 | Name: @PROJECT_NAME@ 7 | Version: @PROJECT_VERSION@ 8 | Description: @PROJECT_DESCRIPTION@ 9 | Libs: -L${libdir} -lpopt 10 | Cflags: -I${includedir} 11 | -------------------------------------------------------------------------------- /.github/workflows/linux.yml: -------------------------------------------------------------------------------- 1 | name: Linux CI 2 | on: [push, pull_request] 3 | jobs: 4 | test: 5 | runs-on: ubuntu-latest 6 | steps: 7 | - uses: actions/checkout@v4 8 | - name: Build the test image 9 | run: docker build -t popt -f ci/Dockerfile . 10 | - name: Run the test suite 11 | run: docker run -t popt 12 | -------------------------------------------------------------------------------- /tests/test-poptrc.in: -------------------------------------------------------------------------------- 1 | test1 alias --simple --arg2 \ 2 | --POPTdesc=$"simple description" --POPTargs=$"ARG" 3 | test1 alias --two --arg1 --arg2 alias 4 | test1 alias --takerest -- 5 | test1 alias -T --arg2 6 | test1 alias -O --arg1 7 | 8 | test1 alias --grab --arg2 "'foo !#:+'" 9 | test1 alias --grabbar --grab bar 10 | 11 | test1 exec --echo-args /bin/echo 12 | test1 alias -e --echo-args 13 | test1 exec -a /bin/echo 14 | -------------------------------------------------------------------------------- /ci/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM registry.fedoraproject.org/fedora:39 2 | MAINTAINER rpm-maint@lists.rpm.org 3 | 4 | WORKDIR /srv/popt 5 | 6 | RUN echo -e "deltarpm=0\ninstall_weak_deps=0\ntsflags=nodocs" >> /etc/dnf/dnf.conf 7 | RUN rm -f /etc/yum.repos.d/*modular.repo 8 | RUN dnf -y update 9 | RUN dnf -y install \ 10 | cmake \ 11 | gettext-devel \ 12 | make \ 13 | gcc \ 14 | binutils \ 15 | && dnf clean all 16 | 17 | COPY . . 18 | 19 | RUN cmake -S . -B ./build -DENABLE_WERROR=ON 20 | CMD cd build && ctest --output-on-failure --force-new-ctest-process 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .ccache 2 | .deps/ 3 | .depend 4 | .libs/ 5 | ABOUT-NLS 6 | ChangeLog 7 | Doxyfile 8 | Makefile 9 | Makefile.in 10 | /aclocal.m4 11 | /autom4te* 12 | build 13 | clang 14 | /config.* 15 | /configure 16 | doxygen 17 | intl 18 | lconv 19 | libtool 20 | /m4/ 21 | popt.spec 22 | stamp-h 23 | stamp-h1 24 | stamp-h.in 25 | tdict 26 | test-poptrc 27 | /tests/test-suite.log 28 | /tests/testit.sh.log 29 | /tests/testit.sh.trs 30 | /tests/test1 31 | /tests/test2 32 | /tests/test3 33 | *.gcda 34 | *.gcno 35 | *.gmo 36 | *.la 37 | *.lcd 38 | *.lo 39 | *.swp 40 | *.o 41 | popt.pc 42 | popt-*.tar.gz 43 | 44 | /build-aux/ 45 | /po/Makefile.in.in 46 | /po/Makevars.template 47 | /po/POTFILES 48 | /po/Rules-quot 49 | /po/boldquot.sed 50 | /po/en@boldquot.header 51 | /po/en@quot.header 52 | /po/insert-header.sin 53 | /po/quot.sed 54 | /po/remove-potcdate.sin 55 | /po/stamp-po 56 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | This is the popt(3) command line option parsing library. While it is similar 2 | to getopt(3), it contains a number of enhancements, including: 3 | 4 | 1) popt is fully reentrant 5 | 2) popt can parse arbitrary argv[] style arrays while 6 | getopt(3) makes this quite difficult 7 | 3) popt allows users to alias command line arguments 8 | 4) popt provides convenience functions for parsing strings 9 | into argv[] style arrays 10 | 11 | Complete documentation on popt(3) is available in popt.pdf (included in this 12 | tarball), which is excerpted with permission from the book "Linux 13 | Application Development" by Michael K. Johnson and Erik Troan (available 14 | from Addison Wesley in May, 1998). 15 | 16 | Bugs, feature requests and contributions can be submitted at 17 | https://github.com/rpm-software-management/popt or alternatively 18 | rpm-maint@lists.rpm.org. 19 | -------------------------------------------------------------------------------- /tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Set up macro for building and adding tests 2 | macro(BuildTest TESTNAME) 3 | add_executable(${TESTNAME} EXCLUDE_FROM_ALL ${TESTNAME}.c) 4 | target_link_libraries(${TESTNAME} PRIVATE popt) 5 | add_test(${TESTNAME}_build ${CMAKE_COMMAND} --build "${CMAKE_BINARY_DIR}" --config "$" --target ${TESTNAME}) 6 | set_tests_properties(${TESTNAME}_build PROPERTIES FIXTURES_SETUP testit_fixture) 7 | endmacro() 8 | 9 | set(TEST_PROGRAMS 10 | test1 11 | test2 12 | test3 13 | tdict 14 | ) 15 | 16 | foreach (TESTPROG ${TEST_PROGRAMS}) 17 | BuildTest(${TESTPROG}) 18 | endforeach() 19 | 20 | configure_file(test-poptrc.in test-poptrc @ONLY) 21 | 22 | find_program (SH_PROGRAM sh) 23 | 24 | if (SH_PROGRAM) 25 | add_test (testit ${SH_PROGRAM} -c "srcdir=${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/testit.sh") 26 | set_tests_properties(testit PROPERTIES FIXTURES_REQUIRED testit_fixture) 27 | endif (SH_PROGRAM) 28 | -------------------------------------------------------------------------------- /doc/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # add a target to generate API documentation with Doxygen 2 | find_package(Doxygen) 3 | option(BUILD_DOCUMENTATION "Create and install the HTML based API documentation (requires Doxygen)" ${DOXYGEN_FOUND}) 4 | 5 | if(BUILD_DOCUMENTATION) 6 | if(NOT DOXYGEN_FOUND) 7 | message(FATAL_ERROR "Doxygen is needed to build the documentation.") 8 | endif() 9 | 10 | set(DOXYGEN_OPTIMIZE_OUTPUT_FOR_C YES) 11 | if (ENABLE_WERROR) 12 | set(DOXYGEN_WARN_AS_ERROR YES) 13 | endif() 14 | doxygen_add_docs(apidocs 15 | ${CMAKE_SOURCE_DIR}/src/popt.h 16 | ALL USE_STAMP_FILE 17 | ) 18 | install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/html TYPE DOC) 19 | endif() 20 | 21 | install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/../popt.3 22 | DESTINATION ${CMAKE_INSTALL_MANDIR}/man3) 23 | 24 | install(FILES 25 | ${CMAKE_CURRENT_SOURCE_DIR}/../COPYING 26 | ${CMAKE_CURRENT_SOURCE_DIR}/../CREDITS 27 | ${CMAKE_CURRENT_SOURCE_DIR}/../README 28 | TYPE DOC) 29 | -------------------------------------------------------------------------------- /tests/test3-data/02.input: -------------------------------------------------------------------------------- 1 | # this next line has 999 letters. this should cause an abort. 2 | xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 3 | -------------------------------------------------------------------------------- /CREDITS: -------------------------------------------------------------------------------- 1 | Initial work on POPT was done primarily by: 2 | 3 | Jeff Johnson 4 | Erik Troan 5 | 6 | Over the years, additional code, documentation, translations, tests etc 7 | have been contributed by: 8 | 9 | Ettore Atalan 10 | John Bradshaw 11 | Hela Basa 12 | Yuri Chornoivan 13 | Gustavo Costa 14 | Wayne Davison 15 | Michal Domonkos 16 | Piotr Drąg 17 | Jan Engelhardt 18 | Ralf S. Engelschall 19 | Oğuz Ersen 20 | Marc Ewing 21 | Fabrice Fontaine 22 | Rafael Fontenelle 23 | Cristian Gafton 24 | Neal Gompa 25 | Christian Göttsche 26 | Emilio Herrera 27 | Jean-Baptiste Holcroft 28 | Michael K. Johnson 29 | Peter Jones 30 | Charles Lee 31 | Elliot Lee 32 | Dmitry V. Levin 33 | Richard Levitte 34 | Carl Henrik Lunde 35 | Jordi Mallach 36 | Balázs Meskó 37 | Arkadiusz Miskiewicz 38 | Panu Matilainen 39 | Paul Nasrat 40 | Elia Pinto 41 | Bernhard Rosenkränzer 42 | Andreas Schwab 43 | Robert Scheck 44 | scootergrisen 45 | simmon 46 | Tobias Stoeckmann 47 | Ricky Tigg 48 | Alexander Traud 49 | Andika Triwidada 50 | Miloslav Trmač 51 | Göran Uddeborg 52 | Geert Warrink 53 | Jakub Wilk 54 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | Copyright (c) 1998 Red Hat Software 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /tests/test3.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "system.h" 4 | 5 | int main (int argc, char **argv) { 6 | char *out; 7 | int newargc, j, f, ret; 8 | const char **newargv; 9 | FILE *fp; 10 | 11 | if (argc == 1) { 12 | printf ("usage: test-popt file_1 file_2 ...\n"); 13 | printf ("you may specify many files\n"); 14 | exit (1); 15 | } 16 | 17 | for (f = 1; f < argc; f++) { 18 | fp = fopen (argv[f], "r"); 19 | if (fp == NULL) { 20 | printf ("cannot read file %s. errno=%s\n", argv[f], 21 | strerror(errno)); 22 | continue; 23 | } 24 | 25 | ret = poptConfigFileToString (fp, &out, 0); 26 | if (ret != 0) { 27 | printf ("cannot parse %s. ret=%d\n", argv[f], ret); 28 | continue; 29 | } 30 | 31 | printf ("single string: '%s'\n", out); 32 | 33 | ret = poptParseArgvString (out, &newargc, &newargv); 34 | if (ret != 0) { 35 | printf ("cannot parse %s. ret=%d\n", out, ret); 36 | continue; 37 | } 38 | 39 | printf ("popt array: size=%d\n", newargc); 40 | for (j = 0; j < newargc; j++) 41 | printf ("'%s'\n", newargv[j]); 42 | 43 | printf ("\n"); 44 | free(newargv); 45 | free(out); 46 | fclose (fp); 47 | } 48 | return 0; 49 | } 50 | -------------------------------------------------------------------------------- /src/libpopt.vers: -------------------------------------------------------------------------------- 1 | LIBPOPT_0 2 | { 3 | global: 4 | _fini; 5 | _init; 6 | _poptArgMask; 7 | _poptGroupMask; 8 | poptAddAlias; 9 | poptAddItem; 10 | poptAliasOptions; 11 | poptBadOption; 12 | _poptBitsN; 13 | _poptBitsM; 14 | _poptBitsK; 15 | poptBitsAdd; 16 | poptBitsArgs; 17 | poptBitsChk; 18 | poptBitsClr; 19 | poptBitsDel; 20 | poptBitsIntersect; 21 | poptBitsUnion; 22 | poptConfigFileToString; 23 | poptDupArgv; 24 | poptFini; 25 | poptFreeContext; 26 | poptGetArg; 27 | poptGetArgs; 28 | poptGetContext; 29 | poptGetInvocationName; 30 | poptGetNextOpt; 31 | poptGetOptArg; 32 | poptHelpOptions; 33 | poptHelpOptionsI18N; 34 | poptInit; 35 | poptParseArgvString; 36 | poptPeekArg; 37 | poptPrintHelp; 38 | poptPrintUsage; 39 | poptReadFile; 40 | poptReadConfigFile; 41 | poptReadConfigFiles; 42 | poptReadDefaultConfig; 43 | poptResetContext; 44 | poptSaneFile; 45 | poptSaveBits; 46 | poptSaveInt; 47 | poptSaveLong; 48 | poptSaveLongLong; 49 | poptSaveShort; 50 | poptSaveString; 51 | poptSetExecPath; 52 | poptSetOtherOptionHelp; 53 | poptStrerror; 54 | poptStrippedArgv; 55 | poptStuffArgs; 56 | local: 57 | *; 58 | }; 59 | -------------------------------------------------------------------------------- /src/system.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file 3 | */ 4 | 5 | #ifdef HAVE_CONFIG_H 6 | #include "config.h" 7 | #endif 8 | 9 | #include 10 | 11 | /* XXX isspace(3) has i18n encoding signedness issues on Solaris. */ 12 | #define _isspaceptr(_chp) isspace((int)(*(unsigned const char *)(_chp))) 13 | 14 | #ifdef HAVE_MCHECK_H 15 | #include 16 | #endif 17 | 18 | #include 19 | #include 20 | 21 | void * xmalloc (size_t size); 22 | 23 | void * xcalloc (size_t nmemb, size_t size); 24 | 25 | void * xrealloc (void * ptr, size_t size); 26 | 27 | char * xstrdup (const char *str); 28 | 29 | #if !defined(HAVE_STPCPY) 30 | /* Copy SRC to DEST, returning the address of the terminating '\0' in DEST. */ 31 | static inline char * stpcpy (char *dest, const char * src) { 32 | register char *d = dest; 33 | register const char *s = src; 34 | 35 | do 36 | *d++ = *s; 37 | while (*s++ != '\0'); 38 | return d - 1; 39 | } 40 | #endif 41 | 42 | /* Memory allocation via macro defs to get meaningful locations from mtrace() */ 43 | #if defined(HAVE_MCHECK_H) && defined(__GNUC__) 44 | #define vmefail() (fprintf(stderr, "virtual memory exhausted.\n"), exit(EXIT_FAILURE), NULL) 45 | #define xmalloc(_size) (malloc(_size) ? : vmefail()) 46 | #define xcalloc(_nmemb, _size) (calloc((_nmemb), (_size)) ? : vmefail()) 47 | #define xrealloc(_ptr, _size) (realloc((_ptr), (_size)) ? : vmefail()) 48 | #define xstrdup(_str) (strcpy((malloc(strlen(_str)+1) ? : vmefail()), (_str))) 49 | #else 50 | #define xmalloc(_size) malloc(_size) 51 | #define xcalloc(_nmemb, _size) calloc((_nmemb), (_size)) 52 | #define xrealloc(_ptr, _size) realloc((_ptr), (_size)) 53 | #define xstrdup(_str) strdup(_str) 54 | #endif /* defined(HAVE_MCHECK_H) && defined(__GNUC__) */ 55 | 56 | #if defined(HAVE_SECURE_GETENV) 57 | #define getenv(_s) secure_getenv(_s) 58 | #elif defined(HAVE___SECURE_GETENV) 59 | #define getenv(_s) __secure_getenv(_s) 60 | #endif 61 | 62 | #if !defined(__GNUC__) && !defined(__attribute__) 63 | #define __attribute__(x) 64 | #endif 65 | #define UNUSED(x) x __attribute__((__unused__)) 66 | #define FORMAT(a, b, c) __attribute__((__format__ (a, b, c))) 67 | #define NORETURN __attribute__((__noreturn__)) 68 | 69 | #include "popt.h" 70 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Build the library 2 | 3 | # autotool compatibility stuff 4 | add_compile_definitions(POPT_SYSCONFDIR="${CMAKE_INSTALL_FULL_SYSCONFDIR}") 5 | add_compile_definitions(PACKAGE="${PROJECT_NAME}") 6 | 7 | # Setup library target 8 | add_library(popt SHARED 9 | popt.c 10 | poptconfig.c 11 | popthelp.c 12 | poptint.c 13 | poptparse.c 14 | poptint.h 15 | system.h 16 | ) 17 | 18 | target_include_directories(popt PUBLIC 19 | $ 20 | $ 21 | ) 22 | 23 | if (Iconv_FOUND) 24 | target_link_libraries(popt PRIVATE Iconv::Iconv) 25 | endif() 26 | 27 | set_target_properties(popt PROPERTIES 28 | VERSION ${PROJECT_VERSION} 29 | SOVERSION ${POPT_SOVERSION} 30 | C_STANDARD 99 31 | C_STANDARD_REQUIRED ON 32 | C_EXTENSIONS ON 33 | PUBLIC_HEADER popt.h 34 | LINK_FLAGS "-Wl,--no-undefined -Wl,--version-script,\"${PROJECT_SOURCE_DIR}/src/libpopt.vers\"" 35 | ) 36 | 37 | # Install the library 38 | configure_file(${PROJECT_SOURCE_DIR}/cmake/popt.pc.in ${CMAKE_BINARY_DIR}/popt.pc @ONLY) 39 | 40 | install(FILES ${CMAKE_BINARY_DIR}/popt.pc 41 | DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig 42 | ) 43 | 44 | install(TARGETS popt 45 | EXPORT poptTargets 46 | LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} 47 | PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} 48 | ) 49 | 50 | # Generate and install the exports 51 | export(EXPORT poptTargets 52 | FILE ${CMAKE_BINARY_DIR}/poptTargets.cmake 53 | ) 54 | install(EXPORT poptTargets 55 | FILE poptTargets.cmake 56 | DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/popt 57 | ) 58 | configure_package_config_file( 59 | ${PROJECT_SOURCE_DIR}/cmake/poptConfig.cmake.in 60 | ${CMAKE_BINARY_DIR}/poptConfig.cmake 61 | INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/popt 62 | NO_SET_AND_CHECK_MACRO 63 | NO_CHECK_REQUIRED_COMPONENTS_MACRO 64 | ) 65 | install(FILES 66 | ${CMAKE_BINARY_DIR}/poptConfig.cmake 67 | DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/popt 68 | ) 69 | write_basic_package_version_file( 70 | ${CMAKE_BINARY_DIR}/poptConfigVersion.cmake 71 | VERSION ${PROJECT_VERSION} 72 | COMPATIBILITY SameMajorVersion 73 | ) 74 | install(FILES 75 | ${CMAKE_BINARY_DIR}/poptConfigVersion.cmake 76 | DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/popt 77 | ) 78 | -------------------------------------------------------------------------------- /tests/test3-data/03.answer: -------------------------------------------------------------------------------- 1 | single string: ' --confversion="1.0.0.0" --expires="19:57:56 03/16/01" --sessions="-1" --hostid="72738c36" --hostid="80b0cafb" --hostid="80c104e4" --hostid="80cf520f" --hostid="809fc805" --port="6666" --realservername="goya:554" --realserverip="127.0.0.1:554" --sdmux="0" --runtimeconf="1" --soc="1" --socaddr="127.0.0.1" --socconntimeout="3" --socqport="4110" --socuport="4111" --loadtest="0" --tunnelssmport="5541" --allowtcptransport="0" --realrevpkts="0" --asmrules="4;" --maxasmtime="10" --asmwaittime="4" --asmcalctime="4" --maxletswitchtime="20" --setbw="6;" --setbwblocktime="15" --asmsetbwtime="3" --setbwwaittime="1" --inputmaxsetbw="100" --encratemaxsetbw="100" --livesetbwdelta="2" --encrate="34000" --maxoutproberate="85" --maxoutencrate="140" --minoutencrate="108" --erprgamma="70" --utp="15" --nbalpha="77" --bbalpha="83" --tsfrequency="10" --recoveryrate="140" --maxbuffer="2000" --csmbuffer="12000" --probedelta="120" --numprobes="4" --probebuffpkts="5" --probeinterval="600000" --clientlog="2" --loglevel="2" --monitor="0" --testmode="0" --emulator="0" --emuaddr="127.0.0.1" --emuport="4200" --auxsvr="0" --mngsvrip="127.0.0.1" --mngsvrport="15550" --ssmip="127.0.0.1" --auxsvrport="14445" --auxsvrchkfreq="2" --auxsvrchkperiod="60;" --simulation="0" --netbuffer="5" --siminterval="3"' 2 | popt array: size=67 3 | '--confversion=1.0.0.0' 4 | '--expires=19:57:56 03/16/01' 5 | '--sessions=-1' 6 | '--hostid=72738c36' 7 | '--hostid=80b0cafb' 8 | '--hostid=80c104e4' 9 | '--hostid=80cf520f' 10 | '--hostid=809fc805' 11 | '--port=6666' 12 | '--realservername=goya:554' 13 | '--realserverip=127.0.0.1:554' 14 | '--sdmux=0' 15 | '--runtimeconf=1' 16 | '--soc=1' 17 | '--socaddr=127.0.0.1' 18 | '--socconntimeout=3' 19 | '--socqport=4110' 20 | '--socuport=4111' 21 | '--loadtest=0' 22 | '--tunnelssmport=5541' 23 | '--allowtcptransport=0' 24 | '--realrevpkts=0' 25 | '--asmrules=4;' 26 | '--maxasmtime=10' 27 | '--asmwaittime=4' 28 | '--asmcalctime=4' 29 | '--maxletswitchtime=20' 30 | '--setbw=6;' 31 | '--setbwblocktime=15' 32 | '--asmsetbwtime=3' 33 | '--setbwwaittime=1' 34 | '--inputmaxsetbw=100' 35 | '--encratemaxsetbw=100' 36 | '--livesetbwdelta=2' 37 | '--encrate=34000' 38 | '--maxoutproberate=85' 39 | '--maxoutencrate=140' 40 | '--minoutencrate=108' 41 | '--erprgamma=70' 42 | '--utp=15' 43 | '--nbalpha=77' 44 | '--bbalpha=83' 45 | '--tsfrequency=10' 46 | '--recoveryrate=140' 47 | '--maxbuffer=2000' 48 | '--csmbuffer=12000' 49 | '--probedelta=120' 50 | '--numprobes=4' 51 | '--probebuffpkts=5' 52 | '--probeinterval=600000' 53 | '--clientlog=2' 54 | '--loglevel=2' 55 | '--monitor=0' 56 | '--testmode=0' 57 | '--emulator=0' 58 | '--emuaddr=127.0.0.1' 59 | '--emuport=4200' 60 | '--auxsvr=0' 61 | '--mngsvrip=127.0.0.1' 62 | '--mngsvrport=15550' 63 | '--ssmip=127.0.0.1' 64 | '--auxsvrport=14445' 65 | '--auxsvrchkfreq=2' 66 | '--auxsvrchkperiod=60;' 67 | '--simulation=0' 68 | '--netbuffer=5' 69 | '--siminterval=3' 70 | 71 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.12) 2 | 3 | # Ensure built-in policies from CMake are used, (e.g. improved policies for macOS) 4 | cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}) 5 | 6 | project(popt 7 | VERSION 1.19 8 | DESCRIPTION "Portable library for parsing command line parameters" 9 | LANGUAGES C 10 | ) 11 | 12 | # Set soversion 13 | set(POPT_SOVERSION 0) 14 | 15 | # Configurable stuff 16 | option(ENABLE_WERROR "Stop build on warnings" OFF) 17 | option(ENABLE_ASAN "Enable address-sanitizer" OFF) 18 | option(ENABLE_UBSAN "Enable undefined behavior-sanitizer" OFF) 19 | 20 | # Set up GNU conventions and standard FHS paths 21 | include(GNUInstallDirs) 22 | 23 | # Activate CMake package configuration helpers 24 | include(CMakePackageConfigHelpers) 25 | 26 | # set the minimum C standard 27 | set(CMAKE_C_STANDARD 99) 28 | set(CMAKE_C_EXTENSIONS ON) 29 | 30 | # Check for necessary symbols and headers 31 | include(CheckSymbolExists) 32 | include(CheckIncludeFile) 33 | 34 | function(chkdef func inc) 35 | string(TOUPPER ${func} FUNC) 36 | set(HAVENAME HAVE_${FUNC}) 37 | check_symbol_exists(${func} "${inc}" ${HAVENAME}) 38 | if (${HAVENAME}) 39 | add_compile_definitions(${HAVENAME}) 40 | endif() 41 | endfunction() 42 | 43 | function(chkhdr inc req) 44 | string(MAKE_C_IDENTIFIER ${inc} ID) 45 | string(TOUPPER ${ID} INC) 46 | set(HAVENAME HAVE_${INC}) 47 | check_include_file(${inc} ${HAVENAME}) 48 | if (${HAVENAME}) 49 | add_compile_definitions(${HAVENAME}) 50 | endif() 51 | if (${req} AND NOT ${HAVENAME}) 52 | message(FATAL_ERROR "required include ${inc} not found") 53 | endif() 54 | endfunction() 55 | 56 | chkdef(stpcpy string.h) 57 | chkdef(strerror string.h) 58 | chkdef(getuid unistd.h) 59 | chkdef(geteuid unistd.h) 60 | chkdef(mtrace mcheck.h) 61 | chkdef(secure_getenv stdlib.h) 62 | chkdef(__secure_getenv stdlib.h) 63 | chkdef(setreuid unistd.h) 64 | chkdef(setuid unistd.h) 65 | chkdef(stpcpy string.h) 66 | chkdef(strerror string) 67 | chkdef(vasprintf stdio.h) 68 | chkdef(srandom stdlib.h) 69 | chkdef(glob_pattern_p glob.h) 70 | chkdef(mbsrtowcs wchar.h) 71 | 72 | 73 | set(OPTINCS 74 | fnmatch.h glob.h langinfo.h libintl.h mcheck.h stdalign.h 75 | ) 76 | foreach(inchdr ${OPTINCS}) 77 | chkhdr(${inchdr} FALSE) 78 | endforeach() 79 | 80 | find_package(Iconv) 81 | 82 | if (Iconv_FOUND) 83 | add_compile_definitions(HAVE_ICONV) 84 | endif() 85 | 86 | add_compile_options(-Wall) 87 | if (ENABLE_WERROR) 88 | add_compile_options(-Werror) 89 | endif() 90 | 91 | # Sanitizers 92 | if (ENABLE_ASAN) 93 | add_compile_options(-fsanitize=address) 94 | add_link_options(-fsanitize=address) 95 | endif() 96 | if (ENABLE_UBSAN) 97 | add_compile_options(-fsanitize=undefined) 98 | add_link_options(-fsanitize=undefined) 99 | endif() 100 | if (ENABLE_ASAN OR ENABLE_UBSAN) 101 | add_compile_options(-fno-omit-frame-pointer) 102 | endif() 103 | 104 | 105 | add_subdirectory(src) 106 | add_subdirectory(doc) 107 | if (EXISTS po/popt.pot) 108 | add_subdirectory(po) 109 | endif() 110 | 111 | # Enable testing 112 | include(CTest) 113 | enable_testing() 114 | add_subdirectory(tests) 115 | -------------------------------------------------------------------------------- /tests/tdict.c: -------------------------------------------------------------------------------- 1 | #include "system.h" 2 | #include 3 | #include "popt.h" 4 | 5 | static int _debug = 0; 6 | static int _verbose = 1; 7 | static const char * dictfn = "/usr/share/dict/words"; 8 | static poptBits dictbits = NULL; 9 | static struct { 10 | unsigned total; 11 | unsigned hits; 12 | unsigned misses; 13 | } e; 14 | 15 | static int loadDict(const char * fn, poptBits * ap) 16 | { 17 | char b[BUFSIZ]; 18 | FILE * fp = fopen(fn, "r"); 19 | char * t, *te; 20 | int nlines = -1; 21 | 22 | if (fp == NULL || ferror(fp)) goto exit; 23 | 24 | nlines = 0; 25 | while ((t = fgets(b, sizeof(b), fp)) != NULL) { 26 | while (*t && isspace(*t)) t++; 27 | if (*t == '#') continue; 28 | te = t + strlen(t); 29 | while (te-- > t && isspace(*te)) *te = '\0'; 30 | if (*t == '\0') continue; 31 | if (ap) { 32 | if (_debug) 33 | fprintf(stderr, "==> poptSaveBits(%p, \"%s\")\n", *ap, t); 34 | (void) poptSaveBits(ap, 0, t); 35 | } 36 | nlines++; 37 | } 38 | exit: 39 | if (fp) (void) fclose(fp); 40 | return nlines; 41 | } 42 | 43 | static struct poptOption options[] = { 44 | { "debug", 'd', POPT_BIT_SET|POPT_ARGFLAG_TOGGLE, &_debug, 1, 45 | "Set debugging.", NULL }, 46 | { "verbose", 'v', POPT_BIT_SET|POPT_ARGFLAG_TOGGLE, &_verbose, 1, 47 | "Set verbosity.", NULL }, 48 | 49 | POPT_AUTOALIAS 50 | POPT_AUTOHELP 51 | POPT_TABLEEND 52 | }; 53 | 54 | int main(int argc, const char ** argv) 55 | { 56 | poptContext optCon = NULL; 57 | const char ** av = NULL; 58 | poptBits avbits = NULL; 59 | int ec = 2; /* assume failure */ 60 | int rc; 61 | 62 | #if defined(HAVE_MCHECK_H) && defined(HAVE_MTRACE) 63 | mtrace(); /* Trace malloc only if MALLOC_TRACE=mtrace-output-file. */ 64 | #endif 65 | 66 | /* XXX Scale the Bloom filters in popt. */ 67 | if ((rc = loadDict(dictfn, NULL)) <= 0) 68 | goto exit; 69 | _poptBitsK = 2; 70 | _poptBitsM = 0; 71 | _poptBitsN = _poptBitsK * (unsigned)rc; 72 | 73 | optCon = poptGetContext("tdict", argc, argv, options, 0); 74 | 75 | /* Read all the options (if any). */ 76 | while ((rc = poptGetNextOpt(optCon)) > 0) { 77 | char * optArg = poptGetOptArg(optCon); 78 | if (optArg) free(optArg); 79 | switch (rc) { 80 | default: goto exit; 81 | } 82 | } 83 | if (rc < -1) { 84 | fprintf(stderr, "tdict: %s: %s\n", 85 | poptBadOption(optCon, POPT_BADOPTION_NOALIAS), 86 | poptStrerror(rc)); 87 | goto exit; 88 | } 89 | 90 | if ((rc = loadDict(dictfn, &dictbits)) <= 0) 91 | goto exit; 92 | 93 | av = poptGetArgs(optCon); 94 | if ((rc = poptBitsArgs(optCon, &avbits)) != 0) 95 | goto exit; 96 | if (avbits) { 97 | poptBits Ibits = NULL; 98 | (void) poptBitsUnion(&Ibits, dictbits); 99 | rc = poptBitsIntersect(&Ibits, avbits); 100 | fprintf(stdout, "===== %s words are in %s\n", (rc ? "Some" : "No"), dictfn); 101 | if (Ibits) free(Ibits); 102 | } 103 | if (av && avbits) 104 | while (*av) { 105 | rc = poptBitsChk(dictbits, *av); 106 | if (rc < 0) goto exit; 107 | e.total++; 108 | if (rc > 0) { 109 | if (_verbose) 110 | fprintf(stdout, "%s:\tYES\n", *av); 111 | e.hits++; 112 | } else { 113 | if (_verbose) 114 | fprintf(stdout, "%s:\tNO\n", *av); 115 | e.misses++; 116 | } 117 | av++; 118 | } 119 | 120 | ec = 0; 121 | 122 | exit: 123 | fprintf(stdout, "===== poptBits N:%u M:%u K:%u (%uKb) total(%u) = hits(%u) + misses(%u)\n", 124 | _poptBitsN, _poptBitsM, _poptBitsK, (((_poptBitsM/8)+1)+1023)/1024, e.total, e.hits, e.misses); 125 | if (avbits) free(avbits); 126 | optCon = poptFreeContext(optCon); 127 | #if defined(HAVE_MCHECK_H) && defined(HAVE_MTRACE) 128 | muntrace(); /* Trace malloc only if MALLOC_TRACE=mtrace-output-file. */ 129 | #endif 130 | return ec; 131 | } 132 | -------------------------------------------------------------------------------- /src/poptint.h: -------------------------------------------------------------------------------- 1 | /** \ingroup popt 2 | * @file 3 | */ 4 | 5 | /* (C) 1998-2000 Red Hat, Inc. -- Licensing details are in the COPYING 6 | file accompanying popt source distributions, available from 7 | http://ftp.rpm.org/popt/releases/. */ 8 | 9 | #ifndef H_POPTINT 10 | #define H_POPTINT 11 | 12 | #include 13 | 14 | #define POPT_OPTION_DEPTH 10 15 | 16 | /** 17 | * Wrapper to free(3), hides const compilation noise, permit NULL, return NULL. 18 | * @param p memory to free 19 | * @retval NULL always 20 | */ 21 | static inline void * 22 | _free(const void * p) 23 | { 24 | if (p != NULL) free((void *)p); 25 | return NULL; 26 | } 27 | 28 | /* Bit mask macros. */ 29 | typedef unsigned int __pbm_bits; 30 | #define __PBM_NBITS (8 * sizeof (__pbm_bits)) 31 | #define __PBM_IX(d) ((d) / __PBM_NBITS) 32 | #define __PBM_MASK(d) ((__pbm_bits) 1 << (((unsigned)(d)) % __PBM_NBITS)) 33 | typedef struct { 34 | __pbm_bits bits[1]; 35 | } pbm_set; 36 | #define __PBM_BITS(set) ((set)->bits) 37 | 38 | #define PBM_ALLOC(d) calloc(__PBM_IX (d) + 1, sizeof(pbm_set)) 39 | #define PBM_FREE(s) _free(s); 40 | #define PBM_SET(d, s) (__PBM_BITS (s)[__PBM_IX (d)] |= __PBM_MASK (d)) 41 | #define PBM_CLR(d, s) (__PBM_BITS (s)[__PBM_IX (d)] &= ~__PBM_MASK (d)) 42 | #define PBM_ISSET(d, s) ((__PBM_BITS (s)[__PBM_IX (d)] & __PBM_MASK (d)) != 0) 43 | 44 | extern void poptJlu32lpair(const void *key, size_t size, 45 | uint32_t *pc, uint32_t *pb); 46 | 47 | /** \ingroup popt 48 | * Typedef's for string and array of strings. 49 | */ 50 | typedef const char * poptString; 51 | typedef poptString * poptArgv; 52 | 53 | /** \ingroup popt 54 | * A union to simplify opt->arg access without casting. 55 | */ 56 | typedef union poptArg_u { 57 | void * ptr; 58 | int * intp; 59 | short * shortp; 60 | long * longp; 61 | long long * longlongp; 62 | float * floatp; 63 | double * doublep; 64 | const char ** argv; 65 | poptCallbackType cb; 66 | poptOption opt; 67 | } poptArg; 68 | 69 | extern unsigned int _poptArgMask; 70 | extern unsigned int _poptGroupMask; 71 | 72 | #define poptArgType(_opt) ((_opt)->argInfo & _poptArgMask) 73 | #define poptGroup(_opt) ((_opt)->argInfo & _poptGroupMask) 74 | 75 | #define F_ISSET(_opt, _FLAG) ((_opt)->argInfo & POPT_ARGFLAG_##_FLAG) 76 | #define LF_ISSET(_FLAG) (argInfo & POPT_ARGFLAG_##_FLAG) 77 | #define CBF_ISSET(_opt, _FLAG) ((_opt)->argInfo & POPT_CBFLAG_##_FLAG) 78 | 79 | /* XXX sick hack to preserve pretense of a popt-1.x ABI. */ 80 | #define poptSubstituteHelpI18N(opt) \ 81 | { if ((opt) == poptHelpOptions) (opt) = poptHelpOptionsI18N; } 82 | 83 | struct optionStackEntry { 84 | int argc; 85 | poptArgv argv; 86 | pbm_set * argb; 87 | int next; 88 | char * nextArg; 89 | const char * nextCharArg; 90 | poptItem currAlias; 91 | int stuffed; 92 | }; 93 | 94 | struct poptContext_s { 95 | struct optionStackEntry optionStack[POPT_OPTION_DEPTH]; 96 | struct optionStackEntry * os; 97 | poptArgv leftovers; 98 | int numLeftovers; 99 | int allocLeftovers; 100 | int nextLeftover; 101 | const struct poptOption * options; 102 | int restLeftover; 103 | const char * appName; 104 | poptItem aliases; 105 | int numAliases; 106 | unsigned int flags; 107 | poptItem execs; 108 | int numExecs; 109 | char * execFail; 110 | poptArgv finalArgv; 111 | int finalArgvCount; 112 | int finalArgvAlloced; 113 | int (*maincall) (int argc, const char **argv); 114 | poptItem doExec; 115 | const char * execPath; 116 | int execAbsolute; 117 | const char * otherHelp; 118 | pbm_set * arg_strip; 119 | }; 120 | 121 | #if defined(POPT_fprintf) 122 | #define POPT_dgettext dgettext 123 | #else 124 | #ifdef HAVE_ICONV 125 | #include 126 | #endif 127 | 128 | #if defined(HAVE_DCGETTEXT) 129 | char *POPT_dgettext(const char * dom, const char * str); 130 | #endif 131 | 132 | FORMAT(printf, 2, 3) 133 | int POPT_fprintf (FILE* stream, const char *format, ...); 134 | #endif /* !defined(POPT_fprintf) */ 135 | 136 | const char *POPT_prev_char (const char *str); 137 | const char *POPT_next_char (const char *str); 138 | 139 | #endif 140 | 141 | #if defined(ENABLE_NLS) && defined(HAVE_LIBINTL_H) 142 | #include 143 | #endif 144 | 145 | #if defined(ENABLE_NLS) && defined(HAVE_GETTEXT) 146 | #define _(foo) gettext(foo) 147 | #else 148 | #define _(foo) foo 149 | #endif 150 | 151 | #if defined(ENABLE_NLS) && defined(HAVE_LIBINTL_H) && defined(HAVE_DCGETTEXT) 152 | #define D_(dom, str) POPT_dgettext(dom, str) 153 | #define POPT_(foo) D_("popt", foo) 154 | #else 155 | #define D_(dom, str) str 156 | #define POPT_(foo) foo 157 | #endif 158 | 159 | #define N_(foo) foo 160 | 161 | -------------------------------------------------------------------------------- /src/poptint.c: -------------------------------------------------------------------------------- 1 | #include "system.h" 2 | #include 3 | #include 4 | #ifdef HAVE_LANGINFO_H 5 | #include 6 | #endif 7 | #include "poptint.h" 8 | 9 | /* Any pair of 32 bit hashes can be used. lookup3.c generates pairs, will do. */ 10 | #define _JLU3_jlu32lpair 1 11 | #define jlu32lpair poptJlu32lpair 12 | #include "lookup3.c" 13 | 14 | const char * 15 | POPT_prev_char (const char *str) 16 | { 17 | const char *p = str; 18 | 19 | while (1) { 20 | p--; 21 | if (((unsigned)*p & 0xc0) != (unsigned)0x80) 22 | return p; 23 | } 24 | } 25 | 26 | const char * 27 | POPT_next_char (const char *str) 28 | { 29 | const char *p = str; 30 | 31 | while (*p != '\0') { 32 | p++; 33 | if (((unsigned)*p & 0xc0) != (unsigned)0x80) 34 | break; 35 | } 36 | return p; 37 | } 38 | 39 | #if !defined(POPT_fprintf) /* XXX lose all the goop ... */ 40 | 41 | #if defined(ENABLE_NLS) && defined(HAVE_LIBINTL_H) && defined(HAVE_DCGETTEXT) 42 | /* 43 | * Rebind a "UTF-8" codeset for popt's internal use. 44 | */ 45 | char * 46 | POPT_dgettext(const char * dom, const char * str) 47 | { 48 | char * codeset = NULL; 49 | char * retval = NULL; 50 | 51 | if (!dom) 52 | dom = textdomain(NULL); 53 | codeset = bind_textdomain_codeset(dom, NULL); 54 | bind_textdomain_codeset(dom, "UTF-8"); 55 | retval = dgettext(dom, str); 56 | bind_textdomain_codeset(dom, codeset); 57 | 58 | return retval; 59 | } 60 | #endif 61 | 62 | #ifdef HAVE_ICONV 63 | /** 64 | * Return malloc'd string converted from UTF-8 to current locale. 65 | * @param istr input string (UTF-8 encoding assumed) 66 | * @return localized string 67 | */ 68 | static char * 69 | strdup_locale_from_utf8 (char * istr) 70 | { 71 | char * codeset = NULL; 72 | char * ostr = NULL; 73 | iconv_t cd; 74 | 75 | if (istr == NULL) 76 | return NULL; 77 | 78 | #ifdef HAVE_LANGINFO_H 79 | codeset = nl_langinfo ((nl_item)CODESET); 80 | #endif 81 | 82 | if (codeset != NULL && strcmp(codeset, "UTF-8") != 0 83 | && (cd = iconv_open(codeset, "UTF-8")) != (iconv_t)-1) 84 | { 85 | char * shift_pin = NULL; 86 | size_t db = strlen(istr); 87 | char * dstr = malloc((db + 1) * sizeof(*dstr)); 88 | char * dstr_tmp; 89 | char * pin = istr; 90 | char * pout = dstr; 91 | size_t ib = db; 92 | size_t ob = db; 93 | size_t err; 94 | 95 | if (dstr == NULL) { 96 | (void) iconv_close(cd); 97 | return NULL; 98 | } 99 | err = iconv(cd, NULL, NULL, NULL, NULL); 100 | while (1) { 101 | *pout = '\0'; 102 | err = iconv(cd, &pin, &ib, &pout, &ob); 103 | if (err != (size_t)-1) { 104 | if (shift_pin == NULL) { 105 | shift_pin = pin; 106 | pin = NULL; 107 | ib = 0; 108 | continue; 109 | } 110 | } else 111 | switch (errno) { 112 | case E2BIG: 113 | { size_t used = (size_t)(pout - dstr); 114 | db *= 2; 115 | dstr_tmp = realloc(dstr, (db + 1) * sizeof(*dstr)); 116 | if (dstr_tmp == NULL) { 117 | free(dstr); 118 | (void) iconv_close(cd); 119 | return NULL; 120 | } 121 | dstr = dstr_tmp; 122 | pout = dstr + used; 123 | ob = db - used; 124 | continue; 125 | } break; 126 | case EINVAL: 127 | case EILSEQ: 128 | default: 129 | break; 130 | } 131 | break; 132 | } 133 | (void) iconv_close(cd); 134 | *pout = '\0'; 135 | ostr = xstrdup(dstr); 136 | free(dstr); 137 | } else 138 | ostr = xstrdup(istr); 139 | 140 | return ostr; 141 | } 142 | #endif 143 | 144 | int 145 | POPT_fprintf (FILE * stream, const char * format, ...) 146 | { 147 | char * b = NULL, * ob = NULL; 148 | int rc; 149 | va_list ap; 150 | 151 | #if defined(HAVE_VASPRINTF) 152 | va_start(ap, format); 153 | if ((rc = vasprintf(&b, format, ap)) < 0) 154 | b = NULL; 155 | va_end(ap); 156 | #else 157 | size_t nb = (size_t)1; 158 | 159 | /* HACK: add +1 to the realloc no. of bytes "just in case". */ 160 | /* XXX Likely unneeded, the issues wrto vsnprintf(3) return b0rkage have 161 | * to do with whether the final '\0' is counted (or not). The code 162 | * below already adds +1 for the (possibly already counted) trailing NUL. 163 | */ 164 | while ((b = realloc(b, nb+1)) != NULL) { 165 | va_start(ap, format); 166 | rc = vsnprintf(b, nb, format, ap); 167 | va_end(ap); 168 | if (rc > -1) { /* glibc 2.1 */ 169 | if ((size_t)rc < nb) 170 | break; 171 | nb = (size_t)(rc + 1); /* precise buffer length known */ 172 | } else /* glibc 2.0 */ 173 | nb += (nb < (size_t)100 ? (size_t)100 : nb); 174 | ob = b; 175 | } 176 | #endif 177 | 178 | rc = 0; 179 | if (b != NULL) { 180 | #ifdef HAVE_ICONV 181 | ob = strdup_locale_from_utf8(b); 182 | if (ob != NULL) { 183 | rc = fprintf(stream, "%s", ob); 184 | free(ob); 185 | } else 186 | #endif 187 | rc = fprintf(stream, "%s", b); 188 | free (b); 189 | } 190 | 191 | return rc; 192 | } 193 | 194 | #endif /* !defined(POPT_fprintf) */ 195 | -------------------------------------------------------------------------------- /tests/test3-data/03.input: -------------------------------------------------------------------------------- 1 | # 2 | # WARNING: NO LINE IN THIS FILE SHOULD BE LONGER THAN 999 characters! 3 | # 4 | # a vague real world example 5 | # 6 | # the vers no of this file. useful for debug 7 | confversion=1.0.0.0 8 | 9 | # date and time of expiry of this license 10 | expires=19:57:56 03/16/01 11 | 12 | # max no of simultaneous sessions 13 | sessions=-1 14 | 15 | # hostid(s) of licensed host(s): matisse 16 | hostid=72738c36 17 | 18 | # degas (exodus) 19 | hostid=80b0cafb 20 | 21 | # max 22 | hostid=80c104e4 23 | 24 | # breton 25 | hostid=80cf520f 26 | 27 | # vaneyck 28 | hostid=809fc805 29 | 30 | # port at which SSM should listen (unless -p) 31 | port=6666 32 | 33 | # the name of the realserver that we proxy for 34 | realservername=goya:554 35 | 36 | # the ip addr of real server we proxy fo 37 | realserverip=127.0.0.1:554 38 | 39 | # are we using an SDMUX to receive rev STP pkts? 40 | sdmux=0 41 | 42 | # allow run time config through TCP connection 43 | runtimeconf=1 44 | 45 | # should we connect to SOC for delivinit/update etc? 46 | soc=1 47 | 48 | # address of the SOC 49 | socaddr=127.0.0.1 50 | 51 | # no of secs before we timeout SOC connection 52 | socconntimeout=3 53 | 54 | # SOC port for sending delivinit query 55 | socqport=4110 56 | 57 | # SOC port for sending delivery update 58 | socuport=4111 59 | 60 | # run in load test mode? (ignore player disconnect) 61 | loadtest=0 62 | 63 | # port of SSM to redirect to on probe bw < desc bw 64 | tunnelssmport=5541 65 | 66 | # allow TCP (RTSP interleaved) streaming? 67 | allowtcptransport=0 68 | 69 | # enable RDT rev packets? 70 | realrevpkts=0 71 | 72 | # allow asm switches? 0=no,1=yes,2=all within maxasmtime,3=1 within maxasmtime 73 | # 4=same as 2 but also whenever told by CSM after maxasmtime+tell CSM 74 | asmrules=4; 75 | # max time to which we will allow asm switches 76 | maxasmtime=10 77 | 78 | # time to wait after switch before starting below 79 | asmwaittime=4 80 | 81 | # time over which to calc post asm switch input rate 82 | asmcalctime=4 83 | 84 | # time after LETSWITCH within which to permit switch 85 | maxletswitchtime=20 86 | 87 | # change setbw? 0=no,1=block,2=sub w/1st,3=sub w/curr,4=tell CSM,5=allow w/asm 88 | # 6=sub w/cur enc rate & tell CSM & generate setbw on switch 89 | setbw=6; 90 | # minimum time between setbw requests from player 91 | setbwblocktime=15 92 | 93 | # max time within which we allow post asm setbw 94 | asmsetbwtime=3 95 | 96 | # post switch wait time (secs) before we send setbw 97 | setbwwaittime=1 98 | 99 | # max setbw as % of [init/post switch] input rate 100 | inputmaxsetbw=100 101 | 102 | # max setbw as % of current encoding rate 103 | encratemaxsetbw=100 104 | 105 | # % increase in encratemaxsetbw for live streams 106 | livesetbwdelta=2 107 | 108 | # temporarily here. encoding rate bits/sec 109 | encrate=34000 110 | 111 | # max output rate = maxoutproberate % probe rate 112 | maxoutproberate=85 113 | 114 | # max output rate = maxoutencrate % curr enc rate 115 | maxoutencrate=140 116 | 117 | # worst case outrate. should be > encratemaxsetbw 118 | minoutencrate=108 119 | 120 | # max out rate = er+erprgamma%(maxoutpr%pr-er) 121 | erprgamma=70 122 | 123 | # the CSM UTP: % loss above which CSM will enter CC 124 | utp=15 125 | 126 | # CSM alpha for narrowband 127 | nbalpha=77 128 | 129 | # CSM alpha for broadband 130 | bbalpha=83 131 | 132 | # periodic sendTS? 0 = sendTS only at SR_COMPUTE 133 | tsfrequency=10 134 | 135 | # SReoc as a % of the encoding rate 136 | recoveryrate=140 137 | 138 | # maximum server side buffer (in packets) 139 | maxbuffer=2000 140 | 141 | # client side buffer (in milliseconds) 142 | csmbuffer=12000 143 | 144 | # probe bw > probedelta % describe bw for us to work 145 | probedelta=120 146 | 147 | # the number of probes to do at the beginning 148 | numprobes=4 149 | 150 | # number of packets to burst during each probe 151 | probebuffpkts=5 152 | 153 | # time (in microsecs) interval between probes 154 | probeinterval=600000 155 | 156 | # client logs to none(0),disk(1),soc(2),both(3) 157 | clientlog=2 158 | 159 | # 0=none,1=brief,2=detailed,3=extensive 160 | loglevel=2 161 | 162 | # connected to monitor? 163 | monitor=0 164 | 165 | # 0=none, 1=test 166 | testmode=0 167 | 168 | # are we using the emulator? 169 | emulator=0 170 | 171 | # emulator IP address 172 | emuaddr=127.0.0.1 173 | 174 | # emulator TCP control port to connect to 175 | emuport=4200 176 | 177 | # 178 | # aux serv config 179 | # 180 | # start aux server? 0=no, 1=yes 181 | auxsvr=0 182 | 183 | # IP address of mgmt server 184 | mngsvrip=127.0.0.1 185 | 186 | # port where mgmt server listens 187 | mngsvrport=15550 188 | 189 | # IP address of SSM that we are monitoring 190 | ssmip=127.0.0.1 191 | 192 | # port where aux server should listen 193 | auxsvrport=14445 194 | 195 | # frequency of aux server checks 196 | auxsvrchkfreq=2 197 | 198 | auxsvrchkperiod=60; 199 | # 200 | # congestion simulation info 201 | # 202 | # congestion simulation? 203 | simulation=0 204 | 205 | # size of the network buffer 206 | netbuffer=5 207 | 208 | # time (in secs) between drop rate recalculation 209 | siminterval=3 210 | 211 | -------------------------------------------------------------------------------- /tests/test2.c: -------------------------------------------------------------------------------- 1 | /* 2 | Popt Library Test Program Number Too 3 | 4 | --> "a real world test of popt bugs" <-- 5 | 6 | Copyright (C) 1999 US Interactive, Inc. 7 | 8 | This program can be used under the GPL or LGPL at your 9 | whim as long as this Copyright remains attached. 10 | */ 11 | 12 | #include "system.h" 13 | 14 | static char *PathnameOfKeyFile = NULL; 15 | static char *PathnameOfOfferFile = NULL; 16 | 17 | static char *txHost = NULL; 18 | static int txSslPort = 443; 19 | static int txStoreId = 0; 20 | 21 | static char *contentHost = NULL; 22 | static char *contentPath = NULL; 23 | 24 | static char *dbPassword = NULL; 25 | static char *dbUserName = NULL; 26 | 27 | static const char *rcfile = "createuser-defaults"; 28 | static char *username = NULL; 29 | 30 | static char *password = NULL; 31 | static char *firstname = NULL; 32 | static char *lastname = NULL; 33 | static char *addr1 = NULL; 34 | static char *addr2 = NULL; 35 | static char *city = NULL; 36 | static char *state = NULL; 37 | static char *postal = NULL; 38 | static char *country = NULL; 39 | 40 | static char *email = NULL; 41 | 42 | static char *dayphone = NULL; 43 | static char *fax = NULL; 44 | 45 | 46 | int 47 | main(int argc, const char ** argv) { 48 | 49 | poptContext optCon; /* context for parsing command-line options */ 50 | struct poptOption userOptionsTable[] = { 51 | { "first", 'f', POPT_ARG_STRING, &firstname, 0, 52 | "user's first name", "first" }, 53 | { "last", 'l', POPT_ARG_STRING, &lastname, 0, 54 | "user's last name", "last" }, 55 | { "username", 'u', POPT_ARG_STRING, &username, 0, 56 | "system user name", "user" }, 57 | { "password", 'p', POPT_ARG_STRING, &password, 0, 58 | "system password name", "password" }, 59 | { "addr1", '1', POPT_ARG_STRING, &addr1, 0, 60 | "line 1 of address", "addr1" }, 61 | { "addr2", '2', POPT_ARG_STRING, &addr2, 0, 62 | "line 2 of address", "addr2" }, 63 | { "city", 'c', POPT_ARG_STRING, &city, 0, 64 | "city", "city" }, 65 | { "state", 's', POPT_ARG_STRING, &state, 0, 66 | "state or province", "state" }, 67 | { "postal", 'P', POPT_ARG_STRING, &postal, 0, 68 | "postal or zip code", "postal" }, 69 | { "zip", 'z', POPT_ARG_STRING, &postal, 0, 70 | "postal or zip code", "postal" }, 71 | { "country", 'C', POPT_ARG_STRING, &country, 0, 72 | "two letter ISO country code", "country" }, 73 | { "email", 'e', POPT_ARG_STRING, &email, 0, 74 | "user's email address", "email" }, 75 | { "dayphone", 'd', POPT_ARG_STRING, &dayphone, 0, 76 | "day time phone number", "dayphone" }, 77 | { "fax", 'F', POPT_ARG_STRING, &fax, 0, 78 | "fax number", "fax" }, 79 | { NULL, 0, 0, NULL, 0, NULL, NULL } 80 | }; 81 | struct poptOption transactOptionsTable[] = { 82 | { "keyfile", '\0', POPT_ARG_STRING, &PathnameOfKeyFile, 0, 83 | "transact offer key file (flat_O.kf)", "key-file" }, 84 | { "offerfile", '\0', POPT_ARG_STRING, &PathnameOfOfferFile, 0, 85 | "offer template file (osl.ofr)", "offer-file" }, 86 | { "storeid", '\0', POPT_ARG_INT, &txStoreId, 0, 87 | "store id", "store-id" }, 88 | { "rcfile", '\0', POPT_ARG_STRING, &rcfile, 0, 89 | "default command line options (in popt format)", "rcfile" }, 90 | { "txhost", '\0', POPT_ARG_STRING, &txHost, 0, 91 | "transact host", "transact-host" }, 92 | { "txsslport", '\0', POPT_ARG_INT, &txSslPort, 0, 93 | "transact server ssl port ", "transact ssl port" }, 94 | { "cnhost", '\0', POPT_ARG_STRING, &contentHost, 0, 95 | "content host", "content-host" }, 96 | { "cnpath", '\0', POPT_ARG_STRING, &contentPath, 0, 97 | "content url path", "content-path" }, 98 | { NULL, 0, 0, NULL, 0, NULL, NULL } 99 | }; 100 | 101 | struct poptOption databaseOptionsTable[] = { 102 | { "dbpassword", '\0', POPT_ARG_STRING, &dbPassword, 0, 103 | "Database password", "DB password" }, 104 | { "dbusername", '\0', POPT_ARG_STRING, &dbUserName, 0, 105 | "Database user name", "DB UserName" }, 106 | { NULL, 0, 0, NULL, 0, NULL, NULL } 107 | }; 108 | 109 | struct poptOption optionsTable[] = { 110 | { NULL, '\0', POPT_ARG_INCLUDE_TABLE, NULL, 0, 111 | "Transact Options (not all will apply)", NULL }, 112 | { NULL, '\0', POPT_ARG_INCLUDE_TABLE, NULL, 0, 113 | "Transact Database Names", NULL }, 114 | { NULL, '\0', POPT_ARG_INCLUDE_TABLE, NULL, 0, 115 | "User Fields", NULL }, 116 | POPT_AUTOHELP 117 | { NULL, 0, 0, NULL, 0, NULL, NULL } 118 | }; 119 | 120 | optionsTable[0].arg = transactOptionsTable; 121 | optionsTable[1].arg = databaseOptionsTable; 122 | optionsTable[2].arg = userOptionsTable; 123 | 124 | #if defined(HAVE_MCHECK_H) && defined(HAVE_MTRACE) 125 | mtrace(); /* Trace malloc only if MALLOC_TRACE=mtrace-output-file. */ 126 | #endif 127 | 128 | optCon = poptGetContext("createuser", argc, argv, optionsTable, 0); 129 | poptReadConfigFile(optCon, rcfile ); 130 | 131 | /* although there are no options to be parsed, check for --help */ 132 | poptGetNextOpt(optCon); 133 | 134 | optCon = poptFreeContext(optCon); 135 | 136 | printf( "dbusername %s\tdbpassword %s\n" 137 | "txhost %s\ttxsslport %d\ttxstoreid %d\tpathofkeyfile %s\n" 138 | "username %s\tpassword %s\tfirstname %s\tlastname %s\n" 139 | "addr1 %s\taddr2 %s\tcity %s\tstate %s\tpostal %s\n" 140 | "country %s\temail %s\tdayphone %s\tfax %s\n", 141 | dbUserName, dbPassword, 142 | txHost, txSslPort, txStoreId, PathnameOfKeyFile, 143 | username, password, firstname, lastname, 144 | addr1,addr2, city, state, postal, 145 | country, email, dayphone, fax); 146 | return 0; 147 | } 148 | -------------------------------------------------------------------------------- /src/poptparse.c: -------------------------------------------------------------------------------- 1 | /** \ingroup popt 2 | * @file 3 | */ 4 | 5 | /* (C) 1998-2002 Red Hat, Inc. -- Licensing details are in the COPYING 6 | file accompanying popt source distributions, available from 7 | http://ftp.rpm.org/popt/releases/. */ 8 | 9 | #include "system.h" 10 | 11 | #define POPT_ARGV_ARRAY_GROW_DELTA 5 12 | 13 | int poptDupArgv(int argc, const char **argv, 14 | int * argcPtr, const char *** argvPtr) 15 | { 16 | size_t nb = (argc + 1) * sizeof(*argv); 17 | const char ** argv2; 18 | char * dst; 19 | int i; 20 | 21 | if (argc <= 0 || argv == NULL) /* XXX can't happen */ 22 | return POPT_ERROR_NOARG; 23 | for (i = 0; i < argc; i++) { 24 | if (argv[i] == NULL) 25 | return POPT_ERROR_NOARG; 26 | nb += strlen(argv[i]) + 1; 27 | } 28 | 29 | dst = malloc(nb); 30 | if (dst == NULL) /* XXX can't happen */ 31 | return POPT_ERROR_MALLOC; 32 | argv2 = (void *) dst; 33 | dst += (argc + 1) * sizeof(*argv); 34 | *dst = '\0'; 35 | 36 | for (i = 0; i < argc; i++) { 37 | argv2[i] = dst; 38 | dst = stpcpy(dst, argv[i]); 39 | dst++; /* trailing NUL */ 40 | } 41 | argv2[argc] = NULL; 42 | 43 | if (argvPtr) { 44 | *argvPtr = argv2; 45 | } else { 46 | free(argv2); 47 | argv2 = NULL; 48 | } 49 | if (argcPtr) 50 | *argcPtr = argc; 51 | return 0; 52 | } 53 | 54 | int poptParseArgvString(const char * s, int * argcPtr, const char *** argvPtr) 55 | { 56 | const char * src; 57 | char quote = '\0'; 58 | int argvAlloced = POPT_ARGV_ARRAY_GROW_DELTA; 59 | const char ** argv = malloc(sizeof(*argv) * argvAlloced); 60 | const char ** argv_tmp; 61 | int argc = 0; 62 | size_t buflen = strlen(s) + 1; 63 | char * buf, * bufOrig = NULL; 64 | int rc = POPT_ERROR_MALLOC; 65 | 66 | if (argv == NULL) return rc; 67 | buf = bufOrig = calloc((size_t)1, buflen); 68 | if (buf == NULL) { 69 | free(argv); 70 | return rc; 71 | } 72 | argv[argc] = buf; 73 | 74 | for (src = s; *src != '\0'; src++) { 75 | if (quote == *src) { 76 | quote = '\0'; 77 | } else if (quote != '\0') { 78 | if (*src == '\\') { 79 | src++; 80 | if (!*src) { 81 | rc = POPT_ERROR_BADQUOTE; 82 | goto exit; 83 | } 84 | if (*src != quote) *buf++ = '\\'; 85 | } 86 | *buf++ = *src; 87 | } else if (_isspaceptr(src)) { 88 | if (*argv[argc] != '\0') { 89 | buf++, argc++; 90 | if (argc == argvAlloced) { 91 | argvAlloced += POPT_ARGV_ARRAY_GROW_DELTA; 92 | argv_tmp = realloc(argv, sizeof(*argv) * argvAlloced); 93 | if (argv_tmp == NULL) goto exit; 94 | argv = argv_tmp; 95 | } 96 | argv[argc] = buf; 97 | } 98 | } else switch (*src) { 99 | case '"': 100 | case '\'': 101 | quote = *src; 102 | break; 103 | case '\\': 104 | src++; 105 | if (!*src) { 106 | rc = POPT_ERROR_BADQUOTE; 107 | goto exit; 108 | } 109 | /* fallthrough */ 110 | default: 111 | *buf++ = *src; 112 | break; 113 | } 114 | } 115 | 116 | if (strlen(argv[argc])) { 117 | argc++, buf++; 118 | } 119 | 120 | rc = poptDupArgv(argc, argv, argcPtr, argvPtr); 121 | 122 | exit: 123 | if (bufOrig) free(bufOrig); 124 | if (argv) free(argv); 125 | return rc; 126 | } 127 | 128 | /* still in the dev stage. 129 | * return values, perhaps 1== file error 130 | * 2== line to long 131 | * 3== umm.... more? 132 | */ 133 | int poptConfigFileToString(FILE *fp, char ** argstrp, 134 | UNUSED(int flags)) 135 | { 136 | char line[999]; 137 | char * argstr; 138 | char * argstr_tmp; 139 | char * p; 140 | char * q; 141 | char * x; 142 | size_t t; 143 | size_t argvlen = 0; 144 | size_t maxlinelen = sizeof(line); 145 | size_t linelen; 146 | size_t maxargvlen = (size_t)480; 147 | 148 | *argstrp = NULL; 149 | 150 | /* | this_is = our_line 151 | * p q x 152 | */ 153 | 154 | if (fp == NULL) 155 | return POPT_ERROR_NULLARG; 156 | 157 | argstr = calloc(maxargvlen, sizeof(*argstr)); 158 | if (argstr == NULL) return POPT_ERROR_MALLOC; 159 | 160 | while (fgets(line, (int)maxlinelen, fp) != NULL) { 161 | p = line; 162 | 163 | /* loop until first non-space char or EOL */ 164 | while( *p != '\0' && _isspaceptr(p) ) 165 | p++; 166 | 167 | linelen = strlen(p); 168 | if (linelen >= maxlinelen-1) { 169 | free(argstr); 170 | return POPT_ERROR_OVERFLOW; /* XXX line too long */ 171 | } 172 | 173 | if (*p == '\0' || *p == '\n') continue; /* line is empty */ 174 | if (*p == '#') continue; /* comment line */ 175 | 176 | q = p; 177 | 178 | while (*q != '\0' && (!_isspaceptr(q)) && *q != '=') 179 | q++; 180 | 181 | if (_isspaceptr(q)) { 182 | /* a space after the name, find next non space */ 183 | *q++='\0'; 184 | while( *q != '\0' && _isspaceptr(q) ) q++; 185 | } 186 | if (*q == '\0') { 187 | /* single command line option (ie, no name=val, just name) */ 188 | q[-1] = '\0'; /* kill off newline from fgets() call */ 189 | argvlen += (t = (size_t)(q - p)) + (sizeof(" --")-1); 190 | if (argvlen >= maxargvlen) { 191 | maxargvlen = (t > maxargvlen) ? t*2 : maxargvlen*2; 192 | argstr_tmp = realloc(argstr, maxargvlen); 193 | if (argstr_tmp == NULL) { 194 | free(argstr); 195 | return POPT_ERROR_MALLOC; 196 | } 197 | argstr = argstr_tmp; 198 | } 199 | strcat(argstr, " --"); 200 | strcat(argstr, p); 201 | continue; 202 | } 203 | if (*q != '=') 204 | continue; /* XXX for now, silently ignore bogus line */ 205 | 206 | /* *q is an equal sign. */ 207 | *q++ = '\0'; 208 | 209 | /* find next non-space letter of value */ 210 | while (*q != '\0' && _isspaceptr(q)) 211 | q++; 212 | if (*q == '\0') 213 | continue; /* XXX silently ignore missing value */ 214 | 215 | /* now, loop and strip all ending whitespace */ 216 | x = p + linelen; 217 | while (_isspaceptr(--x)) 218 | *x = '\0'; /* null out last char if space (including fgets() NL) */ 219 | 220 | /* rest of line accept */ 221 | t = (size_t)(x - p); 222 | argvlen += t + (sizeof("' --='")-1); 223 | if (argvlen >= maxargvlen) { 224 | maxargvlen = (t > maxargvlen) ? t*2 : maxargvlen*2; 225 | argstr_tmp = realloc(argstr, maxargvlen); 226 | if (argstr_tmp == NULL) { 227 | free(argstr); 228 | return POPT_ERROR_MALLOC; 229 | } 230 | argstr = argstr_tmp; 231 | } 232 | strcat(argstr, " --"); 233 | strcat(argstr, p); 234 | strcat(argstr, "=\""); 235 | strcat(argstr, q); 236 | strcat(argstr, "\""); 237 | } 238 | 239 | *argstrp = argstr; 240 | return 0; 241 | } 242 | -------------------------------------------------------------------------------- /tests/testit.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | run() { 4 | prog=$1; shift 5 | name=$1; shift 6 | answer=$1; shift 7 | 8 | result=`HOME=$builddir $builddir/$prog $*` 9 | if [ "$answer" != "$result" ]; then 10 | echo "FAIL: $name: \"$result\" != \"$answer\" " 11 | retval=2 12 | else 13 | echo "PASS: $name" 14 | fi 15 | } 16 | 17 | run_diff() { 18 | prog=$1; shift 19 | name=$1; shift 20 | in_file=$1; shift 21 | answer_file=$1; shift 22 | 23 | out=$builddir/tmp.out 24 | diff_file=$builddir/tmp.diff 25 | 26 | $builddir/$prog $in_file > $out 27 | ret=$? 28 | diff $out $answer_file > $diff_file 29 | diff_ret=$? 30 | 31 | if [ "$diff_ret" != "0" ]; then 32 | echo "FAIL $name: failed output is in $out, diff is:" 33 | cat $diff_file 34 | retval=2 35 | else 36 | echo "PASS $name" 37 | fi 38 | rm $out $diff_file 39 | } 40 | 41 | builddir=`pwd` 42 | retval=0 43 | cd ${builddir} 44 | echo "Running tests in ${builddir}" 45 | 46 | #make -q testcases 47 | 48 | run test1 "test1 - 1" "arg1: 1 arg2: (none)" --arg1 49 | run test1 "test1 - 2" "arg1: 0 arg2: foo" --arg2 foo 50 | run test1 "test1 - 3" "arg1: 1 arg2: something" --arg1 --arg2 something 51 | run test1 "test1 - 4" "arg1: 0 arg2: another" --simple another 52 | run test1 "test1 - 5" "arg1: 1 arg2: alias" --two 53 | run test1 "test1 - 6" "arg1: 1 arg2: (none) rest: --arg2" --arg1 -- --arg2 54 | run test1 "test1 - 7" "arg1: 0 arg2: abcd rest: --arg1" --simple abcd -- --arg1 55 | run test1 "test1 - 8" "arg1: 1 arg2: (none) rest: --arg2" --arg1 --takerest --arg2 56 | run test1 "test1 - 9" "arg1: 0 arg2: foo" -2 foo 57 | run test1 "test1 - 10" "arg1: 0 arg2: (none) arg3: 50" -3 50 58 | run test1 "test1 - 11" "arg1: 0 arg2: bar" -T bar 59 | run test1 "test1 - 12" "arg1: 1 arg2: (none)" -O 60 | run test1 "test1 - 13" "arg1: 1 arg2: foo" -OT foo 61 | run test1 "test1 - 14" "arg1: 0 arg2: (none) inc: 1" --inc 62 | run test1 "test1 - 15" "arg1: 0 arg2: foo inc: 1" -I --arg2 foo 63 | POSIX_ME_HARDER=1 ; export POSIX_ME_HARDER 64 | run test1 "test1 - 16" "arg1: 1 arg2: (none) rest: foo --arg2 something" --arg1 foo --arg2 something 65 | unset POSIX_ME_HARDER 66 | POSIXLY_CORRECT=1 ; export POSIXLY_CORRECT 67 | run test1 "test1 - 17" "arg1: 1 arg2: (none) rest: foo --arg2 something" --arg1 foo --arg2 something 68 | unset POSIXLY_CORRECT 69 | run test1 "test1 - 18" "callback: c sampledata bar arg1: 1 arg2: (none)" --arg1 --cb bar 70 | run test1 "test1 - 19" "" --echo-args 71 | run test1 "test1 - 20" "--arg1" --echo-args --arg1 72 | run test1 "test1 - 21" "--arg2 something" -T something -e 73 | run test1 "test1 - 22" "--arg2 something more args" -T something -a more args 74 | run test1 "test1 - 23" "--echo-args -a" --echo-args -e -a 75 | run test1 "test1 - 24" "arg1: 0 arg2: (none) short: 1" -onedash 76 | run test1 "test1 - 25" "arg1: 0 arg2: (none) short: 1" --onedash 77 | run test1 "test1 - 26" "callback: c arg for cb2 foo arg1: 0 arg2: (none)" --cb2 foo 78 | run test1 "test1 - 27" "arg1: 0 arg2: (none) rest: -" - 79 | run test1 "test1 - 28" "arg1: 0 arg2: foo rest: -" - -2 foo 80 | run test1 "test1 - 29" "arg1: 0 arg2: bbbb" --arg2=aaaa -2 bbbb 81 | run test1 "test1 - 30" "arg1: 0 arg2: 'foo bingo' rest: boggle" --grab bingo boggle 82 | run test1 "test1 - 31" "arg1: 0 arg2: 'foo bar' rest: boggle" --grabbar boggle 83 | 84 | run test1 "test1 - 32" "arg1: 0 arg2: (none) aInt: 123456789" -i 123456789 85 | run test1 "test1 - 33" "arg1: 0 arg2: (none) aInt: 123456789" --int 123456789 86 | run test1 "test1 - 34" "arg1: 0 arg2: (none) aShort: 12345" -s 12345 87 | run test1 "test1 - 35" "arg1: 0 arg2: (none) aShort: 12345" --short 12345 88 | run test1 "test1 - 36" "arg1: 0 arg2: (none) aLong: 1123456789" -l 1123456789 89 | run test1 "test1 - 37" "arg1: 0 arg2: (none) aLong: 1123456789" --long 1123456789 90 | run test1 "test1 - 38" "arg1: 0 arg2: (none) aLongLong: 1111123456789" -L 1111123456789 91 | run test1 "test1 - 39" "arg1: 0 arg2: (none) aLongLong: 1111123456789" --longlong 1111123456789 92 | 93 | run test1 "test1 - 40" "arg1: 0 arg2: (none) aFloat: 10.1" -f 10.1 94 | run test1 "test1 - 41" "arg1: 0 arg2: (none) aFloat: 10.1" --float 10.1 95 | run test1 "test1 - 42" "arg1: 0 arg2: (none) aDouble: 10.1" -d 10.1 96 | run test1 "test1 - 43" "arg1: 0 arg2: (none) aDouble: 10.1" --double 10.1 97 | 98 | run test1 "test1 - 44" "arg1: 0 arg2: (none) oStr: (none)" --optional 99 | run test1 "test1 - 45" "arg1: 0 arg2: (none) oStr: yadda" --optional=yadda 100 | run test1 "test1 - 46" "arg1: 0 arg2: (none) oStr: yadda" --optional yadda 101 | run test1 "test1 - 47" "arg1: 0 arg2: (none) oStr: ping rest: pong" --optional=ping pong 102 | run test1 "test1 - 48" "arg1: 0 arg2: (none) oStr: ping rest: pong" --optional ping pong 103 | run test1 "test1 - 49" "arg1: 0 arg2: (none) aArgv: A B rest: C" --argv A --argv B C 104 | 105 | run test1 "test1 - 50" "arg1: 0 arg2: foo=bar" -2foo=bar 106 | run test1 "test1 - 51" "arg1: 0 arg2: foo=bar" -2=foo=bar 107 | 108 | run test1 "test1 - 52" "arg1: 0 arg2: (none) aFlag: 0xfeed" --bitxor 109 | run test1 "test1 - 53" "arg1: 0 arg2: (none) aFlag: 0xffff" --bitset 110 | run test1 "test1 - 54" "arg1: 0 arg2: (none) aFlag: 0x28c" --bitclr 111 | run test1 "test1 - 55" "arg1: 0 arg2: (none) aFlag: 0x8888" --nobitset 112 | run test1 "test1 - 56" "arg1: 0 arg2: (none) aFlag: 0xface" --nobitclr 113 | 114 | run test1 "test1 - 57" "arg1: 0 arg2: (none) aBits: foo,baz" --bits foo,bar,baz,!bar 115 | 116 | run test1 "test1 - 58" "\ 117 | Usage: test1 [-I?] [-c|--cb2=STRING] [--arg1] [-2|--arg2=ARG] 118 | [-3|--arg3=ANARG] [-onedash] [--optional=STRING] [--val] 119 | [-i|--int=INT] [-s|--short=SHORT] [-l|--long=LONG] 120 | [-L|--longlong=LONGLONG] [-f|--float=FLOAT] [-d|--double=DOUBLE] 121 | [--randint=INT] [--randshort=SHORT] [--randlong=LONG] 122 | [--randlonglong=LONGLONG] [--argv=STRING] [--bitset] [--bitclr] 123 | [-x|--bitxor] [--nstr=STRING] [--lstr=STRING] [-I|--inc] 124 | [-c|--cb=STRING] [--longopt] [-?|--help] [--usage] [--simple=ARG]" --usage 125 | run test1 "test1 - 59" "\ 126 | Usage: test1 [OPTION...] 127 | --arg1 First argument with a really long 128 | description. After all, we have to test 129 | argument help wrapping somehow, right? 130 | -2, --arg2=ARG Another argument (default: \"(none)\") 131 | -3, --arg3=ANARG A third argument 132 | -onedash POPT_ARGFLAG_ONEDASH: Option takes a single - 133 | --optional[=STRING] POPT_ARGFLAG_OPTIONAL: Takes an optional 134 | string argument 135 | --val POPT_ARG_VAL: 125992 141421 136 | -i, --int=INT POPT_ARG_INT: 271828 (default: 271828) 137 | -s, --short=SHORT POPT_ARG_SHORT: 4523 (default: 4523) 138 | -l, --long=LONG POPT_ARG_LONG: 738905609 (default: 738905609) 139 | -L, --longlong=LONGLONG POPT_ARG_LONGLONG: 738905609 (default: 140 | 738905609) 141 | -f, --float=FLOAT POPT_ARG_FLOAT: 3.14159 (default: 3.14159) 142 | -d, --double=DOUBLE POPT_ARG_DOUBLE: 9.8696 (default: 9.8696) 143 | --randint=INT POPT_ARGFLAG_RANDOM: experimental 144 | --randshort=SHORT POPT_ARGFLAG_RANDOM: experimental 145 | --randlong=LONG POPT_ARGFLAG_RANDOM: experimental 146 | --randlonglong=LONGLONG POPT_ARGFLAG_RANDOM: experimental 147 | --argv STRING POPT_ARG_ARGV: append string to argv array 148 | (can be used multiple times) 149 | --[no]bitset POPT_BIT_SET: |= 0x7777 150 | --[no]bitclr POPT_BIT_CLR: &= ~0xf842 151 | -x, --bitxor POPT_ARGFLAG_XOR: ^= (0x8ace^0xfeed) 152 | --nstr=STRING POPT_ARG_STRING: (null) (default: null) 153 | --lstr=STRING POPT_ARG_STRING: \"123456789...\" (default: 154 | \"This tests default strings and exceeds the 155 | ... limit. 156 | 123456789+123456789+123456789+123456789+123456789+ 123456789+123456789+123456789+123456789+123456789+ 1234567...\") 157 | 158 | arg for cb2 159 | -c, --cb2=STRING Test argument callbacks 160 | -I, --inc An included argument 161 | 162 | Callback arguments 163 | -c, --cb=STRING Test argument callbacks 164 | --longopt Unused option for help testing 165 | 166 | Options implemented via popt alias/exec: 167 | --simple=ARG simple description 168 | 169 | Help options: 170 | -?, --help Show this help message 171 | --usage Display brief usage message" --help 172 | 173 | run test1 "test1 - 60" "" --val=foo 174 | run test1 "test1 - 61" "" -x=f1 175 | 176 | run test1 "test1 - 62" "arg1: 0 arg2: (none) aInt: 1" --randint=-1 177 | 178 | if ! [ -e test3-data ]; then 179 | # create symlink for running during 'make distcheck' 180 | ln -s "${srcdir}/test3-data" test3-data 181 | fi 182 | run_diff test3 "test3 - 1" test3-data/01.input test3-data/01.answer 183 | run_diff test3 "test3 - 2" test3-data/02.input test3-data/02.answer 184 | run_diff test3 "test3 - 3" test3-data/03.input test3-data/03.answer 185 | 186 | echo "" 187 | if [ $retval != 0 ]; then 188 | echo "Failed." 189 | exit $retval 190 | else 191 | echo "Passed." 192 | fi 193 | -------------------------------------------------------------------------------- /tests/test1.c: -------------------------------------------------------------------------------- 1 | /* (C) 1998-2002 Red Hat, Inc. -- Licensing details are in the COPYING 2 | file accompanying popt source distributions, available from 3 | http://ftp.rpm.org/popt/releases/. */ 4 | 5 | #include "system.h" 6 | 7 | static int pass2 = 0; 8 | static void option_callback(UNUSED(poptContext con), 9 | UNUSED(enum poptCallbackReason reason), 10 | const struct poptOption * opt, 11 | char * arg, void * data) 12 | { 13 | if (pass2) 14 | fprintf(stdout, "callback: %c %s %s ", opt->val, (char *) data, arg); 15 | } 16 | 17 | static int arg1 = 0; 18 | static const char * arg2 = "(none)"; 19 | static int arg3 = 0; 20 | static int inc = 0; 21 | static int shortopt = 0; 22 | 23 | static int aVal = 141421; 24 | static int bVal = 141421; 25 | static unsigned int aFlag = 0x8aceU; 26 | static unsigned int bFlag = 0x8aceU; 27 | 28 | static short aShort = (short)4523; 29 | static short bShort = (short)4523; 30 | static int aInt = 271828; 31 | static int bInt = 271828; 32 | static long aLong = 738905609L; 33 | static long bLong = 738905609L; 34 | static long long aLongLong = 738905609LL; 35 | static long long bLongLong = 738905609LL; 36 | static float aFloat = 3.1415926535f; 37 | static float bFloat = 3.1415926535f; 38 | static double aDouble = 9.86960440108935861883; 39 | static double bDouble = 9.86960440108935861883; 40 | 41 | static const char ** aArgv = NULL; 42 | static void * aBits = NULL; 43 | static const char *attributes[] = { 44 | "foo", "bar", "baz", "bing", "bang", "boom" 45 | }; 46 | static size_t nattributes = (sizeof(attributes) / sizeof(attributes[0])); 47 | 48 | static char * oStr = (char *) -1; 49 | static int singleDash = 0; 50 | 51 | static const char * lStr = 52 | "This tests default strings and exceeds the ... limit. " 53 | "123456789+123456789+123456789+123456789+123456789+ " 54 | "123456789+123456789+123456789+123456789+123456789+ " 55 | "123456789+123456789+123456789+123456789+123456789+ " 56 | "123456789+123456789+123456789+123456789+123456789+ "; 57 | static char * nStr = NULL; 58 | 59 | static struct poptOption moreCallbackArgs[] = { 60 | { NULL, '\0', POPT_ARG_CALLBACK|POPT_CBFLAG_INC_DATA, 61 | (void *)option_callback, 0, 62 | NULL, NULL }, 63 | { "cb2", 'c', POPT_ARG_STRING, NULL, (int)'c', 64 | "Test argument callbacks", NULL }, 65 | POPT_TABLEEND 66 | }; 67 | 68 | static struct poptOption callbackArgs[] = { 69 | { NULL, '\0', POPT_ARG_CALLBACK, (void *)option_callback, 0, 70 | "sampledata", NULL }, 71 | { "cb", 'c', POPT_ARG_STRING, NULL, (int)'c', 72 | "Test argument callbacks", NULL }, 73 | { "longopt", '\0', 0, NULL, (int)'l', 74 | "Unused option for help testing", NULL }, 75 | POPT_TABLEEND 76 | }; 77 | 78 | static struct poptOption moreArgs[] = { 79 | { "inc", 'I', 0, &inc, 0, "An included argument", NULL }, 80 | POPT_TABLEEND 81 | }; 82 | 83 | static struct poptOption options[] = { 84 | { NULL, '\0', POPT_ARG_INCLUDE_TABLE, &moreCallbackArgs, 0, 85 | "arg for cb2", NULL }, 86 | { "arg1", '\0', 0, &arg1, 0, "First argument with a really long" 87 | " description. After all, we have to test argument help" 88 | " wrapping somehow, right?", NULL }, 89 | { "arg2", '2', POPT_ARG_STRING | POPT_ARGFLAG_SHOW_DEFAULT, &arg2, 0, 90 | "Another argument", "ARG" }, 91 | { "arg3", '3', POPT_ARG_INT, &arg3, 0, 92 | "A third argument", "ANARG" }, 93 | { "onedash", '\0', POPT_ARGFLAG_ONEDASH, &shortopt, 0, 94 | "POPT_ARGFLAG_ONEDASH: Option takes a single -", NULL }, 95 | { "hidden", '\0', POPT_ARG_STRING | POPT_ARGFLAG_DOC_HIDDEN, NULL, 0, 96 | "POPT_ARGFLAG_HIDDEN: A hidden option (--help shouldn't display)", 97 | NULL }, 98 | { "optional", '\0', POPT_ARG_STRING | POPT_ARGFLAG_OPTIONAL, &oStr, 0, 99 | "POPT_ARGFLAG_OPTIONAL: Takes an optional string argument", NULL }, 100 | 101 | { "val", '\0', POPT_ARG_VAL | POPT_ARGFLAG_SHOW_DEFAULT, &aVal, 125992, 102 | "POPT_ARG_VAL: 125992 141421", 0}, 103 | 104 | { "int", 'i', POPT_ARG_INT | POPT_ARGFLAG_SHOW_DEFAULT, &aInt, 0, 105 | "POPT_ARG_INT: 271828", NULL }, 106 | { "short", 's', POPT_ARG_SHORT | POPT_ARGFLAG_SHOW_DEFAULT, &aShort, 0, 107 | "POPT_ARG_SHORT: 4523", NULL }, 108 | { "long", 'l', POPT_ARG_LONG | POPT_ARGFLAG_SHOW_DEFAULT, &aLong, 0, 109 | "POPT_ARG_LONG: 738905609", NULL }, 110 | { "longlong", 'L', POPT_ARG_LONGLONG | POPT_ARGFLAG_SHOW_DEFAULT, &aLongLong, 0, 111 | "POPT_ARG_LONGLONG: 738905609", NULL }, 112 | { "float", 'f', POPT_ARG_FLOAT | POPT_ARGFLAG_SHOW_DEFAULT, &aFloat, 0, 113 | "POPT_ARG_FLOAT: 3.14159", NULL }, 114 | { "double", 'd', POPT_ARG_DOUBLE | POPT_ARGFLAG_SHOW_DEFAULT, &aDouble, 0, 115 | "POPT_ARG_DOUBLE: 9.8696", NULL }, 116 | 117 | { "randint", '\0', POPT_ARG_INT|POPT_ARGFLAG_RANDOM, &aInt, 0, 118 | "POPT_ARGFLAG_RANDOM: experimental", NULL }, 119 | { "randshort", '\0', POPT_ARG_SHORT|POPT_ARGFLAG_RANDOM, &aShort, 0, 120 | "POPT_ARGFLAG_RANDOM: experimental", NULL }, 121 | { "randlong", '\0', POPT_ARG_LONG|POPT_ARGFLAG_RANDOM, &aLong, 0, 122 | "POPT_ARGFLAG_RANDOM: experimental", NULL }, 123 | { "randlonglong", '\0', POPT_ARG_LONGLONG|POPT_ARGFLAG_RANDOM, &aLongLong, 0, 124 | "POPT_ARGFLAG_RANDOM: experimental", NULL }, 125 | 126 | { "argv", '\0', POPT_ARG_ARGV, &aArgv, 0, 127 | "POPT_ARG_ARGV: append string to argv array (can be used multiple times)","STRING"}, 128 | { "bits", '\0', POPT_ARG_BITSET|POPT_ARGFLAG_DOC_HIDDEN, &aBits, 0, 129 | "POPT_ARG_BITSET: add string to bit set (can be used multiple times)","STRING"}, 130 | 131 | { "bitset", '\0', POPT_BIT_SET | POPT_ARGFLAG_TOGGLE | POPT_ARGFLAG_SHOW_DEFAULT, &aFlag, 0x7777, 132 | "POPT_BIT_SET: |= 0x7777", 0}, 133 | { "bitclr", '\0', POPT_BIT_CLR | POPT_ARGFLAG_TOGGLE | POPT_ARGFLAG_SHOW_DEFAULT, &aFlag, 0xf842, 134 | "POPT_BIT_CLR: &= ~0xf842", 0}, 135 | { "bitxor", 'x', POPT_ARG_VAL | POPT_ARGFLAG_XOR | POPT_ARGFLAG_SHOW_DEFAULT, &aFlag, (0x8ace^0xfeed), 136 | "POPT_ARGFLAG_XOR: ^= (0x8ace^0xfeed)", 0}, 137 | 138 | { "nstr", '\0', POPT_ARG_STRING | POPT_ARGFLAG_SHOW_DEFAULT, &nStr, 0, 139 | "POPT_ARG_STRING: (null)", NULL}, 140 | { "lstr", '\0', POPT_ARG_STRING | POPT_ARGFLAG_SHOW_DEFAULT, &lStr, 0, 141 | "POPT_ARG_STRING: \"123456789...\"", NULL}, 142 | 143 | { NULL, '-', POPT_ARG_NONE | POPT_ARGFLAG_DOC_HIDDEN, &singleDash, 0, 144 | NULL, NULL }, 145 | { NULL, '\0', POPT_ARG_INCLUDE_TABLE, &moreArgs, 0, 146 | NULL, NULL }, 147 | { NULL, '\0', POPT_ARG_INCLUDE_TABLE, &callbackArgs, 0, 148 | "Callback arguments", NULL }, 149 | POPT_AUTOALIAS 150 | POPT_AUTOHELP 151 | POPT_TABLEEND 152 | }; 153 | 154 | static void resetVars(void) 155 | { 156 | arg1 = 0; 157 | arg2 = "(none)"; 158 | arg3 = 0; 159 | inc = 0; 160 | shortopt = 0; 161 | 162 | aVal = bVal; 163 | aFlag = bFlag; 164 | 165 | aShort = bShort; 166 | aInt = bInt; 167 | aLong = bLong; 168 | aLongLong = bLongLong; 169 | aFloat = bFloat; 170 | aDouble = bDouble; 171 | 172 | if (aArgv) { 173 | int i; 174 | for (i = 0; aArgv[i] != NULL; i++) { 175 | free((void *)aArgv[i]); 176 | aArgv[i] = NULL; 177 | } 178 | free(aArgv); 179 | aArgv = NULL; 180 | } 181 | if (aBits) 182 | (void) poptBitsClr(aBits); 183 | 184 | oStr = (char *) -1; 185 | 186 | singleDash = 0; 187 | pass2 = 0; 188 | } 189 | 190 | int main(int argc, const char ** argv) 191 | { 192 | int rc; 193 | int ec = 0; 194 | poptContext optCon; 195 | const char ** rest; 196 | int help = 0; 197 | int usage = 0; 198 | 199 | #if defined(HAVE_MCHECK_H) && defined(HAVE_MTRACE) 200 | mtrace(); /* Trace malloc only if MALLOC_TRACE=mtrace-output-file. */ 201 | #endif 202 | 203 | resetVars(); 204 | optCon = poptGetContext("test1", argc, argv, options, 0); 205 | (void) poptReadConfigFile(optCon, "./test-poptrc"); 206 | (void) poptReadDefaultConfig(optCon, 1); 207 | 208 | poptSetExecPath(optCon, ".", 1); 209 | 210 | #if 1 211 | while ((rc = poptGetNextOpt(optCon)) > 0) /* Read all the options ... */ 212 | {} 213 | 214 | poptResetContext(optCon); /* ... and then start over. */ 215 | resetVars(); 216 | #endif 217 | 218 | pass2 = 1; 219 | if ((rc = poptGetNextOpt(optCon)) < -1) { 220 | fprintf(stderr, "test1: bad argument %s: %s\n", 221 | poptBadOption(optCon, POPT_BADOPTION_NOALIAS), 222 | poptStrerror(rc)); 223 | ec = 2; 224 | goto exit; 225 | } 226 | 227 | if (help) { 228 | poptPrintHelp(optCon, stdout, 0); 229 | goto exit; 230 | } 231 | if (usage) { 232 | poptPrintUsage(optCon, stdout, 0); 233 | goto exit; 234 | } 235 | 236 | fprintf(stdout, "arg1: %d arg2: %s", arg1, arg2); 237 | 238 | if (arg3) 239 | fprintf(stdout, " arg3: %d", arg3); 240 | if (inc) 241 | fprintf(stdout, " inc: %d", inc); 242 | if (shortopt) 243 | fprintf(stdout, " short: %d", shortopt); 244 | if (aVal != bVal) 245 | fprintf(stdout, " aVal: %d", aVal); 246 | if (aFlag != bFlag) 247 | fprintf(stdout, " aFlag: 0x%x", aFlag); 248 | if (aShort != bShort) 249 | fprintf(stdout, " aShort: %hd", aShort); 250 | if (aInt != bInt) 251 | fprintf(stdout, " aInt: %d", aInt); 252 | if (aLong != bLong) 253 | fprintf(stdout, " aLong: %ld", aLong); 254 | if (aLongLong != bLongLong) 255 | fprintf(stdout, " aLongLong: %lld", aLongLong); 256 | if (aFloat != bFloat) 257 | fprintf(stdout, " aFloat: %g", (double)aFloat); 258 | if (aDouble != bDouble) 259 | fprintf(stdout, " aDouble: %g", aDouble); 260 | if (aArgv != NULL) { 261 | const char **av = aArgv; 262 | const char * arg; 263 | fprintf(stdout, " aArgv:"); 264 | while ((arg = *av++) != NULL) 265 | fprintf(stdout, " %s", arg); 266 | } 267 | if (aBits) { 268 | const char * separator = " "; 269 | size_t i; 270 | fprintf(stdout, " aBits:"); 271 | for (i = 0; i < nattributes; i++) { 272 | if (!poptBitsChk(aBits, attributes[i])) 273 | continue; 274 | fprintf(stdout, "%s%s", separator, attributes[i]); 275 | separator = ","; 276 | } 277 | } 278 | if (oStr != (char *)-1) 279 | fprintf(stdout, " oStr: %s", (oStr ? oStr : "(none)")); 280 | if (singleDash) 281 | fprintf(stdout, " -"); 282 | 283 | if (poptPeekArg(optCon) != NULL) { 284 | rest = poptGetArgs(optCon); 285 | if (rest) { 286 | fprintf(stdout, " rest:"); 287 | while (*rest) { 288 | fprintf(stdout, " %s", *rest); 289 | rest++; 290 | } 291 | } 292 | } 293 | 294 | fprintf(stdout, "\n"); 295 | 296 | exit: 297 | optCon = poptFreeContext(optCon); 298 | #if defined(HAVE_MCHECK_H) && defined(HAVE_MTRACE) 299 | muntrace(); /* Trace malloc only if MALLOC_TRACE=mtrace-output-file. */ 300 | #endif 301 | return ec; 302 | } 303 | -------------------------------------------------------------------------------- /src/poptconfig.c: -------------------------------------------------------------------------------- 1 | /** \ingroup popt 2 | * @file 3 | */ 4 | 5 | /* (C) 1998-2002 Red Hat, Inc. -- Licensing details are in the COPYING 6 | file accompanying popt source distributions, available from 7 | http://ftp.rpm.org/popt/releases/. */ 8 | 9 | #include "system.h" 10 | #include "poptint.h" 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #if defined(HAVE_FNMATCH_H) 17 | #include 18 | 19 | #endif 20 | 21 | #if defined(HAVE_GLOB_H) 22 | #include 23 | 24 | #if !defined(HAVE_GLOB_PATTERN_P) 25 | /* Return nonzero if PATTERN contains any metacharacters. 26 | Metacharacters can be quoted with backslashes if QUOTE is nonzero. */ 27 | static int 28 | glob_pattern_p (const char * pattern, int quote) 29 | { 30 | const char * p; 31 | int open = 0; 32 | 33 | for (p = pattern; *p != '\0'; ++p) 34 | switch (*p) { 35 | case '?': 36 | case '*': 37 | return 1; 38 | break; 39 | case '\\': 40 | if (quote && p[1] != '\0') 41 | ++p; 42 | break; 43 | case '[': 44 | open = 1; 45 | break; 46 | case ']': 47 | if (open) 48 | return 1; 49 | break; 50 | } 51 | return 0; 52 | } 53 | #endif /* !defined(__GLIBC__) */ 54 | 55 | static int poptGlobFlags = 0; 56 | 57 | static int poptGlob_error(UNUSED(const char * epath), 58 | UNUSED(int eerrno)) 59 | { 60 | return 1; 61 | } 62 | #endif /* HAVE_GLOB_H */ 63 | 64 | /** 65 | * Return path(s) from a glob pattern. 66 | * @param con context 67 | * @param pattern glob pattern 68 | * @retval *acp no. of paths 69 | * @retval *avp array of paths 70 | * @return 0 on success 71 | */ 72 | static int poptGlob(UNUSED(poptContext con), const char * pattern, 73 | int * acp, const char *** avp) 74 | { 75 | const char * pat = pattern; 76 | int rc = 0; /* assume success */ 77 | 78 | #if defined(HAVE_GLOB_H) 79 | if (glob_pattern_p(pat, 0)) { 80 | glob_t _g, *pglob = &_g; 81 | 82 | if (!(rc = glob(pat, poptGlobFlags, poptGlob_error, pglob))) { 83 | if (acp) { 84 | *acp = (int) pglob->gl_pathc; 85 | pglob->gl_pathc = 0; 86 | } 87 | if (avp) { 88 | *avp = (const char **) pglob->gl_pathv; 89 | pglob->gl_pathv = NULL; 90 | } 91 | globfree(pglob); 92 | } else if (rc == GLOB_NOMATCH) { 93 | *avp = NULL; 94 | *acp = 0; 95 | rc = 0; 96 | } else 97 | rc = POPT_ERROR_ERRNO; 98 | } else 99 | #endif /* HAVE_GLOB_H */ 100 | { 101 | if (acp) 102 | *acp = 1; 103 | if (avp && (*avp = calloc((size_t)(1 + 1), sizeof (**avp))) != NULL) 104 | (*avp)[0] = xstrdup(pat); 105 | } 106 | 107 | return rc; 108 | } 109 | 110 | 111 | int poptSaneFile(const char * fn) 112 | { 113 | struct stat sb; 114 | 115 | if (fn == NULL || strstr(fn, ".rpmnew") || strstr(fn, ".rpmsave")) 116 | return 0; 117 | if (stat(fn, &sb) == -1) 118 | return 0; 119 | if (!S_ISREG(sb.st_mode)) 120 | return 0; 121 | if (sb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) 122 | return 0; 123 | return 1; 124 | } 125 | 126 | int poptReadFile(const char * fn, char ** bp, size_t * nbp, int flags) 127 | { 128 | int fdno; 129 | char * b = NULL; 130 | off_t nb = 0; 131 | char * s, * t, * se; 132 | int rc = POPT_ERROR_ERRNO; /* assume failure */ 133 | 134 | fdno = open(fn, O_RDONLY); 135 | if (fdno < 0) 136 | goto exit; 137 | 138 | if ((nb = lseek(fdno, 0, SEEK_END)) == (off_t)-1 139 | || (uintmax_t)nb >= SIZE_MAX 140 | || lseek(fdno, 0, SEEK_SET) == (off_t)-1 141 | || (b = calloc(sizeof(*b), (size_t)nb + 1)) == NULL 142 | || read(fdno, (char *)b, (size_t)nb) != (ssize_t)nb) 143 | { 144 | int oerrno = errno; 145 | (void) close(fdno); 146 | if (nb != (off_t)-1 && (uintmax_t)nb >= SIZE_MAX) 147 | errno = -EOVERFLOW; 148 | else 149 | errno = oerrno; 150 | goto exit; 151 | } 152 | if (close(fdno) == -1) 153 | goto exit; 154 | if (b == NULL) { 155 | rc = POPT_ERROR_MALLOC; 156 | goto exit; 157 | } 158 | rc = 0; 159 | 160 | /* Trim out escaped newlines. */ 161 | if (flags & POPT_READFILE_TRIMNEWLINES) 162 | { 163 | for (t = b, s = b, se = b + nb; *s && s < se; s++) { 164 | switch (*s) { 165 | case '\\': 166 | if (s[1] == '\n') { 167 | s++; 168 | continue; 169 | } 170 | /* fallthrough */ 171 | default: 172 | *t++ = *s; 173 | break; 174 | } 175 | } 176 | *t++ = '\0'; 177 | nb = (off_t)(t - b); 178 | } 179 | 180 | exit: 181 | if (rc != 0) { 182 | if (b) 183 | free(b); 184 | b = NULL; 185 | nb = 0; 186 | } 187 | if (bp) 188 | *bp = b; 189 | else if (b) 190 | free(b); 191 | if (nbp) 192 | *nbp = (size_t)nb; 193 | return rc; 194 | } 195 | 196 | /** 197 | * Check for application match. 198 | * @param con context 199 | * @param s config application name 200 | * return 0 if config application matches 201 | */ 202 | static int configAppMatch(poptContext con, const char * s) 203 | { 204 | int rc = 1; 205 | 206 | if (con->appName == NULL) /* XXX can't happen. */ 207 | return rc; 208 | 209 | #if defined(HAVE_GLOB_H) && defined(HAVE_FNMATCH_H) 210 | if (glob_pattern_p(s, 1)) { 211 | static int flags = FNM_PATHNAME | FNM_PERIOD; 212 | #ifdef FNM_EXTMATCH 213 | flags |= FNM_EXTMATCH; 214 | #endif 215 | rc = fnmatch(s, con->appName, flags); 216 | } else 217 | #endif 218 | rc = strcmp(s, con->appName); 219 | return rc; 220 | } 221 | 222 | static int poptConfigLine(poptContext con, char * line) 223 | { 224 | char *b = NULL; 225 | size_t nb = 0; 226 | char * se = line; 227 | const char * appName; 228 | const char * entryType; 229 | const char * opt; 230 | struct poptItem_s item_buf; 231 | poptItem item = &item_buf; 232 | int i, j; 233 | int rc = POPT_ERROR_BADCONFIG; 234 | 235 | if (con->appName == NULL) 236 | goto exit; 237 | 238 | memset(item, 0, sizeof(*item)); 239 | 240 | appName = se; 241 | while (*se != '\0' && !_isspaceptr(se)) se++; 242 | if (*se == '\0') 243 | goto exit; 244 | else 245 | *se++ = '\0'; 246 | 247 | if (configAppMatch(con, appName)) goto exit; 248 | 249 | while (*se != '\0' && _isspaceptr(se)) se++; 250 | entryType = se; 251 | while (*se != '\0' && !_isspaceptr(se)) se++; 252 | if (*se != '\0') *se++ = '\0'; 253 | 254 | while (*se != '\0' && _isspaceptr(se)) se++; 255 | if (*se == '\0') goto exit; 256 | opt = se; 257 | while (*se != '\0' && !_isspaceptr(se)) se++; 258 | if (opt[0] == '-' && *se == '\0') goto exit; 259 | if (*se != '\0') *se++ = '\0'; 260 | 261 | while (*se != '\0' && _isspaceptr(se)) se++; 262 | if (opt[0] == '-' && *se == '\0') goto exit; 263 | 264 | if (opt[0] == '-' && opt[1] == '-') 265 | item->option.longName = opt + 2; 266 | else if (opt[0] == '-' && opt[2] == '\0') 267 | item->option.shortName = opt[1]; 268 | else { 269 | const char * fn = opt; 270 | 271 | /* XXX handle globs and directories in fn? */ 272 | if ((rc = poptReadFile(fn, &b, &nb, POPT_READFILE_TRIMNEWLINES)) != 0) 273 | goto exit; 274 | if (b == NULL || nb == 0) 275 | goto exit; 276 | 277 | /* Append remaining text to the interpolated file option text. */ 278 | if (*se != '\0') { 279 | size_t nse = strlen(se) + 1; 280 | if ((b = realloc(b, (nb + nse))) == NULL) /* XXX can't happen */ 281 | goto exit; 282 | (void) stpcpy( stpcpy(&b[nb-1], " "), se); 283 | nb += nse; 284 | } 285 | se = b; 286 | 287 | /* Use the basename of the path as the long option name. */ 288 | { const char * longName = strrchr(fn, '/'); 289 | if (longName != NULL) 290 | longName++; 291 | else 292 | longName = fn; 293 | if (longName == NULL) /* XXX can't happen. */ 294 | goto exit; 295 | /* Single character basenames are treated as short options. */ 296 | if (longName[1] != '\0') 297 | item->option.longName = longName; 298 | else 299 | item->option.shortName = longName[0]; 300 | } 301 | } 302 | 303 | if (poptParseArgvString(se, &item->argc, &item->argv)) goto exit; 304 | 305 | item->option.argInfo = POPT_ARGFLAG_DOC_HIDDEN; 306 | for (i = 0, j = 0; i < item->argc; i++, j++) { 307 | const char * f; 308 | if (!strncmp(item->argv[i], "--POPTdesc=", sizeof("--POPTdesc=")-1)) { 309 | f = item->argv[i] + sizeof("--POPTdesc="); 310 | if (f[0] == '$' && f[1] == '"') f++; 311 | item->option.descrip = f; 312 | item->option.argInfo &= ~POPT_ARGFLAG_DOC_HIDDEN; 313 | j--; 314 | } else 315 | if (!strncmp(item->argv[i], "--POPTargs=", sizeof("--POPTargs=")-1)) { 316 | f = item->argv[i] + sizeof("--POPTargs="); 317 | if (f[0] == '$' && f[1] == '"') f++; 318 | item->option.argDescrip = f; 319 | item->option.argInfo &= ~POPT_ARGFLAG_DOC_HIDDEN; 320 | item->option.argInfo |= POPT_ARG_STRING; 321 | j--; 322 | } else 323 | if (j != i) 324 | item->argv[j] = item->argv[i]; 325 | } 326 | if (j != i) { 327 | item->argv[j] = NULL; 328 | item->argc = j; 329 | } 330 | 331 | if (!strcmp(entryType, "alias")) 332 | rc = poptAddItem(con, item, 0); 333 | else if (!strcmp(entryType, "exec")) 334 | rc = poptAddItem(con, item, 1); 335 | exit: 336 | rc = 0; /* XXX for now, always return success */ 337 | if (b) 338 | free(b); 339 | return rc; 340 | } 341 | 342 | int poptReadConfigFile(poptContext con, const char * fn) 343 | { 344 | char * b = NULL, *be; 345 | size_t nb = 0; 346 | const char *se; 347 | char *t = NULL, *te; 348 | int rc; 349 | 350 | if ((rc = poptReadFile(fn, &b, &nb, POPT_READFILE_TRIMNEWLINES)) != 0) 351 | return (errno == ENOENT ? 0 : rc); 352 | if (b == NULL || nb == 0) { 353 | rc = POPT_ERROR_BADCONFIG; 354 | goto exit; 355 | } 356 | 357 | if ((t = malloc(nb + 1)) == NULL) 358 | goto exit; 359 | te = t; 360 | 361 | be = (b + nb); 362 | for (se = b; se < be; se++) { 363 | switch (*se) { 364 | case '\n': 365 | *te = '\0'; 366 | te = t; 367 | while (*te && _isspaceptr(te)) te++; 368 | if (*te && *te != '#') 369 | if ((rc = poptConfigLine(con, te)) != 0) 370 | goto exit; 371 | break; 372 | case '\\': 373 | *te = *se++; 374 | /* \ at the end of a line does not insert a \n */ 375 | if (se < be && *se != '\n') { 376 | te++; 377 | *te++ = *se; 378 | } 379 | break; 380 | default: 381 | *te++ = *se; 382 | break; 383 | } 384 | } 385 | rc = 0; 386 | 387 | exit: 388 | free(t); 389 | if (b) 390 | free(b); 391 | return rc; 392 | } 393 | 394 | int poptReadConfigFiles(poptContext con, const char * paths) 395 | { 396 | char * buf = (paths ? xstrdup(paths) : NULL); 397 | const char * p; 398 | char * pe; 399 | int rc = 0; /* assume success */ 400 | 401 | for (p = buf; p != NULL && *p != '\0'; p = pe) { 402 | const char ** av = NULL; 403 | int ac = 0; 404 | int i; 405 | int xx; 406 | 407 | /* locate start of next path element */ 408 | pe = strchr(p, ':'); 409 | if (pe != NULL && *pe == ':') 410 | *pe++ = '\0'; 411 | else 412 | pe = (char *) (p + strlen(p)); 413 | 414 | xx = poptGlob(con, p, &ac, &av); 415 | 416 | /* work-off each resulting file from the path element */ 417 | for (i = 0; i < ac; i++) { 418 | const char * fn = av[i]; 419 | if (!poptSaneFile(fn)) 420 | continue; 421 | xx = poptReadConfigFile(con, fn); 422 | if (xx && rc == 0) 423 | rc = xx; 424 | free((void *)av[i]); 425 | av[i] = NULL; 426 | } 427 | free(av); 428 | av = NULL; 429 | } 430 | 431 | if (buf) 432 | free(buf); 433 | 434 | return rc; 435 | } 436 | 437 | int poptReadDefaultConfig(poptContext con, UNUSED(int useEnv)) 438 | { 439 | char * home; 440 | struct stat sb; 441 | int rc = 0; /* assume success */ 442 | 443 | if (con->appName == NULL) goto exit; 444 | 445 | rc = poptReadConfigFile(con, POPT_SYSCONFDIR "/popt"); 446 | if (rc) goto exit; 447 | 448 | #if defined(HAVE_GLOB_H) 449 | if (!stat(POPT_SYSCONFDIR "/popt.d", &sb) && S_ISDIR(sb.st_mode)) { 450 | const char ** av = NULL; 451 | int ac = 0; 452 | int i; 453 | 454 | if ((rc = poptGlob(con, POPT_SYSCONFDIR "/popt.d/*", &ac, &av)) == 0) { 455 | for (i = 0; rc == 0 && i < ac; i++) { 456 | const char * fn = av[i]; 457 | if (!poptSaneFile(fn)) 458 | continue; 459 | rc = poptReadConfigFile(con, fn); 460 | free((void *)av[i]); 461 | av[i] = NULL; 462 | } 463 | free(av); 464 | av = NULL; 465 | } 466 | } 467 | if (rc) goto exit; 468 | #endif 469 | 470 | if ((home = getenv("HOME"))) { 471 | char * fn = malloc(strlen(home) + 20); 472 | if (fn != NULL) { 473 | (void) stpcpy(stpcpy(fn, home), "/.popt"); 474 | rc = poptReadConfigFile(con, fn); 475 | free(fn); 476 | } else 477 | rc = POPT_ERROR_ERRNO; 478 | if (rc) goto exit; 479 | } 480 | 481 | exit: 482 | return rc; 483 | } 484 | 485 | poptContext 486 | poptFini(poptContext con) 487 | { 488 | return poptFreeContext(con); 489 | } 490 | 491 | poptContext 492 | poptInit(int argc, const char ** argv, 493 | const struct poptOption * options, const char * configPaths) 494 | { 495 | poptContext con = NULL; 496 | const char * argv0; 497 | 498 | if (argv == NULL || argv[0] == NULL || options == NULL) 499 | return con; 500 | 501 | if ((argv0 = strrchr(argv[0], '/')) != NULL) argv0++; 502 | else argv0 = argv[0]; 503 | 504 | con = poptGetContext(argv0, argc, (const char **)argv, options, 0); 505 | if (con != NULL&& poptReadConfigFiles(con, configPaths)) 506 | con = poptFini(con); 507 | 508 | return con; 509 | } 510 | -------------------------------------------------------------------------------- /src/popt.h: -------------------------------------------------------------------------------- 1 | /** @file 2 | */ 3 | 4 | /* (C) 1998-2000 Red Hat, Inc. -- Licensing details are in the COPYING 5 | file accompanying popt source distributions, available from 6 | http://ftp.rpm.org/popt/releases/. */ 7 | 8 | #ifndef H_POPT 9 | #define H_POPT 10 | 11 | #include /* for FILE * */ 12 | 13 | /** 14 | * \name Arg type identifiers 15 | */ 16 | #define POPT_ARG_NONE 0U /*!< no arg */ 17 | #define POPT_ARG_STRING 1U /*!< arg will be saved as string */ 18 | #define POPT_ARG_INT 2U /*!< arg ==> int */ 19 | #define POPT_ARG_LONG 3U /*!< arg ==> long */ 20 | #define POPT_ARG_INCLUDE_TABLE 4U /*!< arg points to table */ 21 | #define POPT_ARG_CALLBACK 5U /*!< table-wide callback... must be 22 | set first in table; arg points 23 | to callback, descrip points to 24 | callback data to pass */ 25 | #define POPT_ARG_INTL_DOMAIN 6U /*!< set the translation domain 26 | for this table and any 27 | included tables; arg points 28 | to the domain string */ 29 | #define POPT_ARG_VAL 7U /*!< arg should take value val */ 30 | #define POPT_ARG_FLOAT 8U /*!< arg ==> float */ 31 | #define POPT_ARG_DOUBLE 9U /*!< arg ==> double */ 32 | #define POPT_ARG_LONGLONG 10U /*!< arg ==> long long */ 33 | 34 | #define POPT_ARG_MAINCALL (16U+11U) /*!< EXPERIMENTAL: return (*arg) (argc, argv) */ 35 | #define POPT_ARG_ARGV 12U /*!< dupe'd arg appended to realloc'd argv array. */ 36 | #define POPT_ARG_SHORT 13U /*!< arg ==> short */ 37 | #define POPT_ARG_BITSET (16U+14U) /*!< arg ==> bit set */ 38 | 39 | #define POPT_ARG_MASK 0x000000FFU /*!< option type mask */ 40 | #define POPT_GROUP_MASK 0x0000FF00U /*!< option group mask */ 41 | 42 | /** 43 | * \name Arg modifiers 44 | */ 45 | #define POPT_ARGFLAG_ONEDASH 0x80000000U /*!< allow -longoption */ 46 | #define POPT_ARGFLAG_DOC_HIDDEN 0x40000000U /*!< don't show in help/usage */ 47 | #define POPT_ARGFLAG_STRIP 0x20000000U /*!< strip this arg from argv(only applies to long args) */ 48 | #define POPT_ARGFLAG_OPTIONAL 0x10000000U /*!< arg may be missing */ 49 | 50 | #define POPT_ARGFLAG_OR 0x08000000U /*!< arg will be or'ed */ 51 | #define POPT_ARGFLAG_NOR 0x09000000U /*!< arg will be nor'ed */ 52 | #define POPT_ARGFLAG_AND 0x04000000U /*!< arg will be and'ed */ 53 | #define POPT_ARGFLAG_NAND 0x05000000U /*!< arg will be nand'ed */ 54 | #define POPT_ARGFLAG_XOR 0x02000000U /*!< arg will be xor'ed */ 55 | #define POPT_ARGFLAG_NOT 0x01000000U /*!< arg will be negated */ 56 | #define POPT_ARGFLAG_LOGICALOPS \ 57 | (POPT_ARGFLAG_OR|POPT_ARGFLAG_AND|POPT_ARGFLAG_XOR) /*!< arg has a logical op */ 58 | 59 | #define POPT_BIT_SET (POPT_ARG_VAL|POPT_ARGFLAG_OR) 60 | /*!< set arg bit(s) */ 61 | #define POPT_BIT_CLR (POPT_ARG_VAL|POPT_ARGFLAG_NAND) 62 | /*!< clear arg bit(s) */ 63 | 64 | #define POPT_ARGFLAG_SHOW_DEFAULT 0x00800000U /*!< show default value in --help */ 65 | #define POPT_ARGFLAG_RANDOM 0x00400000U /*!< random value in [1,arg] */ 66 | #define POPT_ARGFLAG_TOGGLE 0x00200000U /*!< permit --[no]opt prefix toggle */ 67 | 68 | /** 69 | * \name Callback modifiers 70 | */ 71 | #define POPT_CBFLAG_PRE 0x80000000U /*!< call the callback before parse */ 72 | #define POPT_CBFLAG_POST 0x40000000U /*!< call the callback after parse */ 73 | #define POPT_CBFLAG_INC_DATA 0x20000000U /*!< use data from the include line, 74 | not the subtable */ 75 | #define POPT_CBFLAG_SKIPOPTION 0x10000000U /*!< don't callback with option */ 76 | #define POPT_CBFLAG_CONTINUE 0x08000000U /*!< continue callbacks with option */ 77 | 78 | /** 79 | * \name Error return values 80 | */ 81 | #define POPT_ERROR_NOARG -10 /*!< missing argument */ 82 | #define POPT_ERROR_BADOPT -11 /*!< unknown option */ 83 | #define POPT_ERROR_UNWANTEDARG -12 /*!< option does not take an argument */ 84 | #define POPT_ERROR_OPTSTOODEEP -13 /*!< aliases nested too deeply */ 85 | #define POPT_ERROR_BADQUOTE -15 /*!< error in parameter quoting */ 86 | #define POPT_ERROR_ERRNO -16 /*!< errno set, use strerror(errno) */ 87 | #define POPT_ERROR_BADNUMBER -17 /*!< invalid numeric value */ 88 | #define POPT_ERROR_OVERFLOW -18 /*!< number too large or too small */ 89 | #define POPT_ERROR_BADOPERATION -19 /*!< mutually exclusive logical operations requested */ 90 | #define POPT_ERROR_NULLARG -20 /*!< opt->arg should not be NULL */ 91 | #define POPT_ERROR_MALLOC -21 /*!< memory allocation failed */ 92 | #define POPT_ERROR_BADCONFIG -22 /*!< config file failed sanity test */ 93 | 94 | /** 95 | * \name poptBadOption() flags 96 | */ 97 | #define POPT_BADOPTION_NOALIAS (1U << 0) /*!< don't go into an alias */ 98 | 99 | /** 100 | * \name poptGetContext() flags 101 | */ 102 | #define POPT_CONTEXT_NO_EXEC (1U << 0) /*!< ignore exec expansions */ 103 | #define POPT_CONTEXT_KEEP_FIRST (1U << 1) /*!< pay attention to argv[0] */ 104 | #define POPT_CONTEXT_POSIXMEHARDER (1U << 2) /*!< options can't follow args */ 105 | #define POPT_CONTEXT_ARG_OPTS (1U << 4) /*!< return args as options with value 0 */ 106 | 107 | /** 108 | * Defines a single option that may passed to the program. 109 | */ 110 | struct poptOption { 111 | const char * longName; /*!< may be NULL */ 112 | char shortName; /*!< may be '\0' */ 113 | unsigned int argInfo; /*!< type of argument expected after the option */ 114 | void * arg; /*!< depends on argInfo */ 115 | int val; /*!< 0 means don't return, just update arg */ 116 | const char * descrip; /*!< description for autohelp -- may be NULL */ 117 | const char * argDescrip; /*!< argument description for autohelp -- may be NULL */ 118 | }; 119 | 120 | /** 121 | * A popt alias argument for poptAddAlias(). 122 | */ 123 | struct poptAlias { 124 | const char * longName; /*!< may be NULL */ 125 | char shortName; /*!< may be NUL */ 126 | int argc; /*!< argument count */ 127 | const char ** argv; /*!< must be free()able */ 128 | }; 129 | 130 | /** 131 | * A popt alias or exec argument for poptAddItem(). 132 | */ 133 | typedef struct poptItem_s { 134 | struct poptOption option; /*!< alias/exec name(s) and description. */ 135 | int argc; /*!< (alias) no. of args. */ 136 | const char ** argv; /*!< (alias) args, must be free()able. */ 137 | } * poptItem; 138 | 139 | /** 140 | * \name Auto-generated help/usage 141 | */ 142 | 143 | /** 144 | * Empty table marker to enable displaying popt alias/exec options. 145 | */ 146 | extern struct poptOption poptAliasOptions[]; 147 | /** 148 | * Include in your options table for automatic alias/exec option listing 149 | */ 150 | #define POPT_AUTOALIAS { NULL, '\0', POPT_ARG_INCLUDE_TABLE, poptAliasOptions, \ 151 | 0, "Options implemented via popt alias/exec:", NULL }, 152 | 153 | /** 154 | * Auto help table options. 155 | */ 156 | extern struct poptOption poptHelpOptions[]; 157 | 158 | /** 159 | * Localized popt options 160 | */ 161 | extern struct poptOption * poptHelpOptionsI18N; 162 | 163 | /** 164 | * Include in your options table for automatic help option listing 165 | */ 166 | #define POPT_AUTOHELP { NULL, '\0', POPT_ARG_INCLUDE_TABLE, poptHelpOptions, \ 167 | 0, "Help options:", NULL }, 168 | /** 169 | * Include in your options table as the last element 170 | */ 171 | #define POPT_TABLEEND { NULL, '\0', 0, NULL, 0, NULL, NULL } 172 | 173 | /** 174 | * The main popt context type 175 | */ 176 | typedef struct poptContext_s * poptContext; 177 | 178 | /** 179 | * The main popt option type 180 | */ 181 | #ifndef __cplusplus 182 | typedef struct poptOption * poptOption; 183 | #endif 184 | 185 | /** 186 | * Callback reason values 187 | */ 188 | enum poptCallbackReason { 189 | POPT_CALLBACK_REASON_PRE = 0, 190 | POPT_CALLBACK_REASON_POST = 1, 191 | POPT_CALLBACK_REASON_OPTION = 2 192 | }; 193 | 194 | #ifdef __cplusplus 195 | extern "C" { 196 | #endif 197 | 198 | /** 199 | * Table callback prototype. 200 | * @param con context 201 | * @param reason reason for callback 202 | * @param opt option that triggered callback 203 | * @param arg @todo Document. 204 | * @param data @todo Document. 205 | */ 206 | typedef void (*poptCallbackType) (poptContext con, 207 | enum poptCallbackReason reason, 208 | const struct poptOption * opt, 209 | const char * arg, 210 | const void * data); 211 | 212 | /** 213 | * Destroy context. 214 | * @param con context 215 | * @return NULL always 216 | */ 217 | poptContext poptFreeContext( poptContext con); 218 | 219 | /** 220 | * Initialize popt context. 221 | * @param name context name (usually argv[0] program name) 222 | * @param argc no. of arguments 223 | * @param argv argument array 224 | * @param options address of popt option table 225 | * @param flags or'd POPT_CONTEXT_* bits 226 | * @return initialized popt context 227 | */ 228 | poptContext poptGetContext( 229 | const char * name, 230 | int argc, const char ** argv, 231 | const struct poptOption * options, 232 | unsigned int flags); 233 | 234 | /** 235 | * Destroy context (alternative implementation). 236 | * @param con context 237 | * @return NULL always 238 | */ 239 | poptContext poptFini( poptContext con); 240 | 241 | /** 242 | * Initialize popt context (alternative implementation). 243 | * This routine does poptGetContext() and then poptReadConfigFiles(). 244 | * @param argc no. of arguments 245 | * @param argv argument array 246 | * @param options address of popt option table 247 | * @param configPaths colon separated file path(s) to read. 248 | * @return initialized popt context (NULL on error). 249 | */ 250 | poptContext poptInit(int argc, const char ** argv, 251 | const struct poptOption * options, 252 | const char * configPaths); 253 | 254 | /** 255 | * Reinitialize popt context. 256 | * @param con context 257 | */ 258 | void poptResetContext(poptContext con); 259 | 260 | /** 261 | * Return value of next option found. 262 | * @param con context 263 | * @return next option val, -1 on last item, POPT_ERROR_* on error 264 | */ 265 | int poptGetNextOpt(poptContext con); 266 | 267 | /** 268 | * Return next option argument (if any). 269 | * @param con context 270 | * @return option argument, NULL if no argument is available 271 | */ 272 | char * poptGetOptArg(poptContext con); 273 | 274 | /** 275 | * Return next argument. 276 | * @param con context 277 | * @return next argument, NULL if no argument is available 278 | */ 279 | const char * poptGetArg(poptContext con); 280 | 281 | /** 282 | * Peek at current argument. 283 | * @param con context 284 | * @return current argument, NULL if no argument is available 285 | */ 286 | const char * poptPeekArg(poptContext con); 287 | 288 | /** 289 | * Return remaining arguments. 290 | * @param con context 291 | * @return argument array, NULL terminated 292 | */ 293 | const char ** poptGetArgs(poptContext con); 294 | 295 | /** 296 | * Return the option which caused the most recent error. 297 | * @param con context 298 | * @param flags 299 | * @return offending option 300 | */ 301 | const char * poptBadOption(poptContext con, unsigned int flags); 302 | 303 | /** 304 | * Add arguments to context. 305 | * @param con context 306 | * @param argv argument array, NULL terminated 307 | * @return 0 on success, POPT_ERROR_OPTSTOODEEP on failure 308 | */ 309 | int poptStuffArgs(poptContext con, const char ** argv); 310 | 311 | /** 312 | * Add alias to context. 313 | * @todo Pass alias by reference, not value. 314 | * @deprecated Use poptAddItem instead. 315 | * @param con context 316 | * @param alias alias to add 317 | * @param flags (unused) 318 | * @return 0 on success 319 | */ 320 | int poptAddAlias(poptContext con, struct poptAlias alias, int flags); 321 | 322 | /** 323 | * Add alias/exec item to context. 324 | * @param con context 325 | * @param newItem alias/exec item to add 326 | * @param flags 0 for alias, 1 for exec 327 | * @return 0 on success 328 | */ 329 | int poptAddItem(poptContext con, poptItem newItem, int flags); 330 | 331 | /** 332 | * Test path/file for config file sanity (regular file, permissions etc) 333 | * @param fn file name 334 | * @return 1 on OK, 0 on NOTOK. 335 | */ 336 | int poptSaneFile(const char * fn); 337 | 338 | /** 339 | * Read a file into a buffer. 340 | * @param fn file name 341 | * @param[out] *bp buffer (malloc'd) (or NULL) 342 | * @param[out] *nbp no. of bytes in buffer (including final NUL) (or NULL) 343 | * @param flags 1 to trim escaped newlines 344 | * return 0 on success 345 | */ 346 | int poptReadFile(const char * fn, char ** bp, 347 | size_t * nbp, int flags); 348 | #define POPT_READFILE_TRIMNEWLINES 1 /*!< trim new lines on read? */ 349 | 350 | /** 351 | * Read configuration file. 352 | * @param con context 353 | * @param fn file name to read 354 | * @return 0 on success, POPT_ERROR_ERRNO on failure 355 | */ 356 | int poptReadConfigFile(poptContext con, const char * fn); 357 | 358 | /** 359 | * Read configuration file(s). 360 | * Colon separated files to read, looping over poptReadConfigFile(). 361 | * Note that an '@' character preceding a path in the list will 362 | * also perform additional sanity checks on the file before reading. 363 | * @param con context 364 | * @param paths colon separated file name(s) to read 365 | * @return 0 on success, POPT_ERROR_BADCONFIG on failure 366 | */ 367 | int poptReadConfigFiles(poptContext con, const char * paths); 368 | 369 | /** 370 | * Read default configuration from /etc/popt and $HOME/.popt. 371 | * @param con context 372 | * @param useEnv (unused) 373 | * @return 0 on success, POPT_ERROR_ERRNO on failure 374 | */ 375 | int poptReadDefaultConfig(poptContext con, int useEnv); 376 | 377 | /** 378 | * Duplicate an argument array. 379 | * @note: The argument array is malloc'd as a single area, so only argv must 380 | * be free'd. 381 | * 382 | * @param argc no. of arguments 383 | * @param argv argument array 384 | * @param[out] argcPtr address of returned no. of arguments 385 | * @param[out] argvPtr address of returned argument array 386 | * @return 0 on success, POPT_ERROR_NOARG on failure 387 | */ 388 | int poptDupArgv(int argc, const char **argv, 389 | int * argcPtr, 390 | const char *** argvPtr); 391 | 392 | /** 393 | * Parse a string into an argument array. 394 | * The parse allows ', ", and \ quoting, but ' is treated the same as " and 395 | * both may include \ quotes. 396 | * @note: The argument array is malloc'd as a single area, so only argv must 397 | * be free'd. 398 | * 399 | * @param s string to parse 400 | * @param[out] argcPtr address of returned no. of arguments 401 | * @param[out] argvPtr address of returned argument array 402 | */ 403 | int poptParseArgvString(const char * s, 404 | int * argcPtr, const char *** argvPtr); 405 | 406 | /** 407 | * Parses an input configuration file and returns an string that is a 408 | * command line. For use with popt. You must free the return value when done. 409 | * 410 | * Given the file: 411 | \verbatim 412 | # this line is ignored 413 | # this one too 414 | aaa 415 | bbb 416 | ccc 417 | bla=bla 418 | 419 | this_is = fdsafdas 420 | bad_line= 421 | really bad line 422 | really bad line = again 423 | 5555= 55555 424 | test = with lots of spaces 425 | \endverbatim 426 | * 427 | * The result is: 428 | \verbatim 429 | --aaa --bbb --ccc --bla="bla" --this_is="fdsafdas" --5555="55555" --test="with lots of spaces" 430 | \endverbatim 431 | * 432 | * Passing this to poptParseArgvString() yields an argv of: 433 | \verbatim 434 | '--aaa' 435 | '--bbb' 436 | '--ccc' 437 | '--bla=bla' 438 | '--this_is=fdsafdas' 439 | '--5555=55555' 440 | '--test=with lots of spaces' 441 | \endverbatim 442 | * 443 | * @bug NULL is returned if file line is too long. 444 | * @bug Silently ignores invalid lines. 445 | * 446 | * @param fp file handle to read 447 | * @param *argstrp return string of options (malloc'd) 448 | * @param flags unused 449 | * @return 0 on success 450 | * @see poptParseArgvString 451 | */ 452 | int poptConfigFileToString(FILE *fp, char ** argstrp, int flags); 453 | 454 | /** 455 | * Return formatted error string for popt failure. 456 | * @param error popt error 457 | * @return error string 458 | */ 459 | const char * poptStrerror(int error); 460 | 461 | /** 462 | * Limit search for executables. 463 | * @param con context 464 | * @param path single path to search for executables 465 | * @param allowAbsolute absolute paths only? 466 | */ 467 | void poptSetExecPath(poptContext con, const char * path, int allowAbsolute); 468 | 469 | /** 470 | * Print detailed description of options. 471 | * @param con context 472 | * @param fp output file handle 473 | * @param flags (unused) 474 | */ 475 | void poptPrintHelp(poptContext con, FILE * fp, int flags); 476 | 477 | /** 478 | * Print terse description of options. 479 | * @param con context 480 | * @param fp output file handle 481 | * @param flags (unused) 482 | */ 483 | void poptPrintUsage(poptContext con, FILE * fp, int flags); 484 | 485 | /** 486 | * Provide text to replace default "[OPTION...]" in help/usage output. 487 | * @param con context 488 | * @param text replacement text 489 | */ 490 | void poptSetOtherOptionHelp(poptContext con, const char * text); 491 | 492 | /** 493 | * Return argv[0] from context. 494 | * @param con context 495 | * @return argv[0] 496 | */ 497 | const char * poptGetInvocationName(poptContext con); 498 | 499 | /** 500 | * Shuffle argv pointers to remove stripped args, returns new argc. 501 | * @param con context 502 | * @param argc no. of args 503 | * @param argv arg vector 504 | * @return new argc 505 | */ 506 | int poptStrippedArgv(poptContext con, int argc, char ** argv); 507 | 508 | /** 509 | * Add a string to an argv array. 510 | * @param[out] *argvp argv array 511 | * @param argInfo (unused) 512 | * @param val string arg to add (using strdup) 513 | * @return 0 on success, POPT_ERROR_NULLARG/POPT_ERROR_BADOPERATION 514 | */ 515 | int poptSaveString(const char *** argvp, unsigned int argInfo, 516 | const char * val); 517 | 518 | /** 519 | * Save a long long, performing logical operation with value. 520 | * @warning Alignment check may be too strict on certain platorms. 521 | * @param arg integer pointer, aligned on int boundary. 522 | * @param argInfo logical operation (see POPT_ARGFLAG_*) 523 | * @param aLongLong value to use 524 | * @return 0 on success, POPT_ERROR_NULLARG/POPT_ERROR_BADOPERATION 525 | */ 526 | int poptSaveLongLong(long long * arg, unsigned int argInfo, 527 | long long aLongLong); 528 | 529 | /** 530 | * Save a long, performing logical operation with value. 531 | * @warning Alignment check may be too strict on certain platorms. 532 | * @param arg integer pointer, aligned on int boundary. 533 | * @param argInfo logical operation (see POPT_ARGFLAG_*) 534 | * @param aLong value to use 535 | * @return 0 on success, POPT_ERROR_NULLARG/POPT_ERROR_BADOPERATION 536 | */ 537 | int poptSaveLong(long * arg, unsigned int argInfo, long aLong); 538 | 539 | /** 540 | * Save a short integer, performing logical operation with value. 541 | * @warning Alignment check may be too strict on certain platorms. 542 | * @param arg short pointer, aligned on short boundary. 543 | * @param argInfo logical operation (see POPT_ARGFLAG_*) 544 | * @param aLong value to use 545 | * @return 0 on success, POPT_ERROR_NULLARG/POPT_ERROR_BADOPERATION 546 | */ 547 | int poptSaveShort(short * arg, unsigned int argInfo, long aLong); 548 | 549 | /** 550 | * Save an integer, performing logical operation with value. 551 | * @warning Alignment check may be too strict on certain platorms. 552 | * @param arg integer pointer, aligned on int boundary. 553 | * @param argInfo logical operation (see POPT_ARGFLAG_*) 554 | * @param aLong value to use 555 | * @return 0 on success, POPT_ERROR_NULLARG/POPT_ERROR_BADOPERATION 556 | */ 557 | int poptSaveInt(int * arg, unsigned int argInfo, long aLong); 558 | 559 | /** 560 | * The bit set typedef. 561 | */ 562 | typedef struct poptBits_s { 563 | unsigned int bits[1]; /*!< internal */ 564 | } * poptBits; 565 | 566 | #define _POPT_BITS_N 1024U /*!< estimated population */ 567 | #define _POPT_BITS_M ((3U * _POPT_BITS_N) / 2U) /*!< internal */ 568 | #define _POPT_BITS_K 16U /*!< no. of linear hash combinations */ 569 | 570 | extern unsigned int _poptBitsN; /*!< internal */ 571 | extern unsigned int _poptBitsM; /*!< internal */ 572 | extern unsigned int _poptBitsK; /*!< internal */ 573 | 574 | /** 575 | * Add bits 576 | */ 577 | int poptBitsAdd(poptBits bits, const char * s); 578 | 579 | /** 580 | * Test bits 581 | */ 582 | int poptBitsChk(poptBits bits, const char * s); 583 | 584 | /** 585 | * Clear bitfield 586 | */ 587 | int poptBitsClr(poptBits bits); 588 | 589 | /** 590 | * Delete bits 591 | */ 592 | int poptBitsDel(poptBits bits, const char * s); 593 | 594 | /** 595 | * Test for bit intersection 596 | */ 597 | int poptBitsIntersect(poptBits * ap, const poptBits b); 598 | 599 | /** 600 | * Test for bit union 601 | */ 602 | int poptBitsUnion(poptBits * ap, const poptBits b); 603 | 604 | /** 605 | * Args 606 | */ 607 | int poptBitsArgs(poptContext con, poptBits * ap); 608 | 609 | /** 610 | * Save a string into a bit set (experimental). 611 | * @param[out] bitsp bit set (lazily malloc'd if NULL) 612 | * @param argInfo logical operation (see POPT_ARGFLAG_*) 613 | * @param s string to add to bit set 614 | * @return 0 on success, POPT_ERROR_NULLARG/POPT_ERROR_BADOPERATION 615 | */ 616 | int poptSaveBits(poptBits * bitsp, unsigned int argInfo, 617 | const char * s); 618 | 619 | 620 | #ifdef __cplusplus 621 | } 622 | #endif 623 | 624 | #endif 625 | -------------------------------------------------------------------------------- /src/popthelp.c: -------------------------------------------------------------------------------- 1 | /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */ 2 | 3 | /** \ingroup popt 4 | * @file 5 | */ 6 | 7 | /* (C) 1998-2002 Red Hat, Inc. -- Licensing details are in the COPYING 8 | file accompanying popt source distributions, available from 9 | http://ftp.rpm.org/popt/releases/. */ 10 | 11 | #include "system.h" 12 | 13 | #define POPT_USE_TIOCGWINSZ 14 | #ifdef POPT_USE_TIOCGWINSZ 15 | #include 16 | #endif 17 | 18 | #ifdef HAVE_MBSRTOWCS 19 | #include /* for mbsrtowcs */ 20 | #endif 21 | #include "poptint.h" 22 | 23 | 24 | /** 25 | * Display arguments. 26 | * @param con context 27 | * @param foo (unused) 28 | * @param key option(s) 29 | * @param arg (unused) 30 | * @param data (unused) 31 | */ 32 | NORETURN 33 | static void displayArgs(poptContext con, 34 | UNUSED(enum poptCallbackReason foo), 35 | struct poptOption * key, 36 | UNUSED(const char * arg), 37 | UNUSED(void * data)) 38 | { 39 | if (key->shortName == '?') 40 | poptPrintHelp(con, stdout, 0); 41 | else 42 | poptPrintUsage(con, stdout, 0); 43 | 44 | poptFreeContext(con); 45 | exit(0); 46 | } 47 | 48 | #ifdef NOTYET 49 | static int show_option_defaults = 0; 50 | #endif 51 | 52 | /** 53 | * Empty table marker to enable displaying popt alias/exec options. 54 | */ 55 | struct poptOption poptAliasOptions[] = { 56 | POPT_TABLEEND 57 | }; 58 | 59 | /** 60 | * Auto help table options. 61 | */ 62 | struct poptOption poptHelpOptions[] = { 63 | { NULL, '\0', POPT_ARG_CALLBACK, (void *)displayArgs, 0, NULL, NULL }, 64 | { "help", '?', 0, NULL, (int)'?', N_("Show this help message"), NULL }, 65 | { "usage", '\0', 0, NULL, (int)'u', N_("Display brief usage message"), NULL }, 66 | POPT_TABLEEND 67 | } ; 68 | 69 | static struct poptOption poptHelpOptions2[] = { 70 | { NULL, '\0', POPT_ARG_INTL_DOMAIN, (void *)PACKAGE, 0, NULL, NULL}, 71 | { NULL, '\0', POPT_ARG_CALLBACK, (void *)displayArgs, 0, NULL, NULL }, 72 | { "help", '?', 0, NULL, (int)'?', N_("Show this help message"), NULL }, 73 | { "usage", '\0', 0, NULL, (int)'u', N_("Display brief usage message"), NULL }, 74 | #ifdef NOTYET 75 | { "defaults", '\0', POPT_ARG_NONE, &show_option_defaults, 0, 76 | N_("Display option defaults in message"), NULL }, 77 | #endif 78 | { NULL, '\0', 0, NULL, 0, N_("Terminate options"), NULL }, 79 | POPT_TABLEEND 80 | } ; 81 | 82 | struct poptOption * poptHelpOptionsI18N = poptHelpOptions2; 83 | 84 | #define _POPTHELP_MAXLINE ((size_t)79) 85 | 86 | typedef struct columns_s { 87 | size_t cur; 88 | size_t max; 89 | } * columns_t; 90 | 91 | /** 92 | * Return no. of columns in output window. 93 | * @param fp FILE 94 | * @return no. of columns 95 | */ 96 | static size_t maxColumnWidth(FILE *fp) 97 | { 98 | size_t maxcols = _POPTHELP_MAXLINE; 99 | #if defined(TIOCGWINSZ) 100 | struct winsize ws; 101 | int fdno = fileno(fp ? fp : stdout); 102 | 103 | memset(&ws, 0, sizeof(ws)); 104 | if (fdno >= 0 && !ioctl(fdno, (unsigned long)TIOCGWINSZ, &ws)) { 105 | size_t ws_col = (size_t)ws.ws_col; 106 | if (ws_col > maxcols && ws_col < (size_t)256) 107 | maxcols = ws_col - 1; 108 | } 109 | #endif 110 | return maxcols; 111 | } 112 | 113 | /** 114 | * Determine number of display characters in a string. 115 | * @param s string 116 | * @return no. of display characters. 117 | */ 118 | static inline size_t stringDisplayWidth(const char *s) 119 | { 120 | size_t n = strlen(s); 121 | #ifdef HAVE_MBSRTOWCS 122 | mbstate_t t; 123 | 124 | memset ((void *)&t, 0, sizeof (t)); /* In initial state. */ 125 | /* Determine number of display characters. */ 126 | n = mbsrtowcs (NULL, &s, n, &t); 127 | #else 128 | n = 0; 129 | for (; *s; s = POPT_next_char(s)) 130 | n++; 131 | #endif 132 | 133 | return n; 134 | } 135 | 136 | /** 137 | * @param opt option(s) 138 | */ 139 | static const char * 140 | getTableTranslationDomain(const struct poptOption *opt) 141 | { 142 | if (opt != NULL) 143 | for (; opt->longName || opt->shortName || opt->arg; opt++) { 144 | if (opt->argInfo == POPT_ARG_INTL_DOMAIN) 145 | return opt->arg; 146 | } 147 | return NULL; 148 | } 149 | 150 | /** 151 | * @param opt option(s) 152 | * @param translation_domain translation domain 153 | */ 154 | static const char * 155 | getArgDescrip(const struct poptOption * opt, 156 | /* FIX: i18n macros disabled with lclint */ 157 | const char * translation_domain) 158 | { 159 | if (!poptArgType(opt)) return NULL; 160 | 161 | if (poptArgType(opt) == POPT_ARG_MAINCALL) 162 | return opt->argDescrip; 163 | if (poptArgType(opt) == POPT_ARG_ARGV) 164 | return opt->argDescrip; 165 | 166 | if (opt->argDescrip) { 167 | /* Some strings need popt library, not application, i18n domain. */ 168 | if (opt == (poptHelpOptions + 1) 169 | || opt == (poptHelpOptions + 2) 170 | || !strcmp(opt->argDescrip, N_("Help options:")) 171 | || !strcmp(opt->argDescrip, N_("Options implemented via popt alias/exec:"))) 172 | return POPT_(opt->argDescrip); 173 | 174 | /* Use the application i18n domain. */ 175 | return D_(translation_domain, opt->argDescrip); 176 | } 177 | 178 | switch (poptArgType(opt)) { 179 | case POPT_ARG_NONE: return POPT_("NONE"); 180 | #ifdef DYING 181 | case POPT_ARG_VAL: return POPT_("VAL"); 182 | #else 183 | case POPT_ARG_VAL: return NULL; 184 | #endif 185 | case POPT_ARG_INT: return POPT_("INT"); 186 | case POPT_ARG_SHORT: return POPT_("SHORT"); 187 | case POPT_ARG_LONG: return POPT_("LONG"); 188 | case POPT_ARG_LONGLONG: return POPT_("LONGLONG"); 189 | case POPT_ARG_STRING: return POPT_("STRING"); 190 | case POPT_ARG_FLOAT: return POPT_("FLOAT"); 191 | case POPT_ARG_DOUBLE: return POPT_("DOUBLE"); 192 | case POPT_ARG_MAINCALL: return NULL; 193 | case POPT_ARG_ARGV: return NULL; 194 | default: return POPT_("ARG"); 195 | } 196 | } 197 | 198 | /** 199 | * Display default value for an option. 200 | * @param lineLength display positions remaining 201 | * @param opt option(s) 202 | * @param translation_domain translation domain 203 | * @return 204 | */ 205 | static char * 206 | singleOptionDefaultValue(size_t lineLength, 207 | const struct poptOption * opt, 208 | /* FIX: i18n macros disabled with lclint */ 209 | const char * translation_domain) 210 | { 211 | const char * defstr = D_(translation_domain, "default"); 212 | char * le = malloc(4*lineLength + 1); 213 | char * l = le; 214 | 215 | if (le == NULL) return NULL; /* XXX can't happen */ 216 | *le = '\0'; 217 | *le++ = '('; 218 | le = stpcpy(le, defstr); 219 | *le++ = ':'; 220 | *le++ = ' '; 221 | if (opt->arg) { /* XXX programmer error */ 222 | poptArg arg = { .ptr = opt->arg }; 223 | switch (poptArgType(opt)) { 224 | case POPT_ARG_VAL: 225 | case POPT_ARG_INT: 226 | le += sprintf(le, "%d", arg.intp[0]); 227 | break; 228 | case POPT_ARG_SHORT: 229 | le += sprintf(le, "%hd", arg.shortp[0]); 230 | break; 231 | case POPT_ARG_LONG: 232 | le += sprintf(le, "%ld", arg.longp[0]); 233 | break; 234 | case POPT_ARG_LONGLONG: 235 | le += sprintf(le, "%lld", arg.longlongp[0]); 236 | break; 237 | case POPT_ARG_FLOAT: 238 | { double aDouble = (double) arg.floatp[0]; 239 | le += sprintf(le, "%g", aDouble); 240 | } break; 241 | case POPT_ARG_DOUBLE: 242 | le += sprintf(le, "%g", arg.doublep[0]); 243 | break; 244 | case POPT_ARG_MAINCALL: 245 | le += sprintf(le, "%p", opt->arg); 246 | break; 247 | case POPT_ARG_ARGV: 248 | le += sprintf(le, "%p", opt->arg); 249 | break; 250 | case POPT_ARG_STRING: 251 | { const char * s = arg.argv[0]; 252 | if (s == NULL) 253 | le = stpcpy(le, "null"); 254 | else { 255 | size_t limit = 4*lineLength - (le - l) - sizeof("\"\")"); 256 | size_t slen; 257 | *le++ = '"'; 258 | strncpy(le, s, limit); le[limit] = '\0'; le += (slen = strlen(le)); 259 | if (slen == limit && s[limit]) 260 | le[-1] = le[-2] = le[-3] = '.'; 261 | *le++ = '"'; 262 | } 263 | } break; 264 | case POPT_ARG_NONE: 265 | default: 266 | l = _free(l); 267 | return NULL; 268 | break; 269 | } 270 | } 271 | *le++ = ')'; 272 | *le = '\0'; 273 | 274 | return l; 275 | } 276 | 277 | /** 278 | * Display help text for an option. 279 | * @param fp output file handle 280 | * @param columns output display width control 281 | * @param opt option(s) 282 | * @param translation_domain translation domain 283 | */ 284 | static void singleOptionHelp(FILE * fp, columns_t columns, 285 | const struct poptOption * opt, 286 | const char * translation_domain) 287 | { 288 | size_t maxLeftCol = columns->cur; 289 | size_t indentLength = maxLeftCol + 5; 290 | size_t lineLength = columns->max - indentLength; 291 | const char * help = D_(translation_domain, opt->descrip); 292 | const char * argDescrip = getArgDescrip(opt, translation_domain); 293 | /* Display shortName iff printable non-space. */ 294 | int prtshort = (int)(isprint((int)opt->shortName) && opt->shortName != ' '); 295 | size_t helpLength; 296 | char * defs = NULL; 297 | char * left; 298 | size_t nb = maxLeftCol + 1; 299 | int displaypad = 0; 300 | 301 | /* Make sure there's more than enough room in target buffer. */ 302 | if (opt->longName) nb += strlen(opt->longName); 303 | if (F_ISSET(opt, TOGGLE)) nb += sizeof("[no]") - 1; 304 | if (argDescrip) nb += strlen(argDescrip); 305 | 306 | left = malloc(nb); 307 | if (left == NULL) return; /* XXX can't happen */ 308 | left[0] = '\0'; 309 | left[maxLeftCol] = '\0'; 310 | 311 | #define prtlong (opt->longName != NULL) /* XXX splint needs a clue */ 312 | if (!(prtshort || prtlong)) 313 | goto out; 314 | if (prtshort && prtlong) { 315 | const char *dash = F_ISSET(opt, ONEDASH) ? "-" : "--"; 316 | left[0] = '-'; 317 | left[1] = opt->shortName; 318 | (void) stpcpy(stpcpy(stpcpy(left+2, ", "), dash), opt->longName); 319 | } else if (prtshort) { 320 | left[0] = '-'; 321 | left[1] = opt->shortName; 322 | left[2] = '\0'; 323 | } else if (prtlong) { 324 | /* XXX --long always padded for alignment with/without "-X, ". */ 325 | const char *dash = poptArgType(opt) == POPT_ARG_MAINCALL ? "" 326 | : (F_ISSET(opt, ONEDASH) ? "-" : "--"); 327 | const char *longName = opt->longName; 328 | const char *toggle; 329 | if (F_ISSET(opt, TOGGLE)) { 330 | toggle = "[no]"; 331 | if (longName[0] == 'n' && longName[1] == 'o') { 332 | longName += sizeof("no") - 1; 333 | if (longName[0] == '-') 334 | longName++; 335 | } 336 | } else 337 | toggle = ""; 338 | (void) stpcpy(stpcpy(stpcpy(stpcpy(left, " "), dash), toggle), longName); 339 | } 340 | #undef prtlong 341 | 342 | if (argDescrip) { 343 | char * le = left + strlen(left); 344 | 345 | if (F_ISSET(opt, OPTIONAL)) 346 | *le++ = '['; 347 | 348 | /* Choose type of output */ 349 | if (F_ISSET(opt, SHOW_DEFAULT)) { 350 | defs = singleOptionDefaultValue(lineLength, opt, translation_domain); 351 | if (defs) { 352 | char * t = malloc((help ? strlen(help) : 0) + 353 | strlen(defs) + sizeof(" ")); 354 | if (t) { 355 | char * te = t; 356 | if (help) 357 | te = stpcpy(te, help); 358 | *te++ = ' '; 359 | strcpy(te, defs); 360 | defs = _free(defs); 361 | defs = t; 362 | } 363 | } 364 | } 365 | 366 | if (opt->argDescrip == NULL) { 367 | switch (poptArgType(opt)) { 368 | case POPT_ARG_NONE: 369 | break; 370 | case POPT_ARG_VAL: 371 | #ifdef NOTNOW /* XXX pug ugly nerdy output */ 372 | { long aLong = opt->val; 373 | int ops = F_ISSET(opt, LOGICALOPS); 374 | int negate = F_ISSET(opt, NOT); 375 | 376 | /* Don't bother displaying typical values */ 377 | if (!ops && (aLong == 0L || aLong == 1L || aLong == -1L)) 378 | break; 379 | *le++ = '['; 380 | switch (ops) { 381 | case POPT_ARGFLAG_OR: 382 | *le++ = '|'; 383 | break; 384 | case POPT_ARGFLAG_AND: 385 | *le++ = '&'; 386 | break; 387 | case POPT_ARGFLAG_XOR: 388 | *le++ = '^'; 389 | break; 390 | default: 391 | break; 392 | } 393 | *le++ = (opt->longName != NULL ? '=' : ' '); 394 | if (negate) *le++ = '~'; 395 | le += sprintf(le, (ops ? "0x%lx" : "%ld"), aLong); 396 | *le++ = ']'; 397 | } 398 | #endif 399 | break; 400 | case POPT_ARG_INT: 401 | case POPT_ARG_SHORT: 402 | case POPT_ARG_LONG: 403 | case POPT_ARG_LONGLONG: 404 | case POPT_ARG_FLOAT: 405 | case POPT_ARG_DOUBLE: 406 | case POPT_ARG_STRING: 407 | *le++ = (opt->longName != NULL ? '=' : ' '); 408 | le = stpcpy(le, argDescrip); 409 | break; 410 | default: 411 | break; 412 | } 413 | } else { 414 | char *leo; 415 | 416 | /* XXX argDescrip[0] determines "--foo=bar" or "--foo bar". */ 417 | if (!strchr(" =(", argDescrip[0])) 418 | *le++ = ((poptArgType(opt) == POPT_ARG_MAINCALL) ? ' ' : 419 | (poptArgType(opt) == POPT_ARG_ARGV) ? ' ' : 420 | opt->longName == NULL ? ' ' : '='); 421 | le = stpcpy(leo = le, argDescrip); 422 | 423 | /* Adjust for (possible) wide characters. */ 424 | displaypad = (int)((le - leo) - stringDisplayWidth(argDescrip)); 425 | } 426 | if (F_ISSET(opt, OPTIONAL)) 427 | *le++ = ']'; 428 | *le = '\0'; 429 | } 430 | 431 | if (help) 432 | POPT_fprintf(fp," %-*s ", (int)(maxLeftCol+displaypad), left); 433 | else { 434 | POPT_fprintf(fp," %s\n", left); 435 | goto out; 436 | } 437 | 438 | left = _free(left); 439 | if (defs) 440 | help = defs; 441 | 442 | helpLength = strlen(help); 443 | while (helpLength > lineLength) { 444 | const char * ch; 445 | 446 | ch = help + lineLength - 1; 447 | while (ch > help && !_isspaceptr(ch)) 448 | ch = POPT_prev_char(ch); 449 | if (ch == help) break; /* give up */ 450 | while (ch > (help + 1) && _isspaceptr(ch)) 451 | ch = POPT_prev_char (ch); 452 | ch = POPT_next_char(ch); 453 | 454 | /* 455 | * XXX strdup is necessary to add NUL terminator so that an unknown 456 | * no. of (possible) multi-byte characters can be displayed. 457 | */ 458 | { char * fmthelp = xstrdup(help); 459 | if (fmthelp) { 460 | fmthelp[ch - help] = '\0'; 461 | POPT_fprintf(fp, "%s\n%*s", fmthelp, (int) indentLength, " "); 462 | free(fmthelp); 463 | } 464 | } 465 | 466 | help = ch; 467 | while (_isspaceptr(help) && *help) 468 | help = POPT_next_char(help); 469 | helpLength = strlen(help); 470 | } 471 | 472 | if (helpLength) fprintf(fp, "%s\n", help); 473 | help = NULL; 474 | 475 | out: 476 | defs = _free(defs); 477 | left = _free(left); 478 | } 479 | 480 | /** 481 | * Find display width for longest argument string. 482 | * @param opt option(s) 483 | * @param translation_domain translation domain 484 | * @return display width 485 | */ 486 | static size_t maxArgWidth(const struct poptOption * opt, 487 | const char * translation_domain) 488 | { 489 | size_t max = 0; 490 | size_t len = 0; 491 | const char * argDescrip; 492 | 493 | if (opt != NULL) 494 | while (opt->longName || opt->shortName || opt->arg) { 495 | if (poptArgType(opt) == POPT_ARG_INCLUDE_TABLE) { 496 | void * arg = opt->arg; 497 | /* XXX sick hack to preserve pretense of ABI. */ 498 | if (arg == poptHelpOptions) 499 | arg = poptHelpOptionsI18N; 500 | if (arg) /* XXX program error */ 501 | len = maxArgWidth(arg, translation_domain); 502 | if (len > max) max = len; 503 | } else if (!F_ISSET(opt, DOC_HIDDEN)) { 504 | len = sizeof(" ")-1; 505 | /* XXX --long always padded for alignment with/without "-X, ". */ 506 | len += sizeof("-X, ")-1; 507 | if (opt->longName) { 508 | len += (F_ISSET(opt, ONEDASH) ? sizeof("-") : sizeof("--")) - 1; 509 | len += strlen(opt->longName); 510 | } 511 | 512 | argDescrip = getArgDescrip(opt, translation_domain); 513 | 514 | if (argDescrip) { 515 | 516 | /* XXX argDescrip[0] determines "--foo=bar" or "--foo bar". */ 517 | if (!strchr(" =(", argDescrip[0])) len += sizeof("=")-1; 518 | 519 | /* Adjust for (possible) wide characters. */ 520 | len += stringDisplayWidth(argDescrip); 521 | } 522 | 523 | if (F_ISSET(opt, OPTIONAL)) len += sizeof("[]")-1; 524 | if (len > max) max = len; 525 | } 526 | opt++; 527 | } 528 | 529 | return max; 530 | } 531 | 532 | /** 533 | * Display popt alias and exec help. 534 | * @param fp output file handle 535 | * @param items alias/exec array 536 | * @param nitems no. of alias/exec entries 537 | * @param columns output display width control 538 | * @param translation_domain translation domain 539 | */ 540 | static void itemHelp(FILE * fp, 541 | poptItem items, int nitems, 542 | columns_t columns, 543 | const char * translation_domain) 544 | { 545 | poptItem item; 546 | int i; 547 | 548 | if (items != NULL) 549 | for (i = 0, item = items; i < nitems; i++, item++) { 550 | const struct poptOption * opt; 551 | opt = &item->option; 552 | if ((opt->longName || opt->shortName) && !F_ISSET(opt, DOC_HIDDEN)) 553 | singleOptionHelp(fp, columns, opt, translation_domain); 554 | } 555 | } 556 | 557 | /** 558 | * Display help text for a table of options. 559 | * @param con context 560 | * @param fp output file handle 561 | * @param table option(s) 562 | * @param columns output display width control 563 | * @param translation_domain translation domain 564 | */ 565 | static void singleTableHelp(poptContext con, FILE * fp, 566 | const struct poptOption * table, 567 | columns_t columns, 568 | const char * translation_domain) 569 | { 570 | const struct poptOption * opt; 571 | const char *sub_transdom; 572 | 573 | if (table == poptAliasOptions) { 574 | itemHelp(fp, con->aliases, con->numAliases, columns, NULL); 575 | itemHelp(fp, con->execs, con->numExecs, columns, NULL); 576 | return; 577 | } 578 | 579 | if (table != NULL) 580 | for (opt = table; opt->longName || opt->shortName || opt->arg; opt++) { 581 | if ((opt->longName || opt->shortName) && !F_ISSET(opt, DOC_HIDDEN)) 582 | singleOptionHelp(fp, columns, opt, translation_domain); 583 | } 584 | 585 | if (table != NULL) 586 | for (opt = table; opt->longName || opt->shortName || opt->arg; opt++) { 587 | void * arg = opt->arg; 588 | if (poptArgType(opt) != POPT_ARG_INCLUDE_TABLE) 589 | continue; 590 | /* XXX sick hack to preserve pretense of ABI. */ 591 | if (arg == poptHelpOptions) 592 | arg = poptHelpOptionsI18N; 593 | sub_transdom = getTableTranslationDomain(arg); 594 | if (sub_transdom == NULL) 595 | sub_transdom = translation_domain; 596 | 597 | /* If no popt aliases/execs, skip poptAliasOption processing. */ 598 | if (arg == poptAliasOptions && !(con->numAliases || con->numExecs)) 599 | continue; 600 | if (opt->descrip) 601 | POPT_fprintf(fp, "\n%s\n", D_(sub_transdom, opt->descrip)); 602 | 603 | singleTableHelp(con, fp, arg, columns, sub_transdom); 604 | } 605 | } 606 | 607 | /** 608 | * @param con context 609 | * @param fp output file handle 610 | */ 611 | static size_t showHelpIntro(poptContext con, FILE * fp) 612 | { 613 | const char *usage_str = POPT_("Usage:"); 614 | size_t len = strlen(usage_str); 615 | POPT_fprintf(fp, "%s", usage_str); 616 | 617 | if (!(con->flags & POPT_CONTEXT_KEEP_FIRST)) { 618 | struct optionStackEntry * os = con->optionStack; 619 | const char * fn = (os->argv ? os->argv[0] : NULL); 620 | if (fn == NULL) return len; 621 | if (strchr(fn, '/')) fn = strrchr(fn, '/') + 1; 622 | /* XXX POPT_fprintf not needed for argv[0] display. */ 623 | fprintf(fp, " %s", fn); 624 | len += strlen(fn) + 1; 625 | } 626 | 627 | return len; 628 | } 629 | 630 | void poptPrintHelp(poptContext con, FILE * fp, UNUSED(int flags)) 631 | { 632 | columns_t columns = calloc((size_t)1, sizeof(*columns)); 633 | 634 | (void) showHelpIntro(con, fp); 635 | if (con->otherHelp) 636 | POPT_fprintf(fp, " %s\n", con->otherHelp); 637 | else 638 | POPT_fprintf(fp, " %s\n", POPT_("[OPTION...]")); 639 | 640 | if (columns) { 641 | columns->cur = maxArgWidth(con->options, NULL); 642 | columns->max = maxColumnWidth(fp); 643 | singleTableHelp(con, fp, con->options, columns, NULL); 644 | free(columns); 645 | } 646 | } 647 | 648 | /** 649 | * Display usage text for an option. 650 | * @param fp output file handle 651 | * @param columns output display width control 652 | * @param opt option(s) 653 | * @param translation_domain translation domain 654 | */ 655 | static size_t singleOptionUsage(FILE * fp, columns_t columns, 656 | const struct poptOption * opt, 657 | const char *translation_domain) 658 | { 659 | size_t len = sizeof(" []")-1; 660 | const char * argDescrip = getArgDescrip(opt, translation_domain); 661 | /* Display shortName iff printable non-space. */ 662 | int prtshort = (int)(isprint((int)opt->shortName) && opt->shortName != ' '); 663 | 664 | #define prtlong (opt->longName != NULL) /* XXX splint needs a clue */ 665 | if (!(prtshort || prtlong)) 666 | return columns->cur; 667 | 668 | len = sizeof(" []")-1; 669 | if (prtshort) 670 | len += sizeof("-c")-1; 671 | if (prtlong) { 672 | if (prtshort) len += sizeof("|")-1; 673 | len += (F_ISSET(opt, ONEDASH) ? sizeof("-") : sizeof("--")) - 1; 674 | len += strlen(opt->longName); 675 | } 676 | 677 | if (argDescrip) { 678 | 679 | /* XXX argDescrip[0] determines "--foo=bar" or "--foo bar". */ 680 | if (!strchr(" =(", argDescrip[0])) len += sizeof("=")-1; 681 | 682 | /* Adjust for (possible) wide characters. */ 683 | len += stringDisplayWidth(argDescrip); 684 | } 685 | 686 | if ((columns->cur + len) > columns->max) { 687 | fprintf(fp, "\n "); 688 | columns->cur = (size_t)7; 689 | } 690 | 691 | fprintf(fp, " ["); 692 | if (prtshort) 693 | fprintf(fp, "-%c", opt->shortName); 694 | if (prtlong) 695 | fprintf(fp, "%s%s%s", 696 | (prtshort ? "|" : ""), 697 | (F_ISSET(opt, ONEDASH) ? "-" : "--"), 698 | opt->longName); 699 | #undef prtlong 700 | 701 | if (argDescrip) { 702 | /* XXX argDescrip[0] determines "--foo=bar" or "--foo bar". */ 703 | if (!strchr(" =(", argDescrip[0])) fputc(opt->longName == NULL ? ' ' : '=', fp); 704 | fprintf(fp, "%s", argDescrip); 705 | } 706 | fprintf(fp, "]"); 707 | 708 | return columns->cur + len + 1; 709 | } 710 | 711 | /** 712 | * Display popt alias and exec usage. 713 | * @param fp output file handle 714 | * @param columns output display width control 715 | * @param item alias/exec array 716 | * @param nitems no. of ara/exec entries 717 | * @param translation_domain translation domain 718 | */ 719 | static size_t itemUsage(FILE * fp, columns_t columns, 720 | poptItem item, int nitems, 721 | const char * translation_domain) 722 | { 723 | int i; 724 | 725 | if (item != NULL) 726 | for (i = 0; i < nitems; i++, item++) { 727 | const struct poptOption * opt; 728 | opt = &item->option; 729 | if (poptArgType(opt) == POPT_ARG_INTL_DOMAIN) { 730 | translation_domain = (const char *)opt->arg; 731 | } else 732 | if ((opt->longName || opt->shortName) && !F_ISSET(opt, DOC_HIDDEN)) { 733 | columns->cur = singleOptionUsage(fp, columns, opt, translation_domain); 734 | } 735 | } 736 | 737 | return columns->cur; 738 | } 739 | 740 | /** 741 | * Keep track of option tables already processed. 742 | */ 743 | typedef struct poptDone_s { 744 | int nopts; 745 | int maxopts; 746 | const void ** opts; 747 | } * poptDone; 748 | 749 | /** 750 | * Display usage text for a table of options. 751 | * @param con context 752 | * @param fp output file handle 753 | * @param columns output display width control 754 | * @param opt option(s) 755 | * @param translation_domain translation domain 756 | * @param done tables already processed 757 | * @return 758 | */ 759 | static size_t singleTableUsage(poptContext con, FILE * fp, columns_t columns, 760 | const struct poptOption * opt, 761 | const char * translation_domain, 762 | poptDone done) 763 | { 764 | if (opt != NULL) 765 | for (; (opt->longName || opt->shortName || opt->arg) ; opt++) { 766 | if (poptArgType(opt) == POPT_ARG_INTL_DOMAIN) { 767 | translation_domain = (const char *)opt->arg; 768 | } else 769 | if (poptArgType(opt) == POPT_ARG_INCLUDE_TABLE) { 770 | void * arg = opt->arg; 771 | /* XXX sick hack to preserve pretense of ABI. */ 772 | if (arg == poptHelpOptions) 773 | arg = poptHelpOptionsI18N; 774 | if (done) { 775 | int i = 0; 776 | if (done->opts != NULL) 777 | for (i = 0; i < done->nopts; i++) { 778 | const void * that = done->opts[i]; 779 | if (that == NULL || that != arg) 780 | continue; 781 | break; 782 | } 783 | /* Skip if this table has already been processed. */ 784 | if (arg == NULL || i < done->nopts) 785 | continue; 786 | if (done->opts != NULL && done->nopts < done->maxopts) 787 | done->opts[done->nopts++] = (const void *) arg; 788 | } 789 | columns->cur = singleTableUsage(con, fp, columns, opt->arg, 790 | translation_domain, done); 791 | } else 792 | if ((opt->longName || opt->shortName) && !F_ISSET(opt, DOC_HIDDEN)) { 793 | columns->cur = singleOptionUsage(fp, columns, opt, translation_domain); 794 | } 795 | } 796 | 797 | return columns->cur; 798 | } 799 | 800 | /** 801 | * Return concatenated short options for display. 802 | * @todo Sub-tables should be recursed. 803 | * @param opt option(s) 804 | * @param fp output file handle 805 | * @retval str concatenation of short options 806 | * @return length of display string 807 | */ 808 | static size_t showShortOptions(const struct poptOption * opt, FILE * fp, 809 | char * str) 810 | { 811 | /* bufsize larger then the ascii set, lazy allocation on top level call. */ 812 | size_t nb = (size_t)300; 813 | char * s = (str != NULL ? str : calloc((size_t)1, nb)); 814 | size_t len = (size_t)0; 815 | 816 | if (s == NULL) 817 | return 0; 818 | 819 | if (opt != NULL) 820 | for (; (opt->longName || opt->shortName || opt->arg); opt++) { 821 | if (!F_ISSET(opt, DOC_HIDDEN) && opt->shortName && !poptArgType(opt)) 822 | { 823 | /* Display shortName iff unique printable non-space. */ 824 | if (!strchr(s, opt->shortName) && isprint((int)opt->shortName) 825 | && opt->shortName != ' ') 826 | s[strlen(s)] = opt->shortName; 827 | } else if (poptArgType(opt) == POPT_ARG_INCLUDE_TABLE) { 828 | void * arg = opt->arg; 829 | /* XXX sick hack to preserve pretense of ABI. */ 830 | if (arg == poptHelpOptions) 831 | arg = poptHelpOptionsI18N; 832 | if (arg) /* XXX program error */ 833 | len = showShortOptions(arg, fp, s); 834 | } 835 | } 836 | 837 | /* On return to top level, print the short options, return print length. */ 838 | if (s != str && *s != '\0') { 839 | fprintf(fp, " [-%s]", s); 840 | len = strlen(s) + sizeof(" [-]")-1; 841 | } 842 | if (s != str) 843 | free(s); 844 | return len; 845 | } 846 | 847 | void poptPrintUsage(poptContext con, FILE * fp, UNUSED(int flags)) 848 | { 849 | columns_t columns = calloc((size_t)1, sizeof(*columns)); 850 | struct poptDone_s done_buf; 851 | poptDone done = &done_buf; 852 | 853 | memset(done, 0, sizeof(*done)); 854 | done->nopts = 0; 855 | done->maxopts = 64; 856 | if (columns) { 857 | columns->cur = done->maxopts * sizeof(*done->opts); 858 | columns->max = maxColumnWidth(fp); 859 | done->opts = calloc((size_t)1, columns->cur); 860 | if (done->opts != NULL) 861 | done->opts[done->nopts++] = (const void *) con->options; 862 | 863 | columns->cur = showHelpIntro(con, fp); 864 | columns->cur += showShortOptions(con->options, fp, NULL); 865 | columns->cur = singleTableUsage(con, fp, columns, con->options, NULL, done); 866 | columns->cur = itemUsage(fp, columns, con->aliases, con->numAliases, NULL); 867 | columns->cur = itemUsage(fp, columns, con->execs, con->numExecs, NULL); 868 | 869 | if (con->otherHelp) { 870 | columns->cur += strlen(con->otherHelp) + 1; 871 | if (columns->cur > columns->max) fprintf(fp, "\n "); 872 | fprintf(fp, " %s", con->otherHelp); 873 | } 874 | 875 | fprintf(fp, "\n"); 876 | if (done->opts != NULL) 877 | free(done->opts); 878 | free(columns); 879 | } 880 | } 881 | 882 | void poptSetOtherOptionHelp(poptContext con, const char * text) 883 | { 884 | con->otherHelp = _free(con->otherHelp); 885 | con->otherHelp = xstrdup(text); 886 | } 887 | -------------------------------------------------------------------------------- /src/lookup3.c: -------------------------------------------------------------------------------- 1 | /* -------------------------------------------------------------------- */ 2 | /* 3 | * lookup3.c, by Bob Jenkins, May 2006, Public Domain. 4 | * 5 | * These are functions for producing 32-bit hashes for hash table lookup. 6 | * jlu32w(), jlu32l(), jlu32lpair(), jlu32b(), _JLU3_MIX(), and _JLU3_FINAL() 7 | * are externally useful functions. Routines to test the hash are included 8 | * if SELF_TEST is defined. You can use this free for any purpose. It's in 9 | * the public domain. It has no warranty. 10 | * 11 | * You probably want to use jlu32l(). jlu32l() and jlu32b() 12 | * hash byte arrays. jlu32l() is is faster than jlu32b() on 13 | * little-endian machines. Intel and AMD are little-endian machines. 14 | * On second thought, you probably want jlu32lpair(), which is identical to 15 | * jlu32l() except it returns two 32-bit hashes for the price of one. 16 | * You could implement jlu32bpair() if you wanted but I haven't bothered here. 17 | * 18 | * If you want to find a hash of, say, exactly 7 integers, do 19 | * a = i1; b = i2; c = i3; 20 | * _JLU3_MIX(a,b,c); 21 | * a += i4; b += i5; c += i6; 22 | * _JLU3_MIX(a,b,c); 23 | * a += i7; 24 | * _JLU3_FINAL(a,b,c); 25 | * then use c as the hash value. If you have a variable size array of 26 | * 4-byte integers to hash, use jlu32w(). If you have a byte array (like 27 | * a character string), use jlu32l(). If you have several byte arrays, or 28 | * a mix of things, see the comments above jlu32l(). 29 | * 30 | * Why is this so big? I read 12 bytes at a time into 3 4-byte integers, 31 | * then mix those integers. This is fast (you can do a lot more thorough 32 | * mixing with 12*3 instructions on 3 integers than you can with 3 instructions 33 | * on 1 byte), but shoehorning those bytes into integers efficiently is messy. 34 | */ 35 | /* -------------------------------------------------------------------- */ 36 | 37 | #include 38 | 39 | #if defined(_JLU3_SELFTEST) 40 | # define _JLU3_jlu32w 1 41 | # define _JLU3_jlu32l 1 42 | # define _JLU3_jlu32lpair 1 43 | # define _JLU3_jlu32b 1 44 | #endif 45 | 46 | static const union _dbswap { 47 | const uint32_t ui; 48 | const unsigned char uc[4]; 49 | } endian = { .ui = 0x11223344 }; 50 | # define HASH_LITTLE_ENDIAN (endian.uc[0] == (unsigned char) 0x44) 51 | # define HASH_BIG_ENDIAN (endian.uc[0] == (unsigned char) 0x11) 52 | 53 | #ifndef ROTL32 54 | # define ROTL32(x, s) (((x) << (s)) | ((x) >> (32 - (s)))) 55 | #endif 56 | 57 | /* NOTE: The _size parameter should be in bytes. */ 58 | #define _JLU3_INIT(_h, _size) (0xdeadbeef + ((uint32_t)(_size)) + (_h)) 59 | 60 | /* -------------------------------------------------------------------- */ 61 | /* 62 | * _JLU3_MIX -- mix 3 32-bit values reversibly. 63 | * 64 | * This is reversible, so any information in (a,b,c) before _JLU3_MIX() is 65 | * still in (a,b,c) after _JLU3_MIX(). 66 | * 67 | * If four pairs of (a,b,c) inputs are run through _JLU3_MIX(), or through 68 | * _JLU3_MIX() in reverse, there are at least 32 bits of the output that 69 | * are sometimes the same for one pair and different for another pair. 70 | * This was tested for: 71 | * * pairs that differed by one bit, by two bits, in any combination 72 | * of top bits of (a,b,c), or in any combination of bottom bits of 73 | * (a,b,c). 74 | * * "differ" is defined as +, -, ^, or ~^. For + and -, I transformed 75 | * the output delta to a Gray code (a^(a>>1)) so a string of 1's (as 76 | * is commonly produced by subtraction) look like a single 1-bit 77 | * difference. 78 | * * the base values were pseudorandom, all zero but one bit set, or 79 | * all zero plus a counter that starts at zero. 80 | * 81 | * Some k values for my "a-=c; a^=ROTL32(c,k); c+=b;" arrangement that 82 | * satisfy this are 83 | * 4 6 8 16 19 4 84 | * 9 15 3 18 27 15 85 | * 14 9 3 7 17 3 86 | * Well, "9 15 3 18 27 15" didn't quite get 32 bits diffing 87 | * for "differ" defined as + with a one-bit base and a two-bit delta. I 88 | * used http://burtleburtle.net/bob/hash/avalanche.html to choose 89 | * the operations, constants, and arrangements of the variables. 90 | * 91 | * This does not achieve avalanche. There are input bits of (a,b,c) 92 | * that fail to affect some output bits of (a,b,c), especially of a. The 93 | * most thoroughly mixed value is c, but it doesn't really even achieve 94 | * avalanche in c. 95 | * 96 | * This allows some parallelism. Read-after-writes are good at doubling 97 | * the number of bits affected, so the goal of mixing pulls in the opposite 98 | * direction as the goal of parallelism. I did what I could. Rotates 99 | * seem to cost as much as shifts on every machine I could lay my hands 100 | * on, and rotates are much kinder to the top and bottom bits, so I used 101 | * rotates. 102 | */ 103 | /* -------------------------------------------------------------------- */ 104 | #define _JLU3_MIX(a,b,c) \ 105 | { \ 106 | a -= c; a ^= ROTL32(c, 4); c += b; \ 107 | b -= a; b ^= ROTL32(a, 6); a += c; \ 108 | c -= b; c ^= ROTL32(b, 8); b += a; \ 109 | a -= c; a ^= ROTL32(c,16); c += b; \ 110 | b -= a; b ^= ROTL32(a,19); a += c; \ 111 | c -= b; c ^= ROTL32(b, 4); b += a; \ 112 | } 113 | 114 | /* -------------------------------------------------------------------- */ 115 | /** 116 | * _JLU3_FINAL -- final mixing of 3 32-bit values (a,b,c) into c 117 | * 118 | * Pairs of (a,b,c) values differing in only a few bits will usually 119 | * produce values of c that look totally different. This was tested for 120 | * * pairs that differed by one bit, by two bits, in any combination 121 | * of top bits of (a,b,c), or in any combination of bottom bits of 122 | * (a,b,c). 123 | * * "differ" is defined as +, -, ^, or ~^. For + and -, I transformed 124 | * the output delta to a Gray code (a^(a>>1)) so a string of 1's (as 125 | * is commonly produced by subtraction) look like a single 1-bit 126 | * difference. 127 | * * the base values were pseudorandom, all zero but one bit set, or 128 | * all zero plus a counter that starts at zero. 129 | * 130 | * These constants passed: 131 | * 14 11 25 16 4 14 24 132 | * 12 14 25 16 4 14 24 133 | * and these came close: 134 | * 4 8 15 26 3 22 24 135 | * 10 8 15 26 3 22 24 136 | * 11 8 15 26 3 22 24 137 | */ 138 | /* -------------------------------------------------------------------- */ 139 | #define _JLU3_FINAL(a,b,c) \ 140 | { \ 141 | c ^= b; c -= ROTL32(b,14); \ 142 | a ^= c; a -= ROTL32(c,11); \ 143 | b ^= a; b -= ROTL32(a,25); \ 144 | c ^= b; c -= ROTL32(b,16); \ 145 | a ^= c; a -= ROTL32(c,4); \ 146 | b ^= a; b -= ROTL32(a,14); \ 147 | c ^= b; c -= ROTL32(b,24); \ 148 | } 149 | 150 | #if defined(_JLU3_jlu32w) 151 | uint32_t jlu32w(uint32_t h, const uint32_t *k, size_t size); 152 | /* -------------------------------------------------------------------- */ 153 | /** 154 | * This works on all machines. To be useful, it requires 155 | * -- that the key be an array of uint32_t's, and 156 | * -- that the size be the number of uint32_t's in the key 157 | * 158 | * The function jlu32w() is identical to jlu32l() on little-endian 159 | * machines, and identical to jlu32b() on big-endian machines, 160 | * except that the size has to be measured in uint32_ts rather than in 161 | * bytes. jlu32l() is more complicated than jlu32w() only because 162 | * jlu32l() has to dance around fitting the key bytes into registers. 163 | * 164 | * @param h the previous hash, or an arbitrary value 165 | * @param *k the key, an array of uint32_t values 166 | * @param size the size of the key, in uint32_ts 167 | * @return the lookup3 hash 168 | */ 169 | /* -------------------------------------------------------------------- */ 170 | uint32_t jlu32w(uint32_t h, const uint32_t *k, size_t size) 171 | { 172 | uint32_t a = _JLU3_INIT(h, (size * sizeof(*k))); 173 | uint32_t b = a; 174 | uint32_t c = a; 175 | 176 | if (k == NULL) 177 | goto exit; 178 | 179 | /*----------------------------------------------- handle most of the key */ 180 | while (size > 3) { 181 | a += k[0]; 182 | b += k[1]; 183 | c += k[2]; 184 | _JLU3_MIX(a,b,c); 185 | size -= 3; 186 | k += 3; 187 | } 188 | 189 | /*----------------------------------------- handle the last 3 uint32_t's */ 190 | switch (size) { 191 | case 3 : c+=k[2]; 192 | case 2 : b+=k[1]; 193 | case 1 : a+=k[0]; 194 | _JLU3_FINAL(a,b,c); 195 | /* fallthrough */ 196 | case 0: 197 | break; 198 | } 199 | /*---------------------------------------------------- report the result */ 200 | exit: 201 | return c; 202 | } 203 | #endif /* defined(_JLU3_jlu32w) */ 204 | 205 | #if defined(_JLU3_jlu32l) 206 | uint32_t jlu32l(uint32_t h, const void *key, size_t size); 207 | /* -------------------------------------------------------------------- */ 208 | /* 209 | * jlu32l() -- hash a variable-length key into a 32-bit value 210 | * h : can be any 4-byte value 211 | * k : the key (the unaligned variable-length array of bytes) 212 | * size : the size of the key, counting by bytes 213 | * Returns a 32-bit value. Every bit of the key affects every bit of 214 | * the return value. Two keys differing by one or two bits will have 215 | * totally different hash values. 216 | * 217 | * The best hash table sizes are powers of 2. There is no need to do 218 | * mod a prime (mod is sooo slow!). If you need less than 32 bits, 219 | * use a bitmask. For example, if you need only 10 bits, do 220 | * h = (h & hashmask(10)); 221 | * In which case, the hash table should have hashsize(10) elements. 222 | * 223 | * If you are hashing n strings (uint8_t **)k, do it like this: 224 | * for (i=0, h=0; i 12) { 257 | a += k[0]; 258 | b += k[1]; 259 | c += k[2]; 260 | _JLU3_MIX(a,b,c); 261 | size -= 12; 262 | k += 3; 263 | } 264 | 265 | /*------------------------- handle the last (probably partial) block */ 266 | /* 267 | * "k[2]&0xffffff" actually reads beyond the end of the string, but 268 | * then masks off the part it's not allowed to read. Because the 269 | * string is aligned, the masked-off tail is in the same word as the 270 | * rest of the string. Every machine with memory protection I've seen 271 | * does it on word boundaries, so is OK with this. But VALGRIND will 272 | * still catch it and complain. The masking trick does make the hash 273 | * noticeably faster for short strings (like English words). 274 | */ 275 | #ifndef VALGRIND 276 | 277 | switch (size) { 278 | case 12: c += k[2]; b+=k[1]; a+=k[0]; break; 279 | case 11: c += k[2]&0xffffff; b+=k[1]; a+=k[0]; break; 280 | case 10: c += k[2]&0xffff; b+=k[1]; a+=k[0]; break; 281 | case 9: c += k[2]&0xff; b+=k[1]; a+=k[0]; break; 282 | case 8: b += k[1]; a+=k[0]; break; 283 | case 7: b += k[1]&0xffffff; a+=k[0]; break; 284 | case 6: b += k[1]&0xffff; a+=k[0]; break; 285 | case 5: b += k[1]&0xff; a+=k[0]; break; 286 | case 4: a += k[0]; break; 287 | case 3: a += k[0]&0xffffff; break; 288 | case 2: a += k[0]&0xffff; break; 289 | case 1: a += k[0]&0xff; break; 290 | case 0: goto exit; 291 | } 292 | 293 | #else /* make valgrind happy */ 294 | 295 | k8 = (const uint8_t *)k; 296 | switch (size) { 297 | case 12: c += k[2]; b+=k[1]; a+=k[0] break; 298 | case 11: c += ((uint32_t)k8[10])<<16; /* fallthrough */ 299 | case 10: c += ((uint32_t)k8[9])<<8; /* fallthrough */ 300 | case 9: c += k8[8]; /* fallthrough */ 301 | case 8: b += k[1]; a+=k[0]; break; 302 | case 7: b += ((uint32_t)k8[6])<<16; /* fallthrough */ 303 | case 6: b += ((uint32_t)k8[5])<<8; /* fallthrough */ 304 | case 5: b += k8[4]; /* fallthrough */ 305 | case 4: a += k[0]; break; 306 | case 3: a += ((uint32_t)k8[2])<<16; /* fallthrough */ 307 | case 2: a += ((uint32_t)k8[1])<<8; /* fallthrough */ 308 | case 1: a += k8[0]; break; 309 | case 0: goto exit; 310 | } 311 | 312 | #endif /* !valgrind */ 313 | 314 | } else if (HASH_LITTLE_ENDIAN && ((u.i & 0x1) == 0)) { 315 | const uint16_t *k = (const uint16_t *)key; /* read 16-bit chunks */ 316 | const uint8_t *k8; 317 | 318 | /*----------- all but last block: aligned reads and different mixing */ 319 | while (size > 12) { 320 | a += k[0] + (((uint32_t)k[1])<<16); 321 | b += k[2] + (((uint32_t)k[3])<<16); 322 | c += k[4] + (((uint32_t)k[5])<<16); 323 | _JLU3_MIX(a,b,c); 324 | size -= 12; 325 | k += 6; 326 | } 327 | 328 | /*------------------------- handle the last (probably partial) block */ 329 | k8 = (const uint8_t *)k; 330 | switch (size) { 331 | case 12: 332 | c += k[4]+(((uint32_t)k[5])<<16); 333 | b += k[2]+(((uint32_t)k[3])<<16); 334 | a += k[0]+(((uint32_t)k[1])<<16); 335 | break; 336 | case 11: 337 | c += ((uint32_t)k8[10])<<16; 338 | /* fallthrough */ 339 | case 10: 340 | c += (uint32_t)k[4]; 341 | b += k[2]+(((uint32_t)k[3])<<16); 342 | a += k[0]+(((uint32_t)k[1])<<16); 343 | break; 344 | case 9: 345 | c += (uint32_t)k8[8]; 346 | /* fallthrough */ 347 | case 8: 348 | b += k[2]+(((uint32_t)k[3])<<16); 349 | a += k[0]+(((uint32_t)k[1])<<16); 350 | break; 351 | case 7: 352 | b += ((uint32_t)k8[6])<<16; 353 | /* fallthrough */ 354 | case 6: 355 | b += (uint32_t)k[2]; 356 | a += k[0]+(((uint32_t)k[1])<<16); 357 | break; 358 | case 5: 359 | b += (uint32_t)k8[4]; 360 | /* fallthrough */ 361 | case 4: 362 | a += k[0]+(((uint32_t)k[1])<<16); 363 | break; 364 | case 3: 365 | a += ((uint32_t)k8[2])<<16; 366 | /* fallthrough */ 367 | case 2: 368 | a += (uint32_t)k[0]; 369 | break; 370 | case 1: 371 | a += (uint32_t)k8[0]; 372 | break; 373 | case 0: 374 | goto exit; 375 | } 376 | 377 | } else { /* need to read the key one byte at a time */ 378 | const uint8_t *k = (const uint8_t *)key; 379 | 380 | /*----------- all but the last block: affect some 32 bits of (a,b,c) */ 381 | while (size > 12) { 382 | a += (uint32_t)k[0]; 383 | a += ((uint32_t)k[1])<<8; 384 | a += ((uint32_t)k[2])<<16; 385 | a += ((uint32_t)k[3])<<24; 386 | b += (uint32_t)k[4]; 387 | b += ((uint32_t)k[5])<<8; 388 | b += ((uint32_t)k[6])<<16; 389 | b += ((uint32_t)k[7])<<24; 390 | c += (uint32_t)k[8]; 391 | c += ((uint32_t)k[9])<<8; 392 | c += ((uint32_t)k[10])<<16; 393 | c += ((uint32_t)k[11])<<24; 394 | _JLU3_MIX(a,b,c); 395 | size -= 12; 396 | k += 12; 397 | } 398 | 399 | /*---------------------------- last block: affect all 32 bits of (c) */ 400 | switch (size) { 401 | case 12: c += ((uint32_t)k[11])<<24; /* fallthrough */ 402 | case 11: c += ((uint32_t)k[10])<<16; /* fallthrough */ 403 | case 10: c += ((uint32_t)k[9])<<8; /* fallthrough */ 404 | case 9: c += (uint32_t)k[8]; /* fallthrough */ 405 | case 8: b += ((uint32_t)k[7])<<24; /* fallthrough */ 406 | case 7: b += ((uint32_t)k[6])<<16; /* fallthrough */ 407 | case 6: b += ((uint32_t)k[5])<<8; /* fallthrough */ 408 | case 5: b += (uint32_t)k[4]; /* fallthrough */ 409 | case 4: a += ((uint32_t)k[3])<<24; /* fallthrough */ 410 | case 3: a += ((uint32_t)k[2])<<16; /* fallthrough */ 411 | case 2: a += ((uint32_t)k[1])<<8; /* fallthrough */ 412 | case 1: a += (uint32_t)k[0]; 413 | break; 414 | case 0: 415 | goto exit; 416 | } 417 | } 418 | 419 | _JLU3_FINAL(a,b,c); 420 | 421 | exit: 422 | return c; 423 | } 424 | #endif /* defined(_JLU3_jlu32l) */ 425 | 426 | #if defined(_JLU3_jlu32lpair) 427 | /** 428 | * jlu32lpair: return 2 32-bit hash values. 429 | * 430 | * This is identical to jlu32l(), except it returns two 32-bit hash 431 | * values instead of just one. This is good enough for hash table 432 | * lookup with 2^^64 buckets, or if you want a second hash if you're not 433 | * happy with the first, or if you want a probably-unique 64-bit ID for 434 | * the key. *pc is better mixed than *pb, so use *pc first. If you want 435 | * a 64-bit value do something like "*pc + (((uint64_t)*pb)<<32)". 436 | * 437 | * @param h the previous hash, or an arbitrary value 438 | * @param *key the key, an array of uint8_t values 439 | * @param size the size of the key in bytes 440 | * @retval *pc, IN: primary initval, OUT: primary hash 441 | * *retval *pb IN: secondary initval, OUT: secondary hash 442 | */ 443 | void jlu32lpair(const void *key, size_t size, uint32_t *pc, uint32_t *pb) 444 | { 445 | union { const void *ptr; size_t i; } u; 446 | uint32_t a = _JLU3_INIT(*pc, size); 447 | uint32_t b = a; 448 | uint32_t c = a; 449 | 450 | if (key == NULL) 451 | goto exit; 452 | 453 | c += *pb; /* Add the secondary hash. */ 454 | 455 | u.ptr = key; 456 | if (HASH_LITTLE_ENDIAN && ((u.i & 0x3) == 0)) { 457 | const uint32_t *k = (const uint32_t *)key; /* read 32-bit chunks */ 458 | #ifdef VALGRIND 459 | const uint8_t *k8; 460 | #endif 461 | 462 | /*-- all but last block: aligned reads and affect 32 bits of (a,b,c) */ 463 | while (size > (size_t)12) { 464 | a += k[0]; 465 | b += k[1]; 466 | c += k[2]; 467 | _JLU3_MIX(a,b,c); 468 | size -= 12; 469 | k += 3; 470 | } 471 | /*------------------------- handle the last (probably partial) block */ 472 | /* 473 | * "k[2]&0xffffff" actually reads beyond the end of the string, but 474 | * then masks off the part it's not allowed to read. Because the 475 | * string is aligned, the masked-off tail is in the same word as the 476 | * rest of the string. Every machine with memory protection I've seen 477 | * does it on word boundaries, so is OK with this. But VALGRIND will 478 | * still catch it and complain. The masking trick does make the hash 479 | * noticeably faster for short strings (like English words). 480 | */ 481 | #ifndef VALGRIND 482 | 483 | switch (size) { 484 | case 12: c += k[2]; b+=k[1]; a+=k[0]; break; 485 | case 11: c += k[2]&0xffffff; b+=k[1]; a+=k[0]; break; 486 | case 10: c += k[2]&0xffff; b+=k[1]; a+=k[0]; break; 487 | case 9: c += k[2]&0xff; b+=k[1]; a+=k[0]; break; 488 | case 8: b += k[1]; a+=k[0]; break; 489 | case 7: b += k[1]&0xffffff; a+=k[0]; break; 490 | case 6: b += k[1]&0xffff; a+=k[0]; break; 491 | case 5: b += k[1]&0xff; a+=k[0]; break; 492 | case 4: a += k[0]; break; 493 | case 3: a += k[0]&0xffffff; break; 494 | case 2: a += k[0]&0xffff; break; 495 | case 1: a += k[0]&0xff; break; 496 | case 0: goto exit; 497 | } 498 | 499 | #else /* make valgrind happy */ 500 | 501 | k8 = (const uint8_t *)k; 502 | switch (size) { 503 | case 12: c += k[2]; b+=k[1]; a+=k[0]; break; 504 | case 11: c += ((uint32_t)k8[10])<<16; /* fallthrough */ 505 | case 10: c += ((uint32_t)k8[9])<<8; /* fallthrough */ 506 | case 9: c += k8[8]; /* fallthrough */ 507 | case 8: b += k[1]; a+=k[0]; break; 508 | case 7: b += ((uint32_t)k8[6])<<16; /* fallthrough */ 509 | case 6: b += ((uint32_t)k8[5])<<8; /* fallthrough */ 510 | case 5: b += k8[4]; /* fallthrough */ 511 | case 4: a += k[0]; break; 512 | case 3: a += ((uint32_t)k8[2])<<16; /* fallthrough */ 513 | case 2: a += ((uint32_t)k8[1])<<8; /* fallthrough */ 514 | case 1: a += k8[0]; break; 515 | case 0: goto exit; 516 | } 517 | 518 | #endif /* !valgrind */ 519 | 520 | } else if (HASH_LITTLE_ENDIAN && ((u.i & 0x1) == 0)) { 521 | const uint16_t *k = (const uint16_t *)key; /* read 16-bit chunks */ 522 | const uint8_t *k8; 523 | 524 | /*----------- all but last block: aligned reads and different mixing */ 525 | while (size > (size_t)12) { 526 | a += k[0] + (((uint32_t)k[1])<<16); 527 | b += k[2] + (((uint32_t)k[3])<<16); 528 | c += k[4] + (((uint32_t)k[5])<<16); 529 | _JLU3_MIX(a,b,c); 530 | size -= 12; 531 | k += 6; 532 | } 533 | 534 | /*------------------------- handle the last (probably partial) block */ 535 | k8 = (const uint8_t *)k; 536 | switch (size) { 537 | case 12: 538 | c += k[4]+(((uint32_t)k[5])<<16); 539 | b += k[2]+(((uint32_t)k[3])<<16); 540 | a += k[0]+(((uint32_t)k[1])<<16); 541 | break; 542 | case 11: 543 | c += ((uint32_t)k8[10])<<16; 544 | /* fallthrough */ 545 | case 10: 546 | c += k[4]; 547 | b += k[2]+(((uint32_t)k[3])<<16); 548 | a += k[0]+(((uint32_t)k[1])<<16); 549 | break; 550 | case 9: 551 | c += k8[8]; 552 | /* fallthrough */ 553 | case 8: 554 | b += k[2]+(((uint32_t)k[3])<<16); 555 | a += k[0]+(((uint32_t)k[1])<<16); 556 | break; 557 | case 7: 558 | b += ((uint32_t)k8[6])<<16; 559 | /* fallthrough */ 560 | case 6: 561 | b += k[2]; 562 | a += k[0]+(((uint32_t)k[1])<<16); 563 | break; 564 | case 5: 565 | b += k8[4]; 566 | /* fallthrough */ 567 | case 4: 568 | a += k[0]+(((uint32_t)k[1])<<16); 569 | break; 570 | case 3: 571 | a += ((uint32_t)k8[2])<<16; 572 | /* fallthrough */ 573 | case 2: 574 | a += k[0]; 575 | break; 576 | case 1: 577 | a += k8[0]; 578 | break; 579 | case 0: 580 | goto exit; 581 | } 582 | 583 | } else { /* need to read the key one byte at a time */ 584 | const uint8_t *k = (const uint8_t *)key; 585 | 586 | /*----------- all but the last block: affect some 32 bits of (a,b,c) */ 587 | while (size > (size_t)12) { 588 | a += k[0]; 589 | a += ((uint32_t)k[1])<<8; 590 | a += ((uint32_t)k[2])<<16; 591 | a += ((uint32_t)k[3])<<24; 592 | b += k[4]; 593 | b += ((uint32_t)k[5])<<8; 594 | b += ((uint32_t)k[6])<<16; 595 | b += ((uint32_t)k[7])<<24; 596 | c += k[8]; 597 | c += ((uint32_t)k[9])<<8; 598 | c += ((uint32_t)k[10])<<16; 599 | c += ((uint32_t)k[11])<<24; 600 | _JLU3_MIX(a,b,c); 601 | size -= 12; 602 | k += 12; 603 | } 604 | 605 | /*---------------------------- last block: affect all 32 bits of (c) */ 606 | switch (size) { 607 | case 12: c += ((uint32_t)k[11])<<24; /* fallthrough */ 608 | case 11: c += ((uint32_t)k[10])<<16; /* fallthrough */ 609 | case 10: c += ((uint32_t)k[9])<<8; /* fallthrough */ 610 | case 9: c += k[8]; /* fallthrough */ 611 | case 8: b += ((uint32_t)k[7])<<24; /* fallthrough */ 612 | case 7: b += ((uint32_t)k[6])<<16; /* fallthrough */ 613 | case 6: b += ((uint32_t)k[5])<<8; /* fallthrough */ 614 | case 5: b += k[4]; /* fallthrough */ 615 | case 4: a += ((uint32_t)k[3])<<24; /* fallthrough */ 616 | case 3: a += ((uint32_t)k[2])<<16; /* fallthrough */ 617 | case 2: a += ((uint32_t)k[1])<<8; /* fallthrough */ 618 | case 1: a += k[0]; 619 | break; 620 | case 0: 621 | goto exit; 622 | } 623 | } 624 | 625 | _JLU3_FINAL(a,b,c); 626 | 627 | exit: 628 | *pc = c; 629 | *pb = b; 630 | return; 631 | } 632 | #endif /* defined(_JLU3_jlu32lpair) */ 633 | 634 | #if defined(_JLU3_jlu32b) 635 | uint32_t jlu32b(uint32_t h, const void *key, size_t size); 636 | /* 637 | * jlu32b(): 638 | * This is the same as jlu32w() on big-endian machines. It is different 639 | * from jlu32l() on all machines. jlu32b() takes advantage of 640 | * big-endian byte ordering. 641 | * 642 | * @param h the previous hash, or an arbitrary value 643 | * @param *k the key, an array of uint8_t values 644 | * @param size the size of the key 645 | * @return the lookup3 hash 646 | */ 647 | uint32_t jlu32b(uint32_t h, const void *key, size_t size) 648 | { 649 | union { const void *ptr; size_t i; } u; 650 | uint32_t a = _JLU3_INIT(h, size); 651 | uint32_t b = a; 652 | uint32_t c = a; 653 | 654 | if (key == NULL) 655 | return h; 656 | 657 | u.ptr = key; 658 | if (HASH_BIG_ENDIAN && ((u.i & 0x3) == 0)) { 659 | const uint32_t *k = (const uint32_t *)key; /* read 32-bit chunks */ 660 | #ifdef VALGRIND 661 | const uint8_t *k8; 662 | #endif 663 | 664 | /*-- all but last block: aligned reads and affect 32 bits of (a,b,c) */ 665 | while (size > 12) { 666 | a += k[0]; 667 | b += k[1]; 668 | c += k[2]; 669 | _JLU3_MIX(a,b,c); 670 | size -= 12; 671 | k += 3; 672 | } 673 | 674 | /*------------------------- handle the last (probably partial) block */ 675 | /* 676 | * "k[2]<<8" actually reads beyond the end of the string, but 677 | * then shifts out the part it's not allowed to read. Because the 678 | * string is aligned, the illegal read is in the same word as the 679 | * rest of the string. Every machine with memory protection I've seen 680 | * does it on word boundaries, so is OK with this. But VALGRIND will 681 | * still catch it and complain. The masking trick does make the hash 682 | * noticeably faster for short strings (like English words). 683 | */ 684 | #ifndef VALGRIND 685 | 686 | switch (size) { 687 | case 12: c += k[2]; b+=k[1]; a+=k[0]; break; 688 | case 11: c += k[2]&0xffffff00; b+=k[1]; a+=k[0]; break; 689 | case 10: c += k[2]&0xffff0000; b+=k[1]; a+=k[0]; break; 690 | case 9: c += k[2]&0xff000000; b+=k[1]; a+=k[0]; break; 691 | case 8: b += k[1]; a+=k[0]; break; 692 | case 7: b += k[1]&0xffffff00; a+=k[0]; break; 693 | case 6: b += k[1]&0xffff0000; a+=k[0]; break; 694 | case 5: b += k[1]&0xff000000; a+=k[0]; break; 695 | case 4: a += k[0]; break; 696 | case 3: a += k[0]&0xffffff00; break; 697 | case 2: a += k[0]&0xffff0000; break; 698 | case 1: a += k[0]&0xff000000; break; 699 | case 0: goto exit; 700 | } 701 | 702 | #else /* make valgrind happy */ 703 | 704 | k8 = (const uint8_t *)k; 705 | switch (size) { /* all the case statements fall through */ 706 | case 12: c += k[2]; b+=k[1]; a+=k[0]; break; 707 | case 11: c += ((uint32_t)k8[10])<<8; /* fallthrough */ 708 | case 10: c += ((uint32_t)k8[9])<<16; /* fallthrough */ 709 | case 9: c += ((uint32_t)k8[8])<<24; /* fallthrough */ 710 | case 8: b += k[1]; a+=k[0]; break; 711 | case 7: b += ((uint32_t)k8[6])<<8; /* fallthrough */ 712 | case 6: b += ((uint32_t)k8[5])<<16; /* fallthrough */ 713 | case 5: b += ((uint32_t)k8[4])<<24; /* fallthrough */ 714 | case 4: a += k[0]; break; 715 | case 3: a += ((uint32_t)k8[2])<<8; /* fallthrough */ 716 | case 2: a += ((uint32_t)k8[1])<<16; /* fallthrough */ 717 | case 1: a += ((uint32_t)k8[0])<<24; break; 718 | case 0: goto exit; 719 | } 720 | 721 | #endif /* !VALGRIND */ 722 | 723 | } else { /* need to read the key one byte at a time */ 724 | const uint8_t *k = (const uint8_t *)key; 725 | 726 | /*----------- all but the last block: affect some 32 bits of (a,b,c) */ 727 | while (size > 12) { 728 | a += ((uint32_t)k[0])<<24; 729 | a += ((uint32_t)k[1])<<16; 730 | a += ((uint32_t)k[2])<<8; 731 | a += ((uint32_t)k[3]); 732 | b += ((uint32_t)k[4])<<24; 733 | b += ((uint32_t)k[5])<<16; 734 | b += ((uint32_t)k[6])<<8; 735 | b += ((uint32_t)k[7]); 736 | c += ((uint32_t)k[8])<<24; 737 | c += ((uint32_t)k[9])<<16; 738 | c += ((uint32_t)k[10])<<8; 739 | c += ((uint32_t)k[11]); 740 | _JLU3_MIX(a,b,c); 741 | size -= 12; 742 | k += 12; 743 | } 744 | 745 | /*---------------------------- last block: affect all 32 bits of (c) */ 746 | switch (size) { /* all the case statements fall through */ 747 | case 12: c += k[11]; /* fallthrough */ 748 | case 11: c += ((uint32_t)k[10])<<8; /* fallthrough */ 749 | case 10: c += ((uint32_t)k[9])<<16; /* fallthrough */ 750 | case 9: c += ((uint32_t)k[8])<<24; /* fallthrough */ 751 | case 8: b += k[7]; /* fallthrough */ 752 | case 7: b += ((uint32_t)k[6])<<8; /* fallthrough */ 753 | case 6: b += ((uint32_t)k[5])<<16; /* fallthrough */ 754 | case 5: b += ((uint32_t)k[4])<<24; /* fallthrough */ 755 | case 4: a += k[3]; /* fallthrough */ 756 | case 3: a += ((uint32_t)k[2])<<8; /* fallthrough */ 757 | case 2: a += ((uint32_t)k[1])<<16; /* fallthrough */ 758 | case 1: a += ((uint32_t)k[0])<<24; /* fallthrough */ 759 | break; 760 | case 0: 761 | goto exit; 762 | } 763 | } 764 | 765 | _JLU3_FINAL(a,b,c); 766 | 767 | exit: 768 | return c; 769 | } 770 | #endif /* defined(_JLU3_jlu32b) */ 771 | 772 | #if defined(_JLU3_SELFTEST) 773 | 774 | /* used for timings */ 775 | static void driver1(void) 776 | { 777 | uint8_t buf[256]; 778 | uint32_t i; 779 | uint32_t h=0; 780 | time_t a,z; 781 | 782 | time(&a); 783 | for (i=0; i<256; ++i) buf[i] = 'x'; 784 | for (i=0; i<1; ++i) { 785 | h = jlu32l(h, &buf[0], sizeof(buf[0])); 786 | } 787 | time(&z); 788 | if (z-a > 0) printf("time %d %.8x\n", (int)(z-a), h); 789 | } 790 | 791 | /* check that every input bit changes every output bit half the time */ 792 | #define HASHSTATE 1 793 | #define HASHLEN 1 794 | #define MAXPAIR 60 795 | #define MAXLEN 70 796 | static void driver2(void) 797 | { 798 | uint8_t qa[MAXLEN+1], qb[MAXLEN+2], *a = &qa[0], *b = &qb[1]; 799 | uint32_t c[HASHSTATE], d[HASHSTATE], i=0, j=0, k, l, m=0, z; 800 | uint32_t e[HASHSTATE],f[HASHSTATE],g[HASHSTATE],h[HASHSTATE]; 801 | uint32_t x[HASHSTATE],y[HASHSTATE]; 802 | uint32_t hlen; 803 | 804 | printf("No more than %d trials should ever be needed \n",MAXPAIR/2); 805 | for (hlen=0; hlen < MAXLEN; ++hlen) { 806 | z=0; 807 | for (i=0; i>(8-j)); 821 | c[0] = jlu32l(m, a, hlen); 822 | b[i] ^= ((k+1)<>(8-j)); 824 | d[0] = jlu32l(m, b, hlen); 825 | /* check every bit is 1, 0, set, and not set at least once */ 826 | for (l=0; lz) z=k; 838 | if (k == MAXPAIR) { 839 | printf("Some bit didn't change: "); 840 | printf("%.8x %.8x %.8x %.8x %.8x %.8x ", 841 | e[0],f[0],g[0],h[0],x[0],y[0]); 842 | printf("i %u j %u m %u len %u\n", i, j, m, hlen); 843 | } 844 | if (z == MAXPAIR) goto done; 845 | } 846 | } 847 | } 848 | done: 849 | if (z < MAXPAIR) { 850 | printf("Mix success %2u bytes %2u initvals ",i,m); 851 | printf("required %u trials\n", z/2); 852 | } 853 | } 854 | printf("\n"); 855 | } 856 | 857 | /* Check for reading beyond the end of the buffer and alignment problems */ 858 | static void driver3(void) 859 | { 860 | uint8_t buf[MAXLEN+20], *b; 861 | uint32_t len; 862 | uint8_t q[] = "This is the time for all good men to come to the aid of their country..."; 863 | uint32_t h; 864 | uint8_t qq[] = "xThis is the time for all good men to come to the aid of their country..."; 865 | uint32_t i; 866 | uint8_t qqq[] = "xxThis is the time for all good men to come to the aid of their country..."; 867 | uint32_t j; 868 | uint8_t qqqq[] = "xxxThis is the time for all good men to come to the aid of their country..."; 869 | uint32_t ref,x,y; 870 | uint8_t *p; 871 | uint32_t m = 13; 872 | 873 | printf("Endianness. These lines should all be the same (for values filled in):\n"); 874 | printf("%.8x %.8x %.8x\n", 875 | jlu32w(m, (const uint32_t *)q, (sizeof(q)-1)/4), 876 | jlu32w(m, (const uint32_t *)q, (sizeof(q)-5)/4), 877 | jlu32w(m, (const uint32_t *)q, (sizeof(q)-9)/4)); 878 | p = q; 879 | printf("%.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x\n", 880 | jlu32l(m, p, sizeof(q)-1), jlu32l(m, p, sizeof(q)-2), 881 | jlu32l(m, p, sizeof(q)-3), jlu32l(m, p, sizeof(q)-4), 882 | jlu32l(m, p, sizeof(q)-5), jlu32l(m, p, sizeof(q)-6), 883 | jlu32l(m, p, sizeof(q)-7), jlu32l(m, p, sizeof(q)-8), 884 | jlu32l(m, p, sizeof(q)-9), jlu32l(m, p, sizeof(q)-10), 885 | jlu32l(m, p, sizeof(q)-11), jlu32l(m, p, sizeof(q)-12)); 886 | p = &qq[1]; 887 | printf("%.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x\n", 888 | jlu32l(m, p, sizeof(q)-1), jlu32l(m, p, sizeof(q)-2), 889 | jlu32l(m, p, sizeof(q)-3), jlu32l(m, p, sizeof(q)-4), 890 | jlu32l(m, p, sizeof(q)-5), jlu32l(m, p, sizeof(q)-6), 891 | jlu32l(m, p, sizeof(q)-7), jlu32l(m, p, sizeof(q)-8), 892 | jlu32l(m, p, sizeof(q)-9), jlu32l(m, p, sizeof(q)-10), 893 | jlu32l(m, p, sizeof(q)-11), jlu32l(m, p, sizeof(q)-12)); 894 | p = &qqq[2]; 895 | printf("%.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x\n", 896 | jlu32l(m, p, sizeof(q)-1), jlu32l(m, p, sizeof(q)-2), 897 | jlu32l(m, p, sizeof(q)-3), jlu32l(m, p, sizeof(q)-4), 898 | jlu32l(m, p, sizeof(q)-5), jlu32l(m, p, sizeof(q)-6), 899 | jlu32l(m, p, sizeof(q)-7), jlu32l(m, p, sizeof(q)-8), 900 | jlu32l(m, p, sizeof(q)-9), jlu32l(m, p, sizeof(q)-10), 901 | jlu32l(m, p, sizeof(q)-11), jlu32l(m, p, sizeof(q)-12)); 902 | p = &qqqq[3]; 903 | printf("%.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x\n", 904 | jlu32l(m, p, sizeof(q)-1), jlu32l(m, p, sizeof(q)-2), 905 | jlu32l(m, p, sizeof(q)-3), jlu32l(m, p, sizeof(q)-4), 906 | jlu32l(m, p, sizeof(q)-5), jlu32l(m, p, sizeof(q)-6), 907 | jlu32l(m, p, sizeof(q)-7), jlu32l(m, p, sizeof(q)-8), 908 | jlu32l(m, p, sizeof(q)-9), jlu32l(m, p, sizeof(q)-10), 909 | jlu32l(m, p, sizeof(q)-11), jlu32l(m, p, sizeof(q)-12)); 910 | printf("\n"); 911 | for (h=0, b=buf+1; h<8; ++h, ++b) { 912 | for (i=0; i 9 | .sp 10 | .BI "poptContext poptGetContext(const char * " name ", int " argc , 11 | .BI " const char ** "argv , 12 | .BI " const struct poptOption * " options , 13 | .BI " unsigned int " flags ); 14 | .sp 15 | .BI "poptContext poptFreeContext(poptContext " con ); 16 | .sp 17 | .BI "void poptResetContext(poptContext " con ); 18 | .sp 19 | .BI "int poptGetNextOpt(poptContext " con ); 20 | .sp 21 | .BI "const char * poptGetOptArg(poptContext " con ); 22 | .sp 23 | .BI "const char * poptGetArg(poptContext " con ); 24 | .sp 25 | .BI "const char * poptPeekArg(poptContext " con ); 26 | .sp 27 | .BI "const char ** poptGetArgs(poptContext " con ); 28 | .sp 29 | .BI "const char *const poptStrerror(const int " error ); 30 | .sp 31 | .BI "const char * poptBadOption(poptContext " con ", int " flags ); 32 | .sp 33 | .BI "int poptReadDefaultConfig(poptContext " con ", int " flags ); 34 | .sp 35 | .BI "int poptReadConfigFile(poptContext " con ", char * " fn ); 36 | .sp 37 | .BI "int poptAddAlias(poptContext " con ", struct poptAlias " alias , 38 | .BI " int " flags ); 39 | .sp 40 | .BI "int poptParseArgvString(char * " s ", int * " argcPtr , 41 | .BI " const char *** " argvPtr ); 42 | .sp 43 | .BI "int poptDupArgv(int " argc ", const char ** " argv ", int * " argcPtr ", 44 | .BI " const char *** " argvPtr ");" 45 | .sp 46 | .BI "int poptStuffArgs(poptContext " con ", const char ** " argv ); 47 | .sp 48 | .fi 49 | .SH DESCRIPTION 50 | The popt library exists essentially for parsing command-line 51 | options. It is found superior in many ways when compared to 52 | parsing the argv array by hand or using the getopt functions 53 | .B getopt() 54 | and 55 | .B getopt_long() 56 | [see 57 | .BR getopt "(3)]." 58 | Some specific advantages of popt are: it does not utilize global 59 | .RI "variables, thus enabling multiple passes in parsing " argv 60 | .RI "; it can parse an arbitrary array of " argv "-style elements, " 61 | allowing parsing of command-line-strings from any source; 62 | it provides a standard method of option aliasing (to be 63 | discussed at length below.); it can exec external option filters; and, 64 | finally, it can automatically generate help and usage messages for 65 | the application. 66 | .sp 67 | Like 68 | .BR getopt_long() , 69 | the popt library supports short and long style options. Recall 70 | that a 71 | .B short option 72 | consists of a - character followed by a single alphanumeric character. 73 | A 74 | .BR "long option" , 75 | common in GNU utilities, consists of two - characters followed by a 76 | string made up of letters, numbers and hyphens. Long options are 77 | optionally allowed to begin with a single -, primarily to allow command-line 78 | compatibility between popt applications and X toolkit applications. 79 | Either type of option may be followed by an argument. A space separates a 80 | short option from its arguments; either a space or an = separates a long 81 | option from an argument. 82 | .sp 83 | The popt library is highly portable and should work on any POSIX 84 | platform. The latest version is distributed with rpm and is always available 85 | from: http://ftp.rpm.org/popt/releases/. 86 | .sp 87 | It may be redistributed under the MIT license, see the file COPYING 88 | in the popt source distribution for details. 89 | .SH "BASIC POPT USAGE" 90 | .SS "1. THE OPTION TABLE" 91 | Applications provide popt with information on their command-line 92 | options by means of an "option table," i.e., an array of 93 | .B struct poptOption 94 | structures: 95 | .sp 96 | #include 97 | .sp 98 | .nf 99 | struct poptOption { 100 | const char * longName; /* may be NULL */ 101 | char shortName; /* may be '\\0' */ 102 | unsigned int argInfo; /* type of argument expected after the option */ 103 | void * arg; /* depends on argInfo */ 104 | int val; /* 0 means don't return, just update arg */ 105 | const char * descrip; /* description for autohelp -- may be NULL */ 106 | const char * argDescrip; /* argument description for autohelp -- may be NULL*/ 107 | }; 108 | .fi 109 | .sp 110 | Each member of the table defines a single option that may be 111 | passed to the program. Long and short options are considered 112 | a single option that may occur in two different forms. The 113 | first two members, 114 | .IR longName " and " shortName ", define the names of the option;" 115 | the first is a long name, while the latter is a single character. 116 | .sp 117 | The 118 | .IR argInfo " member tells popt what type of argument is expected" 119 | after the option. If no argument is expected, 120 | .B POPT_ARG_NONE 121 | should be used. 122 | The valid values of 123 | .IR argInfo 124 | are shown in the following table: 125 | .sp 126 | .TS 127 | lfB lfB lfB 128 | lfB lfR lfR. 129 | Value Description arg Type 130 | POPT_ARG_NONE No argument expected int 131 | POPT_ARG_STRING No type checking to be performed char * 132 | POPT_ARG_ARGV No type checking to be performed char ** 133 | POPT_ARG_SHORT A short argument is expected short 134 | POPT_ARG_INT An integer argument is expected int 135 | POPT_ARG_LONG A long integer is expected long 136 | POPT_ARG_LONGLONG A long long integer is expected long long 137 | POPT_ARG_VAL Integer value taken from \f(CWval\fR int 138 | POPT_ARG_FLOAT A float argument is expected float 139 | POPT_ARG_DOUBLE A double argument is expected double 140 | .TE 141 | .sp 142 | For numeric values, if the \fIargInfo\fR value is bitwise or'd with one of 143 | \fBPOPT_ARGFLAG_OR\fR, \fBPOPT_ARGFLAG_AND\fR, or \fBPOPT_ARGFLAG_XOR\fR, 144 | the value is saved by performing an OR, AND, or XOR. 145 | If the \fIargInfo\fR value is bitwise or'd with \fBPOPT_ARGFLAG_NOT\fR, 146 | the value will be negated before saving. For the common operations of 147 | setting and/or clearing bits, \fBPOPT_BIT_SET\fR and \fBPOPT_BIT_CLR\fR 148 | have the appropriate flags set to perform bit operations. 149 | .sp 150 | If the \fIargInfo\fR value is bitwise or'd with \fBPOPT_ARGFLAG_ONEDASH\fR, 151 | the long argument may be given with a single - instead of two. For example, 152 | if \fB--longopt\fR is an option with \fBPOPT_ARGFLAG_ONEDASH\fR, is 153 | specified, \fB-longopt\fR is accepted as well. 154 | .sp 155 | .RI "The next element, " arg ", allows popt to automatically update " 156 | .RI "program variables when the option is used. If " arg " is " 157 | .BR NULL ", it is ignored and popt takes no special action. " 158 | Otherwise it should point to a variable of the type indicated in the 159 | .RB "right-most column of the table above. A " POPT_ARG_ARGV " arg will 160 | (re-)allocate an array of char * string pointers, append the string argument, and add a 161 | .BR NULL " sentinel at the end of the array as needed." 162 | .RB "The target char ** address of a " POPT_ARG_ARGV " arg should be initialized to " NULL "." 163 | .sp 164 | .RI "If the option takes no argument (" argInfo " is " 165 | .BR POPT_ARG_NONE "), the variable pointed to by " 166 | .IR arg " is set to 1 when the option is used. (Incidentally, it " 167 | will perhaps not escape the attention of hunt-and-peck typists that 168 | .RB "the value of " POPT_ARG_NONE " is 0.) If the option does take " 169 | an argument, the variable that 170 | .IR arg " points to is updated to reflect the value of the argument." 171 | .RB "Any string is acceptable for " POPT_ARG_STRING " and " POPT_ARG_ARGV " arguments, but " 172 | .BR POPT_ARG_INT ", " POPT_ARG_SHORT ", " POPT_ARG_LONG ", " POPT_ARG_LONGLONG ", " POPT_ARG_FLOAT ", and " 173 | .BR POPT_ARG_DOUBLE " are converted to the appropriate type, and an " 174 | error returned if the conversion fails. 175 | .sp 176 | \fBPOPT_ARG_VAL\fR causes \fIarg\fP to be set to the (integer) value of 177 | \fIval\fP when the argument is found. This is most often useful for 178 | mutually-exclusive arguments in cases where it is not an error for 179 | multiple arguments to occur and where you want the last argument 180 | specified to win; for example, "rm -i -f". \fBPOPT_ARG_VAL\fP causes 181 | the parsing function not to return a value, since the value of \fIval\fP 182 | has already been used. 183 | .sp 184 | If the \fIargInfo\fR value is bitwise or'd with \fBPOPT_ARGFLAG_OPTIONAL\fR, 185 | the argument to the long option may be omitted. If the long option 186 | is used without an argument, a default value of zero or NULL will be saved 187 | (if the arg pointer is present), otherwise behavior will be identical to 188 | a long option with argument. 189 | .sp 190 | .RI "The next option, " val ", is the value popt's parsing function 191 | should return when the option is encountered. If it is 0, the parsing 192 | function does not return a value, instead parsing the next 193 | command-line argument. 194 | .sp 195 | .RI "The last two options, " descrip " and " argDescrip " are only required 196 | if automatic help messages are desired (automatic usage messages can 197 | .RI "be generated without them). " descrip " is a text description of the 198 | .RI "argument and " argDescrip " is a short summary of the type of arguments 199 | .RI "the option expects, or NULL if the option doesn't require any 200 | arguments. 201 | .sp 202 | .RB "If popt should automatically provide " --usage " and " --help " (" -? ") 203 | .RB "options, one line in the table should be the macro " POPT_AUTOHELP ". 204 | .RB "This macro includes another option table (via " POPT_ARG_INCLUDE_TABLE 205 | ; see below) in the main one which provides the table entries for these 206 | .RB "arguments. When " --usage " or " --help " are passed to programs which 207 | use popt's automatic help, popt displays the appropriate message on 208 | stderr as soon as it finds the option, and exits the program with a 209 | return code of 0. If you want to use popt's automatic help generation in 210 | a different way, you need to explicitly add the option entries to your programs 211 | .RB "option table instead of using " POPT_AUTOHELP ". 212 | .sp 213 | If the \fIargInfo\fR value is bitwise or'd with \fBPOPT_ARGFLAG_DOC_HIDDEN\fR, 214 | the argument will not be shown in help output. 215 | .sp 216 | If the \fIargInfo\fR value is bitwise or'd with \fBPOPT_ARGFLAG_SHOW_DEFAULT\fR, 217 | the initial value of the arg will be shown in help output. 218 | .sp 219 | The final structure in the table should have all the pointer values set 220 | .RB "to " NULL " and all the arithmetic values set to 0, marking the " 221 | .RB "end of the table. The macro " POPT_TABLEEND " is provided to do that. 222 | .sp 223 | There are two types of option table entries which do not specify command 224 | line options. When either of these types of entries are used, the 225 | \fIlongName\fR element must be \fBNULL\fR and the \fBshortName\fR element 226 | must be \fB'\\0'\fR. 227 | .sp 228 | The first of these special entry types allows the application to nest 229 | another option table in the current one; such nesting may extend quite 230 | deeply (the actual depth is limited by the program's stack). Including 231 | other option tables allows a library to provide a standard set of 232 | command-line options to every program which uses it (this is often done 233 | in graphical programming toolkits, for example). To do this, set 234 | the \fIargInfo\fR field to \fBPOPT_ARG_INCLUDE_TABLE\fR and the 235 | \fRarg\fR field to point to the table which is being included. If 236 | automatic help generation is being used, the \fIdescrip\fR field should 237 | contain an overall description of the option table being included. 238 | .sp 239 | The other special option table entry type tells popt to call a function (a 240 | callback) when any option in that table is found. This is especially useful 241 | when included option tables are being used, as the program which provides 242 | the top-level option table doesn't need to be aware of the other options 243 | which are provided by the included table. When a callback is set for 244 | a table, the parsing function never returns information on an option in 245 | the table. Instead, options information must be retained via the callback 246 | or by having popt set a variable through the option's \fIarg\fR field. 247 | Option callbacks should match the following prototype: 248 | .sp 249 | .nf 250 | .BI "void poptCallbackType(poptContext con, 251 | .BI " enum poptCallbackReason reason, 252 | .BI " const struct poptOption * opt, 253 | .BI " const char * arg, const void * data); 254 | .fi 255 | .sp 256 | The first parameter is the context which is being parsed (see the next 257 | section for information on contexts). \fIreason\fR is 258 | \fBPOPT_CALLBACK_REASON_PRE\fR, \fBPOPT_CALLBACK_REASON_POST\fR, or 259 | \fBPOPT_CALLBACK_REASON_OPTION\fR. \fIopt\fR points to the option 260 | which triggered this callback, and \fIarg\fR is the option's argument. 261 | If the option does not take an argument, \fIarg\fR is \fBNULL\fR. The 262 | final parameter, \fIdata\fR is taken from the \fIdescrip\fR field 263 | of the option table entry which defined the callback. As \fIdescrip\fR 264 | is a pointer, this allows callback functions to be passed an arbitrary 265 | set of data (though a typecast will have to be used). 266 | .sp 267 | The option table entry which defines a callback has an \fIargInfo\fR of 268 | \fBPOPT_ARG_CALLBACK\fR, an \fIarg\fR which points to the callback 269 | function, and a \fIdescrip\fR field which specifies an arbitrary pointer 270 | to be passed to the callback. 271 | .SS "2. CREATING A CONTEXT" 272 | popt can interleave the parsing of multiple command-line sets. It allows 273 | this by keeping all the state information for a particular set of 274 | command-line arguments in a 275 | .BR poptContext " data structure, an opaque type that should not be " 276 | modified outside the popt library. 277 | .sp 278 | .RB "New popt contexts are created by " poptGetContext() ":" 279 | .sp 280 | .nf 281 | .BI "poptContext poptGetContext(const char * " name ", int "argc ", 282 | .BI " const char ** "argv ", 283 | .BI " const struct poptOption * "options ", 284 | .BI " unsigned int "flags ");" 285 | .fi 286 | .sp 287 | The first parameter, 288 | .IR name ", is used only for alias handling (discussed later). It " 289 | should be the name of the application whose options are being parsed, 290 | .RB "or should be " NULL " if no option aliasing is desired. The next " 291 | two arguments specify the command-line arguments to parse. These are 292 | .RB "generally passed to " poptGetContext() " exactly as they were " 293 | .RB "passed to the program's " main() " function. The " 294 | .IR options " parameter points to the table of command-line options, " 295 | which was described in the previous section. The final parameter, 296 | .IR flags , 297 | can be any bitwise or combination of the following four values: 298 | .br 299 | .TS 300 | lfB lfB 301 | lfB lfR. 302 | Value Description 303 | POPT_CONTEXT_NO_EXEC Ignore exec expansions 304 | POPT_CONTEXT_KEEP_FIRST Do not ignore argv[0] 305 | POPT_CONTEXT_POSIXMEHARDER Options cannot follow arguments 306 | POPT_CONTEXT_ARG_OPTS Return the arguments as options of value 0 307 | .TE 308 | .sp 309 | Here is a more detailed discussion of each flag: 310 | .sp 311 | .TP 312 | .B POPT_CONTEXT_NO_EXEC 313 | This bit disables all uses of 314 | .BR exec "(2) from within the given popt context." 315 | .sp 316 | .TP 317 | .B POPT_CONTEXT_KEEP_FIRST 318 | By default, popt ignores the value in 319 | .I argv[0] 320 | as it is typically the name of the program being run rather than a command-line 321 | argument. Specifying this flag causes popt to treat 322 | .I argv[0] 323 | as an option. 324 | .sp 325 | .TP 326 | .B POPT_CONTEXT_POSIXMEHARDER 327 | When this flag is set, it is required that all options is placed before any 328 | arguments. This flag is also in effect if any of the environment variables 329 | .B POSIXLY_CORRECT 330 | or 331 | .B POSIX_ME_HARDER 332 | is set. 333 | .sp 334 | .TP 335 | .B POPT_CONTEXT_ARG_OPTS 336 | When this flag is set, all non-option arguments will get the value 0. This means 337 | that 338 | .B poptGetNextOpt() 339 | returns 0 for all non-option arguments, while 340 | .BR poptGetArg() " returns " NULL . 341 | .sp 342 | .PP 343 | .RB "A " poptContext " keeps track of which options have already been " 344 | parsed and which remain, among other things. If a program wishes to 345 | restart option processing of a set of arguments, it can reset the 346 | .BR poptContext " by passing the context as the sole argument to " 347 | .BR poptResetContext() . 348 | .sp 349 | When argument processing is complete, the process should free the 350 | .BR poptContext " as it contains dynamically allocated components. The " 351 | .BR poptFreeContext() " function takes a " 352 | .BR poptContext " as its sole argument and frees the resources the " 353 | context is using. It always returns NULL for convenience. 354 | .sp 355 | .RB "Here are the prototypes of both " poptResetContext() " and " 356 | .BR poptFreeContext() : 357 | .sp 358 | .nf 359 | .B #include 360 | .BI "poptContext poptFreeContext(poptContext " con ");" 361 | .BI "void poptResetContext(poptContext " con ");" 362 | .fi 363 | .sp 364 | .SS "3. PARSING THE COMMAND LINE" 365 | .RB "After an application has created a " poptContext ", it may begin " 366 | .RB "parsing arguments. " poptGetNextOpt() " performs the actual " 367 | argument parsing. 368 | .sp 369 | .nf 370 | .B #include 371 | .BI "int poptGetNextOpt(poptContext " con ");" 372 | .fi 373 | .sp 374 | Taking the context as its sole argument, this function parses the next 375 | command-line argument found. After finding the next argument in the 376 | option table, the function fills in the object pointed to by the option 377 | .RI "table entry's " arg 378 | .RB "pointer if it is not " NULL ". If the val entry for the option is " 379 | non-0, the function then returns that value. Otherwise, 380 | .BR poptGetNextOpt() " continues on to the next argument." 381 | .sp 382 | .BR poptGetNextOpt() " returns -1 when the final argument has been " 383 | parsed, and other negative values when errors occur. This makes it a 384 | good idea to 385 | .RI "keep the " val " elements in the options table greater than 0." 386 | .sp 387 | .RI "If all of the command-line options are handled through " arg 388 | pointers, command-line parsing is reduced to the following line of code: 389 | .sp 390 | .nf 391 | rc = poptGetNextOpt(poptcon); 392 | .fi 393 | .sp 394 | Many applications require more complex command-line parsing than this, 395 | however, and use the following structure: 396 | .sp 397 | .nf 398 | while ((rc = poptGetNextOpt(poptcon)) > 0) { 399 | switch (rc) { 400 | /* specific arguments are handled here */ 401 | } 402 | } 403 | .fi 404 | .sp 405 | When returned options are handled, the application needs to know the 406 | value of any arguments that were specified after the option. There are two 407 | ways to discover them. One is to ask popt to fill in a variable with the 408 | .RI "value of the option through the option table's " arg " elements. The " 409 | .RB "other is to use " poptGetOptArg() ":" 410 | .sp 411 | .nf 412 | .B #include 413 | .BI "char * poptGetOptArg(poptContext " con ");" 414 | .fi 415 | .sp 416 | This function returns the argument given for the final option returned by 417 | .BR poptGetNextOpt() ", or it returns " NULL " if no argument was specified." 418 | The calling function is responsible for deallocating this string. 419 | .sp 420 | .SS "4. LEFTOVER ARGUMENTS" 421 | Many applications take an arbitrary number of command-line arguments, 422 | such as a list of file names. When popt encounters an argument that does 423 | not begin with a -, it assumes it is such an argument and adds it to a list 424 | of leftover arguments. Three functions allow applications to access such 425 | arguments: 426 | .nf 427 | .HP 428 | .BI "const char * poptGetArg(poptContext " con ");" 429 | .fi 430 | This function returns the next leftover argument and marks it as 431 | processed. 432 | .PP 433 | .nf 434 | .HP 435 | .BI "const char * poptPeekArg(poptContext " con ");" 436 | .fi 437 | The next leftover argument is returned but not marked as processed. 438 | This allows an application to look ahead into the argument list, 439 | without modifying the list. 440 | .PP 441 | .nf 442 | .HP 443 | .BI "const char ** poptGetArgs(poptContext " con ");" 444 | .fi 445 | All the leftover arguments are returned in a manner identical to 446 | .IR argv ". The final element in the returned array points to " 447 | .BR NULL ", indicating the end of the arguments. 448 | .sp 449 | .SS "5. AUTOMATIC HELP MESSAGES" 450 | The \fBpopt\fR library can automatically generate help messages which 451 | describe the options a program accepts. There are two types of help 452 | messages which can be generated. Usage messages are a short messages 453 | which lists valid options, but does not describe them. Help messages 454 | describe each option on one (or more) lines, resulting in a longer, but 455 | more useful, message. Whenever automatic help messages are used, the 456 | \fBdescrip\fR and \fBargDescrip\fR fields \fBstruct poptOption\fR members 457 | should be filled in for each option. 458 | .sp 459 | The \fBPOPT_AUTOHELP\fR macro makes it easy to add \fB--usage\fR and 460 | \fB--help\fR messages to your program, and is described in part 1 461 | of this man page. If more control is needed over your help messages, 462 | the following two functions are available: 463 | .sp 464 | .nf 465 | .B #include 466 | .BI "void poptPrintHelp(poptContext " con ", FILE * " f ", int " flags "); 467 | .BI "void poptPrintUsage(poptContext " con ", FILE * " f ", int " flags "); 468 | .fi 469 | .sp 470 | \fBpoptPrintHelp()\fR displays the standard help message to the stdio file 471 | descriptor f, while \fBpoptPrintUsage()\fR displays the shorter usage 472 | message. Both functions currently ignore the \fBflags\fR argument; it is 473 | there to allow future changes. 474 | .sp 475 | .SH "ERROR HANDLING" 476 | All of the popt functions that can return errors return integers. 477 | When an error occurs, a negative error code is returned. The 478 | following table summarizes the error codes that occur: 479 | .sp 480 | .TS 481 | lfB lfB 482 | lfB lfR. 483 | Error Description 484 | POPT_ERROR_NOARG Argument missing for an option. 485 | POPT_ERROR_BADOPT Option's argument couldn't be parsed. 486 | POPT_ERROR_UNWANTEDARG Option does not take an argument. 487 | POPT_ERROR_OPTSTOODEEP Option aliasing nested too deeply. 488 | POPT_ERROR_BADQUOTE Quotations do not match. 489 | POPT_ERROR_ERRNO errno set, use strerror(errno). 490 | POPT_ERROR_BADNUMBER Option couldn't be converted to number. 491 | POPT_ERROR_OVERFLOW A given number was too big or small. 492 | POPT_ERROR_BADOPERATION Mutually exclusive logical operations requested. 493 | POPT_ERROR_NULLARG opt->arg should not be NULL. 494 | POPT_ERROR_MALLOC Memory allocation failed. 495 | POPT_ERROR_BADCONFIG Config file failed sanity test. 496 | .TE 497 | .sp 498 | Here is a more detailed discussion of each error: 499 | .sp 500 | .TP 501 | .B POPT_ERROR_NOARG 502 | An option that requires an argument was specified on the command 503 | line, but no argument was given. This can be returned only by 504 | .BR poptGetNextOpt() . 505 | .sp 506 | .TP 507 | .B POPT_ERROR_BADOPT 508 | .RI "An option was specified in " argv " but is not in the option 509 | .RB "table. This error can be returned only from " poptGetNextOpt() . 510 | .sp 511 | .TP 512 | .B POPT_ERROR_OPTSTOODEEP 513 | A set of option aliases is nested too deeply. Currently, popt 514 | follows options only 10 levels 515 | .B (POPT_OPTION_DEPTH) 516 | to prevent infinite recursion. Only 517 | .B poptGetNextOpt() 518 | can return this error. 519 | .sp 520 | .TP 521 | .B POPT_ERROR_BADQUOTE 522 | A parsed string has a quotation mismatch (such as a single quotation 523 | .RB "mark). " poptParseArgvString() ", " poptReadConfigFile() ", or " 524 | .BR poptReadDefaultConfig() " can return this error." 525 | .sp 526 | .TP 527 | .B POPT_ERROR_ERRNO 528 | .RI "A system call returned with an error, and " errno " still 529 | contains the error from the system call. Both 530 | .BR poptReadConfigFile() " and " poptReadDefaultConfig() " can " 531 | return this error. 532 | .sp 533 | .TP 534 | .B POPT_ERROR_BADNUMBER 535 | A conversion from a string to a number (int or long) failed due 536 | to the string containing non-numeric characters. This occurs when 537 | .BR poptGetNextOpt() " is processing an argument of type " 538 | .BR POPT_ARG_INT ", " POPT_ARG_SHORT ", " POPT_ARG_LONG ", " POPT_ARG_LONGLONG ", " 539 | .BR POPT_ARG_FLOAT ", or " POPT_ARG_DOUBLE "." 540 | .sp 541 | .TP 542 | .B POPT_ERROR_OVERFLOW 543 | A string-to-number conversion failed because the number was too 544 | .RB "large or too small. Like " POPT_ERROR_BADNUMBER ", this error 545 | .RB "can occur only when " poptGetNextOpt() " is processing an " 546 | .RB "argument of type " POPT_ARG_INT ", " POPT_ARG_SHORT ", " POPT_ARG_LONG ", " POPT_ARG_LONGLONG ", " 547 | .BR POPT_ARG_FLOAT ", or " POPT_ARG_DOUBLE "." 548 | .sp 549 | .TP 550 | .B POPT_ERROR_BADOPERATION 551 | More than one logical operation (AND, OR, XOR) was specified for an option, or 552 | .B POPT_ARGFLAG_RANDOM 553 | was specified but the platform does not support the 554 | .B random() 555 | function. This can be returned only by 556 | .BR poptSaveLongLong() ", " poptSaveLong() ", " poptSaveInt() ", " 557 | .BR poptSaveShort() " and " poptGetNextOpt() "." 558 | .sp 559 | .TP 560 | .B POPT_ERROR_NULLARG 561 | An operation was invoked on a null target 562 | .I arg 563 | (including zero-length string arguments). In the 564 | .B poptBitsArgs() 565 | case, this includes an empty leftover 566 | .I argv 567 | array. This can only be returned by the 568 | .B poptBits*() 569 | and 570 | .B poptSave*() 571 | functions, 572 | .B poptConfigFileToString() 573 | and 574 | .BR poptGetNextOpt() . 575 | .sp 576 | .TP 577 | .B POPT_ERROR_MALLOC 578 | Memory allocation failed. This can only be returned by 579 | .BR poptReadFile() , 580 | .BR poptDupArgv() , 581 | .BR poptParseArgvString() , 582 | .B poptConfigFileToString() 583 | and 584 | .BR poptGetNextOpt() . 585 | .sp 586 | .TP 587 | .B POPT_ERROR_BADCONFIG 588 | The popt configuration files are corrupted. This can only be returned by 589 | .B poptReadConfigFile() 590 | and 591 | .BR poptReadConfigFiles() . 592 | .sp 593 | .PP 594 | Two functions are available to make it easy for applications to provide 595 | good error messages. 596 | .HP 597 | .nf 598 | .BI "const char *const poptStrerror(const int " error ");" 599 | .fi 600 | This function takes a popt error code and returns a string describing 601 | .RB "the error, just as with the standard " strerror() " function." 602 | .PP 603 | .HP 604 | .nf 605 | .BI "const char * poptBadOption(poptContext " con ", int " flags ");" 606 | .fi 607 | .RB "If an error occurred during " poptGetNextOpt() ", this function " 608 | .RI "returns the option that caused the error. If the " flags " argument" 609 | .RB "is set to " POPT_BADOPTION_NOALIAS ", the outermost option is " 610 | .RI "returned. Otherwise, " flags " should be 0, and the option that is " 611 | returned may have been specified through an alias. 612 | .PP 613 | These two functions make popt error handling trivial for most 614 | applications. When an error is detected from most of the functions, 615 | an error message is printed along with the error string from 616 | .BR poptStrerror() ". When an error occurs during argument parsing, " 617 | code similar to the following displays a useful error message: 618 | .sp 619 | .nf 620 | fprintf(stderr, "%s: %s\\n", 621 | poptBadOption(optCon, POPT_BADOPTION_NOALIAS), 622 | poptStrerror(rc)); 623 | .fi 624 | .sp 625 | .SH "OPTION ALIASING" 626 | .RB "One of the primary benefits of using popt over " getopt() " is the " 627 | ability to use option aliasing. This lets the user specify options that 628 | popt expands into other options when they are specified. If the standard 629 | .RB "grep program made use of popt, users could add a " --text " option " 630 | .RB "that expanded to " "-i -n -E -2" " to let them more easily find " 631 | information in text files. 632 | .sp 633 | .SS "1. SPECIFYING ALIASES" 634 | .RI "Aliases are normally specified in two places: " /etc/popt 635 | .RB "and the " .popt " file in the user's home directory (found through " 636 | .RB "the " HOME " environment variable). Both files have the same format, " 637 | an arbitrary number of lines formatted like this: 638 | .sp 639 | .IB appname " alias " newoption "" " expansion" 640 | .sp 641 | .RI "The " appname " is the name of the application, which must be the " 642 | .RI "same as the " name " parameter passed to " 643 | .BR poptGetContext() ". This allows each file to specify aliases for " 644 | .RB "multiple programs. The " alias " keyword specifies that an alias is " 645 | being defined; currently popt configuration files support only aliases, but 646 | other abilities may be added in the future. The next option is the option 647 | that should be aliased, and it may be either a short or a long option. The 648 | rest of the line specifies the expansion for the alias. It is parsed 649 | similarly to a shell command, which allows \\, ", and ' to be used for 650 | quoting. If a backslash is the final character on a line, the next line 651 | in the file is assumed to be a logical continuation of the line containing 652 | the backslash, just as in shell. 653 | .sp 654 | .RB "The following entry would add a " --text " option to the grep command, " 655 | as suggested at the beginning of this section. 656 | .sp 657 | .B "grep alias --text -i -n -E -2" 658 | .SS "2. ENABLING ALIASES" 659 | .RB "An application must enable alias expansion for a " poptContext 660 | .RB "before calling " poptGetNextArg() " for the first time. There are " 661 | three functions that define aliases for a context: 662 | .HP 663 | .nf 664 | .BI "int poptReadDefaultConfig(poptContext " con ", int " flags ");" 665 | .fi 666 | .RI "This function reads aliases from " /etc/popt " and the " 667 | .BR .popt " file in the user's home directory. Currently, " 668 | .IR flags " should be " 669 | .BR NULL ", as it is provided only for future expansion." 670 | .PP 671 | .HP 672 | .nf 673 | .BI "int poptReadConfigFile(poptContext " con ", char * " fn ");" 674 | .fi 675 | .RI "The file specified by " fn " is opened and parsed as a popt " 676 | configuration file. This allows programs to use program-specific 677 | configuration files. 678 | .PP 679 | .HP 680 | .nf 681 | .BI "int poptAddAlias(poptContext " con ", struct poptAlias " alias ", 682 | .BI " int " flags ");" 683 | .fi 684 | Occasionally, processes want to specify aliases without having to 685 | read them from a configuration file. This function adds a new alias 686 | .RI "to a context. The " flags " argument should be 0, as it is " 687 | currently reserved for future expansion. The new alias is specified 688 | .RB "as a " "struct poptAlias" ", which is defined as:" 689 | .sp 690 | .nf 691 | struct poptAlias { 692 | const char * longName; /* may be NULL */ 693 | char shortName; /* may be '\\0' */ 694 | int argc; 695 | const char ** argv; /* must be free()able */ 696 | }; 697 | .fi 698 | .sp 699 | .RI "The first two elements, " longName " and " shortName ", specify " 700 | .RI "the option that is aliased. The final two, " argc " and " argv "," 701 | define the expansion to use when the aliases option is encountered. 702 | .PP 703 | .SH "PARSING ARGUMENT STRINGS" 704 | Although popt is usually used for parsing arguments already divided into 705 | .RI "an " argv "-style array, some programs need to parse strings that " 706 | are formatted identically to command lines. To facilitate this, popt 707 | provides a function that parses a string into an array of strings, 708 | using rules similar to normal shell parsing. 709 | .sp 710 | .nf 711 | .B "#include " 712 | .BI "int poptParseArgvString(char * " s ", int * " argcPtr ", 713 | .BI " char *** " argvPtr ");" 714 | .BI "int poptDupArgv(int " argc ", const char ** " argv ", int * " argcPtr ", 715 | .BI " const char *** " argvPtr ");" 716 | .fi 717 | .sp 718 | .RI "The string s is parsed into an " argv "-style array. The integer " 719 | .RI "pointed to by the " argcPtr " parameter contains the number of elements " 720 | .RI "parsed, and the final " argvPtr " parameter contains the address of the" 721 | newly created array. 722 | .RB "The routine " poptDupArgv() " can be used to make a copy of an existing " 723 | argument array. 724 | .sp 725 | .RI "The " argvPtr 726 | .RB "created by " poptParseArgvString() " or " poptDupArgv() " is suitable to pass directly " 727 | .RB "to " poptGetContext() . 728 | Both routines return a single dynamically allocated contiguous 729 | .RB "block of storage and should be " free() "ed when the application is" 730 | finished with the storage. 731 | .SH "HANDLING EXTRA ARGUMENTS" 732 | Some applications implement the equivalent of option aliasing but need 733 | .RB "to do so through special logic. The " poptStuffArgs() " function " 734 | allows an application to insert new arguments into the current 735 | .BR poptContext . 736 | .sp 737 | .nf 738 | .B "#include " 739 | .BI "int poptStuffArgs(poptContext "con ", const char ** " argv ");" 740 | .fi 741 | .sp 742 | .RI "The passed " argv 743 | .RB "must have a " NULL " pointer as its final element. When " 744 | .BR poptGetNextOpt() " is next called, the " 745 | "stuffed" arguments are the first to be parsed. popt returns to the 746 | normal arguments once all the stuffed arguments have been exhausted. 747 | .SH "EXAMPLE" 748 | The following example is a simplified version of the program "robin" 749 | which appears in Chapter 15 of the text cited below. Robin has 750 | been stripped of everything but its argument-parsing logic, slightly 751 | reworked, and renamed "parse." It may prove useful in illustrating 752 | at least some of the features of the extremely rich popt library. 753 | .sp 754 | .nf 755 | #include 756 | #include 757 | #include 758 | 759 | void usage(poptContext optCon, int exitcode, char *error, char *addl) { 760 | poptPrintUsage(optCon, stderr, 0); 761 | if (error) fprintf(stderr, "%s: %s\\n", error, addl); 762 | poptFreeContext(optCon); 763 | exit(exitcode); 764 | } 765 | 766 | int main(int argc, char *argv[]) { 767 | int c; /* used for argument parsing */ 768 | int i = 0; /* used for tracking options */ 769 | int speed = 0; /* used in argument parsing to set speed */ 770 | int raw = 0; /* raw mode? */ 771 | int j; 772 | char buf[BUFSIZ+1]; 773 | const char *portname; 774 | poptContext optCon; /* context for parsing command-line options */ 775 | 776 | struct poptOption optionsTable[] = { 777 | { "bps", 'b', POPT_ARG_INT, &speed, 0, 778 | "signaling rate in bits-per-second", "BPS" }, 779 | { "crnl", 'c', POPT_ARG_NONE, 0, 'c', 780 | "expand cr characters to cr/lf sequences", NULL }, 781 | { "hwflow", 'h', POPT_ARG_NONE, 0, 'h', 782 | "use hardware (RTS/CTS) flow control", NULL }, 783 | { "noflow", 'n', POPT_ARG_NONE, 0, 'n', 784 | "use no flow control", NULL }, 785 | { "raw", 'r', POPT_ARG_NONE, &raw, 0, 786 | "don't perform any character conversions", NULL }, 787 | { "swflow", 's', POPT_ARG_NONE, 0, 's', 788 | "use software (XON/XOF) flow control", NULL } , 789 | POPT_AUTOHELP 790 | POPT_TABLEEND 791 | }; 792 | 793 | optCon = poptGetContext(NULL, argc, (const char **) argv, optionsTable, 0); 794 | poptSetOtherOptionHelp(optCon, "[OPTIONS]* "); 795 | 796 | if (argc < 2) 797 | usage(optCon, 1, 0, NULL); 798 | 799 | /* Now do options processing, get portname */ 800 | while ((c = poptGetNextOpt(optCon)) >= 0) { 801 | switch (c) { 802 | case 'c': 803 | buf[i++] = 'c'; 804 | break; 805 | case 'h': 806 | buf[i++] = 'h'; 807 | break; 808 | case 's': 809 | buf[i++] = 's'; 810 | break; 811 | case 'n': 812 | buf[i++] = 'n'; 813 | break; 814 | } 815 | } 816 | portname = poptGetArg(optCon); 817 | if((portname == NULL) || !(poptPeekArg(optCon) == NULL)) 818 | usage(optCon, 1, "Specify a single port", ".e.g., /dev/cua0"); 819 | 820 | if (c < -1) { 821 | /* an error occurred during option processing */ 822 | fprintf(stderr, "%s: %s\\n", 823 | poptBadOption(optCon, POPT_BADOPTION_NOALIAS), 824 | poptStrerror(c)); 825 | return 1; 826 | } 827 | 828 | /* Print out options, portname chosen */ 829 | printf("Options chosen: "); 830 | for(j = 0; j < i ; j++) 831 | printf("-%c ", buf[j]); 832 | if(raw) printf("-r "); 833 | if(speed) printf("-b %d ", speed); 834 | printf("\\nPortname chosen: %s\\n", portname); 835 | 836 | poptFreeContext(optCon); 837 | exit(0); 838 | } 839 | .fi 840 | .sp 841 | RPM, a popular Linux package management program, makes heavy use 842 | of popt's features. Many of its command-line arguments are implemented 843 | through popt aliases, which makes RPM an excellent example of how to 844 | take advantage of the popt library. For more information on RPM, see 845 | https://rpm.org. The popt source code distribution includes test 846 | program(s) which use all of the features of the popt libraries in 847 | various ways. If a feature isn't working for you, the popt test code 848 | is the first place to look. 849 | .SH BUGS 850 | None presently known. 851 | .SH AUTHOR 852 | Erik W. Troan 853 | .PP 854 | This man page is derived in part from 855 | .IR "Linux Application Development" 856 | by Michael K. Johnson and Erik W. Troan, Copyright (c) 1998 by Addison 857 | Wesley Longman, Inc., and included in the popt documentation with the 858 | permission of the Publisher and the appreciation of the Authors. 859 | .PP 860 | Thanks to Robert Lynch for his extensive work on this man page. 861 | .SH "SEE ALSO" 862 | .BR getopt (3) 863 | .sp 864 | .IR "Linux Application Development" ", by Michael K. Johnson and " 865 | Erik W. Troan (Addison-Wesley, 1998; ISBN 0-201-30821-5), Chapter 24. 866 | .sp 867 | .BR popt.pdf " is a PDF version of the above cited book " 868 | chapter. It can be found in the source archive for popt available at: 869 | http://ftp.rpm.org/popt/releases/. 870 | --------------------------------------------------------------------------------