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 = ®istrar_##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