1. foreach routine
- Posted by duke normandin <dnormandin at bsdrocksperlrolls.com> Dec 21, 2006
- 741 views
Hi... Where are we at on this issue? I searched/read the forum archives on this issue last night. Any conclusions / plans? I ask because I can't believe that it wasn't included (and some others) right from the onset. In the "Euphoria Reference Manual" Part I-Section 2, it states: "Euphoria data structures are almost infinitely flexible." Further down, "Not only can a Euphoria program easily represent all conventional data structures but you can create very useful, flexible structures that would be extremely hard to declare in a conventional language." That may be true, but what good is all that if you can't get at / manipulate them easily? IMHO, sequences are *so huge* in Euphoria that we should scrap some of the functions that are supported but perhaps rarely used, in favor of beefing up "sequence support". In the meantime, anybody ever come across a "foreach" C function that could be called from Euphoria? Later... -- duke
2. Re: foreach routine
- Posted by c.k.lester <euphoric at cklester.com> Dec 21, 2006
- 682 views
FMI, what is the benefit of a foreach statement vs. for x = y to z? for i=1 to length(some_list) do call_func(rtn, {some_list[i], d}) end for for each list in some_list do call_func(rtn, {list, d}) end for Would there be a performance benefit on the backend?
3. Re: foreach routine
- Posted by Derek Parnell <ddparnell at bigpond.com> Dec 21, 2006
- 691 views
- Last edited Dec 22, 2006
duke normandin wrote: > > Hi... > > Where are we at on this issue? Here is a first cut at an interim solution...
-- foreach.e -- Extended version. Covers the full functionality. --/func every_item(pTheList, pRID, pData, pStart, pEnd, pSpan) --/desc Process each specified item in the list --/ret SEQUENCE: If no errors, a 4-element sequence; -- [1] = 0 (zero) -- [2] = 0 (if pRID sees each item) -- = integer (whatever pRID returned to end the processing) -- [3] = The index of the last item processed. -- [4] = The (possibly updated) list. -- If errors, a 2-element sequence; -- [1] = Error code: -- 1 => The supplied low index is < 1 -- 2 => The supplied low index is > list length -- 3 => The supplied high index is < 1 -- 4 => The supplied high index is > list length -- 5 => The supplied routine id is invalid -- [2] = The parameter in error. -- -- This function calls the routine id /i(pRID) for each of the items -- requested in the list /i(pTheList). The range and direction is -- specified by /i(pStart) and /i(pEnd). /i(pStart) is the index -- of the first item to be processed and /i(pEnd) is the index -- of the last item to be processed. If /i(pStart) is higher than -- /i(pEnd) then the items are processed in right-to-left order -- otherwise they are processed in left-to-right order. /n -- -- The /i(pSpan) parameter specifies the 'gap' between successive -- items to be processed. To process each item use 1 as the span, to -- process every second item use 2, etc... /n -- -- The /i(pRID) parameter is a routine id of a caller defined function -- which is called for each item processed. It is passed three parameters: -- [1] => The index of the item being processed. -- [2] => The value of the item being processed. -- [3] => The /i(pData) parameter. This can be any object. -- The routine must return either a single integer or a one-element -- sequence. If it returns a 0 (zero) then next item is processed. If -- it returns a non-zero integer, the processing of items is stopped. -- If it returns a sequence, the first element is used to replace the -- item just processed in the list. -- -- Example: --/code -- sequence res -- function showit(integer pIdx, object pItem, object pExtra) -- printf(1, "%d: %s\n", {pIdx, pItem}) -- if pItem = pExtra then return 1 end if -- return {pItem - ('A' - 'a')} -- end function -- -- res = every_item("ABCDEF", routine_id("showit"), 'D', 2, 5, 1) -- printf(1, "%d %d %d %s\n", res) --/endcode ---------------------------------------------------------- global function every_item(sequence pTheList, integer pRID, object pData, integer pStart, integer pEnd, integer pSpan) ---------------------------------------------------------- integer lDir object lRes integer lLastI integer lLow integer lHigh if length(pTheList) = 0 then return {0,0,0, pTheList} end if if pStart > pEnd then lDir = -1 lLow = pEnd lHigh = pStart else lDir = 1 lHigh = pEnd lLow = pStart end if if lLow < 1 then return {1, lLow} end if if lLow > length(pTheList) then return {2, lLow} end if if lHigh < 1 then return {3, lHigh} end if if lHigh > length(pTheList) then return {4, lHigh} end if if pRID < 0 then return {5, pRID} end if lRes = 0 for i = pStart to pEnd by lDir * pSpan do lLastI = i lRes = call_func(pRID, {i, pTheList[i], pData}) if integer(lRes) then if lRes != 0 then exit end if else pTheList[i] = lRes[1] end if end for return {0, lRes, lLastI, pTheList} end function --/func foreach(pTheList, pRID) --/desc Process every item in the list, from left to right. --/ret SEQUENCE: If no errors, a 4-element sequence; -- [1] = 0 (zero) -- [2] = 0 (if pRID sees each item) -- = integer (whatever pRID returned to end the processing) -- [3] = The index of the last item processed. -- [4] = The (possibly updated) list. -- If errors, a 2-element sequence; -- [1] = 5 (The supplied routine id is invalid) -- [2] = The pRID value. -- -- This function calls the routine id /i(pRID) for each of the items -- in the list /i(pTheList). They are processed in left-to-right order. /n -- -- The /i(pRID) parameter is a routine id of a caller defined function -- which is called for each item processed. It is passed three parameters: -- [1] => The index of the item being processed. -- [2] => The value of the item being processed. -- [3] => 0 -- The routine must return either a single integer or a one-element -- sequence. If it returns a 0 (zero) then next item is processed. If -- it returns a non-zero integer, the processing of items is stopped. -- If it returns a sequence, the first element is used to replace the -- item just processed in the list. -- -- Example: --/code -- sequence res -- function showit(integer pIdx, object pItem, object pExtra) -- printf(1, "%d: %s\n", {pIdx, pItem}) -- if pItem = 'D' then return 1 end if -- return {pItem - ('A' - 'a')} -- end function -- -- res = foreach("ABCDEF", routine_id("showit")) -- printf(1, "%d %d %d %s\n", res) --/endcode ---------------------------------------------------------- global function foreach(sequence pTheList, integer pRID) ---------------------------------------------------------- return every_item(pTheList, pRID, 0, 1, length(pTheList), 1) end function --/func foreach_reverse(pTheList, pRID) --/desc Process every item in the list, from right to left. --/ret SEQUENCE: If no errors, a 4-element sequence; -- [1] = 0 (zero) -- [2] = 0 (if pRID sees each item) -- = integer (whatever pRID returned to end the processing) -- [3] = The index of the last item processed. -- [4] = The (possibly updated) list. -- If errors, a 2-element sequence; -- [1] = 5 (The supplied routine id is invalid) -- [2] = The pRID value. -- -- This function calls the routine id /i(pRID) for each of the items -- in the list /i(pTheList). They are processed in right-to-left order. /n -- -- The /i(pRID) parameter is a routine id of a caller defined function -- which is called for each item processed. It is passed three parameters: -- [1] => The index of the item being processed. -- [2] => The value of the item being processed. -- [3] => 0 -- The routine must return either a single integer or a one-element -- sequence. If it returns a 0 (zero) then next item is processed. If -- it returns a non-zero integer, the processing of items is stopped. -- If it returns a sequence, the first element is used to replace the -- item just processed in the list. -- -- Example: --/code -- sequence res -- function showit(integer pIdx, object pItem, object pExtra) -- printf(1, "%d: %s\n", {pIdx, pItem}) -- if pItem = 'D' then return 1 end if -- return {pItem - ('A' - 'a')} -- end function -- -- res = foreach_reverse("ABCDEF", routine_id("showit")) -- printf(1, "%d %d %d %s\n", res) --/endcode ---------------------------------------------------------- global function foreach_reverse(sequence pTheList, integer pRID) ---------------------------------------------------------- return every_item(pTheList, pRID, 0, length(pTheList), 1, 1) end function
-- Derek Parnell Melbourne, Australia Skype name: derek.j.parnell
4. Re: foreach routine
- Posted by duke normandin <dnormandin at bsdrocksperlrolls.com> Dec 21, 2006
- 683 views
- Last edited Dec 22, 2006
c.k.lester wrote: > > FMI, what is the benefit of a foreach statement vs. for x = y to z? > > for i=1 to length(some_list) do > call_func(rtn, {some_list[i], d}) > end for > > for each list in some_list do > call_func(rtn, {list, d}) > end for > > Would there be a performance benefit on the backend? Hi... I'm too new to euphoria code to venture even a guess, never mind an opinion. Coming from Perl, I'm trying to emulate the following: read(STDIN, $buffer, $ENV{CONTENT_LENGTH}); @pairs = split(/&/, $buffer); foreach $pair (@pairs){ ($name, $value) = split(/=/, $pair); blah blah } I'm going to use a `for' loop to `getc' CONTENT_LENGTH amount of chars and shove them into `sequence buffer'. I've got a split routine that I think will work. I just need to walk through the 'sequence pairs' one at a time, split again and stash each in there own sequence. Like I said in a prior post -- sequences are so HUGE of a deal in Euphoria that the support for them ought to be a non-issue. As it stands now, the hoops that I *think* I'll have to jump through to do anything with sequences are bizarre. Maybe this is *one* of the issues that needs to be fixed in order to make a powerful language that much more attractive and efficient to use. BTW... TP80-cgilib.e ! Still available?? Later.... -- duke
5. Re: foreach routine
- Posted by duke normandin <dnormandin at bsdrocksperlrolls.com> Dec 22, 2006
- 680 views
Derek Parnell wrote: > > duke normandin wrote: > > > > Hi... > > > > Where are we at on this issue? > > Here is a first cut at an interim solution... > }}} <eucode> > -- foreach.e [snip and saved] Nice Code! and well documented! The Euphoria community may just put you in the Hall-of-Fame you know ;) Like I said in another post, I basically trying to emulate Perl's `foreach' routine, as in: foreach $pair (@pairs){ do something } where @pairs is a simple array (no sweat! => a "U4ia" sequence) $pair is a variable used in "list" context so it gets a string So in Perl, what happens here is that the foreach routine is fed an array (sequence), it walks through it and returns each element one at a time. This element gets shoved into $pair (in this example). $pair is then massaged whichever way you need. In Lua, they have `foreach' to walk through a hash, and `foreachi' to walk through an "indexed" array. Slick too! -- duke
6. Re: foreach routine
- Posted by Derek Parnell <ddparnell at bigpond.com> Dec 22, 2006
- 692 views
duke normandin wrote: > Like I said in another post, I basically trying to emulate Perl's `foreach' > routine, as in: > foreach $pair (@pairs){ > do something > } > > where @pairs is a simple array (no sweat! => a "U4ia" sequence) > $pair is a variable used in "list" context so it gets a string
include foreach.e function do_something(integer x, object item, object extra) -- Do something with the item return 0 end function sequence result result = foreach(pairs, routine_id("do_something")) if result[1] = 0 then -- No problems else -- Something went wrong end if
I know about 'foreach' as I use it all the time in the D programming language. D is a bit like a static-typed, object-enabled, compiled Euphoria. http://www.digitalmars.com/d/statement.html#ForeachStatement I also use it in the Progress 4GL (OpenEdge) which is a proprietary database language. -- Derek Parnell Melbourne, Australia Skype name: derek.j.parnell
7. Re: foreach routine
- Posted by ags <eu at 531pi.co.nz> Dec 22, 2006
- 688 views
duke normandin wrote: > > Coming from Perl, I'm trying to emulate the following: > > read(STDIN, $buffer, $ENV{CONTENT_LENGTH}); > @pairs = split(/&/, $buffer); > foreach $pair (@pairs){ > ($name, $value) = split(/=/, $pair); > blah > blah > } BTW you will probably miss tightly integrated regular expression too. I've been meaning to wrap the perlre.dll for a while now but it's a bit of a headache everytime I look at the API :) That and the fact that you can't just drop in a RE in things like split, unpack, etc. But I use Perl and Euphoria equally as much... Perl for CGI and general scripting for server stuff and Euphoria for Windows programming and general scripting on Windows. Gary
8. Re: foreach routine
- Posted by don cole <doncole at pacbell.net> Dec 22, 2006
- 683 views
Hi and welcome to Euphoria Duke, I don't know anything about Perl, C, other languages etc... > > > > Coming from Perl, I'm trying to emulate the following: > > > > read(STDIN, $buffer, $ENV{CONTENT_LENGTH}); > > @pairs = split(/&/, $buffer); > > foreach $pair (@pairs){ > > ($name, $value) = split(/=/, $pair); > > blah > > blah > > } >
include strlist.e I put this in my stock include files (that come with Euphoria setup),
list=split(line,'/') this will make a lot of little sequences out of one big one.
Don Cole }}}
9. Re: foreach routine
- Posted by duke normandin <dnormandin at bsdrocksperlrolls.com> Dec 22, 2006
- 673 views
ags wrote: > > duke normandin wrote: > > > > Coming from Perl, I'm trying to emulate the following: > > > > read(STDIN, $buffer, $ENV{CONTENT_LENGTH}); > > @pairs = split(/&/, $buffer); > > foreach $pair (@pairs){ > > ($name, $value) = split(/=/, $pair); > > blah > > blah > > } > > BTW you will probably miss tightly integrated regular expression too. I've > been meaning to wrap the perlre.dll for a while now but it's a bit of a > headache > everytime I look at the API :) > > That and the fact that you can't just drop in a RE in things like split, > unpack, > etc. > > But I use Perl and Euphoria equally as much... Perl for CGI and general > scripting > for server stuff and Euphoria for Windows programming and general scripting > on Windows. My gut feeling tells me that U4ia can do CGI and various backend stuff OK. The issue for me is how efficiently? So far, lots of hoops to jump through to get simple things done. However I'm serious about U4ia. I'm still reading the reference manual. In section 2.3 it states: "Programming in Euphoria is based entirely on creating and manipulating flexible, dynamic sequences. Sequences are IT - there are no other structures to learn" Nice --- but hardly no tools to do the above "manipulating" of sequences. Its sad! -- duke
10. Re: foreach routine
- Posted by duke normandin <dnormandin at bsdrocksperlrolls.com> Dec 22, 2006
- 669 views
don cole wrote: > > > Hi and welcome to Euphoria Duke, > > I don't know anything about Perl, C, other languages etc... > > > > > > Coming from Perl, I'm trying to emulate the following: > > > > > > read(STDIN, $buffer, $ENV{CONTENT_LENGTH}); > > > @pairs = split(/&/, $buffer); > > > foreach $pair (@pairs){ > > > ($name, $value) = split(/=/, $pair); > > > blah > > > blah > > > } > > > }}} <eucode> > > include strlist.e > -- I put this in my stock include files (that come with Euphoria setup), > -- even though you must download it separtly (in the acrchives). > > list=split(line,'/') --this will make a lot of little sequences out of one > big one. I might have to hunt you down like a dog and buy you a cup of coffee (or something) ;) Thanks! -- duke
11. Re: foreach routine
- Posted by Derek Parnell <ddparnell at bigpond.com> Dec 22, 2006
- 697 views
duke normandin wrote: > > Coming from Perl, I'm trying to emulate the following: > > read(STDIN, $buffer, $ENV{CONTENT_LENGTH}); > @pairs = split(/&/, $buffer); > foreach $pair (@pairs){ > ($name, $value) = split(/=/, $pair); > blah > blah > } These might help ...
-- split.e --/func split_char(pDelim, pText) --/desc This will create subsequences of pText which is delimited by pDelim --/ret SEQUENCE: A set of subsequences. --This looks for the delimiter in pText and breaks it up into subsequences --at the delimiter boundaries. -- -- Example: --/code -- res = split_char('=', "age=59") -- -- Returns {"age", "59"} -- res = split_char(';', "abc;defg;hi;jkl;;qwerty") -- -- Returns {"abc","defg","hi","jkl","","qwerty"} --/endcode global function split_char(integer pDelim, sequence pText) sequence lResult integer lPos integer lNewPos lResult = {} lNewPos = 1 lPos = find(pDelim, pText) while lPos > 0 do lResult = append(lResult, pText[lNewPos..lPos-1]) lNewPos = find(pDelim, pText[lPos+1..$]) if lNewPos > 0 then lPos += lNewPos lNewPos = lPos - lNewPos + 1 else lNewPos = lPos+1 lPos = 0 end if end while lResult = append(lResult, pText[lNewPos..$]) return lResult end function --/func split(pDelim, pText) --/desc This will create nested subsequences of pText which is delimited by pDelim --/ret SEQUENCE: A set of nested subsequences. --/i(pDelim) is a set of one-character delimiters. /i(pText) is recursively -- split based on successive delimiters in /i(pDelim). -- -- Example: --/code -- res = split("&=", "dude=duke&age=59&style=kewl") -- -- Returns {{"dude","duke"}, {"age", "59"}, {"style", "kewl"}} --/endcode -- --However, if /i(pDelim) is either an integer or a single character sequence -- the result is equivalent to the split_char() function. -- --Example: --/code -- res = split('=', "age=59") -- -- Returns {"age", "59"} -- res = split(";", "abc;defg;hi;jkl;;qwerty") -- -- Returns {"abc","defg","hi","jkl","","qwerty"} --/endcode global function split(object pDelim, sequence pText) sequence lResult if integer(pDelim) then return split_char(pDelim, pText) end if lResult = split_char(pDelim[1], pText) if length(pDelim) > 1 then for i = 1 to length(lResult) do lResult[i] = split(pDelim[2..$], lResult[i]) end for end if return lResult end function --/func toKeyValue(pPairs) --/desc Converts the set of paired subsequences into two sequences of keys and values. --/ret SEQUENCE: A 2-element sequence. The first contains a list of keys, the 2nd a list of corresponding values. --The input is assumed to be a list of 2-element (pairs) sequences. The --output is just the pairs rearranged such that the first output subsequence -- is a list of all the keys, and the second output subsequences is -- a list of the corresponding values for those keys. -- --Example: --/code -- res = toKeyValue( {{"dude","duke"}, {"age", "59"}, {"style", "kewl"}} ) -- -- Returns ... -- -- { {"dude", "age", "style"}, {"duke", "59", "kewl"} } --/endcode global function toKeyValue(sequence pPairs) sequence lResult lResult = repeat( repeat({}, length(pPairs)), 2) for i = 1 to length(pPairs) do lResult[1][i] = pPairs[i][1] lResult[2][i] = pPairs[i][2] end for return lResult end function --/func findKeyValue(pKey, pKeyValues, pDefault) --/desc Returns the value associated with the /i(pKey) parameter. --/ret OBJECT: The associated value of the key. --The /i(pKeyValues) parameter must be a 2-element sequence, the --first containing keys and the second containing values for those keys. -- --This looks for the /i(pKey) value in the keys subsequence and when --found returns the corresponding value. If not found, it returns the --supplied /i(pDefault) value. -- --Example: --/code -- sequence x -- x = toKeyValue( split("&=", "dude=duke&age=59&style=kewl") ) -- ? findKeyValue("age", x, -1) -- returns "59" -- ? findKeyValue("dude", x, -1) -- returns "duke" -- ? findKeyValue("rabbit", x, -1) -- returns -1 -- ? findKeyValue("style", x, -1) -- returns "kewl" --/endcode global function findKeyValue(object pKey, sequence pKeyValues, object pDefault) integer lPos lPos = find(pKey, pKeyValues[1]) if lPos > 0 then return pKeyValues[2][lPos] else return pDefault end if end function
-- Derek Parnell Melbourne, Australia Skype name: derek.j.parnell
12. Re: foreach routine
- Posted by Chris Bensler <bensler at nt.net> Dec 22, 2006
- 673 views
duke normandin wrote: > > My gut feeling tells me that U4ia can do CGI and various backend stuff OK. > The issue for me is how efficiently? So far, lots of hoops to jump through > to get simple things done. However I'm serious about U4ia. I'm still reading > the > reference manual. In section 2.3 it states: Euphoria is capable of most anything. It's a double-edged sword. If you are looking for a specialty language, then Eu is not for you, but otherwise it does a very good job at being a general programming language. Many things seem to be more tedious in Euphoria because it's so general and it doesn't offer a gamut of 'candy' features that make things like CGI convenient. You won't find much candy in Euphoria, and that's good. There is plenty of libraries to make it simpler though. The main issue with Eu is that because the community is so small compared to other popular languages, there isn't a very large selection of libraries available and many are not fully developed. CGI for example, is an area that has not been entirely addressed by the community yet. Support for CGI in Eu is still in it's infancy. You can find several libraries for CGI in the archives, but you certainly won't find it as convenient or as full-featured as perl or php, which are more designed for the task. Having said that, it's most definitely capable of CGI. The Euforum and most of the functionality of the RDS website is powered by Eu. Several others have made Euphoria driven websites as well, including myself. I've even written a special tool that allows Eu to work inline in html, like PHP or SSI. > "Programming in Euphoria is based entirely on creating and manipulating > flexible, dynamic sequences. Sequences are IT - there are no other > structures to learn" > > Nice --- but hardly no tools to do the above "manipulating" of sequences. > Its sad! What kind of tools? Most things that people think they need are nothing more than convenience features, or are due to trying to make Eu like some other language that they are more accustomed to. You are right that it does need some more functionality for dealing with sequences, but it's probably not the kinds of features you are thinking of. Chris Bensler ~ The difference between ordinary and extraordinary is that little extra ~ http://empire.iwireweb.com - Empire for Euphoria
13. Re: foreach routine
- Posted by Jules Davy <jdavy at dsl.pipex.com> Dec 22, 2006
- 688 views
> Nice --- but hardly no tools to do the above "manipulating" of sequences. > Its sad! > -- > duke take a look at Ricardo Forno's general functions library, I find it very useful for sequence splicing and dicing.
14. Re: foreach routine
- Posted by Chris Bensler <bensler at nt.net> Dec 22, 2006
- 673 views
duke normandin wrote: > > c.k.lester wrote: > > > > FMI, what is the benefit of a foreach statement vs. for x = y to z? I've considered foreach in the past for various language designs and preprocessor features. I could see no real gain and it creates issues when one also wants access to the iterator in a foreach loop, which is often enough that a foreach construct is too specific to be a good addition to Euphoria. > > Would there be a performance benefit on the backend? Not likely, possibly a very tiny one. > Hi... > > I'm too new to euphoria code to venture even a guess, never mind an opinion. > Coming from Perl, I'm trying to emulate the following: > > read(STDIN, $buffer, $ENV{CONTENT_LENGTH}); > @pairs = split(/&/, $buffer); > foreach $pair (@pairs){ > ($name, $value) = split(/=/, $pair); > blah > blah > } > > I'm going to use a `for' loop to `getc' CONTENT_LENGTH amount of chars and > shove them into `sequence buffer'. > > I've got a split routine that I think will work. > > I just need to walk through the 'sequence pairs' one at a time, split > again and stash each in there own sequence. > > Like I said in a prior post -- sequences are so HUGE of a deal in Euphoria > that the support for them ought to be a non-issue. As it stands now, the hoops > that I *think* I'll have to jump through to do anything with sequences are > bizarre. Maybe this is *one* of the issues that needs to be fixed in order > to make a powerful language that much more attractive and efficient to use. > > BTW... TP80-cgilib.e ! Still available?? Later.... > -- > duke Here is some Eu code to do what you want (split() function sold separately) Warning: code is not tested, consider it a guideline only
include get.e -- needed for get_bytes() and value() sequence pairs,pair sequence name,data -- ('value' is a standard routine name, so I will use 'data' instead) sequence buffer object tmp -- temporary/intermediate variable tmp = getenv("CONTENT_LENGTH") if atom(tmp) then -- CONTENT_LENGTH was not found else tmp = value(tmp) if tmp[1] != GET_SUCCESS then -- value() failed else buffer = get_bytes(STDIN,tmp[2]) pairs = split(buffer,'&') for i = 1 to length(pairs) do pair = pairs[i] tmp = split(pair,'=') name = tmp[1] data = tmp[2] -- blah -- blah end for end if end if
Chris Bensler ~ The difference between ordinary and extraordinary is that little extra ~ http://empire.iwireweb.com - Empire for Euphoria
15. Re: foreach routine
- Posted by duke normandin <dnormandin at bsdrocksperlrolls.com> Dec 22, 2006
- 690 views
Derek Parnell wrote: > > duke normandin wrote: > > > > Coming from Perl, I'm trying to emulate the following: > > > > read(STDIN, $buffer, $ENV{CONTENT_LENGTH}); > > @pairs = split(/&/, $buffer); > > foreach $pair (@pairs){ > > ($name, $value) = split(/=/, $pair); > > blah > > blah > > } > > These might help ... > }}} <eucode> > -- split.e [code snipped] What can I say but *awesome* !! -- and -- thanks a bunch. I've got enough code to study now so that I'll either "Get it!" or I should imigrate "down-under" and chase "roos" for a living. ;) Later... -- duke
16. Re: foreach routine
- Posted by duke normandin <dnormandin at bsdrocksperlrolls.com> Dec 22, 2006
- 661 views
Chris Bensler wrote: > > Here is some Eu code to do what you want (split() function sold separately) > Warning: code is not tested, consider it a guideline only > > }}} <eucode> > include get.e -- needed for get_bytes() and value() > sequence pairs,pair > sequence name,data -- ('value' is a standard routine name, so I will use > 'data' instead) > sequence buffer > object tmp -- temporary/intermediate variable > > tmp = getenv("CONTENT_LENGTH") > if atom(tmp) then > -- CONTENT_LENGTH was not found > else > tmp = value(tmp) > if tmp[1] != GET_SUCCESS then > -- value() failed > else > buffer = get_bytes(STDIN,tmp[2]) > pairs = split(buffer,'&') > for i = 1 to length(pairs) do > pair = pairs[i] > tmp = split(pair,'=') > name = tmp[1] > data = tmp[2] > -- blah > -- blah > end for > end if > end if > </eucode> {{{ Thanks Chris.... Why am I not getting this? tmp = getenv("CONTENT_LENGTH") if atom(tmp) then CONTENT_LENGTH -- duke
17. Re: foreach routine
- Posted by duke normandin <dnormandin at bsdrocksperlrolls.com> Dec 22, 2006
- 679 views
Jules Davy wrote: > > > Nice --- but hardly no tools to do the above "manipulating" of sequences. > > Its sad! > > -- > > duke > > take a look at Ricardo Forno's general functions library, I find it very > useful > for sequence splicing and dicing. Thanks! I'll have a look! -- duke
18. Re: foreach routine
- Posted by duke normandin <dnormandin at bsdrocksperlrolls.com> Dec 22, 2006
- 679 views
duke normandin wrote: > > Chris Bensler wrote: > > > > > Here is some Eu code to do what you want (split() function sold separately) > > Warning: code is not tested, consider it a guideline only > > > > }}} <eucode> > > include get.e -- needed for get_bytes() and value() > > sequence pairs,pair > > sequence name,data -- ('value' is a standard routine name, so I will use > > 'data' instead) > > sequence buffer > > object tmp -- temporary/intermediate variable > > > > tmp = getenv("CONTENT_LENGTH") > > if atom(tmp) then > > -- CONTENT_LENGTH was not found > > else > > tmp = value(tmp) > > if tmp[1] != GET_SUCCESS then > > -- value() failed > > else > > buffer = get_bytes(STDIN,tmp[2]) > > pairs = split(buffer,'&') > > for i = 1 to length(pairs) do > > pair = pairs[i] > > tmp = split(pair,'=') > > name = tmp[1] > > data = tmp[2] > > -- blah > > -- blah > > end for > > end if > > end if > > </eucode> {{{ > > Thanks Chris.... > > Why am I not getting this? > > tmp = getenv("CONTENT_LENGTH") > if atom(tmp) then > > CONTENT_LENGTH > -- > duke I hit the send key too quickly -- my bad! What I was going to say is: CONTENT_LENGTH will either be empty or contain the number of chars/bytes sent. So if atom(tmp) then checks to see if getenv() returned a number, right? If true, we have that many chars/bytes. If 0 CONTENT_LENGTH was empty. Do I need another cup of coffee? or something? It seems that the logic is backwards. TIA... (now hit the send button, duke) -- duke
19. Re: foreach routine
- Posted by Chris Bensler <bensler at nt.net> Dec 22, 2006
- 699 views
duke normandin wrote: > > What I was going to say is: > > CONTENT_LENGTH will either be empty or contain the number of chars/bytes > sent. So > if atom(tmp) then > > checks to see if getenv() returned a number, right? If true, we have that > many chars/bytes. If 0 CONTENT_LENGTH was empty. > > Do I need another cup of coffee? or something? It seems that the logic > is backwards. TIA... (now hit the send button, duke) > -- > duke The getenv() routine will return -1 if the environment variable CONTENT_LENGTH doesn't exist. If it does exist, a string will be returned. Since CONTENT_LENGTH is supposed to be a number, we use value() to convert the string to a number. value() also returns a sequence of length = 2, where the 1st element is an error code and the 2nd is the actual number value. Hence the 2 error checks. HTH Chris Bensler ~ The difference between ordinary and extraordinary is that little extra ~ http://empire.iwireweb.com - Empire for Euphoria
20. Re: foreach routine
- Posted by "Greg Haberek" <ghaberek at gmail.com> Dec 22, 2006
- 704 views
> Why am I not getting this? > > tmp = getenv("CONTENT_LENGTH") You're probably running this from a command line and the server. Server environment variables are born when the server calls your CGI app, and they die when it finiishes. ~Greg
21. Re: foreach routine
- Posted by cklester <cklester at yahoo.com> Dec 22, 2006
- 684 views
duke normandin wrote: > My gut feeling tells me that U4ia can do CGI and various backend stuff OK. > The issue for me is how efficiently? So far, lots of hoops to jump through > to get simple things done. I've not really had to jump through any "hoops." Using some libraries freely available in the archive, plus building a little bit of my own, I've got several web sites being served by Euphoria. I've built a content management system called Building Blocks CMS. It has made development of dynamic web sites pretty easy. I'm even incorporating Ajax functionality now. Cool stuff! -=ck "Programming in a state of Euphoria." http://www.cklester.com/euphoria/
22. Re: foreach routine
- Posted by duke normandin <dnormandin at bsdrocksperlrolls.com> Dec 22, 2006
- 681 views
- Last edited Dec 23, 2006
Chris Bensler wrote: > > duke normandin wrote: > > > > What I was going to say is: > > > > CONTENT_LENGTH will either be empty or contain the number of chars/bytes > > sent. So > > if atom(tmp) then > > > > checks to see if getenv() returned a number, right? If true, we have that > > many chars/bytes. If 0 CONTENT_LENGTH was empty. > > > > Do I need another cup of coffee? or something? It seems that the logic > > is backwards. TIA... (now hit the send button, duke) > > -- > > duke > > The getenv() routine will return -1 if the environment variable CONTENT_LENGTH > doesn't exist. If it does exist, a string will be returned. Are you sure? I've never proven this to myself, but it has always been my understanding that with respect the method=POST, the ENV. VAR. CONTENT_LENGTH would be set to the amount of bytes sent out. THEREFORE, this is why we "read" that many bytes from STDIN, and only that many. So my point is that CONTENT_LENGTH will in one case be a positive number or a -1 -- both atoms. No? The above of course does not apply to method=GET, because in the latter, all the data is stuffed in the ENV. VAR. QUERY_STRING. Here we can check to see if getenv("QUERY_STRING") returns an atom i.e -1, because QUERY_STRING will either contain a string, or will be undefined. -- duke
23. Re: foreach routine
- Posted by Derek Parnell <ddparnell at bigpond.com> Dec 22, 2006
- 699 views
- Last edited Dec 23, 2006
duke normandin wrote: > > Chris Bensler wrote: > > The getenv() routine will return -1 if the environment variable > > CONTENT_LENGTH > > doesn't exist. If it does exist, a string will be returned. > > Are you sure? I've never proven this to myself, but it has always been my > understanding that with respect the method=POST, the ENV. VAR. CONTENT_LENGTH > would be set to the amount of bytes sent out. THEREFORE, this is why we "read" > that many bytes from STDIN, and only that many. So my point is that > CONTENT_LENGTH > will in one case be a positive number or a -1 -- both atoms. No? Yes and no. The Euphoria function getenv() always returns a string if the environment variable exists, and -1 if it doesn't exist. In your case, CONTENT_LENGTH will most likely always be there due to the CGI environment, but when getenv() returns its content, it is a string representation of a number and not the number itself. So if the number of characters to read in from STDIN is 59, getenv("CONTENT_LENGTH") will return "59" and not 59. Thus you have to convert the string "59" to its number form. res = value( "59" ) The value() function always returns a 2-element sequence. The first element is the success/failure code and the second is the converted number. So in this case, value() returns {0,59} where the leading 0 indicates successful conversion occured. So in code ...
object result result = getenv("CONTENT_LENGTH") if sequence(result) then -- a string was returned. result = value(result) if result[1] = 0 then --- a good conversion. readsize = result[2] else --- bad data in string! end if else --- CONTENT_LENGTH doesn't exist end if
> The above of course does not apply to method=GET, because in the latter, all > the data is stuffed in the ENV. VAR. QUERY_STRING. Here we can check to see > if getenv("QUERY_STRING") returns an atom i.e -1, because QUERY_STRING will > either contain a string, or will be undefined. > -- > duke -- Derek Parnell Melbourne, Australia Skype name: derek.j.parnell
24. Re: foreach routine
- Posted by duke normandin <dnormandin at bsdrocksperlrolls.com> Dec 23, 2006
- 670 views
Derek Parnell wrote: > > duke normandin wrote: > > > > Chris Bensler wrote: > > > The getenv() routine will return -1 if the environment variable > > > CONTENT_LENGTH > > > doesn't exist. If it does exist, a string will be returned. > > > > Are you sure? I've never proven this to myself, but it has always been my > > understanding that with respect the method=POST, the ENV. VAR. > > CONTENT_LENGTH > > would be set to the amount of bytes sent out. THEREFORE, this is why we > > "read" > > that many bytes from STDIN, and only that many. So my point is that > > CONTENT_LENGTH > > will in one case be a positive number or a -1 -- both atoms. No? > > Yes and no. The Euphoria function getenv() always returns a string if the > environment > variable exists, and -1 if it doesn't exist. In your case, CONTENT_LENGTH will > most likely always be there due to the CGI environment, but when getenv() > returns > its content, it is a string representation of a number and not the number > itself. > So if the number of characters to read in from STDIN is 59, > getenv("CONTENT_LENGTH") > will return "59" and not 59. Thus you have to convert the string "59" to its > number form. I got it! Damn! I've got to watch the data types more carefully. Not used to it. ;) To recap, getenv returns the atom -1 if the ENV.VAR. is unset OR a string containing whatever. In the case of CONTENT_LENGTH I was expecting an integer. I now know to convert CONTENT_LENGTH *to* an integer. > res = value( "59" ) [snip] I really don't need to do all that testing. What the Perl/PHP etc world has done all this time is: 1. getenv("REQUEST_METHOD") 2. if == "POST" 2.a value_array = value(getenv("CONTENT_LENGTH") 2.b stash get_bytes(0, value_array[2]) 3. if == "GET" 3.a stash getenv("QUERY_STRING") 4. if == "some_bogus_method" 4.a cgi_die("gracefully") 5. amen That is what I want to reproduce in Euphoria come "hell or high water" ;) Once I have the above "stash", then we use your "foreach" and "split" code to massage the FORM[key]=values I love it !! Thanks you all for the mini EU tutorials!! -- duke
25. Re: foreach routine
- Posted by Chris Bensler <bensler at nt.net> Dec 23, 2006
- 691 views
duke normandin wrote: > > Derek Parnell wrote: > > > > duke normandin wrote: > > > > > > Chris Bensler wrote: > > > > The getenv() routine will return -1 if the environment variable > > > > CONTENT_LENGTH > > > > doesn't exist. If it does exist, a string will be returned. > > > > > > Are you sure? I've never proven this to myself, but it has always been my > > > understanding that with respect the method=POST, the ENV. VAR. > > > CONTENT_LENGTH > > > would be set to the amount of bytes sent out. THEREFORE, this is why we > > > "read" > > > that many bytes from STDIN, and only that many. So my point is that > > > CONTENT_LENGTH > > > will in one case be a positive number or a -1 -- both atoms. No? > > > > Yes and no. The Euphoria function getenv() always returns a string if the > > environment > > variable exists, and -1 if it doesn't exist. In your case, CONTENT_LENGTH > > will > > most likely always be there due to the CGI environment, but when getenv() > > returns > > its content, it is a string representation of a number and not the number > > itself. > > So if the number of characters to read in from STDIN is 59, > > getenv("CONTENT_LENGTH") > > will return "59" and not 59. Thus you have to convert the string "59" to its > > number form. > > I got it! Damn! I've got to watch the data types more carefully. Not used to > it. ;) > To recap, getenv returns the atom -1 if the ENV.VAR. is unset OR a string > containing > whatever. In the case of CONTENT_LENGTH I was expecting an integer. I now know > to > convert CONTENT_LENGTH *to* an integer. > > > res = value( "59" ) > > [snip] > > I really don't need to do all that testing. > > What the Perl/PHP etc world has done all this time is: > > 1. getenv("REQUEST_METHOD") > 2. if == "POST" > 2.a value_array = value(getenv("CONTENT_LENGTH") > 2.b stash get_bytes(0, value_array[2]) > 3. if == "GET" > 3.a stash getenv("QUERY_STRING") > 4. if == "some_bogus_method" > 4.a cgi_die("gracefully") > 5. amen > > That is what I want to reproduce in Euphoria come "hell or high water" ;) > > Once I have the above "stash", then we use your "foreach" and "split" code to > massage the FORM[key]=values > I love it !! Thanks you all for the mini EU tutorials!! > -- > duke Good programming practice is to always trap error conditions whenever you can. I get the impression though, that you meant that you don't want to have to do the error testing all the time. Make a routine that takes care of it for you instead. I use this routine.. This avoids the error by making it default to an empty string. This routine will always return a valid string or "".
global function cgi_getenv(string name) object tmp tmp = getenv(name) if atom(tmp) then return "" end if return tmp end function
Similarly for value(), I have.. This avoids the error by making it default to 0. This always returns the converted number, or 0.
global function get_value(object x) sequence ret ret = value(x) if ret[1] = GET_SUCCESS then return ret[2] else return 0 end if end function
The above routines are not generally a good way to deal with error cases, but for specific purposes such as this situation, it should be fine. Using those two routines, I could make a new routine specifically to return the content_length.. This routine returns the number value of the content length.
global function cgi_content_length() integer len len = cgi_getenv("CONTENT_LENGTH") return get_value(len) end function
And a routine to handle the request method...
global function cgi_request_method() return cgi_getenv("REQUEST_METHOD") end function
For further processing of the POST or QUERY, you will need some code like the following, to convert url-encoded strings to plain text.
function replace_hex(sequence s) sequence f,hex -- find and store the index of all instances of '%' in s f = {} for i = 1 to length(s) do if s[i] = '%' then f &= i end if end for if length(f) then for i = length(f) to 1 by -1 do hex = get_value("#"&s[f[i]+1..f[i]+2]) -- convert the string code to a character code s = s[1..f[i]-1] & hex & s[f[i]+3..length(s)] end for end if return s end function ------------------------------------------------ -- This is the function that you are mostly after -- cgi_parse_request() will convert a url-encoded string to key/value pairs -- in the form of {{key1,key2,...},{val1,val2,...}} -- EG. "firstname=Duke&lastname=Normandin" -- becomes {{"firstname","lastname"},{"Duke","Normandin"}} global function cgi_parse_request(sequence s) s ={ s , {} } s[1] = join(split(s[1],'+'),' ') -- convert '+' to ' ' s[1] = join(split(s[1],'&'),';') -- convert '&' to ';' s[1] = split(s[1],';') if length(s[1]) then s[2] = repeat("",length(s[1])) end if for i = 1 to length(s[1]) do s[1][i] = split(s[1][i],'=') s[1][i][1] = replace_hex(s[1][i][1]) if length(s[1][i]) > 1 then s[2][i] = replace_hex(s[1][i][2]) end if s[1][i] = s[1][i][1] end for return s end function
Here is a routine to handle fetching the post data. It will return a sequence of key/values as described for cgi_parse_request()
global function cgi_get_post() sequence buf integer len len = cgi_content_length() buf = get_bytes(STDIN,len) return cgi_parse_request(buf) end function
Here is the routine to handle QUERY data.
global function cgi_get_query() sequence buf buf = cgi_getenv("QUERY_STRING") return cgi_parse_request(buf) end function
Now you can make a routine to actually do the whole thing for you..
global function cgi_get_request() sequence req req = cgi_request_method() if equal(req,"POST") then return cgi_get_post() elsif equal(req,"GET") then return cgi_get_query() else -- error, invalid request method end if end function
Buene? You may be wondering why the pairs are stored as {key_list,data_list} instead of {{key1,data1},{key2,data2}}. The reason is because it's easier to search for a key that way. EG. sequence pairs integer f pairs = cgi_get_request() f = find("firstname",pairs[1]) if f then puts(STDOUT,"Your firstname is: " & pairs[2][f] & "\n") end if Chris Bensler ~ The difference between ordinary and extraordinary is that little extra ~ http://empire.iwireweb.com - Empire for Euphoria
26. Re: foreach routine
- Posted by Alan Oxley <fizzpop at axemail.co.za> Dec 23, 2006
- 691 views
Hi Duke, I notice the comparisons to Perl. There is no such thing as a "perfect" language - its always a trade off. Euphoria works well for me, its small, very fast, simple but you do need to create functions or even libraries that are perhaps builtin in other languages. Often these have already been coded and are in the archive. Its like reading a manual. While searching for something, you find other things that you will need later. <stirring + punting> Did you know Rob (RDS) once took a bit of Perl written by Larry Wall, converted it to Euphoria and sent that back to Larry... it was faster of course and Larry did not reply - he must have been too busy ;)) </stirring + punting>
27. Re: foreach routine
- Posted by duke normandin <dnormandin at bsdrocksperlrolls.com> Dec 23, 2006
- 668 views
Chris Bensler wrote: > > [snip] > > > > I really don't need to do all that testing. > > > > What the Perl/PHP etc world has done all this time is: > > > > 1. getenv("REQUEST_METHOD") > > 2. if == "POST" > > 2.a value_array = value(getenv("CONTENT_LENGTH") > > 2.b stash get_bytes(0, value_array[2]) > > 3. if == "GET" > > 3.a stash getenv("QUERY_STRING") > > 4. if == "some_bogus_method" > > 4.a cgi_die("gracefully") > > 5. amen > > > > That is what I want to reproduce in Euphoria come "hell or high water" ;) > > > > Once I have the above "stash", then we use your "foreach" and "split" code > > to > > massage the FORM[key]=values > > I love it !! Thanks you all for the mini EU tutorials!! > > -- > > duke > > Good programming practice is to always trap error conditions whenever you can. I agree! But how often you need to trap errors depends on the language you are using and the number of lines of code you need to generate to get something done. > I get the impression though, that you meant that you don't want to have to do > the error testing all the time. Make a routine that takes care of it for you > instead. That's what I meant. As a EU novice, I'm quickly seeing that my coding style and practices *need* to be different than those I was using with Perl and PHP. That said, I've been doing CGI / Web / SQL stuff since 1996 using Perl mostly. I know how the CGI and back-end stuff works!! I just need to learn to do it correctly "the EU way". ;)) Nice collection of functions BTW!! I'm sure they get the job done. Can't wait to put it all together and try it out. Thanks for the input! -- duke
28. Re: foreach routine
- Posted by cklester <cklester at yahoo.com> Dec 23, 2006
- 679 views
duke normandin wrote: > > > Once I have the above "stash", then we use your "foreach" and "split" code to > massage the FORM[key]=values Have you checked out the CGI code available in the archive? I just do this: include cgi.e process_cgi() -- then x = get_key_value("whatever") ...or something close to that. Easy! :) -=ck "Programming in a state of Euphoria." http://www.cklester.com/euphoria/
29. Re: foreach routine
- Posted by duke normandin <dnormandin at bsdrocksperlrolls.com> Dec 23, 2006
- 675 views
cklester wrote: > > duke normandin wrote: > > > > > > Once I have the above "stash", then we use your "foreach" and "split" code > > to > > massage the FORM[key]=values > > Have you checked out the CGI code available in the archive? I just do this: > > include cgi.e > process_cgi() > -- then > x = get_key_value("whatever") > > ...or something close to that. Easy! :) I have searched the archives, but I don't think that I ran across cgi.e. I will check it out. Thanks! -- duke
30. Re: foreach routine
- Posted by Chris Bensler <bensler at nt.net> Dec 23, 2006
- 656 views
duke normandin wrote: > > Chris Bensler wrote: > > > > > Good programming practice is to always trap error conditions whenever you > > can. > > I agree! But how often you need to trap errors depends on the language you are > using and the number of lines of code you need to generate to get something > done. > > > I get the impression though, that you meant that you don't want to have to > > do > > the error testing all the time. Make a routine that takes care of it for you > > instead. > > That's what I meant. As a EU novice, I'm quickly seeing that my coding style > and practices *need* to be different than those I was using with Perl and > PHP. Once you have your 'EUreka!' moment, things will start to click quickly :P > That said, I've been doing CGI / Web / SQL stuff since 1996 using Perl mostly. > I > know how the CGI and back-end stuff works!! I just need to learn to do it > correctly "the EU way". ;)) Nice collection of functions BTW!! I'm sure they > get the job done. Can't wait to put it all together and try it out. Thanks > for the input! > -- > duke Sorry, I didn't mean for it to sound preachy. I can tell that you know web programming and I look forward to the contributions I'm sure you will be making in no time :) You are right in thinking that there appears to be alot of 'hoops' to jump through when using Euphoria. Don't let it turn you away though. Eu is an excellent language. Eu's greatest hurdle is to get more people to use it, so we have more people contributing quality code and banging heads. This thread is precisely why I started the thread about standardized euphoria and this issue is why I have been working on a design and implementation of an improved set of standard includes for quite a long time. Something like a CGI library should be a part of the standard includes (guess where I ripped the cgi functions I pasted for you? ;). People shouldn't have to construct a hammer before they can build a house and I hope I can help to resolve that for us. Anyways I'm getting off topic. Chris Bensler ~ The difference between ordinary and extraordinary is that little extra ~ http://empire.iwireweb.com - Empire for Euphoria
31. Re: foreach routine
- Posted by duke normandin <dnormandin at bsdrocksperlrolls.com> Dec 23, 2006
- 688 views
Chris Bensler wrote: > > > That said, I've been doing CGI / Web / SQL stuff since 1996 using Perl > > mostly. > > I > > know how the CGI and back-end stuff works!! I just need to learn to do it > > correctly "the EU way". ;)) Nice collection of functions BTW!! I'm sure they > > get the job done. Can't wait to put it all together and try it out. Thanks > > for the input! > > Sorry, I didn't mean for it to sound preachy. I can tell that you know web > programming > and I look forward to the contributions I'm sure you will be making in no time > :) No worries! Really!! > You are right in thinking that there appears to be alot of 'hoops' to jump > through > when using Euphoria. Don't let it turn you away though. Eu is an excellent > language. > Eu's greatest hurdle is to get more people to use it, so we have more people > contributing quality code and banging heads. > > This thread is precisely why I started the thread about standardized euphoria > and this issue is why I have been working on a design and implementation of > an improved set of standard includes for quite a long time. Something like a > CGI library should be a part of the standard includes (guess where I ripped > the cgi functions I pasted for you? ;). People shouldn't have to construct a > hammer before they can build a house and I hope I can help to resolve that for > us. Anyways I'm getting off topic. The above paragraphs are reason enough for me to adopt EU as my "native" language. I like your attitude and style, and I have a sense that, for the most part, you mirror the prevailing attitude(s) of this fine community. I'm not a C programmer, so I can't be of much use with the guts of EU, but I sure can't wait to get up to speed with the language itself in order to start making a contribution. You know, I may be familiar with Perl and its CPAN etc, but I left that community and more-and-more the language itself for a reason or two....! But methinks I've found a home! Anyway, thank you for your candor and insights. You and Derek Parnell and others have been just great. Later.... -- duke