/* * $Id$ */ /* * Harbour Project source code: * uHTTPD (Micro HTTP server) cgi functions * * Copyright 2009 Francesco Saverio Giudice * www - http://harbour-project.org * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This program 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 General Public License * along with this software; see the file COPYING. If not, write to * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, * Boston, MA 02111-1307 USA (or visit the web site http://www.gnu.org/). * * As a special exception, the Harbour Project gives permission for * additional uses of the text contained in its release of Harbour. * * The exception is that, if you link the Harbour libraries with other * files to produce an executable, this does not by itself cause the * resulting executable to be covered by the GNU General Public License. * Your use of that executable is in no way restricted on account of * linking the Harbour library code into it. * * This exception does not however invalidate any other reasons why * the executable file might be covered by the GNU General Public License. * * This exception applies only to the code released by the Harbour * Project under the name Harbour. If you copy code from other * Harbour Project or Free Software Foundation releases into a copy of * Harbour, as the General Public License permits, the exception does * not apply to the code that you add in this way. To avoid misleading * anyone as to the status of such modified files, you must delete * this exception notice from them. * * If you write modifications of your own for Harbour, it is your choice * whether to permit this exception to apply to your modifications. * If you do not wish that, delete this exception notice. * */ #include "error.ch" #include "fileio.ch" //#define HB_USE_HBTIP // Use functions from HBTIP - TOIMPLEMENT #define CRLF ( Chr( 13 ) + Chr( 10 ) ) #xtranslate THROW( ) => ( Eval( ErrorBlock(), ), Break( ) ) #define HB_IHASH() HB_HSETCASEMATCH( {=>}, .F. ) MEMVAR _SERVER, _GET, _POST, _COOKIE, _REQUEST, _HTTP_REQUEST FUNCTION uhttpd_GetVars( cFields, cSeparator ) LOCAL hHashVars := { => } LOCAL aField, cField, aFields LOCAL cName, xValue __defaultNIL( @cSeparator, "&" ) aFields := uhttpd_Split( cSeparator, cFields ) FOR EACH cField in aFields aField := uhttpd_Split( "=", cField, 1 ) IF Len( aField ) == 1 hHashVars[ aField[ 1 ] ] := NIL LOOP ELSEIF Len( aField ) != 2 LOOP ENDIF cName := LTrim( aField[ 1 ] ) xValue := uhttpd_UrlDecode( aField[ 2 ] ) // Is it an array entry? IF Substr( cName, Len( cName ) - 1 ) == "[]" cName := Substr( cName, 1, Len( cName ) - 2 ) hHashVars[ cName ] := { xValue } ELSE // now check if variable already exists. If yes and I have already another element // with same name, then I will change it to an array IF ( hb_HPos( hHashVars, cName ) ) > 0 IF !HB_ISARRAY( hHashVars[ cName ] ) // Transform it to array hHashVars[ cName ] := { hHashVars[ cName ] } ENDIF aAdd( hHashVars[ cName ], xValue ) ELSE hHashVars[ cName ] := xValue ENDIF ENDIF NEXT RETURN hHashVars /* uhttpd_SplitUrl( cUrl ) --> hUrl (C) 2006 Francesco Saverio Giudice Splits a valid URL into simple components and return them in a hash it works like parse_url() PHP function a URL string is something like this: http://[username:password@]hostname[:port][/path[/file[.ext]][?arg1=[value][&arg2=[value]]][#anchor]] Parameters: cUrl - Valid URL string Returns: hUrl - Hash containing these keys: SCHEME - protocol name HOST - hostname PORT - protocol port number USER - username PASS - password PATH - path to directory and/or file QUERY - part after question mark ? FRAGMENT - part after hashmark # */ FUNCTION uhttpd_SplitUrl( cUrl ) LOCAL hUrl := { => } LOCAL nPos, cTemp, cUserNamePassword, cHostnamePort LOCAL cProto, cHost, cPort, nPort, cUser, cPass, cPath, cQuery, cFragment LOCAL cUri // Prevents case matching hb_HSetCaseMatch( hUrl, .F. ) cTemp := cUrl cUri := "" // Starting with // http://[username:password@]hostname[:port][/path[/file[.ext]][?arg1=[value][&arg2=[value]]][#anchor]] // Read protocol nPos := At( "://", cTemp ) IF nPos > 0 cProto := Left( cTemp, nPos - 1 ) // delete protocol from temp string cTemp := SubStr( cTemp, nPos + 3 ) ELSE cProto := "" ENDIF cUri += cProto + iif( !Empty( cProto ), "://", "" ) // Now we have: // [username:password@]hostname[:port][/path[/file[.ext]][?arg1=[value][&arg2=[value]]][#anchor]] // Read username and password nPos := At( "@", cTemp ) IF nPos > 0 cUserNamePassword := Left( cTemp, nPos - 1 ) // delete Username and Password from temp string cTemp := SubStr( cTemp, nPos + 1 ) // Split username and password nPos := At( ":", cUserNamePassword ) IF nPos > 0 cUser := Left( cUserNamePassword, nPos - 1 ) cPass := SubStr( cUserNamePassword, nPos + 1 ) ELSE cUser := cUserNamePassword cPass := "" ENDIF ELSE cUser := "" cPass := "" ENDIF // Now we have: // hostname[:port][/path[/file[.ext]][?arg1=[value][&arg2=[value]]][#anchor]] // Search for anchor using # char from right nPos := RAt( "#", cTemp ) IF nPos > 0 cFragment := SubStr( cTemp, nPos + 1 ) // delete anchor from temp string cTemp := SubStr( cTemp, 1, nPos - 1 ) ELSE cFragment := "" ENDIF // Now we have: // hostname[:port][/path[/file[.ext]][?arg1=[value][&arg2=[value]]]] // Search for Query part using ? char from right nPos := RAt( "?", cTemp ) IF nPos > 0 cQuery := SubStr( cTemp, nPos + 1 ) // delete query from temp string cTemp := SubStr( cTemp, 1, nPos - 1 ) ELSE cQuery := "" ENDIF // Now we have: // hostname[:port][/path[/file[.ext]] cUri += cTemp // Search for Path part using / char from right nPos := RAt( "/", cTemp ) IF nPos > 0 cPath := SubStr( cTemp, nPos ) // delete path from temp string cTemp := SubStr( cTemp, 1, nPos - 1 ) ELSE cPath := "/" ENDIF // Now we have: // hostname[:port] cHostnamePort := cTemp // Searching port number nPos := At( ":", cHostnamePort ) IF nPos > 0 cHost := Left( cHostnamePort, nPos - 1 ) cPort := SubStr( cHostnamePort, nPos + 1 ) nPort := Val( cPort ) IF nPort <= 0 nPort := -1 ENDIF ELSE cHost := cHostnamePort nPort := -1 ENDIF // Assemble hash hb_hSet( hUrl, "SCHEME" , cProto ) hb_hSet( hUrl, "HOST" , cHost ) hb_hSet( hUrl, "PORT" , nPort ) hb_hSet( hUrl, "USER" , cUser ) hb_hSet( hUrl, "PASS" , cPass ) hb_hSet( hUrl, "PATH" , cPath ) hb_hSet( hUrl, "QUERY" , cQuery ) hb_hSet( hUrl, "FRAGMENT", cFragment ) hb_hSet( hUrl, "URI" , cURI ) // Prevents externals to add something else to this Hash hb_HSetAutoAdd( hUrl, .F. ) RETURN hUrl /* uhttpd_SplitString( cString ) --> aLines (C) 2006 Francesco Saverio Giudice Splits a string into simple components and return them in an array Parameters: cString - Initial string cDelim - Delimiter - default CRLF lRemDelim - Remove delimiter from return values - default .T. Returns: aLines - Array with lines / fields for each element Sample: SplitString( "this=is=a=line=with=equals", "=" ) -> { "this", "is", "a", "line", "with", "equals" } */ FUNCTION uhttpd_SplitString( cString, cDelim, lRemDelim, nCount ) LOCAL nEOLPos LOCAL cBuffer := cString LOCAL aLines := {}, cLine LOCAL nHowMany := 0 __defaultNIL( @cDelim, ( CHR( 13 ) + CHR( 10 ) ) ) __defaultNIL( @lRemDelim, .T. ) __defaultNIL( @nCount, -1 ) //WriteToLogFile( "Splitstring: " + cStr( cString ) ) DO WHILE ( nEOLPos := AT( cDelim, cBuffer ) ) > 0 nHowMany++ IF lRemDelim cLine := LEFT( cBuffer, nEOLPos - 1 ) ELSE cLine := LEFT( cBuffer, ( nEOLPos + LEN( cDelim ) ) - 1 ) ENDIF //WriteToLogFile( "cBuffer, cDelim, nEOLPos, cLine: " + cStr( cBuffer ) + "," + cStr( cDelim ) + "," + cStr( nEOLPos ) + "," + cStr( cLine ) ) aAdd( aLines, cLine ) cBuffer := SubStr( cBuffer, nEOLPos + LEN( cDelim ) ) IF nCount > -1 IF nHowMany >= nCount EXIT ENDIF ENDIF ENDDO // Check last line IF Len( cBuffer ) > 0 aAdd( aLines, cBuffer ) ENDIF RETURN aLines /************************************************************ * Encoding URL */ FUNCTION uhttpd_URLEncode( cString, lComplete ) #ifdef HB_USE_HBTIP __defaultNIL( @lComplete, .T. ) RETURN TIPENCODERURL_ENCODE( cString, lComplete ) #else LOCAL cRet := "", i, nVal, cChar __defaultNIL( @lComplete, .T. ) FOR i := 1 TO Len( cString ) cChar := SubStr( cString, i, 1) DO CASE CASE cChar == " " cRet += "+" CASE ( cChar >= "A" .AND. cChar <= "Z" ) .OR. ; ( cChar >= "a" .AND. cChar <= "z" ) .OR. ; ( cChar >= "0" .AND. cChar <= "9" ) .OR. ; cChar == '.' .OR. cChar == ',' .OR. cChar == '&' .OR. ; cChar == '/' .OR. cChar == ';' .OR. cChar == '_' cRet += cChar CASE iif( !lComplete, cChar == ':' .OR. cChar == '?' .OR. cChar == '=', .F. ) cRet += cChar OTHERWISE nVal := Asc( cChar ) cRet += "%" + hb_NumToHex( nVal ) ENDCASE NEXT RETURN cRet /************************************************************ * Decoding URL */ FUNCTION uhttpd_URLDecode( cString ) #ifdef HB_USE_HBTIP RETURN TIPENCODERURL_DECODE( cString ) #else LOCAL cRet := "", i, cChar FOR i := 1 TO Len( cString ) cChar := SubStr( cString, i, 1 ) DO CASE CASE cChar == "+" cRet += " " CASE cChar == "%" i ++ cRet += Chr( hb_HexToNum( SubStr( cString, i, 2 ) ) ) i ++ OTHERWISE cRet += cChar ENDCASE NEXT RETURN cRet #endif /* * DateToGMT( dDate, cTime, nDayToAdd ) --> cGMTDate * * dDate : default DATE() * cTime : default "00:00:00" * nDayToAdd : default 0 - may be a negative number * * cGMTDate : The string return in form of "Saturday, 31-Oct-03 00:00:00 GMT" */ FUNCTION uhttpd_DateToGMT( dDate, cTime, nDayToAdd, nSecsToAdd ) LOCAL cStr LOCAL cOldDateFormat := Set( _SET_DATEFORMAT, "dd-mm-yy" ) LOCAL nDay, nMonth, nYear, nDoW LOCAL aDays := { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" } LOCAL aMonths := { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" } __defaultNIL( @dDate, DATE() ) __defaultNIL( @cTime, TIME() ) __defaultNIL( @nDayToAdd, 0 ) __defaultNIL( @nSecsToAdd, 0 ) //Tracelog( "DateToGMT - StartingValue", dDate, cTime, nDayToAdd, nSecsToAdd ) cTime := uhttpd_AddSecondsToTime( cTime, nSecsToAdd, @nDayToAdd ) dDate += nDayToAdd nDay := Day( dDate ) nMonth := Month( dDate ) nYear := Year( dDate) nDoW := Dow( dDate ) cStr := aDays[ nDow ] + ", " + StrZero( nDay, 2 ) + "-" + aMonths[ nMonth ] + "-" + ; Right( StrZero( nYear, 4 ), 2 ) + " " + cTime + " GMT" //Tracelog( "DateToGMT", cStr ) Set( _SET_DATEFORMAT, cOldDateFormat ) RETURN cStr /* * AddSecondsToTime( cTime, nSecsToAdd, @nDaysAdded ) --> cNewTime * * cTime : default "00:00:00" * nSecsToAdd : default 0 - may be a negative number * nDaysAdded : (out) return how many days add (or subtract) to actual date if numbers seconds is * more than 86400 seconds (1 day) * * cNewTime : The new time string * * Rules: time is converted to seconds from midnight, then added of nSecsToAdd. Divided of 1 day and * then reverted to Time string */ FUNCTION uhttpd_AddSecondsToTime( cTime, nSecsToAdd, nDaysAdded ) LOCAL nOneDaySeconds := 86400 // 24 * 60 * 60 LOCAL cNewTime, nSecs __defaultNIL( @cTime, TIME() ) __defaultNIL( @nSecsToAdd, 0 ) // nDaysAdded can be already valued, so below i add to this value __defaultNIL( @nDaysAdded, 0 ) IF nSecsToAdd != 0 nSecs := Secs( cTime ) + nSecsToAdd nDaysAdded += Int( nSecs / nOneDaySeconds ) // Attention! nDaysAdded can be already filled nSecs := nSecs - nDaysAdded cNewTime := TSTRING( nSecs ) ELSE cNewTime := cTime ENDIF RETURN cNewTime FUNCTION uhttpd_TimeDiffAsSeconds( dDateStart, dDateEnd, cTimeStart, cTimeEnd ) LOCAL aRetVal __defaultNIL( @dDateEnd, DATE() ) __defaultNIL( @cTimeEnd, TIME() ) aRetVal := FT_ELAPSED( dDateStart, dDateEnd, cTimeStart, cTimeEnd ) RETURN aRetVal[ 4, 2 ] FUNCTION uhttpd_OutputString( cString, aTranslate, lProtected ) LOCAL cHtml __defaultNIL( @lProtected, .F. ) __defaultNIL( @aTranslate, { { '"', '"' }, { ' ', ' ' } } ) //TraceLog( "OutputString( cString, aTranslate, lProtected )", cString, aTranslate, lProtected ) IF lProtected cHtml := uhttpd_HtmlSpecialChars( cString ) ELSE cHtml := uhttpd_TranslateStrings( cString, aTranslate ) ENDIF //TraceLog( "OutputString() = cHtml", cHtml ) RETURN cHtml FUNCTION uhttpd_HtmlSpecialChars( cString, cQuote_style ) LOCAL aTranslations := { ; { '&', '&' } ,; { '<', '<' } ,; { '>', '>' } ; } RETURN uhttpd_HtmlConvertChars( cString, cQuote_style, aTranslations ) FUNCTION uhttpd_HtmlConvertChars( cString, cQuote_style, aTranslations ) __defaultNIL( @cQuote_style, "ENT_COMPAT" ) DO CASE CASE cQuote_style == "ENT_COMPAT" aAdd( aTranslations, { '"', '"' } ) CASE cQuote_style == "ENT_QUOTES" aAdd( aTranslations, { '"', '"' } ) aAdd( aTranslations, { "'", ''' } ) CASE cQuote_style == "ENT_NOQUOTES" ENDCASE RETURN uhttpd_TranslateStrings( cString, aTranslations ) FUNCTION uhttpd_CRLF2BR( cString ) LOCAL aTranslations := { ; { CRLF, '
' } ; } RETURN uhttpd_TranslateStrings( cString, aTranslations ) FUNCTION uhttpd_TranslateStrings( cString, aTranslate ) LOCAL aTran FOR EACH aTran IN aTranslate IF aTran[1] $ cString cString := StrTran( cString, aTran[1], aTran[2] ) ENDIF NEXT RETURN cString FUNCTION uhttpd_StrStr( cString, cSearch ) LOCAL nPos := AT( cSearch, cString ) LOCAL cVal := iif( nPos > 0, SubStr( cString, nPos ), NIL ) RETURN cVal FUNCTION uhttpd_StrIStr( cString, cSearch ) RETURN uhttpd_StrStr( Upper( cSearch ), Upper( cString ) ) FUNCTION uhttpd_HtmlEntities( cString, cQuote_style ) // LOCAL aTranslations := { ; // ATTENTION, this chars are visible only with OEM font // { hb_BChar( 160 ), ' ' } ,; //   Nonbreaking space // { hb_BChar( 161 ), '¡' } ,; // ¡ Inverted exclamation // { hb_BChar( 162 ), '¢' } ,; // ¢ Cent sign // { hb_BChar( 163 ), '£' } ,; // £ Pound sterling // { hb_BChar( 164 ), '¤' } ,; // ¤ General currency sign // { hb_BChar( 165 ), '¥' } ,; // ¥ Yen sign // { hb_BChar( 166 ), '¦' } ,; // ¦ or &brkbar; Broken vertical bar // { hb_BChar( 167 ), '§' } ,; // § Section sign // { hb_BChar( 168 ), '¨' } ,; // ¨ or ¨ Diaeresis / Umlaut // { hb_BChar( 169 ), '©' } ,; // © Copyright // { hb_BChar( 170 ), 'ª' } ,; // ª Feminine ordinal // { hb_BChar( 171 ), '«' } ,; // « Left angle quote, guillemet left // { hb_BChar( 172 ), '¬' } ,; // ¬ Not sign // { hb_BChar( 173 ), '­' } ,; // ­ Soft hyphen // { hb_BChar( 174 ), '®' } ,; // ® Registered trademark // { hb_BChar( 175 ), '¯' } ,; // ¯ or &hibar; Macron accent // { hb_BChar( 176 ), '°' } ,; // ° Degree sign // { hb_BChar( 177 ), '±' } ,; // ± Plus or minus // { hb_BChar( 178 ), '²' } ,; // ² Superscript two // { hb_BChar( 179 ), '³' } ,; // ³ Superscript three // { hb_BChar( 180 ), '´' } ,; // ´ Acute accent // { hb_BChar( 181 ), 'µ' } ,; // µ Micro sign // { hb_BChar( 182 ), '¶' } ,; // ¶ Paragraph sign // { hb_BChar( 183 ), '·' } ,; // · Middle dot // { hb_BChar( 184 ), '¸' } ,; // ¸ Cedilla // { hb_BChar( 185 ), '¹' } ,; // ¹ Superscript one // { hb_BChar( 186 ), 'º' } ,; // º Masculine ordinal // { hb_BChar( 187 ), '»' } ,; // » Right angle quote, guillemet right // { hb_BChar( 188 ), '¼' } ,; // ¼ Fraction one-fourth // { hb_BChar( 189 ), '½' } ,; // ½ Fraction one-half // { hb_BChar( 190 ), '¾' } ,; // ¾ Fraction three-fourths // { hb_BChar( 191 ), '¿' } ,; // ¿ Inverted question mark // { hb_BChar( 192 ), 'À' } ,; // À Capital A, grave accent // { hb_BChar( 193 ), 'Á' } ,; // Á Capital A, acute accent // { hb_BChar( 194 ), 'Â' } ,; // Â Capital A, circumflex // { hb_BChar( 195 ), 'Ã' } ,; // Ã Capital A, tilde // { hb_BChar( 196 ), 'Ä' } ,; // Ä Capital A, diaeresis / umlaut // { hb_BChar( 197 ), 'Å' } ,; // Å Capital A, ring // { hb_BChar( 198 ), 'Æ' } ,; // Æ Capital AE ligature // { hb_BChar( 199 ), 'Ç' } ,; // Ç Capital C, cedilla // { hb_BChar( 200 ), 'È' } ,; // È Capital E, grave accent // { hb_BChar( 201 ), 'É' } ,; // É Capital E, acute accent // { hb_BChar( 202 ), 'Ê' } ,; // Ê Capital E, circumflex // { hb_BChar( 203 ), 'Ë' } ,; // Ë Capital E, diaeresis / umlaut // { hb_BChar( 204 ), 'Ì' } ,; // Ì Capital I, grave accent // { hb_BChar( 205 ), 'Í' } ,; // Í Capital I, acute accent // { hb_BChar( 206 ), 'Î' } ,; // Î Capital I, circumflex // { hb_BChar( 207 ), 'Ï' } ,; // Ï Capital I, diaeresis / umlaut // { hb_BChar( 208 ), 'Ð' } ,; // Ð Capital Eth, Icelandic // { hb_BChar( 209 ), 'Ñ' } ,; // Ñ Capital N, tilde // { hb_BChar( 210 ), 'Ò' } ,; // Ò Capital O, grave accent // { hb_BChar( 211 ), 'Ó' } ,; // Ó Capital O, acute accent // { hb_BChar( 212 ), 'Ô' } ,; // Ô Capital O, circumflex // { hb_BChar( 213 ), 'Õ' } ,; // Õ Capital O, tilde // { hb_BChar( 214 ), 'Ö' } ,; // Ö Capital O, diaeresis / umlaut // { hb_BChar( 215 ), '×' } ,; // × Multiply sign // { hb_BChar( 216 ), 'Ø' } ,; // Ø Capital O, slash // { hb_BChar( 217 ), 'Ù' } ,; // Ù Capital U, grave accent // { hb_BChar( 218 ), 'Ú' } ,; // Ú Capital U, acute accent // { hb_BChar( 219 ), 'Û' } ,; // Û Capital U, circumflex // { hb_BChar( 220 ), 'Ü' } ,; // Ü Capital U, diaeresis / umlaut // { hb_BChar( 221 ), 'Ý' } ,; // Ý Capital Y, acute accent // { hb_BChar( 222 ), 'Þ' } ,; // Þ Capital Thorn, Icelandic // { hb_BChar( 223 ), 'ß' } ,; // ß Small sharp s, German sz // { hb_BChar( 224 ), 'à' } ,; // à Small a, grave accent // { hb_BChar( 225 ), 'á' } ,; // á Small a, acute accent // { hb_BChar( 226 ), 'â' } ,; // â Small a, circumflex // { hb_BChar( 227 ), 'ã' } ,; // ã Small a, tilde // { hb_BChar( 228 ), 'ä' } ,; // ä Small a, diaeresis / umlaut // { hb_BChar( 229 ), 'å' } ,; // å Small a, ring // { hb_BChar( 230 ), 'æ' } ,; // æ Small ae ligature // { hb_BChar( 231 ), 'ç' } ,; // ç Small c, cedilla // { hb_BChar( 232 ), 'è' } ,; // è Small e, grave accent // { hb_BChar( 233 ), 'é' } ,; // é Small e, acute accent // { hb_BChar( 234 ), 'ê' } ,; // ê Small e, circumflex // { hb_BChar( 235 ), 'ë' } ,; // ë Small e, diaeresis / umlaut // { hb_BChar( 236 ), 'ì' } ,; // ì Small i, grave accent // { hb_BChar( 237 ), 'í' } ,; // í Small i, acute accent // { hb_BChar( 238 ), 'î' } ,; // î Small i, circumflex // { hb_BChar( 239 ), 'ï' } ,; // ï Small i, diaeresis / umlaut // { hb_BChar( 240 ), 'ð' } ,; // ð Small eth, Icelandic // { hb_BChar( 241 ), 'ñ' } ,; // ñ Small n, tilde // { hb_BChar( 242 ), 'ò' } ,; // ò Small o, grave accent // { hb_BChar( 243 ), 'ó' } ,; // ó Small o, acute accent // { hb_BChar( 244 ), 'ô' } ,; // ô Small o, circumflex // { hb_BChar( 245 ), 'õ' } ,; // õ Small o, tilde // { hb_BChar( 246 ), 'ö' } ,; // ö Small o, diaeresis / umlaut // { hb_BChar( 247 ), '÷' } ,; // ÷ Division sign // { hb_BChar( 248 ), 'ø' } ,; // ø Small o, slash // { hb_BChar( 249 ), 'ù' } ,; // ù Small u, grave accent // { hb_BChar( 250 ), 'ú' } ,; // ú Small u, acute accent // { hb_BChar( 251 ), 'û' } ,; // û Small u, circumflex // { hb_BChar( 252 ), 'ü' } ,; // ü Small u, diaeresis / umlaut // { hb_BChar( 253 ), 'ý' } ,; // ý Small y, acute accent // { hb_BChar( 254 ), 'þ' } ,; // þ Small thorn, Icelandic // { hb_BChar( 255 ), 'ÿ' } ; // ÿ Small y, diaeresis / umlaut // } LOCAL aTranslations := {} LOCAL i FOR i := 160 TO 255 aAdd( aTranslations, { hb_BChar( i ), "&#" + Str( i, 3 ) + ";" } ) NEXT RETURN uhttpd_HtmlConvertChars( cString, cQuote_style, aTranslations ) PROCEDURE uhttpd_Die( cError ) LOCAL oErr, lError IF cError != NIL //THEN OutStd( cError ) //__OutDebug( "cError: ", cError ) //IF !oCGI:HeaderSent() // oCGI:WriteLN( CRLF2BR( cError ), CRLF2BR( CRLF() ) ) // //oCGI:WriteLN( CRLF2BR( hb_dumpVar(TConfigure():hConfig) ) ) //ENDIF // Generate Error oErr := ErrorNew() oErr:severity := ES_ERROR oErr:genCode := EG_LIMIT oErr:subSystem := "uhttpd_CGI" oErr:subCode := 0 oErr:description := cError oErr:canRetry := .F. oErr:canDefault := .F. oErr:fileName := "" oErr:osCode := 0 lError := Eval( ErrorBlock(), oErr ) IF !HB_ISLOGICAL( lError ) .OR. lError __ErrInHandler() ENDIF Break( oErr ) //QUIT ELSE QUIT ENDIF RETURN FUNCTION uhttpd_HTMLSpace( n ) RETURN replicate( " ", n ) //" " /* FROM FT LIB */ STATIC FUNCTION FT_ELAPSED(dStart, dEnd, cTimeStart, cTimeEnd) LOCAL nTotalSec, nCtr, nConstant, nTemp, aRetVal[4,2] IF HB_ISSTRING( dStart ) cTimeStart := dStart dStart := DATE() ELSEIF ! HB_ISDATE( dStart ) dStart := DATE() ENDIF IF HB_ISSTRING( dEnd ) cTimeEnd := dEnd dEnd := DATE() ELSEIF ! HB_ISDATE( dEnd ) dEnd := DATE() ENDIF iif( ! HB_ISSTRING( cTimeStart ), cTimeStart := '00:00:00', ) iif( ! HB_ISSTRING( cTimeEnd ) , cTimeEnd := '00:00:00', ) nTotalSec := (dEnd - dStart) * 86400 + ; VAL(cTimeEnd) * 3600 + ; VAL(SUBSTR(cTimeEnd,AT(':', cTimeEnd)+1,2)) * 60 + ; iif(RAT(':', cTimeEnd) == AT(':', cTimeEnd), 0, ; VAL(SUBSTR(cTimeEnd,RAT(':', cTimeEnd)+1))) - ; VAL(cTimeStart) * 3600 - ; VAL(SUBSTR(cTimeStart,AT(':', cTimeStart)+1,2)) * 60 - ; iif(RAT(':', cTimeStart) == AT(':', cTimeStart), 0, ; VAL(SUBSTR(cTimeStart,RAT(':', cTimeStart)+1))) nTemp := nTotalSec FOR nCtr := 1 to 4 nConstant := iif(nCtr == 1, 86400, iif(nCtr == 2, 3600, iif( nCtr == 3, 60, 1))) aRetVal[nCtr,1] := INT(nTemp/nConstant) aRetval[nCtr,2] := nTotalSec / nConstant nTemp -= aRetVal[nCtr,1] * nConstant NEXT RETURN aRetVal PROCEDURE uhttpd_WriteToLogFile( cString, cLog, lCreate ) LOCAL nHandle, cSep cSep := hb_ps() // __defaultNIL( @cLog, AppFullPath() + cSep + "logfile.log" ) __defaultNIL( @cLog, cSep + "tmp" + cSep + "logfile.log" ) __defaultNIL( @lCreate, .F. ) IF cLog != NIL IF !lCreate .AND. hb_FileExists( cLog ) nHandle := FOpen( cLog, FO_READWRITE + FO_SHARED ) ELSE nHandle := hb_FCreate( cLog, FC_NORMAL, FO_READWRITE + FO_SHARED ) //__OutDebug( "Create ", nHandle ) ENDIF //cString := "PROCEDURE: " + ProcName( -2 ) + " " + cString IF nHandle > 0 FSeek( nHandle, 0, FS_END ) FWrite( nHandle, cString ) FWrite( nHandle, CRLF ) FClose( nHandle ) ENDIF ENDIF RETURN /*********************************************************************************/ FUNCTION uhttpd_SplitFileName( cFile ) LOCAL hFile LOCAL cPath, cName, cExt, cDrive, cSep HB_FnameSplit( cFile, @cPath, @cName, @cExt, @cDrive ) hFile := { ; "FILE" => cFile ,; "DRIVE" => cDrive ,; "PATH" => cPath ,; "NAME" => cName ,; "EXT" => cExt ,; "FULLPATH" => NIL ,; "FULLNAME" => cName + cExt ,; "UNC" => NIL ; } cSep := hb_ps() hFile:FULLPATH := iif( !Empty( hFile:PATH ), iif( !( Right( hFile:PATH, Len( cSep ) ) == cSep ), hFile:PATH + cSep, hFile:PATH ), "" ) hFile:UNC := hFile:FULLPATH + hFile:FULLNAME RETURN hFile FUNCTION uhttpd_AppFullPath() LOCAL hExeFile := uhttpd_SplitFileName( HB_ARGV(0) ) LOCAL cPrgFullPath := hExeFile:FULLPATH LOCAL cPath, cSep cSep := hb_ps() IF Right( cPrgFullPath, Len( cSep ) ) == cSep cPath := SubStr( cPrgFullPath, 1, Len( cPrgFullPath ) - Len( cSep ) ) ELSE cPath := cPrgFullPath ENDIF RETURN cPath FUNCTION uhttpd_AppFullName() LOCAL hExeFile := uhttpd_SplitFileName( HB_ARGV(0) ) RETURN hExeFile:FULLNAME FUNCTION uhttpd_CStrToVal( cExp, cType ) IF ! HB_ISSTRING( cExp ) Throw( ErrorNew( "CSTR", 0, 3101, ProcName(), "Argument error", { cExp, cType } ) ) ENDIF SWITCH cType CASE 'C' RETURN cExp CASE 'P' RETURN hb_HexToNum( cExp ) CASE 'D' IF cExp[3] >= '0' .AND. cExp[3] <= '9' .AND. cExp[5] >= '0' .AND. cExp[5] <= '9' RETURN sToD( cExp ) ELSE RETURN cToD( cExp ) ENDIF CASE 'L' RETURN iif( cExp[1] == 'T' .OR. cExp[1] == 'Y' .OR. cExp[2] == 'T' .OR. cExp[2] == 'Y', .T., .F. ) CASE 'N' RETURN Val( cExp ) CASE 'M' RETURN cExp CASE 'U' RETURN NIL /* CASE 'A' Throw( ErrorNew( "CSTR", 0, 3101, ProcName(), "Argument error", { cExp, cType } ) ) CASE 'B' Throw( ErrorNew( "CSTR", 0, 3101, ProcName(), "Argument error", { cExp, cType } ) ) CASE 'O' Throw( ErrorNew( "CSTR", 0, 3101, ProcName(), "Argument error", { cExp, cType } ) ) */ OTHERWISE Throw( ErrorNew( "CSTR", 0, 3101, ProcName(), "Argument error", { cExp, cType } ) ) ENDSWITCH RETURN NIL FUNCTION uhttpd_GetField( cVar, cType ) LOCAL xVal LOCAL nPos := hb_HPos( _Request, cVar ) IF nPos > 0 //cVar IN ::h_Request:Keys xVal := hb_HValueAt( _Request, nPos ) //::h_Request[ cVar ] IF Empty( xVal ) xVal := NIL ENDIF IF cType != NIL .AND. cType $ "NLD" xVal := uhttpd_CStrToVal( xVal, cType ) ENDIF ENDIF RETURN xVal FUNCTION uhttpd_SetField( cVar, cVal ) LOCAL xVal := uhttpd_HGetValue( _Request, cVar ) _Request[ cVar ] := cVal RETURN xVal FUNCTION uhttpd_HGetValue( hHash, cKey ) LOCAL nPos LOCAL xVal IF hHash != NIL xVal := iif( ( nPos := hb_HPos( hHash, cKey )) == 0, NIL, hb_HValueAt( hHash, nPos) ) ENDIF //RETURN iif( cKey IN hHash:Keys, hHash[ cKey ], NIL ) RETURN xVal