/* Copyright (C) 2001 ITK Autor : Rust (rust@itk.ru) Licence : (GPL) http://www.itk.ru/clipper/licence.html */ #define CR CHR(13) #define LF CHR(10) #define CHUNKSIZE 1024 memvar vars, recurse, stopparsing memvar html, ifdeep, ifyes, ifanyyes memvar whiledeep, whilestack, whileyes, conn memvar rdbms, host, login, passwd, rs PROCEDURE Main() LOCAL srcfile LOCAL conn PRIVATE vars := GETENV() PUBLIC recurse := -1 PUBLIC stopparsing := .F. set translate off ErrorBlock({|e| BREAK(e)}) vars:WWW_CLIP_VERSION := "0.0.1" ?? "Content-type: text/html" ? "Generator: WWW-Clip Version "+vars:WWW_CLIP_VERSION ? srcfile := vars:PATH_TRANSLATED ? ParseFile(srcfile) RETURN FUNCTION ParseFile(srcfile) LOCAL fd LOCAL src := "" LOCAL chunk := SPACE(CHUNKSIZE) LOCAL read LOCAL len LOCAL I LOCAL istag := .F. LOCAL tagbegin := 0 LOCAL tagend := 0 LOCAL term LOCAL isquote := .F. LOCAL ret := "" LOCAL done := .F. LOCAL brk := .F. LOCAL nxt := .F. LOCAL pars := "" LOCAL ch PRIVATE html := ARRAY(0) PRIVATE ifdeep := 0 PRIVATE ifyes := ARRAY(100) PRIVATE ifanyyes := ARRAY(100) PRIVATE whiledeep := 0 PRIVATE whilestack := ARRAY(100) PRIVATE whileyes := ARRAY(100) PRIVATE conn := NIL PRIVATE rdbms PRIVATE host PRIVATE login PRIVATE passwd PRIVATE rs := map() recurse++ IF recurse >= 10 recurse-- RETURN ret ENDIF AFILL(whilestack,0) IF vars:REQUEST_METHOD == "GET" pars := vars:QUERY_STRING ELSE fd := FOPEN("-|",0) DO WHILE (read := FREAD(fd,@chunk,CHUNKSIZE)) == CHUNKSIZE pars += chunk chunk := SPACE(CHUNKSIZE) ENDDO pars += LEFT(chunk,read) FCLOSE(fd) ENDIF ParseParameters(pars) fd := FOPEN(srcfile,0) IF fd == -1 recurse-- RETURN "File not found" ENDIF DO WHILE (read := FREAD(fd,@chunk,CHUNKSIZE)) == CHUNKSIZE src += chunk chunk := SPACE(CHUNKSIZE) ENDDO src += LEFT(chunk,read) FCLOSE(fd) len := LEN(src) FOR I:=1 TO len ch := SUBSTR(src,I,1) IF !isquote IF !istag IF ch == "<" istag := .T. tagbegin := I term := SUBSTR(src,tagend+1,tagbegin-tagend-1) IF LEN(term) > 0 AADD(html,term) ENDIF ENDIF ELSE IF ch == ">" istag := .F. tagend := I term := SUBSTR(src,tagbegin,tagend-tagbegin+1) AADD(html,term) ENDIF ENDIF ENDIF IF ch == '"' .AND. SUBSTR(src,MAX(I-1,1),1) != "\" isquote := !isquote ENDIF NEXT AADD(html,SUBSTR(src,MAX(tagbegin,tagend+1))) FOR I:=1 TO LEN(html) IF stopparsing EXIT ENDIF IF LEFT(html[I],2) == "connect: too few arguments

"+LF ENDIF rdbms := terms[1] host := IF(LEN(terms)>1,terms[2],NIL) login := IF(LEN(terms)>2,terms[3],NIL) passwd := IF(LEN(terms)>3,terms[4],NIL) host := IF(host=="NIL" .OR. host=="",NIL,host) login := IF(login=="NIL" .OR. login=="",NIL,login) passwd := IF(passwd=="NIL" .OR. passwd=="",NIL,passwd) IF UPPER(rdbms) == "OR" .OR. UPPER(rdbms) == "MS" conn := ConnectNew(rdbms,NIL,NIL,login,passwd) ENDIF CASE cmd == "CLIP" CASE cmd == "CLOSE" conn:Destroy() CASE cmd == "CONTINUE" nxt := .T. CASE cmd == "CONVERT" terms := ParseArgs(args) IF LEN(terms) < 1 RETURN "

convert: too few arguments

"+LF ENDIF vars[HASHSTR(UPPER(terms[1]))] :=; XTOC(vars[HASHSTR(UPPER(terms[1]))]) CASE cmd == "DATABASE" terms := ParseArgs(args) IF LEN(terms) == 0 RETURN "

database: too few arguments

"+LF ENDIF IF rdbms == "PG" conn := ConnectNew(rdbms,host,NIL,login,passwd,terms[1]) ELSEIF rdbms == "MS" conn:Command("use "+terms[1]) ENDIF CASE cmd == "EVAL" IF LEN(args)==0 RETURN "

eval: too few arguments

"+LF ENDIF ret := DoEval(ParseExpr(args)) CASE cmd == "EXEC" IF LEN(args)==0 RETURN "

exec: too few arguments

"+LF ENDIF tmp := "" err := "" SYSCMD(args,"",@tmp,@err) ret := tmp CASE cmd == "FETCH" RETURN ret CASE cmd == "FTIME" terms := ParseArgs(args) IF LEN(terms) < 1 RETURN "

ftime: too few arguments

"+LF ENDIF tmp := 0 IF LEN(terms) > 1 tmp := VAL(terms[2]) ENDIF ret += STRFTIME(terms[1],tmp) CASE cmd == "FREE" terms := ParseArgs(args) IF LEN(terms) == 0 RETURN "

free: too few arguments

"+LF ENDIF r := rs[HASHSTR(UPPER(terms[1]))] r:Destroy() CASE cmd == "IF" IF LEN(args)==0 RETURN "

if: too few arguments

"+LF ENDIF tmp := DoEval(ParseExpr(args)) IF tmp != "0" .AND. tmp != "1" RETURN tmp ENDIF ifdeep++ IF ifdeep == 1 .OR. ifyes[ifdeep-1] ifanyyes[ifdeep] := ifyes[ifdeep] := (tmp != "0") ELSE ifyes[ifdeep] := .F. ENDIF CASE cmd == "ELSEIF" IF LEN(args)==0 RETURN "

elseif: too few arguments

"+LF ENDIF IF ifdeep == 1 .OR. ifyes[ifdeep-1] IF !ifyes[ifdeep] tmp := DoEval(ParseExpr(args)) IF tmp != "0" .AND. tmp != "1" ret += tmp ENDIF ifanyyes[ifdeep] := ifyes[ifdeep] := (tmp != "0") ELSE ifyes[ifdeep] := .F. ENDIF ELSE ifyes[ifdeep] := .F. ENDIF CASE cmd == "ELSE" IF ifdeep == 1 .OR. ifyes[ifdeep-1] ifyes[ifdeep] := !ifanyyes[ifdeep] ELSE ifyes[ifdeep] := .F. ENDIF CASE cmd == "ENDIF" ifdeep-- CASE cmd == "INCLUDE" terms := ParseArgs(args) IF LEN(terms)<1 RETURN "

include: too few arguments

"+LF ENDIF ret := ParseFile(terms[1]) CASE cmd == "PRINT" terms := ParseArgs(args) IF LEN(terms) < 0 RETURN "

print: too few arguments

"+LF ENDIF args := STRTRAN(terms[1],'\"','"') args := STRTRAN(args,"\n",LF) args := STRTRAN(args,"\t",CHR(9)) args := STRTRAN(args,"\?","?") ret := ParseFields(args,.F.) CASE cmd == "PRINT_LOOP" terms := ParseArgs(args) IF LEN(terms)<1 RETURN "

print_loop: too few arguments

"+LF ENDIF r := rs[HASHSTR(UPPER(terms[1]))] IF whiledeep == 0 .OR. whilestack[whiledeep] != I whiledeep++ whilestack[whiledeep] := I ELSE r:Skip() ENDIF whileyes[whiledeep] := !r:Eof() CASE cmd == "PRINT_ROWS" terms := ParseArgs(args) IF LEN(terms)<2 RETURN "

print_rows: too few arguments

"+LF ENDIF r := rs[HASHSTR(UPPER(terms[1]))] terms[2] := STRTRAN(terms[2],'\"','"') terms[2] := STRTRAN(terms[2],"\n",LF) terms[2] := STRTRAN(terms[2],"\t",CHR(9)) DO WHILE !r:Eof() ret += ParseFields(terms[2],.F.) r:Skip() ENDDO CASE cmd == "QUERY" terms := ParseArgs(args) IF LEN(terms)<1 RETURN "

query: too few arguments

"+LF ENDIF query := ParseQuery(terms[1]) IF LEN(terms) == 1 vars:AFFECTED_ROWS := conn:Command(query) ELSE r := rs[HASHSTR(UPPER(terms[2]))] :=; conn:CreateRowset(query) vars:NUM_FIELDS := r:NFields() vars:NUM_ROWS := r:Lastrec() ENDIF CASE cmd == "QTABLE" terms := ParseArgs(args) IF LEN(terms)<1 RETURN "

qtable: too few arguments

"+LF ENDIF borders := .F. IF LEN(terms)>1 .AND. UPPER(terms[2]) == "BORDERS" borders := .T. ENDIF r := rs[HASHSTR(UPPER(terms[1]))] ret := ""+LF ret += "" FOR J:=1 TO r:NFields() ret += "" ret += r:FieldName(J) ret += "" NEXT ret += ""+LF rec := r:Recno() r:GoTop() DO WHILE !r:Eof() ret += "" data := r:Read() FOR J:=1 TO r:NFields() ret += "" tmp := data[HASHSTR(UPPER(r:FieldName(J)))] ret += XTOC(tmp) ret += "" NEXT ret += ""+LF r:Skip() ENDDO r:Goto(rec) ret += "" CASE cmd == "QLONGFORM" terms := ParseArgs(args) IF LEN(terms)<1 RETURN "

qlongform: too few arguments

"+LF ENDIF r := rs[HASHSTR(UPPER(terms[1]))] rec := r:Recno() r:GoTop() DO WHILE !r:Eof() data := r:Read() FOR J:=1 TO r:NFields() ret += ""+r:FieldName(J)+": " tmp := data[HASHSTR(UPPER(r:FieldName(J)))] ret += XTOC(tmp) ret += "
"+LF NEXT ret += "

"+LF r:Skip() ENDDO r:Goto(rec) CASE cmd == "QSELECT" terms := ParseArgs(args) IF LEN(terms)<2 RETURN "

qselect: too few arguments

"+LF ENDIF ret += '"+LF CASE cmd == "SEEK" terms := ParseArgs(args) IF LEN(terms)<2 RETURN "

seek: too few arguments

"+LF ENDIF r := rs[HASHSTR(UPPER(terms[1]))] pos := VAL(terms[2]) r:Goto(pos) CASE cmd == "SET" .OR. cmd == "SETEXPR" terms := ParseArgs(args) IF LEN(terms)<2 RETURN "

set: too few arguments

"+LF ENDIF pos := AT(" ",args) tmp := "vars:"+STUFF(args,pos,1,":=") DoEval(ParseExpr(tmp)) CASE cmd == "SETDEFAULT" terms := ParseArgs(args) IF LEN(terms)<2 RETURN "

setdefault: too few arguments

"+LF ENDIF pos := AT(" ",args) tmp := HASHSTR(UPPER(SUBSTR(args,1,pos-1))) mkeys := MAPKEYS(vars) FOR J:=1 TO LEN(mkeys) IF mkeys[J] == tmp RETURN ret ENDIF NEXT pos := AT(" ",args) tmp := "vars:"+STUFF(args,pos,1,":=") DoEval(tmp) CASE cmd == "WHILE" IF LEN(args)==0 RETURN "

while: too few arguments

"+LF ENDIF tmp := DoEval(ParseExpr(args)) IF whiledeep == 0 .OR. whilestack[whiledeep]!=I whiledeep++ whilestack[whiledeep] := I ENDIF whileyes[whiledeep] := (tmp != "0") CASE cmd == "DONE" done := .T. OTHERWISE ret := "

Unknown command: "+tag+"

"+LF ENDCASE ENDIF RECOVER USING e ret := "
WWWClip: Error in tag <"+; SUBSTR(html[I],2,LEN(html[I])-2)+">:
"+; "operation:"+e:operation+"
"+; "description:"+e:description+"
"+LF stopparsing := .T. END SEQUENCE RETURN ret FUNCTION XTOC(x) IF VALTYPE(x) == "C" RETURN x ELSEIF VALTYPE(x) == "N" RETURN ALLTRIM(STR(x)) ELSEIF VALTYPE(x) == "D" RETURN DTOC(x) ELSEIF VALTYPE(x) == "L" RETURN IF(x,"TRUE","FALSE") ENDIF RETURN "---" FUNCTION ParseQuery(pat) LOCAL ret LOCAL qpos LOCAL ch LOCAL I LOCAL tmp DO WHILE (qpos := AT("?",pat)) != 0 I := qpos+1 ch := SUBSTR(pat,I,1) DO WHILE ISALPHA(ch) .OR. ISDIGIT(ch) .OR. ch $ "_-" I++ ch := SUBSTR(pat,I,1) ENDDO tmp := XTOC(vars[HASHSTR(UPPER(SUBSTR(pat,qpos+1,I-qpos-1)))]) pat := STUFF(pat,qpos,I-qpos,tmp) ENDDO DO WHILE (qpos := AT("$",pat)) != 0 I := qpos+1 ch := SUBSTR(pat,I,1) DO WHILE ISALPHA(ch) .OR. ISDIGIT(ch) .OR. ch $ "_-" I++ ch := SUBSTR(pat,I,1) ENDDO tmp := XTOC(vars[HASHSTR(UPPER(SUBSTR(pat,qpos+1,I-qpos-1)))]) pat := STUFF(pat,qpos,I-qpos,tmp) ENDDO RETURN pat FUNCTION ParseFields(pat,expr) LOCAL ret := "" LOCAL qpos,fpos LOCAL ch LOCAL I LOCAL tmp LOCAL data LOCAL r LOCAL fval pat := STRTRAN(pat,"\$",CHR(1)) pat := STRTRAN(pat,"\@",CHR(2)) pat := STRTRAN(pat,"\#",CHR(3)) IF !expr DO WHILE (qpos := AT("$",pat)) != 0 I := qpos+1 ch := SUBSTR(pat,I,1) DO WHILE ISALPHA(ch) .OR. ISDIGIT(ch) .OR. ch $ "_-" I++ ch := SUBSTR(pat,I,1) ENDDO tmp := XTOC(vars[HASHSTR(UPPER(SUBSTR(pat,qpos+1,I-qpos-1)))]) pat := STUFF(pat,qpos,I-qpos,tmp) ENDDO DO WHILE (qpos := AT("#",pat)) != 0 I := qpos+1 ch := SUBSTR(pat,I,1) DO WHILE ISALPHA(ch) .OR. ISDIGIT(ch) .OR. ch $ "_-" I++ ch := SUBSTR(pat,I,1) ENDDO tmp := URLEncode(XTOC(vars[HASHSTR(UPPER(SUBSTR(pat,qpos+1,I-qpos-1)))])) pat := STUFF(pat,qpos,I-qpos,tmp) ENDDO ENDIF DO WHILE (qpos := AT("@",pat)) != 0 ret += SUBSTR(pat,1,qpos-1) fpos := qpos+1 DO WHILE SUBSTR(pat,fpos,1) != "." fpos++ ENDDO r := rs[HASHSTR(UPPER(SUBSTR(pat,qpos+1,fpos-qpos-1)))] data := r:Read() I := fpos+1 ch := SUBSTR(pat,I,1) DO WHILE ISALPHA(ch) .OR. ISDIGIT(ch) .OR. ch $ "_-" I++ ch := SUBSTR(pat,I,1) ENDDO tmp := SUBSTR(pat,fpos+1,I-fpos-1) IF ISALPHA(tmp) fval := data[HASHSTR(UPPER(tmp))] ELSE fval := data[HASHSTR(UPPER(r:FieldName(VAL(tmp)+1)))] ENDIF IF !expr .OR. VALTYPE(fval)=="N" ret += XTOC(fval) ELSE ret += '"'+XTOC(fval)+'"' ENDIF pat := SUBSTR(pat,I) ENDDO ret += pat pat := ret ret := "" DO WHILE (qpos := AT("#",pat)) != 0 ret += SUBSTR(pat,1,qpos-1) fpos := qpos+1 DO WHILE SUBSTR(pat,fpos,1) != "." fpos++ ENDDO r := rs[HASHSTR(UPPER(SUBSTR(pat,qpos+1,fpos-qpos-1)))] data := r:Read() I := fpos+1 ch := SUBSTR(pat,I,1) DO WHILE ISALPHA(ch) .OR. ISDIGIT(ch) .OR. ch $ "_-" I++ ch := SUBSTR(pat,I,1) ENDDO tmp := SUBSTR(pat,fpos+1,I-fpos-1) IF ISALPHA(tmp) ret += URLEncode(XTOC(data[HASHSTR(UPPER(tmp))])) ELSE ret += URLEncode(XTOC(data[HASHSTR(UPPER(r:FieldName(VAL(tmp)+1)))])) ENDIF pat := SUBSTR(pat,I) ENDDO ret += pat ret := STRTRAN(ret,CHR(1),"$") ret := STRTRAN(ret,CHR(2),"@") ret := STRTRAN(ret,CHR(3),"#") RETURN ret FUNCTION ParseArgs(args,leftquotes) LOCAL terms := ARRAY(0) LOCAL len := LEN(args) LOCAL I LOCAL isquote := .F. LOCAL termbegin := 0 LOCAL termend := 0 LOCAL ch LOCAL tmp LOCAL wordbegin := 1 LOCAL bb := 1 LOCAL ee := -1 IF leftquotes != NIL .AND. leftquotes bb := 0 ee := 1 ENDIF FOR I:=1 TO len ch := SUBSTR(args,I,1) IF isquote IF ch=='"' .AND. SUBSTR(args,I-1,1) != "\" isquote := .F. AADD(terms,SUBSTR(args,wordbegin+bb,I-wordbegin+ee)) I++ DO WHILE I < len .AND. SUBSTR(args,I,1) == " " I++ ENDDO wordbegin := I I-- ENDIF ELSE IF ch=='"' tmp := ALLTRIM(SUBSTR(args,wordbegin,I-wordbegin)) IF tmp != "" AADD(terms,tmp) ENDIF isquote := .T. wordbegin := I ELSEIF ch==" " tmp := ALLTRIM(SUBSTR(args,wordbegin,I-wordbegin)) IF tmp != "" AADD(terms,ALLTRIM(SUBSTR(args,wordbegin,I-wordbegin))) ENDIF DO WHILE I < len .AND. SUBSTR(args,I,1) == " " I++ ENDDO wordbegin := I I-- ENDIF ENDIF NEXT tmp := ALLTRIM(SUBSTR(args,wordbegin)) IF tmp != "" AADD(terms,tmp) ENDIF RETURN terms FUNCTION ParseExpr(args) LOCAL ret := "" LOCAL terms LOCAL I LOCAL tmp args := ParseFields(args,.T.) terms := ParseArgs(args,.T.) FOR I:=1 TO LEN(terms) ParseColon(terms,I) NEXT args := STRTRAN(args,"\$",CHR(1)) args := STRTRAN(args,"\@",CHR(2)) args := STRTRAN(args,"\#",CHR(3)) FOR I:=1 TO LEN(terms) IF terms[I] != NIL IF LEFT(terms[I],1) != '"' tmp := STRTRAN(terms[I],"&&"," .AND. ") tmp := STRTRAN(tmp,"&"," .AND. ") tmp := STRTRAN(tmp,"||"," .OR. ") tmp := STRTRAN(tmp,"|"," .OR. ") tmp := STRTRAN(tmp,"$","vars:") ret += tmp + " " ELSE tmp := STRTRAN(terms[I],'\"','"+CHR(34)+"') tmp := STRTRAN(tmp,"\t",'"+CHR(9)+"') tmp := STRTRAN(tmp,"\n",'"+CHR(10)+"') ret += tmp + " " ENDIF ENDIF NEXT ret := STRTRAN(ret,CHR(1),"$") ret := STRTRAN(ret,CHR(2),"@") ret := STRTRAN(ret,CHR(3),"#") RETURN ret PROCEDURE ParseColon(terms,I) LOCAL string LOCAL pattern IF terms[I] != NIL .AND. LTRIM(terms[I]) == ":" .AND.; I > 1 .AND. I < LEN(terms) string := terms[I-1] string := SUBSTR(string,2,LEN(string)-2) pattern := terms[I+1] pattern := SUBSTR(pattern,2,LEN(pattern)-2) terms[I-1] := NIL terms[I+1] := NIL terms[I] := "Regul("+'"'+pattern+'"'+","+'"'+string+'"'+")" ENDIF RETURN FUNCTION Regul(pattern,string) LOCAL reg := ARRAY(0) IF SEARCH(pattern,string,reg) RETURN reg[1][1] ENDIF RETURN 0 FUNCTION DoEval(args) LOCAL ret LOCAL bl LOCAL tmp LOCAL typ bl := &("{|| "+args+"}") tmp := EVAL(bl) typ := VALTYPE(tmp) IF typ == "C"; ret := tmp ELSEIF typ == "N"; ret := LTRIM(STR(tmp)) ELSEIF typ == "D"; ret := DTOC(tmp) ELSEIF typ == "L"; ret := IF(tmp,"1","0") ELSE; ret := "---"; ENDIF RETURN ret PROCEDURE ParseParameters(pars) LOCAL pos LOCAL tmp LOCAL var pars := STRTRAN(pars,"+"," ") URLDecode(@pars) DO WHILE (pos := AT("&",pars)) != 0 tmp := ALLTRIM(SUBSTR(pars,1,pos-1)) pos := AT("=",tmp) var := SUBSTR(tmp,pos+1) var := IF(LEN(var)==0,NIL,var) var := IF(var=="---",NIL,var) IF var != NIL .AND. ISDIGIT(var) var := VAL(var) ENDIF vars[HASHSTR(UPPER(SUBSTR(tmp,1,pos-1)))] := var pars := SUBSTR(pars,LEN(tmp)+2) ENDDO tmp := pars pos := AT("=",tmp) var := SUBSTR(tmp,pos+1) var := IF(LEN(var)==0,NIL,var) var := IF(var=="---",NIL,var) IF var != NIL .AND. ISDIGIT(var) var := VAL(var) ENDIF vars[HASHSTR(UPPER(SUBSTR(tmp,1,pos-1)))] := var RETURN FUNCTION URLDecode(s) LOCAL pos DO WHILE (pos := AT("%",s)) != 0 s := STUFF(s,pos,3,CHR(CTON(SUBSTR(s,pos+1,2),16))) ENDDO s := STRTRAN(s,"+"," ") RETURN s FUNCTION URLEncode(s) LOCAL I := 1 LOCAL ch LOCAL ret := "" LOCAL len := LEN(s) FOR I:=1 TO len ch := SUBSTR(s,I,1) IF ch == " " ret += "+" ELSEIF ASC(ch) > 32 .AND. ASC(ch) < 127 ret += ch ELSE ret += "%"+NTOC(ASC(ch),16) ENDIF NEXT RETURN ret