/*
 * Library to support cross-platform C system functions
 *
 * Copyright (C) 2008-2015, Joachim Metz <joachim.metz@gmail.com>
 *
 * Refer to AUTHORS for acknowledgements.
 *
 * This software is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This software 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 Lesser General Public License
 * along with this software.  If not, see <http://www.gnu.org/licenses/>.
 */

#if !defined( _LIBCSYSTEM_H )
#define _LIBCSYSTEM_H

#include <libcsystem/codepage.h>
#include <libcsystem/definitions.h>
#include <libcsystem/error.h>
#include <libcsystem/extern.h>
#include <libcsystem/features.h>
#include <libcsystem/types.h>

/* unistd.h is included here to export getopt, optarg, optind and optopt
 */
#if defined( HAVE_UNISTD_H )
#include <unistd.h>
#endif

#if defined( __cplusplus )
extern "C" {
#endif

/* -------------------------------------------------------------------------
 * Support functions
 * ------------------------------------------------------------------------- */

/* Returns the library version as a string
 */
LIBCSYSTEM_EXTERN \
const char *libcsystem_get_version(
             void );

LIBCSYSTEM_EXTERN \
int libcsystem_file_exists(
     const char *filename,
     libcsystem_error_t **error );

#if defined( LIBCSYSTEM_HAVE_WIDE_CHARACTER_TYPE )

LIBCSYSTEM_EXTERN \
int libcsystem_file_exists_wide(
     const wchar_t *filename,
     libcsystem_error_t **error );

#endif /* defined( LIBCSYSTEM_HAVE_WIDE_CHARACTER_TYPE ) */

/* -------------------------------------------------------------------------
 * Error functions
 * ------------------------------------------------------------------------- */

/* Frees an error
 */
LIBCSYSTEM_EXTERN \
void libcsystem_error_free(
      libcsystem_error_t **error );

/* Prints a descriptive string of the error to the stream
 * Returns the number of printed characters if successful or -1 on error
 */
LIBCSYSTEM_EXTERN \
int libcsystem_error_fprint(
     libcsystem_error_t *error,
     FILE *stream );

/* Prints a descriptive string of the error to the string
 * Returns the number of printed characters if successful or -1 on error
 */
LIBCSYSTEM_EXTERN \
int libcsystem_error_sprint(
     libcsystem_error_t *error,
     char *string,
     size_t size );

/* Prints a backtrace of the error to the stream
 * Returns the number of printed characters if successful or -1 on error
 */
LIBCSYSTEM_EXTERN \
int libcsystem_error_backtrace_fprint(
     libcsystem_error_t *error,
     FILE *stream );

/* Prints a backtrace of the error to the string
 * Returns the number of printed characters if successful or -1 on error
 */
LIBCSYSTEM_EXTERN \
int libcsystem_error_backtrace_sprint(
     libcsystem_error_t *error,
     char *string,
     size_t size );

/* -------------------------------------------------------------------------
 * Support functions
 * ------------------------------------------------------------------------- */

/* Initializes the system values
 * Returns 1 if successful or -1 on error
 */
LIBCSYSTEM_EXTERN \
int libcsystem_initialize(
     int stdio_mode,
     libcsystem_error_t **error );

/* -------------------------------------------------------------------------
 * File IO functions
 * ------------------------------------------------------------------------- */

#if defined( WINAPI ) && !defined( __CYGWIN__ )
#define libcsystem_file_io_close( file_descriptor ) \
        _close( file_descriptor )

#elif defined( HAVE_CLOSE )
#define libcsystem_file_io_close( file_descriptor ) \
        close( file_descriptor )
#endif

/* -------------------------------------------------------------------------
 * Getopt functions
 * ------------------------------------------------------------------------- */

#if defined( HAVE_GETOPT )
#define libcsystem_getopt( argument_count, argument_values, options_string ) \
        getopt( argument_count, argument_values, options_string )

#elif defined( LIBCSYSTEM_HAVE_WIDE_CHARACTER_TYPE )

/* The current option argument
 */
LIBCSYSTEM_EXTERN \
wchar_t *optarg;

/* The option index
 * Start with argument 1 (argument 0 is the program name)
 */
LIBCSYSTEM_EXTERN \
int optind;

/* Value to indicate the current option
 */
LIBCSYSTEM_EXTERN \
wint_t optopt;

/* Get the program options
 * Function for platforms that do not have the getopt function
 * Returns the option character processed, or -1 on error,
 * ? if the option was not in the options string, : if the option argument was missing
 */
LIBCSYSTEM_EXTERN \
wint_t libcsystem_getopt(
        int argument_count,
        wchar_t * const argument_values[],
        const wchar_t *options_string );

#else

/* The current option argument
 */
LIBCSYSTEM_EXTERN \
char *optarg;

/* The option index
 * Start with argument 1 (argument 0 is the program name)
 */
LIBCSYSTEM_EXTERN \
int optind;

/* Value to indicate the current option
 */
LIBCSYSTEM_EXTERN \
int optopt;

/* Get the program options
 * Function for platforms that do not have the getopt function
 * Returns the option character processed, or -1 on error,
 * ? if the option was not in the options string, : if the option argument was missing
 */
LIBCSYSTEM_EXTERN \
int libcsystem_getopt(
     int argument_count,
     char * const argument_values[],
     const char *options_string );

#endif /* defined( HAVE_GETOPT ) */

/* -------------------------------------------------------------------------
 * Glob functions
 * ------------------------------------------------------------------------- */

#if !defined( HAVE_GLOB_H )

/* Creates a glob
 * Make sure the value glob is referencing, is set to NULL
 * Returns 1 if successful or -1 on error
 */
LIBCSYSTEM_EXTERN \
int libcsystem_glob_initialize(
     libcsystem_glob_t **glob,
     libcsystem_error_t **error );

/* Frees a glob
 * Returns 1 if successful or -1 on error
 */
LIBCSYSTEM_EXTERN \
int libcsystem_glob_free(
     libcsystem_glob_t **glob,
     libcsystem_error_t **error );

/* Resolves filenames with wildcards (globs)
 * Returns 1 if successful or -1 on error
 */
#if defined( WINAPI ) && ( defined( _UNICODE ) || defined( UNICODE ) )
LIBCSYSTEM_EXTERN \
int libcsystem_glob_resolve(
     libcsystem_glob_t *glob,
     wchar_t * const patterns[],
     int number_of_patterns,
     libcsystem_error_t **error );
#else
LIBCSYSTEM_EXTERN \
int libcsystem_glob_resolve(
     libcsystem_glob_t *glob,
     char * const patterns[],
     int number_of_patterns,
     libcsystem_error_t **error );
#endif /* defined( WINAPI ) && ( defined( _UNICODE ) || defined( UNICODE ) ) */

/* Retrieves the glob results
 * Returns 1 if successful or -1 on error
 */
#if defined( WINAPI ) && ( defined( _UNICODE ) || defined( UNICODE ) )
LIBCSYSTEM_EXTERN \
int libcsystem_glob_get_results(
     libcsystem_glob_t *glob,
     int *number_of_results,
     wchar_t ***results,
     libcsystem_error_t **error );
#else
LIBCSYSTEM_EXTERN \
int libcsystem_glob_get_results(
     libcsystem_glob_t *glob,
     int *number_of_results,
     char ***results,
     libcsystem_error_t **error );
#endif /* defined( WINAPI ) && ( defined( _UNICODE ) || defined( UNICODE ) ) */

#endif /* !defined( HAVE_GLOB_H ) */

/* -------------------------------------------------------------------------
 * Internationalization (i18n) functions
 * ------------------------------------------------------------------------- */

/* TODO for now do nothing i18n-like
#define	_( string ) \
	gettext( string )
*/

#define	_( string ) \
	string

/* -------------------------------------------------------------------------
 * Signal functions
 * ------------------------------------------------------------------------- */

/* Attaches a signal handler for Ctrl+C or Ctrl+Break signals
 * Returns 1 if successful or -1 on error
 */
LIBCSYSTEM_EXTERN \
int libcsystem_signal_attach(
     void (*signal_handler)( libcsystem_signal_t ),
     libcsystem_error_t **error );

/* Detaches a signal handler for Ctrl+C or Ctrl+Break signals
 * Returns 1 if successful or -1 on error
 */
LIBCSYSTEM_EXTERN \
int libcsystem_signal_detach(
     libcsystem_error_t **error );

#if defined( __cplusplus )
}
#endif

#endif

