| iMatix home page
| << | < | > | >>
SFL Logo SFL
Version 2.1

The Standard Function Library

The SFL (Standard Function Library) from iMatix is a portable function library for C/C++ programs. The SFL is the result of many years' development, and is provided as free software for the benefit of the Internet community.

You may want to go straight to the Table of Contents.

The SFL is written in ANSI C and has been ported to MS-DOS, Windows, UNIX systems (Linux, IBM AIX, SunOS, HP/UX, Solaris, NetBSD, FreeBSD, SCO OpenServer, Digital UNIX) and Digital OpenVMS. It comes with complete sources and documentation in HTML.

The SFL provides about 300 functions that cover these areas:

The SFL is free software that you may use and distribute for private or commercial purposes according to the SFL License Agreement.  

Table of Contents

  • What Is The SFL
  • Origins
  • Objectives
  • Portability
  • Installing The SFL
  • Availability and Distribution
  • Installation for UNIX Systems
  • Installation for Digital VMS Systems
  • Installation for Windows
  • Installation for MS-DOS
  • Using The SFL
  • The Universal Header File - prelude.h
  • The Library Header File - sfl.h
  • System Notes
  • To Do List
  • Contributors and References
  • The SFL License Agreement
  • Universal Header File for C programming
  • Define SFL version
  • Large bitstring manipulation functions
  • bits_init
  • bits_term
  • bits_create
  • bits_destroy
  • bits_set
  • bits_clear
  • bits_test
  • bits_fput
  • bits_fget
  • Compression functions
  • compress_block
  • expand_block
  • compress_rle
  • expand_rle
  • compress_nulls
  • expand_nulls
  • compress_bits
  • expand_bits
  • Console output functions
  • console_send
  • console_enable
  • console_disable
  • console_set_mode
  • console_capture
  • coprintf
  • coputs
  • coputc
  • Conversion functions
  • conv_bool_str
  • conv_date_pict
  • conv_date_str
  • conv_number_str
  • conv_str_bool
  • conv_str_date
  • conv_str_day
  • conv_str_number
  • conv_str_time
  • conv_time_pict
  • conv_time_str
  • Encryption and decryption functions
  • crypt_encode
  • crypt_decode
  • calculate_crc
  • Date and time functions
  • date_now
  • time_now
  • leap_year
  • julian_date
  • day_of_week
  • next_weekday
  • prev_weekday
  • week_of_year
  • year_quarter
  • default_century
  • pack_date
  • pack_time
  • unpack_date
  • unpack_time
  • date_to_days
  • days_to_date
  • date_to_timer
  • timer_to_date
  • timer_to_time
  • timer_to_gmdate
  • timer_to_gmtime
  • time_to_csecs
  • csecs_to_time
  • future_date
  • past_date
  • date_diff
  • valid_date
  • valid_time
  • date_is_future
  • date_is_past
  • timezone_string
  • local_to_gmt
  • gmt_to_local
  • External data representation functions
  • exdr_write
  • exdr_writed
  • exdr_read
  • Fast string searching functions
  • strfind
  • strfind_r
  • strfind_rb
  • memfind
  • memfind_r
  • memfind_rb
  • txtfind
  • File-access functions
  • file_open
  • file_locate
  • file_close
  • file_read
  • file_readn
  • file_write
  • file_copy
  • file_concat
  • file_rename
  • file_delete
  • file_exists
  • file_where
  • file_cycle
  • file_cycle_needed
  • file_has_changed
  • safe_to_extend
  • default_extension
  • fixed_extension
  • strip_extension
  • strip_file_path
  • strip_file_name
  • file_is_readable
  • file_is_writeable
  • file_is_executable
  • file_is_program
  • file_is_directory
  • file_is_legal
  • file_exec_name
  • get_file_size
  • get_file_time
  • get_file_lines
  • file_slurp
  • file_slurpl
  • file_set_eoln
  • get_tmp_file_name
  • Initialisation file access functions
  • ini_find_section
  • ini_scan_section
  • ini_dyn_load
  • ini_dyn_save
  • ini_dyn_changed
  • ini_dyn_refresh
  • ini_dyn_value
  • ini_dyn_values
  • Multilanguage support
  • set_userlang
  • set_userlang_str
  • get_userlang
  • get_userlang_str
  • set_accents
  • get_accents
  • get_units_name
  • get_tens_name
  • get_day_name
  • get_day_abbrev
  • get_month_name
  • get_month_abbrev
  • timestamp_string
  • Line buffering functions
  • linebuf_create
  • linebuf_destroy
  • linebuf_reset
  • linebuf_append
  • linebuf_first
  • linebuf_next
  • linebuf_last
  • linebuf_prev
  • Linked-list functions
  • list_unlink
  • list_relink
  • list_add
  • list_remove
  • list_sort
  • SMTP mailer function
  • smtp_send_mail_ex
  • smtp_send_mail
  • Mathematic functions
  • point_in_rect
  • point_in_circle
  • point_in_poly
  • Message-file access functions
  • open_message_file
  • close_message_file
  • print_message
  • message_text
  • Memory allocation functions
  • mem_alloc_
  • mem_realloc_
  • mem_strdup_
  • mem_strfree_
  • mem_free_
  • mem_assert_
  • mem_checkall_
  • mem_check_
  • mem_descr_
  • mem_new_trans_
  • mem_commit_
  • mem_rollback_
  • mem_size_
  • mem_used
  • mem_allocs
  • mem_frees
  • mem_display
  • mem_scavenger
  • MIME support functions
  • encode_base64
  • decode_base64
  • decode_mime_time
  • encode_mime_time
  • Linked-list functions
  • node_create
  • node_destroy
  • node_relink_after
  • node_relink_before
  • node_unlink
  • node_relink
  • Directory access functions
  • open_dir
  • read_dir
  • close_dir
  • format_dir
  • fix_dir
  • free_dir
  • load_dir_list
  • free_dir_list
  • sort_dir_list
  • add_dir_list
  • resolve_path
  • locate_path
  • clean_path
  • get_curdir
  • set_curdir
  • file_matches
  • make_dir
  • remove_dir
  • Process control functions
  • process_create
  • process_status
  • process_kill
  • process_close
  • process_server
  • process_alarm
  • process_esc
  • process_unesc
  • process_priority
  • Time-slot functions
  • year_range_empty
  • year_range_fill
  • year_slot_clear
  • year_slot_set
  • year_slot_filled
  • day_range_empty
  • day_range_fill
  • day_slot_clear
  • day_slot_set
  • day_slot_filled
  • date_to_day
  • time_to_min
  • String-handling functions
  • strdupl
  • strfree
  • strskp
  • strcset
  • strpad
  • strlwc
  • strupc
  • strcrop
  • stropen
  • strclose
  • strunique
  • strmatch
  • strprefixed
  • strprefix
  • strdefix
  • strhash
  • strconvch
  • xstrcat
  • xstrcpy
  • lexcmp
  • lexncmp
  • lexwcmp
  • soundex
  • soundexn
  • strt2descr
  • descr2strt
  • strtfree
  • removechars
  • replacechrswith
  • insertstring
  • insertchar
  • leftfill
  • rightfill
  • trim
  • ltrim
  • searchreplace
  • deletestring
  • getstrfld
  • setstrfld
  • getstrfldlen
  • findstrinfile
  • getequval
  • matchtable
  • stringreplace
  • wordwrapstr
  • stricstr
  • strtempcmp
  • istoken
  • eatstr
  • eatstrpast
  • movestrpast
  • eatchar
  • isoneoftokens
  • TCP/IP, UDP/IP socket functions
  • sock_init
  • sock_term
  • passive_TCP
  • passive_UDP
  • passive_socket
  • create_socket
  • connect_TCP
  • connect_UDP
  • connect_TCP_fast
  • connect_UDP_fast
  • connect_socket
  • connect_to_peer
  • address_end_point
  • build_sockaddr
  • socket_localaddr
  • socket_peeraddr
  • socket_nodelay
  • socket_is_alive
  • socket_error
  • accept_socket
  • connect_error
  • get_sock_addr
  • get_peer_addr
  • read_TCP
  • write_TCP
  • read_UDP
  • write_UDP
  • close_socket
  • sock_select
  • get_hostname
  • get_hostaddr
  • get_hostaddrs
  • sock_ntoa
  • sockmsg
  • winsock_last_error
  • socket_is_permitted
  • get_host_file
  • get_name_server
  • Symbol-table functions
  • sym_create_table_
  • sym_delete_table
  • sym_empty_table
  • sym_merge_tables
  • sym_lookup_symbol
  • sym_create_symbol_
  • sym_assume_symbol_
  • sym_delete_symbol
  • sym_exec_all
  • sym_hash
  • sym_get_value
  • sym_get_number
  • sym_get_boolean
  • sym_set_value
  • sym_sort_table
  • symb2strt_
  • strt2symb_
  • symb2descr_
  • descr2symb_
  • System-level functions (assertions,...)
  • sys_assert
  • sys_name
  • HTTP and CGI Support functions
  • http_escape
  • http_escape_size
  • http_unescape
  • http_query2strt
  • http_query2symb
  • http_query2descr
  • http_encode_meta
  • cgi_parse_query_vars
  • cgi_parse_file_vars
  • http_multipart_decode
  • is_full_url
  • cgi_get_input
  • cgi_fld_by_name
  • cgi_fld_by_index
  • cgi_fld_len_by_index
  • displayform
  • Environment variable functions
  • env_get_string
  • env_get_number
  • env_get_boolean
  • env2descr
  • descr2env
  • env2symb
  • symb2env
  • String token manipulation functions.
  • tok_split
  • tok_split_rich
  • tok_free
  • tok_push
  • tok_size
  • tok_text_size
  • tok_subst
  • Linked-list functions
  • tree_init
  • tree_insert
  • tree_delete
  • tree_find
  • tree_traverse
  • tree_first
  • tree_last
  • tree_next
  • tree_prev
  • Tracing functions
  • enable_trace
  • disable_trace
  • push_trace
  • pop_trace
  • set_trace_file
  • trace
  • Process user id (uid) and group id (gid) functions
  • get_uid_name
  • get_gid_name
  • set_uid_user
  • set_uid_root
  • set_gid_user
  • set_gid_root
  • set_uid_gid
  • get_login
  • XML (Extensible Markup Language) access functions
  • xml_new
  • xml_modify_value
  • xml_item_name
  • xml_item_value
  • xml_free
  • xml_first_child
  • xml_next_sibling
  • xml_parent
  • xml_put_attr
  • xml_attr
  • xml_attr_name
  • xml_attr_value
  • xml_get_attr
  • xml_free_attr
  • xml_first_attr
  • xml_next_attr
  • xml_changed
  • xml_refresh
  • xml_save
  • xml_error
  • xml_load
  • What Is The SFL

    Origins

    At iMatix we develop portable free and commercial software. We work in ANSI C to cover the widest range possible. A major part of our toolkit has always been our subroutine library. This was initially written for MS-DOS in 1991 but has developed into a more ambitious project since then.

    From the outset, we ignored commercial libraries. Our software is usually free - as in 'liberated' rather than 'gratis' - and using a commercial library would have been intolerable. We looked for free libraries, but found only specialised and mostly non-portable collections of functions. So, we built our own. We hope you like it. We certainly use it all the time.

    Objectives

    When we designed the SFL, we had certain things in mind:

    Portability

    The SFL is in use on these systems:

    Some recent functions may not have been tested or implemented across all platforms. Some functions are empty on some platforms. Since the SFL is continually improving and enlarging, there are always newer functions that are less tested, and possibly less than 100% portable. Our intention is that the transparency of the SFL makes these functions easy to test and improve.

    Installing The SFL

    Availability and Distribution

    We supply the SFL as two archives: a source kit and a documentation kit (in HTML). These files are available for download by HTTP from our website on a permanent basis. You need to recompile the SFL for your specific system, using an ANSI C compiler. We don't provide binary kits (as yet) for several reasons:

    Getting The Source Archive

    The SFL source archive is supplied as a zip file and a GNU gzip+tar file. These are the files in the /pub/sfl/src directory:

    sflsrc21.tgz   308722 98/04/25 10:17:16  Gzip/tar archive
    sflsrc21.zip   385323 98/07/25 23:28:32  ZIP archive
    

    If you have trouble accessing the iMatix site, send us an e-mail and we'll send you the SFL archives by return e-mail, using the uuencode format.

    Getting The The Documentation Kit

    The SFL documentation is supplied as HTML files, available on-line or off-line as a single .zip file that you can install on a hard disk for rapid access, and also as a GNU gzipped file. These are the files in the /pub/sfl/doc directory:

    sflbig21.tgz   184689 98/04/25 10:17:22  Gzip/tar archive
    sflbig21.zip   190376 98/07/25 23:28:36  ZIP archive
    sfldoc21.tgz   217445 98/04/25 10:17:18  Gzip/tar archive
    sfldoc21.zip   571527 98/07/25 23:28:36  ZIP archive
    

    We recommend that you unzip or gunzip/detar the archive into a subdirectory. Point your browser at the index.htm file. We use relative addressing in all HTML documents, so that links work just as well on a local hard-disk as on-line on our website. In a windowing environment is it easy and useful to create an icon that runs a Web browser on this file.


    Installation for UNIX Systems

    To install the SFL on a UNIX system you need to:

    1. Download the source archive and decompress it.
    2. Run the 'build' script to compile the SFL sources and build the libsfl.a archive file.
    3. Optionally, install the libsfl.a file in the /usr/lib directory.
    4. Optionally, install the SFL header file(s) in the /usr/include directory.

    Decompressing The Source Archive

    To unzip the source .zip file, you need the Infozip unzip tool:

    $ mkdir temp
    $ mv sflsrc21.zip temp
    $ cd temp
    $ unzip -a sflsrc21
    

    To decompress the source .tgz file you need GNU gzip/gunzip and tar:

    $ mkdir temp
    $ mv sflsrc21.tgz temp
    $ cd temp
    $ gzip -d sflsrc21.tgz
      or
    $ gunzip sflsrc21.tgz
    $ tar -xvf sflsrc21.tar
    

    You can also, in extreme cases, unzip the files on a PC and transfer the individual files to the UNIX system.

    Compiling The SFL Sources

    The SFL source archive includes a script, c, that you can (and should) use to compile the SFL sources. This script invokes the ANSI C compiler to produce an object code file. It detects the platform and invokes the compiler with the necessary switches for ANSI C compilation. On some systems this is the normal behaviour for the cc command. On other systems it is not normal. You should make the c script executable, (preferrably) install it in a shared directory like /usr/local/bin, and try it out:

    $ chmod a+rx c
    $ mv c /usr/local/bin
    $ c
    

    To compile the SFL sources, use this command:

    $ chmod +x build
    $ build
    

    If you get warnings or error messages, this is usually a bad sign. Some compilers issue warnings just because you ask for ANSI compilation. If you get any other error messages, please let us know.

    You can use individual SFL files simply by specifying them on the command line when you compile and link a program. However, this is usually a pain. Therefore, the build script creates a library file called libsfl.a. The linker can automatically search this file for the SFL functions. To install libsfl.a in the /usr/lib directory, do this:

    $ mv libsfl.a /usr/lib
    

    Using The SFL In Your Applications

    To use an SFL function in your applications you must include a header file that defines the structures, prototypes, and types for the function API. The SFL provides three types of header files:

    1. One header file per function group. These are provided for reference; you will normally not use these directly.
    2. A Universal Header File which encapsulates and replaces all local header files. Again, this is provided for reference; you do not normally use this directly.
    3. A Library Header File that contains the Universal Header File and all the SFL header files in one go. This is meant to simplify application programming and installation.

    We recommend that you install the sfl.h file in /usr/include. A typical application program starts like this:

    #include <sfl.h>
    

    To link an application program, use the c -l command. This assumes that libsfl.a is installed /usr/lib.


    Installation for Digital VMS Systems

    To install the SFL on a Digital VMS system you need to:

    1. Download the source archive and decompress it.
    2. Run the 'build.txt' command file to build the libsfl.olb library file.
    3. Optionally, install the libsfl.olb file in the SYS$LIBRARY directory.
    4. Optionally, install the SFL header file(s) in the SYS$LIBRARY directory.

    Decompressing The Source Archive

    To unzip the source .zip file, you need the Infozip unzip tool (note that you need the -a switch):

    $ create/dir [.temp]
    $ ren sflsrc21.zip [.temp]
    $ set def [.temp]
    $ unzip -a sflsrc21
    

    You can also, in extreme cases, unzip the files on a PC and transfer the individual files to the VMS system.

    Compiling The SFL Sources

    To compile the SFL sources, use this command:

    $ @build.txt
    

    If you get warnings or error messages, this is a bad sign - please let us know.

    The build.txt command file creates a library file called libsfl.olb. You can install this in a central directory like SYS$LIBRARY if you wish. You'll need system privileges to do this.

    Using The SFL In Your Applications

    To use an SFL function in your applications you must include a header file that defines the structures, prototypes, and types for the function API. The SFL provides three types of header files:

    1. One header file per function group. These are provided for reference; you will normally not use these directly.
    2. A Universal Header File which encapsulates and replaces all local header files. Again, this is provided for reference; you do not normally use this directly.
    3. A Library Header File that contains the Universal Header File and all the SFL header files in one go. This is meant to simplify application programming and installation.

    We recommend that you install the sfl.h file in SYS$LIBRARY. A typical application program starts like this:

    #include <sfl.h>
    

    Installation for Windows

    Briefly, either create a static library, and include that in your project; create a .DLL and call that, or add the files you want to use to your project and compile them as part of the application.

    With MSVC 4.0, we find it useful to create a main project for the application in hand, and a subproject for the SFL. We build the SFL as a static library. If you use MFC, you must compile everything (including MFC) in single-threaded mode, and use libd.

    Under MSVC 1.5x, there is a bug in the project manager that generates invalid make files: the SFL prelude.h file refers to various non-Windows include files, within #if statements. The MSVC 1.5x project manager includes these in the make file; you must manually remove them. One solution is to edit prelude.h; another is to use a Perl or Awk script to edit the make file each time you change the project. You could also move to a different 16-bit compiler. Finally, you can create the make files as empty files in the C include directory.


    Installation for MS-DOS

    To install the SFL on a MS-DOS system you need to:

    1. Download the source archive and decompress it.
    2. Run build.bat to build the libsfl.lib library file.
    3. Optionally, install the libsfl.lib file in central directory.
    4. Optionally, install the SFL header file(s) in a central directory.

    Decompressing The Source Archive

    To unzip the source .zip file, you need the Infozip unzip tool, or PKzip version 2.04g or later, or a compatible unzip program.:

    C:\DOWNLOAD> md temp
    C:\DOWNLOAD> copy sflsrc21.zip temp
    C:\DOWNLOAD> del sflsrc21.zip
    C:\DOWNLOAD> cd temp
    C:\DOWNLOAD> unzip sflsrc21
    

    Compiling The SFL Sources

    These build scripts are provided for MS-DOS:

    The build scripts create a library file called libsfl.lib. You can install this, and sfl.h, in a central directory if you wish.

    Using The SFL In Your Applications

    To use an SFL function in your applications you must include a header file that defines the structures, prototypes, and types for the function API. The SFL provides three types of header files:

    1. One header file per function group. These are provided for reference; you will normally not use these directly.
    2. A Universal Header File which encapsulates and replaces all local header files. Again, this is provided for reference; you do not normally use this directly.
    3. A Library Header File that contains the Universal Header File and all the SFL header files in one go. This is meant to simplify application programming and installation.

    We recommend that you install the sfl.h file in the /include directory of your compiler. A typical application program starts like this:

    #include <sfl.h>
    

    Using The SFL

     

    The Universal Header File - prelude.h

    What and Why?

    The Universal Header File a technology that we have developed to make C applications more easily portable with less effort. One of the big difficulties in compiling C code on different platforms is that header files change their names, locations, and internal functions from system to system, even on one system over time.

    Typically, you may see C programs that start with a rash of #ifdef's mixed with #include's depending on the system, compiler, and specific needs of the program.

    Since we are basically really lazy, all this unnecessary work is intolerable. We would much rather make the compiler work harder. The systems we develop on (typically MS-DOS with Turbo-C) are so fast that we can afford to take a really lazy approach.

    So, what we do is this: we include every 'useful' and 'standard' header file that we can think of. We then include every 'useful' non-portable file that we've ever needed, in a clean way, so that application code does not need to 'know' how it was done.

    At the same time we define lots of things that make life easier. Generally we don't like macros, since these create 'pseudo languages' that are just more work to learn. However, some things (like #define FOREVER for (;;)) are so useful and pretty comonplace, so we stick them in too.

    Lastly, we flatten-out the problem called 'what system am I running on', by providing a set of definitions like __UNIX__ and __UTYPE_SUNOS that code can use if it has to. Again, it can be quite messy to figure-out that we're compiling on a Brand X, so we need this-and-that header file. We hide this so that we can forget about it.

    Okay, those are the benefits of this approach. What are the costs? We typically hear these criticisms:

    We use the Universal Header File in all C projects (not just those based on the SFL). If it was not for the simple fact that it has helped us a lot, we'd probably not make it available.

    Using the Universal Header File

    You should probably read through the prelude.h file to best understand it. Our usual habit is to comment the code first, so that it's self-explanatory. The SFL documentation has a section on the Universal Header File. This section is generated from the code.

    When you use the SFL Library Header File (sfl.h), you don't need to include prelude.h, since it's already embedded in sfl.h. This makes application programming easier (just one header file to include). If you need to change prelude.h, you can either change sfl.h as well, or rebuild sfl.h using the build script. Better still, tell us what you want to change, so that we can maintain a single version of the file.  

    The Library Header File - sfl.h

    Each module in the SFL consists of a header file and one or more C source files. You can choose to include the header files that you want (this is what the SFL source code does), but this can quickly become burdensome. To simplify matters, a single header file sfl.h contains all the individual header files. It also contains the Universal Header File.

    System Notes

    MS-DOS

    Most of the SFL is portable to MS-DOS. Exceptions are: the socket i/o functions (sflsock), the user/group ID functions (sfluid) and the server process functions (sflserv). These are all null; you can call any of the functions, but they will return either an okay feedback (in most cases) or an error feedback (for the socket functions). The SFL compiles cleanly with Borland Turbo C/C++ 1.0 and Microsoft VC++ 4.0; it has not been tested with Borland C/C++.

    MS-Windows

    Most of the SFL is portable to Windows 3.x, Windows 95, and Windows NT. Exceptions are: the user/group ID functions (sfluid) and the server process functions (sflserv). These are all null; you can call any of the functions, but they will return an okay feedback. The SFL compiles cleanly with Microsoft VC++ 4.0; it has not been tested with Borland C/C++.

    Digital VAX

    The SFL is portable to Digital VMS except for the directory access functions (sfldir), user/group functions (sfluid) and the server process functions (sflserv). The sfldir functions will be implemented at a later date. The other functions are null; you can call any of the functions, but they will return an okay feedback. The SFL compiles cleanly with Vax C and Dec C and has been tested with various releases of these compilers.

    Linux

    The SFL is fully portable to Linux and has been tested with GNU C. It should give no compiler warning errors.

    Sun OS and Sun Sparc

    The SFL is fully portable to Sun OS. You may have trouble finding an ANSI C compiler, especially on Sparc systems. People sometimes install GNU C, using the Sun header files and libraries. This should work, although we have not tested it recently. Sometimes the Sun ANSI C compiler is called acc, not cc. You can use the CCNAME environment variable to point to the right compiler name. Some Sun C compilers give warnings when you use the ANSI compile mode. You can ignore these warnings.

    See also the warning about 'Other UNIX Systems'; some SunOS installations show this symptom.

    HP/UX

    The SFL is fully portable to HP/UX. It should give no compiler warning errors.

    IBM AIX

    The SFL is fully portable to IBM/AIX. It should give no compiler warning errors.

    Digital UNIX

    The SFL is fully portable to Digital UNIX. It should give no compiler warning errors. When compiling on an Alpha system, the word size is 64 bits.

    Other UNIX Systems

    The directory functions can fail on SVr4 if the <dirent.h> file does not match the C library. Recompile with CCDEFINES set to the value "-D _USE_BSD_DIRENT" and they should work a bit better. Under Solaris with GCC, you should not define this macro.

    OS/2

    The SFL was ported to OS/2 by Ewen McNiell around New Year's Eve 1996. It runs under EMX. The SFL distribution kit includes an OS/2 build script. The 'c' script runs under OS/2 as well as UNIX.

    To Do List

    Contributors and References

     

    The SFL License Agreement

    This license agreement covers your use of the iMatix STANDARD FUNCTION LIBRARY (SFL), its source code, documentation, and executable files, hereinafter referred to as "the Product".

    The Product is Copyright © 1991-98 iMatix. You may use it and distribute it according to this following License Agreement. If you do not agree with these terms, please remove the Product from your system. By incorporating the Product in your work or distributing the Product to others you implicitly agree to these license terms.

    Statement Of Copyright

    The Product is, and remains, Copyright © 1991-98 iMatix, with exception of specific copyrights as noted in the individual source files.

    Conditions Of Use

    You do not need to provide the source code for the Product as part of your product. However, you must do one of these things to comply with the Product License Agreement:

    1. Provide the source code for Product modules that you use, or
    2. Make your product freely available according to a license similar to the GNU General Public License, or the Perl Artistic License, or
    3. Add this phrase to the documentation for your product: "This product uses parts of the iMatix SFL, Copyright © 1991-98 iMatix <http://www.imatix.com>".

    Rights Of Usage

    You may freely and at no cost use the Product in any project, commercial, academic, military, or private, so long as you respect the License Agreement. The License Agreement does not affect any software except the Product. In particular, any application that uses the Product does not itself fall under the License Agreement.

    You may modify any part of the Product, including sources and documentation, except this License Agreement, which you may not modify.

    You must clearly indicate any modifications at the start of each source file. The user of any modified Product code must know that the source file is not original.

    At your discretion, you may rewrite or reuse any part of the Product so that your derived code is not obviously part of the Product. This derived code does not fall under the Product License Agreement directly, but you must include a credit at the start of each source file indicating the original authorship and source of the code, and a statement of copyright as follows:
    "Parts copyright (c) 1991-98 iMatix."

    Rights Of Distribution

    You may freely distribute the Product, or any subset of the Product, by any means. The License, in the form of the file called "LICENSE.TXT" must accompany any such distribution.

    You may charge a fee for distributing the Product, for providing a warranty on the Product, for making modifications to the Product, or for any other service provided in relation to the Product. You are not required to ask our permission for any of these activities.

    At no time will iMatix associate itself with any distribution of the Product except that supplied from the Internet site http://www.imatix.com.

    Disclaimer Of Warranty

    The Product is provided as free software, in the hope that it will be useful. It is provided "as-is", without warranty of any kind, either expressed or implied, including, but not limited to, the implied warranties of merchantability and fitness for a particular purpose. The entire risk as to the quality and performance of the Product is with you. Should the Product prove defective, the full cost of repair, servicing, or correction lies with you.

    Universal Header File for C programming

    Filename: prelude.h
    Package: Standard Function Library (SFL)
    Written: 93/03/29 iMatix SFL project team sfl@imatix.com
    Revised: 98/06/27
    Copyright: Copyright (c) 1991-98 iMatix
    Version: 1.92
    1.90 PH Released with SFL 1.90
    1.91 PH 98/04/27 Added DRDOS LFN and DJGPP support - rj
    1.92 PH 98/05/18 Added QNX support (provided by Alessandro Sala)

    Synopsis

    This header file encapsulates many generally-useful include files and defines lots of good stuff. The intention of this header file is to hide the messy #ifdef's that you typically need to make real programs compile & run. To use, specify as the first include file in your program. The main contributors to this file were:
    PH Pieter Hintjens <ph@imatix.com>
    EDM Ewen McNeill <ewen@imatix.com>
    PA Pascal Antonnaux <pascal@imatix.com>
    BW Bruce Walter <walter@fortean.com>
    RJ Rob Judd <judd@alphalink.com.au>

    List of Functions

    List of Symbol Definitions

    prelude.h defines these symbols, possibly conditionally:
    Symbol: Defined as:
    ASSERT(f) (various)
    DEBUG TRUE
    DOES_SNPRINTF (various)
    DOES_SOCKETS /* System supports BSD sockets */
    DOES_UID /* System supports uid functions */
    EXIT_FAILURE 1 /* GCC, sometimes. */
    EXIT_SUCCESS 0 /* but not defined on SunOs with */
    FALSE 0
    FOREVER for (;;) /* FOREVER { ... } */
    FORK_CHILD 0
    FORK_ERROR -1 /* Return codes from fork() */
    LINE_MAX 255 /* if not previously #define'd */
    MSDOS_FILESYSTEM (various)
    NAMEFOLD (various)
    O_BINARY 0
    O_NDELAY 0
    O_NONBLOCK (various)
    PATHEND (various)
    PATHFOLD (various)
    PATHSEP (various)
    PATH_MAX 2048 /* if not previously #define'd */
    SIGABRT 22 /* Termination by abort() */
    SIGALRM (various)
    SIGILL 4 /* Illegal instruction */
    SIGINT 2 /* Ctrl-C sequence */
    SIGSEGV 11 /* Segment violation */
    SIGTERM 15 /* Kill signal */
    TIMEZONE (various)
    TRUE 1 /* ANSI standard */
    _INCLUDE_HPUX_SOURCE TRUE
    _INCLUDE_POSIX_SOURCE TRUE
    _INCLUDE_XOPEN_SOURCE TRUE
    _PRELUDE_INCLUDED TRUE
    __IS_32BIT__ /* Else assume 32-bit OS/compiler */
    __IS_64BIT__ (various)
    __MSDOS__ (various)
    __OS2__ TRUE
    __STRICT_ANSI__ TRUE
    __UNIX__ (various)
    __UTYPE_AUX TRUE
    __UTYPE_BSDOS TRUE
    __UTYPE_DECALPHA TRUE
    __UTYPE_FREEBSD TRUE
    __UTYPE_GENERIC TRUE
    __UTYPE_HPUX TRUE
    __UTYPE_IBMAIX TRUE
    __UTYPE_IRIX TRUE
    __UTYPE_LINUX TRUE
    __UTYPE_MIPS TRUE
    __UTYPE_NETBSD TRUE
    __UTYPE_NEXT TRUE
    __UTYPE_QNX TRUE
    __UTYPE_SCO TRUE
    __UTYPE_SINIX TRUE
    __UTYPE_SUNOS TRUE
    __UTYPE_SUNSOLARIS TRUE
    __UTYPE_UNIXWARE TRUE
    __VMS_XOPEN TRUE
    __VMS__ TRUE
    __WINDOWS__ (various)
    bit_clr(x,bit) ((x) &= ~bit_msk (bit))
    bit_msk(bit) (1 << (bit))
    bit_set(x,bit) ((x) |= bit_msk (bit))
    bit_tst(x,bit) ((x) & bit_msk (bit))
    environ _environ
    local static void /* Shorthand for local functions */
    max(a,b) (((a) > (b))? (a): (b))
    memmove(d,s,l) bcopy (s,d,l)
    min(a,b) (((a) < (b))? (a): (b))
    random(num) (various)
    randomize() srand ((unsigned) time (NULL))
    sleep(a) (various)
    snprintf _snprintf
    strclr(s) (*(s) = 0)
    streq(s1,s2) (!strcmp ((s1), (s2)))
    strerror(n) sys_errlist [n]
    strlast(s) ((s) [strlen (s) - 1])
    strneq(s1,s2) (strcmp ((s1), (s2)))
    strnull(s) (*(s) == 0)
    strterm(s) ((s) [strlen (s)])
    strused(s) (*(s) != 0)
    tbllast(x) (x [tblsize (x) - 1])
    tblsize(x) (sizeof (x) / sizeof ((x) [0]))
    until(expr) while (!(expr)) /* do { ... } until (expr) */
    vsnprintf _vsnprintf

    List of Type Definitions

    Type name: Defined as:
    Bool unsigned short
    byte unsigned char
    dbyte unsigned short
    dword unsigned long
    function void (*) (void)
    gid_t int
    qbyte (various)
    uid_t int
    word unsigned short

    Define SFL version

    Filename: sflvers.h
    Package: Standard Function Library (SFL)
    Written: 96/11/21 iMatix SFL project team sfl@imatix.com
    Revised: 98/10/02
    Copyright: Copyright (c) 1991-98 iMatix

    Synopsis

    Defines the SFL_VERSION constant.

    List of Symbol Definitions

    sflvers.h defines these symbols, possibly conditionally:
    Symbol: Defined as:
    SFL_VERSION "2.01" /* Main SFL version */
    _SFLVERS_INCLUDED TRUE

    Large bitstring manipulation functions

    Filename: sflbits.h
    Package: Standard Function Library (SFL)
    Written: 96/05/14 iMatix SFL project team sfl@imatix.com
    Revised: 97/09/08
    Copyright: Copyright (c) 1991-98 iMatix

    Synopsis

    Provides operations to manipulate large bitstrings. The bitstrings are compressed. Intended for bit-based index techniques, where bitstrings can be millions of bits long. These functions are still in development; this is an early version that provides basic functionality. Simple tests on large bitmaps with random filling show a cost of about 3 bytes per bit, after compression. This includes all the indexing information.

    List of Functions

    List of Symbol Definitions

    sflbits.h defines these symbols, possibly conditionally:
    Symbol: Defined as:
    BIT_DATASIZE 500 /* Size of block data part */
    BIT_INDEXSIZE BIT_DATASIZE/2 /* Size of block index part */
    BIT_MAXBITS 16384000L /* Max. possible bit number */
    BIT_MAXBLOCKS 1024 /* Max. size of bitstring */
    BIT_SECTSIZE 8192 /* Size of one bitstring section */
    _SFLBITS_INCLUDED TRUE
     

    bits_init

    #include "sflbits.h"
    int
    bits_init (void)
    

    Synopsis

    Initialises bitstring functions. You must call this before using any other bitstring functions. Returns 0 if okay, -1 if there was an error.

    Source Code - (sflbits.c)

    {
        ASSERT (comp_zero == NULL);
    
        comp_zero = mem_alloc (BIT_SECTSIZE + 1);
        if (!comp_zero)
            return (-1);                    /*  Could not allocate new block     */
    
        memset (compressed, BIT_SECTSIZE, 0x00);
        comp_zero_size = compress bits (compressed, comp_zero, BIT_SECTSIZE);
        comp_zero      = mem_realloc (comp_zero, comp_zero_size);
    
        comp_ones = mem_alloc (BIT_SECTSIZE + 1);
        if (!comp_ones)
          {
            mem_free (comp_ones);
            return (-1);                    /*  Could not allocate new block     */
          }
        memset (compressed, BIT_SECTSIZE, 0xFF);
        comp_ones_size = compress bits (compressed, comp_ones, BIT_SECTSIZE);
        comp_ones      = mem_realloc (comp_ones, comp_ones_size);
    
        return (0);
    }
    
     

    bits_term

    #include "sflbits.h"
    int
    bits_term (void)
    

    Synopsis

    Terminates bitstring functions. You must call this when you are finished using the bitstring functions. Returns 0 if okay, -1 if there was an error.

    Source Code - (sflbits.c)

    {
        mem_free (comp_zero);
        mem_free (comp_ones);
        return (0);
    }
    
     

    bits_create

    #include "sflbits.h"
    BITS *
    bits_create (void)
    

    Synopsis

    Creates a new bitstring and initialises all bits to zero. Returns a BITS handle which you should use in all further references to the bitstring.

    Source Code - (sflbits.c)

    {
        BITS
            *bits;                          /*  Newly-created bitstring          */
        BITBLOCK
            *index;                         /*  Newly-created index block        */
    
        bits = mem_alloc (sizeof (BITS));
        if (bits)
          {
            memset (bits, 0, sizeof (BITS));
            index = mem_alloc (sizeof (BITBLOCK));
            if (index)
              {
                /*  Set all index fields to 0: bitstring is all zeroes           */
                memset (index, 0, sizeof (BITBLOCK));
                index-> left       = 0;
                index-> right      = 0;
                index-> size       = BIT_DATASIZE;
                bits-> block [0]   = index;
                bits-> block_count = 1;
                bits-> free_list   = 0;     /*  No blocks in free list           */
              }
            else
              {
                mem_free (bits);
                bits = NULL;
              }
          }
        return (bits);
    }
    
     

    bits_destroy

    #include "sflbits.h"
    void
    bits_destroy (
        BITS *bits)
    

    Synopsis

    Releases all memory used by a bitstring and deletes the bitstring. Do not refer to the bitstring after calling this function.

    Source Code - (sflbits.c)

    {
        int
            block_nbr;                      /*  Bitstring block number           */
    
        ASSERT (bits);
    
        /*  Free all blocks allocated to bitmap                                  */
        for (block_nbr = 0; block_nbr < bits-> block_count; block_nbr++)
            mem_free (bits-> block [block_nbr]);
    
        mem_free (bits);
    }
    
     

    bits_set

    #include "sflbits.h"
    int
    bits_set (
        BITS *bits,
        long bit)
    

    Synopsis

    Sets the specified bit in the bitmap. Returns ?

    Source Code - (sflbits.c)

    {
        int
            index,                          /*  Number of index block            */
            section;                        /*  Number of section in index       */
        dbyte
            bit_nbr;                        /*  Number of bit in section         */
    
        ASSERT (bits);
    
        locate_bit  (bits, bit, &index, &section, &bit_nbr);
        get_section (bits, index, section, section_data, TRUE);
        section_data [bit_nbr / 8] |= 1 << (bit_nbr % 8);
        put_section (bits, index, section, section_data);
    
        return 0;
    }
    
     

    bits_clear

    #include "sflbits.h"
    int
    bits_clear (
        BITS *bits,
        long bit)
    

    Synopsis

    Clears the specified bit in the bitmap. Returns ?

    Source Code - (sflbits.c)

    {
        int
            index,                          /*  Number of index block            */
            section;                        /*  Number of section in index       */
        dbyte
            bit_nbr;                        /*  Number of bit in section         */
    
        ASSERT (bits);
    
        locate_bit  (bits, bit, &index, &section, &bit_nbr);
        get_section (bits, index, section, section_data, TRUE);
        section_data [bit_nbr / 8] &= 255 - (1 << (bit_nbr % 8));
        put_section (bits, index, section, section_data);
    
        return 0;
    }
    
     

    bits_test

    #include "sflbits.h"
    int
    bits_test (
        const BITS *bits,
        long bit)
    

    Synopsis

    Tests the specified bit in the bitmap. Returns 1 or 0.

    Source Code - (sflbits.c)

    {
        int
            index,                          /*  Number of index block            */
            section;                        /*  Number of section in index       */
        dbyte
            bit_nbr;                        /*  Number of bit in section         */
    
        ASSERT (bits);
    
        locate_bit  (bits, bit, &index, &section, &bit_nbr);
        get_section ((BITS *) bits, index, section, section_data, FALSE);
        if ((section_data [bit_nbr / 8]) & (1 << (bit_nbr % 8)))
            return (1);
        else
            return (0);
    }
    
     

    bits_fput

    #include "sflbits.h"
    int
    bits_fput (FILE *file,
        const BITS *bits)
    

    Synopsis

    Writes the bitstring to the specified file stream. To read the bitstring, use the bits fget() function. The structure of the bitstring is:

    Source Code - (sflbits.c)

    {
        int
            block_nbr;                      /*  Bitstring block number           */
        word
            comp_size;                      /*  Size of compressed block         */
        BITBLOCK
            *block_ptr;                     /*  Points to bitstring block        */
    
        ASSERT (bits);
        ASSERT (file);
    
        /*  Write bitstring header to file                                       */
        fwrite (&bits-> block_count, sizeof (bits-> block_count), 1, file);
        fwrite (&bits-> free_list,   sizeof (bits-> free_list),   1, file);
    
        /*  Write bitstring blocks to file                                       */
        for (block_nbr = 0; block_nbr < bits-> block_count; block_nbr++)
          {
            block_ptr = bits-> block [block_nbr];
            comp_size = compress block ((byte *) block_ptr,
                                        compressed, (word) block_ptr-> size);
    
            fwrite (&comp_size, sizeof (comp_size), 1, file);
            fwrite (compressed, comp_size,          1, file);
          }
        return 0;
    }
    
     

    bits_fget

    #include "sflbits.h"
    BITS *
    bits_fget (FILE *file)
    

    Synopsis

    Reads a bitstring from the specified file stream. You must have previously written the bitstring using bit_fput (). Returns a newly-created bitmap, or NULL if there was insufficient memory.

    Source Code - (sflbits.c)

    {
        int
            block_nbr;                      /*  Bitstring block number           */
        word
            comp_size;                      /*  Size of compressed block         */
        BITBLOCK
            *block_ptr;                     /*  Points to bitstring block        */
        BITS
            *bits;
    
        ASSERT (file);
    
        bits = bits create ();              /*  Create a new, empty bitmap       */
    
        /*  Read bitstring header from file                                      */
        fread (&bits-> block_count, sizeof (bits-> block_count), 1, file);
        fread (&bits-> free_list,   sizeof (bits-> free_list),   1, file);
    
        /*  Read bitstring blocks from file                                      */
        for (block_nbr = 0; block_nbr < bits-> block_count; block_nbr++)
          {
            block_nbr = alloc_block (bits);
            if (block_nbr == 0)
              {
                bits destroy (bits);
                return (NULL);
              }
            fread (&comp_size, sizeof (comp_size), 1, file);
            fread (compressed, comp_size,          1, file);
            block_ptr        = bits-> block [block_nbr];
            block_ptr-> size = expand block (compressed, (byte *) block_ptr,
                                             comp_size);
          }
        return (bits);
    }
    

    Compression functions

    Filename: sflcomp.h
    Package: Standard Function Library (SFL)
    Written: 91/05/20 iMatix SFL project team sfl@imatix.com
    Revised: 97/09/08
    Copyright: Copyright (c) 1991-98 iMatix

    Synopsis

    Various compression/decompression functions. The LZ-type algorith (LZRW1/KH) was originally written by Kurt Haenen <ghgaea8@blekul11> and made portable by P. Hintjens. This is a reasonable LZ/RLE algorithm, very fast, but about 30% less efficient than a ZIP-type algorithm in terms of space. The RLE algorithms are better suited to compressing sparse data. The nulls variant is specifically tuned to data that consists mostly of binary zeroes. The bits variant is tuned for compressing sparse bitmaps.

    List of Functions

    List of Symbol Definitions

    sflcomp.h defines these symbols, possibly conditionally:
    Symbol: Defined as:
    _SFLCOMP_INCLUDED TRUE
     

    compress_block

    #include "sflcomp.h"
    word
    compress_block (
        const byte *src,
        byte *dst,
        word src_size)
    

    Synopsis

    Takes up to 64Kb of uncompressed data in Source, compresses it using a fast LZ/RLE algorithm and places the result in Dest. The compression technique is comparable to that used by Zip and such tools, but less agressive. It is, however, fast enough to use in realtime. Returns the size of the compressed data. To decompress the data, use the expand block() function.

    Source Code - (sflcomp.c)

    {
        static short
              Hash [4096];
        short SymbolAddress;
        word  Key;
        word  Size;
        byte  Bit = 0;
        word  Command = 0;
        word  src_index = 0;
        word  dst_size = 3;
        word  HeaderIndex = 1;
    
        dst [0] = FLAG_COMPRESS;
        for (Key = 0; Key < 4096; Key++)
            Hash [Key] = -1;
    
        while ((src_index < src_size) && (dst_size <= src_size))
          {
            if (Bit > 15)
              {
                dst [HeaderIndex]     = (byte) ((Command >> 8) & 0x00ff);
                dst [HeaderIndex + 1] = (byte) ( Command       & 0x00ff);
                HeaderIndex = dst_size;
                dst_size += 2;
                Bit = 0;
              }
            for (Size = 1;; Size++)
                if ((word) (src_index + Size) >= src_size
                || (src [src_index] != src [src_index + Size])
                || (Size >= 0x0fff))
                    break;
    
            if (Size >= 16)
              {
                dst [dst_size++] = 0;
                dst [dst_size++] = (byte) (((word) (Size - 16) >> 8) & 0x00ff);
                dst [dst_size++] = (byte) ((Size - 16) & 0x00ff);
                dst [dst_size++] = src [src_index];
                src_index += Size;
                Command = (Command << 1) + 1;
              }
            else
            if (get_match (src, src_index, src_size,
                           Hash, &Size, &SymbolAddress) != 0)
              {
                Key = ((src_index - SymbolAddress) << 4) + (Size - 3);
                dst [dst_size++] = (byte) ((Key >> 8) & 0x00ff);
                dst [dst_size++] = (byte) (Key & 0x00ff);
                src_index += Size;
                Command = (Command << 1) + 1;
              }
            else
              {
                dst [dst_size++] = src [src_index++];
                Command = (Command << 1);
              }
            Bit++;
          }
        Command <<= (16 - Bit);
        dst [HeaderIndex]     = (byte) ((Command >> 8) & 0x00ff);
        dst [HeaderIndex + 1] = (byte) ( Command       & 0x00ff);
    
         if (dst_size > src_size)
          {
             for (dst_size = 0; dst_size < src_size; dst_size++)
                 dst [dst_size + 1] = src [dst_size];
             dst [0] = FLAG_COPY;
             return (src_size + 1);
           }
         return (dst_size);
    }
    
     

    expand_block

    #include "sflcomp.h"
    word
    expand_block (
        const byte *src,
        byte *dst,
        word src_size)
    

    Synopsis

    Expands a block of data previously compressed using the compress block() function. The compressed block is passed in src; the expanded result in dst. dst must be large enough to accomodate the largest possible decompressed block. Returns the size of the uncompressed data.

    Source Code - (sflcomp.c)

    {
        word SymbolAddress;
        word ChunkSize;
        word Counter;
        word Command = 0;
        word src_index = 1;
        word dst_size = 0;
        byte Bit = 0;
    
        if (src [0] == FLAG_COPY)
          {
            for (dst_size = 1; dst_size < src_size; dst_size++)
                dst [dst_size - 1] = src [dst_size];
            return (src_size - 1);
          }
        while (src_index < src_size)
          {
            if (Bit == 0)
              {
                Command  = src [src_index++] << 8;
                Command += src [src_index++];
                Bit = 16;
              }
            if (Command & 0x8000)
              {
                SymbolAddress =  (word) (src [src_index++] << 4);
                SymbolAddress += (word) (src [src_index] >> 4);
                if (SymbolAddress)
                  {
                    ChunkSize = (word) (src [src_index++] & 0x0f) + 3;
                    SymbolAddress = dst_size - SymbolAddress;
                    for (Counter = 0; Counter < ChunkSize; Counter++)
                        dst [dst_size++] = dst [SymbolAddress++];
                  }
                else
                  {
                    ChunkSize  = (word) (src [src_index++] << 8);
                    ChunkSize += (word) (src [src_index++] + 16);
                    for (Counter = 0; Counter < ChunkSize; Counter++)
                        dst [dst_size++] = src [src_index];
                    src_index++;
                  }
              }
            else
                dst [dst_size++] = src [src_index++];
    
            Command <<= 1;
            Bit--;
          }
        return (dst_size);
    }
    
     

    compress_rle

    #include "sflcomp.h"
    word
    compress_rle (
        byte *src,
        byte *dst,
        word src_size)
    

    Synopsis

    Takes a block of uncompressed data in src, compresses it using a RLE algorithm and places the result in dst. To decompress the data, use the expand rle () function. Returns the size of the compressed data. The dst buffer should be 10% larger than the src buffer. The src buffer must be at least src_size + 1 bytes long. It may be modified. The compressed data contains these strings:
    [01-7F][data...] String of uncompressed data, 1 to 127 bytes.
    [83-FF][byte] Run of 3 to 127 identical bytes.
    [80][len][byte] Run of 128 to 255 identical bytes.
    [81][lo][hi][byte] Run of 256 to 2^16 identical bytes.
    [82][len] Run of 3 to 255 spaces.
    [00][len] Run of 3 to 255 binary zeroes.

    Source Code - (sflcomp.c)

    {
        word
            dst_size,                       /*  Size of compressed data          */
            src_scan,                       /*  Scan through source data         */
            run_end,                        /*  Points to end of run of bytes    */
            length = 0;                     /*  Size of the run or string        */
        byte
            cur_byte,                       /*  Next byte to process             */
            *header;                        /*  Header of unpacked string        */
        Bool
            have_run;                       /*  TRUE when we have a run          */
    
        src_scan = 0;                       /*  Start at beginning of source     */
        dst_size = 0;                       /*  No output yet                    */
        header   = NULL;                    /*  No open unpacked string          */
        while (src_scan < src_size)
          {
            cur_byte = src [src_scan++];
            have_run = FALSE;               /*  Unless we find a run             */
    
            /*  Three identical bytes signals the start of a run                 */
            if (cur_byte == src [src_scan]
            &&  cur_byte == src [src_scan + 1]
            && (src_scan + 1 < src_size))
              {
                /*  Stick-in a sentinel character to ensure that the run ends    */
                src [src_size] = !cur_byte;
                run_end = src_scan;         /*  src_scan <= src_size             */
                while (src [run_end] == cur_byte)
                    run_end++;
    
                have_run = TRUE;
                if (header)                 /*  If we have a previous unpacked   */
                  {                         /*    string, close it               */
                    *header = (byte) length;
                    header  = NULL;
                  }
                length = run_end - src_scan + 1;
                src_scan = run_end;
              }
            if (have_run)
              {
                /*  We compress short runs of spaces and nulls separately        */
                if (length < 256 && cur_byte == 0)
                  {
                    dst [dst_size++] = 0x00;
                    dst [dst_size++] = (byte) length;
                  }
                else
                if (length < 256 && cur_byte == ' ')
                  {
                    dst [dst_size++] = 0x82;
                    dst [dst_size++] = (byte) length;
                  }
                else
                if (length < 128)
                  {
                    dst [dst_size++] = (byte) length | 0x80;
                    dst [dst_size++] = cur_byte;
                  }
                else
                if (length < 256)           /*  Short run 128-255 bytes          */
                  {
                    dst [dst_size++] = 0x80;
                    dst [dst_size++] = (byte) length;
                    dst [dst_size++] = cur_byte;
                  }
                else                        /*  Long run 256-2^16 bytes          */
                  {
                    dst [dst_size++] = 0x81;
                    dst [dst_size++] = (byte) (length & 0xff);
                    dst [dst_size++] = (byte) (length >> 8);
                    dst [dst_size++] = cur_byte;
                  }
              }
            else
              {
                if (!header)                /*  Start new unpacked string if     */
                  {                         /*    necessary                      */
                    header = &dst [dst_size++];
                    length = 0;
                  }
                dst [dst_size++] = cur_byte;
                if (++length == 127)        /*  Each string can be up to 127     */
                  {                         /*    bytes long (high bit cleared)  */
                    *header = (byte) length;
                    header  = NULL;
                  }
              }
          }
        if (header)                         /*  If we have a previous unpacked   */
          {                                 /*    string, close it               */
            *header = (byte) length;
            header  = NULL;
          }
        return (dst_size);                  /*  Return compressed data size      */
    }
    
     

    expand_rle

    #include "sflcomp.h"
    word
    expand_rle (
        const byte *src,
        byte *dst,
        word src_size)
    

    Synopsis

    Expands a block of data previously compressed using the compress rle() function. The compressed block is passed in src; the expanded result in dst. Dst must be large enough to accomodate the largest possible decompressed block. Returns the size of the expanded data.

    Source Code - (sflcomp.c)

    {
        word
            dst_size,                       /*  Size of expanded data            */
            src_scan,                       /*  Scan through source data         */
            length;                         /*  Size of the run or string        */
        byte
            cur_byte;                       /*  Next byte to process             */
    
        src_scan = 0;
        dst_size = 0;
        while (src_scan < src_size)
          {
            cur_byte = src [src_scan++];
    
            /*  1 to 127 is uncompressed string of 1 to 127 bytes                */
            if (cur_byte > 0 && cur_byte < 128)
              {
                length = (word) cur_byte;
                memcpy (dst + dst_size, src + src_scan, length);
                src_scan += length;
                dst_size += length;
              }
            else                            /*  Run of 3 or more bytes           */
              {
                switch (cur_byte)
                  {
                    case 0x00:              /*  Run of 3-255 zeroes              */
                        length   = src [src_scan++];
                        cur_byte = 0;
                        break;
                    case 0x82:              /*  Run of 3-255 spaces              */
                        length   = src [src_scan++];
                        cur_byte = ' ';
                        break;
                    case 0x80:              /*  Short run 128-255 bytes          */
                        length   = src [src_scan++];
                        cur_byte = src [src_scan++];
                        break;
                    case 0x81:              /*  Long run 256-2^16 bytes          */
                        length   = src [src_scan++];
                        length  += src [src_scan++] << 8;
                        cur_byte = src [src_scan++];
                        break;
                    default:                /*  Run of 3 to 127 bytes            */
                        length = cur_byte & 127;
                        cur_byte = src [src_scan++];
                  }
                memset (dst + dst_size, cur_byte, length);
                dst_size += length;
              }
          }
        return (dst_size);                  /*  Return expanded data size        */
    }
    
     

    compress_nulls

    #include "sflcomp.h"
    word
    compress_nulls (
        byte *src,
        byte *dst,
        word src_size)
    

    Synopsis

    Similar to compress rle(), but optimised towards compression of binary zeroes. Use this when you are certain that the sparse areas are set to binary zeroes. You must use expand nulls () to decompress a block compressed with this function. Returns the size of the compressed data. The dst buffer should be 10% larger than the src buffer. The src buffer must be at least src_size + 1 bytes long. It may be modified. The compressed data contains these strings:
    [01-7F][data...] String of uncompressed data, 1 to 127 bytes.
    [82-FF] Run of 2 to 127 binary zeroes.
    [81][80-FF] Run of 128 to 255 binary zeroes.
    [80][lo][hi] Run of 256 to 2^16 binary zeroes.
    [00][len][byte] Run of 4 to 255 identical bytes.
    [00][00][lo][hi][byte] Run of 256 to 2^16 identical bytes.

    Source Code - (sflcomp.c)

    {
        word
            dst_size,                       /*  Size of compressed data          */
            src_scan,                       /*  Scan through source data         */
            run_end,                        /*  Points to end of run of bytes    */
            length = 0;                     /*  Size of the run or string        */
        byte
            cur_byte,                       /*  Next byte to process             */
            *header;                        /*  Header of unpacked string        */
        Bool
            have_run;                       /*  TRUE when we have a run          */
    
        src_scan = 0;                       /*  Start at beginning of source     */
        dst_size = 0;                       /*  No output yet                    */
        header   = NULL;                    /*  No open unpacked string          */
        while (src_scan < src_size)
          {
            cur_byte = src [src_scan++];
            have_run = FALSE;               /*  Unless we find a run             */
    
            /*  Two identical bytes may signal the start of a run                */
            if (cur_byte == src [src_scan]
            &&  src_scan < src_size)
              {
                /*  Stick-in a sentinel character to ensure that the run ends    */
                src [src_size] = !cur_byte;
                run_end = src_scan;         /*  src_scan <= src_size             */
                while (src [run_end] == cur_byte)
                    run_end++;
    
                /*  A run is 4+ identical bytes or 2+ nulls                      */
                if ((run_end - src_scan > 2) || cur_byte == 0)
                  {
                    have_run = TRUE;
                    if (header)             /*  If we have a previous unpacked   */
                      {                     /*    string, close it               */
                        *header = (byte) length;
                        header  = NULL;
                      }
                    length = run_end - src_scan + 1;
                    src_scan = run_end;
                  }
              }
            if (have_run)
              {
                if (cur_byte == 0)
                  {
                    if (length < 128)       /*  2-127 binary zeroes              */
                        dst [dst_size++] = (byte) (length | 0x80);
                    else
                    if (length < 256)       /*  128-256 binary zeroes            */
                      {
                        dst [dst_size++] = 0x81;
                        dst [dst_size++] = (byte) length;
                      }
                    else                    /*  256-2^15 binary zeroes           */
                      {
                        dst [dst_size++] = 0x80;
                        dst [dst_size++] = (byte) (length & 0xff);
                        dst [dst_size++] = (byte) (length >> 8);
                      }
                  }
                else
                if (length < 256)           /*  Short run 4-255 bytes            */
                  {
                    dst [dst_size++] = 0x00;
                    dst [dst_size++] = (byte) length;
                    dst [dst_size++] = cur_byte;
                  }
                else                        /*  Long run 256-2^16 bytes          */
                  {
                    dst [dst_size++] = 0x00;
                    dst [dst_size++] = 0x00;
                    dst [dst_size++] = (byte) (length & 0xff);
                    dst [dst_size++] = (byte) (length >> 8);
                    dst [dst_size++] = cur_byte;
                  }
              }
            else
              {
                if (!header)                /*  Start new unpacked string if     */
                  {                         /*    necessary                      */
                    header = &dst [dst_size++];
                    length = 0;
                  }
                dst [dst_size++] = cur_byte;
                if (++length == 127)        /*  Each string can be up to 127     */
                  {                         /*    bytes long (high bit cleared)  */
                    *header = (byte) length;
                    header  = NULL;
                  }
              }
          }
        if (header)                         /*  If we have a previous unpacked   */
          {                                 /*    string, close it               */
            *header = (byte) length;
            header  = NULL;
          }
        return (dst_size);                  /*  Return compressed data size      */
    }
    
     

    expand_nulls

    #include "sflcomp.h"
    word
    expand_nulls (
        const byte *src,
        byte *dst,
        word src_size)
    

    Synopsis

    Expands a block of data previously compressed using the compress nulls() function. The compressed block is passed in src; the expanded result in dst. Dst must be large enough to accomodate the largest possible decompressed block. Returns the size of the expanded data.

    Source Code - (sflcomp.c)

    {
        word
            dst_size,                       /*  Size of expanded data            */
            src_scan,                       /*  Scan through source data         */
            length;                         /*  Size of the run or string        */
        byte
            cur_byte;                       /*  Next byte to process             */
    
        src_scan = 0;
        dst_size = 0;
        while (src_scan < src_size)
          {
            cur_byte = src [src_scan++];
    
            /*  1 to 127 is uncompressed string of 1 to 127 bytes                */
            if (cur_byte > 0 && cur_byte < 128)
              {
                length = (word) cur_byte;
                memcpy (dst + dst_size, src + src_scan, length);
                src_scan += length;
                dst_size += length;
              }
            else                            /*  Run of 2 or more bytes           */
              {
                switch (cur_byte)
                  {
                    case 0x00:              /*  Run of non-zero bytes            */
                        length = src [src_scan++];
                        if (length == 0)    /*  Stored as double-byte            */
                          {
                            length   = src [src_scan++];
                            length  += src [src_scan++] << 8;
                          }
                        cur_byte = src [src_scan++];
                        break;
                    case 0x80:              /*  256-2^16 zeroes                  */
                        length   = src [src_scan++];
                        length  += src [src_scan++] << 8;
                        cur_byte = 0;
                        break;
                    case 0x81:              /*  128 to 255 zeroes                */
                        length   = src [src_scan++];
                        cur_byte = 0;
                        break;
                    default:                /*  2 to 127 zeroes                  */
                        length   = cur_byte & 127;
                        cur_byte = 0;
                  }
                memset (dst + dst_size, cur_byte, length);
                dst_size += length;
              }
          }
        return (dst_size);                  /*  Return expanded data size        */
    }
    
     

    compress_bits

    #include "sflcomp.h"
    word
    compress_bits (
        byte *src,
        byte *dst,
        word src_size)
    

    Synopsis

    Similar to compress rle(), but optimised towards compression of sparse bitmaps. Use this when you are playing with large, sparse bitmaps. You must use expand bits () to decompress a block compressed with this function. Returns the size of the compressed data. The dst buffer should be 10% larger than the src buffer for worst cases. The src buffer must be at least src_size + 1 bytes long. It may be modified. The compressed data contains these strings:
    [00-07] Single byte containing a bit in position 0 to 7.
    [08-7F][data...] String of uncompressed data, 1 to 120 bytes.
    [82-FF] Run of 1 to 126 binary zeroes.
    [81][00-FD] Run of 127 to 380 binary zeroes.
    [81][FE][len][byte] Run of 4 to 255 identical bytes.
    [81][FF][lo][hi][byte] Run of 256 to 2^16 identical bytes.
    [80][lo][hi] Run of 381 to 2^16 binary zeroes.

    Source Code - (sflcomp.c)

    {
        word
            dst_size,                       /*  Size of compressed data          */
            src_scan,                       /*  Scan through source data         */
            run_end,                        /*  Points to end of run of bytes    */
            length = 0;                     /*  Size of the run or string        */
        byte
            cur_byte,                       /*  Next byte to process             */
            *header;                        /*  Header of unpacked string        */
        static byte
            single_bits [256];              /*  Bytes with one bit set           */
        static Bool
            initialised = FALSE;            /*  First time flag                  */
    
        /*  The single_bits table provides a fast lookup for bytes with          */
        /*  one bit set.  The 'interesting' bytes are non-zero in the table      */
        /*  where their value is the output code value (0-7) + 1.                */
        if (!initialised)                   /*  First time?  Initialise          */
          {
            memset (single_bits, 0, 256);
            single_bits [1]   = 1;
            single_bits [2]   = 2;
            single_bits [4]   = 3;
            single_bits [8]   = 4;
            single_bits [16]  = 5;
            single_bits [32]  = 6;
            single_bits [64]  = 7;
            single_bits [128] = 8;
          }
    
        src_scan = 0;                       /*  Start at beginning of source     */
        dst_size = 0;                       /*  No output yet                    */
        header   = NULL;                    /*  No open unpacked string          */
        while (src_scan < src_size)
          {
            cur_byte = src [src_scan++];
    
            /*- Look for 1 or more binary zeroes, and compress into a run -------*/
    
            if (cur_byte == 0)
              {
                src [src_size] = 0xff;      /*  Stop with a sentinel             */
                run_end = src_scan;         /*  src_scan <= src_size             */
                while (src [run_end] == 0)
                    run_end++;
    
                if (header)                 /*  If we have a previous unpacked   */
                  {                         /*    string, close it               */
                    *header = (byte) length + 7;
                    header  = NULL;
                  }
                length = run_end - src_scan + 1;
                src_scan = run_end;
                if (length < 127)           /*  1-126 binary zeroes              */
                    dst [dst_size++] = (byte) (++length | 0x80);
                else
                if (length < 381)           /*  127-380 binary zeroes            */
                  {
                    dst [dst_size++] = 0x81;
                    dst [dst_size++] = (byte) length - 127;
                  }
                else                        /*  381-2^16 binary zeroes           */
                  {
                    dst [dst_size++] = 0x80;
                    dst [dst_size++] = (byte) (length & 0xff);
                    dst [dst_size++] = (byte) (length >> 8);
                  }
              }
            else
    
            /*- Next, look for bytes with 1 bit set; we encode these as 1 byte --*/
    
            if (single_bits [cur_byte])     /*  Single bit value?                */
              {
                dst [dst_size++] = single_bits [cur_byte] - 1;
                if (header)                 /*  If we have a previous unpacked   */
                  {                         /*    string, close it               */
                    *header = (byte) length + 7;
                    header  = NULL;
                  }
              }
            else
    
            /*- Next, look for a run of 4 or more identical (non-zero) bytes ----*/
    
            if (cur_byte == src [src_scan]
            &&  cur_byte == src [src_scan + 1]
            &&  cur_byte == src [src_scan + 2]
            && (src_scan < src_size - 2))
              {
                src [src_size] = !cur_byte; /*  Stick in a sentinel byte         */
                run_end = src_scan;         /*  src_scan <= src_size             */
                while (src [run_end] == cur_byte)
                    run_end++;
    
                if (header)                 /*  If we have a previous unpacked   */
                  {                         /*    string, close it               */
                    *header = (byte) length + 7;
                    header  = NULL;
                  }
                length = run_end - src_scan + 1;
                src_scan = run_end;
    
                if (length < 256)           /*  Short run 4-255 bytes            */
                  {
                    dst [dst_size++] = 0x81;
                    dst [dst_size++] = 0xFE;
                    dst [dst_size++] = (byte) length;
                    dst [dst_size++] = cur_byte;
                  }
                else                        /*  Long run 256-2^16 bytes          */
                  {
                    dst [dst_size++] = 0x81;
                    dst [dst_size++] = 0xFF;
                    dst [dst_size++] = (byte) (length & 0xff);
                    dst [dst_size++] = (byte) (length >> 8);
                    dst [dst_size++] = cur_byte;
                  }
              }
            else
    
            /*- Lastly, compress unpackable strings into chunks of 120 bytes ----*/
    
              {
                if (!header)                /*  Start new unpacked string if     */
                  {                         /*    necessary                      */
                    header = &dst [dst_size++];
                    length = 0;
                  }
                dst [dst_size++] = cur_byte;
                if (++length == 120)        /*  Each string can be up to 120     */
                  {                         /*    bytes long (high bit cleared)  */
                    *header = (byte) length + 7;
                    header  = NULL;
                  }
              }
          }
        if (header)                         /*  If we have a previous unpacked   */
          {                                 /*    string, close it               */
            *header = (byte) length + 7;
            header  = NULL;
          }
        return (dst_size);                  /*  Return compressed data size      */
    }
    
     

    expand_bits

    #include "sflcomp.h"
    word
    expand_bits (
        const byte *src,
        byte *dst,
        word src_size)
    

    Synopsis

    Expands a block of data previously compressed using the compress bits() function. The compressed block is passed in src; the expanded result in dst. Dst must be large enough to accomodate the largest possible decompressed block. Returns the size of the expanded data.

    Source Code - (sflcomp.c)

    {
        word
            dst_size,                       /*  Size of expanded data            */
            src_scan,                       /*  Scan through source data         */
            length;                         /*  Size of the run or string        */
        byte
            cur_byte;                       /*  Next byte to process             */
    
        src_scan = 0;
        dst_size = 0;
        while (src_scan < src_size)
          {
            cur_byte = src [src_scan++];
    
            if (cur_byte < 8)               /*  Single bit in position 0 to 7    */
                dst [dst_size++] = 1 << cur_byte;
            else
            if (cur_byte < 128)             /*  String of 1 to 120 bytes         */
              {
                length = (word) cur_byte - 7;
                memcpy (dst + dst_size, src + src_scan, length);
                src_scan += length;
                dst_size += length;
              }
            else                            /*  Run of 1 or more bytes           */
              {
                switch (cur_byte)
                  {
                    case 0x80:              /*  381-2^16 binary zeroes           */
                        length   = src [src_scan++];
                        length  += src [src_scan++] << 8;
                        cur_byte = 0;
                        break;
                    case 0x81:
                        length = src [src_scan++];
                        if (length == 0xFE) /*  4-255 non-zero bytes             */
                          {
                            length   = src [src_scan++];
                            cur_byte = src [src_scan++];
                          }
                        else
                        if (length == 0xFF) /*  Run of 256-2^15 non-zero bytes   */
                          {
                            length   = src [src_scan++];
                            length  += src [src_scan++] << 8;
                            cur_byte = src [src_scan++];
                          }
                        else
                          {
                            length  += 127;
                            cur_byte = 0;   /*  127 to 380 zeroes                */
                          }
                        break;
                    default:                /*  1 to 126 zeroes                  */
                        length   = (cur_byte - 1) & 127;
                        cur_byte = 0;
                  }
                memset (dst + dst_size, cur_byte, length);
                dst_size += length;
              }
          }
        return (dst_size);                  /*  Return expanded data size        */
    }
    

    Console output functions

    Filename: sflcons.h
    Package: Standard Function Library (SFL)
    Written: 97/05/22 iMatix SFL project team sfl@imatix.com
    Revised: 98/02/08
    Copyright: Copyright (c) 1991-98 iMatix

    Synopsis

    Provides redirectable console output: use the coprintf() and coputs() calls instead of printf() and puts() in a real-time application. Then, you can call console send() to send all console output to a specified function. This is a useful way to get output into -- for example -- a GUI window.

    List of Functions

    List of Symbol Definitions

    sflcons.h defines these symbols, possibly conditionally:
    Symbol: Defined as:
    _SFLCONS_INCLUDED TRUE

    List of Type Definitions

    Type name: Defined as:
    CONSOLE_FCT void () (const char *)
     

    console_send

    #include "sflcons.h"
    void
    console_send (CONSOLE_FCT *new_console_fct, Bool echo)
    

    Synopsis

    Redirects console output to a specified CONSOLE_FCT function. If the specified address is NULL, redirects back to the stdout stream. This is independent of any console capturing in progress. If the echo argument is TRUE, console output is also sent to stdout.

    Source Code - (sflcons.c)

    {
        console_fct  = new_console_fct;
        console_echo = echo;                /*  Copy to stdout                   */
    }
    
     

    console_enable

    #include "sflcons.h"
    void
    console_enable (void)
    

    Synopsis

    Enables console output. Use together with console disable() to stop and start console output.

    Source Code - (sflcons.c)

    {
        console_active = TRUE;
    }
    
     

    console_disable

    #include "sflcons.h"
    void
    console_disable (void)
    

    Synopsis

    Disables console output. Use together with console enable() to stop and start console output.

    Source Code - (sflcons.c)

    {
        console_active = FALSE;
    }
    
     

    console_set_mode

    #include "sflcons.h"
    void
    console_set_mode (int mode)
    

    Synopsis

    Sets console display mode; the argument can be one of:
    CONSOLE PLAIN Output text exactly as specified
    CONSOLE DATETIME Prefix text by "yy/mm/dd hh:mm:ss "
    CONSOLE TIME Prefix text by "hh:mm:ss "
    The default is plain output.

    Source Code - (sflcons.c)

    {
        ASSERT (mode == CONSOLE_PLAIN
             || mode == CONSOLE_DATETIME
             || mode == CONSOLE_TIME);
    
        console_mode = mode;
    }
    
     

    console_capture

    #include "sflcons.h"
    int
    console_capture (const char *filename, char mode)
    

    Synopsis

    Starts capturing console output to the specified file. If the mode is 'w', creates an empty capture file. If the mode is 'a', appends to any existing data. Returns 0 if okay, -1 if there was an error - in this case you can test the value of errno. If the filename is NULL or an empty string, closes any current capture file.

    Source Code - (sflcons.c)

    {
        if (console_file)
          {
            file close (console_file);
            console_file = NULL;
          }
        if (filename && *filename)
          {
            ASSERT (mode == 'w' || mode == 'a');
            console_file = file open (filename, mode);
            if (console_file == NULL)
                return (-1);
          }
        return (0);
    }
    
     

    coprintf

    #include "sflcons.h"
    int
    coprintf (const char *format, ...)
    

    Synopsis

    As printf() but sends output to the current console. This is by default the stdout device, unless you used console send() to direct console output to some function. A newline is added automatically.

    Source Code - (sflcons.c)

    {
        static char
            formatted [LINE_MAX];
        va_list
            argptr;                         /*  Argument list pointer            */
        int
            fmtsize = 0;                    /*  Size of formatted line           */
        char
            *prefixed = NULL;               /*  Prefixed formatted line          */
    
        if (console_active)
          {
            va_start (argptr, format);      /*  Start variable args processing   */
    #if (defined (DOES_SNPRINTF))
            fmtsize = vsnprintf (formatted, LINE_MAX, format, argptr);
    #else
            fmtsize = vsprintf  (formatted, format, argptr);
    #endif
            va_end (argptr);                /*  End variable args processing     */
            ASSERT (fmtsize < LINE_MAX);
    
            switch (console_mode)
              {
                case CONSOLE_DATETIME:
                    prefixed = xstrcpy (NULL, date_str (), " ", time_str (), ": ",
                                        formatted, NULL);
                    break;
                case CONSOLE_TIME:
                    prefixed = xstrcpy (NULL, time_str (), ": ", formatted, NULL);
                    break;
              }
            if (console_file)
              {
                file write (console_file, prefixed? prefixed: formatted);
                fflush (console_file);
              }
            if (console_fct)
                (console_fct) (prefixed? prefixed: formatted);
    
            if (console_echo)
              {
                fprintf (stdout, prefixed? prefixed: formatted);
                fprintf (stdout, "\n");
                fflush  (stdout);
              }
            if (prefixed)
              {
                fmtsize = strlen (prefixed);
                mem_free (prefixed);
              }
          }
        return (fmtsize);
    }
    
     

    coputs

    #include "sflcons.h"
    int
    coputs (const char *string)
    

    Synopsis

    As puts() but sends output to the current console. This is by default the stdout device, unless you used console send() to direct console output to some function.

    Source Code - (sflcons.c)

    {
        coprintf (string);
        return (1);
    }
    
     

    coputc

    #include "sflcons.h"
    int
    coputc (int character)
    

    Synopsis

    As putc() but sends output to the current console. This is by default the stdout device, unless you used console send() to direct console output to some function.

    Source Code - (sflcons.c)

    {
        char
            buffer [2];
    
        if (console_active)
          {
            if (console_file)
              {
                putc (character, console_file);
                fflush (console_file);
              }
            if (console_fct)
              {
                buffer [0] = (char) character;
                buffer [1] = '\0';
                (console_fct) (buffer);
              }
            if (console_echo)
              {
                putc (character, stdout);
                fflush  (stdout);
              }
          }
        return (character);
    }
    

    Conversion functions

    Filename: sflconv.h
    Package: Standard Function Library (SFL)
    Written: 95/12/17 iMatix SFL project team sfl@imatix.com
    Revised: 97/09/08
    Copyright: Copyright (c) 1991-98 iMatix

    Synopsis

    These functions provide conversion between a set of datatypes (dates, times, numbers, Booleans) and external strings that represent the values. The objective is to format datatypes for display or printing, and to validate and convert strings supplied by the user. Conversion is controlled by a set of options specific to each datatype. Additionally, dates and times may be formatted using picture strings. The functions were written for use in an interactive 'forms' environment.

    List of Functions

    List of Symbol Definitions

    sflconv.h defines these symbols, possibly conditionally:
    Symbol: Defined as:
    BOOL_1_0 4
    BOOL_TRUE_FALSE 2
    BOOL_T_F 3
    BOOL_YES_NO 0 /* Boolean field formatting */
    BOOL_Y_N 1
    CONV_ERR_BAD_MONTH 8 /* Unknown month name */
    CONV_ERR_DATE_OVERFLOW 5 /* Result too large for output */
    CONV_ERR_DATE_SIZE 6 /* Too few or too many digits */
    CONV_ERR_DECS_HIDDEN 18 /* Decimals not allowed if hidden */
    CONV_ERR_DECS_MISSING 11 /* Not enough decimals supplied */
    CONV_ERR_DECS_OVERFLOW 19 /* Too many decimal positions */
    CONV_ERR_DECS_REJECTED 17 /* Decimals not allowed if integer */
    CONV_ERR_INVALID_INPUT 1 /* Unrecognised char in input */
    CONV_ERR_MULTIPLE_AM 4 /* More than one 'am' or 'pm' */
    CONV_ERR_MULTIPLE_DELIM 7 /* Too many delimiters */
    CONV_ERR_MULTIPLE_MONTH 10 /* More than one month name */
    CONV_ERR_MULTIPLE_POINT 16 /* More than one decimal point */
    CONV_ERR_MULTIPLE_SIGN 13 /* More than one sign character */
    CONV_ERR_NOT_BOOLEAN 3 /* Not a yes/no or true/false value */
    CONV_ERR_NUM_OVERFLOW 12 /* Result too large for output */
    CONV_ERR_OUT_OF_RANGE 2 /* Value out of valid range */
    CONV_ERR_REJECT_3_5 9 /* 3/5 digits in a row not allowed */
    CONV_ERR_SIGN_BAD_FIN 15 /* Malformed financial negative */
    CONV_ERR_SIGN_REJECTED 14 /* Sign not allowed if unsigned */
    CONV_ERR_TOO_MANY_DIGITS 20 /* Too many digits for number */
    CONV_MAX_DECS 100 /* Up to 100 dec