00001 /** @file tcl/conversions.cc tcl conversion functions for basic types */ 00002 00003 /////////////////////////////////////////////////////////////////////// 00004 // 00005 // Copyright (c) 2001-2004 California Institute of Technology 00006 // Copyright (c) 2004-2007 University of Southern California 00007 // Rob Peters <rjpeters at usc dot edu> 00008 // 00009 // created: Wed Jul 11 08:58:53 2001 00010 // commit: $Id: conversions.cc 11876 2009-10-22 15:53:06Z icore $ 00011 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/tcl/conversions.cc $ 00012 // 00013 // -------------------------------------------------------------------- 00014 // 00015 // This file is part of GroovX 00016 // [http://ilab.usc.edu/rjpeters/groovx/] 00017 // 00018 // GroovX is free software; you can redistribute it and/or modify it 00019 // under the terms of the GNU General Public License as published by 00020 // the Free Software Foundation; either version 2 of the License, or 00021 // (at your option) any later version. 00022 // 00023 // GroovX is distributed in the hope that it will be useful, but 00024 // WITHOUT ANY WARRANTY; without even the implied warranty of 00025 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00026 // General Public License for more details. 00027 // 00028 // You should have received a copy of the GNU General Public License 00029 // along with GroovX; if not, write to the Free Software Foundation, 00030 // Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. 00031 // 00032 /////////////////////////////////////////////////////////////////////// 00033 00034 #ifndef GROOVX_TCL_CONVERSIONS_CC_UTC20050628162420_DEFINED 00035 #define GROOVX_TCL_CONVERSIONS_CC_UTC20050628162420_DEFINED 00036 00037 #include "tcl/conversions.h" 00038 00039 #include "rutz/error.h" 00040 #include "rutz/fstring.h" 00041 #include "rutz/sfmt.h" 00042 #include "rutz/value.h" 00043 00044 #include <limits> 00045 #include <tcl.h> 00046 00047 #include "rutz/trace.h" 00048 #include "rutz/debug.h" 00049 GVX_DBG_REGISTER 00050 00051 using rutz::fstring; 00052 00053 /////////////////////////////////////////////////////////////////////// 00054 // 00055 // File scope functions 00056 // 00057 /////////////////////////////////////////////////////////////////////// 00058 00059 namespace 00060 { 00061 class safe_unshared_obj 00062 { 00063 private: 00064 Tcl_Obj* m_obj; 00065 bool m_is_owning; 00066 00067 safe_unshared_obj(const safe_unshared_obj&); 00068 safe_unshared_obj& operator=(const safe_unshared_obj&); 00069 00070 public: 00071 safe_unshared_obj(Tcl_Obj* obj, const Tcl_ObjType* target_type) : 00072 m_obj(obj), m_is_owning(false) 00073 { 00074 if ( (m_obj->typePtr != target_type) && Tcl_IsShared(m_obj) ) 00075 { 00076 m_is_owning = true; 00077 m_obj = Tcl_DuplicateObj(m_obj); 00078 Tcl_IncrRefCount(m_obj); 00079 } 00080 } 00081 00082 Tcl_Obj* get() const { return m_obj; } 00083 00084 ~safe_unshared_obj() 00085 { 00086 if (m_is_owning) 00087 Tcl_DecrRefCount(m_obj); 00088 } 00089 }; 00090 } 00091 00092 /////////////////////////////////////////////////////////////////////// 00093 // 00094 // (Tcl --> C++) aux_convert_to specializations 00095 // 00096 /////////////////////////////////////////////////////////////////////// 00097 00098 int tcl::aux_convert_to(Tcl_Obj* obj, int*) 00099 { 00100 GVX_TRACE("tcl::aux_convert_to(int*)"); 00101 00102 int val; 00103 00104 static const Tcl_ObjType* const int_type = Tcl_GetObjType("int"); 00105 00106 GVX_ASSERT(int_type != 0); 00107 00108 safe_unshared_obj safeobj(obj, int_type); 00109 00110 if ( Tcl_GetIntFromObj(0, safeobj.get(), &val) != TCL_OK ) 00111 { 00112 throw rutz::error(rutz::sfmt("expected integer but got \"%s\"", 00113 Tcl_GetString(obj)), SRC_POS); 00114 } 00115 00116 return val; 00117 } 00118 00119 unsigned int tcl::aux_convert_to(Tcl_Obj* obj, unsigned int*) 00120 { 00121 GVX_TRACE("tcl::aux_convert_to(unsigned int*)"); 00122 00123 int sval = aux_convert_to(obj, static_cast<int*>(0)); 00124 00125 if (sval < 0) 00126 { 00127 throw rutz::error(rutz::sfmt("expected integer but got \"%s\" " 00128 "(value was negative)", 00129 Tcl_GetString(obj)), SRC_POS); 00130 } 00131 00132 return static_cast<unsigned int>(sval); 00133 } 00134 00135 long tcl::aux_convert_to(Tcl_Obj* obj, long*) 00136 { 00137 GVX_TRACE("tcl::aux_convert_to(long*)"); 00138 00139 Tcl_WideInt wideval; 00140 00141 static const Tcl_ObjType* const wide_int_type = Tcl_GetObjType("wideInt"); 00142 00143 GVX_ASSERT(wide_int_type != 0); 00144 00145 safe_unshared_obj safeobj(obj, wide_int_type); 00146 00147 const long longmax = std::numeric_limits<long>::max(); 00148 const long longmin = std::numeric_limits<long>::min(); 00149 00150 if ( Tcl_GetWideIntFromObj(0, safeobj.get(), &wideval) != TCL_OK ) 00151 { 00152 throw rutz::error(rutz::sfmt("expected long value but got \"%s\"", 00153 Tcl_GetString(obj)), SRC_POS); 00154 } 00155 else if (wideval > static_cast<Tcl_WideInt>(longmax)) 00156 { 00157 throw rutz::error(rutz::sfmt("expected long value but got \"%s\" " 00158 "(value too large, max is %ld)", 00159 Tcl_GetString(obj), 00160 longmax), SRC_POS); 00161 } 00162 else if (wideval < static_cast<Tcl_WideInt>(longmin)) 00163 { 00164 throw rutz::error(rutz::sfmt("expected long value but got \"%s\" " 00165 "(value too small, min is %ld)", 00166 Tcl_GetString(obj), 00167 longmin), SRC_POS); 00168 } 00169 00170 return static_cast<long>(wideval); 00171 } 00172 00173 unsigned long tcl::aux_convert_to(Tcl_Obj* obj, unsigned long*) 00174 { 00175 GVX_TRACE("tcl::aux_convert_to(unsigned long*)"); 00176 00177 Tcl_WideInt wideval; 00178 00179 static const Tcl_ObjType* const wide_int_type = Tcl_GetObjType("int"); /// wideInt?? 00180 00181 GVX_ASSERT(wide_int_type != 0); 00182 00183 safe_unshared_obj safeobj(obj, wide_int_type); 00184 00185 const unsigned long ulongmax = std::numeric_limits<unsigned long>::max(); 00186 00187 if ( Tcl_GetWideIntFromObj(0, safeobj.get(), &wideval) != TCL_OK ) 00188 { 00189 throw rutz::error(rutz::sfmt("expected unsigned long value " 00190 "but got \"%s\"", Tcl_GetString(obj)), 00191 SRC_POS); 00192 } 00193 else if (wideval < 0) 00194 { 00195 throw rutz::error(rutz::sfmt("expected unsigned long value " 00196 "but got \"%s\" (value was negative)", 00197 Tcl_GetString(obj)), SRC_POS); 00198 } 00199 // OK, now we know our wideval is non-negative, so we can safely 00200 // cast it to an unsigned type (Tcl_WideUInt) for comparison against 00201 // ulongmax (note: don't try to do this comparison by casting 00202 // ulongmax to a signed type like Tcl_WideInt, since the result of 00203 // the cast will be a negative number, leading to a bogus 00204 // comparison) 00205 else if (static_cast<Tcl_WideUInt>(wideval) > ulongmax) 00206 { 00207 throw rutz::error(rutz::sfmt("expected unsigned long value " 00208 "but got \"%s\" " 00209 "(value too large, max is %lu)", 00210 Tcl_GetString(obj), ulongmax), 00211 SRC_POS); 00212 } 00213 00214 return static_cast<unsigned long>(wideval); 00215 } 00216 00217 long long tcl::aux_convert_to(Tcl_Obj* obj, long long*) 00218 { 00219 GVX_TRACE("tcl::aux_convert_to(long long*)"); 00220 00221 static const Tcl_ObjType* const wide_int_type = Tcl_GetObjType("wideInt"); 00222 00223 GVX_ASSERT(wide_int_type != 0); 00224 00225 safe_unshared_obj safeobj(obj, wide_int_type); 00226 00227 long long wideval; 00228 00229 if ( Tcl_GetWideIntFromObj(0, safeobj.get(), &wideval) != TCL_OK ) 00230 { 00231 throw rutz::error(rutz::sfmt("expected long value but got \"%s\"", 00232 Tcl_GetString(obj)), SRC_POS); 00233 } 00234 00235 return wideval; 00236 } 00237 00238 bool tcl::aux_convert_to(Tcl_Obj* obj, bool*) 00239 { 00240 GVX_TRACE("tcl::aux_convert_to(bool*)"); 00241 00242 int int_val; 00243 00244 static const Tcl_ObjType* const boolean_type = Tcl_GetObjType("boolean"); 00245 00246 GVX_ASSERT(boolean_type != 0); 00247 00248 safe_unshared_obj safeobj(obj, boolean_type); 00249 00250 if ( Tcl_GetBooleanFromObj(0, safeobj.get(), &int_val) != TCL_OK ) 00251 { 00252 throw rutz::error(rutz::sfmt("expected boolean value but got \"%s\"", 00253 Tcl_GetString(obj)), SRC_POS); 00254 } 00255 return bool(int_val); 00256 } 00257 00258 double tcl::aux_convert_to(Tcl_Obj* obj, double*) 00259 { 00260 GVX_TRACE("tcl::aux_convert_to(double*)"); 00261 00262 double val; 00263 00264 static const Tcl_ObjType* const double_type = Tcl_GetObjType("double"); 00265 00266 GVX_ASSERT(double_type != 0); 00267 00268 safe_unshared_obj safeobj(obj, double_type); 00269 00270 if ( Tcl_GetDoubleFromObj(0, safeobj.get(), &val) != TCL_OK ) 00271 { 00272 throw rutz::error(rutz::sfmt("expected floating-point number " 00273 "but got \"%s\"", 00274 Tcl_GetString(obj)), SRC_POS); 00275 } 00276 return val; 00277 } 00278 00279 float tcl::aux_convert_to(Tcl_Obj* obj, float*) 00280 { 00281 GVX_TRACE("tcl::aux_convert_to(float*)"); 00282 00283 return float(aux_convert_to(obj, static_cast<double*>(0))); 00284 } 00285 00286 const char* tcl::aux_convert_to(Tcl_Obj* obj, const char**) 00287 { 00288 GVX_TRACE("tcl::aux_convert_to(const char**)"); 00289 00290 return Tcl_GetString(obj); 00291 } 00292 00293 fstring tcl::aux_convert_to(Tcl_Obj* obj, fstring*) 00294 { 00295 GVX_TRACE("tcl::aux_convert_to(fstring*)"); 00296 00297 int length; 00298 00299 char* text = Tcl_GetStringFromObj(obj, &length); 00300 00301 GVX_ASSERT(length >= 0); 00302 00303 return fstring(rutz::char_range(text, static_cast<unsigned int>(length))); 00304 } 00305 00306 00307 /////////////////////////////////////////////////////////////////////// 00308 // 00309 // (C++ --> Tcl) aux_convert_from specializations 00310 // 00311 /////////////////////////////////////////////////////////////////////// 00312 00313 tcl::obj tcl::aux_convert_from(long long val) 00314 { 00315 GVX_TRACE("tcl::aux_convert_from(long long)"); 00316 00317 return Tcl_NewWideIntObj(val); 00318 } 00319 00320 tcl::obj tcl::aux_convert_from(long val) 00321 { 00322 GVX_TRACE("tcl::aux_convert_from(long)"); 00323 00324 return Tcl_NewLongObj(val); 00325 } 00326 00327 tcl::obj tcl::aux_convert_from(unsigned long val) 00328 { 00329 GVX_TRACE("tcl::aux_convert_from(unsigned long)"); 00330 00331 long sval(val); 00332 00333 if (sval < 0) 00334 throw rutz::error("signed/unsigned conversion failed", SRC_POS); 00335 00336 return Tcl_NewLongObj(sval); 00337 } 00338 00339 tcl::obj tcl::aux_convert_from(int val) 00340 { 00341 GVX_TRACE("tcl::aux_convert_from(int)"); 00342 00343 return Tcl_NewIntObj(val); 00344 } 00345 00346 tcl::obj tcl::aux_convert_from(unsigned int val) 00347 { 00348 GVX_TRACE("tcl::aux_convert_from(unsigned int)"); 00349 00350 int sval(val); 00351 00352 if (sval < 0) 00353 throw rutz::error("signed/unsigned conversion failed", SRC_POS); 00354 00355 return Tcl_NewIntObj(sval); 00356 } 00357 00358 tcl::obj tcl::aux_convert_from(unsigned char val) 00359 { 00360 GVX_TRACE("tcl::aux_convert_from(unsigne char)"); 00361 00362 return Tcl_NewIntObj(val); 00363 } 00364 00365 tcl::obj tcl::aux_convert_from(bool val) 00366 { 00367 GVX_TRACE("tcl::aux_convert_from(bool)"); 00368 00369 return Tcl_NewBooleanObj(val); 00370 } 00371 00372 tcl::obj tcl::aux_convert_from(double val) 00373 { 00374 GVX_TRACE("tcl::aux_convert_from(double)"); 00375 00376 return Tcl_NewDoubleObj(val); 00377 } 00378 00379 tcl::obj tcl::aux_convert_from(float val) 00380 { 00381 GVX_TRACE("tcl::aux_convert_from(float)"); 00382 00383 return Tcl_NewDoubleObj(val); 00384 } 00385 00386 tcl::obj tcl::aux_convert_from(const char* val) 00387 { 00388 GVX_TRACE("tcl::aux_convert_from(const char*)"); 00389 00390 return Tcl_NewStringObj(val, -1); 00391 } 00392 00393 tcl::obj tcl::aux_convert_from(const fstring& val) 00394 { 00395 GVX_TRACE("tcl::aux_convert_from(const fstring&)"); 00396 00397 return Tcl_NewStringObj(val.c_str(), val.length()); 00398 } 00399 00400 tcl::obj tcl::aux_convert_from(const rutz::value& val) 00401 { 00402 GVX_TRACE("tcl::aux_convert_from(const rutz::value&)"); 00403 00404 return Tcl_NewStringObj(val.get_string().c_str(), -1); 00405 } 00406 00407 static const char __attribute__((used)) vcid_groovx_tcl_conversions_cc_utc20050628162420[] = "$Id: conversions.cc 11876 2009-10-22 15:53:06Z icore $ $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/tcl/conversions.cc $"; 00408 #endif // !GROOVX_TCL_CONVERSIONS_CC_UTC20050628162420_DEFINED