libshevek-1.3.orig/0000755000175000017500000000000011753242640013630 5ustar sheveksheveklibshevek-1.3.orig/config.doxygen0000644000175000017500000016376611553533024016514 0ustar shevekshevek# Doxyfile 1.5.6 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project # # All text after a hash (#) is considered a comment and will be ignored # The format is: # TAG = value [value, ...] # For lists items can also be appended using: # TAG += value [value, ...] # Values that contain spaces should be placed between quotes (" ") #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- # This tag specifies the encoding used for all characters in the config file # that follow. The default is UTF-8 which is also the encoding used for all # text before the first occurrence of this tag. Doxygen uses libiconv (or the # iconv built into libc) for the transcoding. See # http://www.gnu.org/software/libiconv for the list of possible encodings. DOXYFILE_ENCODING = UTF-8 # The PROJECT_NAME tag is a single word (or a sequence of words surrounded # by quotes) that should identify the project. PROJECT_NAME = libshevek # The PROJECT_NUMBER tag can be used to enter a project or revision number. # This could be handy for archiving the generated documentation or # if some version control system is used. PROJECT_NUMBER = # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) # base path where the generated documentation will be put. # If a relative path is entered, it will be relative to the location # where doxygen was started. If left blank the current directory will be used. OUTPUT_DIRECTORY = doc # If the CREATE_SUBDIRS tag is set to YES, then doxygen will create # 4096 sub-directories (in 2 levels) under the output directory of each output # format and will distribute the generated files over these directories. # Enabling this option can be useful when feeding doxygen a huge amount of # source files, where putting all generated files in the same directory would # otherwise cause performance problems for the file system. CREATE_SUBDIRS = NO # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. # The default language is English, other supported languages are: # Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, # Croatian, Czech, Danish, Dutch, Farsi, Finnish, French, German, Greek, # Hungarian, Italian, Japanese, Japanese-en (Japanese with English messages), # Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, Polish, # Portuguese, Romanian, Russian, Serbian, Slovak, Slovene, Spanish, Swedish, # and Ukrainian. OUTPUT_LANGUAGE = English # If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will # include brief member descriptions after the members that are listed in # the file and class documentation (similar to JavaDoc). # Set to NO to disable this. BRIEF_MEMBER_DESC = YES # If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend # the brief description of a member or function before the detailed description. # Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the # brief descriptions will be completely suppressed. REPEAT_BRIEF = YES # This tag implements a quasi-intelligent brief description abbreviator # that is used to form the text in various listings. Each string # in this list, if found as the leading text of the brief description, will be # stripped from the text and the result after processing the whole list, is # used as the annotated text. Otherwise, the brief description is used as-is. # If left blank, the following values are used ("$name" is automatically # replaced with the name of the entity): "The $name class" "The $name widget" # "The $name file" "is" "provides" "specifies" "contains" # "represents" "a" "an" "the" ABBREVIATE_BRIEF = # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then # Doxygen will generate a detailed section even if there is only a brief # description. ALWAYS_DETAILED_SEC = NO # If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all # inherited members of a class in the documentation of that class as if those # members were ordinary class members. Constructors, destructors and assignment # operators of the base classes will not be shown. INLINE_INHERITED_MEMB = NO # If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full # path before files name in the file list and in the header files. If set # to NO the shortest path that makes the file name unique will be used. FULL_PATH_NAMES = YES # If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag # can be used to strip a user-defined part of the path. Stripping is # only done if one of the specified strings matches the left-hand part of # the path. The tag can be used to show relative paths in the file list. # If left blank the directory from which doxygen is run is used as the # path to strip. STRIP_FROM_PATH = # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of # the path mentioned in the documentation of a class, which tells # the reader which header file to include in order to use a class. # If left blank only the name of the header file containing the class # definition is used. Otherwise one should specify the include paths that # are normally passed to the compiler using the -I flag. STRIP_FROM_INC_PATH = # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter # (but less readable) file names. This can be useful is your file systems # doesn't support long names like on DOS, Mac, or CD-ROM. SHORT_NAMES = NO # If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen # will interpret the first line (until the first dot) of a JavaDoc-style # comment as the brief description. If set to NO, the JavaDoc # comments will behave just like regular Qt-style comments # (thus requiring an explicit @brief command for a brief description.) JAVADOC_AUTOBRIEF = NO # If the QT_AUTOBRIEF tag is set to YES then Doxygen will # interpret the first line (until the first dot) of a Qt-style # comment as the brief description. If set to NO, the comments # will behave just like regular Qt-style comments (thus requiring # an explicit \brief command for a brief description.) QT_AUTOBRIEF = NO # The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen # treat a multi-line C++ special comment block (i.e. a block of //! or /// # comments) as a brief description. This used to be the default behaviour. # The new default is to treat a multi-line C++ comment block as a detailed # description. Set this tag to YES if you prefer the old behaviour instead. MULTILINE_CPP_IS_BRIEF = NO # If the DETAILS_AT_TOP tag is set to YES then Doxygen # will output the detailed description near the top, like JavaDoc. # If set to NO, the detailed description appears after the member # documentation. DETAILS_AT_TOP = NO # If the INHERIT_DOCS tag is set to YES (the default) then an undocumented # member inherits the documentation from any documented member that it # re-implements. INHERIT_DOCS = YES # If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce # a new page for each member. If set to NO, the documentation of a member will # be part of the file/class/namespace that contains it. SEPARATE_MEMBER_PAGES = NO # The TAB_SIZE tag can be used to set the number of spaces in a tab. # Doxygen uses this value to replace tabs by spaces in code fragments. TAB_SIZE = 8 # This tag can be used to specify a number of aliases that acts # as commands in the documentation. An alias has the form "name=value". # For example adding "sideeffect=\par Side Effects:\n" will allow you to # put the command \sideeffect (or @sideeffect) in the documentation, which # will result in a user-defined paragraph with heading "Side Effects:". # You can put \n's in the value part of an alias to insert newlines. ALIASES = # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C # sources only. Doxygen will then generate output that is more tailored for C. # For instance, some of the names that are used will be different. The list # of all members will be omitted, etc. OPTIMIZE_OUTPUT_FOR_C = NO # Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java # sources only. Doxygen will then generate output that is more tailored for # Java. For instance, namespaces will be presented as packages, qualified # scopes will look different, etc. OPTIMIZE_OUTPUT_JAVA = NO # Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran # sources only. Doxygen will then generate output that is more tailored for # Fortran. OPTIMIZE_FOR_FORTRAN = NO # Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL # sources. Doxygen will then generate output that is tailored for # VHDL. OPTIMIZE_OUTPUT_VHDL = NO # If you use STL classes (i.e. std::string, std::vector, etc.) but do not want # to include (a tag file for) the STL sources as input, then you should # set this tag to YES in order to let doxygen match functions declarations and # definitions whose arguments contain STL classes (e.g. func(std::string); v.s. # func(std::string) {}). This also make the inheritance and collaboration # diagrams that involve STL classes more complete and accurate. BUILTIN_STL_SUPPORT = NO # If you use Microsoft's C++/CLI language, you should set this option to YES to # enable parsing support. CPP_CLI_SUPPORT = NO # Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. # Doxygen will parse them like normal C++ but will assume all classes use public # instead of private inheritance when no explicit protection keyword is present. SIP_SUPPORT = NO # For Microsoft's IDL there are propget and propput attributes to indicate getter # and setter methods for a property. Setting this option to YES (the default) # will make doxygen to replace the get and set methods by a property in the # documentation. This will only work if the methods are indeed getting or # setting a simple type. If this is not the case, or you want to show the # methods anyway, you should set this option to NO. IDL_PROPERTY_SUPPORT = YES # If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC # tag is set to YES, then doxygen will reuse the documentation of the first # member in the group (if any) for the other members of the group. By default # all members of a group must be documented explicitly. DISTRIBUTE_GROUP_DOC = NO # Set the SUBGROUPING tag to YES (the default) to allow class member groups of # the same type (for instance a group of public functions) to be put as a # subgroup of that type (e.g. under the Public Functions section). Set it to # NO to prevent subgrouping. Alternatively, this can be done per class using # the \nosubgrouping command. SUBGROUPING = YES # When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum # is documented as struct, union, or enum with the name of the typedef. So # typedef struct TypeS {} TypeT, will appear in the documentation as a struct # with name TypeT. When disabled the typedef will appear as a member of a file, # namespace, or class. And the struct will be named TypeS. This can typically # be useful for C code in case the coding convention dictates that all compound # types are typedef'ed and only the typedef is referenced, never the tag name. TYPEDEF_HIDES_STRUCT = NO #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- # If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in # documentation are documented, even if no documentation was available. # Private class members and static file members will be hidden unless # the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES EXTRACT_ALL = NO # If the EXTRACT_PRIVATE tag is set to YES all private members of a class # will be included in the documentation. EXTRACT_PRIVATE = NO # If the EXTRACT_STATIC tag is set to YES all static members of a file # will be included in the documentation. EXTRACT_STATIC = NO # If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) # defined locally in source files will be included in the documentation. # If set to NO only classes defined in header files are included. EXTRACT_LOCAL_CLASSES = YES # This flag is only useful for Objective-C code. When set to YES local # methods, which are defined in the implementation section but not in # the interface are included in the documentation. # If set to NO (the default) only methods in the interface are included. EXTRACT_LOCAL_METHODS = NO # If this flag is set to YES, the members of anonymous namespaces will be # extracted and appear in the documentation as a namespace called # 'anonymous_namespace{file}', where file will be replaced with the base # name of the file that contains the anonymous namespace. By default # anonymous namespace are hidden. EXTRACT_ANON_NSPACES = NO # If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all # undocumented members of documented classes, files or namespaces. # If set to NO (the default) these members will be included in the # various overviews, but no documentation section is generated. # This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_MEMBERS = NO # If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all # undocumented classes that are normally visible in the class hierarchy. # If set to NO (the default) these classes will be included in the various # overviews. This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_CLASSES = NO # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all # friend (class|struct|union) declarations. # If set to NO (the default) these declarations will be included in the # documentation. HIDE_FRIEND_COMPOUNDS = NO # If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any # documentation blocks found inside the body of a function. # If set to NO (the default) these blocks will be appended to the # function's detailed documentation block. HIDE_IN_BODY_DOCS = NO # The INTERNAL_DOCS tag determines if documentation # that is typed after a \internal command is included. If the tag is set # to NO (the default) then the documentation will be excluded. # Set it to YES to include the internal documentation. INTERNAL_DOCS = NO # If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate # file names in lower-case letters. If set to YES upper-case letters are also # allowed. This is useful if you have classes or files whose names only differ # in case and if your file system supports case sensitive file names. Windows # and Mac users are advised to set this option to NO. CASE_SENSE_NAMES = YES # If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen # will show members with their full class and namespace scopes in the # documentation. If set to YES the scope will be hidden. HIDE_SCOPE_NAMES = NO # If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen # will put a list of the files that are included by a file in the documentation # of that file. SHOW_INCLUDE_FILES = YES # If the INLINE_INFO tag is set to YES (the default) then a tag [inline] # is inserted in the documentation for inline members. INLINE_INFO = YES # If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen # will sort the (detailed) documentation of file and class members # alphabetically by member name. If set to NO the members will appear in # declaration order. SORT_MEMBER_DOCS = YES # If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the # brief documentation of file, namespace and class members alphabetically # by member name. If set to NO (the default) the members will appear in # declaration order. SORT_BRIEF_DOCS = NO # If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the # hierarchy of group names into alphabetical order. If set to NO (the default) # the group names will appear in their defined order. SORT_GROUP_NAMES = NO # If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be # sorted by fully-qualified names, including namespaces. If set to # NO (the default), the class list will be sorted only by class name, # not including the namespace part. # Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. # Note: This option applies only to the class list, not to the # alphabetical list. SORT_BY_SCOPE_NAME = NO # The GENERATE_TODOLIST tag can be used to enable (YES) or # disable (NO) the todo list. This list is created by putting \todo # commands in the documentation. GENERATE_TODOLIST = YES # The GENERATE_TESTLIST tag can be used to enable (YES) or # disable (NO) the test list. This list is created by putting \test # commands in the documentation. GENERATE_TESTLIST = YES # The GENERATE_BUGLIST tag can be used to enable (YES) or # disable (NO) the bug list. This list is created by putting \bug # commands in the documentation. GENERATE_BUGLIST = YES # The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or # disable (NO) the deprecated list. This list is created by putting # \deprecated commands in the documentation. GENERATE_DEPRECATEDLIST= YES # The ENABLED_SECTIONS tag can be used to enable conditional # documentation sections, marked by \if sectionname ... \endif. ENABLED_SECTIONS = # The MAX_INITIALIZER_LINES tag determines the maximum number of lines # the initial value of a variable or define consists of for it to appear in # the documentation. If the initializer consists of more lines than specified # here it will be hidden. Use a value of 0 to hide initializers completely. # The appearance of the initializer of individual variables and defines in the # documentation can be controlled using \showinitializer or \hideinitializer # command in the documentation regardless of this setting. MAX_INITIALIZER_LINES = 30 # Set the SHOW_USED_FILES tag to NO to disable the list of files generated # at the bottom of the documentation of classes and structs. If set to YES the # list will mention the files that were used to generate the documentation. SHOW_USED_FILES = YES # If the sources in your project are distributed over multiple directories # then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy # in the documentation. The default is NO. SHOW_DIRECTORIES = NO # Set the SHOW_FILES tag to NO to disable the generation of the Files page. # This will remove the Files entry from the Quick Index and from the # Folder Tree View (if specified). The default is YES. SHOW_FILES = YES # Set the SHOW_NAMESPACES tag to NO to disable the generation of the # Namespaces page. This will remove the Namespaces entry from the Quick Index # and from the Folder Tree View (if specified). The default is YES. SHOW_NAMESPACES = YES # The FILE_VERSION_FILTER tag can be used to specify a program or script that # doxygen should invoke to get the current version for each file (typically from # the version control system). Doxygen will invoke the program by executing (via # popen()) the command , where is the value of # the FILE_VERSION_FILTER tag, and is the name of an input file # provided by doxygen. Whatever the program writes to standard output # is used as the file version. See the manual for examples. FILE_VERSION_FILTER = #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- # The QUIET tag can be used to turn on/off the messages that are generated # by doxygen. Possible values are YES and NO. If left blank NO is used. QUIET = NO # The WARNINGS tag can be used to turn on/off the warning messages that are # generated by doxygen. Possible values are YES and NO. If left blank # NO is used. WARNINGS = YES # If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings # for undocumented members. If EXTRACT_ALL is set to YES then this flag will # automatically be disabled. WARN_IF_UNDOCUMENTED = YES # If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for # potential errors in the documentation, such as not documenting some # parameters in a documented function, or documenting parameters that # don't exist or using markup commands wrongly. WARN_IF_DOC_ERROR = YES # This WARN_NO_PARAMDOC option can be abled to get warnings for # functions that are documented, but have no documentation for their parameters # or return value. If set to NO (the default) doxygen will only warn about # wrong or incomplete parameter documentation, but not about the absence of # documentation. WARN_NO_PARAMDOC = NO # The WARN_FORMAT tag determines the format of the warning messages that # doxygen can produce. The string should contain the $file, $line, and $text # tags, which will be replaced by the file and line number from which the # warning originated and the warning text. Optionally the format may contain # $version, which will be replaced by the version of the file (if it could # be obtained via FILE_VERSION_FILTER) WARN_FORMAT = "$file:$line: $text" # The WARN_LOGFILE tag can be used to specify a file to which warning # and error messages should be written. If left blank the output is written # to stderr. WARN_LOGFILE = #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- # The INPUT tag can be used to specify the files and/or directories that contain # documented source files. You may enter file names like "myfile.cpp" or # directories like "/usr/src/myproject". Separate the files or directories # with spaces. INPUT = src # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is # also the default input encoding. Doxygen uses libiconv (or the iconv built # into libc) for the transcoding. See http://www.gnu.org/software/libiconv for # the list of possible encodings. INPUT_ENCODING = UTF-8 # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank the following patterns are tested: # *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx # *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90 FILE_PATTERNS = *.hh # The RECURSIVE tag can be used to turn specify whether or not subdirectories # should be searched for input files as well. Possible values are YES and NO. # If left blank NO is used. RECURSIVE = NO # The EXCLUDE tag can be used to specify files and/or directories that should # excluded from the INPUT source files. This way you can easily exclude a # subdirectory from a directory tree whose root is specified with the INPUT tag. EXCLUDE = # The EXCLUDE_SYMLINKS tag can be used select whether or not files or # directories that are symbolic links (a Unix filesystem feature) are excluded # from the input. EXCLUDE_SYMLINKS = NO # If the value of the INPUT tag contains directories, you can use the # EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude # certain files from those directories. Note that the wildcards are matched # against the file with absolute path, so to exclude all test directories # for example use the pattern */test/* EXCLUDE_PATTERNS = # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names # (namespaces, classes, functions, etc.) that should be excluded from the # output. The symbol name can be a fully qualified name, a word, or if the # wildcard * is used, a substring. Examples: ANamespace, AClass, # AClass::ANamespace, ANamespace::*Test EXCLUDE_SYMBOLS = # The EXAMPLE_PATH tag can be used to specify one or more files or # directories that contain example code fragments that are included (see # the \include command). EXAMPLE_PATH = # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank all files are included. EXAMPLE_PATTERNS = # If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be # searched for input files to be used with the \include or \dontinclude # commands irrespective of the value of the RECURSIVE tag. # Possible values are YES and NO. If left blank NO is used. EXAMPLE_RECURSIVE = NO # The IMAGE_PATH tag can be used to specify one or more files or # directories that contain image that are included in the documentation (see # the \image command). IMAGE_PATH = # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program # by executing (via popen()) the command , where # is the value of the INPUT_FILTER tag, and is the name of an # input file. Doxygen will then use the output that the filter program writes # to standard output. If FILTER_PATTERNS is specified, this tag will be # ignored. INPUT_FILTER = # The FILTER_PATTERNS tag can be used to specify filters on a per file pattern # basis. Doxygen will compare the file name with each pattern and apply the # filter if there is a match. The filters are a list of the form: # pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further # info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER # is applied to all files. FILTER_PATTERNS = # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using # INPUT_FILTER) will be used to filter the input files when producing source # files to browse (i.e. when SOURCE_BROWSER is set to YES). FILTER_SOURCE_FILES = NO #--------------------------------------------------------------------------- # configuration options related to source browsing #--------------------------------------------------------------------------- # If the SOURCE_BROWSER tag is set to YES then a list of source files will # be generated. Documented entities will be cross-referenced with these sources. # Note: To get rid of all source code in the generated output, make sure also # VERBATIM_HEADERS is set to NO. SOURCE_BROWSER = NO # Setting the INLINE_SOURCES tag to YES will include the body # of functions and classes directly in the documentation. INLINE_SOURCES = NO # Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct # doxygen to hide any special comment blocks from generated source code # fragments. Normal C and C++ comments will always remain visible. STRIP_CODE_COMMENTS = YES # If the REFERENCED_BY_RELATION tag is set to YES # then for each documented function all documented # functions referencing it will be listed. REFERENCED_BY_RELATION = NO # If the REFERENCES_RELATION tag is set to YES # then for each documented function all documented entities # called/used by that function will be listed. REFERENCES_RELATION = NO # If the REFERENCES_LINK_SOURCE tag is set to YES (the default) # and SOURCE_BROWSER tag is set to YES, then the hyperlinks from # functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will # link to the source code. Otherwise they will link to the documentstion. REFERENCES_LINK_SOURCE = YES # If the USE_HTAGS tag is set to YES then the references to source code # will point to the HTML generated by the htags(1) tool instead of doxygen # built-in source browser. The htags tool is part of GNU's global source # tagging system (see http://www.gnu.org/software/global/global.html). You # will need version 4.8.6 or higher. USE_HTAGS = NO # If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen # will generate a verbatim copy of the header file for each class for # which an include is specified. Set to NO to disable this. VERBATIM_HEADERS = YES #--------------------------------------------------------------------------- # configuration options related to the alphabetical class index #--------------------------------------------------------------------------- # If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index # of all compounds will be generated. Enable this if the project # contains a lot of classes, structs, unions or interfaces. ALPHABETICAL_INDEX = NO # If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then # the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns # in which this list will be split (can be a number in the range [1..20]) COLS_IN_ALPHA_INDEX = 5 # In case all classes in a project start with a common prefix, all # classes will be put under the same header in the alphabetical index. # The IGNORE_PREFIX tag can be used to specify one or more prefixes that # should be ignored while generating the index headers. IGNORE_PREFIX = #--------------------------------------------------------------------------- # configuration options related to the HTML output #--------------------------------------------------------------------------- # If the GENERATE_HTML tag is set to YES (the default) Doxygen will # generate HTML output. GENERATE_HTML = YES # The HTML_OUTPUT tag is used to specify where the HTML docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `html' will be used as the default path. HTML_OUTPUT = html # The HTML_FILE_EXTENSION tag can be used to specify the file extension for # each generated HTML page (for example: .htm,.php,.asp). If it is left blank # doxygen will generate files with .html extension. HTML_FILE_EXTENSION = .html # The HTML_HEADER tag can be used to specify a personal HTML header for # each generated HTML page. If it is left blank doxygen will generate a # standard header. HTML_HEADER = # The HTML_FOOTER tag can be used to specify a personal HTML footer for # each generated HTML page. If it is left blank doxygen will generate a # standard footer. HTML_FOOTER = # The HTML_STYLESHEET tag can be used to specify a user-defined cascading # style sheet that is used by each HTML page. It can be used to # fine-tune the look of the HTML output. If the tag is left blank doxygen # will generate a default style sheet. Note that doxygen will try to copy # the style sheet file to the HTML output directory, so don't put your own # stylesheet in the HTML output directory as well, or it will be erased! HTML_STYLESHEET = # If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, # files or namespaces will be aligned in HTML using tables. If set to # NO a bullet list will be used. HTML_ALIGN_MEMBERS = YES # If the GENERATE_HTMLHELP tag is set to YES, additional index files # will be generated that can be used as input for tools like the # Microsoft HTML help workshop to generate a compiled HTML help file (.chm) # of the generated HTML documentation. GENERATE_HTMLHELP = NO # If the GENERATE_DOCSET tag is set to YES, additional index files # will be generated that can be used as input for Apple's Xcode 3 # integrated development environment, introduced with OSX 10.5 (Leopard). # To create a documentation set, doxygen will generate a Makefile in the # HTML output directory. Running make will produce the docset in that # directory and running "make install" will install the docset in # ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find # it at startup. GENERATE_DOCSET = NO # When GENERATE_DOCSET tag is set to YES, this tag determines the name of the # feed. A documentation feed provides an umbrella under which multiple # documentation sets from a single provider (such as a company or product suite) # can be grouped. DOCSET_FEEDNAME = "Doxygen generated docs" # When GENERATE_DOCSET tag is set to YES, this tag specifies a string that # should uniquely identify the documentation set bundle. This should be a # reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen # will append .docset to the name. DOCSET_BUNDLE_ID = org.doxygen.Project # If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML # documentation will contain sections that can be hidden and shown after the # page has loaded. For this to work a browser that supports # JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox # Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). HTML_DYNAMIC_SECTIONS = NO # If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can # be used to specify the file name of the resulting .chm file. You # can add a path in front of the file if the result should not be # written to the html output directory. CHM_FILE = # If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can # be used to specify the location (absolute path including file name) of # the HTML help compiler (hhc.exe). If non-empty doxygen will try to run # the HTML help compiler on the generated index.hhp. HHC_LOCATION = # If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag # controls if a separate .chi index file is generated (YES) or that # it should be included in the master .chm file (NO). GENERATE_CHI = NO # If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING # is used to encode HtmlHelp index (hhk), content (hhc) and project file # content. CHM_INDEX_ENCODING = # If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag # controls whether a binary table of contents is generated (YES) or a # normal table of contents (NO) in the .chm file. BINARY_TOC = NO # The TOC_EXPAND flag can be set to YES to add extra items for group members # to the contents of the HTML help documentation and to the tree view. TOC_EXPAND = NO # The DISABLE_INDEX tag can be used to turn on/off the condensed index at # top of each HTML page. The value NO (the default) enables the index and # the value YES disables it. DISABLE_INDEX = NO # This tag can be used to set the number of enum values (range [1..20]) # that doxygen will group on one line in the generated HTML documentation. ENUM_VALUES_PER_LINE = 4 # The GENERATE_TREEVIEW tag is used to specify whether a tree-like index # structure should be generated to display hierarchical information. # If the tag value is set to FRAME, a side panel will be generated # containing a tree-like index structure (just like the one that # is generated for HTML Help). For this to work a browser that supports # JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, # Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are # probably better off using the HTML help feature. Other possible values # for this tag are: HIERARCHIES, which will generate the Groups, Directories, # and Class Hiererachy pages using a tree view instead of an ordered list; # ALL, which combines the behavior of FRAME and HIERARCHIES; and NONE, which # disables this behavior completely. For backwards compatibility with previous # releases of Doxygen, the values YES and NO are equivalent to FRAME and NONE # respectively. GENERATE_TREEVIEW = NONE # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be # used to set the initial width (in pixels) of the frame in which the tree # is shown. TREEVIEW_WIDTH = 250 # Use this tag to change the font size of Latex formulas included # as images in the HTML documentation. The default is 10. Note that # when you change the font size after a successful doxygen run you need # to manually remove any form_*.png images from the HTML output directory # to force them to be regenerated. FORMULA_FONTSIZE = 10 #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- # If the GENERATE_LATEX tag is set to YES (the default) Doxygen will # generate Latex output. GENERATE_LATEX = YES # The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `latex' will be used as the default path. LATEX_OUTPUT = latex # The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be # invoked. If left blank `latex' will be used as the default command name. LATEX_CMD_NAME = latex # The MAKEINDEX_CMD_NAME tag can be used to specify the command name to # generate index for LaTeX. If left blank `makeindex' will be used as the # default command name. MAKEINDEX_CMD_NAME = makeindex # If the COMPACT_LATEX tag is set to YES Doxygen generates more compact # LaTeX documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_LATEX = NO # The PAPER_TYPE tag can be used to set the paper type that is used # by the printer. Possible values are: a4, a4wide, letter, legal and # executive. If left blank a4wide will be used. PAPER_TYPE = a4wide # The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX # packages that should be included in the LaTeX output. EXTRA_PACKAGES = # The LATEX_HEADER tag can be used to specify a personal LaTeX header for # the generated latex document. The header should contain everything until # the first chapter. If it is left blank doxygen will generate a # standard header. Notice: only use this tag if you know what you are doing! LATEX_HEADER = # If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated # is prepared for conversion to pdf (using ps2pdf). The pdf file will # contain links (just like the HTML output) instead of page references # This makes the output suitable for online browsing using a pdf viewer. PDF_HYPERLINKS = YES # If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of # plain latex in the generated Makefile. Set this option to YES to get a # higher quality PDF documentation. USE_PDFLATEX = YES # If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. # command to the generated LaTeX files. This will instruct LaTeX to keep # running if errors occur, instead of asking the user for help. # This option is also used when generating formulas in HTML. LATEX_BATCHMODE = NO # If LATEX_HIDE_INDICES is set to YES then doxygen will not # include the index chapters (such as File Index, Compound Index, etc.) # in the output. LATEX_HIDE_INDICES = NO #--------------------------------------------------------------------------- # configuration options related to the RTF output #--------------------------------------------------------------------------- # If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output # The RTF output is optimized for Word 97 and may not look very pretty with # other RTF readers or editors. GENERATE_RTF = NO # The RTF_OUTPUT tag is used to specify where the RTF docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `rtf' will be used as the default path. RTF_OUTPUT = rtf # If the COMPACT_RTF tag is set to YES Doxygen generates more compact # RTF documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_RTF = NO # If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated # will contain hyperlink fields. The RTF file will # contain links (just like the HTML output) instead of page references. # This makes the output suitable for online browsing using WORD or other # programs which support those fields. # Note: wordpad (write) and others do not support links. RTF_HYPERLINKS = NO # Load stylesheet definitions from file. Syntax is similar to doxygen's # config file, i.e. a series of assignments. You only have to provide # replacements, missing definitions are set to their default value. RTF_STYLESHEET_FILE = # Set optional variables used in the generation of an rtf document. # Syntax is similar to doxygen's config file. RTF_EXTENSIONS_FILE = #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- # If the GENERATE_MAN tag is set to YES (the default) Doxygen will # generate man pages GENERATE_MAN = YES # The MAN_OUTPUT tag is used to specify where the man pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `man' will be used as the default path. MAN_OUTPUT = man # The MAN_EXTENSION tag determines the extension that is added to # the generated man pages (default is the subroutine's section .3) MAN_EXTENSION = .3 # If the MAN_LINKS tag is set to YES and Doxygen generates man output, # then it will generate one additional man file for each entity # documented in the real man page(s). These additional files # only source the real man page, but without them the man command # would be unable to find the correct page. The default is NO. MAN_LINKS = NO #--------------------------------------------------------------------------- # configuration options related to the XML output #--------------------------------------------------------------------------- # If the GENERATE_XML tag is set to YES Doxygen will # generate an XML file that captures the structure of # the code including all documentation. GENERATE_XML = NO # The XML_OUTPUT tag is used to specify where the XML pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `xml' will be used as the default path. XML_OUTPUT = xml # The XML_SCHEMA tag can be used to specify an XML schema, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_SCHEMA = # The XML_DTD tag can be used to specify an XML DTD, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_DTD = # If the XML_PROGRAMLISTING tag is set to YES Doxygen will # dump the program listings (including syntax highlighting # and cross-referencing information) to the XML output. Note that # enabling this will significantly increase the size of the XML output. XML_PROGRAMLISTING = YES #--------------------------------------------------------------------------- # configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- # If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will # generate an AutoGen Definitions (see autogen.sf.net) file # that captures the structure of the code including all # documentation. Note that this feature is still experimental # and incomplete at the moment. GENERATE_AUTOGEN_DEF = NO #--------------------------------------------------------------------------- # configuration options related to the Perl module output #--------------------------------------------------------------------------- # If the GENERATE_PERLMOD tag is set to YES Doxygen will # generate a Perl module file that captures the structure of # the code including all documentation. Note that this # feature is still experimental and incomplete at the # moment. GENERATE_PERLMOD = NO # If the PERLMOD_LATEX tag is set to YES Doxygen will generate # the necessary Makefile rules, Perl scripts and LaTeX code to be able # to generate PDF and DVI output from the Perl module output. PERLMOD_LATEX = NO # If the PERLMOD_PRETTY tag is set to YES the Perl module output will be # nicely formatted so it can be parsed by a human reader. This is useful # if you want to understand what is going on. On the other hand, if this # tag is set to NO the size of the Perl module output will be much smaller # and Perl will parse it just the same. PERLMOD_PRETTY = YES # The names of the make variables in the generated doxyrules.make file # are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. # This is useful so different doxyrules.make files included by the same # Makefile don't overwrite each other's variables. PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- # If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will # evaluate all C-preprocessor directives found in the sources and include # files. ENABLE_PREPROCESSING = YES # If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro # names in the source code. If set to NO (the default) only conditional # compilation will be performed. Macro expansion can be done in a controlled # way by setting EXPAND_ONLY_PREDEF to YES. MACRO_EXPANSION = NO # If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES # then the macro expansion is limited to the macros specified with the # PREDEFINED and EXPAND_AS_DEFINED tags. EXPAND_ONLY_PREDEF = NO # If the SEARCH_INCLUDES tag is set to YES (the default) the includes files # in the INCLUDE_PATH (see below) will be search if a #include is found. SEARCH_INCLUDES = YES # The INCLUDE_PATH tag can be used to specify one or more directories that # contain include files that are not input files but should be processed by # the preprocessor. INCLUDE_PATH = # You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard # patterns (like *.h and *.hpp) to filter out the header-files in the # directories. If left blank, the patterns specified with FILE_PATTERNS will # be used. INCLUDE_FILE_PATTERNS = # The PREDEFINED tag can be used to specify one or more macro names that # are defined before the preprocessor is started (similar to the -D option of # gcc). The argument of the tag is a list of macros of the form: name # or name=definition (no spaces). If the definition and the = are # omitted =1 is assumed. To prevent a macro definition from being # undefined via #undef or recursively expanded use the := operator # instead of the = operator. PREDEFINED = # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then # this tag can be used to specify a list of macro names that should be expanded. # The macro definition that is found in the sources will be used. # Use the PREDEFINED tag if you want to use a different macro definition. EXPAND_AS_DEFINED = # If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then # doxygen's preprocessor will remove all function-like macros that are alone # on a line, have an all uppercase name, and do not end with a semicolon. Such # function macros are typically used for boiler-plate code, and will confuse # the parser if not removed. SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- # Configuration::additions related to external references #--------------------------------------------------------------------------- # The TAGFILES option can be used to specify one or more tagfiles. # Optionally an initial location of the external documentation # can be added for each tagfile. The format of a tag file without # this location is as follows: # TAGFILES = file1 file2 ... # Adding location for the tag files is done as follows: # TAGFILES = file1=loc1 "file2 = loc2" ... # where "loc1" and "loc2" can be relative or absolute paths or # URLs. If a location is present for each tag, the installdox tool # does not have to be run to correct the links. # Note that each tag file must have a unique name # (where the name does NOT include the path) # If a tag file is not located in the directory in which doxygen # is run, you must also specify the path to the tagfile here. TAGFILES = # When a file name is specified after GENERATE_TAGFILE, doxygen will create # a tag file that is based on the input files it reads. GENERATE_TAGFILE = # If the ALLEXTERNALS tag is set to YES all external classes will be listed # in the class index. If set to NO only the inherited external classes # will be listed. ALLEXTERNALS = NO # If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed # in the modules index. If set to NO, only the current project's groups will # be listed. EXTERNAL_GROUPS = YES # The PERL_PATH should be the absolute path and name of the perl script # interpreter (i.e. the result of `which perl'). PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- # If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will # generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base # or super classes. Setting the tag to NO turns the diagrams off. Note that # this option is superseded by the HAVE_DOT option below. This is only a # fallback. It is recommended to install and use dot, since it yields more # powerful graphs. CLASS_DIAGRAMS = YES # You can define message sequence charts within doxygen comments using the \msc # command. Doxygen will then run the mscgen tool (see # http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the # documentation. The MSCGEN_PATH tag allows you to specify the directory where # the mscgen tool resides. If left empty the tool is assumed to be found in the # default search path. MSCGEN_PATH = # If set to YES, the inheritance and collaboration graphs will hide # inheritance and usage relations if the target is undocumented # or is not a class. HIDE_UNDOC_RELATIONS = YES # If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is # available from the path. This tool is part of Graphviz, a graph visualization # toolkit from AT&T and Lucent Bell Labs. The other options in this section # have no effect if this option is set to NO (the default) HAVE_DOT = NO # By default doxygen will write a font called FreeSans.ttf to the output # directory and reference it in all dot files that doxygen generates. This # font does not include all possible unicode characters however, so when you need # these (or just want a differently looking font) you can specify the font name # using DOT_FONTNAME. You need need to make sure dot is able to find the font, # which can be done by putting it in a standard location or by setting the # DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory # containing the font. DOT_FONTNAME = FreeSans # By default doxygen will tell dot to use the output directory to look for the # FreeSans.ttf font (which doxygen will put there itself). If you specify a # different font using DOT_FONTNAME you can set the path where dot # can find it using this tag. DOT_FONTPATH = # If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect inheritance relations. Setting this tag to YES will force the # the CLASS_DIAGRAMS tag to NO. CLASS_GRAPH = YES # If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect implementation dependencies (inheritance, containment, and # class references variables) of the class with other documented classes. COLLABORATION_GRAPH = YES # If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen # will generate a graph for groups, showing the direct groups dependencies GROUP_GRAPHS = YES # If the UML_LOOK tag is set to YES doxygen will generate inheritance and # collaboration diagrams in a style similar to the OMG's Unified Modeling # Language. UML_LOOK = NO # If set to YES, the inheritance and collaboration graphs will show the # relations between templates and their instances. TEMPLATE_RELATIONS = NO # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT # tags are set to YES then doxygen will generate a graph for each documented # file showing the direct and indirect include dependencies of the file with # other documented files. INCLUDE_GRAPH = YES # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and # HAVE_DOT tags are set to YES then doxygen will generate a graph for each # documented header file showing the documented files that directly or # indirectly include this file. INCLUDED_BY_GRAPH = YES # If the CALL_GRAPH and HAVE_DOT options are set to YES then # doxygen will generate a call dependency graph for every global function # or class method. Note that enabling this option will significantly increase # the time of a run. So in most cases it will be better to enable call graphs # for selected functions only using the \callgraph command. CALL_GRAPH = NO # If the CALLER_GRAPH and HAVE_DOT tags are set to YES then # doxygen will generate a caller dependency graph for every global function # or class method. Note that enabling this option will significantly increase # the time of a run. So in most cases it will be better to enable caller # graphs for selected functions only using the \callergraph command. CALLER_GRAPH = NO # If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen # will graphical hierarchy of all classes instead of a textual one. GRAPHICAL_HIERARCHY = YES # If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES # then doxygen will show the dependencies a directory has on other directories # in a graphical way. The dependency relations are determined by the #include # relations between the files in the directories. DIRECTORY_GRAPH = YES # The DOT_IMAGE_FORMAT tag can be used to set the image format of the images # generated by dot. Possible values are png, jpg, or gif # If left blank png will be used. DOT_IMAGE_FORMAT = png # The tag DOT_PATH can be used to specify the path where the dot tool can be # found. If left blank, it is assumed the dot tool can be found in the path. DOT_PATH = # The DOTFILE_DIRS tag can be used to specify one or more directories that # contain dot files that are included in the documentation (see the # \dotfile command). DOTFILE_DIRS = # The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of # nodes that will be shown in the graph. If the number of nodes in a graph # becomes larger than this value, doxygen will truncate the graph, which is # visualized by representing a node as a red box. Note that doxygen if the # number of direct children of the root node in a graph is already larger than # DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note # that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. DOT_GRAPH_MAX_NODES = 50 # The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the # graphs generated by dot. A depth value of 3 means that only nodes reachable # from the root by following a path via at most 3 edges will be shown. Nodes # that lay further from the root node will be omitted. Note that setting this # option to 1 or 2 may greatly reduce the computation time needed for large # code bases. Also note that the size of a graph can be further restricted by # DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. MAX_DOT_GRAPH_DEPTH = 0 # Set the DOT_TRANSPARENT tag to YES to generate images with a transparent # background. This is enabled by default, which results in a transparent # background. Warning: Depending on the platform used, enabling this option # may lead to badly anti-aliased labels on the edges of a graph (i.e. they # become hard to read). DOT_TRANSPARENT = YES # Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output # files in one run (i.e. multiple -o and -T options on the command line). This # makes dot run faster, but since only newer versions of dot (>1.8.10) # support this, this feature is disabled by default. DOT_MULTI_TARGETS = NO # If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will # generate a legend page explaining the meaning of the various boxes and # arrows in the dot generated graphs. GENERATE_LEGEND = YES # If the DOT_CLEANUP tag is set to YES (the default) Doxygen will # remove the intermediate dot files that are used to generate # the various graphs. DOT_CLEANUP = YES #--------------------------------------------------------------------------- # Configuration::additions related to the search engine #--------------------------------------------------------------------------- # The SEARCHENGINE tag specifies whether or not a search engine should be # used. If set to NO the values of all tags below this one will be ignored. SEARCHENGINE = NO libshevek-1.3.orig/Makefile.am0000644000175000017500000000661311752426365015701 0ustar shevekshevek# Makefile.am - build rules # Copyright 2005-2012 Bas Wijnen # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . AUTOMAKE_OPTIONS = foreign subdir-objects # Rules for versions (current:revision:age), from libtool manual: # 1. Start with version information of ‘0:0:0’ for each libtool library. # 2. Update the version information only immediately before a public release of your software. More frequent updates are unnecessary, and only guarantee that the current interface number gets larger faster. # 3. If the library source code has changed at all since the last update, then increment revision (‘c:r:a’ becomes ‘c:r+1:a’). # 4. If any interfaces have been added, removed, or changed since the last update, increment current, and set revision to 0. # 5. If any interfaces have been added since the last public release, then increment age. # 6. If any interfaces have been removed or changed since the last public release, then set age to 0. VERSION_CURRENT = 0 VERSION_REVISION = 0 VERSION_AGE = 0 shevekdir = $(prefix)/include/shevek pkgdir = $(libdir)/pkgconfig lib_LTLIBRARIES = libshevek.la pkg_DATA = shevek.pc noinst_DATA = doc EXTRA_DIST = autogen.sh symbol-versions shevek.pc.in JUNK = configure ltmain.sh config.guess config.sub aclocal.m4 depcomp install-sh missing Makefile.in INSTALL COPYING shevek_HEADERS = \ src/args.hh \ src/avahi.hh \ src/bg.hh \ src/case.hh \ src/closure.hh \ src/crefptr.hh \ src/debug.hh \ src/dir.hh \ src/dl.hh \ src/error.hh \ src/fd.hh \ src/file.hh \ src/iostring.hh \ src/mainloop.hh \ src/process.hh \ src/refbase.hh \ src/regexp.hh \ src/server.hh \ src/shm.hh \ src/socket.hh \ src/split.hh \ src/telnet.hh \ src/time.hh libshevek_la_SOURCES = $(shevek_HEADERS) \ src/args.cc \ src/avahi.cc \ src/bg.cc \ src/case.cc \ src/closure.cc \ src/crefptr.cc \ src/debug.cc \ src/dir.cc \ src/dl.cc \ src/error.cc \ src/fd.cc \ src/file.cc \ src/iostring.cc \ src/mainloop.cc \ src/process.cc \ src/refbase.cc \ src/regexp.cc \ src/socket.cc \ src/split.cc \ src/telnet.cc \ src/time.cc libshevek_la_CPPFLAGS = -I.. $(AVAHI_CFLAGS) $(AVAHI_GLIB_CFLAGS) $(GLIBMM_CFLAGS) -Wall -Werror -ggdb3 -DCOPYRIGHT_YEARS=\"2005-2012\" -DCOPYRIGHT_EMAIL=\"wijnen@debian.org\" -DCOPYRIGHT_AUTHOR=\"Bas\ Wijnen\" libshevek_la_LDFLAGS = -Wl,--version-script -Wl,symbol-versions -version-info $(VERSION_CURRENT):$(VERSION_REVISION):$(VERSION_AGE) -Wl,--as-needed libshevek_la_LIBADD = $(AVAHI_GLIB_LIBS) $(AVAHI_LIBS) $(GLIBMM_LIBS) -ldl -lpthread libshevek_la_DEPENDENCIES = symbol-versions doc: doxygen config.doxygen $(MAKE) -C doc/latex # For some reason, files in here are created write-protected. # So use -f while removing them. clean-local: rm -rf doc autoclean: maintainer-clean ifneq ($(wildcard $(JUNK)),) rm -r $(wildcard $(JUNK)) endif .PHONY: doc libshevek-1.3.orig/AUTHORS0000644000175000017500000000003711553533024014675 0ustar shevekshevekBas Wijnen libshevek-1.3.orig/symbol-versions0000644000175000017500000000007311553533024016723 0ustar shevekshevekSHEVEK_1 { global: *shevek*; lt_dl*; local: *; }; libshevek-1.3.orig/.gitignore0000644000175000017500000000031111553533024015610 0ustar shevekshevek.libs Makefile Makefile.in aclocal.m4 autom4te.cache config.guess config.log config.status config.sub configure depcomp doc install-sh *.la libtool ltmain.sh missing shevek.pc .deps .dirstamp *.lo *.o libshevek-1.3.orig/README0000644000175000017500000000173411553533024014512 0ustar shevekshevekLibshevek is a collection of useful functions written mostly on top of Glib. The idea is to have things which work out of the box, with as little special configuration as possible. For example, you don't need to call shevek_init () or similar at the start of your program. I tried to stay low on dependencies. Still, I did want to use some things, and so I decided to depend on those. When deciding whether or not to add a dependency, I think of people who don't use the functionality. How much will it cost them to install those libraries anyway? The main dependency is Glib. Nothing works without it. There are no people who use libshevek but not Glib. So the above criterion puts no barrier on depending on it. I did add a dependency to avahi as well. Many programs use shevek::server, and it gets much more useful with avahi support. Also, any computer should have avahi installed anyway, so even if you don't use it with libshevek, you'll still want it installed on your machine. libshevek-1.3.orig/configure.ac0000644000175000017500000000243511713327752016126 0ustar shevekshevek# configure.ac - template for the configure script # Copyright 2005-2012 Bas Wijnen # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . AC_PREREQ(2.53) AC_INIT([libshevek],[1.3],[wijnen@debian.org]) AM_INIT_AUTOMAKE(AC_PACKAGE_NAME,AC_PACKAGE_VERSION) # for substitution in pkgconfig files VERSION=AC_PACKAGE_VERSION AC_PROG_CXX AC_PROG_LIBTOOL PKG_CHECK_MODULES(GLIBMM, glibmm-2.4,, AC_MSG_ERROR([You need Glibmm to compile AC_PACKAGE_NAME])) PKG_CHECK_MODULES(AVAHI, avahi-client,, AC_MSG_ERROR([You need avahi to compile AC_PACKAGE_NAME])) PKG_CHECK_MODULES(AVAHI_GLIB, avahi-glib,, AC_MSG_ERROR([You need avahi-glib to compile AC_PACKAGE_NAME])) AC_CONFIG_FILES(Makefile shevek.pc) AC_OUTPUT libshevek-1.3.orig/ChangeLog0000644000175000017500000003756211752433251015416 0ustar shevekshevek2012-05-09 Bas Wijnen * configure.ac: Version 1.3. * Makefile.am: Add copyright information. * src/iostring.cc: Fix string reading. * src/file.cc, src/process.cc, src/shm.hh, src/socket.cc: Include unistd.h for g++ 4.7. * src/telnet.cc, src/telnet.hh: Change enums to char constants for g++ 4.7. 2012-01-27 Bas Wijnen * configure.ac: Version 1.2. * src/iostring.cc, src/iostring.hh: Fix int, unsigned and string reading. 2011-04-11 Bas Wijnen * src/shm.hh: New file. * src/thread.hh, src/thread.cc: removed. * src/crefptr.hh: Avoid debugging message. * Makefile.am, shevek.pc.in: Handle new and removed files. 2011-04-10 Bas Wijnen * main/*, src/*: Rename directory. * sound/*: Removed. * src/gettext.hh, src/hex.hh, src/tiff.hh, src/hex.cc, src/tiff.cc, src/angle.hh, src/home.hh, src/sstr.hh, src/angle.cc, src/home.cc, src/vector.hh: move to old/, then remove. * configure.ac, Makefile.am: Update to reflect all changes. * README, NEWS: Removed; they were empty anyway. * src/shevek.pc.in, shevek.pc.in: Moved. * src/symbol-versions, symbol-versions: Moved. * autogen.sh, src/Makefile.am: Removed. * shevek.pc.in: Make dependencies public; add copyright defines. * configure.ac, src/dl.cc, src/dl.hh: Move from libltdl to libdl. * src/crefptr.cc, src/crefptr.hh: Improve debugging. * src/args.cc, src/args.hh: Move copyright to configure.ac. * config.doxygen, src/socket.hh, src/fd.hh, src/error.hh, src/regexp.hh, src/split.hh, src/args.hh, src/iostring.hh, src/dl.hh, src/refbase.hh, src/case.hh, src/process.hh, src/mainloop.hh, src/debug.hh, src/bg.hh, src/avahi.hh, src/telnet.hh, src/time.hh, src/crefptr.hh, src/server.hh, src/dir.hh, Makefile.am: Write and improve documentation. 2011-04-10 Bas Wijnen * main/Makefile.am: Disable unused files. * main/shevek.pc.in, sound/shevek-sound.pc.in: Make library dependencies public so newer linker can handle things. * main/error.hh: Always send ustring to error, or ostring chokes. * main/crefptr.cc, main/crefptr.hh: Bug hunting. 2011-03-07 Bas Wijnen * main/tiff.hh, main/iostring.hh, main/closure.cc, main/dir.cc, main/tiff.cc, main/socket.cc, main/args.cc, main/angle.hh, main/avahi.hh, main/angle.cc, sound/Makefile.am: Fix some bugs reported by cppcheck. 2010-10-27 Bas Wijnen * main/args.cc: Support configuration files. * main/Makefile.am, sound/Makefile.am, Makefile.am: Add library versioning comments. 2010-07-09 Bas Wijnen * main/crefptr.cc, main/crefptr.hh: Protect constructing objects from destruction. 2010-06-11 Bas Wijnen * main/args.cc, main/args.hh: Allow detection of argument usage. * main/Makefile.am, sound/Makefile.am: Add explicit soname. 2010-03-05 Bas Wijnen * main/crefptr.cc, main/crefptr.hh: Check target after set_owner. 2010-03-05 Bas Wijnen * main/iostring.cc: Support "% " and "%:". * main/hex.cc, main/hex.hh: New files. 2009-12-01 Bas Wijnen * main/fd.cc, main/fd.hh: Add write_raw support to allow binaries to be sent over telnet sockets. 2009-03-22 Bas Wijnen * main/crefptr.cc, main/crefptr.hh: New files. 2009-01-22 Bas Wijnen * main/refbase.hh: Add cast_dynamic member. 2009-01-11 Bas Wijnen * main/avahi.cc, main/avahi.hh: New files. * configure.ac, main/Makefile.am, main/socket.cc: Support and use the new files. * main/telnet.cc, main/socket.hh, main/fd.hh, main/closure.cc, main/refbase.hh, main/socket.cc, main/fd.cc, main/shevek.pc.in, main/thread.cc: Use object references instead of calls to reference. This way things automatically work right with exceptions. 2008-11-11 Bas Wijnen * main/tiff.hh, main/iostring.hh, main/dir.cc, main/thread.hh, main/tiff.cc, main/socket.cc, main/regexp.cc, main/args.cc, main/dl.cc, main/dir.hh, sound/vorbis.cc, sound/sound-player.cc, sound/sound-input.cc, sound/cd.cc, sound/cd-poll.cc: Don't use std::string with ostring. 2008-10-18 Bas Wijnen * main/error.hh, main/iostring.hh, main/dl.hh, main/thread.hh, main/socket.cc, main/tiff.cc, main/args.cc, main/iostring.cc, main/dl.cc, sound/vorbis.cc, sound/sound-player.cc, sound/sound-input.cc, sound/cd.cc: Make std::string/Glib::ustring difference in iostring explicit. 2008-10-06 Bas Wijnen * main/process.cc, main/process.hh: Improve interface. 2008-10-05 Bas Wijnen * main/process.cc: Allow process to die early; kill if it doesn't. 2008-09-29 Bas Wijnen * main/server.hh: Bugfixes. 2008-09-21 Bas Wijnen * main/iostring.hh, main/iostring.cc: Implement width and precision for ostring. * main/closure.hh, main/closure.cc: Bugfixes. 2008-08-22 Bas Wijnen * main/closure.hh, main/closure.cc: Allow reuse of closures, to avoid needless thread creation. 2008-08-14 Bas Wijnen * main/*, config.doxygen: Start with doxygen comments. 2008-08-11 Bas Wijnen * main/closure.hh, main/closure.cc, main/Makefile.am: Add support for closures. 2008-07-28 Bas Wijnen * main/iostring.hh, main/iostring.cc: Make pop return difference. 2008-06-26 Bas Wijnen * main/iostring.cc: Allow %a to get "all" from istring . 2008-06-09 Bas Wijnen * main/fd.cc: Protect idle handle from double registration. 2008-06-08 Bas Wijnen * main/iostring.hh: Add support for skipping input. * main/iostring.hh, main/iostring.cc: Use strto[u]l for reading numbers. 2008-05-29 Bas Wijnen * main/iostring.hh: Add istring::direct. 2008-05-25 Bas Wijnen * main/iostring.cc: Allow string formats as last character on line. 2008-05-24 Bas Wijnen * main/args.hh, main/args.cc: Avoid compiler errors when used without automake; don't show package name if it is identical to program name. 2008-05-23 Bas Wijnen * main/iostring.hh, main/iostring.cc: Implement ostring, fix istring. * main/refbase.cc: Remove debugging statements. 2008-04-26 Bas Wijnen * main/thread.hh, main/thread.cc: Add cancellation support. * main/iostring.cc, main/debug.cc, sound/sound-input-plugin.hh: Fix gcc-4.3 issues. 2008-04-01 Bas Wijnen * main/thread.hh, main/thread.cc: Add support for communicating threads. 2008-02-20 Bas Wijnen * main/shevek.pc, sound/shevek-sound.pc: Moved to *.pc.in. * configure.ac, main/Makefile.am, sound/Makefile.am: Generate *.pc files from *.pc.in files. * sound/sound.hh, sound/sound-player.cc: Don't use slots multithreaded. 2008-01-25 Bas Wijnen * main/iostring.hh: Renamed from main/reader.hh. * main/case.hh, main/case.cc: Add string case operations. * autogen.sh: Add --foreign switch to automake. * main/iostring.hh, main/iostring.cc, main/Makefile.am: Un-inline longer functions, add inf and nan support, add support for %[...]. 2007-12-06 Bas Wijnen Moved ChangeLog up, merging main and sound. * All files: Change license to GNU GPL 3 or later. * main/reader.hh: Fix end-of-input handling. 2007-04-02 Bas Wijnen * sound-input.cc: Accept reading DOS-newlines in databases. 2007-02-07 Bas Wijnen * Makefile.am: Install pkgconfig file. 2007-02-05 Bas Wijnen * ChangeLog: New file (sound parts split off from libshevek due to shared library dependencies). 2007-12-05 Bas Wijnen * reader.hh: Complete. 2007-12-04 Bas Wijnen * All files: Change license to GNU GPL version 3 or later. * reader.hh: New file. * Makefile.am: Include reader.hh. 2007-05-30 Bas Wijnen * Makefile.am: Add symbol-versions dependency. 2007-04-08 Bas Wijnen * process.cc: Bugfix. 2007-02-07 Bas Wijnen * split.cc, split.hh: Fix \nnn-handling. * debug.cc: Let dump send everything to target. 2007-02-05 Bas Wijnen * Makefile.am, shevek.pc: Add shevek.pc. * symbol-versions: Make all symbols global. 2007-01-18 Bas Wijnen * thread.cc, thread.hh: Merged again since libpthread is part of libc anyway. * Makefile.am: Create shared library. * symbol-versions: New file. 2007-01-16 Bas Wijnen * sound-player.cc, sound-recorder.cc, sound.hh, thread.cc, thread.hh: Split off into their own package in preparation of building shared libraries. * configure.ac, Makefile.am: Updated. 2007-01-15 Bas Wijnen * split.cc, split.hh: New files. * Makefile.am: Updated. 2006-11-17 Bas Wijnen * sound-recorder.cc: Bugfix. * debug.hh: Remove UNUSED macro. * tiff.cc: Change UNUSED macro into G_GNUC_UNUSED. * fd.cc: Add redundant check that buffer isn't uninitialised. * debug.hh: Change startfunc and dbg so they can be enabled without a recompile, through environment variables. * debug.cc: New file. * Makefile.am: Add debug.cc, enable warnings. 2006-11-03 Bas Wijnen * thread.hh, thread.cc: New files. * Makefile.am: Updated. 2006-08-25 Bas Wijnen * process.cc, process.hh: Avoid const_casts. 2006-08-24 Bas Wijnen * dl.hh: Make dl non-copyable. 2006-07-24 Bas Wijnen * dir.cc: Change to "error.hh". 2006-04-15 Bas Wijnen * sound.hh: Make --disable-alsa a compile-time option, which does not need to be repeated for programs linking to the library. * configure.ac, Makefile.am: Improve cross-compiling support. 2006-04-14 Bas Wijnen * Makefile.am: Link only to direct dependencies. 2006-04-13 Bas Wijnen * dir.cc, dir.hh: New files. * Makefile.am: Use dir.cc, dir.hh. 2006-04-11 Bas Wijnen * socket.cc: Use shevek_error instead of throw. * time.hh, time.cc: Add weekday support. 2006-03-31 Bas Wijnen * time.cc: Fix argument bugs in call to mktime. 2006-03-30 Bas Wijnen * time.hh, time.cc: Add support for local absolute times. * sound.hh: Typo fix. 2006-03-27 Bas Wijnen * sound-recorder.cc, sound-player.cc, sound.hh, configure.ac, Makefile.am: Allow compile-time disabling of alsa support. * sound-player.cc: Ignore EAGAIN instead of aborting on it. * debian/rules: Allow cross-compiling for arm (untested). * time.cc: Fix leap-year count error. 2006-03-01 Bas Wijnen * time.hh, time.cc (schedule): Add support for priorities. * Makefile.am: Added libshevek-pic again, because the previous thing didn't work. 2005-10-18 Bas Wijnen * Makefile.am: Removed libshevek-pic, use libtool to make libshevek contain PIC code as well. 2005-10-14 Bas Wijnen * sound.hh, sound.cc, sound-player.cc, sound-recorder.cc: Split implementation. * AUTHORS, README, NEWS, configure.ac, Makefile.am, autogen.sh: New files. * args.cc, args.hh, dl.cc, dl.hh: Moved to autotools. 2005-09-21 Bas Wijnen * bg.cc, bg.hh: New files. * Makefile.mm: Added files. 2005-09-02 Bas Wijnen * Makefile.mm: Removed double extra files. * fd.cc (hack_disconnect): Hack around SigC++ bug. * fd.cc: Increment reference count for callbacks (idle). * fd.cc: Bugfixes. 2005-08-31 Bas Wijnen * fd.cc: Fix double unread callback call. 2005-08-26 Bas Wijnen * sound.hh, sound.cc: Added OSS support. 2005-08-24 Bas Wijnen * sstr.hh: Use pointers, not references, to please gcc. * dl.cc, dl.hh: New files. * shevek.mm: Allow usage in shared objects. 2005-08-13 Bas Wijnen * args.cc (l_setup): Adjust argc and argv for use after parsing. * bootstrap: Break on error. * sound.cc (l_setup_device): Don't demand specific period size. * debian/changelog, debian/compat, debian/control, debian/copyright, debian/rules, debian/libshevek-dev.install: New files. 2005-08-06 Bas Wijnen * sound.cc (thread::l_setup_device): Correct periodsize for actual value. * args.hh, args.cc (args, l_setup): Change argc and argv. 2005-08-05 Bas Wijnen * Makefile.mm, sound.hh, sound.cc, bootstrap: Make sound.* files part of the archive. 2005-07-19 Bas Wijnen * error.hh, error.cc (_error_impl, shevek_warning, shevek_error, shevek_error_errno, shevek_warning_errno): Give file and line number information with errors. * tiff.cc (tiff::write): Fix memory leak. * shevek.mm: New file. 2005-06-09 Bas Wijnen * args.cc (l_setup): Don't flag arguments without default as required. 2005-06-06 Bas Wijnen * time.cc (schedule): Schedule events after I/O, not before. 2005-06-04 Bas Wijnen * args.hh, args.cc: Use program name and version of program, not library. * time.hh, time.cc: Allow cutting digits from fractions of seconds. 2005-05-11 Bas Wijnen * process.hh, process.cc (create, create, create, process, ~process, run): Specify which stdfds to pipe. 2005-05-04 Bas Wijnen * process.cc, process.hh: New files. * Makefile.mm: Updated. * fd.cc (read_block): Handle error on fd during poll. * fd.cc (l_read, l_read_priority): Allow and handle errors during block. * fd.cc (~fd): Disconnect idle handlers. * socket.cc (socket): Initialise m_name. * socket.cc (connect_unix): Use delete[] instead of delete. 2005-04-21 Bas Wijnen * fd.cc (read_block): Allow poll to return values > 1. * fd.cc (read_block): Handle data returned from normal read during priority read request. * fd.cc (read_line_block): Fix timeout check. * fd.cc (l_read): Don't call a callback when force filling. * angle.hh, angle.cc (operator<, operator>, operator<=, operator>=, operator==, operator!=): New functions. * args.hh, args.cc (operator[], begin, end): Use std::string instead of Glib::ustring for commandline arguments. 2005-04-19 Bas Wijnen * fd.hh, fd.cc (read_line_block): New function. * server.hh (continue_reading): New function. * server.hh (l_connect): Use continue_reading. * sstr.hh (getstr): New macro. 2005-03-18 Bas Wijnen * server.hh (open): Set use_stdio to true by default. * server.hh (~server, shutdown): Added shutdown, do at destruct. * socket.cc (listen, listen_unix, connect_unix, accept): Use errno in error message. * socket.cc (listen_unix, disconnect), socket.hh (m_name): Unlink socket at destruction. 2005-03-18 Bas Wijnen * server.hh (ignore_broken_pipes): Global variable to ignore SIGPIPE. * server.hh (connection): Added disconnect function. * server.hh: Removed self as argument to functions. 2005-03-18 Bas Wijnen * fd.cc (read, read_priority, read_lines, l_unread, unread, write, fd, l_read, l_read_priority, l_idle), fd.hh, socket.cc (l_finish_disconnect, disconnect), socket.hh, server.hh (l_error, l_delayed_disconnect): Flush read buffer before signalling EOF. * fd.cc (read_block): Checked value parameter instead of return. * fd.cc (l_read), socket.cc (socket): Made EOF an error condition. * fd.cc (l_read, l_write): Only handle result if there is no error. * fd.cc (l_check): Treat hangup as ready to read, not error. * fd.cc (l_check): Read data even if there is no callback. * fd.cc (l_idle): Disconnect handler if handled. * server.hh: Changed newlines to unix-style. 2005-01-28 Bas Wijnen * refbase.hh (refptr_this): Removed startfunc, keeping it independant of debug.hh. 2005-01-28 Bas Wijnen * ChangeLog: New file. libshevek-1.3.orig/shevek.pc.in0000644000175000017500000000042011553533024016037 0ustar shevekshevekprefix=@prefix@ exec_prefix=@exec_prefix@ libdir=@libdir@ includedir=@includedir@ Name: shevek Description: GLibmm extensions by shevek Version: @VERSION@ Requires: glibmm-2.4 avahi-client avahi-glib Libs: -L${libdir} -lshevek -lpthread -ldl -lrt Cflags: -I${includedir} libshevek-1.3.orig/src/0000755000175000017500000000000011753242637014425 5ustar sheveksheveklibshevek-1.3.orig/src/bg.cc0000644000175000017500000000273011553533024015315 0ustar shevekshevek/* bg.cc - send process to the background * Copyright 2005 Bas Wijnen * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include "bg.hh" #include "debug.hh" #include "error.hh" namespace shevek { void bg (bool exit_on_fail) { startfunc; char *debug = std::getenv ("SHEVEK_DEBUG"); if (debug && (std::string (":") + debug + ":").find (":bg:") != std::string::npos) { std::cerr << "shevek::bg called, but not backgrounding because " "bg is set in SHEVEK_DEBUG\n"; return; } switch (fork () ) { case -1: if (exit_on_fail) { shevek_error_errno ("unable to fork"); exit (1); } shevek_warning_errno ("unable to fork, remaining in foreground"); return; case 0: // child return; default: // parent exit (0); } } } libshevek-1.3.orig/src/debug.hh0000644000175000017500000000410111553533024016017 0ustar shevekshevek/* debug.hh - debugging macros * Copyright 2003 Bas Wijnen * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef SHEVEK_DEBUG_HH #define SHEVEK_DEBUG_HH #include #include #include #include #ifdef NDEBUG #define startfunc #define dbg(x) #else // !defined (NDEBUG) namespace shevek { extern bool _debug_dbg, _debug_startfunc; /// Make a hex-dump of data and send it to target. /** On the left, a hexadecimal representation of the bytes in data is printed. * On the right data itself, with non-printable characters replaced by def. */ void dump (std::string const &data, std::ostream &target, char def = '.'); } /// Print a message about the function that is being executed (if enabled at run-time). /** If SHEVEK_DEBUG contains %startfunc, this will print a message when * the function is entered. For this to happen, it must be written * at the start of a function, followed by a semicolon. */ #define startfunc \ do { if (shevek::_debug_startfunc) std::cerr << "Debug: entering " \ << __PRETTY_FUNCTION__ << '\n'; } while (0) /// Print a debugging message (if enabled at run-time). /** If SHEVEK_DEBUG contains %dbg, this will print the file and line this * occurs in, followed by the message x. */ #define dbg(x) do { if (shevek::_debug_dbg) std::cerr << __FILE__ << ':' \ << __LINE__ << '(' << __FUNCTION__ << "): " << x << '\n'; } while (0) #endif // !defined (NDEBUG) #endif // defined (SHEVEK_DEBUG_HH) libshevek-1.3.orig/src/avahi.hh0000644000175000017500000001557511553533024016042 0ustar shevekshevek/* avahi.hh - publish and browse network ports with avahi * Copyright 2009 Bas Wijnen * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef SHEVEK_AVAHI_HH #define SHEVEK_AVAHI_HH #include #include #include #include "refbase.hh" #include #include #include #include #include #include #include namespace shevek { /// Serve and browse the local network using avahi. /** Easy to use interface for serving and browsing avahi-supporting hosts. * Note that it is not as configurable as using libavahi directly. */ class avahi : public refbase { public: /// Publish a service on a port. /** The protocol is the name of the protocol, without leading underscore and without protocol specification. The published port is _NAME._tcp. It is not possible to publish over udp with this class. Note that you must separately set up a server to listen on the port. */ void publish (Glib::ustring const &protocol, int port); /// Class for browsing other hosts. class browser; /// Create a browser and populate it with a list of available hosts for the requested protocol. /** The browser must not contain a leading underscore, and must not contain the protocol specification. The actual requested port is _NAME._tcp. It is not possible to browse udp with this class. */ inline Glib::RefPtr create_browser (Glib::ustring const &protocol); /// Create an avahi object for serving and/or browsing. static Glib::RefPtr create (Glib::ustring const &name = Glib::ustring ()) { return Glib::RefPtr (new avahi (name)); } /// Unpublish all ports and free all structures associated with the object. ~avahi (); private: avahi (Glib::ustring const &name, bool allow_restart = true, bool blocking_poller = false); std::map m_ports; char *m_name; bool m_allow_restart; AvahiPoll const *m_poll_api; AvahiGLibPoll *m_glib_poll; AvahiEntryGroup *m_group; AvahiClient *m_client; AvahiSimplePoll *m_poller; void create_services (AvahiClient *client); void create_client (); void name_change (AvahiClient *client); static void group_callback (AvahiEntryGroup *g, AvahiEntryGroupState state, void *userdata); static void callback (AvahiClient *client, AvahiClientState state, void *userdata); }; /// Class for browsing other hosts. class avahi::browser : public refbase { public: /// Details about a discovered service. These are internally created and may be examined by the application. struct details { /// Network interface. AvahiIfIndex interface; /// Protocol. This is always tcp, because other protocols are never browsed by this class. AvahiProtocol protocol; /// Hostname or ip address of the server. Glib::ustring address; /// Some flags about the result. Usually not useful; see the avahi documentation for possible values and their meanings. AvahiLookupResultFlags flags; /// Create a details object. The application has no use for this. details (AvahiIfIndex i, AvahiProtocol p) : interface (i), protocol (p) {} /// Create a details object. The application has no use for this. details (AvahiIfIndex i, AvahiProtocol p, Glib::ustring a, AvahiLookupResultFlags f) : interface (i), protocol (p), address (a), flags (f) {} /// Create a details object. The application has no use for this. details () {} /// Allow sorting so details can be put in a std::set. bool operator< (details const &that) const { return interface == that.interface ? protocol < that.protocol : interface < that.interface; } }; /// Container class for a list of details. typedef std::set
details_list; /// Information about a discovered server. struct owner { /// Hostname or ip address of the server. Glib::ustring host; /// Port that is served by the server. int port; /// Create an owner object. The application has no use for this. owner (Glib::ustring const &h, int p) : host (h), port (p) {} /// Create an owner object. The application has no use for this. owner () : port (-1) {} /// Allow sorting so owners can be put in a std::map. bool operator< (owner const &that) const { return host == that.host ? port < that.port : host < that.host; } /// Services provided by this host. details_list details; }; /// Container class for a list of owners. typedef std::map list; /// Access the list of owners. list const &get_list () { return m_list; } /// Signal to be notified when the list changes. sigc::signal1 signal_changed () { return m_changed; } /// The destructor cleans everything up. ~browser (); /// Create a browser class without an existing avahi object. Don't use this if you have an avahi object; use avahi::create_browser instead. static Glib::RefPtr create (Glib::ustring const &protocol) { return Glib::RefPtr (new browser (avahi::create (), protocol)); } /// Synchronously get a list of owners. When using this, the servers are not monitored, so you will not be notified of any changes. static list get_list_block (Glib::ustring const &protocol, Glib::ustring const &name = Glib::ustring ()); private: Glib::RefPtr m_parent; list m_list; AvahiServiceBrowser *m_sb; sigc::signal1 m_changed; Glib::ustring m_filter; friend class avahi; browser (Glib::RefPtr parent, Glib::ustring const &protocol); static void resolve_callback (AvahiServiceResolver *r, AvahiIfIndex interface, AvahiProtocol protocol, AvahiResolverEvent event, char const *name, char const *type, char const *domain, char const *host_name, AvahiAddress const *address, uint16_t port, AvahiStringList *txt, AvahiLookupResultFlags flags, void * userdata); static void browse_callback (AvahiServiceBrowser *b, AvahiIfIndex interface, AvahiProtocol protocol, AvahiBrowserEvent event, char const *name, char const *type, char const *domain, AvahiLookupResultFlags flags, void *userdata); }; Glib::RefPtr avahi::create_browser (Glib::ustring const &protocol) { return Glib::RefPtr (new browser (refptr_this (), protocol)); } } #endif libshevek-1.3.orig/src/closure.cc0000644000175000017500000000745211553533024016407 0ustar shevekshevek/* closure.cc - Cooperative multitasking * Copyright 2008 Bas Wijnen * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "closure.hh" #include "error.hh" #include "debug.hh" #include #include namespace shevek { closure *closure::current = NULL; void closure::do_write (int *fds) { errno = 0; char c = 0; while (::write (fds[1], &c, 1) != 1) { if (errno == EINTR) { errno = 0; continue; } shevek_error_errno ("error writing for closure"); throw "error writing for closure"; } } void closure::do_read (int *fds) { char c = 0; errno = 0; while (::read (fds[0], &c, 1) != 1) { if (errno == EINTR) { errno = 0; continue; } shevek_error_errno ("error reading for closure"); throw "error reading for closure"; } } closure::closure () { closure *real_current = current; if (::pipe (blocking_pipe) || ::pipe (waking_pipe)) { shevek_error_errno ("unable to create pipes for closure"); throw "unable to create pipe for closure"; } state = EMPTY; if (::pthread_create (&thread, NULL, &start_wrapper, this)) { shevek_error_errno ("unable to create thread for closure"); throw "unable to create thread for closure"; } do_read (blocking_pipe); current = real_current; } closure::~closure () { if (::pthread_cancel (thread) || ::pthread_join (thread, NULL)) { shevek_warning_errno ("unable to kill closure"); } ::close (waking_pipe[0]); ::close (waking_pipe[1]); ::close (blocking_pipe[0]); ::close (blocking_pipe[1]); } void *closure::start_wrapper (void *d) { // Allow killing at any time. ::pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, NULL); current = reinterpret_cast (d); while (true) { block (); // Someone told us to start running with a function. // Do so. current->function (); // When done, set state to empty and call the callback // (if it exists). current->state = EMPTY; current->function = sigc::slot0 (); if (current->callback) { current->callback (); current->callback = sigc::slot0 (); } } return NULL; } void closure::set_function (sigc::slot0 func, bool run, sigc::slot0 cb) { if (!empty ()) { shevek_error ("changing function of non-empty closure"); throw "changing function of non-empty closure"; } function = func; state = BLOCKING; callback = cb; if (run) wake (); } void closure::block () { if (!current) { shevek_error ("trying to block non-closure"); throw "trying to block non-closure"; } closure *c = current; // Set state to blocking, unless it was EMPTY. if (c->state == RUNNING) c->state = BLOCKING; c->do_write (c->blocking_pipe); c->do_read (c->waking_pipe); c->state = RUNNING; } void closure::wake () { if (state != BLOCKING) { shevek_error ("trying to wake closure which isn't " "blocking"); throw "trying to wake closure which isn't blocking"; } Glib::RefPtr keep_object_alive = refptr_this (); (void)&keep_object_alive; closure *previous = current; current = this; do_write (waking_pipe); do_read (blocking_pipe); current = previous; } } libshevek-1.3.orig/src/file.cc0000644000175000017500000000330111752427702015645 0ustar shevekshevek/* file.hh - files with fd * Copyright 2003 Bas Wijnen * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "file.hh" #include "error.hh" #include #include #include #include namespace shevek { void file::open (std::string name, bool read, bool write) { if (!read && !write) shevek_error ("unable to open file: not reading and not writing"); int flags = read ? (write ? O_RDWR : O_RDONLY) : O_WRONLY; // NOCTTY is probably not usually doing anything, but it's good if it does. int filedes = ::open (name.c_str (), flags | O_NOCTTY); if (filedes < 0) shevek_error_errno ("unable to open file"); set_fd (filedes); } file::file (Glib::RefPtr main) : fd (-1, main) { set_eof (sigc::mem_fun (*this, &file::close) ); } void file::close () { if (get_fd () >= 0) ::close (get_fd () ); } file::~file () { close (); } Glib::RefPtr file::create (Glib::RefPtr main) { return Glib::RefPtr (new file (main) ); } } libshevek-1.3.orig/src/refbase.cc0000644000175000017500000000271311553533024016335 0ustar shevekshevek/* refbase.cc - base class for using Glib::RefPtr * Copyright 2003 Bas Wijnen * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "debug.hh" #include "refbase.hh" namespace shevek { void refbase::reference () { // in case of an overflow (2**(8*sizeof(int)) references), never delete // the object, because we will not know when. // This also makes sure that an object which is being deleted // can still be used (for example, if refptr_this is called from // its destructor). Of course those pointers should be destroyed when // the destructor finishes; this code doesn't check that. if (m_refcount) ++m_refcount; } void refbase::unreference () { if (m_refcount && !--m_refcount) { delete this; } } refbase::refbase () : m_refcount (1) { } refbase::~refbase () { } } libshevek-1.3.orig/src/regexp.hh0000644000175000017500000000463611553533024016240 0ustar shevekshevek/* regexp.hh - regular expressions * Copyright 2004 Bas Wijnen * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef SHEVEK_REGEXP_HH #define SHEVEK_REGEXP_HH #include #include #include #include "debug.hh" namespace shevek { /// Use regular expressions. class regexp { regex_t m_buffer; bool m_case_sensitive; regmatch_t *m_match; unsigned m_size; std::string m_pattern, m_data; void l_setup (std::string const &pattern, bool destroy); public: /// Create a new object, and optionally fill it with a pattern. regexp (std::string const &pattern = std::string (), bool case_sensitive = false); /// Set a pattern, removing the previous one. regexp &operator= (std::string const &pattern); /// Copy a regexp. regexp (regexp const &that); /// Copy a regexp. regexp &operator= (regexp const &that); /// Set whether the evaluation should be case sensitive. void case_sensitive (bool value = true); /// Destructor, this cleans up internal structures. ~regexp (); /// Check whether the pattern matches a string, and fill internal match structures if it does. bool operator() (std::string const &data); /// Retrieve the value of a subexpression from the last matched string. /** This throws an exception if the subexpression is not valid. */ std::string operator[] (unsigned idx) const; /// Test whether a subexpression was filled by the last matching string. bool valid (unsigned idx) const; /// Get the number of subexpression. unsigned size () const; /// Transform a string with \-codes according to the last matching string. std::string transform (std::string const &data) const; /// Get the current pattern. std::string const &pattern () const; }; } #endif libshevek-1.3.orig/src/refbase.hh0000644000175000017500000000506211553533024016347 0ustar shevekshevek/* refbase.hh - base class for using Glib::RefPtr * Copyright 2003 Bas Wijnen * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef SHEVEK_REFBASE_HH #define SHEVEK_REFBASE_HH #include #include namespace shevek { /// Base class for classes which want reference counting through Glib::RefPtr. class refbase { public: /// Identical to GLib::RefPtr <>::cast_dynamic, but nicer to type. template Glib::RefPtr <_T> cast_dynamic () { return Glib::RefPtr <_T>::cast_dynamic (refptr_this ()); } protected: /// Constructor, increments reference count. refbase (); /// Destructor, decrements reference count and destroys the object if it reaches 0. virtual ~refbase (); /// Get a RefPtr to this, protected because only members should need it. /** This function allows member functions, which have a pointer to the * object, but not a Glib::RefPtr, to pass a RefPtr to others. */ template Glib::RefPtr refptr_this (); private: // Not copyable refbase (refbase const &that); refbase &operator= (refbase const &that); // Reference functions, needed for Glib::RefPtr. virtual void reference (); virtual void unreference (); // Allow Glib::RefPtr to call the above. template friend class Glib::RefPtr; // Reference count. unsigned m_refcount; }; template Glib::RefPtr refbase::refptr_this () { // This is a bit of a hack, but I don't see a way to solve it otherwise. // The idea is that members of refbase-derived classes need a refptr to // their this pointer, to give away. // The only usable constructor of RefPtr for that purpose is the one which // is meant for create (). However, that does not increment the reference // counter. So I do that by hand. reference (); return Glib::RefPtr (dynamic_cast (this) ); } } #endif libshevek-1.3.orig/src/dir.hh0000644000175000017500000000401711553533024015515 0ustar shevekshevek/* dir.hh - directory access * Copyright 2006 Bas Wijnen * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef SHEVEK_DIR_HH #define SHEVEK_DIR_HH #include #include #include #include namespace shevek { /// Get information about files in a directory. class dir { public: /// Information about a single file in a directory. struct file { /// The name of the file. std::string name; /// Whether it is a directory. bool is_dir; /// The user-ID of the file. uid_t uid; /// The group-ID of the file. gid_t gid; /// The size of the file. off_t size; /// Sorting operator, needed for putting them in a std::set. bool operator< (file const &that) const; }; /// Storage of the files. typedef std::set store; /// Iterator for looping over the files. typedef store::const_iterator const_iterator; /// Create an empty directory object. dir (); /// Create a directory object and load content into it. dir (std::string const &path); /// Load new content into an existing directory object. void load (std::string const &path); /// Loop over the files. const_iterator begin () const; /// Loop over the files. const_iterator end () const; /// Number of files in the directory. unsigned size () const; private: store data; }; } #endif libshevek-1.3.orig/src/time.hh0000644000175000017500000002320211553533024015672 0ustar shevekshevek/* time.hh - class definitions to work with time. * Copyright 2003-2006 Bas Wijnen * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef SHEVEK_TIME_HH #define SHEVEK_TIME_HH #include #include namespace shevek { /// Schedule a callback for when the main loop has time. sigc::connection schedule (sigc::slot0 callback, int prio = Glib::PRIORITY_HIGH_IDLE, Glib::RefPtr context = Glib::MainContext::get_default () ); /// Type for storing the time. typedef int64_t timetype; class relative_time; /// The absolute_time class stores a date and time. /** Everything is in UTC, except the output of local_* (); */ class absolute_time { // number of seconds since epoch. timetype m_seconds; // number of nanoseconds. Should be less than 1000 000 000. unsigned m_nanoseconds; static bool l_schedule (sigc::slot0 callback); // let schedule use l_schedule friend sigc::connection schedule (sigc::slot0 callback, int prio, Glib::RefPtr context); static unsigned s_digits; public: /// Create a new absolute_time containing the current time. /** Note that this makes a call to gettimeofday, which is much slower than specifying seconds and nanoseconds. * Thus, if you need an absolute_time object to fill with an actual time later, use absolute_time foo (0, 0); instead of this default constructor. */ absolute_time (); /// A specific time. /** days may be 0-365, with months 0. * If months > 0, both days and months have a base of 1. */ absolute_time (unsigned years, unsigned months, unsigned days, unsigned hours, unsigned minutes, unsigned seconds, unsigned nanoseconds = 0); /// Fast constructor. /** This directly fills the internal structures. * It is therefore faster than the other constructors, in particular the default constructor, which makes a kernel call. */ absolute_time (timetype seconds, unsigned nanoseconds); /// Semi-constructor which creates a new absolute_time given a date in local time. /** The input is the same as for the similar constructor. */ static absolute_time create_from_local (unsigned years, unsigned months, unsigned days, unsigned hours, unsigned minutes, unsigned seconds, unsigned nanoseconds = 0); /// Set number of digits to use when printing (for fractions of seconds) static void set_digits (unsigned num); /// Get the number of digits which is used when printing. static unsigned get_digits (); /// Add an interval to this moment. absolute_time operator+ (relative_time that) const; /// Subtract an interval from this moment. absolute_time operator- (relative_time that) const; /// Compute the interval between two moments. relative_time operator- (absolute_time that) const; /// Add an interval to this moment. absolute_time &operator+= (relative_time that); /// Subtract an interval from this moment. absolute_time &operator-= (relative_time that); /// Compare two moments. bool operator< (absolute_time that) const; /// Compare two moments. bool operator> (absolute_time that) const; /// Compare two moments. bool operator<= (absolute_time that) const; /// Compare two moments. bool operator>= (absolute_time that) const; /// Compare two moments. /** Note that this is rarely a useful operation, because minor errors may be introduced by computations. * In other words: only use this on times which have been set, never on times which have been computed. */ bool operator== (absolute_time that) const; /// Compare two moments. /** Note that this is rarely a useful operation, because minor errors may be introduced by computations. * In other words: only use this on times which have been set, never on times which have been computed. */ bool operator!= (absolute_time that) const; /// Get the nanoseconds. unsigned nanoseconds () const; /// Get the seconds in local time. unsigned local_second () const; /// Get the minutes in local time. unsigned local_minute () const; /// Get the hour in local time. unsigned local_hour () const; /// Get the day of the year in local time, range 0-365. unsigned local_days () const; /// Get the day of the month in local time, range 1-31. unsigned local_day () const; /// Get the day of the week in local time, range 0-6 where 0 means sunday. unsigned local_weekday () const; /// Get the month in local time, range 1-12. unsigned local_month () const; /// Get the year in local time. unsigned local_year () const; /// Get the seconds in UTC. unsigned second () const; /// Get the minutes in UTC. unsigned minute () const; /// Get the hour in UTC. unsigned hour () const; /// Get the day of the year in UTC, range 0-365. unsigned days () const; /// Get the day of the month in UTC, range 1-31. unsigned day () const; /// Get the day of the week in UTC, range 0-6 where 0 means sunday. unsigned weekday () const; /// Get the month in UTC, range 1-12. unsigned month () const; /// Get the year in UTC. unsigned year () const; /// Total number of seconds since january 1970, as encoded. timetype total () const; /// Schedule a callback at a certain time. sigc::connection schedule (sigc::slot0 callback, Glib::RefPtr context = Glib::MainContext::get_default ()); /// Write the time to a std::ostream. friend std::ostream &operator<< (std::ostream &s, absolute_time t); }; /// Time interval. class relative_time { // number of seconds. timetype m_seconds; // number of nanoseconds. Should be less than 1000000000. int m_nanoseconds; static unsigned s_digits; public: /// The default constructor creates an interval of 0. relative_time (); /// Construct an interval of a given size. relative_time (timetype days, int hours, int minutes, int seconds, int nanoseconds = 0); /// Fast constructor. /** This directly fills the members and is therefore slightly faster than the other constructors. * However, the others aren't really slow either. */ relative_time (timetype seconds, unsigned nanoseconds); /// Set number of digits to use when printing (for fractions of seconds). static void set_digits (unsigned num); /// Get the number of digits that is used when printing. static unsigned get_digits (); /// Add two intervals. relative_time operator+ (relative_time that) const; /// Add an interval to a moment. absolute_time operator+ (absolute_time that) const; /// Subtract two intervals. relative_time operator- (relative_time that) const; /// Negate an interval. relative_time operator- () const; /// Scale an interval. relative_time operator* (float c) const; /// Scale an interval. relative_time operator/ (float c) const; /// Modulo operator for two intervals. relative_time operator% (relative_time that) const; /// Division of two intervals. double operator/ (relative_time that) const; /// Add an interval. relative_time &operator+= (relative_time that); /// Subtract an interval. relative_time &operator-= (relative_time that); /// Scale the interval. relative_time &operator*= (float c); /// Scale the interval. relative_time &operator/= (float c); /// Modulo. relative_time &operator%= (relative_time that); /// Compare with another interval. bool operator< (relative_time that) const; /// Compare with another interval. bool operator> (relative_time that) const; /// Compare with another interval. bool operator<= (relative_time that) const; /// Compare with another interval. bool operator>= (relative_time that) const; /// Compare two intervals. Note that this is rarely a useful operation, /// because minor errors may be introduced by computations. bool operator== (relative_time that) const; /// Compare two intervals. Note that this is rarely a useful operation, /// because minor errors may be introduced by computations. bool operator!= (relative_time that) const; /// Number of nanoseconds. unsigned nanoseconds () const; /// Number of seconds. unsigned seconds () const; /// Number of minutes. unsigned minutes () const; /// Number of hours. unsigned hours () const; /// Number of days. unsigned days () const; /// Is this a negative interval? bool isnegative () const; /// Total number of seconds, as encoded. timetype total () const; /// Write the interval to a std::ostream. friend std::ostream &operator<< (std::ostream &s, relative_time t); private: // internal function to clean the seconds/nanoseconds void l_clean (); }; /// Read a time from a std::istream. std::istream &operator>> (std::istream &s, absolute_time &t); /// Read an interval from a std::istream. std::istream &operator>> (std::istream &s, relative_time &t); } #endif libshevek-1.3.orig/src/shm.hh0000644000175000017500000000556511752430076015543 0ustar shevekshevek/* shm.hh - shared memory * Copyright 2007 Bas Wijnen * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef SHEVEK_SHM_HH #define SHEVEK_SHM_HH #include "refbase.hh" #include "error.hh" #include #include #include #include #include #include namespace shevek { /// This class implements an interface for sharing memory between processes. template class shm : public refbase { shm (std::string const &name, bool l_create, bool writable, bool keep); ~shm (); T *m_data; std::string m_name; int m_fd; bool m_destroy; public: /// Create a new block of shared memory. /** If keep is true, it will not be unlinked when the object is destroyed. */ static Glib::RefPtr > create (std::string const &name, bool keep = false) { return Glib::RefPtr > (new shm (name, true, true, keep)); } /// Open an existing block of shared memory. static Glib::RefPtr > open (std::string const &name, bool writable = true) { return Glib::RefPtr > (new shm (name, false, writable, true)); } /// Access the shared data. T *data () { return m_data; } /// Access the shared data. T const *data () const { return m_data; } }; template shm ::shm (std::string const &name, bool l_create, bool writable, bool keep) { m_destroy = !keep; m_name = std::string ("/") + typeid (T).name () + '-' + name; m_fd = shm_open (m_name.c_str (), l_create ? O_CREAT | O_EXCL | O_RDWR : writable ? O_RDWR : O_RDONLY, 0666); if (m_fd < 0) { shevek_error_errno ("unable to open shared memory file " + m_name); throw "unable to open shared memory file"; } if (l_create && ftruncate (m_fd, sizeof (T)) < 0) { shevek_error_errno ("unable to set size of shared memory file " + m_name); throw "unable to set size of shared memory file"; } m_data = reinterpret_cast (mmap (NULL, sizeof (T), writable ? PROT_READ | PROT_WRITE : PROT_READ, MAP_SHARED, m_fd, 0)); if (!m_data) { shevek_error_errno ("unable to map shared memory file " + m_name); throw "unable to map shared memory"; } } template shm ::~shm () { close (m_fd); munmap (m_data, sizeof (T)); if (m_destroy) shm_unlink (m_name.c_str ()); } } #endif libshevek-1.3.orig/src/split.cc0000644000175000017500000000710311553533024016057 0ustar shevekshevek/* split.cc - split a line into words * Copyright 2007 Bas Wijnen * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "split.hh" #include "error.hh" #include namespace { bool get_digit (char c, unsigned &d) { if (c >= '0' && c <= '9') { d = c - '0'; return true; } if (c >= 'a' && c <= 'f') { d = c - 'a' + 10; return true; } if (c >= 'A' && c <= 'F') { d = c - 'A' + 10; return true; } return false; } } namespace shevek { void split::load (std::string const &str, bool allow_empty, std::string const &delimiters) { std::string::size_type p = 0; bool have_quote = false; while (true) { if (!allow_empty) p = str.find_first_not_of (delimiters, p); if (p == std::string::npos || p >= str.size ()) break; push_back (std::string ()); char quote = 0; for (; true; ++p) { if (p == std::string::npos || p >= str.size ()) break; if (have_quote) { if (str[p] == quote) { have_quote = false; continue; } back () += str[p]; continue; } if (str[p] == '"' || str[p] == '\'') { quote = str[p]; have_quote = true; continue; } if (delimiters.find (str[p]) != std::string::npos) { ++p; break; } if (str[p] == '\\') { ++p; if (p == str.size ()) { shevek_error ("backslash at end of line"); return; } if (str[p] >= '0' && str[p] < '8') { unsigned d[3]; d[0] = str[p] - '0'; if (str.size () > p + 1) d[1] = str[p + 1] - '0'; else d[1] = 9; if (d[1] < 8 && str.size () > p + 2) d[2] = str[p + 2] - '0'; else d[2] = 9; char result = 0; for (unsigned i = 0; i < 3; ++i) { if (d[i] >= 8) break; ++p; result <<= 3; result |= d[i]; } --p; back () += result; continue; } switch (str[p]) { case 'x': { ++p; unsigned d[2]; if (str.size () <= p) { shevek_error ("\\x at end of line"); return; } if (!get_digit (str[p], d[0])) { shevek_error ("no hex digit after \\x"); return; } if (str.size () == p + 1 || !get_digit (str[p + 1], d[1])) { back () += (char)d[0]; continue; } ++p; back () += (char)((d[0] << 4) + d[1]); continue; } case 'n': back () += '\n'; continue; case 'r': back () += '\r'; continue; case 't': back () += '\t'; continue; case 'a': back () += '\a'; continue; case 'v': back () += '\v'; continue; case 'f': back () += '\f'; continue; } // fall through } back () += str[p]; } } } split split::sub (unsigned from) const { split ret; if (from < size ()) { std::copy (begin () + from, end (), std::back_inserter (ret)); } return ret; } } libshevek-1.3.orig/src/regexp.cc0000644000175000017500000001006611553533024016220 0ustar shevekshevek/* regexp.icc - inline functions for regexp.hh -*- C++ -*- * Copyright 2003 Bas Wijnen * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "regexp.hh" #include "iostring.hh" namespace shevek { void regexp::l_setup (std::string const &pattern, bool destroy) { startfunc; m_pattern = pattern; m_data.clear (); int flags = REG_EXTENDED; if (!m_case_sensitive) flags |= REG_ICASE; int r = regcomp (&m_buffer, pattern.c_str (), flags); if (r) { size_t s = regerror (r, &m_buffer, 0, 0); char *err = new char[s]; std::string str_err (err, s - 1); delete[] err; if (!destroy) { // this will not fail, but if it does, it shouldn't loop. l_setup ("", true); } throw std::string (rostring ("error compiling regular expression: %s", str_err)); } m_match = new regmatch_t[m_buffer.re_nsub + 1]; m_size = m_buffer.re_nsub + 1; } regexp::regexp (std::string const &pattern, bool case_sensitive) : m_case_sensitive (case_sensitive) { startfunc; l_setup (pattern, true); } regexp ®exp::operator= (std::string const &pattern) { startfunc; regfree (&m_buffer); delete[] m_match; l_setup (pattern, false); return *this; } regexp::regexp (regexp const &that) : m_case_sensitive (that.m_case_sensitive) { startfunc; l_setup (that.m_pattern, true); } regexp ®exp::operator= (regexp const &that) { startfunc; regfree (&m_buffer); delete[] m_match; l_setup (that.m_pattern, false); return *this; } void regexp::case_sensitive (bool value) { startfunc; m_case_sensitive = value; } regexp::~regexp () { startfunc; regfree (&m_buffer); delete[] m_match; } bool regexp::operator() (std::string const &data) { startfunc; m_data = data; // An empty pattern never matches // (this is an exception, because actually it always matches). if (m_pattern.empty () ) return false; return regexec (&m_buffer, data.c_str (), m_size, m_match, 0) == 0; } std::string regexp::operator[] (unsigned idx) const { startfunc; if (!valid (idx) ) throw "invalid index"; return m_data.substr (m_match[idx].rm_so, m_match[idx].rm_eo - m_match[idx].rm_so); } bool regexp::valid (unsigned idx) const { startfunc; if (idx >= m_size) throw "index out of range"; return m_match[idx].rm_so != -1; } unsigned regexp::size () const { startfunc; return m_size; } std::string regexp::transform (std::string const &data) const { startfunc; std::string retval; std::string::size_type p, last = 0; while ( (p = data.find ('\\', last) ) != std::string::npos) { retval += data.substr (last, p - last); last = p + 1; if (data.size () == p + 1) throw "unexpected \\ at end of transform data"; if (data[p + 1] == '\\') { retval += '\\'; ++last; } else { p = data.find_first_not_of ("0123456789", last); std::string number; if (p == std::string::npos) { number = data.substr (last); last = data.size (); } else { number = data.substr (last, p - last); if (data[p] == '\\') last = p + 1; else last = p; } unsigned idx = atoi (number.c_str () ); retval += (*this)[idx]; } } retval += data.substr (last); return retval; } std::string const ®exp::pattern () const { startfunc; return m_pattern; } } libshevek-1.3.orig/src/socket.cc0000644000175000017500000003010711752430237016217 0ustar shevekshevek/* socket.cc - function implementations for shevek::socket -*- C++ -*- * Copyright 2003-2005 Bas Wijnen * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "socket.hh" #include "error.hh" #include namespace shevek { Glib::RefPtr socket::create (Glib::RefPtr main) { startfunc; return Glib::RefPtr (new socket (main) ); } socket::socket (Glib::RefPtr main) : fd (-1, main), m_listener (false), m_name (0) { startfunc; // default error response is to disconnect. This can be overridden. set_error (sigc::mem_fun (*this, &socket::disconnect) ); } socket::~socket () { startfunc; disconnect (); } // convert service to (host byte order) port int socket::l_service_to_port (std::string const &service) { startfunc; int port; char const *c = service.c_str (); struct servent *serv = getservbyname (c, "tcp"); if (serv == 0) { char *end; port = strtol (c, &end, 0); if (*c == 0 || *end != 0) shevek_error (ostring ("unable to find service %s", Glib::ustring (service))); } else port = ntohs (serv->s_port); return port; } void socket::listen_tcp (std::string const &service, listen_t cb, unsigned queue) { startfunc; Glib::RefPtr have_reference = refptr_this (); disconnect (); struct addrinfo *result; struct addrinfo hints; memset (&hints, 0, sizeof (struct addrinfo)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = 0; hints.ai_flags = AI_PASSIVE; int ret = getaddrinfo (NULL, service.c_str (), &hints, &result); if (ret != 0) { shevek_error (Glib::ustring (std::string (rostring ("unable to parse tcp port %s: %s", service, gai_strerror (ret))))); return; } for (struct addrinfo *ai = result; ai; ai = ai->ai_next) { int filedes = ::socket (ai->ai_family, ai->ai_socktype, ai->ai_protocol); if (filedes < 0) continue; int opt = 1; setsockopt (filedes, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof (opt) ); if (::bind (filedes, ai->ai_addr, ai->ai_addrlen) == 0) { // Success. freeaddrinfo (result); if (::listen (filedes, queue) != 0) shevek_error_errno (Glib::ustring (std::string (rostring ("cannot listen to bound socket for %s", service)))); set_fd (filedes); m_listener = true; read_custom (cb); return; } } freeaddrinfo (result); shevek_error (Glib::ustring (std::string (rostring ("unable to open listening socket for %s", service)))); } void socket::listen_avahi (std::string const &service, Glib::ustring const &protocol, Glib::ustring const &name, listen_t cb, unsigned queue) { startfunc; Glib::RefPtr have_reference = refptr_this (); listen_tcp (service, cb, queue); m_avahi = avahi::create (name); m_avahi->publish (protocol, l_service_to_port (service)); } void socket::listen_unix (std::string const &file, listen_t cb, unsigned queue) { startfunc; Glib::RefPtr have_reference = refptr_this (); disconnect (); int filedes = ::socket (PF_UNIX, SOCK_STREAM, 0); if (filedes < 0) { shevek_error_errno ("unable to open socket"); return; } struct sockaddr_un *addr = reinterpret_cast (new char [sizeof (struct sockaddr_un) + file.size () + 1]); addr->sun_family = AF_UNIX; memcpy (addr->sun_path, file.data (), file.size () ); addr->sun_path[file.size ()] = 0; if (::bind (filedes, reinterpret_cast (addr), SUN_LEN (addr) ) ) { delete[] addr; shevek_error_errno ("unable to bind to file"); return; } delete[] addr; if (::listen (filedes, queue) ) { ::unlink (file.c_str () ); shevek_error_errno ("unable to listen on file"); return; } m_listener = true; set_fd (filedes); read_custom (cb); m_name = new std::string (file); } void socket::listen (std::string const &port, listen_t cb, unsigned queue) { startfunc; Glib::RefPtr have_reference = refptr_this (); // discriminate unix/tcp sockets on a '/' in their name. There may be // localisations where a '/' may appear in numbers. If so, then those // numbers are not supported. Also, I don't allow /'s in service names. // // avahi sockets are specified as service-or-port|name|protocol if (port.find ('/') != std::string::npos) listen_unix (port, cb, queue); else { std::string::size_type p = port.find ('|'); if (p == std::string::npos) listen_tcp (port, cb, queue); else { std::string block = port.substr (p + 1); std::string::size_type p2 = block.find ('|'); if (p2 == std::string::npos) { shevek_error ("avahi socket needs two |'s"); return; } listen_avahi (port.substr (0, p), block.substr (p2 + 1), block.substr (0, p2), cb, queue); } } } void socket::connect_tcp (std::string const &host, std::string const &service) { startfunc; Glib::RefPtr have_reference = refptr_this (); disconnect (); struct addrinfo *result; struct addrinfo hints; memset (&hints, 0, sizeof (struct addrinfo)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = 0; hints.ai_flags = AI_V4MAPPED | AI_ADDRCONFIG; int ret = getaddrinfo (host.empty () ? NULL : host.c_str (), service.c_str (), &hints, &result); if (ret != 0) { shevek_error (Glib::ustring (std::string (rostring ("unable to parse tcp address %s, port %s: %s", host, service, gai_strerror (ret))))); return; } for (struct addrinfo *ai = result; ai; ai = ai->ai_next) { int filedes = ::socket (ai->ai_family, ai->ai_socktype, ai->ai_protocol); if (filedes < 0) continue; if (::connect (filedes, ai->ai_addr, ai->ai_addrlen) >= 0) { // Success. set_fd (filedes); freeaddrinfo (result); return; } } freeaddrinfo (result); shevek_error (Glib::ustring (std::string (rostring ("unable to open socket to %s for %s", host, service)))); } void socket::connect_avahi (avahi::browser::owner const &target, avahi::browser::details const &details) { startfunc; Glib::RefPtr have_reference = refptr_this (); if (!details.address.empty ()) connect_tcp (std::string (details.address), rostring ("%d", target.port)); else { for (avahi::browser::details_list::const_iterator i = target.details.begin (); i != target.details.end (); ++i) { try { connect_tcp (std::string (i->address), rostring ("%d", target.port)); return; } catch (...) { // Ignore. } } shevek_error ("unable to open avahi target"); } } void socket::connect_unix (std::string const &unix_name) { startfunc; Glib::RefPtr have_reference = refptr_this (); disconnect (); int filedes = ::socket (PF_UNIX, SOCK_STREAM, 0); if (filedes < 0) { shevek_error_errno ("unable to open socket"); } struct sockaddr_un *addr = reinterpret_cast (new char [sizeof (struct sockaddr_un) + unix_name.size () + 1]); addr->sun_family = AF_UNIX; memcpy (addr->sun_path, unix_name.data (), unix_name.size () ); addr->sun_path[unix_name.size ()] = 0; if (::connect (filedes, reinterpret_cast (addr), SUN_LEN (addr) ) ) { delete[] reinterpret_cast (addr); shevek_error_errno ("unable to connect"); throw "unable to connect"; } delete[] reinterpret_cast (addr); set_fd (filedes); } void socket::connect (std::string const &port) { startfunc; Glib::RefPtr have_reference = refptr_this (); if (port.find ('/') != std::string::npos) { connect_unix (port); return; } std::string::size_type p = port.find_last_of (':'); if (p != std::string::npos) { connect_tcp (port.substr (0, p), port.substr (p + 1)); return; } p = port.find ('|'); if (p == std::string::npos) { connect_tcp ("", port); return; } std::string name = port.substr (0, p); std::string protocol = port.substr (p + 1); avahi::browser::list list = avahi::browser::get_list_block (protocol, name); if (list.empty ()) { shevek_error (Glib::ustring (std::string (rostring ("unable to connect to avahi type %s, protocol %s: no server found", name, protocol)))); return; } if (list.size () > 1) { shevek_error (Glib::ustring (std::string (rostring ("unable to connect to avahi type %s, protocol %s: multiple servers found", name, protocol)))); return; } connect_tcp (std::string (list.begin ()->second.details.begin ()->address), rostring ("%d", list.begin ()->second.port)); } void socket::accept (Glib::RefPtr sock) { startfunc; Glib::RefPtr have_reference = refptr_this (); int filedes = ::accept (get_fd (), NULL, NULL); if (filedes < 0) shevek_error_errno ("unable to accept connection"); sock->set_fd (filedes); } void socket::l_finish_disconnect () { m_disconnect (); } void socket::disconnect () { startfunc; if (get_fd () < 0) return; Glib::RefPtr have_reference = refptr_this (); m_listener = false; if (m_name) { dbg ("unlinking " << m_name); if (::unlink (m_name->c_str ())) shevek_warning_errno ("failed to unlink unix socket"); delete m_name; m_name = NULL; } dbg ("possibly tried to unlink"); write_reset (); ::close (get_fd ()); set_fd (-1); unread (true, sigc::mem_fun (*this, &socket::l_finish_disconnect) ); } std::string socket::l_get_socket_info (struct sockaddr_in *addr, bool numeric) const { startfunc; if (addr->sin_family != AF_INET) { shevek_error ("not an ipv4 address"); return std::string (); } std::string port_s; if (!numeric) { struct servent *se = getservbyport (addr->sin_port, "tcp"); if (se) port_s = se->s_name; } if (port_s.empty () ) port_s = rostring ("%d", ntohs (addr->sin_port)); if (!numeric) { int size = 1000; char *buffer = new char[size]; struct hostent he, *hp; int herr; while (ERANGE == gethostbyaddr_r (reinterpret_cast (&addr->sin_addr), sizeof (addr->sin_addr), AF_INET, &he, buffer, size, &hp, &herr) ) { delete[] buffer; buffer = new char[size *= 2]; } if (hp) { std::string ret = rostring ("%s:%s", hp->h_name, port_s); delete[] buffer; return ret; } } unsigned char const *hack = reinterpret_cast (&addr->sin_addr); return rostring ("%d.%d.%d.%d:%s", int (hack[0]), int (hack[1]), int (hack[2]), int (hack[3]), port_s); } std::string socket::get_peer_info (bool numeric) const { startfunc; struct sockaddr_in sock; socklen_t len = sizeof (sock); if (getpeername (get_fd (), reinterpret_cast (&sock), &len) ) { shevek_error_errno ("unable to get peer name"); return std::string (); } return l_get_socket_info (&sock, numeric); } std::string socket::get_own_info (bool numeric) const { startfunc; struct sockaddr_in sock; socklen_t len = sizeof (sock); if (getsockname (get_fd (), reinterpret_cast (&sock), &len) ) { shevek_error_errno ("unable to get peer name"); return std::string (); } return l_get_socket_info (&sock, numeric); } socket::disconnect_t socket::signal_disconnect () { startfunc; return m_disconnect; } } libshevek-1.3.orig/src/crefptr.hh0000644000175000017500000002351111611036753016406 0ustar shevekshevek/* crefptr - cyclic-protected reference counting smart pointers. * Copyright 2009 Bas Wijnen * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef SHEVEK_CREFPTR_HH #define SHEVEK_CREFPTR_HH #include #include #include "error.hh" namespace shevek { // Structure of the refptr: // The object with the data derives from crefbase. This cannot be copied. // Pointers to it are of type crefptr <_T>, where _T is the deriving class. // crefbase contains a list of _ptrdata with pointers to the object. // _ptrdata contains the target object, the pointer which references it and the owner of the reference. // crefptr contains (through _ptr) a list iterator, pointing to its _ptrdata. // crefptr->_data->_ref is always crefptr, and object->_refs[]->target is always object. /// Circular-dependancy-protected reference-counting object base class. /** Objects which derive from this class are reference-counted in a way that detects dependency loops and destroys the entire loop when it is no longer externally referenced. * For this, it is important that objects which contain pointers register them appropriately. */ class crefbase { class _ptr; class _ptrptr; class _objptr; template friend class crefptr; // Internal pointers to crefptrs. class _ptrptr { _ptr *_data; public: _ptr &operator* () { return *_data; } _ptr *operator-> () { return _data; } _ptrptr (_ptr *p) { _data = p; } }; // Internal pointers to crefbase objects. class _objptr { crefbase *_data; public: _objptr (crefbase *d) { _data = d; } crefbase &operator* () { return *_data; } crefbase *operator-> () const { return _data; } }; // This struct is used internally for storing back references to a pointer. struct _ptrdata { _objptr target; // Link to self, so _ptr only needs to store an iterator. _ptrptr ref; // The referencing pointer. _objptr owner; // The owner of ref. _ptrdata (_objptr t, _ptrptr r, _objptr o) : target (t), ref (r), owner (o) {} }; // Base class for crefptr. class _ptr { friend class crefbase; template friend class crefptr; std::list <_ptrdata>::iterator _data; _objptr _target () const { return _data->target; } _objptr &_owner () const { return _data->owner; } // The reference counting machinery. protected: inline _ptr (_objptr owner, _objptr target); inline ~_ptr (); public: inline _ptr (_ptr const &that); inline _ptr &operator= (_ptr const &that); inline void reset (); inline void set_owner (crefbase *owner); }; // Object to which null-pointers point. This is needed to store their owners. This object is never deleted because init_done () is never called. static crefbase no_target; // This is set at creation; the object cannot be destroyed until it is reset using init_done (). int _init; // List of pointers referencing this object, with their owner. // This costs more memory than storing the data in _ptr, but _ptr must be as small as possible, // because it is passed around and thus copied a lot. std::list <_ptrdata> _refs; // Use _refs. void _check (); bool _checking; void _add (_ptrptr p, _objptr owner); void _remove (_ptrptr p); // Can't copy refcounted objects. crefbase &operator= (crefbase const &that); // NI crefbase (crefbase const &that); // NI static int dbg_tag; #ifdef DEBUG_CREFBASE std::list ::iterator dbg_iterator; static std::list dbg_check; #endif protected: /// Constructor, which is called when an object is created. crefbase () : _init (0), _checking (false) { #ifdef DEBUG_CREFBASE dbg_check.push_back (this); dbg_iterator = --dbg_check.end (); #endif } /// Virtual destructor, which does nothing except allowing derived class to have a virtual destructor. virtual ~crefbase () { if (this == &no_target) return; if (!_refs.empty ()) shevek_error ("reference list is not empty"); #ifdef DEBUG_CREFBASE dbg_check.erase (dbg_iterator); #endif if (_init == 0) shevek_error ("removing object before init_done was called"); if (_init != 1) std::cerr << "Removing object " << this << " which is tagged " << _init << '\n'; } public: /// Set the default tag for when init_done is called. /** If the tag is not set to 1, a message will be printed to standard error on destruction. * The previous tag is returned. * If tag is set to 0, the old value is not changed. * The initial default value is 1. */ static int set_default_tag (int tag) { int old = dbg_tag; if (tag) dbg_tag = tag; return old; } /// After calling this, the object is destroyed without references. /** On creation, an object does not have any references. To prevent immediate destruction, it is first in an initialisation phase. * During that phase, it will not be destroyed, even if it has no references. * This function should be called immeiately after creating the object (normally through crefptr::init): * shevek::crefptr bar = foo::create ().init (); * If code is not given or 0, the default tag (set with set_default_tag) will be used. */ void init_done (int code = 0) { if (!code) code = dbg_tag; if (this == &no_target) shevek_error ("calling init_done on no_target"); if (_init) shevek_error ("calling init_done more than once"); _init = code; if (code != 1) std::cerr << "Tagging object " << this << " with code " << code << '\n'; _check (); } /// Check if all objects have called init_done. /** When debugging is enabled, this function checks for all objects if they have called init_done. * When debugging is not enabled, no list of objects is kept, and this check does nothing. */ static void check (bool fatal = true) { #ifdef DEBUG_CREFBASE unsigned count = 0; for (std::list ::iterator i = dbg_check.begin (); i != dbg_check.end (); ++i) { if (*i == &no_target) continue; if (!(*i)->_init) { shevek_warning (shevek::ostring ("init_done not called before check for %08x", (unsigned)*i)); ++count; } else if ((*i)->_init != 1) std::cerr << "Check: object " << *i << ", tagged " << (*i)->_init << " still lives (" << (*i)->_refs.size () << " references)\n"; } std::cerr << "checked " << dbg_check.size () << " items\n"; if (count && fatal) { shevek_error ("check failed"); throw "check failed"; } #endif } }; /// Keep a pointer to an object derived from crefbase. template class crefptr : public crefbase::_ptr { public: /// Create a new pointer. If this pointer is stored inside a crefbase-derived object, make sure to set the owner. crefptr (crefbase *target = NULL, crefbase *owner = NULL) : _ptr (owner, target) {} /// Dereference the pointer. _T &operator* () const { if (_target ().operator-> () == &crefbase::no_target) shevek_error ("dereferencing NULL crefptr"); return reinterpret_cast <_T &> (*_target ()); } /// Dereference the pointer. _T *operator-> () const { if (_target ().operator-> () == &crefbase::no_target) return NULL; return reinterpret_cast <_T *> (_target ().operator-> ()); } /// Test if two pointers refer to the same object. bool operator== (crefptr <_T> const &that) const { return _target ().operator-> () == that._target ().operator-> (); } /// Test if two pointers don't refer to the same object. bool operator!= (crefptr <_T> const &that) const { return _target ().operator-> () != that._target ().operator-> (); } /// Create a new pointer from this one, up- or downcast. Normally, this is used to fill a new crefptr. template _R *cast_dynamic () const { return dynamic_cast <_R *> (_target ().operator-> ()); } /// Implicit pointer conversion. operator _T * () const { _T *ret = reinterpret_cast <_T *> (_target ().operator-> ()); if (ret == &crefbase::no_target) return NULL; return ret; } /// Allow the pointer to be destroyed. See crefbase::init_done for details. crefptr <_T> init (int code = 0) { _target ()->init_done (code); return *this; } }; crefbase::_ptr::_ptr (_objptr owner, _objptr target) { if (target.operator-> () == NULL) target = &crefbase::no_target; target->_add (this, owner); } crefbase::_ptr::~_ptr () { _target ()->_remove (this); } // Using the copy constructor is a problem, because the owner is not given. // So it really shouldn't be used, but it's unacceptable to forbid passing // crefptrs as function arguments. So we assume that the copy constructor // will not be used in other places, and set the owner to NULL. crefbase::_ptr::_ptr (_ptr const &that) { _objptr target = that._target (); target->_add (this, NULL); } crefbase::_ptr &crefbase::_ptr::operator= (_ptr const &that) { _objptr target = that._target (); if (target.operator-> () == _target ().operator-> ()) return *this; _objptr owner = _owner (); _target ()->_remove (this); target->_add (this, owner); return *this; } void crefbase::_ptr::reset () { if (_target ().operator-> () == &crefbase::no_target) return; _objptr owner = _owner (); _target ()->_remove (this); crefbase::no_target._add (this, owner); } void crefbase::_ptr::set_owner (crefbase *owner) { _owner () = owner; _target ()->_check (); } } #endif libshevek-1.3.orig/src/iostring.cc0000644000175000017500000005351611710537461016577 0ustar shevekshevek/* iostring.hh - Read and write strings in parts. * Copyright 2007-2008 Bas Wijnen * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include #include #include "iostring.hh" #include "case.hh" #include "error.hh" #include "debug.hh" #include "regexp.hh" namespace shevek { static Glib::ustring::size_type find_non_whitespace (Glib::ustring const &str, Glib::ustring::size_type start) { Glib::ustring::size_type ret; for (ret = start; ret < str.size (); ++ret) { // Definition of "whitespace" as defined by // javascript (Ecma-262). gunichar c = str[ret]; if (c != 0xa0 && c != 0x20 && c != 0xc && c != 0xb && c != 0x9 && c != 0xa && c != 0xd && c != 0x2028 && c != 0x2029 && g_unichar_type (c) != G_UNICODE_SPACE_SEPARATOR) break; } return ret; } void istring::del_whitespace () { pos.top () = find_non_whitespace (data, pos.top ()); } bool istring::read_const (Glib::ustring const &format, Glib::ustring::size_type &inpos) { bool escaped = false; while (inpos < format.size ()) { if (escaped && format[inpos] == ':') { if (pos.top () != 0 && pos.top () != data.size () && Glib::Unicode::isalnum (data[pos.top () - 1]) && Glib::Unicode::isalnum (data[pos.top ()])) return false; ++inpos; escaped = false; continue; } if (escaped || (format[inpos] != '%' && format[inpos] != ' ')) { if (format[inpos] != data[pos.top ()]) return false; ++inpos; ++pos.top (); escaped = false; continue; } if (format[inpos] == ' ') { del_whitespace (); ++inpos; escaped = false; continue; } ++inpos; if (inpos >= format.size ()) { // A single % at end of string means // that the input must be parsed // completely. return pos.top () == data.size (); } if (format[inpos] != '%' && format[inpos] != ' ' && format[inpos] != ':') return true; escaped = true; } return true; } int istring::pop (bool keep) { Glib::ustring::size_type p = pos.top (); if (pos.size () > 1) pos.pop (); else pos.top () = 0; int ret = p - pos.top (); if (keep) pos.top () = p; return ret; } template <> bool istring::read_var (Glib::ustring const &format, double &ret, Glib::ustring::size_type &inpos) { ++inpos; // First check for inf and/or nan del_whitespace (); if (pos.top () >= data.size ()) return false; bool neg (false); if (data[pos.top ()] == '+') ++pos.top (); else if (data[pos.top ()] == '-') { ++pos.top (); neg = true; } if (data.size () - pos.top () >= 8 && shevek::tolower (data.substr (pos.top (), 8)) == "infinity") { pos.top () += 8; ret = std::numeric_limits ::infinity () * (neg ? -1 : 1); return true; } if (data.size () - pos.top () >= 3 && shevek::tolower (data.substr (pos.top (), 3)) == "inf") { pos.top () += 3; ret = std::numeric_limits ::infinity () * (neg ? -1 : 1); return true; } if (data.size () - pos.top () >= 3 && shevek::tolower (data.substr (pos.top (), 3)) == "nan") { pos.top () += 3; if (pos.top () < data.size () && data[pos.top ()] == '(') { Glib::ustring::size_type e = data.find_first_of (")\n", pos.top ()); if (e != Glib::ustring::npos && data[e] == ')') pos.top () = e + 1; } ret = std::numeric_limits ::quiet_NaN () * (neg ? -1 : 1); return true; } std::istringstream s (data.substr (pos.top ())); s >> ret; ret *= (neg ? -1 : 1); std::streampos p = s.tellg (); if (!s || p < 0) return false; pos.top () += p; return true; } template <> bool istring::read_var (Glib::ustring const &format, float &ret, Glib::ustring::size_type &inpos) { ++inpos; // First check for inf and/or nan del_whitespace (); if (pos.top () >= data.size ()) return false; bool neg (false); if (data[pos.top ()] == '+') ++pos.top (); else if (data[pos.top ()] == '-') { ++pos.top (); neg = true; } if (data.size () - pos.top () >= 8 && shevek::tolower (data.substr (pos.top (), 8)) == "infinity") { pos.top () += 8; ret = std::numeric_limits ::infinity () * (neg ? -1 : 1); return true; } if (data.size () - pos.top () >= 3 && shevek::tolower (data.substr (pos.top (), 3)) == "inf") { pos.top () += 3; ret = std::numeric_limits ::infinity () * (neg ? -1 : 1); return true; } if (data.size () - pos.top () >= 3 && shevek::tolower (data.substr (pos.top (), 3)) == "nan") { pos.top () += 3; if (pos.top () < data.size () && data[pos.top ()] == '(') { Glib::ustring::size_type e = data.find_first_of (")\n", pos.top ()); if (e != Glib::ustring::npos && data[e] == ')') pos.top () = e + 1; } ret = std::numeric_limits ::quiet_NaN () * (neg ? -1 : 1); return true; } std::istringstream s (data.substr (pos.top ())); s >> ret; ret *= (neg ? -1 : 1); std::streampos p = s.tellg (); if (!s || p < 0) return false; pos.top () += p; return true; } #define next(x) do { \ if (inpos >= format.size ()) \ return false; \ x = format[inpos++]; \ if (x == '%') \ { \ if (inpos >= format.size ()) \ return false; \ if (format[inpos++] != '%') \ return false; \ } \ } while (false) template <> bool istring::read_var (Glib::ustring const &format, Glib::ustring &ret, Glib::ustring::size_type &inpos) { startfunc; gunichar c; next (c); if (c == '[') { Glib::ustring range; bool invert (false); if (format[inpos] == '^') { ++inpos; if (inpos >= format.size ()) return false; invert = true; } next (c); range += c; while (format[inpos] != ']') { next (c); if (c == '-') { gunichar z; next (z); z &= 0xff; gunichar a = *--range.end () & 0xff; if (a > z) { int t = a; a = z; z = t; } for (++a; a <= z; ++a) range += a; continue; } range += c; } Glib::ustring::size_type orig = pos.top (); if (invert) { while (pos.top () < data.size () && range.find_first_of (data[pos.top ()]) == Glib::ustring::npos) ++pos.top (); } else { while (pos.top () < data.size () && range.find_first_of (data[pos.top ()]) != Glib::ustring::npos) ++pos.top (); } ret = data.substr (orig, pos.top () - orig); ++inpos; return true; } std::istringstream s (data.substr (pos.top ())); std::string line; switch (c) { default: // One word s >> ret; break; case 'l': // One line std::getline (s, line); ret = line; break; case 'a': // All ret = data.substr (pos.top ()); pos.top () = data.size (); return true; case 'r': // Regular expression case 'R': // Case insensitive regular expression gunichar quote; next (quote); gunichar n; Glib::ustring expr; do { next (n); expr += n; } while (quote != n); expr = expr.substr (0, expr.size () - 1); if (expr.empty () || expr[0] != '^') expr = Glib::ustring (1, '^') + expr; shevek::regexp re (expr, c == 'r'); if (!re (data.substr (pos.top ()))) return false; ret = re.transform ("\\0"); pos.top () += ret.size (); return true; } if (!s) return false; std::streampos p = s.tellg (); if (p >= 0) pos.top () += p; else pos.top () = data.size (); return true; } static int make_base (gunichar code) { switch (code) { case 'o': // octal return 8; case 'x': // hexadecimal return 16; case 'd': // decimal return 10; case 'b': // binary return 2; default: // any return 0; } } static bool read_char (Glib::ustring const &data, Glib::ustring::size_type &pos, int &ret) { Glib::ustring::size_type p = find_non_whitespace (data, pos); if (p == Glib::ustring::npos || data.size () <= p + 2 || (data[p] != '\'' && data[p] != '"') || data[p] != data[p + 2]) return false; pos = p + 3; ret = data[p + 1]; return true; } template <> bool istring::read_var (Glib::ustring const &format, int &ret, Glib::ustring::size_type &inpos) { int base = make_base (format[inpos++]); if (read_char (data, pos.top (), ret)) return true; Glib::ustring d = data.substr (pos.top ()); char *end; char const *str = d.c_str (); ret = strtol (str, &end, base); if (str == end) return false; pos.top () += end - str; return true; } template <> bool istring::read_var (Glib::ustring const &format, unsigned &ret, Glib::ustring::size_type &inpos) { int base = make_base (format[inpos++]); int r; if (read_char (data, pos.top (), r)) { ret = r; return true; } Glib::ustring d = data.substr (pos.top ()); char *end; char const *str = d.c_str (); ret = strtoul (str, &end, base); if (str == end) return false; pos.top () += end - str; return true; } ostring &ostring::init (Glib::ustring const &f) { format = f; pos = 0; return *this; } void ostring::write_const () { while (pos < format.size ()) { if (format[pos] != '%') { data += format[pos++]; continue; } if (++pos >= format.size ()) shevek_error ("ostring format ends on %"); if (format[pos] != '%') return; data += '%'; ++pos; } shevek_error ("Not enough % codes in format"); } ostring &ostring::operator ()() { while (pos < format.size ()) { if (format[pos] != '%') { data += format[pos++]; continue; } if (++pos >= format.size ()) shevek_error ("ostring format ends on %"); if (format[pos] != '%') shevek_error ("Too many % codes in format"); data += '%'; ++pos; } return *this; } template <> void ostring::write_var (unsigned short const &a, Glib::ustring const &flags, unsigned width, unsigned precision) { (void)precision; std::ostringstream s; if (width > 0) s << std::setw (width); if (flags.find ('0') != Glib::ustring::npos) s << std::setfill ('0'); if (pos < format.size () && (format[pos] == 'x' || format[pos] == 'X')) s << std::hex; s << a; data += s.str (); if (pos < format.size ()) ++pos; } template <> void ostring::write_var (short const &a, Glib::ustring const &flags, unsigned width, unsigned precision) { (void)precision; std::ostringstream s; if (width > 0) s << std::setw (width); if (flags.find ('0') != Glib::ustring::npos) s << std::setfill ('0'); if (pos < format.size () && (format[pos] == 'x' || format[pos] == 'X')) s << std::hex; s << a; data += s.str (); if (pos < format.size ()) ++pos; } template <> void ostring::write_var (unsigned const &a, Glib::ustring const &flags, unsigned width, unsigned precision) { (void)precision; std::ostringstream s; if (width > 0) s << std::setw (width); if (flags.find ('0') != Glib::ustring::npos) s << std::setfill ('0'); if (pos < format.size () && (format[pos] == 'x' || format[pos] == 'X')) s << std::hex; s << a; data += s.str (); if (pos < format.size ()) ++pos; } template <> void ostring::write_var (int const &a, Glib::ustring const &flags, unsigned width, unsigned precision) { (void)precision; std::ostringstream s; if (width > 0) s << std::setw (width); if (flags.find ('0') != Glib::ustring::npos) s << std::setfill ('0'); if (pos < format.size () && (format[pos] == 'x' || format[pos] == 'X')) s << std::hex; s << a; data += s.str (); if (pos < format.size ()) ++pos; } template <> void ostring::write_var (Glib::ustring const &a, Glib::ustring const &flags, unsigned width, unsigned precision) { Glib::ustring s; if (precision > 0 && a.size () > precision) s = a.substr (0, precision); else s = a; if (width >= 0 && s.size () < width) { if (flags.find ('-')) s += Glib::ustring (width - s.size (), ' '); else s = Glib::ustring (width - s.size (), ' ') + s; } data += s; if (pos < format.size ()) ++pos; } static std::string const rwhitespace (" \t\n\r\0", 5); void ristring::del_whitespace () { while (pos.top () < data.size () && rwhitespace.find (data[pos.top ()]) != std::string::npos) ++pos.top (); } bool ristring::read_const (std::string const &format, std::string::size_type &inpos) { bool escaped = false; while (inpos < format.size ()) { if (escaped && format[inpos] == ':') { if (pos.top () != 0 && pos.top () != data.size () && Glib::Ascii::isalnum (data[pos.top () - 1]) && Glib::Ascii::isalnum (data[pos.top ()])) return false; ++inpos; escaped = false; continue; } if (escaped || (format[inpos] != '%' && format[inpos] != ' ')) { if (format[inpos] != data[pos.top ()]) return false; ++inpos; ++pos.top (); escaped = false; continue; } if (format[inpos] == ' ') { del_whitespace (); ++inpos; escaped = false; continue; } ++inpos; if (inpos >= format.size ()) { // A single % at end of string means // that the input must be parsed // completely. return pos.top () == data.size (); } if (format[inpos] != '%' && format[inpos] != ' ' && format[inpos] != ':') return true; escaped = true; } return true; } int ristring::pop (bool keep) { std::string::size_type p = pos.top (); if (pos.size () > 1) pos.pop (); else pos.top () = 0; int ret = p - pos.top (); if (keep) pos.top () = p; return ret; } template <> bool ristring::read_var (std::string const &format, double &ret, std::string::size_type &inpos) { ++inpos; // First check for inf and/or nan del_whitespace (); if (pos.top () >= data.size ()) return false; bool neg (false); if (data[pos.top ()] == '+') ++pos.top (); else if (data[pos.top ()] == '-') { ++pos.top (); neg = true; } if (data.size () - pos.top () >= 8 && shevek::tolower (data.substr (pos.top (), 8)) == "infinity") { pos.top () += 8; ret = std::numeric_limits ::infinity () * (neg ? -1 : 1); return true; } if (data.size () - pos.top () >= 3 && shevek::tolower (data.substr (pos.top (), 3)) == "inf") { pos.top () += 3; ret = std::numeric_limits ::infinity () * (neg ? -1 : 1); return true; } if (data.size () - pos.top () >= 3 && shevek::tolower (data.substr (pos.top (), 3)) == "nan") { pos.top () += 3; if (pos.top () < data.size () && data[pos.top ()] == '(') { std::string::size_type e = data.find_first_of (")\n", pos.top ()); if (e != std::string::npos && data[e] == ')') pos.top () = e + 1; } ret = std::numeric_limits ::quiet_NaN () * (neg ? -1 : 1); return true; } std::istringstream s (data.substr (pos.top ())); s >> ret; ret *= (neg ? -1 : 1); std::streampos p = s.tellg (); if (!s || p < 0) return false; pos.top () += p; return true; } template <> bool ristring::read_var (std::string const &format, float &ret, std::string::size_type &inpos) { ++inpos; // First check for inf and/or nan del_whitespace (); if (pos.top () >= data.size ()) return false; bool neg (false); if (data[pos.top ()] == '+') ++pos.top (); else if (data[pos.top ()] == '-') { ++pos.top (); neg = true; } if (data.size () - pos.top () >= 8 && shevek::tolower (data.substr (pos.top (), 8)) == "infinity") { pos.top () += 8; ret = std::numeric_limits ::infinity () * (neg ? -1 : 1); return true; } if (data.size () - pos.top () >= 3 && shevek::tolower (data.substr (pos.top (), 3)) == "inf") { pos.top () += 3; ret = std::numeric_limits ::infinity () * (neg ? -1 : 1); return true; } if (data.size () - pos.top () >= 3 && shevek::tolower (data.substr (pos.top (), 3)) == "nan") { pos.top () += 3; if (pos.top () < data.size () && data[pos.top ()] == '(') { std::string::size_type e = data.find_first_of (")\n", pos.top ()); if (e != std::string::npos && data[e] == ')') pos.top () = e + 1; } ret = std::numeric_limits ::quiet_NaN () * (neg ? -1 : 1); return true; } std::istringstream s (data.substr (pos.top ())); s >> ret; ret *= (neg ? -1 : 1); std::streampos p = s.tellg (); if (!s || p < 0) return false; pos.top () += p; return true; } template <> bool ristring::read_var (std::string const &format, std::string &ret, std::string::size_type &inpos) { startfunc; char c; next (c); if (c == '[') { std::string range; bool invert (false); if (format[inpos] == '^') { ++inpos; if (inpos >= format.size ()) return false; invert = true; } next (c); range += c; while (format[inpos] != ']') { next (c); if (c == '-') { int z; next (z); z &= 0xff; int a = *--range.end () & 0xff; if (a > z) { int t = a; a = z; z = t; } for (++a; a <= z; ++a) range += a; continue; } range += c; } std::string::size_type orig = pos.top (); if (invert) { while (pos.top () < data.size () && range.find_first_of (data[pos.top ()]) == std::string::npos) ++pos.top (); } else { while (pos.top () < data.size () && range.find_first_of (data[pos.top ()]) != std::string::npos) ++pos.top (); } ret = data.substr (orig, pos.top () - orig); ++inpos; return true; } std::istringstream s (data.substr (pos.top ())); switch (c) { default: // One word s >> ret; break; case 'l': // One line std::getline (s, ret); break; case 'a': // All ret = data.substr (pos.top ()); pos.top () = data.size (); return true; case 'r': // Regular expression case 'R': // Case insensitive regular expression char quote; next (quote); char n; std::string expr; do { next (n); expr += n; } while (quote != n); expr = expr.substr (0, expr.size () - 1); if (expr.empty () || expr[0] != '^') expr = std::string (1, '^') + expr; shevek::regexp re (expr, c == 'r'); if (!re (data.substr (pos.top ()))) return false; ret = re.transform ("\\0"); pos.top () += ret.size (); return true; } if (!s) return false; std::streampos p = s.tellg (); if (p >= 0) pos.top () += p; else pos.top () = data.size (); return true; } static bool read_char (std::string const &data, std::string::size_type &pos, int &ret) { std::string::size_type p = data.find_first_not_of (rwhitespace, pos); if (p == std::string::npos || data.size () <= p + 2 || (data[p] != '\'' && data[p] != '"') || data[p] != data[p + 2]) return false; pos = p + 3; ret = data[p + 1]; return true; } template <> bool ristring::read_var (std::string const &format, int &ret, std::string::size_type &inpos) { int base = make_base (format[inpos++]); if (read_char (data, pos.top (), ret)) return true; std::string d = data.substr (pos.top ()); char *end; char const *str = d.c_str (); ret = strtol (str, &end, base); if (str == end) return false; pos.top () += end - str; return true; } template <> bool ristring::read_var (std::string const &format, unsigned &ret, std::string::size_type &inpos) { int base = make_base (format[inpos++]); int r; if (read_char (data, pos.top (), r)) { ret = r; return true; } std::string d = data.substr (pos.top ()); char *end; char const *str = d.c_str (); ret = strtoul (str, &end, base); if (str == end) return false; pos.top () += end - str; return true; } rostring &rostring::init (std::string const &f) { format = f; pos = 0; return *this; } void rostring::write_const () { while (pos < format.size ()) { if (format[pos] != '%') { data += format[pos++]; continue; } if (++pos >= format.size ()) shevek_error ("rostring format ends on %"); if (format[pos] != '%') return; data += '%'; ++pos; } shevek_error ("Not enough % codes in format"); } rostring &rostring::operator ()() { while (pos < format.size ()) { if (format[pos] != '%') { data += format[pos++]; continue; } if (++pos >= format.size ()) shevek_error ("rostring format ends on %"); if (format[pos] != '%') shevek_error ("Too many % codes in format"); data += '%'; ++pos; } return *this; } template <> void rostring::write_var (unsigned const &a, std::string const &flags, unsigned width, unsigned precision) { (void)precision; std::ostringstream s; if (width > 0) s << std::setw (width); if (flags.find ('0') != std::string::npos) s << std::setfill ('0'); if (pos < format.size () && (format[pos] == 'x' || format[pos] == 'X')) s << std::hex; s << a; data += s.str (); if (pos < format.size ()) ++pos; } template <> void rostring::write_var (int const &a, std::string const &flags, unsigned width, unsigned precision) { (void)precision; std::ostringstream s; if (width > 0) s << std::setw (width); if (flags.find ('0') != std::string::npos) s << std::setfill ('0'); if (pos < format.size () && (format[pos] == 'x' || format[pos] == 'X')) s << std::hex; s << a; data += s.str (); if (pos < format.size ()) ++pos; } } libshevek-1.3.orig/src/socket.hh0000644000175000017500000001156111553533024016231 0ustar shevekshevek/* socket.hh - network sockets for use with shevek::main * Copyright 2003 Bas Wijnen * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef SHEVEK_SOCKET_HH #define SHEVEK_SOCKET_HH #include #include #include #include #include #include #include #include "debug.hh" #include "fd.hh" #include "error.hh" #include "avahi.hh" namespace shevek { /// Use a unix-domain, tcp or avahi network connection with shevek::fd. class socket : public fd { public: /// Disconnect signal type. typedef sigc::signal0 disconnect_t; /// New connection callback type. typedef sigc::slot0 listen_t; /// Create a new socket. static Glib::RefPtr create (Glib::RefPtr main = Glib::MainContext::get_default () ); /// Listen for new connections on a UNIX socket. Use listen instead. void listen_unix (std::string const &file, listen_t cb, unsigned queue = 10); /// Listen for new connections on a TCP socket. Use listen instead. void listen_tcp (std::string const &service, listen_t cb, unsigned queue = 10); /// Listen for new connections on a TCP socket, and register it with avahi. Use listen instead. void listen_avahi (std::string const &service, Glib::ustring const &protocol, Glib::ustring const &name, listen_t cb, unsigned queue = 10); /// Listen for new connections. /** This is the preferred function to use. * Format: * UNIX domain sockets: anything with at least one / in it. * TCP services: the name. * TCP port numbers: the number. * For TCP, appending |name|protocol, where name is the application name and protocol the connection type. */ void listen (std::string const &port, listen_t cb, unsigned queue = 10); /// Connect to a UNIX socket. Use connect instead. void connect_unix (std::string const &unix_name); /// Connect to a TCP socket. Use connect instead. void connect_tcp (std::string const &host, std::string const &service); /// Connect to an avahi TCP socket. Use connect instead. void connect_avahi (avahi::browser::owner const &target, avahi::browser::details const &details = avahi::browser::details ()); /// Connect to a socket. /** This is the preferred function to use. * Format: * UNIX domain sockets: anything with at least one / in it. * TCP: hostname:port, where the hostname and colon may be omitted, and the port may be a service or number. * Avahi: name|protocol, where name is the application name, and protocol the connection type. */ void connect (std::string const &port); /// Accept a connection (only allowed on a listening socket). void accept (Glib::RefPtr sock); /// Get information about the other side of a connection. std::string get_peer_info (bool numeric = false) const; /// Get info about our side of the connection. std::string get_own_info (bool numeric = false) const; /// Schedule a function to be called when the socket is disconnected. disconnect_t signal_disconnect (); /// Disconnect the socket without reconnecting. void disconnect (); protected: /// Constructor. socket (Glib::RefPtr main); /// Destructor. virtual ~socket (); private: // Accept a new connection (called from main loop) void l_listen (listen_t cb); // transform a service or int to a real int static int l_service_to_port (std::string const &service); // Determine hostname and port from sockaddr_in std::string l_get_socket_info (struct sockaddr_in *addr, bool numeric) const; // Finish disconnecting (read buffer is empty). void l_finish_disconnect (); // Callback function for the user: data has been read. read_t m_read; // Callback function for the user: socket is disconnected. disconnect_t m_disconnect; // Is this socket listening for connections? bool m_listener; // Remember the name of unix listensockets, to unlink them. std::string *m_name; // Callback for listensockets, called when a new connection is made. listen_t m_listen; // Avahi object for listening sockets. Glib::RefPtr m_avahi; }; } #endif // defined SHEVEK_SOCKET_HH libshevek-1.3.orig/src/avahi.cc0000644000175000017500000002215111553533024016014 0ustar shevekshevek/* avahi-publish.cc - publish network ports with avahi * Copyright 2009 Bas Wijnen * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "avahi.hh" #include #include "iostring.hh" #include "error.hh" #include "debug.hh" namespace shevek { void avahi::publish (Glib::ustring const &protocol, int port) { if (!m_name) shevek_error ("cannot publish without a service name"); if (m_ports.find (protocol) != m_ports.end ()) shevek_error (shevek::ostring ("duplicate registration of protocol %s", protocol)); m_ports[protocol] = port; create_services (m_client); } void avahi::name_change (AvahiClient *client) { char *n = avahi_alternative_service_name (m_name); avahi_free (m_name); m_name = n; dbg (shevek::ostring ("name collision; renamed to %s", m_name)); create_services (client); } void avahi::group_callback (AvahiEntryGroup *g, AvahiEntryGroupState state, void *userdata) { avahi *self = (avahi *)userdata; dbg ("group state change: " << state); AvahiClient *client = avahi_entry_group_get_client (g); switch (state) { case AVAHI_ENTRY_GROUP_UNCOMMITED: case AVAHI_ENTRY_GROUP_REGISTERING: break; case AVAHI_ENTRY_GROUP_ESTABLISHED: dbg ("Established a group"); break; case AVAHI_ENTRY_GROUP_COLLISION: self->name_change (client); break; case AVAHI_ENTRY_GROUP_FAILURE: if (avahi_client_errno (client) != AVAHI_ERR_DISCONNECTED) shevek_error (shevek::ostring ("group failure: %s", avahi_strerror (avahi_client_errno (client)))); self->create_client (); break; default: shevek_error (shevek::ostring ("invalid case %d", state)); } } void avahi::create_services (AvahiClient *client) { if (!m_name || avahi_client_get_state (client) != AVAHI_CLIENT_S_RUNNING) return; if (!m_group) { m_group = avahi_entry_group_new (client, &group_callback, this); if (!m_group) shevek_error (shevek::ostring ("failed to create group: %s", avahi_strerror (avahi_client_errno (client)))); } if (m_ports.empty () || !avahi_entry_group_is_empty (m_group)) return; for (std::map ::iterator i = m_ports.begin (); i != m_ports.end (); ++i) { Glib::ustring p = Glib::ustring (1, '_') + i->first + "._tcp"; int ret = avahi_entry_group_add_service (m_group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, (AvahiPublishFlags)0, m_name, p.c_str (), NULL, NULL, i->second, NULL); if (ret < 0) { if (ret == AVAHI_ERR_COLLISION) return name_change (client); else shevek_error (shevek::ostring ("avahi error: %s", avahi_strerror (avahi_client_errno (client)))); } } int ret = avahi_entry_group_commit (m_group); if (ret < 0) shevek_error (shevek::ostring ("error committing group: %s", avahi_strerror (avahi_client_errno (client)))); } void avahi::callback (AvahiClient *client, AvahiClientState state, void *userdata) { avahi *self = (avahi *)userdata; dbg ("state change: " << state); switch (state) { case AVAHI_CLIENT_S_RUNNING: self->create_services (client); break; case AVAHI_CLIENT_S_COLLISION: case AVAHI_CLIENT_S_REGISTERING: if (self->m_group) avahi_entry_group_reset (self->m_group); break; case AVAHI_CLIENT_FAILURE: shevek_error ("client reports failure"); break; case AVAHI_CLIENT_CONNECTING: break; default: shevek_warning (shevek::ostring ("unknown state %d", state)); break; } } void avahi::create_client () { if (m_client) avahi_client_free (m_client); int error; m_client = avahi_client_new (m_poll_api, m_allow_restart ? AVAHI_CLIENT_NO_FAIL :(AvahiClientFlags)0, &callback, this, &error); if (!m_client) shevek_error (shevek::ostring ("error creating client: %s", avahi_strerror (avahi_client_errno (m_client)))); } avahi::avahi (Glib::ustring const &name, bool allow_restart, bool blocking_poller) { m_name = name.empty () ? NULL : avahi_strdup (name.c_str ()); m_allow_restart = allow_restart; m_client = NULL; m_group = NULL; if (blocking_poller) { m_poller = avahi_simple_poll_new (); m_poll_api = avahi_simple_poll_get (m_poller); } else { m_poller = NULL; m_glib_poll = avahi_glib_poll_new (NULL, G_PRIORITY_DEFAULT); m_poll_api = avahi_glib_poll_get (m_glib_poll); } create_client (); } avahi::~avahi () { avahi_client_free (m_client); if (m_poller) avahi_simple_poll_free (m_poller); else avahi_glib_poll_free (m_glib_poll); avahi_free (m_name); } static int _setup_malloc () { avahi_set_allocator (avahi_glib_allocator ()); return 0; } static G_GNUC_UNUSED int _dummy = _setup_malloc (); avahi::browser::browser (Glib::RefPtr parent, Glib::ustring const &protocol) { m_parent = parent; Glib::ustring p = Glib::ustring (1, '_') + protocol + "._tcp"; m_sb = avahi_service_browser_new(m_parent->m_client, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, p.c_str (), NULL, (AvahiLookupFlags)0, &browse_callback, this); if (!m_sb) shevek_error (shevek::ostring ("unable to open browser: %s", avahi_strerror (avahi_client_errno (m_parent->m_client)))); } avahi::browser::~browser () { avahi_service_browser_free (m_sb); } void avahi::browser::resolve_callback (AvahiServiceResolver *r, AvahiIfIndex interface, AvahiProtocol protocol, AvahiResolverEvent event, char const *name, char const *type, char const *domain, char const *host_name, AvahiAddress const *address, uint16_t port, AvahiStringList *txt, AvahiLookupResultFlags flags, void * userdata) { dbg ("resolved " << name); browser *self = (browser *)userdata; if (event == AVAHI_RESOLVER_FAILURE) shevek_error (shevek::ostring ("Error resolving service: %s", avahi_strerror (avahi_client_errno (self->m_parent->m_client)))); if (event != AVAHI_RESOLVER_FOUND) shevek_error ("Invalid case"); char a[AVAHI_ADDRESS_STR_MAX]; avahi_address_snprint (a, sizeof(a), address); list::iterator i = self->m_list.find (name); if (i == self->m_list.end ()) i = self->m_list.insert (std::make_pair (name, owner (host_name, port))).first; details d (interface, protocol, a, flags); if (i->second.details.find (d) != i->second.details.end ()) shevek_error (shevek::ostring ("registering already registered service %s with identical interface and protocol", name)); i->second.details.insert (d); self->m_changed (name); avahi_service_resolver_free (r); } void avahi::browser::browse_callback (AvahiServiceBrowser *b, AvahiIfIndex interface, AvahiProtocol protocol, AvahiBrowserEvent event, char const *name, char const *type, char const *domain, AvahiLookupResultFlags flags, void *userdata) { browser *self = (browser *)userdata; switch (event) { case AVAHI_BROWSER_NEW: { dbg ("new " << name); if (!self->m_filter.empty () && self->m_filter != name) break; AvahiServiceResolver *resolver = avahi_service_resolver_new (self->m_parent->m_client, interface, protocol, name, type, domain, AVAHI_PROTO_UNSPEC, (AvahiLookupFlags)0, &resolve_callback, self); if (!resolver) shevek_error (shevek::ostring ("Failed to resolve service '%s': %s\n", name, avahi_strerror (avahi_client_errno (self->m_parent->m_client)))); break; } case AVAHI_BROWSER_REMOVE: { dbg ("remove " << name); list::iterator i = self->m_list.find (name); if (i == self->m_list.end ()) { shevek_warning (shevek::ostring ("remove event for %s, which is not registered", name)); return; } details_list::iterator j = i->second.details.find (details (interface, protocol)); if (j == i->second.details.end ()) { shevek_warning (shevek::ostring ("remove event for %s, which is not registered", name)); return; } i->second.details.erase (j); if (i->second.details.empty ()) self->m_list.erase (i); self->m_changed (name); break; } case AVAHI_BROWSER_CACHE_EXHAUSTED: dbg ("cache exhausted"); break; case AVAHI_BROWSER_ALL_FOR_NOW: dbg ("all for now"); if (self->m_parent->m_poller) avahi_simple_poll_quit (self->m_parent->m_poller); break; case AVAHI_BROWSER_FAILURE : shevek_error (shevek::ostring ("Error: %s", avahi_strerror (avahi_client_errno (self->m_parent->m_client)))); default: shevek_error ("Error: invalid case"); } } avahi::browser::list avahi::browser::get_list_block (Glib::ustring const &protocol, Glib::ustring const &name) { Glib::RefPtr parent (new avahi (name, true, true)); Glib::RefPtr self (new browser (parent, protocol)); self->m_filter = name; avahi_simple_poll_loop (parent->m_poller); return self->get_list (); } } libshevek-1.3.orig/src/closure.hh0000644000175000017500000000573311553533024016421 0ustar shevekshevek/* closure.hh - Cooperative multitasking * Copyright 2008 Bas Wijnen * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef SHEVEK_CLOSURE_HH #define SHEVEK_CLOSURE_HH #include #include "refbase.hh" namespace shevek { /// Block and resume without blocking the main loop. /** Closures allow blocking and resuming the main loop. They * are implemented with threads, which means that they don't * work well with multi-threaded programs. * * If a function wants to be able to block using a closure, it must be * called using closure(). It (or any function it calls) can then * suspend by calling closure::block(). It can be awoken again by * calling closure::wake() on the closure object. */ class closure : public refbase { static closure *current; enum state_t { EMPTY, BLOCKING, RUNNING } state; sigc::slot0 callback, function; pthread_t thread; int blocking_pipe[2]; int waking_pipe[2]; void do_write (int *fds); void do_read (int *fds); static void *start_wrapper (void *me); closure (); public: /// Create a new closure. /** Create a new closure. It will be empty initially. */ static Glib::RefPtr create () { return Glib::RefPtr (new closure ()); } /// Check if the closure is empty. /** Check if the closure is empty. If it is, set_function() * can be called. */ bool empty () const { return state == EMPTY; } /// Set running function on an empty closure. /** Set running function. The closure must be empty when this * is called. When the function exits, the closure returns to * the empty state, and the callback is called, if given. */ void set_function (sigc::slot0 func, bool run = true, sigc::slot0 cb = sigc::slot0 ()); /// Destructor. ~closure (); /// Sleep, returning control to the caller until awoken. /** This function puts the current closure to sleep. It will * continue to run when awoken with wake(). It can also be * destroyed. This function uses a global variable to know * which is the current closure, so it can be called without an * object, as closure::block (); . */ static void block (); /// Continue running the closure. /** Wake a closure. It is an error to wake a closure which * isn't blocking (in particular also the currently running * closure). */ void wake (); }; } #endif libshevek-1.3.orig/src/process.cc0000644000175000017500000001177511752430017016413 0ustar shevekshevek/* process.cc - functions for process.hh * Copyright 2005 Bas Wijnen * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "process.hh" #include "error.hh" #include "debug.hh" #include #include #include extern "C" { extern char **environ; } namespace shevek { char **process::make_pointers (std::list const &source) { char **ret = new char *[source.size () + 1]; int count = 0; for (std::list ::const_iterator i = source.begin (); i != source.end (); ++i) { ret[count] = new char[i->size () + 1]; memcpy (ret[count], i->data (), i->size ()); ret[count][i->size ()] = '\0'; ++count; } ret[source.size ()] = 0; return ret; } void process::clean (char **pointers) { for (int i = 0; pointers[i]; ++i) delete[] pointers[i]; } char *process::dup (char const *str) { int s = strlen (str); char *ret = new char[s + 1]; memcpy (ret, str, s + 1); return ret; } Glib::RefPtr process::create (std::string const &command, std::list &argv, bool pipe_stdin, bool pipe_stdout, bool pipe_stderr) { char **new_argv = make_pointers (argv); Glib::RefPtr ret (new process (command, new_argv, environ, pipe_stdin, pipe_stdout, pipe_stderr)); clean (new_argv); return ret; } Glib::RefPtr process::create (std::string const &command, std::list &argv, std::list const &envp, bool pipe_stdin, bool pipe_stdout, bool pipe_stderr) { char **new_argv = make_pointers (argv); char **new_envp = make_pointers (envp); Glib::RefPtr ret (new process (command, new_argv, new_envp, pipe_stdin, pipe_stdout, pipe_stderr) ); clean (new_argv); clean (new_envp); return ret; } Glib::RefPtr process::in () { return m_in; } Glib::RefPtr process::out () { return m_out; } Glib::RefPtr process::err () { return m_err; } pid_t process::pid () { return m_pid; } process::process (std::string const &command, char **argv, char **envp, bool pipe_stdin, bool pipe_stdout, bool pipe_stderr) { startfunc; int fds[3][2]; if ((pipe_stdin && ::pipe (fds[0])) || (pipe_stdout && ::pipe (fds[1])) || (pipe_stderr && ::pipe (fds[2]))) { shevek_error_errno ("unable to create pipes for communication"); return; } m_pid = ::fork (); switch (m_pid) { case -1: // error shevek_error_errno ("unable to fork child"); return; case 0: // child if (pipe_stdin) { ::close (fds[0][1]); ::close (STDIN_FILENO); ::dup2 (fds[0][0], STDIN_FILENO); ::close (fds[0][0]); } if (pipe_stdout) { ::close (fds[1][0]); ::close (STDOUT_FILENO); ::dup2 (fds[1][1], STDOUT_FILENO); ::close (fds[1][1]); } if (pipe_stderr) { ::close (fds[2][0]); ::close (STDERR_FILENO); ::dup2 (fds[2][1], STDERR_FILENO); ::close (fds[2][1]); } execve (command.c_str (), argv, envp); shevek_error_errno ("execve failed"); return; default: // parent if (pipe_stdin) { ::close (fds[0][0]); m_in = fd::create (fds[0][1]); m_in->set_error (sigc::mem_fun (m_in.operator-> (), &fd::reset)); } if (pipe_stdout) { ::close (fds[1][1]); m_out = fd::create (fds[1][0]); m_out->set_error (sigc::mem_fun (m_out.operator-> (), &fd::reset)); } if (pipe_stderr) { ::close (fds[2][1]); m_err = fd::create (fds[2][0]); m_err->set_error (sigc::mem_fun (m_err.operator-> (), &fd::reset)); } return; } } process::~process () { startfunc; if (m_in) { ::close (m_in->get_fd () ); m_in->set_fd (-1); } if (m_out) { ::close (m_out->get_fd () ); m_out->set_fd (-1); } if (m_err) { ::close (m_err->get_fd () ); m_err->set_fd (-1); } ::kill (m_pid, SIGHUP); ::waitpid (m_pid, 0, 0); } std::string process::run (std::string const &command, std::string const &sh) { Glib::RefPtr p = shell (command, false, true, false, sh); std::string result; while (true) { std::string &part = p->m_out->read_block (); if (part.empty () ) break; result += part; part.clear (); } return result; } } libshevek-1.3.orig/src/iostring.hh0000644000175000017500000007604611710352274016611 0ustar shevekshevek/* iostring.hh - Read and write strings in parts. * Copyright 2007-2008 Bas Wijnen * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef SHEVEK_IOSTRING_HH #define SHEVEK_IOSTRING_HH #include #include #include #include namespace shevek { /// shevek::istring is a C++ version of scanf. /** It uses templates to allow expanding it to user-defined types, * but it still uses a format string to make it better translatable. */ class istring { // The data to parse. Glib::ustring data; // Pointer to data still to be parsed. std::stack pos; // Read a variable. template bool read_var (Glib::ustring const &format, T &ret, Glib::ustring::size_type &inpos); // Read away whitespace. void del_whitespace (); // Check for a constant. bool read_const (Glib::ustring const &format, Glib::ustring::size_type &inpos); public: // Constructors: fill data and make one stack level. /// Create a new istring with no data. istring () { pos.push (0); } /// Create a new istring with data. istring (Glib::ustring const &str) { init (str); } /// Set new data to an existing istring. void init (Glib::ustring const &str) { data = str; while (!pos.empty ()) pos.pop (); pos.push (0); } // Stack functions. /// Push the current position to the stack so it can be restored later. void push () { pos.push (pos.top ()); } /// Pop the last pushed position from the stack. /** If keep is true or not given, the current position is restored to the last position. * If it is false, the current position is not changed. */ int pop (bool keep = false); /// Set the current position to 0, but don't change the stack. void reset () { pos.top () = 0; } /// Get remaining string. Glib::ustring rest () const { return data.substr (pos.top ()); } /// Skip some characters. void skip (Glib::ustring::size_type p) { pos.top () += p; } /// Read a constant string from the input. bool operator() (Glib::ustring const &format) { push (); Glib::ustring::size_type inpos = 0; bool ret = read_const (format, inpos) && inpos == format.size (); pop (ret); return ret; } /// Read a string containing one argument from the input. template bool operator() (Glib::ustring const &format, T1 &arg1) { push (); Glib::ustring::size_type inpos = 0; bool ret = read_const (format, inpos) && read_var (format, arg1, inpos) && read_const (format, inpos) && inpos == format.size (); pop (ret); return ret; } /// Read a string containing two arguments from the input. template bool operator() (Glib::ustring const &format, T1 &arg1, T2 &arg2) { push (); Glib::ustring::size_type inpos = 0; bool ret = read_const (format, inpos) && read_var (format, arg1, inpos) && read_const (format, inpos) && read_var (format, arg2, inpos) && read_const (format, inpos) && inpos == format.size (); pop (ret); return ret; } /// Read a string containing three arguments from the input. template bool operator() (Glib::ustring const &format, T1 &arg1, T2 &arg2, T3 &arg3) { push (); Glib::ustring::size_type inpos = 0; bool ret = read_const (format, inpos) && read_var (format, arg1, inpos) && read_const (format, inpos) && read_var (format, arg2, inpos) && read_const (format, inpos) && read_var (format, arg3, inpos) && read_const (format, inpos) && inpos == format.size (); pop (ret); return ret; } /// Read a string containing four arguments from the input. template bool operator() (Glib::ustring const &format, T1 &arg1, T2 &arg2, T3 &arg3, T4 &arg4) { push (); Glib::ustring::size_type inpos = 0; bool ret = read_const (format, inpos) && read_var (format, arg1, inpos) && read_const (format, inpos) && read_var (format, arg2, inpos) && read_const (format, inpos) && read_var (format, arg3, inpos) && read_const (format, inpos) && read_var (format, arg4, inpos) && read_const (format, inpos) && inpos == format.size (); pop (ret); return ret; } /// Read a string containing five arguments from the input. template bool operator() (Glib::ustring const &format, T1 &arg1, T2 &arg2, T3 &arg3, T4 &arg4, T5 &arg5) { push (); Glib::ustring::size_type inpos = 0; bool ret = read_const (format, inpos) && read_var (format, arg1, inpos) && read_const (format, inpos) && read_var (format, arg2, inpos) && read_const (format, inpos) && read_var (format, arg3, inpos) && read_const (format, inpos) && read_var (format, arg4, inpos) && read_const (format, inpos) && read_var (format, arg5, inpos) && read_const (format, inpos) && inpos == format.size (); pop (ret); return ret; } /// Read a string containing six arguments from the input. template bool operator() (Glib::ustring const &format, T1 &arg1, T2 &arg2, T3 &arg3, T4 &arg4, T5 &arg5, T6 &arg6) { push (); Glib::ustring::size_type inpos = 0; bool ret = read_const (format, inpos) && read_var (format, arg1, inpos) && read_const (format, inpos) && read_var (format, arg2, inpos) && read_const (format, inpos) && read_var (format, arg3, inpos) && read_const (format, inpos) && read_var (format, arg4, inpos) && read_const (format, inpos) && read_var (format, arg5, inpos) && read_const (format, inpos) && read_var (format, arg6, inpos) && read_const (format, inpos) && inpos == format.size (); pop (ret); return ret; } /// Read a string containing seven arguments from the input. template bool operator() (Glib::ustring const &format, T1 &arg1, T2 &arg2, T3 &arg3, T4 &arg4, T5 &arg5, T6 &arg6, T7 &arg7) { push (); Glib::ustring::size_type inpos = 0; bool ret = read_const (format, inpos) && read_var (format, arg1, inpos) && read_const (format, inpos) && read_var (format, arg2, inpos) && read_const (format, inpos) && read_var (format, arg3, inpos) && read_const (format, inpos) && read_var (format, arg4, inpos) && read_const (format, inpos) && read_var (format, arg5, inpos) && read_const (format, inpos) && read_var (format, arg6, inpos) && read_const (format, inpos) && read_var (format, arg7, inpos) && read_const (format, inpos) && inpos == format.size (); pop (ret); return ret; } /// Read a string containing eight arguments from the input. template bool operator() (Glib::ustring const &format, T1 &arg1, T2 &arg2, T3 &arg3, T4 &arg4, T5 &arg5, T6 &arg6, T7 &arg7, T8 &arg8) { push (); Glib::ustring::size_type inpos = 0; bool ret = read_const (format, inpos) && read_var (format, arg1, inpos) && read_const (format, inpos) && read_var (format, arg2, inpos) && read_const (format, inpos) && read_var (format, arg3, inpos) && read_const (format, inpos) && read_var (format, arg4, inpos) && read_const (format, inpos) && read_var (format, arg5, inpos) && read_const (format, inpos) && read_var (format, arg6, inpos) && read_const (format, inpos) && read_var (format, arg7, inpos) && read_const (format, inpos) && read_var (format, arg8, inpos) && read_const (format, inpos) && inpos == format.size (); pop (ret); return ret; } /// Read a variable from given data and return it. /** This allows using a shevek::istring in an expression without the need to create a new variable for it. * If the input doesn't match the format, def is returned. */ template static T direct (Glib::ustring const &data, Glib::ustring const &format, T def = T ()) { T ret; istring tmp (data); if (!tmp (format, ret)) ret = def; return ret; } }; /// Template function for reading any type. /** The default implementation uses a std::istringstream extractor. * This function can be specialized by a program to allow reading custom types with a shevek::istring. */ template bool istring::read_var (Glib::ustring const &format, T &ret, Glib::ustring::size_type &inpos) { ++inpos; std::istringstream s (data.substr (pos.top ())); s >> ret; std::streampos p = s.tellg (); if (!s || p < 0) return false; pos.top () += p; return true; } /// Specialization of read_var for double. template <> bool istring::read_var (Glib::ustring const &format, double &ret, Glib::ustring::size_type &inpos); /// Specialization of read_var for float. template <> bool istring::read_var (Glib::ustring const &format, float &ret, Glib::ustring::size_type &inpos); /// Specialization of read_var for Glib::ustring. template <> bool istring::read_var (Glib::ustring const &format, Glib::ustring &ret, Glib::ustring::size_type &inpos); /// Specialization of read_var for int. template <> bool istring::read_var (Glib::ustring const &format, int &ret, Glib::ustring::size_type &inpos); /// Specialization of read_var for unsigned. template <> bool istring::read_var (Glib::ustring const &format, unsigned &ret, Glib::ustring::size_type &inpos); /// shevek::ostring is a C++ version of printf. /** It uses templates to allow expanding it to user-defined types, but it still uses a format string to make it better translatable. * ostring works on utf-8 strings (Glib::ustring). For std::string, use rostring. */ class ostring { Glib::ustring data; Glib::ustring format; Glib::ustring::size_type pos; void write_const (); template void write_var (T const &a, Glib::ustring const &flags, unsigned width, unsigned precision); template void write_var_raw (T const &a); ostring &init (Glib::ustring const &f); // If you get a linker error to this line, you have tried to insert a std::string into a shevek::ostring. // Fix the program by turning it into a Glib::ustring first, or by using a shevek::rostring instead. template ostring &operator ()(T const &a) { write_const (); write_var_raw (a); return *this; } ostring &operator ()(); public: /// Use the result as a string. operator Glib::ustring () const { return data; } /// Use the result as a string. Glib::ustring operator+ (Glib::ustring const &that) const { return data + that; } /// Send the result to an ostream. friend std::ostream &operator<< (std::ostream &s, ostring const &o) { return s << o.data; } /// Create a string with a constant format. ostring (Glib::ustring const &fmt) { init (fmt)(); } /// Create a string with one argument. template ostring (Glib::ustring const &fmt, T1 const &a1) { init (fmt)(a1)(); } /// Create a string with two arguments. template ostring (Glib::ustring const &fmt, T1 const &a1, T2 const &a2) { init (fmt)(a1)(a2)(); } /// Create a string with three arguments. template ostring (Glib::ustring const &fmt, T1 const &a1, T2 const &a2, T3 const &a3) { init (fmt)(a1)(a2)(a3)(); } /// Create a string with four arguments. template ostring (Glib::ustring const &fmt, T1 const &a1, T2 const &a2, T3 const &a3, T4 const &a4) { init (fmt)(a1)(a2)(a3)(a4)(); } /// Create a string with five arguments. template ostring (Glib::ustring const &fmt, T1 const &a1, T2 const &a2, T3 const &a3, T4 const &a4, T5 const &a5) { init (fmt)(a1)(a2)(a3)(a4)(a5)(); } /// Create a string with six arguments. template ostring (Glib::ustring const &fmt, T1 const &a1, T2 const &a2, T3 const &a3, T4 const &a4, T5 const &a5, T6 const &a6) { init (fmt)(a1)(a2)(a3)(a4)(a5)(a6)(); } /// Create a string with seven arguments. template ostring (Glib::ustring const &fmt, T1 const &a1, T2 const &a2, T3 const &a3, T4 const &a4, T5 const &a5, T6 const &a6, T7 const &a7) { init (fmt)(a1)(a2)(a3)(a4)(a5)(a6)(a7)(); } /// Create a string with eight arguments. template ostring (Glib::ustring const &fmt, T1 const &a1, T2 const &a2, T3 const &a3, T4 const &a4, T5 const &a5, T6 const &a6, T7 const &a7, T8 const &a8) { init (fmt)(a1)(a2)(a3)(a4)(a5)(a6)(a7)(a8)(); } /// Create a string with nine arguments. template ostring (Glib::ustring const &fmt, T1 const &a1, T2 const &a2, T3 const &a3, T4 const &a4, T5 const &a5, T6 const &a6, T7 const &a7, T8 const &a8, T9 const &a9) { init (fmt)(a1)(a2)(a3)(a4)(a5)(a6)(a7)(a8)(a9)(); } }; /// Write a variable to a string. /** This first read the flags, width and precision, and passes that to write_var (which can be specialized by types). */ template void ostring::write_var_raw (T const &a) { unsigned width = 0, precision = 0; Glib::ustring flags; while (pos < format.size () && (format[pos] < 'a' || format[pos] > 'z') && (format[pos] < 'A' || format[pos] > 'Z') && (format[pos] < '1' || format[pos] > '9')) flags += format[pos++]; while (pos < format.size () && format[pos] >= '0' && format[pos] <= '9') { width *= 10; width += format[pos++] - '0'; } if (pos < format.size () && format[pos] == '.') { ++pos; while (pos < format.size () && format[pos] >= '0' && format[pos] <= '9') { precision *= 10; precision += format[pos++] - '0'; } } return write_var (a, flags, width, precision); } /// Write a variable to the string. /** This function can be specialized to allow writing custom types using shevek::ostring. */ template void ostring::write_var (T const &a, Glib::ustring const &flags, unsigned width, unsigned precision) { (void)flags; (void)width; (void)precision; if (pos < format.size ()) ++pos; std::ostringstream s; s << a; data += s.str (); } /// Specialization for unsigned short. template <> void ostring::write_var (unsigned short const &a, Glib::ustring const &flags, unsigned width, unsigned precision); /// Specialization for short. template <> void ostring::write_var (short const &a, Glib::ustring const &flags, unsigned width, unsigned precision); /// Specialization for unsigned. template <> void ostring::write_var (unsigned const &a, Glib::ustring const &flags, unsigned width, unsigned precision); /// Specialization for int. template <> void ostring::write_var (int const &a, Glib::ustring const &flags, unsigned width, unsigned precision); /// Specialization for Glib::ustring. template <> void ostring::write_var (Glib::ustring const &a, Glib::ustring const &flags, unsigned width, unsigned precision); /// Not implemented. /** For std::string, you should use ri/ostring instead. So this is declared and not defined. * It will trigger a compiler error if it is used. */ template <> void ostring::write_var_raw (std::string const &a); template <> bool istring::read_var (Glib::ustring const &format, std::string &ret, Glib::ustring::size_type &inpos); /// shevek::ristring is identical to shevek::istring, but it uses std::string instead of Glib::ustring. class ristring { // The data to parse. std::string data; // Pointer to data still to be parsed. std::stack pos; // Read a variable. template bool read_var (std::string const &format, T &ret, std::string::size_type &inpos); // Read away whitespace. void del_whitespace (); // Check for a constant. bool read_const (std::string const &format, std::string::size_type &inpos); public: // Constructors: fill data and make one stack level. /// Create a new istring with no data. ristring () { pos.push (0); } /// Create a new istring with data. ristring (std::string const &str) { init (str); } /// Set new data to an existing istring. void init (std::string const &str) { data = str; while (!pos.empty ()) pos.pop (); pos.push (0); } // Stack functions. /// Push the current position to the stack so it can be restored later. void push () { pos.push (pos.top ()); } /// Pop the last pushed position from the stack. /** If keep is true or not given, the current position is restored to the last position. * If it is false, the current position is not changed. */ int pop (bool keep = false); /// Set the current position to 0, but don't change the stack. void reset () { pos.top () = 0; } /// Get remaining string. std::string rest () const { return data.substr (pos.top ()); } /// Skip some characters. void skip (std::string::size_type p) { pos.top () += p; } /// Read a constant string from the input. bool operator() (std::string const &format) { push (); std::string::size_type inpos = 0; bool ret = read_const (format, inpos) && inpos == format.size (); pop (ret); return ret; } /// Read a string containing one argument from the input. template bool operator() (std::string const &format, T1 &arg1) { push (); std::string::size_type inpos = 0; bool ret = read_const (format, inpos) && read_var (format, arg1, inpos) && read_const (format, inpos) && inpos == format.size (); pop (ret); return ret; } /// Read a string containing two arguments from the input. template bool operator() (std::string const &format, T1 &arg1, T2 &arg2) { push (); std::string::size_type inpos = 0; bool ret = read_const (format, inpos) && read_var (format, arg1, inpos) && read_const (format, inpos) && read_var (format, arg2, inpos) && read_const (format, inpos) && inpos == format.size (); pop (ret); return ret; } /// Read a string containing three arguments from the input. template bool operator() (std::string const &format, T1 &arg1, T2 &arg2, T3 &arg3) { push (); std::string::size_type inpos = 0; bool ret = read_const (format, inpos) && read_var (format, arg1, inpos) && read_const (format, inpos) && read_var (format, arg2, inpos) && read_const (format, inpos) && read_var (format, arg3, inpos) && read_const (format, inpos) && inpos == format.size (); pop (ret); return ret; } /// Read a string containing four arguments from the input. template bool operator() (std::string const &format, T1 &arg1, T2 &arg2, T3 &arg3, T4 &arg4) { push (); std::string::size_type inpos = 0; bool ret = read_const (format, inpos) && read_var (format, arg1, inpos) && read_const (format, inpos) && read_var (format, arg2, inpos) && read_const (format, inpos) && read_var (format, arg3, inpos) && read_const (format, inpos) && read_var (format, arg4, inpos) && read_const (format, inpos) && inpos == format.size (); pop (ret); return ret; } /// Read a string containing five arguments from the input. template bool operator() (std::string const &format, T1 &arg1, T2 &arg2, T3 &arg3, T4 &arg4, T5 &arg5) { push (); std::string::size_type inpos = 0; bool ret = read_const (format, inpos) && read_var (format, arg1, inpos) && read_const (format, inpos) && read_var (format, arg2, inpos) && read_const (format, inpos) && read_var (format, arg3, inpos) && read_const (format, inpos) && read_var (format, arg4, inpos) && read_const (format, inpos) && read_var (format, arg5, inpos) && read_const (format, inpos) && inpos == format.size (); pop (ret); return ret; } /// Read a string containing six arguments from the input. template bool operator() (std::string const &format, T1 &arg1, T2 &arg2, T3 &arg3, T4 &arg4, T5 &arg5, T6 &arg6) { push (); std::string::size_type inpos = 0; bool ret = read_const (format, inpos) && read_var (format, arg1, inpos) && read_const (format, inpos) && read_var (format, arg2, inpos) && read_const (format, inpos) && read_var (format, arg3, inpos) && read_const (format, inpos) && read_var (format, arg4, inpos) && read_const (format, inpos) && read_var (format, arg5, inpos) && read_const (format, inpos) && read_var (format, arg6, inpos) && read_const (format, inpos) && inpos == format.size (); pop (ret); return ret; } /// Read a string containing seven arguments from the input. template bool operator() (std::string const &format, T1 &arg1, T2 &arg2, T3 &arg3, T4 &arg4, T5 &arg5, T6 &arg6, T7 &arg7) { push (); std::string::size_type inpos = 0; bool ret = read_const (format, inpos) && read_var (format, arg1, inpos) && read_const (format, inpos) && read_var (format, arg2, inpos) && read_const (format, inpos) && read_var (format, arg3, inpos) && read_const (format, inpos) && read_var (format, arg4, inpos) && read_const (format, inpos) && read_var (format, arg5, inpos) && read_const (format, inpos) && read_var (format, arg6, inpos) && read_const (format, inpos) && read_var (format, arg7, inpos) && read_const (format, inpos) && inpos == format.size (); pop (ret); return ret; } /// Read a string containing eight arguments from the input. template bool operator() (std::string const &format, T1 &arg1, T2 &arg2, T3 &arg3, T4 &arg4, T5 &arg5, T6 &arg6, T7 &arg7, T8 &arg8) { push (); std::string::size_type inpos = 0; bool ret = read_const (format, inpos) && read_var (format, arg1, inpos) && read_const (format, inpos) && read_var (format, arg2, inpos) && read_const (format, inpos) && read_var (format, arg3, inpos) && read_const (format, inpos) && read_var (format, arg4, inpos) && read_const (format, inpos) && read_var (format, arg5, inpos) && read_const (format, inpos) && read_var (format, arg6, inpos) && read_const (format, inpos) && read_var (format, arg7, inpos) && read_const (format, inpos) && read_var (format, arg8, inpos) && read_const (format, inpos) && inpos == format.size (); pop (ret); return ret; } /// Read a variable from given data and return it. /** This allows using a shevek::istring in an expression without the need to create a new variable for it. * If the input doesn't match the format, def is returned. */ template static T direct (std::string const &data, std::string const &format, T def = T ()) { T ret; istring tmp (data); if (!tmp (format, ret)) ret = def; return ret; } }; /// Template function for reading any type. /** The default implementation uses a std::istringstream extractor. * This function can be specialized by a program to allow reading custom types with a shevek::ristring. */ template bool ristring::read_var (std::string const &format, T &ret, std::string::size_type &inpos) { ++inpos; std::istringstream s (data.substr (pos.top ())); s >> ret; std::streampos p = s.tellg (); if (!s || p < 0) return false; pos.top () += p; return true; } /// Specialization of read_var for double. template <> bool ristring::read_var (std::string const &format, double &ret, std::string::size_type &inpos); /// Specialization of read_var for float. template <> bool ristring::read_var (std::string const &format, float &ret, std::string::size_type &inpos); /// Specialization of read_var for std::string. template <> bool ristring::read_var (std::string const &format, std::string &ret, std::string::size_type &inpos); /// Specialization of read_var for int. template <> bool ristring::read_var (std::string const &format, int &ret, std::string::size_type &inpos); /// Specialization of read_var for unsigned. template <> bool ristring::read_var (std::string const &format, unsigned &ret, std::string::size_type &inpos); /// shevek::rostring is identical to shevek::ostring, but it uses std::string instead of Glib::ustring. class rostring { std::string data; std::string format; std::string::size_type pos; void write_const (); template void write_var (T const &a, std::string const &flags, unsigned width, unsigned precision); template void write_var_raw (T const &a); rostring &init (std::string const &f); template rostring &operator ()(T const &a) { write_const (); write_var_raw (a); return *this; } rostring &operator ()(); public: /// Use the result as a string. operator std::string () const { return data; } /// Use the result as a string. std::string operator+ (std::string const &that) const { return data + that; } /// Send the result to an ostream. friend std::ostream &operator<< (std::ostream &s, rostring const &o) { return s << o.data; } /// Create a string with a constant format. rostring (std::string const &fmt) { init (fmt)(); } /// Create a string with one argument. template rostring (std::string const &fmt, T1 const &a1) { init (fmt)(a1)(); } /// Create a string with two arguments. template rostring (std::string const &fmt, T1 const &a1, T2 const &a2) { init (fmt)(a1)(a2)(); } /// Create a string with three arguments. template rostring (std::string const &fmt, T1 const &a1, T2 const &a2, T3 const &a3) { init (fmt)(a1)(a2)(a3)(); } /// Create a string with four arguments. template rostring (std::string const &fmt, T1 const &a1, T2 const &a2, T3 const &a3, T4 const &a4) { init (fmt)(a1)(a2)(a3)(a4)(); } /// Create a string with five arguments. template rostring (std::string const &fmt, T1 const &a1, T2 const &a2, T3 const &a3, T4 const &a4, T5 const &a5) { init (fmt)(a1)(a2)(a3)(a4)(a5)(); } /// Create a string with six arguments. template rostring (std::string const &fmt, T1 const &a1, T2 const &a2, T3 const &a3, T4 const &a4, T5 const &a5, T6 const &a6) { init (fmt)(a1)(a2)(a3)(a4)(a5)(a6)(); } /// Create a string with seven arguments. template rostring (std::string const &fmt, T1 const &a1, T2 const &a2, T3 const &a3, T4 const &a4, T5 const &a5, T6 const &a6, T7 const &a7) { init (fmt)(a1)(a2)(a3)(a4)(a5)(a6)(a7)(); } /// Create a string with eight arguments. template rostring (std::string const &fmt, T1 const &a1, T2 const &a2, T3 const &a3, T4 const &a4, T5 const &a5, T6 const &a6, T7 const &a7, T8 const &a8) { init (fmt)(a1)(a2)(a3)(a4)(a5)(a6)(a7)(a8)(); } /// Create a string with nine arguments. template rostring (std::string const &fmt, T1 const &a1, T2 const &a2, T3 const &a3, T4 const &a4, T5 const &a5, T6 const &a6, T7 const &a7, T8 const &a8, T9 const &a9) { init (fmt)(a1)(a2)(a3)(a4)(a5)(a6)(a7)(a8)(a9)(); } }; /// Function to write a variable to the string. /** Normally, you should specialize write_var, not this function. */ template void rostring::write_var_raw (T const &a) { unsigned width = 0, precision = 0; std::string flags; while (pos < format.size () && (format[pos] < 'a' || format[pos] > 'z') && (format[pos] < 'A' || format[pos] > 'Z') && (format[pos] < '1' || format[pos] > '9')) flags += format[pos++]; while (pos < format.size () && format[pos] >= '0' && format[pos] <= '9') { width *= 10; width += format[pos++] - '0'; } if (pos < format.size () && format[pos] == '.') { ++pos; while (pos < format.size () && format[pos] >= '0' && format[pos] <= '9') { precision *= 10; precision += format[pos++] - '0'; } } return write_var (a, flags, width, precision); } /// Function to write a variable to the string. /** This function can be specialized to allow writing custom types using shevek::rostring. */ template void rostring::write_var (T const &a, std::string const &flags, unsigned width, unsigned precision) { (void)flags; (void)width; (void)precision; if (pos < format.size ()) ++pos; std::ostringstream s; s << a; data += s.str (); } /// Specialization for unsigned. /** This allows printing in hexadecimal and inserting 0's on the left. */ template <> void rostring::write_var (unsigned const &a, std::string const &flags, unsigned width, unsigned precision); /// Specialization for int. /** This allows printing in hexadecimal and inserting 0's on the left. */ template <> void rostring::write_var (int const &a, std::string const &flags, unsigned width, unsigned precision); /// Not implemented. /** For Glib::ustring, you should use i/ostring instead. So this is declared and not defined. * It will trigger a compiler error if it is used. */ template <> void rostring::write_var_raw (Glib::ustring const &a); template <> bool ristring::read_var (std::string const &format, Glib::ustring &ret, std::string::size_type &inpos); } #endif libshevek-1.3.orig/src/split.hh0000644000175000017500000000332711611117365016076 0ustar shevekshevek/* split.hh - split a line into words * Copyright 2007 Bas Wijnen * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef SHEVEK_SPLIT_HH #define SHEVEK_SPLIT_HH #include #include namespace shevek { /// Split a string into words and retrieve them individually. class split : public std::vector { public: /// Create a new split object, and optionally load it with data. split (std::string const &str = std::string ()) { load (str); } /// Load new data into an existing split object. void load (std::string const &str, bool allow_empty = false, std::string const &delimiters = std::string (" \t\v\f\a\n\r\0", 8)); /// Get a word from the split object. /** This differs from std::vector's method in that it returns an empty string if idx is out of range. */ std::string operator[] (unsigned idx) const { if (idx >= size ()) return std::string (); return std::vector ::operator[] (idx); } /// Get a new split object containing only the last part of this one. split sub (unsigned from) const; }; } #endif // defined (SHEVEK_SPLIT_HH) libshevek-1.3.orig/src/args.hh0000644000175000017500000002344611561164126015704 0ustar shevekshevek/* args.hh - argument parsing made easy * Copyright 2003-2010 Bas Wijnen * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef SHEVEK_ARGS_HH #define SHEVEK_ARGS_HH #include #include #include #include #include #include #include "debug.hh" // Allow using this class without using automake. #ifndef PACKAGE_NAME #define PACKAGE_NAME "[name not defined]" #endif #ifndef PACKAGE_TARNAME #define PACKAGE_TARNAME PACKAGE_NAME #endif #ifndef PACKAGE_BUGREPORT #define PACKAGE_BUGREPORT "[bug report e-mail not defined]" #endif #ifndef PACKAGE_VERSION #define PACKAGE_VERSION "[version not defined]" #endif #ifndef COPYRIGHT_YEARS #define COPYRIGHT_YEARS "[no time of copyright defined]" #endif #ifndef COPYRIGHT_EMAIL #define COPYRIGHT_EMAIL "" #endif #ifndef COPYRIGHT_AUTHOR #define COPYRIGHT_AUTHOR "[no author defined]" #endif namespace shevek { /// Commandline and configuration file parsing helper. /** Args is a commandline parsing helper. It allows giving the possible * short and long options in a simple list and provides --help and --version * output to the user of the program. * * Usage: * create an array of shevek::args::option, containing the desired options. * create an instance of args and pass it argc and argv on the constructor. * It will call all the callbacks of the options from the constructor. * size () and operator[] can be used to access the non-option arguments. */ class args { public: class option; /// Parse the commandline. Only the default arguments (--help, -h and /// --version) are understood. args (int &argc, char **&argv, int min_args, int max_args, Glib::ustring const &description, /* The parameters below should always have their default values, * they are just here to get the #define'd values into the library. * The COPYRIGHT_* values should be defined in configure.ac */ Glib::ustring const ©right_years = COPYRIGHT_YEARS, Glib::ustring const ©right_email = (COPYRIGHT_EMAIL[0] == '\0' ? PACKAGE_BUGREPORT : COPYRIGHT_EMAIL), Glib::ustring const &programmer = COPYRIGHT_AUTHOR, Glib::ustring const &email = PACKAGE_BUGREPORT, char const *programname = PACKAGE_NAME, char const *packagename = PACKAGE_TARNAME, char const *version = PACKAGE_VERSION); /// Parse the commandline providing a list of possible options. template args (int &argc, char **&argv, option (&o)[size_], int min_args, int max_args, Glib::ustring const &description); /// The number of non-option arguments. unsigned size () const; /// Get the non-option arguments. std::string const &operator[] (unsigned idx) const; /// Iterate over the non-option arguments. std::vector ::const_iterator begin () const; /// Iterate over the non-option arguments. std::vector ::const_iterator end () const; private: std::vector m_args; void l_setup (int &argc, char **&argv, option *o, unsigned num_options, int min_args, int max_args, Glib::ustring const &description, struct ::option *longopts, Glib::ustring const ©right_years = COPYRIGHT_YEARS, Glib::ustring const ©right_email = (COPYRIGHT_EMAIL[0] == '\0' ? PACKAGE_BUGREPORT : COPYRIGHT_EMAIL), Glib::ustring const &programmer = COPYRIGHT_AUTHOR, Glib::ustring const &email = PACKAGE_BUGREPORT, char const *programname = PACKAGE_NAME, char const *packagename = PACKAGE_TARNAME, char const *version = PACKAGE_VERSION); }; /// Define an option which can be given to the program. class args::option { public: /// Callback for options without an argument. typedef sigc::slot1 callback0; /// Callback for options with an argument. typedef sigc::slot2 callback1; /// Option has no argument and calls a function. option (char shortopt, Glib::ustring const &longopt, Glib::ustring const &help_line, callback0 handle, bool *used = NULL); /// Option has mandatory argument and calls a function. option (char shortopt, Glib::ustring const &longopt, Glib::ustring const &help_line, bool have_default, callback1 handle, Glib::ustring default_val = Glib::ustring (), bool *used = NULL); /// Option has optional argument and calls respective function. option (char shortopt, Glib::ustring const &longopt, Glib::ustring const &help_line, callback0 handle0, callback1 handle1, bool *used = NULL); /// Set the value of a boolean variable. option (char shortopt, Glib::ustring const &longopt, Glib::ustring const &help_line, bool &var, bool value, bool *used = NULL); /// Set the value of a string variable (utf-8). option (char shortopt, Glib::ustring const &longopt, Glib::ustring const &help_line, bool have_default, Glib::ustring &var, bool *used = NULL); /// Set the value of a string variable. option (char shortopt, Glib::ustring const &longopt, Glib::ustring const &help_line, bool have_default, std::string &var, bool *used = NULL); /// Set the value of an integer variable. option (char shortopt, Glib::ustring const &longopt, Glib::ustring const &help_line, bool have_default, unsigned long &var, bool *used = NULL); /// Set the value of an integer variable. option (char shortopt, Glib::ustring const &longopt, Glib::ustring const &help_line, bool have_default, long &var, bool *used = NULL); /// Set the value of an integer variable. option (char shortopt, Glib::ustring const &longopt, Glib::ustring const &help_line, bool have_default, unsigned &var, bool *used = NULL); /// Set the value of an integer variable. option (char shortopt, Glib::ustring const &longopt, Glib::ustring const &help_line, bool have_default, int &var, bool *used = NULL); /// Set the value of an integer variable. option (char shortopt, Glib::ustring const &longopt, Glib::ustring const &help_line, bool have_default, unsigned short &var, bool *used = NULL); /// Set the value of an integer variable. option (char shortopt, Glib::ustring const &longopt, Glib::ustring const &help_line, bool have_default, short &var, bool *used = NULL); /// Set the value of a floating point variable. option (char shortopt, Glib::ustring const &longopt, Glib::ustring const &help_line, bool have_default, float &var, bool *used = NULL); /// Set the value of a floating point variable. option (char shortopt, Glib::ustring const &longopt, Glib::ustring const &help_line, bool have_default, double &var, bool *used = NULL); /// Fill a list of variables. An item is appended to the list for each /// time the option is specified. template option (char shortopt, Glib::ustring const &longopt, Glib::ustring const &help_line, std::list <_T> &list); private: friend class args; enum opt_t {NEED_ARG, NO_ARG, OPT_ARG}; void setup (char shortopt, Glib::ustring const &longopt, Glib::ustring const &help_line, bool have_default, opt_t have_arg, callback0 handle0, callback1 handle1, bool *used); void call (bool is_double, char const *optarg); char m_shortopt; Glib::ustring m_longopt; Glib::ustring m_help; bool m_have_default; Glib::ustring m_default; opt_t m_have_arg; callback0 m_handle0; callback1 m_handle1; bool *m_used; bool m_is_used; static void l_set (bool is_double, Glib::ustring const &arg, Glib::ustring *var); static void l_setstd (bool is_double, Glib::ustring const &arg, std::string *var); static void l_setint (bool is_double, Glib::ustring const &arg, int *var); static void l_setuint (bool is_double, Glib::ustring const &arg, unsigned *var); static void l_setlint (bool is_double, Glib::ustring const &arg, long *var); static void l_setulint (bool is_double, Glib::ustring const &arg, unsigned long *var); static void l_setsint (bool is_double, Glib::ustring const &arg, short *var); static void l_setusint (bool is_double, Glib::ustring const &arg, unsigned short *var); static void l_setbool (bool is_double, bool val, bool *var); static void l_setfloat (bool is_double, Glib::ustring const &arg, float *var); static void l_setdfloat (bool is_double, Glib::ustring const &arg, double *var); template static void l_setlist (bool is_double, Glib::ustring const &arg, std::list <_T> *list); }; template args::args (int &argc, char **&argv, option (&o)[size_], int min_args, int max_args, Glib::ustring const &description) { startfunc; struct ::option longopts[size_ + 4]; l_setup (argc, argv, o, size_, min_args, max_args, description, longopts); } template args::option::option (char shortopt, Glib::ustring const &longopt, Glib::ustring const &help_line, std::list <_T> &list) { startfunc; setup (shortopt, longopt, help_line, false, NEED_ARG, callback0 (), sigc::bind (sigc::ptr_fun (&l_setlist <_T>), &list), NULL); } template void args::option::l_setlist (bool is_double, Glib::ustring const &arg, std::list <_T> *list) { startfunc; list->push_back (_T () ); option tmp ('x', "x", "x", false, list->back () ); tmp.m_handle1 (false, arg); } } #endif libshevek-1.3.orig/src/dl.cc0000644000175000017500000000234611553533024015327 0ustar shevekshevek/* dl.cc - load dynamic libraries * Copyright 2005 Bas Wijnen * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "dl.hh" namespace shevek { dl::dl () : m_handle (NULL) { } dl::~dl () { if (m_handle) close (); } void dl::open (std::string const &file) { if (m_handle) close (); m_handle = dlopen (file.c_str (), RTLD_NOW); if (!m_handle) shevek_error (ostring ("unable to open dynamic library: %s", dlerror ())); } void dl::close () { if (!m_handle) shevek_error ("unable to close: no valid handle"); dlclose (m_handle); m_handle = NULL; } } libshevek-1.3.orig/src/process.hh0000644000175000017500000002227611553533024016424 0ustar shevekshevek/* process.hh - fork/exec made userfriendly * Copyright 2005-2008 Bas Wijnen * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef SHEVEK_PROCESS_HH #define SHEVEK_PROCESS_HH #include #include "refbase.hh" #include "fd.hh" namespace shevek { /// Create a process, optionally connection its standard in- and output streams to the calling program. class process : public shevek::refbase { public: /// Create a process from a filename and an argument list. static Glib::RefPtr create (std::string const &command, std::list &argv, bool pipe_stdin = true, bool pipe_stdout = true, bool pipe_stderr = true); /// Create a process from a filename, an argument list and an environment. static Glib::RefPtr create (std::string const &command, std::list &argv, std::list const &envp, bool pipe_stdin = true, bool pipe_stdout = true, bool pipe_stderr = true); /// Run a string with the shell. /** Note that the process is forked from the shell, and so does not get killed when the process goes away. */ static Glib::RefPtr shell (std::string const &command, bool pipe_stdin = true, bool pipe_stdout = true, bool pipe_stderr = true, std::string const &sh = "/bin/sh") { std::list args; args.push_back (sh); args.push_back ("-c"); args.push_back (command); return create (command, args, pipe_stdin, pipe_stdout, pipe_stderr); } /// The standard input pipe, if it was requested. Glib::RefPtr in (); /// The standard output pipe, if it was requested. Glib::RefPtr out (); /// The standard error pipe, if it was requested. Glib::RefPtr err (); /// The process ID. pid_t pid (); /// The destructor. This kills the process if it was still running. ~process (); /// Run a process and return its output. /** A convenience function for running a process and catching its standard output in a string. * This blocks until the process has exited. */ static std::string run (std::string const &command, std::string const &sh); /// Create a process without arguments. static Glib::RefPtr create (std::string const &command, bool pipe_stdin = true, bool pipe_stdout = true, bool pipe_stderr = true) { std::list args; args.push_back (command); return create (command, args, pipe_stdin, pipe_stdout, pipe_stderr); } /// Create a process with one argument. static Glib::RefPtr create (std::string const &command, std::string const &a1, bool pipe_stdin = true, bool pipe_stdout = true, bool pipe_stderr = true) { std::list args; args.push_back (command); args.push_back (a1); return create (command, args, pipe_stdin, pipe_stdout, pipe_stderr); } /// Create a process with two arguments. static Glib::RefPtr create (std::string const &command, std::string const &a1, std::string const &a2, bool pipe_stdin = true, bool pipe_stdout = true, bool pipe_stderr = true) { std::list args; args.push_back (command); args.push_back (a1); args.push_back (a2); return create (command, args, pipe_stdin, pipe_stdout, pipe_stderr); } /// Create a process with three arguments. static Glib::RefPtr create (std::string const &command, std::string const &a1, std::string const &a2, std::string const &a3, bool pipe_stdin = true, bool pipe_stdout = true, bool pipe_stderr = true) { std::list args; args.push_back (command); args.push_back (a1); args.push_back (a2); args.push_back (a3); return create (command, args, pipe_stdin, pipe_stdout, pipe_stderr); } /// Create a process with four arguments. static Glib::RefPtr create (std::string const &command, std::string const &a1, std::string const &a2, std::string const &a3, std::string const &a4, bool pipe_stdin = true, bool pipe_stdout = true, bool pipe_stderr = true) { std::list args; args.push_back (command); args.push_back (a1); args.push_back (a2); args.push_back (a3); args.push_back (a4); return create (command, args, pipe_stdin, pipe_stdout, pipe_stderr); } /// Create a process with five arguments. static Glib::RefPtr create (std::string const &command, std::string const &a1, std::string const &a2, std::string const &a3, std::string const &a4, std::string const &a5, bool pipe_stdin = true, bool pipe_stdout = true, bool pipe_stderr = true) { std::list args; args.push_back (command); args.push_back (a1); args.push_back (a2); args.push_back (a3); args.push_back (a4); args.push_back (a5); return create (command, args, pipe_stdin, pipe_stdout, pipe_stderr); } /// Create a process with six arguments. static Glib::RefPtr create (std::string const &command, std::string const &a1, std::string const &a2, std::string const &a3, std::string const &a4, std::string const &a5, std::string const &a6, bool pipe_stdin = true, bool pipe_stdout = true, bool pipe_stderr = true) { std::list args; args.push_back (command); args.push_back (a1); args.push_back (a2); args.push_back (a3); args.push_back (a4); args.push_back (a5); args.push_back (a6); return create (command, args, pipe_stdin, pipe_stdout, pipe_stderr); } /// Create a process with seven arguments. static Glib::RefPtr create (std::string const &command, std::string const &a1, std::string const &a2, std::string const &a3, std::string const &a4, std::string const &a5, std::string const &a6, std::string const &a7, bool pipe_stdin = true, bool pipe_stdout = true, bool pipe_stderr = true) { std::list args; args.push_back (command); args.push_back (a1); args.push_back (a2); args.push_back (a3); args.push_back (a4); args.push_back (a5); args.push_back (a6); args.push_back (a7); return create (command, args, pipe_stdin, pipe_stdout, pipe_stderr); } /// Create a process with eight arguments. static Glib::RefPtr create (std::string const &command, std::string const &a1, std::string const &a2, std::string const &a3, std::string const &a4, std::string const &a5, std::string const &a6, std::string const &a7, std::string const &a8, bool pipe_stdin = true, bool pipe_stdout = true, bool pipe_stderr = true) { std::list args; args.push_back (command); args.push_back (a1); args.push_back (a2); args.push_back (a3); args.push_back (a4); args.push_back (a5); args.push_back (a6); args.push_back (a7); args.push_back (a8); return create (command, args, pipe_stdin, pipe_stdout, pipe_stderr); } /// Create a process with nine arguments. static Glib::RefPtr create (std::string const &command, std::string const &a1, std::string const &a2, std::string const &a3, std::string const &a4, std::string const &a5, std::string const &a6, std::string const &a7, std::string const &a8, std::string const &a9, bool pipe_stdin = true, bool pipe_stdout = true, bool pipe_stderr = true) { std::list args; args.push_back (command); args.push_back (a1); args.push_back (a2); args.push_back (a3); args.push_back (a4); args.push_back (a5); args.push_back (a6); args.push_back (a7); args.push_back (a8); args.push_back (a9); return create (command, args, pipe_stdin, pipe_stdout, pipe_stderr); } private: Glib::RefPtr m_in, m_out, m_err; pid_t m_pid; process (std::string const &command, char **argv, char **envp, bool pipe_stdin, bool pipe_stdout, bool pipe_stderr); static char **make_pointers (std::list const &source); static void clean (char **pointers); static char *dup (char const *str); }; } #endif libshevek-1.3.orig/src/bg.hh0000644000175000017500000000214411553533024015326 0ustar shevekshevek/* bg.hh - send process to the background * Copyright 2005 Bas Wijnen * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef SHEVEK_BG_HH #define SHEVEK_BG_HH namespace shevek { /// Send process to the background. /** Send process to the background, returning control to the caller. If "bg" * is specified in the environment variable SHEVEK_DEBUG, this function's * only action is to print a message to the standard error pipe. */ void bg (bool exit_on_fail = true); } #endif libshevek-1.3.orig/src/dl.hh0000644000175000017500000000402711553533024015337 0ustar shevekshevek/* dl.hh - load dynamic libraries * Copyright 2005 Bas Wijnen * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef SHEVEK_DL_HH #define SHEVEK_DL_HH #include #include "dlfcn.h" #include "refbase.hh" #include "error.hh" namespace shevek { /// Load symbols from dynamic libraries. /** Usage: create, open, get, get, ..., close */ class dl : public refbase { void *m_handle; public: /// Create a new dl object. static Glib::RefPtr
create () { return Glib::RefPtr
(new dl ()); } /// Close object and free structures. ~dl (); /// Open a shared library. void open (std::string const &file = std::string ()); /// Close the library, freeing the resources. /** This is done automatically if open is called again, or the object is destroyed. */ void close (); /// Get a symbol from the library. /** Its type must be given by the caller and cannot be checked for correctness. */ template T &get (std::string const &name); protected: dl (); }; template T &dl::get (std::string const &name) { if (!m_handle) shevek_error ("unable to get symbol: no valid handle"); union { void *input; T *output; } hack; hack.input = dlsym (m_handle, name.c_str ()); if (!hack.input) shevek_error (ostring ("unable to get symbol: %s", dlerror ())); return *hack.output; } } #endif libshevek-1.3.orig/src/case.cc0000644000175000017500000000224311553533024015637 0ustar shevekshevek/* case.cc - Convert case in strings * Copyright 2008 Bas Wijnen * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "case.hh" #include namespace shevek { std::string toupper (std::string const &orig) { std::string ret; for (std::string::const_iterator i = orig.begin (); i != orig.end (); ++i) ret += ::toupper (*i); return ret; } std::string tolower (std::string const &orig) { std::string ret; for (std::string::const_iterator i = orig.begin (); i != orig.end (); ++i) ret += ::tolower (*i); return ret; } } libshevek-1.3.orig/src/fd.hh0000644000175000017500000001665411553533024015342 0ustar shevekshevek/* fd.hh - use file descriptors with Glib * Copyright 2003-2005 Bas Wijnen * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef SHEVEK_FD_HH #define SHEVEK_FD_HH #include #include #include "refbase.hh" #include "time.hh" namespace shevek { /// The fd class is a generic wrapper for a file descriptor to use it in the Glib event loop. class fd : virtual public refbase { public: /* types */ /// Function pointer to call when data is read from fd typedef sigc::slot0 read_custom_t; /// Function pointer to call when fd is ready for reading typedef sigc::slot1 read_t; /// Function pointer to call when a complete line has arrived typedef sigc::slot1 read_lines_t; /// Function pointer to call when an error occurs typedef sigc::slot0 error_t; /// Function pointer to call when data has been written typedef sigc::slot0 write_done_t; /// Function pointer to filter in and outgoing data typedef sigc::slot1 filter_t; /// Function pointer to signal that all data is flushed after unread () typedef sigc::slot0 flush_t; /* member functions */ /// Poll for read with a custom callback to poll. /** If no callback is set for priority read, this callback is used for that as well. */ void read_custom (read_custom_t cb); /// Poll for priority read with a custom callback to poll. void read_priority_custom (read_custom_t cb); /// Poll for read and set read callback (resets custom callback) /** If no callback is set for priority read, this callback is used for that as well. */ void read (read_t cb); /// Poll for priority read and set read callback (resets custom callback) void read_priority (read_t cb); /// Poll for read and set read lines callback (resets custom and read callback). Polls for priority read as well. void read_lines (read_lines_t cb); /// Stop polling for read (including priority read). void unread (bool flush_buffer = false, flush_t cb = flush_t () ); /// Write data and set a callback (defaults to none). void write (std::string const &data, write_done_t cb = write_done_t () ); /// Write data, ignoring the filter, and set a callback (defaults to none). void write_raw (std::string const &data, write_done_t cb = write_done_t () ); /// Block until write buffer is empty. /** This will block at most until the timeout is reached, if it is positive. */ bool write_block (relative_time timeout = relative_time (-1, 0) ); /// Block until data is read, try writing if there is a write buffer. /** Return read data as reference to buffer. (callback is not called) * Returns immediately if buffer is not empty. * Priority read buffer and normal read buffer are both checked. * This will block at most until the timeout is reached, if it is * positive. */ std::string &read_block (relative_time timeout = relative_time (-1, 0) ); /// Call read_block until a line has been read, or the timeout expires. std::string read_line_block (relative_time timeout = relative_time (-1, 0) ); /// Change file descriptor. void set_fd (int fd); /// If set, incoming data is filtered through this callback before it is put into the buffer. void in_filter (filter_t cb); /// If set, outgoing data is filtered through this callback before it is sent to the file descriptor. void out_filter (filter_t cb); /// Create a new fd. static Glib::RefPtr create (int value = -1, Glib::RefPtr main = Glib::MainContext::get_default () ); /// Set a callback for all error types at once /** This is used for any error for which no other callback is set. */ void set_error (error_t cb); /// Callback for errors from poll void set_poll_error (error_t cb); /// Callback for errors from read void set_read_error (error_t cb); /// Callback for errors from write void set_write_error (error_t cb); /// Callback for end of file void set_eof (error_t cb); /// Stop reading, delete the buffer. void read_reset (); /// Stop writing, delete the buffer. void write_reset (); /// Stop reading and writing, delete the buffers. void reset (); /// Get the fd. This function should mostly be used by derived classes. int get_fd () const; /// Get the main context. Also mostly used by derived classes. Glib::RefPtr get_main_context (); protected: /// Constructor fd (int value, Glib::RefPtr main); /// Destructor ~fd (); private: // not copyable fd (fd const &that); // NI fd &operator= (fd const &that); // NI /* internal functions */ // callback, called when poll returns any event on the fd bool l_check (Glib::IOCondition result); // helper function for l_check and blocking functions void l_write (); // helper function for l_check and blocking functions void l_read (bool force_fill); void l_read_priority (bool force_fill); // callback for idle function bool l_idle (); bool l_idle_priority (); // finish up unread after read buffer is flushed void l_unread (); // disconnect if neccesary, and reconnect (with new fd and/or iocondition) void l_connect (Glib::IOCondition io = Glib::IO_HUP | Glib::IO_ERR | Glib::IO_NVAL); // read lines at a time bool l_read_lines (std::string &data); /* types */ // element for the write queue struct write_t { std::string data; write_done_t done; }; /* data */ // write queue std::list m_writebuffer; // read buffer std::string m_readbuffer; std::string m_priority_readbuffer; // read callback read_t m_read; read_t m_read_priority; // read lines callback read_lines_t m_read_lines; // callback for custom reader read_custom_t m_read_custom; read_custom_t m_read_priority_custom; // flush callback bool m_flushing; flush_t m_flush; // file descriptor int m_fd; // data filters filter_t m_in_filter, m_out_filter; // read and idle callback sigc::connection m_handle, m_idle, m_idle_priority; // error callbacks error_t m_error, m_poll_error, m_rerror, m_werror, m_eof; // main context Glib::RefPtr m_main; // current io condition Glib::IOCondition m_iocondition; // objects to keep the object alive as long as it can be called. Glib::RefPtr m_keepalive_helper; Glib::RefPtr m_keepalive_helper_idle; Glib::RefPtr m_keepalive_helper_idle_priority; /* static members */ // buffer to return from blocking functions when object is destroyed. static std::string s_junkbuffer; }; } #endif libshevek-1.3.orig/src/debug.cc0000644000175000017500000000345111553533024016014 0ustar shevekshevek/* debug.cc - debugging stuff * Copyright 2003-2006 Bas Wijnen * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "debug.hh" #include #include namespace { bool check (std::string const &name) { char *val = std::getenv ("SHEVEK_DEBUG"); if (!val) return false; return (std::string (":") + val + ":") .find (std::string (":") + name + ":") != std::string::npos; } } namespace shevek { bool _debug_startfunc = check ("startfunc"); bool _debug_dbg = check ("dbg"); // hexdump void dump (std::string const &data, std::ostream &target, char def) { unsigned l = data.size (); for (unsigned y = 0; y < l; y += 16) { target << std::setfill (' ') << std::setw (3) << std::hex << y << ':' << std::setfill ('0'); for (unsigned x = 0; x < 16; ++x) { if (y + x >= l) target << " "; else target << " " << std::setw (2) << std::hex << unsigned (data[y + x] & 0xff); } target << '\t'; for (unsigned x = 0; x < 16; ++x) { if (y + x >= l) break; if (std::isprint (data[y + x])) target << data[y + x]; else target << def; } target << std::setfill (' ') << '\n'; } } } libshevek-1.3.orig/src/time.cc0000644000175000017500000004724111553533024015671 0ustar shevekshevek/* time.cc - function implementations for time.hh -*- C++ -*- * Copyright 2003-2006 Bas Wijnen * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "time.hh" #include "debug.hh" #include "error.hh" #include #include #include #include namespace shevek { // now absolute_time::absolute_time () { startfunc; struct timeval tv; if (gettimeofday (&tv, 0) ) shevek_error ("error returned from gettimeofday"); m_seconds = tv.tv_sec; m_nanoseconds = tv.tv_usec * 1000; } // a specific time. days may be 0-365, with months 0. // if months > 0, both days and months have a base of 1. absolute_time::absolute_time (unsigned years, unsigned months, unsigned days, unsigned hours, unsigned minutes, unsigned seconds, unsigned nanoseconds) : m_seconds (seconds), m_nanoseconds (nanoseconds) { startfunc; timetype y = years; y -= 1970; if (months != 0) { static unsigned const daysofmonth[12] = {0, 31, 31 + 28, 31 + 28 + 31, 31 + 28 + 31 + 30, 31 + 28 + 31 + 30 + 31, 31 + 28 + 31 + 30 + 31 + 30, 31 + 28 + 31 + 30 + 31 + 30 + 31, 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31, 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30, 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31, 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30}; if (months > 2 && (y & 3) == 2) ++days; // months and days are 1-based, not 0 --months; --days; days += daysofmonth[months]; } days += 365 * y; days += (y + 2) / 4; // leap years hours += days * 24; minutes += hours * 60; m_seconds += minutes * 60; } // fast constructor absolute_time::absolute_time (timetype seconds, unsigned nanoseconds) : m_seconds (seconds), m_nanoseconds (nanoseconds) { startfunc; } absolute_time absolute_time::create_from_local (unsigned years, unsigned months, unsigned days, unsigned hours, unsigned minutes, unsigned seconds, unsigned nanoseconds) { struct tm t; t.tm_sec = seconds; t.tm_min = minutes; t.tm_hour = hours; t.tm_mday = days; t.tm_mon = months - 1; t.tm_year = years - 1900; t.tm_isdst = -1; timetype s = mktime (&t); return absolute_time (s, nanoseconds); } // do computations absolute_time absolute_time::operator+ (relative_time that) const { startfunc; absolute_time t (*this); if (that.isnegative () ) { if (t.m_nanoseconds < -that.nanoseconds () ) { t.m_nanoseconds += 1000000000; --t.m_seconds; } t.m_nanoseconds -= that.nanoseconds (); } else { t.m_nanoseconds += that.nanoseconds (); if (t.m_nanoseconds > 1000000000) { t.m_nanoseconds -= 1000000000; ++t.m_seconds; } } t.m_seconds += that.total (); return t; } absolute_time absolute_time::operator- (relative_time that) const { startfunc; absolute_time t (*this); if (that.isnegative () ) { t.m_nanoseconds += that.nanoseconds (); if (t.m_nanoseconds > 1000000000) { t.m_nanoseconds -= 1000000000; ++t.m_seconds; } } else { if (t.m_nanoseconds < that.nanoseconds () ) { t.m_nanoseconds += 1000000000; --t.m_seconds; } t.m_nanoseconds -= that.nanoseconds (); } t.m_seconds -= that.total (); return t; } relative_time absolute_time::operator- (absolute_time that) const { startfunc; timetype s = m_seconds; int ns = m_nanoseconds; ns -= that.m_nanoseconds; s -= that.m_seconds; return relative_time (s, ns); } absolute_time &absolute_time::operator+= (relative_time that) { startfunc; return *this = *this + that; } absolute_time &absolute_time::operator-= (relative_time that) { startfunc; return *this = *this - that; } bool absolute_time::operator< (absolute_time that) const { if (m_seconds == that.m_seconds) return m_nanoseconds < that.m_nanoseconds; else return m_seconds < that.m_seconds; } bool absolute_time::operator> (absolute_time that) const { if (m_seconds == that.m_seconds) return m_nanoseconds > that.m_nanoseconds; else return m_seconds > that.m_seconds; } bool absolute_time::operator<= (absolute_time that) const { if (m_seconds == that.m_seconds) { return m_nanoseconds <= that.m_nanoseconds; } else return m_seconds <= that.m_seconds; } bool absolute_time::operator>= (absolute_time that) const { if (m_seconds == that.m_seconds) { return m_nanoseconds >= that.m_nanoseconds; } else return m_seconds >= that.m_seconds; } bool absolute_time::operator== (absolute_time that) const { return m_seconds == that.m_seconds && m_nanoseconds == that.m_nanoseconds; } bool absolute_time::operator!= (absolute_time that) const { return m_seconds != that.m_seconds || m_nanoseconds != that.m_nanoseconds; } unsigned absolute_time::nanoseconds () const { startfunc; return m_nanoseconds; } unsigned absolute_time::local_second () const { startfunc; struct tm st; time_t t = m_seconds; if (!localtime_r (&t, &st) ) shevek_error ("call to localtime_r failed"); return st.tm_sec; } unsigned absolute_time::local_minute () const { startfunc; struct tm st; time_t t = m_seconds; if (!localtime_r (&t, &st) ) shevek_error ("call to localtime_r failed"); return st.tm_min; } unsigned absolute_time::local_hour () const { startfunc; struct tm st; time_t t = m_seconds; if (!localtime_r (&t, &st) ) shevek_error ("call to localtime_r failed"); return st.tm_hour; } unsigned absolute_time::local_days () const // 0-365 { startfunc; struct tm st; time_t t = m_seconds; if (!localtime_r (&t, &st) ) shevek_error ("call to localtime_r failed"); return st.tm_yday; } unsigned absolute_time::local_day () const // 1-31 { startfunc; struct tm st; time_t t = m_seconds; if (!localtime_r (&t, &st) ) shevek_error ("call to localtime_r failed"); return st.tm_mday; } unsigned absolute_time::local_weekday () const // 0-6, 0 == Sunday { startfunc; struct tm st; time_t t = m_seconds; if (!localtime_r (&t, &st) ) shevek_error ("call to localtime_r failed"); return st.tm_wday; } unsigned absolute_time::local_month () const { startfunc; struct tm st; time_t t = m_seconds; if (!localtime_r (&t, &st) ) shevek_error ("call to localtime_r failed"); return st.tm_mon; } unsigned absolute_time::local_year () const { startfunc; struct tm st; time_t t = m_seconds; if (!localtime_r (&t, &st) ) shevek_error ("call to localtime_r failed"); return st.tm_year + 1900; } unsigned absolute_time::second () const { startfunc; struct tm st; time_t t = m_seconds; if (!gmtime_r (&t, &st) ) shevek_error ("call to gmtime_r failed"); return st.tm_sec; } unsigned absolute_time::minute () const { startfunc; struct tm st; time_t t = m_seconds; if (!gmtime_r (&t, &st) ) shevek_error ("call to gmtime_r failed"); return st.tm_min; } unsigned absolute_time::hour () const { startfunc; struct tm st; time_t t = m_seconds; if (!gmtime_r (&t, &st) ) shevek_error ("call to gmtime_r failed"); return st.tm_hour; } unsigned absolute_time::days () const // 0-365 { startfunc; struct tm st; time_t t = m_seconds; if (!gmtime_r (&t, &st) ) shevek_error ("call to gmtime_r failed"); return st.tm_yday; } unsigned absolute_time::day () const // 1-31 { startfunc; struct tm st; time_t t = m_seconds; if (!gmtime_r (&t, &st) ) shevek_error ("call to gmtime_r failed"); return st.tm_mday; } unsigned absolute_time::weekday () const // 0-6, 0 == Sunday { startfunc; struct tm st; time_t t = m_seconds; if (!gmtime_r (&t, &st) ) shevek_error ("call to gmtime_r failed"); return st.tm_wday; } unsigned absolute_time::month () const { startfunc; struct tm st; time_t t = m_seconds; if (!gmtime_r (&t, &st) ) shevek_error ("call to gmtime_r failed"); return st.tm_mon; } unsigned absolute_time::year () const { startfunc; struct tm st; time_t t = m_seconds; if (!gmtime_r (&t, &st) ) shevek_error ("call to gmtime_r failed"); return st.tm_year + 1900; } // total number of seconds, as encoded timetype absolute_time::total () const { startfunc; return m_seconds; } // schedule wrapper, to change function return type bool absolute_time::l_schedule (sigc::slot0 callback) { callback (); // don't reschedule return false; } // schedule a callback when the main loop is ready sigc::connection schedule (sigc::slot0 callback, int prio, Glib::RefPtr context) { return context->signal_idle (). connect (sigc::bind (sigc::ptr_fun (&absolute_time::l_schedule), callback), prio); } // schedule a callback sigc::connection absolute_time::schedule (sigc::slot0 callback, Glib::RefPtr context) { relative_time t = *this - absolute_time (); unsigned time; if (t.isnegative () ) time = 0; else time = t.total () * 1000 + t.nanoseconds () / 1000000; return context->signal_timeout (). connect (sigc::bind (sigc::ptr_fun (&l_schedule), callback), time); } // no timedifference (that is, 0) relative_time::relative_time () : m_seconds (0), m_nanoseconds (0) { startfunc; l_clean (); } // a specific time. relative_time::relative_time (timetype days, int hours, int minutes, int seconds, int nanoseconds) : m_seconds (seconds), m_nanoseconds (nanoseconds) { startfunc; hours += 24 * days; minutes += 60 * hours; m_seconds += 60 * minutes; l_clean (); } // fast constructor relative_time::relative_time (timetype seconds, unsigned nanoseconds) : m_seconds (seconds), m_nanoseconds (nanoseconds) { startfunc; l_clean (); } // do computations relative_time relative_time::operator+ (relative_time that) const { startfunc; relative_time t (*this); t.m_nanoseconds += that.m_nanoseconds; t.m_seconds += that.m_seconds; t.l_clean (); return t; } absolute_time relative_time::operator+ (absolute_time that) const { startfunc; return that + *this; } relative_time relative_time::operator- (relative_time that) const { startfunc; relative_time t (*this); t.m_nanoseconds -= that.m_nanoseconds; t.m_seconds -= that.total (); t.l_clean (); return t; } relative_time relative_time::operator- () const { startfunc; relative_time t (*this); t.m_seconds = -t.m_seconds; t.m_nanoseconds = -t.m_nanoseconds; t.l_clean (); return t; } relative_time relative_time::operator* (float c) const { startfunc; timetype s = m_seconds; int ns = m_nanoseconds; ns = int (ns * c); double part = s * c; s = timetype (s * c); part -= s; ns += int (1000000000 * part); relative_time t (s, ns); return t; } relative_time relative_time::operator/ (float c) const { startfunc; timetype s = m_seconds; int ns = m_nanoseconds; ns = int (ns / c); double part = s / c; s = timetype (s / c); part -= s; ns += int (1000000000 * part); relative_time t (s, ns); return t; } double relative_time::operator/ (relative_time that) const { startfunc; return (m_seconds * 1000000000.0 + m_nanoseconds) * 1.0 / (that.m_seconds * 1000000000.0 + that.m_nanoseconds); } relative_time relative_time::operator% (relative_time that) const { startfunc; if (that == relative_time () ) shevek_error ("division by zero"); int witherror = int (*this / that); relative_time ret = that * witherror; while (ret.m_seconds < 0) if (that.m_seconds < 0) ret -= that; else ret += that; while (ret > that) if (that.m_seconds < 0) ret += that; else ret -= that; return ret; } relative_time &relative_time::operator+= (relative_time that) { startfunc; return *this = *this + that; } relative_time &relative_time::operator-= (relative_time that) { startfunc; return *this = *this - that; } relative_time &relative_time::operator*= (float c) { startfunc; return *this = *this * c; } relative_time &relative_time::operator/= (float c) { startfunc; return *this = *this / c; } relative_time &relative_time::operator%= (relative_time that) { startfunc; return *this = *this % that; } bool relative_time::operator< (relative_time that) const { if (m_seconds == that.m_seconds) return m_nanoseconds < that.m_nanoseconds; else return m_seconds < that.m_seconds; } bool relative_time::operator> (relative_time that) const { if (m_seconds == that.m_seconds) return m_nanoseconds > that.m_nanoseconds; else return m_seconds > that.m_seconds; } bool relative_time::operator<= (relative_time that) const { if (m_seconds == that.m_seconds) { return m_nanoseconds <= that.m_nanoseconds; } else return m_seconds <= that.m_seconds; } bool relative_time::operator>= (relative_time that) const { if (m_seconds == that.m_seconds) { return m_nanoseconds >= that.m_nanoseconds; } else return m_seconds >= that.m_seconds; } bool relative_time::operator== (relative_time that) const { return m_seconds == that.m_seconds && m_nanoseconds == that.m_nanoseconds; } bool relative_time::operator!= (relative_time that) const { return m_seconds != that.m_seconds || m_nanoseconds != that.m_nanoseconds; } unsigned relative_time::nanoseconds () const { startfunc; return m_nanoseconds < 0 ? -m_nanoseconds : m_nanoseconds; } unsigned relative_time::seconds () const { startfunc; timetype s = m_seconds; if (s < 0) s = -s; return s % 60; } unsigned relative_time::minutes () const { startfunc; timetype s = m_seconds; if (s < 0) s = -s; return (s / 60) % 60; } unsigned relative_time::hours () const { startfunc; timetype s = m_seconds; if (s < 0) s = -s; return (s / (60 * 60) ) % 24; } unsigned relative_time::days () const { startfunc; timetype s = m_seconds; if (s < 0) s = -s; return s / (60 * 60 * 24); } bool relative_time::isnegative () const { startfunc; return m_seconds < 0 || m_nanoseconds < 0; } // total number of seconds, as encoded timetype relative_time::total () const { startfunc; return m_seconds; } void relative_time::l_clean () { if (m_nanoseconds >= 1000000000) { while (m_nanoseconds >= 1000000000) { m_nanoseconds -= 1000000000; ++m_seconds; } if (m_seconds < 0) { m_nanoseconds -= 1000000000; ++m_seconds; } } else if (m_nanoseconds <= -1000000000) { while (m_nanoseconds <= -1000000000) { m_nanoseconds += 1000000000; --m_seconds; } if (m_seconds > 0) { m_nanoseconds += 1000000000; --m_seconds; } } else if (m_nanoseconds < 0 && m_seconds > 0) { m_nanoseconds += 1000000000; --m_seconds; } else if (m_nanoseconds > 0 && m_seconds < 0) { m_nanoseconds -= 1000000000; ++m_seconds; } } namespace { int get_next (std::istream &s, char before, bool last = false, bool allow_negative = false, bool optional = false) { if (!s) return 0; if (before != 0) { char c; s >> c; if (c != before) { if (optional) s.putback (c); else s.setstate (std::ios::failbit); return 0; } } if (last) return 0; int retval; s >> retval; if (!s) return 0; if (retval < 0 && !allow_negative) { s.setstate (std::ios::failbit); return 0; } return retval; } unsigned div_digits (unsigned num, unsigned digits) { switch (digits) { default: return 0; case 1: return num / 100000000; case 2: return num / 10000000; case 3: return num / 1000000; case 4: return num / 100000; case 5: return num / 10000; case 6: return num / 1000; case 7: return num / 100; case 8: return num / 10; case 9: return num; } } } std::ostream &operator<< (std::ostream &s, absolute_time t) { s << '['; s << std::setfill ('0') << std::setw (4) << t.year () << '-' << std::setw (2) << (t.month () + 1) << '-' << std::setw (2) << t.day () << '/' << std::setw (2) << t.hour () << ':' << std::setw (2) << t.minute () << ':' << std::setw (2) << t.second (); if (absolute_time::s_digits > 0) { unsigned ns = div_digits (t.nanoseconds (), absolute_time::s_digits); s << '.' << std::setw (absolute_time::s_digits) << ns; } s << ']' << std::setfill (' '); return s; } std::istream &operator>> (std::istream &s, absolute_time &t) { unsigned year = get_next (s, '['); unsigned month = get_next (s, '-'); unsigned day = get_next (s, '-'); unsigned hour = get_next (s, '/'); unsigned minute = get_next (s, ':'); unsigned second = get_next (s, ':'); unsigned nanosecond = get_next (s, '.', false, false, true); get_next (s, ']', true); if (s) t = absolute_time (year, month, day, hour, minute, second, nanosecond); return s; } std::ostream &operator<< (std::ostream &s, relative_time t) { s << '{'; if (t.isnegative () ) s << '-'; if (t.days () != 0) s << t.days () << '/'; s << std::setfill ('0') << std::setw (2) << t.hours () << ':' << std::setw (2) << t.minutes () << ':' << std::setw (2) << t.seconds (); if (relative_time::s_digits > 0) { unsigned ns = div_digits (t.nanoseconds (), relative_time::s_digits); s << '.' << std::setw (relative_time::s_digits) << ns; } s << '}' << std::setfill (' '); return s; } std::istream &operator>> (std::istream &s, relative_time &t) { int day = get_next (s, '{', false, true); int hour; char c; s >> c; if (c == '/') { hour = get_next (s, 0); get_next (s, ':', true); } else if (c == ':') { hour = day; day = 0; } else { s.setstate (std::ios::failbit); return s; } int minute = get_next (s, 0); int second = get_next (s, ':'); int nanosecond = get_next (s, '.', false, false, true); get_next (s, '}', true); if (s) t = relative_time (day, hour, minute, second, nanosecond); return s; } unsigned shevek::absolute_time::s_digits (9); void absolute_time::set_digits (unsigned num) { s_digits = num > 9 ? 9 : num; } unsigned absolute_time::get_digits () { return s_digits; } unsigned shevek::relative_time::s_digits (9); void relative_time::set_digits (unsigned num) { s_digits = num > 9 ? 9 : num; } unsigned relative_time::get_digits () { return s_digits; } } libshevek-1.3.orig/src/server.hh0000644000175000017500000002432311611112252016236 0ustar shevekshevek/* server.hh - a line-protocol network server * Copyright 2003-2005 Bas Wijnen * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef SHEVEK_SERVER_HH #define SHEVEK_SERVER_HH #include "refbase.hh" #include "telnet.hh" #include #include namespace { sighandler_t ignore_broken_pipes = ::signal (SIGPIPE, SIG_IGN); } namespace shevek { /// Set up a network server using shevek::telnet. /** * New connections are accepted, and callbacks to the program are made * when a line of data is received. * * An example file showing how to use the server:
// \#include <shevek/server.hh>
// \#include <shevek/mainloop.hh>
//
// // per-server data structure
// struct serverdata
// {
// // Put in here whatever you like, possibly nothing. There is one
// // instantiation of this class per server.
// // In most cases, global variables can be used instead of this class, but
// // this way allows programs to run more than one server of the same kind,
// // each with its own settings. That is a Good Thing.
// // It is available from server.data (), and therefore from
// // client->get_server ()->data ()
// };
//
// // Each object of this class is a connection. Add any members that are
// // needed on a per-connection basis in this class. Below is a very minimal
// // example, which implements an echo server (everything you write to it is
// // echoed back).
// class client : public shevek::server <client, serverdata>::connection
// {
// // Allow the server to call pickup and read.
// friend class shevek::server <client, serverdata>;
// void pickup (bool is_stdio)
// {
// out->write ("Welcome to the echo server.\\n");
// }
// void read (std::string const &line)
// {
// // An echo server should echo.
// out->write (line + '\\n');
// }
// static Glib::RefPtr <client> create ()
// { return Glib::RefPtr <client> (new client () ); }
// // Make sure it cannot be constructed other than with create.
// // Don't use the constructor for initialising, use pickup () instead.
// // The connection is not initialised when the constructor is called.
// client () {}
// };
//
// int main ()
// {
// Glib::RefPtr <shevek::server <client, serverdata> >
// s = shevek::server <client, serverdata>::create ();
// // "1234" is the port to listen on. It may be a name from
// // /etc/services, such as "telnet" (although you need to be root to claim
// // that one). It can also be a filename, which will be created as a unix
// // domain socket. Debugging is a little harder then, as netcat cannot
// // connect to such sockets.
// s->open ("1234");
// shevek::loop ();
// return 0;
// }
*/ template class server : virtual public shevek::refbase { static inline fd::read_lines_t get_connection_cb_from_friend (client *who) { return sigc::mem_fun (who, &client::read); } public: /// Iterator for looping over all current connections. typedef typename std::list >::iterator iterator; /// Iterator for looping over all current connections. typedef typename std::list >::const_iterator const_iterator; /// Base of the client class which is implemented by the calling program. /** A client object is created for every connection which is accepted. * This class handles server administration and provides access to members from the client class. */ struct connection : virtual public refbase { /// The input socket. The client can stop reading from this connection by calling in->unread (). Glib::RefPtr in; /// The output socket. This is used to send data to the connection. Glib::RefPtr out; /// This is called after in->unread (), to resume accepting data from this connection. void continue_reading () { in->read_lines (server ::get_connection_cb_from_friend (dynamic_cast (this) ) ); } /// Destructor. ~connection () {} protected: /// The client class can construct this object with its create function. connection () {} /// Access to the server object which hosts this client. Glib::RefPtr > get_server () { return m_server; } /// This can be called by the client object to close this connection. void disconnect () { m_server->l_error (m_self); } private: friend class server ; Glib::RefPtr > m_server; iterator m_self; }; private: std::list > m_connections; Glib::RefPtr m_listener; serverdata m_data; server (); void l_read (std::string const &line, Glib::RefPtr conn); void l_connect (Glib::RefPtr in, Glib::RefPtr out, bool is_stdio); void l_pickup (); void l_delayed_disconnect (typename std::list >::iterator conn); void l_error (typename std::list >::iterator conn); public: /// Create a new server object. static Glib::RefPtr create (); /// Open a port and start running. /** If use_stdio is true, there will be an initial connection from standard input/standard output. */ void open (std::string const &port, bool use_stdio = true); /// Get the corresponding serverdata structure. serverdata &data () { return m_data; } /// Get the corresponding serverdata structure. serverdata const &data () const { return m_data;} /// Loop over all current connections. iterator begin () { return m_connections.begin (); } /// Loop over all current connections. iterator end () { return m_connections.end (); } /// Loop over all current connections. const_iterator begin () const { return m_connections.begin (); } /// Loop over all current connections. const_iterator end () const { return m_connections.end (); } /// Stop running this server, closing all current connections. void shutdown (); /// The destructor shuts down the server. ~server () { shutdown (); } }; template void server ::shutdown () { if (m_listener) { m_listener->disconnect (); m_listener = Glib::RefPtr (); } while (!m_connections.empty () ) m_connections.front ()->disconnect (); } template void server ::l_read (std::string const &line, Glib::RefPtr conn) { conn->read (line); } template void server ::l_delayed_disconnect (typename std::list >::iterator conn) { Glib::RefPtr s = Glib::RefPtr ::cast_dynamic ( (*conn)->in); if (s) s->disconnect (); m_connections.erase (conn); } template void server ::l_error (typename std::list >::iterator conn) { Glib::RefPtr s = Glib::RefPtr ::cast_dynamic ( (*conn)->in); if (s) { s->signal_disconnect ().connect (sigc::bind (sigc::mem_fun (*this, &server ::l_delayed_disconnect), conn) ); s->disconnect (); } else { (*conn)->in->unread (); m_connections.erase (conn); } } template void server ::l_connect (Glib::RefPtr in, Glib::RefPtr out, bool is_stdio) { m_connections.push_back (client::create () ); m_connections.back ()->in = in; m_connections.back ()->out = out; m_connections.back ()->m_server = refptr_this > (); m_connections.back ()->m_self = --m_connections.end (); in->set_error (sigc::bind (sigc::mem_fun (*this, &server ::l_error), --m_connections.end () ) ); in->set_eof (sigc::bind (sigc::mem_fun (*this, &server ::l_error), --m_connections.end () ) ); m_connections.back ()->continue_reading (); out->set_error (sigc::bind (sigc::mem_fun (*this, &server ::l_error), --m_connections.end () ) ); m_connections.back ()->pickup (is_stdio); } template void server ::l_pickup () { Glib::RefPtr newfd = telnet::create (); m_listener->accept (newfd); l_connect (newfd, newfd, false); } template server ::server () { } template Glib::RefPtr > server ::create () { return Glib::RefPtr > (new server () ); } template void server ::open (std::string const &port, bool use_stdio) { if (m_listener) m_listener->disconnect (); if (!port.empty () ) { m_listener = socket::create (); m_listener->listen (port, sigc::mem_fun (*this, &server ::l_pickup) ); } if (use_stdio) { l_connect (fd::create (STDIN_FILENO), fd::create (STDOUT_FILENO), true); } } } #endif libshevek-1.3.orig/src/telnet.cc0000644000175000017500000002061111752432022016213 0ustar shevekshevek/* telnet.icc - inline functions for telnet.hh -*- C++ -*- * Copyright 2003 Bas Wijnen * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "telnet.hh" namespace shevek { telnet::option_t telnet::options[6] = { { BINARY, &telnet::will_check, &telnet::wont_check, &telnet::do_check, &telnet::dont_check, false, false, false }, { ECHO, &telnet::will_check, &telnet::wont_check, &telnet::do_check, &telnet::dont_check, false, false, true }, { SUPPRESS_GA, &telnet::will_check, &telnet::wont_check, &telnet::do_check, &telnet::dont_check, false, false, false }, { STATUS, &telnet::l_dont, &telnet::nop, &telnet::l_wont, &telnet::nop, false, false, false }, { TIMING_MARK, &telnet::l_dont, &telnet::nop, &telnet::l_wont, &telnet::nop, false, false, false }, { EXOPL, &telnet::l_dont, &telnet::nop, &telnet::l_wont, &telnet::nop, false, false, false } }; telnet::option_t *telnet::s_find (char opt) { startfunc; for (unsigned i = 0; i < sizeof (options) / sizeof (*options); ++i) { if (options[i].type == opt) return &options[i]; } // the type will be used in responses, so set it to the correct value nop_option.type = opt; return &nop_option; } void telnet::nop (option_t *) { startfunc; } void telnet::l_dont (option_t *opt) { startfunc; Glib::RefPtr keep_object_alive = refptr_this (); (void)&keep_object_alive; m_ignore = true; std::string cmd ("\377\376 ", 3); cmd[2] = opt->type; write (cmd); m_ignore = false; } void telnet::l_wont (option_t *opt) { startfunc; Glib::RefPtr keep_object_alive = refptr_this (); (void)&keep_object_alive; m_ignore = true; std::string cmd (std::string ("\377\374 ", 3) ); cmd[2] = opt->type; write (cmd); m_ignore = false; } void telnet::l_do (option_t *opt) { startfunc; Glib::RefPtr keep_object_alive = refptr_this (); (void)&keep_object_alive; m_ignore = true; std::string cmd (std::string ("\377\375 ", 3) ); cmd[2] = opt->type; write (cmd); m_ignore = false; } void telnet::l_will (option_t *opt) { startfunc; Glib::RefPtr keep_object_alive = refptr_this (); (void)&keep_object_alive; m_ignore = true; std::string cmd (std::string ("\377\373 ", 3) ); cmd[2] = opt->type; write (cmd); m_ignore = false; } void telnet::do_check (option_t *opt) { startfunc; if (opt->here) return; Glib::RefPtr keep_object_alive = refptr_this (); (void)&keep_object_alive; if (opt->not_both && opt->there) l_wont (opt); else { opt->here = true; l_will (opt); } } void telnet::dont_check (option_t *opt) { startfunc; if (!opt->here) return; Glib::RefPtr keep_object_alive = refptr_this (); (void)&keep_object_alive; opt->here = false; l_wont (opt); } void telnet::will_check (option_t *opt) { startfunc; if (opt->there) return; Glib::RefPtr keep_object_alive = refptr_this (); (void)&keep_object_alive; if (opt->not_both && opt->here) l_dont (opt); else { opt->there = true; l_do (opt); } } void telnet::wont_check (option_t *opt) { startfunc; if (!opt->there) return; Glib::RefPtr keep_object_alive = refptr_this (); (void)&keep_object_alive; opt->there = false; l_dont (opt); } void telnet::l_do_sub (std::string const &data, std::string::size_type &pos) { startfunc; } void telnet::l_in_filter (std::string &data) { startfunc; Glib::RefPtr keep_object_alive = refptr_this (); (void)&keep_object_alive; std::string::size_type pos, oldpos = 0; std::string buffer = m_inbuffer + data; m_inbuffer.clear (); data.clear (); while (m_inbuffer.empty () ) { pos = buffer.find_first_of ("\377\r", oldpos); if (pos == buffer.size () - 1) { m_inbuffer = buffer.substr (pos, 1); buffer = buffer.substr (0, pos); break; } if (pos == std::string::npos) break; data += buffer.substr (oldpos, pos - oldpos); option_t *opt; switch (buffer[pos++]) { case '\r': if (!options[BINARY_IDX].there) { if (buffer[pos] == 0) { data += '\r'; ++pos; } else if (buffer[pos] != '\n') data += '\r'; } break; case '\xff': switch (buffer[pos++]) { case SE: break; case NOP: break; case MARK: break; case BREAK: break; case IP: break; case AO: break; case AYT: write (m_am_here); break; case EC: if (!data.empty () ) data = data.substr (0, data.size () - 1); break; case EL: oldpos = data.find_last_of ('\n'); if (oldpos != std::string::npos) data = data.substr (oldpos + 1); else data.clear (); break; case GA: break; case SB: l_do_sub (data, pos); break; case WILL: if (pos == buffer.size () ) { m_inbuffer = buffer.substr (pos - 2, 2); break; } opt = s_find (buffer[pos]); (this->*opt->will) (opt); ++pos; break; case WONT: if (pos == buffer.size () ) { m_inbuffer = buffer.substr (pos - 2, 2); break; } opt = s_find (buffer[pos]); (this->*opt->wont) (opt); ++pos; break; case DO: if (pos == buffer.size () ) { m_inbuffer = buffer.substr (pos - 2, 2); break; } opt = s_find (buffer[pos]); (this->*opt->doo) (opt); ++pos; break; case DONT: if (pos == buffer.size () ) { m_inbuffer = buffer.substr (pos - 2, 2); break; } opt = s_find (buffer[pos]); (this->*opt->dont) (opt); ++pos; break; case IAC: data += std::string ("\377\377", 2); } } oldpos = pos; } data += buffer.substr (oldpos); if (options[ECHO_IDX].here) write (data); return; } void telnet::l_out_filter (std::string &data) { startfunc; if (m_ignore) return; Glib::RefPtr keep_object_alive = refptr_this (); (void)&keep_object_alive; std::string::size_type pos, oldpos = 0; std::string result; while (1) { pos = data.find_first_of ("\xff\r\n", oldpos); if (pos == std::string::npos) { result += data.substr (oldpos); data = result; return; } result += data.substr (oldpos, pos - oldpos); switch (data[pos++]) { case '\r': if (!options[BINARY_IDX].here) result += std::string ("\r\x00", 2); else result += '\r'; break; case '\n': if (!options[BINARY_IDX].here) result += std::string ("\r\n", 2); else result += '\n'; break; case '\xff': result += std::string ("\xff\xff", 2); break; default: throw "bug: default reached in case"; } oldpos = pos; } } telnet::telnet (Glib::RefPtr main) : socket (main), m_ignore (false), m_am_here ("[Yes]\n") { startfunc; nop_option.will = &telnet::nop; nop_option.wont = &telnet::nop; nop_option.doo = &telnet::nop; nop_option.dont = &telnet::nop; in_filter (sigc::mem_fun (*this, &telnet::l_in_filter) ); out_filter (sigc::mem_fun (*this, &telnet::l_out_filter) ); } Glib::RefPtr telnet::create (Glib::RefPtr main) { startfunc; return Glib::RefPtr (new telnet (main) ); } std::string &telnet::you_there () { startfunc; return m_am_here; } } libshevek-1.3.orig/src/dir.cc0000644000175000017500000000360411553533024015504 0ustar shevekshevek/* dir.cc - directory access * Copyright 2006 Bas Wijnen * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "dir.hh" #include "error.hh" #include #include #include #include namespace shevek { bool dir::file::operator< (file const &that) const { // directories are sorted before other files if (is_dir ^ that.is_dir) return is_dir; return name < that.name; } dir::dir () { } dir::dir (std::string const &path) { load (path); } void dir::load (std::string const &path) { DIR *dir = opendir (path.c_str ()); if (!dir) { shevek_error_errno (rostring ("unable to open directory %s", path)); return; } struct dirent *de; for (de = readdir (dir); de; de = readdir (dir)) { struct stat s; std::string p = path + '/' + de->d_name; if (stat (p.c_str (), &s) < 0) continue; file f; f.name = de->d_name; f.is_dir = S_ISDIR (s.st_mode); f.uid = s.st_uid; f.gid = s.st_gid; f.size = s.st_size; data.insert (f); } closedir (dir); } dir::const_iterator dir::begin () const { return data.begin (); } dir::const_iterator dir::end () const { return data.end (); } unsigned dir::size () const { return data.size (); } } libshevek-1.3.orig/src/error.hh0000644000175000017500000000420311553533024016065 0ustar shevekshevek/* error.hh - error and warning handling * Copyright 2004 Bas Wijnen * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef SHEVEK_ERROR_HH #define SHEVEK_ERROR_HH #include "iostring.hh" #include #include #include namespace shevek { /// Set whether shevek_error will throw or not. /** Note that setting this to false may trigger bugs, as it is not tested much. */ bool fatal_errors (bool fatal = true); /// Internal function for printing the errors. void _error_impl (Glib::ustring const &msg, bool is_error, char const *file, unsigned line, char const *fun); /// Give an error message with file, line and function information. #define shevek_error(x) \ shevek::_error_impl ((x), true, __FILE__, __LINE__, __FUNCTION__) /// Give a warning message with file, line and function information. #define shevek_warning(x) \ shevek::_error_impl ((x), false, __FILE__, __LINE__, __FUNCTION__) /// Give an error message with file, line and function information. /** Use errno to give extra information about the error. */ #define shevek_error_errno(x) \ shevek::_error_impl (shevek::ostring ("%s: %s", Glib::ustring (x), strerror (errno)), true, __FILE__, __LINE__, __FUNCTION__) /// Give a warning message with file, line and function information. /** Use errno to give extra information about the error. */ #define shevek_warning_errno(x) \ shevek::_error_impl (shevek::ostring ("%s: %s", Glib::ustring (x), strerror (errno)), false, __FILE__, __LINE__, __FUNCTION__) } #endif libshevek-1.3.orig/src/case.hh0000644000175000017500000000241711553533024015654 0ustar shevekshevek/* case.hh - Convert case in strings * Copyright 2008 Bas Wijnen * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef SHEVEK_CASE_HH #define SHEVEK_CASE_HH #include namespace shevek { /// Convert the characters in a string to uppercase. std::string toupper (std::string const &orig); /// Convert the characters in a string to lowercase. std::string tolower (std::string const &orig); /// Convert the characters in a string so that two case-folded /// strings compare equal if the original strings were equal, except /// for possible case differences. inline std::string casefold (std::string const &orig) { return tolower (orig); } } #endif libshevek-1.3.orig/src/fd.cc0000644000175000017500000004727211553533024015330 0ustar shevekshevek/* fd.cc - function definitions for fd.hh -*- C++ -*- * Copyright 2003-2005 Bas Wijnen * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "fd.hh" #include "error.hh" #include #include #include "debug.hh" #include #define hack_disconnect(x) do { if (x.rep_) x.rep_->call_ = 0; } while (0) namespace shevek { std::string fd::s_junkbuffer; void fd::read_custom (read_custom_t cb) { startfunc; Glib::RefPtr keep_object_alive = refptr_this (); (void)&keep_object_alive; m_read_custom = cb; l_connect (m_iocondition | Glib::IO_IN | Glib::IO_PRI); } void fd::read_priority_custom (read_custom_t cb) { startfunc; Glib::RefPtr keep_object_alive = refptr_this (); (void)&keep_object_alive; m_read_priority_custom = cb; l_connect (m_iocondition | Glib::IO_PRI); } void fd::read (read_t cb) { startfunc; Glib::RefPtr keep_object_alive = refptr_this (); (void)&keep_object_alive; m_flush = flush_t (); hack_disconnect (m_flush); m_read_custom = read_custom_t (); hack_disconnect (m_read_custom); m_read = cb; if (m_readbuffer.empty ()) l_connect (m_iocondition | Glib::IO_IN | Glib::IO_PRI); else { l_connect (m_iocondition | Glib::IO_PRI); if (!m_idle.connected ()) { m_idle = m_main->signal_idle ().connect (sigc::mem_fun (*this, &fd::l_idle)); m_keepalive_helper_idle = refptr_this (); } return; } } void fd::read_priority (read_t cb) { startfunc; Glib::RefPtr keep_object_alive = refptr_this (); (void)&keep_object_alive; m_flush = flush_t (); hack_disconnect (m_flush); m_read_priority_custom = read_custom_t (); hack_disconnect (m_read_priority_custom); m_read_priority = cb; l_connect (m_iocondition | Glib::IO_PRI); } void fd::read_lines (read_lines_t cb) { startfunc; Glib::RefPtr keep_object_alive = refptr_this (); (void)&keep_object_alive; m_flush = flush_t (); hack_disconnect (m_flush); m_read_custom = read_custom_t (); hack_disconnect (m_read_custom); m_read = sigc::mem_fun (*this, &fd::l_read_lines); m_read_lines = cb; if (m_readbuffer.empty ()) l_connect (m_iocondition | Glib::IO_IN | Glib::IO_PRI); else { l_connect (m_iocondition | Glib::IO_PRI); if (!m_idle.connected ()) { m_idle = m_main->signal_idle ().connect (sigc::mem_fun (*this, &fd::l_idle)); m_keepalive_helper_idle = refptr_this (); } return; } } void fd::l_unread () { startfunc; Glib::RefPtr keep_object_alive = refptr_this (); (void)&keep_object_alive; m_read = read_t (); hack_disconnect (m_read); m_read_priority = read_t (); hack_disconnect (m_read_priority); m_read_custom = read_custom_t (); hack_disconnect (m_read_custom); m_read_priority_custom = read_custom_t (); hack_disconnect (m_read_priority_custom); if (m_idle.connected ()) { m_idle.disconnect (); m_keepalive_helper_idle.reset (); } if (m_idle_priority.connected ()) { m_idle_priority.disconnect (); m_keepalive_helper_idle_priority.reset (); } flush_t cb = m_flush; m_flush = flush_t (); hack_disconnect (m_flush); m_flushing = false; if (cb) cb (); } void fd::unread (bool flush_buffer, flush_t cb) { startfunc; l_connect (m_iocondition & ~(Glib::IO_IN | Glib::IO_PRI)); if (!flush_buffer) { l_unread (); return; } m_flush = cb; if (!m_idle.connected () && !m_idle_priority.connected ()) l_unread (); else m_flushing = true; } void fd::write (std::string const &data, write_done_t cb) { startfunc; // add an extra artificial reference to the object, to prevent // deletion from the filter (that would cause a crash otherwise) Glib::RefPtr keep_object_alive = refptr_this (); (void)&keep_object_alive; std::string the_data (data); // first filter it, if there is a filter. If the filter deletes the // object, deletion is delayed until the function exits. if (m_out_filter) m_out_filter (the_data); // add a new entry to the list only if we cannot use the last one if (m_writebuffer.empty () || !m_writebuffer.back ().done) { m_writebuffer.push_back (write_t ()); } m_writebuffer.back ().data += the_data; l_connect (m_iocondition | Glib::IO_OUT); m_writebuffer.back ().done = cb; } void fd::write_raw (std::string const &data, write_done_t cb) { startfunc; // add an extra artificial reference to the object, to prevent // deletion from the filter (that would cause a crash otherwise) Glib::RefPtr keep_object_alive = refptr_this (); (void)&keep_object_alive; std::string the_data (data); // add a new entry to the list only if we cannot use the last one if (m_writebuffer.empty () || !m_writebuffer.back ().done) { m_writebuffer.push_back (write_t ()); } m_writebuffer.back ().data += the_data; l_connect (m_iocondition | Glib::IO_OUT); m_writebuffer.back ().done = cb; } bool fd::write_block (relative_time timeout) { startfunc; Glib::RefPtr keep_object_alive = refptr_this (); (void)&keep_object_alive; relative_time zero; bool use_timeout = timeout > zero; int fixed_timeout_value = timeout == zero ? 0 : -1; // Use an explicit constructor to prevent a system call. // The system call is only needed if there is indeed a (nonzero) timeout. absolute_time t (0, 0); if (use_timeout) t = absolute_time () + timeout; while (!m_writebuffer.empty ()) { int tm; if (use_timeout) { relative_time to = t - absolute_time (); if (to < relative_time ()) { return false; } tm = to.total () * 1000 + to.nanoseconds () / 1000000; } else tm = fixed_timeout_value; struct pollfd pfd; pfd.events = POLLOUT; pfd.revents = 0; pfd.fd = m_fd; int ret = ::poll (&pfd, 1, tm); if (ret == -1 && errno == EAGAIN) continue; if (ret != 1 || !(pfd.revents & POLLOUT)) { return false; } l_write (); if (m_fd < 0) { return false; } } return true; } std::string &fd::read_block (relative_time timeout) { startfunc; if (!m_priority_readbuffer.empty ()) { return m_priority_readbuffer; } if (!m_readbuffer.empty ()) { return m_readbuffer; } Glib::RefPtr keep_object_alive = refptr_this (); (void)&keep_object_alive; relative_time zero; bool use_timeout = timeout > zero; int fixed_timeout_value = timeout == zero ? 0 : -1; // Use an explicit constructor to prevent a system call. // The system call is only needed if there is indeed a (nonzero) timeout. absolute_time t (0, 0); if (use_timeout) t = absolute_time () + timeout; while (true) { int tm; if (use_timeout) { relative_time to = t - absolute_time (); if (to < relative_time ()) { s_junkbuffer.clear (); return s_junkbuffer; } tm = to.total () * 1000 + to.nanoseconds () / 1000000; } else tm = fixed_timeout_value; struct pollfd pfd; pfd.events = POLLIN | POLLPRI; if (!m_writebuffer.empty ()) pfd.events |= POLLOUT; pfd.revents = 0; pfd.fd = m_fd; int ret = ::poll (&pfd, 1, tm); if (ret == -1 && errno == EAGAIN) continue; if (ret < 1) { s_junkbuffer.clear (); return s_junkbuffer; } if (pfd.revents & POLLPRI) { if (m_read_priority) l_read_priority (true); else l_read (true); if (m_fd < 0) { s_junkbuffer.clear (); return s_junkbuffer; } if (!m_priority_readbuffer.empty ()) { if (!m_idle_priority.connected ()) { m_idle_priority = m_main->signal_idle ().connect (sigc::mem_fun (*this, &fd::l_idle_priority)); m_keepalive_helper_idle_priority = refptr_this (); } return m_priority_readbuffer; } if (!m_readbuffer.empty ()) { if (!m_idle.connected ()) { m_idle = m_main->signal_idle ().connect (sigc::mem_fun (*this, &fd::l_idle)); m_keepalive_helper_idle = refptr_this (); } return m_readbuffer; } } if (pfd.revents & POLLOUT) { l_write (); if (m_fd < 0) { s_junkbuffer.clear (); return s_junkbuffer; } } if (pfd.revents & POLLIN) { l_read (true); if (m_fd < 0) { s_junkbuffer.clear (); return s_junkbuffer; } if (!m_readbuffer.empty ()) { // Set an idle callback to handle any data which might // be left over. if (!m_idle.connected ()) { m_idle = m_main->signal_idle ().connect (sigc::mem_fun (*this, &fd::l_idle)); m_keepalive_helper_idle = refptr_this (); } return m_readbuffer; } } if (pfd.revents & (POLLERR | POLLHUP | POLLNVAL)) { s_junkbuffer.clear (); return s_junkbuffer; } } } std::string fd::read_line_block (shevek::relative_time timeout) { bool use_timeout = timeout >= shevek::relative_time (); shevek::absolute_time t (0, 0); if (use_timeout) t = absolute_time () + timeout; std::string sofar; std::string::size_type pos; std::string *buffer = 0; while ((pos = sofar.find ('\n')) == std::string::npos) { buffer = &read_block (timeout); if (buffer->empty () || (use_timeout && buffer->find ('\n') == std::string::npos && (timeout = t - absolute_time ()) < relative_time ())) { *buffer = sofar + *buffer; return std::string (); } sofar += *buffer; buffer->clear (); } if (buffer) *buffer = sofar.substr (pos + 1); return sofar.substr (0, pos); } void fd::set_fd (int the_fd) { startfunc; Glib::RefPtr keep_object_alive = refptr_this (); (void)&keep_object_alive; if (m_fd >= 0) { if (m_handle.connected ()) { m_handle.disconnect (); m_keepalive_helper.reset (); } } m_fd = the_fd; if (the_fd >= 0) { ::fcntl (the_fd, F_SETFL, O_NONBLOCK); l_connect (); } } void fd::in_filter (filter_t cb) { startfunc; m_in_filter = cb; } void fd::out_filter (filter_t cb) { startfunc; m_out_filter = cb; } void fd::l_connect (Glib::IOCondition io) { startfunc; if (m_fd < 0) return; Glib::RefPtr keep_object_alive = refptr_this (); (void)&keep_object_alive; if (m_handle.connected ()) { m_handle.disconnect (); m_keepalive_helper.reset (); } m_handle = m_main->signal_io ().connect (sigc::mem_fun (*this, &fd::l_check), m_fd, io); m_iocondition = io; m_keepalive_helper = refptr_this (); } Glib::RefPtr fd::create (int value, Glib::RefPtr main) { startfunc; return Glib::RefPtr (new fd (value, main)); } fd::fd (int value, Glib::RefPtr main) : m_main (main) { startfunc; m_iocondition = Glib::IO_HUP | Glib::IO_ERR | Glib::IO_NVAL; m_fd = -1; m_flushing = false; set_fd (value); } fd::~fd () { startfunc; set_fd (-1); } void fd::l_read (bool force_fill) { startfunc; ::ssize_t l; char buffer[1000]; l = ::read (m_fd, buffer, sizeof (buffer)); if (l == 0) { if (m_eof) m_eof (); else if (m_error) m_error (); else if (force_fill) { ::close (m_fd); set_fd (-1); } else shevek_error ("unhandled EOF"); return; } if (l < 0) { if (errno != EAGAIN) { if (m_rerror) m_rerror (); else if (m_error) m_error (); else if (force_fill) { ::close (m_fd); set_fd (-1); } else shevek_error ("unhandled read error"); return; } } else if (m_read || force_fill) // throw data away if there is no callback { std::string tmp (buffer, l); // filter the data if (m_in_filter) m_in_filter (tmp); m_readbuffer += tmp; // when force filling, don't call a callback if (!force_fill) { // only connect to idle if unread was not called during callback if (m_read && !m_read (m_readbuffer) && m_read) { l_connect (m_iocondition & ~Glib::IO_IN); if (!m_idle.connected ()) { m_idle = m_main->signal_idle ().connect (sigc::mem_fun (*this, &fd::l_idle)); m_keepalive_helper_idle = refptr_this (); } } else if (m_flushing && !m_idle_priority.connected ()) { l_unread (); } } } } void fd::l_read_priority (bool force_fill) { startfunc; ::ssize_t l; char buffer[1000]; l = ::read (m_fd, buffer, sizeof (buffer)); if (l == 0) { if (m_eof) m_eof (); else if (m_error) m_error (); else if (force_fill) { ::close (m_fd); set_fd (-1); } else shevek_error ("unhandled EOF"); return; } if (l < 0) { if (errno != EAGAIN) { if (m_rerror) m_rerror (); else if (m_error) m_error (); else if (force_fill) { ::close (m_fd); set_fd (-1); } else shevek_error ("unhandled read error"); return; } } // throw data away if there is no callback if (m_read_priority || m_read || force_fill) { std::string tmp (buffer, l); // filter the data if (m_in_filter) m_in_filter (tmp); std::string *buffer; if (m_read_priority) buffer = &m_priority_readbuffer; else buffer = &m_readbuffer; (*buffer) += tmp; // when force filling, don't call a callback if (!force_fill) { // only connect to idle if unread was not called during callback if (m_read_priority && !m_read_priority (*buffer) && m_read_priority) { if (!m_idle_priority.connected ()) { m_idle_priority = m_main->signal_idle ().connect (sigc::mem_fun (*this, &fd::l_idle_priority)); m_keepalive_helper_idle_priority = refptr_this (); } else if (m_flushing && !m_idle.connected ()) l_unread (); } // only connect to idle if unread was not called during callback else if (m_read && !m_read (*buffer) && m_read) { if (!m_idle.connected ()) { m_idle = m_main->signal_idle ().connect (sigc::mem_fun (*this, &fd::l_idle)); m_keepalive_helper_idle = refptr_this (); } else if (m_flushing && !m_idle.connected ()) l_unread (); } } } } void fd::l_write () { startfunc; if (m_writebuffer.empty ()) return; ::ssize_t l; ::size_t todo = m_writebuffer.front ().data.size (); l = ::write (m_fd, m_writebuffer.front ().data.data (), todo); if (l < 0) { if (errno != EAGAIN) { if (m_werror) m_werror (); else if (m_error) m_error (); else shevek_error ("unhandled write error"); if (m_fd < 0) return; } return; } if (todo == unsigned (l)) { if (m_writebuffer.front ().done) m_writebuffer.front ().done (); // the writebuffer can have been cleared by a write_reset // from the callback if (!m_writebuffer.empty ()) m_writebuffer.pop_front (); if (m_writebuffer.empty ()) { l_connect (m_iocondition & ~Glib::IO_OUT); } } else { m_writebuffer.front ().data.erase (0, l); } } bool fd::l_check (Glib::IOCondition result) { startfunc; // keep the object alive at least until this function exits // if this is not done, callbacks deleting the object may cause crashes Glib::RefPtr keep_object_alive = refptr_this (); (void)&keep_object_alive; if ( (result & (Glib::IO_ERR | Glib::IO_NVAL)) != 0) { if (m_poll_error) m_poll_error (); else if (m_error) m_error (); else { shevek_error ("unhandled poll error"); } return true; } if ( (result & Glib::IO_PRI) != 0) { if (m_read_priority_custom) m_read_priority_custom (); else if (m_read_priority) l_read_priority (false); else if (m_read_custom) m_read_custom (); else if (m_read) l_read (false); if (m_fd < 0) { return true; } } if ( (result & Glib::IO_OUT) != 0) { l_write (); if (m_fd < 0) { return true; } } // treat hangup as read: it will be handled by the reader if ( (result & (Glib::IO_IN | Glib::IO_HUP)) != 0) { if (m_read_custom) m_read_custom (); else l_read (false); } return true; } bool fd::l_idle () { startfunc; Glib::RefPtr keep_object_alive = refptr_this (); (void)&keep_object_alive; if (!m_read || m_readbuffer.empty ()) { if (m_idle.connected ()) { m_idle.disconnect (); m_keepalive_helper_idle.reset (); } if (m_flushing) l_unread (); return true; } if (m_read (m_readbuffer)) { if (m_idle.connected ()) { m_idle.disconnect (); m_keepalive_helper_idle.reset (); } if (m_flushing) { if (!m_idle_priority.connected ()) l_unread (); } else if (m_read) { l_connect (m_iocondition | Glib::IO_IN | Glib::IO_PRI); } } return true; } bool fd::l_idle_priority () { startfunc; if (!m_read_priority || m_priority_readbuffer.empty ()) return true; Glib::RefPtr keep_object_alive = refptr_this (); (void)&keep_object_alive; if (m_read_priority (m_priority_readbuffer)) { if (m_idle_priority.connected ()) { m_idle_priority.disconnect (); m_keepalive_helper_idle_priority.reset (); } if (m_flushing) { if (!m_idle.connected ()) l_unread (); } else if (m_read_priority) l_connect (m_iocondition | Glib::IO_PRI); } return true; } bool fd::l_read_lines (std::string &data) { startfunc; std::string::size_type pos = data.find ('\n'); if (pos == std::string::npos) return true; std::string line = data.substr (0, pos); // no newline in here data = data.substr (pos + 1); // remove the newline as well m_read_lines (line); return data.find ('\n') == std::string::npos; } int fd::get_fd () const { startfunc; return m_fd; } Glib::RefPtr fd::get_main_context () { startfunc; return m_main; } void fd::set_error (error_t cb) { startfunc; m_error = cb; } void fd::set_poll_error (error_t cb) { startfunc; m_poll_error = cb; } void fd::set_read_error (error_t cb) { startfunc; m_rerror = cb; } void fd::set_write_error (error_t cb) { startfunc; m_werror = cb; } void fd::set_eof (error_t cb) { startfunc; m_eof = cb; } void fd::read_reset () { startfunc; Glib::RefPtr keep_object_alive = refptr_this (); (void)&keep_object_alive; unread (); m_readbuffer.clear (); m_priority_readbuffer.clear (); } void fd::write_reset () { startfunc; Glib::RefPtr keep_object_alive = refptr_this (); (void)&keep_object_alive; m_writebuffer.clear (); l_connect (m_iocondition & ~Glib::IO_OUT); } void fd::reset () { startfunc; Glib::RefPtr keep_object_alive = refptr_this (); (void)&keep_object_alive; read_reset (); write_reset (); } } libshevek-1.3.orig/src/file.hh0000644000175000017500000000240211553533024015652 0ustar shevekshevek/* file.hh - files with fd * Copyright 2003 Bas Wijnen * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef SHEVEK_FILE_HH #define SHEVEK_FILE_HH #include "fd.hh" namespace shevek { /// Use normal files with the fd class. class file : public fd { file (Glib::RefPtr main); virtual ~file (); public: /// Create a new file object. static Glib::RefPtr create (Glib::RefPtr main = Glib::MainContext::get_default () ); /// Open a new file in the object. void open (std::string name, bool read, bool write); /// Close the file. void close (); }; } #endif libshevek-1.3.orig/src/mainloop.cc0000644000175000017500000000223211553533024016540 0ustar shevekshevek/* main.hh - main function * Copyright 2003 Bas Wijnen * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include "mainloop.hh" namespace shevek { // convenience functions: start and stop the Glib main loop // don't use this, just use Gtk stuff, if you use gtk in your program. static Glib::RefPtr _main_loop; void loop () { _main_loop = Glib::MainLoop::create (); _main_loop->run (); } void end_loop () { if (_main_loop && _main_loop->is_running () ) _main_loop->quit (); } } libshevek-1.3.orig/src/crefptr.cc0000644000175000017500000000561211611037003016363 0ustar shevekshevek/* crefptr - cyclic-protected reference counting smart pointers. * Copyright 2009-2010 Bas Wijnen * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "crefptr.hh" #include "debug.hh" namespace shevek { #ifdef DEBUG_CREFBASE std::list crefbase::dbg_check; #endif int crefbase::dbg_tag = 1; void crefbase::_check () { if (!_init || _checking) return; _checking = true; if (!_refs.empty ()) { std::list <_objptr> queue, cleaner; queue.push_back (this); bool clean = false; while (!clean && !queue.empty ()) { _objptr current = queue.front (); queue.pop_front (); //dbg ("checking references of " << current.operator-> ()); for (std::list <_ptrdata>::iterator i = current->_refs.begin (); i != current->_refs.end (); ++i) { //dbg (" for " << current.operator-> () << ", checking " << i->ref.operator-> () << "; owner: " << i->owner.operator-> ()); if (i->owner.operator-> () == NULL || !i->owner->_init) { clean = true; break; } if (i->owner->_checking) continue; queue.push_back (i->owner); i->owner->_checking = true; cleaner.push_back (i->owner); } //dbg ("done checking references of " << current.operator-> ()); } for (std::list <_objptr>::iterator i = cleaner.begin (); i != cleaner.end (); ++i) (*i)->_checking = false; if (clean) { _checking = false; return; } dbg ("unlinking " << this << " with " << _refs.size () << " reference(s)"); //for (std::list <_ptrdata>::iterator i = _refs.begin (); i != _refs.end (); ++i) //dbg ("ref: " << i->target.operator-> () << "; " << i->owner.operator-> ()); while (!_refs.empty ()) _refs.front ().ref->reset (); } delete this; } crefbase crefbase::no_target; void crefbase::_add (_ptrptr p, _objptr owner) { _refs.push_back (_ptrdata (this, p, owner)); p->_data = --_refs.end (); //dbg ("added reference " << p.operator-> () << " (target = " << p->_target ().operator-> () << ") to " << this << " with owner " << owner.operator-> ()); } void crefbase::_remove (_ptrptr p) { //dbg ("removing reference " << p.operator-> () << " (target = " << p->_target ().operator-> () << ") to " << this << " with owner " << p->_owner ().operator-> ()); _refs.erase (p->_data); _check (); } } libshevek-1.3.orig/src/telnet.hh0000644000175000017500000000700011752432141016224 0ustar shevekshevek/* telnet.hh - implementation of the telnet protocol * Copyright 2003 Bas Wijnen * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef SHEVEK_TELNET_HH #define SHEVEK_TELNET_HH #include "socket.hh" namespace shevek { /// Input and output filters for shevek::socket to make them telnet sockets. class telnet : public socket { // These are ideal for an enum, in a sense, but the values are really char constants, and C++ doesn't allow that for enums. So the choice is to cast the enum value to a char, or to not use an enum. I don't like casts. // Command constants static char const SE = '\xf0'; static char const NOP = '\xf1'; static char const MARK = '\xf2'; static char const BREAK = '\xf3'; static char const IP = '\xf4'; static char const AO = '\xf5'; static char const AYT = '\xf6'; static char const EC = '\xf7'; static char const EL = '\xf8'; static char const GA = '\xf9'; static char const SB = '\xfa'; static char const WILL = '\xfb'; static char const WONT = '\xfc'; static char const DO = '\xfd'; static char const DONT = '\xfe'; static char const IAC = '\xff'; // Option constants. static char const BINARY = '\x00'; static char const ECHO = '\x01'; static char const SUPPRESS_GA = '\x03'; static char const STATUS = '\x05'; static char const TIMING_MARK = '\x06'; static char const EXOPL = '\xff'; enum option_idx { BINARY_IDX = 0, ECHO_IDX = 1, SUPPRESS_GA_IDX = 2, STATUS_IDX = 3, TIMING_MARK_IDX = 4, EXOPL_IDX = 5 }; struct option_t; typedef void (telnet::*action)(option_t *opt); struct option_t { char type; action will, wont, doo, dont; bool here, there, not_both; }; static option_t options[6]; option_t nop_option; option_t *s_find (char opt); void nop (option_t *); void nopwill (option_t *opt); void nopdo (option_t *opt); void l_will (option_t *opt); void l_wont (option_t *opt); void l_do (option_t *opt); void l_dont (option_t *opt); void will_check (option_t *opt); void do_check (option_t *opt); void wont_check (option_t *opt); void dont_check (option_t *opt); void l_do_sub (std::string const &data, std::string::size_type &pos); bool m_ignore; void l_in_filter (std::string &data); void l_out_filter (std::string &data); std::string m_am_here, m_inbuffer; protected: /// Derived classes have their own create function and may call the constructor. telnet (Glib::RefPtr main); public: /// Create a new telnet socket. static Glib::RefPtr create (Glib::RefPtr main = Glib::MainContext::get_default () ); /// Return the string that is used in reply to ARE_YOU_THERE requests. /** This can also be used to change the reply. */ std::string &you_there (); }; } #endif libshevek-1.3.orig/src/error.cc0000644000175000017500000000261511553533024016060 0ustar shevekshevek/* error.hh - error and warning handling * Copyright 2004 Bas Wijnen * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "error.hh" #include #include namespace shevek { static bool _break_on_error = true; void _error_impl (Glib::ustring const &message, bool is_error, char const *file, unsigned line, char const *fun) { std::cerr << file << " (" << fun << "):" << line << (is_error ? ":Error: " : ":Warning: ") << message << '\n'; if (is_error && _break_on_error) { throw message; } /* else { std::cerr << (is_error ? "Error: " : "Warning: ") << message << '\n'; } */ } bool fatal_errors (bool fatal) { bool retval = _break_on_error; _break_on_error = fatal; return retval; } } libshevek-1.3.orig/src/args.cc0000644000175000017500000004252511553533024015667 0ustar shevekshevek/* args.cc - function implementations of args.hh -*- C++ -*- * Copyright 2003-2010 Bas Wijnen * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include "iostring.hh" #include "debug.hh" #include "args.hh" #include "error.hh" namespace shevek { args::args (int &argc, char **&argv, int min_args, int max_args, Glib::ustring const &description, Glib::ustring const ©right_years, Glib::ustring const ©right_email, Glib::ustring const &programmer, Glib::ustring const &email, char const *programname, char const *packagename, char const *version) { // don't put this structure in l_setup, because it has variable length struct ::option longopts[4]; l_setup (argc, argv, 0, 0, min_args, max_args, description, longopts, copyright_years, copyright_email, programmer, email, programname, packagename, version); } void args::l_setup (int &argc, char **&argv, option *o, unsigned num_options, int min_args, int max_args, Glib::ustring const &description, struct ::option *longopts, Glib::ustring const ©right_years, Glib::ustring const ©right_email, Glib::ustring const &programmer, Glib::ustring const &email, char const *programname, char const *packagename, char const *version) { startfunc; int dummy; // to make sure the returnvalue is 0 for long options. Glib::ustring optstring = "h"; // Every progam must have a --help argument. longopts[num_options].name = "help"; longopts[num_options].has_arg = no_argument; longopts[num_options].flag = 0; longopts[num_options].val = 'h'; // Every progam must have a --version argument. longopts[num_options + 1].name = "version"; longopts[num_options + 1].has_arg = no_argument; longopts[num_options + 1].flag = &dummy; longopts[num_options + 1].val = 0; // Every program must have a --configfile argument. longopts[num_options + 2].name = "configfile"; longopts[num_options + 2].has_arg = required_argument; longopts[num_options + 2].flag = &dummy; longopts[num_options + 2].val = 0; // The last element must mark the end of the array. ::memset (&longopts[num_options + 3], 0, sizeof (*longopts)); for (unsigned i = 0; i < num_options; ++i) { if (o[i].m_shortopt) { optstring += o[i].m_shortopt; if (o[i].m_have_arg != option::NO_ARG) optstring += ':'; if (o[i].m_have_arg == option::OPT_ARG) optstring += ':'; } longopts[i].name = o[i].m_longopt.c_str (); switch (o[i].m_have_arg) { case option::NO_ARG: longopts[i].has_arg = no_argument; break; case option::OPT_ARG: longopts[i].has_arg = optional_argument; break; case option::NEED_ARG: longopts[i].has_arg = required_argument; } longopts[i].flag = &dummy; longopts[i].val = 0; } int opt; std::string filename; while (true) { char nul = '\0'; optarg = &nul; int idx; opt = getopt_long (argc, argv, optstring.c_str (), longopts, &idx); if (opt == -1) break; if (opt == ':') { shevek_error ("invalid option definition"); return; } if (opt == '?') { shevek_error ("parse error in option list (try --help)"); return; } if (opt == 'h') { // handle --help internally std::cout << programname; if (Glib::ustring (programname) != packagename) std::cout << " from " << packagename; else std::cout << programname; std::cout << ", version " << version << "\n\n" << description << "\n" "Possible options are:\n" "-h\t--help\t\tShow this help and exit.\n" "\t--version\tShow version information and exit.\n" "\t--configfile\tUse a specific config file.\n"; for (unsigned i = 0; i < num_options; ++i) { if (o[i].m_shortopt != 0) std::cout << "-" << o[i].m_shortopt; unsigned len = o[i].m_longopt.length (); std::cout << "\t--" << o[i].m_longopt << '\t'; if (len < 6) std::cout << '\t'; std::cout << o[i].m_help; if (o[i].m_have_default) std::cout << " [" << o[i].m_default << ']'; std::cout << '\n'; } std::cout << "\nPlease send bug reports and other comments to <" << email << ">\n"; exit (0); } if (opt == 0 && unsigned (idx) == num_options + 1) { // handle --version internally std::cout << programname << " from " << packagename << ", version " << version << "\n\n" << "Copyright (C) " << copyright_years << ' ' << programmer << " <" << copyright_email << ">\n\n" "This program is free software: you can redistribute it and/or modify\n" "it under the terms of the GNU General Public License as published by\n" "the Free Software Foundation, either version 3 of the License, or\n" "(at your option) any later version.\n" "\n" "This program is distributed in the hope that it will be useful,\n" "but WITHOUT ANY WARRANTY; without even the implied warranty of\n" "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" "GNU General Public License for more details.\n" "\n" "You should have received a copy of the GNU General Public License\n" "along with this program. If not, see .\n" "\n" "\nPlease send bug reports and other comments to <" << email << ">\n"; exit (0); } if (opt == 0 && unsigned (idx) == num_options + 2) { // Handle --configfile internally. filename = optarg; continue; } if (opt == 0) // long option { o[idx].call (false, optarg); continue; } for (unsigned i = 0; i < num_options; ++i) { if (opt == o[i].m_shortopt) { o[i].call (false, optarg); break; } } } if (optind > 1) { char *tmp = argv[0]; argv[0] = argv[optind - 1]; argv[optind - 1] = tmp; argv += optind - 1; argc -= optind - 1; } if (argc - 1 < min_args || (max_args >= min_args && argc - 1 > max_args) ) { if (min_args < max_args) shevek_error (ostring ("invalid number of non-option arguments %d. " "Must be between %d and %d.", argc - 1, min_args, max_args)); else if (min_args == max_args) shevek_error (ostring ("invalid number of non-option arguments %d. " "Must be %d.", argc - 1, min_args)); else shevek_error (ostring ("invalid number of non-option arguments %d. " "Must be at least %d.", argc - 1, min_args)); } for (int i = 1; i < argc; ++i) { m_args.push_back (argv[i]); } // Read the configuration file. bool use_default_filename = false; if (filename.empty ()) { std::vector path (2); path[0] = Glib::get_user_config_dir (); path[1] = programname; filename = Glib::build_filename (path); use_default_filename = true; } std::ifstream file (filename.c_str ()); if (!use_default_filename && !file) shevek_error (shevek::ostring ("specified configuration file not found: %s", Glib::ustring (filename))); std::string line; while (std::getline (file, line)) { shevek::ristring s (line); std::string key; if (s (" #") || s (" %")) continue; if (s (" %[^ \t=] =", key)) { unsigned i; for (i = 0; i < num_options; ++i) { if (key == o[i].m_longopt) { if (o[i].m_have_arg == option::NO_ARG) shevek_warning (shevek::ostring ("config file %s: option %s doesn't accept an argument", Glib::ustring (filename), Glib::ustring (key))); o[i].call (o[i].m_is_used, s.rest ().c_str ()); break; } } if (i >= num_options) shevek_warning (shevek::ostring ("config file %s: unknown option %s", Glib::ustring (filename), Glib::ustring (key))); } else if (s (" %s %", key)) { unsigned i; for (i = 0; i < num_options; ++i) { if (key == o[i].m_longopt) { if (o[i].m_have_arg == option::NEED_ARG) shevek_warning (shevek::ostring ("config file %s: option %s requires an argument", Glib::ustring (filename), Glib::ustring (key))); o[i].call (o[i].m_is_used, NULL); break; } } if (i >= num_options) shevek_warning (shevek::ostring ("config file %s: unknown option %s", Glib::ustring (filename), Glib::ustring (key))); } } } unsigned args::size () const { startfunc; return m_args.size (); } std::string const &args::operator[] (unsigned idx) const { startfunc; if (idx > m_args.size () ) throw "index out of range"; return m_args[idx]; } std::vector ::const_iterator args::begin () const { startfunc; return m_args.begin (); } std::vector ::const_iterator args::end () const { startfunc; return m_args.end (); } void args::option::setup (char shortopt, Glib::ustring const &longopt, Glib::ustring const &help_line, bool have_default, opt_t have_arg, callback0 handle0, callback1 handle1, bool *used) { startfunc; m_shortopt = shortopt; m_longopt = longopt; m_help = help_line; m_have_default = have_default; m_have_arg = have_arg; m_handle0 = handle0; m_handle1 = handle1; m_is_used = false; m_used = used; if (m_used) *m_used = false; } args::option::option (char shortopt, Glib::ustring const &longopt, Glib::ustring const &help_line, callback0 handle, bool *used) { startfunc; setup (shortopt, longopt, help_line, false, NO_ARG, handle, callback1 (), used); } args::option::option (char shortopt, Glib::ustring const &longopt, Glib::ustring const &help_line, bool have_default, callback1 handle, Glib::ustring default_val, bool *used) { startfunc; m_default = default_val; setup (shortopt, longopt, help_line, have_default, NEED_ARG, callback0 (), handle, used); } args::option::option (char shortopt, Glib::ustring const &longopt, Glib::ustring const &help_line, callback0 handle0, callback1 handle1, bool *used) { startfunc; setup (shortopt, longopt, help_line, false, OPT_ARG, handle0, handle1, used); } args::option::option (char shortopt, Glib::ustring const &longopt, Glib::ustring const &help_line, bool &var, bool value, bool *used) { startfunc; setup (shortopt, longopt, help_line, false, NO_ARG, sigc::bind (sigc::bind (sigc::ptr_fun (&l_setbool), &var), value), callback1 (), used); } args::option::option (char shortopt, Glib::ustring const &longopt, Glib::ustring const &help_line, bool have_default, Glib::ustring &var, bool *used) { startfunc; setup (shortopt, longopt, help_line, have_default, NEED_ARG, callback0 (), sigc::bind (sigc::ptr_fun (&l_set), &var), used); } args::option::option (char shortopt, Glib::ustring const &longopt, Glib::ustring const &help_line, bool have_default, std::string &var, bool *used) { startfunc; if (have_default) m_default = var; setup (shortopt, longopt, help_line, have_default, NEED_ARG, callback0 (), sigc::bind (sigc::ptr_fun (&l_setstd), &var), used); } args::option::option (char shortopt, Glib::ustring const &longopt, Glib::ustring const &help_line, bool have_default, unsigned long &var, bool *used) { startfunc; if (have_default) m_default = ostring ("%d", var); setup (shortopt, longopt, help_line, have_default, NEED_ARG, callback0 (), sigc::bind (sigc::ptr_fun (&l_setulint), &var), used); } args::option::option (char shortopt, Glib::ustring const &longopt, Glib::ustring const &help_line, bool have_default, long &var, bool *used) { startfunc; if (have_default) m_default = ostring ("%d", var); setup (shortopt, longopt, help_line, have_default, NEED_ARG, callback0 (), sigc::bind (sigc::ptr_fun (&l_setlint), &var), used); } args::option::option (char shortopt, Glib::ustring const &longopt, Glib::ustring const &help_line, bool have_default, unsigned &var, bool *used) { startfunc; if (have_default) m_default = ostring ("%d", var); setup (shortopt, longopt, help_line, have_default, NEED_ARG, callback0 (), sigc::bind (sigc::ptr_fun (&l_setuint), &var), used); } args::option::option (char shortopt, Glib::ustring const &longopt, Glib::ustring const &help_line, bool have_default, int &var, bool *used) { startfunc; if (have_default) m_default = ostring ("%d", var); setup (shortopt, longopt, help_line, have_default, NEED_ARG, callback0 (), sigc::bind (sigc::ptr_fun (&l_setint), &var), used); } args::option::option (char shortopt, Glib::ustring const &longopt, Glib::ustring const &help_line, bool have_default, unsigned short &var, bool *used) { startfunc; if (have_default) m_default = ostring ("%d", var); setup (shortopt, longopt, help_line, have_default, NEED_ARG, callback0 (), sigc::bind (sigc::ptr_fun (&l_setusint), &var), used); } args::option::option (char shortopt, Glib::ustring const &longopt, Glib::ustring const &help_line, bool have_default, short &var, bool *used) { startfunc; if (have_default) m_default = ostring ("%d", var); setup (shortopt, longopt, help_line, have_default, NEED_ARG, callback0 (), sigc::bind (sigc::ptr_fun (&l_setsint), &var), used); } args::option::option (char shortopt, Glib::ustring const &longopt, Glib::ustring const &help_line, bool have_default, float &var, bool *used) { startfunc; if (have_default) m_default = ostring ("%d", var); setup (shortopt, longopt, help_line, have_default, NEED_ARG, callback0 (), sigc::bind (sigc::ptr_fun (&l_setfloat), &var), used); } args::option::option (char shortopt, Glib::ustring const &longopt, Glib::ustring const &help_line, bool have_default, double &var, bool *used) { startfunc; if (have_default) m_default = ostring ("%d", var); setup (shortopt, longopt, help_line, have_default, NEED_ARG, callback0 (), sigc::bind (sigc::ptr_fun (&l_setdfloat), &var), used); } void args::option::call (bool is_double, char const *arg) { startfunc; m_is_used = true; if (m_used) *m_used = true; switch (m_have_arg) { case NO_ARG: m_handle0 (is_double); break; case NEED_ARG: m_handle1 (is_double, arg); break; case OPT_ARG: if (arg) m_handle1 (is_double, arg); else m_handle0 (is_double); } } void args::option::l_set (bool is_double, Glib::ustring const &arg, Glib::ustring *var) { startfunc; if (!is_double) *var = arg; } void args::option::l_setstd (bool is_double, Glib::ustring const &arg, std::string *var) { startfunc; if (!is_double) *var = arg; } void args::option::l_setlint (bool is_double, Glib::ustring const &arg, long *var) { startfunc; char *ep; if (!is_double) { *var = strtol (arg.c_str (), &ep, 0); if (*ep != 0) throw "invalid argument to option expecting long"; } } void args::option::l_setulint (bool is_double, Glib::ustring const &arg, unsigned long *var) { startfunc; if (!is_double) { char *ep; *var = strtoul (arg.c_str (), &ep, 0); if (*ep != 0) throw "invalid argument to option expection unsigned long"; } } void args::option::l_setint (bool is_double, Glib::ustring const &arg, int *var) { startfunc; if (!is_double) { char *ep; long tmp; tmp = strtol (arg.c_str (), &ep, 0); if (*ep != 0) throw "invalid argument to option expecting long"; *var = tmp; } } void args::option::l_setuint (bool is_double, Glib::ustring const &arg, unsigned *var) { startfunc; if (!is_double) { char *ep; unsigned long tmp; tmp = strtoul (arg.c_str (), &ep, 0); if (*ep != 0) throw "invalid argument to option expecting unsigned long"; *var = tmp; } } void args::option::l_setsint (bool is_double, Glib::ustring const &arg, short *var) { startfunc; if (!is_double) { char *ep; long tmp; tmp = strtol (arg.c_str (), &ep, 0); if (*ep != 0) throw "invalid argument to option expecting long"; *var = tmp; } } void args::option::l_setusint (bool is_double, Glib::ustring const &arg, unsigned short *var) { startfunc; if (!is_double) { char *ep; unsigned long tmp; tmp = strtoul (arg.c_str (), &ep, 0); if (*ep != 0) throw "invalid argument to option expecting unsigned long"; *var = tmp; } } void args::option::l_setbool (bool is_double, bool val, bool *var) { startfunc; if (!is_double) *var = val; } void args::option::l_setfloat (bool is_double, Glib::ustring const &arg, float *var) { startfunc; if (!is_double) { char *ep; *var = strtof (arg.c_str (), &ep); if (*ep != 0) throw "invalid argument to option expecting float"; } } void args::option::l_setdfloat (bool is_double, Glib::ustring const &arg, double *var) { startfunc; if (!is_double) { char *ep; *var = strtod (arg.c_str (), &ep); if (*ep != 0) throw "invalid argument to option expecting double"; } } } libshevek-1.3.orig/src/mainloop.hh0000644000175000017500000000234511553533024016557 0ustar shevekshevek/* main.hh - main function * Copyright 2003 Bas Wijnen * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef SHEVEK_MAINLOOP_HH #define SHEVEK_MAINLOOP_HH namespace shevek { // convenience functions: start and stop the Glib main loop // don't use this, just use Gtk stuff, if you use gtk in your program. /// Start the Glib main loop. /** If you use Gtk, just use Gtk::Main::run instead. */ void loop (); /// Tell the main loop to stop running when the current event is handled. /** There is no difference between this and Gtk::Main::quit. */ void end_loop (); } #endif // defined SHEVEK_MAINLOOP_HH