• Main Page
  • Related Pages
  • Namespaces
  • Data Structures
  • Files
  • File List
  • Globals

epics/apps/crucible/stream/src/StreamFormatConverter.h (r4864/r2310)

Go to the documentation of this file.
00001 /***************************************************************
00002 * StreamDevice Support                                         *
00003 *                                                              *
00004 * (C) 2005 Dirk Zimoch (dirk.zimoch@psi.ch)                    *
00005 *                                                              *
00006 * This is the format converter header of StreamDevice.         *
00007 * Please refer to the HTML files in ../doc/ for a detailed     *
00008 * documentation.                                               *
00009 *                                                              *
00010 * If you do any changes in this file, you are not allowed to   *
00011 * redistribute it any more. If there is a bug or a missing     *
00012 * feature, send me an email and/or your patch. If I accept     *
00013 * your changes, they will go to the next release.              *
00014 *                                                              *
00015 * DISCLAIMER: If this software breaks something or harms       *
00016 * someone, it's your problem.                                  *
00017 *                                                              *
00018 ***************************************************************/
00019 
00020 #ifndef StreamFormatConverter_h
00021 #define StreamFormatConverter_h
00022 
00023 #include "StreamFormat.h"
00024 #include "StreamBuffer.h"
00025 #include "StreamProtocol.h"
00026 
00027 #define esc (0x1b)
00028 
00029 template <class C>
00030 class StreamFormatConverterRegistrar
00031 {
00032 public:
00033     StreamFormatConverterRegistrar(const char* name, const char* provided) {
00034         static C prototype;
00035         prototype.provides(name, provided);
00036     }
00037 };
00038 
00039 class StreamFormatConverter
00040 {
00041     static StreamFormatConverter* registered [];
00042     const char* _name;
00043 public:
00044     virtual ~StreamFormatConverter();
00045     static int parseFormat(const char*& source, FormatType, StreamFormat&, StreamBuffer& infoString);
00046     const char* name() { return _name; }
00047     void provides(const char* name, const char* provided);
00048     static StreamFormatConverter* find(unsigned char c);
00049     virtual int parse(const StreamFormat& fmt,
00050         StreamBuffer& info, const char*& source, bool scanFormat) = 0;
00051     virtual bool printLong(const StreamFormat& fmt,
00052         StreamBuffer& output, long value);
00053     virtual bool printDouble(const StreamFormat& fmt,
00054         StreamBuffer& output, double value);
00055     virtual bool printString(const StreamFormat& fmt,
00056         StreamBuffer& output, const char* value);
00057     virtual bool printPseudo(const StreamFormat& fmt,
00058         StreamBuffer& output);
00059     virtual int scanLong(const StreamFormat& fmt,
00060         const char* input, long& value);
00061     virtual int scanDouble(const StreamFormat& fmt,
00062         const char* input, double& value);
00063     virtual int scanString(const StreamFormat& fmt,
00064         const char* input, char* value, size_t maxlen);
00065     virtual int scanPseudo(const StreamFormat& fmt,
00066         StreamBuffer& inputLine, long& cursor);
00067 };
00068 
00069 inline StreamFormatConverter* StreamFormatConverter::
00070 find(unsigned char c) {
00071     return registered[c];
00072 }
00073 
00074 #define RegisterConverter(converter, conversions) \
00075 template class StreamFormatConverterRegistrar<converter>; \
00076 StreamFormatConverterRegistrar<converter> \
00077 registrar_##converter(#converter,conversions); \
00078 void* ref_##converter = &registrar_##converter\
00079 
00080 /****************************************************************************
00081 * A user defined converter class inherits public from StreamFormatConverter
00082 * and handles one or more conversion characters.
00083 * Print and scan of the same conversion character must be handled by the
00084 * same class but not both need to be supported.
00085 *
00086 * parse()
00087 * =======
00088 * This function is called when the protocol is parsed (at initialisation)
00089 * whenever one of the conversions handled by your converter is found.
00090 * The fields fmt.conv, fmt.flags, fmt.prec, and fmt.width have
00091 * already been filled in. If a scan format is parsed, scanFormat is true. If
00092 * a print format is parsed, scanFormat is false.
00093 *
00094 * The source pointer points to the character of the format string just after
00095 * the conversion character. You can parse additional characters if they
00096 * belong to the format string handled by your class. Move the source pointer
00097 * so that is points to the first character after the format string.
00098 *
00099 * Example:
00100 *
00101 *   source  source
00102 *   before  after
00103 *       V   V
00104 *  "%39[1-9]constant text"
00105 *      |
00106 *   conversion
00107 *   character
00108 *
00109 * You can write any string to info you need in print*() or scan*(). This will
00110 * probably be necessary if you have taken characters from the format string.
00111 *
00112 * Return long_format, double_format, string_format, or enum_format
00113 * depending on the datatype associated with the conversion character.
00114 * You need not to return the same value for print and for scan formats.
00115 * You can even return different values depending on the format string, but
00116 * I can't imagine why anyone should do that.
00117 *
00118 * If the format is not a real data conversion but does other things with
00119 * the data (append or check a checksum, encode or decode the data,...),
00120 * return pseudo_format.
00121 *
00122 * Return false if there is any parse error or if print or scan is requested
00123 * but not supported by this conversion.
00124 *
00125 * print[Long|Double|String|Pseudo](), scan[Long|Double|String|Pseudo]()
00126 * =================
00127 * Provide a print*() and/or scan*() method appropriate for the data type
00128 * you have returned in the parse() method. That method is called whenever
00129 * the conversion appears in an output or input, resp.
00130 * You only need to implement the flavour of print and/or scan suitable for
00131 * the datatype returned by parse().
00132 *
00133 * Now, fmt.type contains the value returned by parse(). With fmt.info()
00134 * you will get the string you have written to info in parse() (null terminated).
00135 * The length of the info string can be found in fmt.infolen.
00136 *
00137 * In print*(), append the converted value to output. Do not modify what is
00138 * already in output (unless you really know what you're doing).
00139 * Return true on success, false on failure.
00140 *
00141 * In scan*(), read the value from input and return the number of consumed
00142 * bytes. In the string version, don't write more bytes than maxlen! If the
00143 * skip_flag is set, you don't need to write to value, since the value will be
00144 * discarded anyway. Return -1 on failure.
00145 *
00146 *
00147 * Register your class
00148 * ===================
00149 * To register your class, write
00150 *
00151 * RegisterConverter (your_class, "conversions");
00152 *
00153 * in the global context of your file.
00154 * "conversions" is a string containing all conversion characters
00155 * handled by your class.
00156 *
00157 * For examples see StreamFormatConverter.cc.
00158 *
00159 * HINT: Do not branch depending on the conversion character.
00160 *       Provide multiple classes, that's more efficient.
00161 *
00162 ****************************************************************************/
00163 
00164 #endif

Generated on Tue Dec 10 2013 04:52:22 for ROCsoft by  doxygen 1.7.1