/*                                             -*- mode:C++; fill-column:100 -*-
  SFBPrintf.h - Crappy cheapo knockoff printf-like routines
  Copyright (C) 2009 The Regents of the University of New Mexico
 
  This library 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 2.1 of the License, or (at your option) any later version.

  This library 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
  Lesser General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this library; if not, write to the Free Software
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
  USA

  $Id$
 */

/**
  \file SFBPrintf.h Support for simple packet-customized printf- and scanf-like functions.
  \author David H. Ackley.  
  \date (C) 2009 All rights reserved.
  \lgpl
 */
#ifndef SFBPRINTF_H
#define SFBPRINTF_H

#include "SFBTypes.h"
#include <stdarg.h>

enum LoggingLevels { 
  LOGLEVEL_NONE,  ///< When passed to #setLogLevel(int), suppress all logging output
  LOGLEVEL_QUIET, ///< When passed to #setLogLevel(int), allow less than normal logging output
  LOGLEVEL_NORMAL, ///< When passed to #setLogLevel(int), allow normal logging output
  LOGLEVEL_VERBOSE, ///< When passed to #setLogLevel(int), allow more than normal logging output
  LOGLEVEL_DEBUG    ///< When passed to #setLogLevel(int), allow all logging output
};
/**
   Set the logging level to \a n.  Larger values produce more output, smaller values produce less.
   Initial value is #LOGLEVEL_NORMAL.

   \param n Logging level.  Can be any int, but only the values #LOGLEVEL_NONE, #LOGLEVEL_QUIET,
                            #LOGLEVEL_NORMAL, #LOGLEVEL_VERBOSE, #LOGLEVEL_DEBUG really make much sense.
 */
extern void setLogLevel(int n) ;

/**
   Return the current logging level.  See #setLogLevel(int) for details.
 */
extern int getLogLevel() ;

/** Set the log face.  Using this function, logging messages can be directed to any (physical or
    virtual) face.  Default value: #ALL_FACES
*/
extern void setLogFace(u8 face) ;

/**
   Return the current log face.  See #setLogFace(u8) for details.
*/
extern u8 getLogFace() ;

/**
 Convenience shorthand for printing to all available physical faces.  Equivalent to
 #facePrintf(ALL_FACES, format, ...), which see for details of the possible format codes.
 */
extern void pprintf(const char * format, ...) ;

extern void facePrintf(u8 face, const char * format, ...) ;
extern void vfacePrintf(u8 face, const char * format, va_list & ap) ;

/**
 Formatted reading from a packet into individual variables.  Scanning starts at the \e current
 #packetCursor() of \a packet, \e not necessarily at the beginning, and the #packetCursor() of \a
 packet is advanced as scanning proceeds.

 \param packet The packet that is to be scanned.  

 \param format a null-terminated string controlling what is to be printed; see below.

 \param ... a variable sequence of pointer arguments of sufficient number and appropriate types
            through which to store values for all the "% codes" in \a format that require arguments.

 With the exceptions of \%s, \%f, and \%p, which are not supported, #packetScanf supports the same format
 codes as #facePrintf prints, which see for further description of the format conversions.  Note
 that the pointed-to variables must be appropriate (sizes at least) for the converted type!  For
 example,
 \code
  void MyBHandler(u8 * packet) {
    u32 fourBytes; u16 twoBytes; u8 oneByte;
    if (packetScanf(packet,"b%c%d%h",&oneByte,&fourBytes,&twoBytes) != 4) 
       return;
    ..
  }
 \endcode
 is correct since the sizes of the \c oneByte, \c fourBytes, and \c twoBytes variables match the
 specified sizes of \%c, \%d, and \%h, respectively.

 Since 0.9.9, there is some support for field widths, limited to the \%b, \%o, \%d, \%x, and \%t
 conversions only.  

 packetScanf returns the number of successful matches it made, where a 'match' counts as either a
 successful '\% conversion' \e or a successful match of a \e single literal byte of the format
 string.  E.g., given a packet containing "fg123h", \c packetScanf(packet,"fg%dh",&u32var) will
 return 4 -- one for the 'f', one for the 'g', one for the '\%d', and one for the 'h'.  (But watch
 out!  Given the same packet, \c packetScanf(packet,"fg%dh\n",&u32var) will return 5 -- including
 one for the successful matching of the end-of-packet!)

 XXX Still need formatting details; examples.

 \since 0.9.9 for field widths
 
 */
extern u32 packetScanf(u8 * packet, const char * format, ...) ;

extern u32 vPacketScanf(u8 * packet, const char * format, va_list & ap) ;

extern void vfaceLogf(int includeTimestamp, int level, u8 face, const char * format, va_list & ap) ;

/* The 'log*' functions output a timestamp first */
extern void logf(int level, const char * format, ...) ;  

/**
   If #getLogLevel() is at least #LOGLEVEL_NORMAL, print "Ln " plus a timestamp, plus as directed by
   \a format, to the current #getLogFace().  Otherwise do nothing.
*/
extern void logNormal(const char * format, ...) ;

/**
   If #getLogLevel() is at least #LOGLEVEL_VERBOSE, print "Lv " plus a timestamp, plus as directed by
   \a format, to the current #getLogFace().  Otherwise do nothing.
*/
extern void logVerbose(const char * format, ...) ;

/**
   If #getLogLevel() is at least #LOGLEVEL_DEBUG, print "Ld " plus a timestamp, plus as directed by
   \a format, to the current #getLogFace().  Otherwise do nothing.
*/
extern void logDebug(const char * format, ...) ;

/**
   If #getLogLevel() is at least #LOGLEVEL_QUIET, print "Lq " plus a timestamp, plus as directed by
   \a format, to the current #getLogFace().  Otherwise do nothing.
*/
extern void logQuiet(const char * format, ...) ;

/* The 'msg*' functions print only what you say */
extern void msgf(int level, const char * format, ...) ;

/**
   If #getLogLevel() is at least #LOGLEVEL_NORMAL, print "Lq " plus as directed by \a format, to the
   current #getLogFace().  Otherwise do nothing.
*/
extern void msgNormal(const char * format, ...) ;
/**
   If #getLogLevel() is at least #LOGLEVEL_VERBOSE, print "Lv " plus as directed by \a format, to the
   current #getLogFace().  Otherwise do nothing.
*/
extern void msgVerbose(const char * format, ...) ;
/**
   If #getLogLevel() is at least #LOGLEVEL_DEBUG, print "Ld " plus as directed by \a format, to the
   current #getLogFace().  Otherwise do nothing.
*/
extern void msgDebug(const char * format, ...) ;
/**
   If #getLogLevel() is at least #LOGLEVEL_QUIET, print "Lq " plus as directed by \a format, to the
   current #getLogFace().  Otherwise do nothing.
*/
extern void msgQuiet(const char * format, ...) ;

/**
   The declaration of a function that can perform custom formatting during a printf(-family)
   formatting operation.  A CustomPrintfHandler is established during any given printf call by using
   the %Z code and passing an argument of type CustomPrintfHandler.  Once established, that
   CustomPrintfHandler is invoked via the %z code and passing an argument of type void*, which will
   become the \a arg parameter to the CustomPrintfHandler function.  When the CustomPrintfHandler is
   invoked, it prints whatever it likes to \a face, either respecting, or not, the \a width, \a
   zerofill, and \a alt arguments, as it chooses.  

   Additional usage notes:
   - The %Z code may be used multiple times in a single printf call, in which case the most-recent
     %Z invocation determines what CustomPrintfHandler is called.
   - It is an error if a %z code is invoked without a prior %Z code, or if the argument to the most
     recent prior %Z is null, and the code will die blinking #E_API_NULL_HANDLER.
   - An established CustomPrintfHandler association is local to the current printf invocation,
     lasting until the next %Z code or to the end of the current format string is reached, whichever
     comes first.
   - It \b is possible to call a printf(-family) function recursively from inside a
     CustomPrintfHandler function.  Such a recursive call will have no CustomPrintfHandler
     established within it unless and until its format specifies one via its own %Z code.

   See also ::CustomPacketScanfHandler.

   \since 0.9.15

 */
typedef void (*CustomPrintfHandler)(u8 face, void * arg, bool alt, int width, bool zerofill);

/**
   The declaration of a function that can perform custom input scanning during a
   packetScanf(-family) reading operation.  A CustomPacketScanfHandler is established during any
   given packetScanf call by using the %Z code and passing an argument of type
   CustomPacketScanfHandler.  Once established, that CustomPacketScanfHandler is invoked via the %z
   code and passing an argument of type void*, which will become the \a arg parameter to the
   CustomPacketScanfHandler function.  When the CustomPacketScanfHandler is invoked, it reads from
   the supplied \a packet however it wishes to, either respecting, or not, the \a width and \a alt
   arguments, as it chooses.

   If the return value from a CustomPacketScanfHandler is \c true, that means a successful %z scan
   and store was performed, and the total matches returned by the packetScanf should be increased by
   1, and the packet scanning should continue.  If the return value is \c false, that means a
   scanning error occurred during the %z processing, and the packetScanf should be stopped at this
   point.

   The %Z code may be used multiple times in a single packetScanf call, and the most-recent %Z
   invocation determines what CustomPacketScanfHandler is called for any given %z.  It is an error
   if a %z code is invoked without a prior %Z code, or if the argument to the most recent prior %Z
   is null, and the code will die blinking #E_API_NULL_HANDLER.

   See also ::CustomPrintfHandler.

   \since 0.9.15

 */
typedef bool (*CustomPacketScanfHandler)(u8 * packet, void * arg, bool alt, int width);

#endif /* SFBPRINTF_H */
