You can subscribe to this list here.
2000 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
(2) |
Dec
|
---|---|---|---|---|---|---|---|---|---|---|---|---|
2001 |
Jan
(35) |
Feb
(22) |
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
From: Tyson D. <ty...@ty...> - 2001-01-15 08:17:26
|
On 15-Jan-2001, Ina Cheng <in...@st...> wrote: > Hi Tyson, > > In the example of the SOAP spec > > <SOAP-ENV:Envelope > xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" > SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"> > <SOAP-ENV:Body> > <m:GetStockPrice xmlns:m="some uri"> > <symbol>DIS</symbol> > </m:GetStockPrice> > </SOAP-ENV:Body> > </SOAP-ENV:Envelope> > > The paper said the request takes a string parameter, ticker symbol and > returns a float etc. > > How can I be sure that `DIS' is of type string and not other type? Ah, this is where the research part of your project starts. The SOAP spec says (section 5) First, given a schema in any notation consistent with the type system described, a schema for an XML grammar may be constructed. Second, given a type-system schema and a particular graph of values conforming to that schema, an XML instance may be constructed. This means given a Mercury value (== graph of values conforming to that schema) and a system for converting Mercury types to XML, you can create an XML document. In reverse, given an XML instance produced in accordance with these rules, and given also the original schema, a copy of the original value graph may be constructed. This says that you can reverse it and get back the original Mercury value from the XML document (plus the schema you used to generate it). But this doesn't answer your question -- it just allows us to understand this paragraph (5.1) Although it is possible to use the xsi:type attribute such that a graph of values is self-describing both in its structure and the types of its values, the serialization rules permit that the types of values MAY be determinate only by reference to a schema. Such schemas MAY be in the notation described by "XML Schema Part 1: Structures" [10] and "XML Schema Part 2: Datatypes" [11] or MAY be in any other notation. Note also that, while the serialization rules apply to compound types other than arrays and structs, many schemas will contain only struct and array types. So, either you: - embed xsi:type attributes on each node that says what type this node is. - assume that some agreed upon schema is used to describe the values (and the rest of this section is an example/suggestion of such a schema). Now they say "schema" as a generic term for any sort of systematic transformation, but they also suggest using XML Schema (which aren't yet standard). The example they give is pretty close to XML Schema. So later on there is an example schema: <element name="age" type="int"/> <element name="height" type="float"/> <element name="displacement" type="negativeInteger"/> <element name="color"> <simpleType base="xsd:string"> <enumeration value="Green"/> <enumeration value="Blue"/> </simpleType> </element> Which could be used to describe the following instances: <age>45</age> <height>5.9</height> <displacement>-450</displacement> <color>Blue</color> Now if you (somehow) had that schema, it would be pretty easy to figure it out and do the conversion in either direction. So perhaps you can find a place to slot this schema into the implementation (e.g. you have to provide one for each method that is exposed in the web server). And you can assume that the caller has a copy of it too (they will use it to generate their SOAP message). I think that IBM's Web Services are an attempt to provide this information "on-the-fly" -- e.g. if you want to use SOAP for RPC, it will provide you with a schema which you can download first, then you can use the SOAP message to do the call. Certainly this is a point where the SOAP spec takes a hands-off approach -- each implementation can make its own decisions here. But you might want to read up on this a bit further and let me know what you find. > > Can I assume if the argument is of type int, the soap message will be something > like: > > <int> 1 </int> ? This is pretty similar to the case of embedding the type, it would probably look more like: <cost xsi:type="xsd:float">29.95</cost> or <SOAP-ENC:int id="int1">45</SOAP-ENC:int> -- Tyson Dowd # # Surreal humour isn't everyone's cup of fur. tr...@cs... # http://www.cs.mu.oz.au/~trd # |
From: Ina C. <in...@st...> - 2001-01-15 06:15:27
|
Hi Tyson, In the example of the SOAP spec <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"> <SOAP-ENV:Body> <m:GetStockPrice xmlns:m="some uri"> <symbol>DIS</symbol> </m:GetStockPrice> </SOAP-ENV:Body> </SOAP-ENV:Envelope> The paper said the request takes a string parameter, ticker symbol and returns a float etc. How can I be sure that `DIS' is of type string and not other type? Can I assume if the argument is of type int, the soap message will be something like: <int> 1 </int> ? Ina |
From: Ina C. <in...@st...> - 2001-01-15 05:54:13
|
Hi Tyson, Sorry for the late reply since I didn't receive your email until I read the archive mailing list by curiosity ... > FROM: Tyson Dowd > DATE: 01/10/2001 22:00:24 > SUBJECT: [qs-dev] quicksilver + SOAP > > Ina -- could you get that patch into your version of dl.m and perhaps > work on submitting a diff to *this* mailing list > (quicksilver-developers) containing: > > - the webserver with the dynamic_linking and xml libraries added > (plus Makefile changes and stuff) > > - the changes you have made to get the SOAP server going > (just make sure it doesn't interfere with the normal > functioning of the webserver). > > You can commit this when it looks OK -- Pete, would you perfer a branch > or is the main line OK for you? > > This will help me, because when Ina has problems I have to reconstruct > all this stuff from scratch The following diff is only for your information. I haven't finish yet and not planning to commit the changes to the main branch within a short period of time. Ina ========================================================================= ? temp ? concurrency/concurrency.init ? net/net.init ? server/soap.m ? server/back.m ? server/web.m ? server/foo.m ? server/server ? server/foo.init ? stream/stream.init Index: Mmakefile =================================================================== RCS file: /cvsroot/quicksilver/webserver/Mmakefile,v retrieving revision 1.2 diff -u -r1.2 Mmakefile --- Mmakefile 2000/11/20 17:11:38 1.2 +++ Mmakefile 2001/01/15 05:15:36 @@ -9,6 +9,12 @@ MMAKEFLAGS= SUBDIRS=concurrency net stream server +# Use shared libraries, since they're needed for dynamic linking +MGNUCFLAGS += --pic-reg +MLFLAGS += --shared + +# Link in the `-ldl' library (this may not be needed on some systems) +MLLIBS += -ldl #-----------------------------------------------------------------------------# .PHONY: depend Index: concurrency/semaphore.m =================================================================== RCS file: /cvsroot/quicksilver/webserver/concurrency/semaphore.m,v retrieving revision 1.2 diff -u -r1.2 semaphore.m --- concurrency/semaphore.m 2000/11/20 14:44:35 1.2 +++ concurrency/semaphore.m 2001/01/15 05:15:36 @@ -84,7 +84,7 @@ MR_Word sem_mem; ME_Semaphore *sem; - incr_hp(sem_mem, round_up(sizeof(ME_Semaphore), sizeof(MR_Word))); + incr_hp(sem_mem, MR_round_up(sizeof(ME_Semaphore), sizeof(MR_Word))); sem = (ME_Semaphore *) sem_mem; sem->count = 0; #ifndef MR_HIGHLEVEL_CODE Index: server/Mmakefile =================================================================== RCS file: /cvsroot/quicksilver/webserver/server/Mmakefile,v retrieving revision 1.3 diff -u -r1.3 Mmakefile --- server/Mmakefile 2000/11/24 14:21:17 1.3 +++ server/Mmakefile 2001/01/15 05:15:36 @@ -1,11 +1,33 @@ -MAIN_TARGET=server +MAIN_TARGET=server libfoo +XML_DIR = ../../../webserver/xml +DYNAMIC_DIR = ../../../../extras/dynamic_linking + -include ../Mmake.params + +GRADE = hlc.par.gc +VPATH=../concurrency:../net:../stream:$(XML_DIR):$(DYNAMIC_DIR):$(MMAKE_VPATH) +MCFLAGS+=-I ../concurrency -I ../net -I ../stream \ + -I $(XML_DIR) -I $(DYNAMIC_DIR) +MGNUCFLAGS+= --pic-reg \ + -I ../concurrency -I ../net -I ../stream \ + -I $(XML_DIR) -I $(DYNAMIC_DIR) +MLLIBS=../net/libnet.$A ../stream/libstream.$A \ + ../concurrency/libconcurrency.$A \ + $(XML_DIR)/libxml.$A \ + $(DYNAMIC_DIR)/libdl.$A +MLFLAGS = -R$(XML_DIR) $(EXTRA_MLFLAGS) -L$(XML_DIR) +# MLFLAGS = -R$(XML_DIR) -R$(DYNAMIC_DIR) $(EXTRA_MLFLAGS) \ +# -L$(XML_DIR) -L$(DYNAMIC_DIR) +C2INITARGS = $(XML_DIR)/xml.init $(DYNAMIC_DIR)/dl.init + + +# Use shared libraries, since they're needed for dynamic linking +# MGNUCFLAGS += --pic-reg +MLFLAGS += --shared -VPATH=../concurrency:../net:../stream:$(MMAKE_VPATH) -MCFLAGS+=-I ../concurrency -I ../net -I ../stream -MGNUCFLAGS+=-I ../concurrency -I ../net -I ../stream -MLLIBS=../net/libnet.$A ../stream/libstream.$A ../concurrency/libconcurrency.$A +# Link in the `-ldl' library (this may not be needed on some systems) +MLLIBS += -ldl -depend: server.depend +depend: server.depend foo.depend server: $(MLLIBS) Index: server/server.m =================================================================== RCS file: /cvsroot/quicksilver/webserver/server/server.m,v retrieving revision 1.4 diff -u -r1.4 server.m --- server/server.m 2000/11/27 10:02:58 1.4 +++ server/server.m 2001/01/15 05:15:36 @@ -21,9 +21,13 @@ :- import_module bool, char, exception, getopt. :- import_module int, list, require, std_util, string. +:- import_module soap. +:- import_module web. +:- import_module foo. + main --> io__command_line_arguments(Args0), - { OptionOpts = option_ops(short_option, long_option, option_defaults)}, + { OptionOpts = option_ops(short_option, long_option, option_defaults)}, { getopt__process_options(OptionOpts, Args0, _Args, OptionsResult) }, ( { OptionsResult = ok(OptTable) }, @@ -76,7 +80,14 @@ { parse_request(RequestLines, RequestOrResponse) }, ( { RequestOrResponse = left(Request) }, - generate_response(Request, Response) + ( + { Request^cmd = post }, + get_soapmessage(TCP, Request, Request0) + ; + { Request^cmd = get }, + { Request0 = Request } + ), + generate_response(Request0, Response) ; { RequestOrResponse = right(Response) } ), @@ -115,12 +126,26 @@ :- type request ---> request( - cmd :: string, + cmd :: cmd, uri :: string, version :: string, - headers :: list(string) + headers :: list(header), + body :: maybe(body) ). +:- type cmd + ---> get + ; post. + +:- type header + ---> header( + name :: string, + value :: string, + extra :: maybe(string) + ). + +:- type body == string. + :- pred parse_request(list(list(char))::in, either(request, response)::out) is det. @@ -131,12 +156,19 @@ three_words(Cmd, URI, HTTP_Version, RequestLine, _), ( Cmd \= [], URI \= [], HTTP_Version \= [] - -> - Request = request(string__from_char_list(Cmd), + -> + parse_headers(RequestLines, Headers), + ( + Cmd = ['P','O','S','T'] + -> + Command = post + ; + Command = get + ), + Request = request(Command, string__from_char_list(URI), string__from_char_list(HTTP_Version), - list__map(string__from_char_list, - RequestLines)), + Headers, no), Either = left(Request) ; Response = response(501, [], no_body, yes), @@ -173,7 +205,91 @@ { Word = [] } ). +:- pred parse_headers(list(list(char))::in, list(header)::out) is det. + +parse_headers([], []). +parse_headers([RequestLine | RequestLines], Headers) :- + three_words(Name, Value, Extra, RequestLine, _), + ( + Extra \= [] + -> + Extra0 = yes(string__from_char_list(Extra)) + ; + Extra0 = no + ), + Header = header(string__from_char_list(Name), + string__from_char_list(Value), + Extra0), + parse_headers(RequestLines, Headers0), + Headers = [Header | Headers0]. + + +%-----------------------------------------------------------------------------%+ +:- pred get_soapmessage(S, request, request, io__state, io__state) + <= stream__duplex(S). +:- mode get_soapmessage(in, in, out, di, uo) is det. + +get_soapmessage(S, Request, Request0) --> + { get_content_length(Request^headers, Length) }, + get_body(S, Length, SoapMessage), + { Request0 = request(Request^cmd, + Request^uri, + Request^version, + Request^headers, + yes(string__from_char_list(SoapMessage))) }. + +% XXX should error message be produced if content length = 0 +:- pred get_content_length(list(header)::in, int::out) is det. + +get_content_length([], 0). +get_content_length([header(Name, Value, _) | Headers], Length) :- + ( + is_content_length(Name), + string__to_int(Value, Length0) + -> + Length = Length0 + ; + get_content_length(Headers, Length) + ). +:- pred is_content_length(string::in) is semidet. +is_content_length("Content-Length:"). +is_content_length("Content-length:"). + +:- pred is_content_type(string::in) is semidet. +is_content_type("Content-Type:"). +is_content_type("Content-type:"). + +:- pred get_body(S, int, list(char), io__state, io__state) + <= stream__duplex(S). +:- mode get_body(in, in, out, di, uo) is det. + +% XXX what happen if there are still characters when length = 0 + +get_body(S, Length, RequestLines) --> + stream__read_char(S, CharResult), + { Length0 = Length - 1 }, + ( + { Length0 = 0 }, + { CharResult = ok(Char) } + -> + { RequestLines = [Char] } + % stream__write_string( S, "length is 0\n") + ; + { CharResult = error(Error) } + -> + { error(string__format("get_request: %s.", [s(Error)])) } + ; + { CharResult = ok(Char) } + -> + get_body(S, Length0, RequestLines0), + { RequestLines = [Char | RequestLines0] } + ; + % what about if char = '\r' '\n' + %assume { CharResult = eof } + { RequestLines = [] } + ). %-----------------------------------------------------------------------------% @@ -183,7 +299,7 @@ :- type response ---> response( respCode :: int, - respHeaders :: list(string), + respHeaders :: list(header), % respCoding :: list(transfer_coding), respBody :: response_body, respSendBody :: bool @@ -198,15 +314,52 @@ io__state::di, io__state::uo) is det. generate_response(Request, Response) --> - io__see(uri_to_filename(Request^uri), SeeResult), ( - { SeeResult = ok }, - io__read_file_as_string(_Result, String), - io__seen, - { Response = response(200, [], string_body(String), yes) } + { Request^cmd = get }, + io__see(uri_to_filename(Request^uri), SeeResult), + ( + { SeeResult = ok }, + io__read_file_as_string(_Result, String), + io__seen, + { Response = response(200, [], + string_body(String), yes) } + ; + { SeeResult = error(_) }, + { Response = response(404, [], no_body, yes) } + ) ; - { SeeResult = error(_) }, - { Response = response(404, [], no_body, yes) } + { Request^cmd = post }, + ( + { Request^body = yes(Body) } , + parse_soapmessage(Body, NsBody), + % write(NsBody), nl, + { get_procedure_call(NsBody, Proc) }, + write(Proc), nl, + { get_parameters(NsBody, Proc, Params) }, + write(Params), nl, + + % make_web_request(Proc, Params, Procedure), + + load_dynamic_library("./libfoo.so", Result, HttpCode), + ( + { Result = yes(Output) }, + { generate_response_body(NsBody, Proc, + Output, ResBody0) }, + { ResBody = string_body(ResBody0) } + ; + { Result = no }, + { ResBody = no_body } + ) + ; + % 200 - 299 is client request successful + % 400 = Bad Request + { Request^body = no }, + { ResBody = no_body }, + { HttpCode = 400 } + ), + { list__filter(filter, Request^headers, Headers) }, + { Response = response(HttpCode, Headers, + ResBody, yes) } ). :- func uri_to_filename(string) = string. @@ -221,6 +374,10 @@ last_char(Str) = string__unsafe_index(Str, string__length(Str) - 1). +:- pred filter(header::in) is semidet. +filter(header("Content-Length:", _, _)). +filter(header("Content-Type:", _, _)). + %-----------------------------------------------------------------------------% :- pred send_response(S, response, io__state, io__state) <= stream__output(S). @@ -239,13 +396,24 @@ stream__write_string(S, string__format("HTTP/1.1 %d %s\r\n", [i(HttpCode), s(reason(HttpCode))])). -:- pred headers(S, list(string), io__state, io__state) <= stream__output(S). +:- pred headers(S, list(header), io__state, io__state) <= stream__output(S). :- mode headers(in, in, di, uo) is det. headers(_, []) --> []. headers(S, Headers) --> - { Headers = [_ | _] }, - list__foldl(stream__write_string(S), Headers). + { Headers = [header(Name, Value, Other)|Tail] }, + stream__write_string(S, Name), + stream__write_char(S, ' '), + stream__write_string(S, Value), + stream__write_char(S, ' '), + ( + { Other = yes(String) } -> + stream__write_string(S, String) + ; + [] + ), + stream__write_char(S, '\n'), + headers(S, Tail). :- pred body(S, response_body, io__state, io__state) <= stream__output(S). :- mode body(in, in, di, uo) is det. The following 2 files are newly added. ===========================================================================%---------------------------------------------------------------------------% :- module soap. :- interface. :- import_module io, list, string. :- import_module xml, xml:ns. :- pred parse_soapmessage(string, ((xml:ns):nsDocument), io__state, io__state). :- mode parse_soapmessage(in, out, di, uo) is det. :- pred get_procedure_call(nsDocument, nsElement). :- mode get_procedure_call(in, out) is det. :- pred get_parameters(nsDocument, nsElement, list(nsContent)). :- mode get_parameters(in, in, out) is det. :- pred generate_response_body(nsDocument, nsElement, string, string). :- mode generate_response_body(in, in, in, out) is det. :- pred get_first_element(list(T)::in, T::out) is det. %---------------------------------------------------------------------------% :- implementation. :- import_module array, assoc_list, bool, char, map, require, std_util. :- import_module parsing, xml:cat, xml:doc, xml:encoding, xml:parse. % parse soap message % NsDoc is namespace aware soap message parse_soapmessage(SoapMessage, NsDoc) --> pstate(mkEntity(SoapMessage), mkEncoding(utf8), init), io((pred(Dirs0::out, di, uo) is det --> get_environment_var("XML_DIRS", MStr), ( { MStr = no }, { Str = "." } ; { MStr = yes(Str) } ), { split((':'), Str, Dirs0) } ), Dirs), set(gDirs, dirs(Dirs)), { map__from_assoc_list([ "ASCII" - mkEncoding(ascii7), "ascii" - mkEncoding(ascii7), "Latin-1" - mkEncoding(latin1), "Latin1" - mkEncoding(latin1), "UTF-8" - mkEncoding(utf8), "utf-8" - mkEncoding(utf8) ], Encodings) }, set(gEncodings, encodings(Encodings)), document, finish(Res), ( { Res = ok((_, Doc)) }, { nsTranslate(Doc, NsDoc) } ; { Res = error(_Err) }, { NsDoc = nsDoc([], 0, [], array([comment("test")])) } ). :- pred split(char, string, list(string)). :- mode split(in, in, out) is det. split(C, Str0, Strs) :- string__to_char_list(Str0, Chars), split1(C, [], Strs0, Chars, _), reverse(Strs0, Strs). :- pred split1(char, list(string), list(string), list(char), list(char)). :- mode split1(in, in, out, in, out) is det. split1(_C, Strs, Strs, [], []). split1(C, Strs0, Strs) --> =([_|_]), split2(C, [], Cs0), { reverse(Cs0, Cs) }, ( { Cs \= [] } -> { string__from_char_list(Cs, Str) }, { Strs1 = [Str|Strs0] } ; { Strs1 = Strs0 } ), split1(C, Strs1, Strs). :- pred split2(char, list(char), list(char), list(char), list(char)). :- mode split2(in, in, out, in, out) is det. split2(_C, Cs, Cs, [], []). split2(C, Cs0, Cs) --> [C0], ( { C = C0 } -> { Cs = Cs0 } ; split2(C, [C0|Cs0], Cs) ). %---------------------------------------------------------------------------% % Assume only one procedure call with one argument in a soap message get_procedure_call(NsDoc, Procedure) :- get_procedure(NsDoc, [], Procedurelist), get_first_element(Procedurelist, Procedure). get_first_element([], _) :- error("Procedure not found."). get_first_element([H|_], H). :- pred get_procedure(nsDocument, list(nsElement), list(nsElement)). :- mode get_procedure(in, in, out) is det. get_procedure(NsDoc, Acc0, Acc) :- get_procedure(NsDoc^content, NsDoc^root, Acc0, Acc). :- pred get_procedure(array(nsContent), ref(nsContent), list(nsElement), list(nsElement)). :- mode get_procedure(in, in, in, out) is det. get_procedure(ContentArray, ContentRef, Acc0, Acc) :- lookup(ContentArray, ContentRef, Content), ( Content = nsElement(Elem) -> ( Elem^eName^localName \= "Envelope", Elem^eName^localName \= "Body" -> Acc = [Elem] ; Kid = Elem^eContent, elem_foldl(get_procedure, ContentArray, Kid, Acc0, Acc) ) ; Acc = Acc0 ). :- pred elem_foldl(pred(array(nsContent), ref(nsContent), list(nsElement), list(nsElement)), array(nsContent), list(ref(nsContent)), list(nsElement), list(nsElement)). :- mode elem_foldl(pred(in, in, in, out) is det, in, in, in, out) is det. elem_foldl(_Pred, _, [], Acc, Acc). elem_foldl(Pred, ContentArray, [Ref|Refs], Acc0, Acc) :- call(Pred, ContentArray, Ref, Acc0, Acc1), elem_foldl(Pred, ContentArray, Refs, Acc1, Acc). %---------------------------------------------------------------------------% get_parameters(NsDoc, Proc, Parameters) :- Param_Index = Proc^eContent, content_foldl(get_param, NsDoc^content, Param_Index, no, [], Parameters). :- pred get_param(array(nsContent), ref(nsContent), bool, list(nsContent), list(nsContent)). :- mode get_param(in, in, in, in, out) is det. get_param(ContentArray, ContentRef, Flag, Acc0, Acc) :- lookup(ContentArray, ContentRef, Content), ( Content = nsElement(Elem) -> Kids = Elem^eContent, Flag0 = yes, content_foldl(get_param, ContentArray, Kids, Flag0, Acc0, Acc1), Acc = [Content|Acc1] ; Flag = yes -> Acc = [Content|Acc0] ; Acc = Acc0 ). :- pred content_foldl(pred(array(nsContent), ref(nsContent), bool, list(nsContent), list(nsContent)), array(nsContent), list(ref(nsContent)), bool, list(nsContent), list(nsContent)). :- mode content_foldl(pred(in, in, in, in, out) is det, in, in, in, in, out) is det. content_foldl(_Pred, _, [], _, Acc, Acc). content_foldl(Pred, ContentArray, [Ref|Refs], Flag, Acc0, Acc) :- call(Pred, ContentArray, Ref, Flag, Acc0, Acc1), content_foldl(Pred, ContentArray, Refs, Flag, Acc1, Acc). %---------------------------------------------------------------------------% % assume Method has prefix or default namespace % eg. m:GetStockPrice or GetStockPrice generate_response_body(NsDoc, Method, Result, ResponseBody) :- generate_res_body(NsDoc^content, NsDoc^root, Method, Result, [], [], ResponseBodyList), list__reverse(ResponseBodyList, ResponseBodyList0), string__append_list(ResponseBodyList0, ResponseBody). :- pred generate_res_body(array(nsContent), ref(nsContent), nsElement, string, nsList, list(string), list(string)). :- mode generate_res_body(in, in, in, in, in, in, out) is det. generate_res_body(ContentArray, ContentRef, Method, Result, URIList0, Acc0, Acc) :- lookup(ContentArray, ContentRef, Content), ( Content = nsElement(Elem), is_envelope_body(Elem^eName^localName) -> list__append(URIList0, Elem^eNamespaces, URIList), assoc_list__reverse_members(URIList, URIListRev), get_prefix(URIListRev, Elem^eName^nsURI, Elem^eName^localName, ElementName), string__append("<", ElementName, ElemName), %----------------------------------------------------- format_attrs(Elem^eAttrs, URIList, URIListRev, Attrs), string__append_list(Attrs, AttrsString), string__append(ElemName, AttrsString, Elem_Attrs), Acc1 = [Elem_Attrs|Acc0], ( not(is_body(Elem^eName^localName)) -> Kids = Elem^eContent, doc_foldl(generate_res_body, ContentArray, Kids, Method, Result, URIList, Acc1, Acc2) ; generate_method_response(Method, Result, ResBody), Acc2 = [ResBody|Acc1] ), make_end_tag(ElementName, EndTag), Acc = [EndTag|Acc2] ; Acc = Acc0 ). :- pred is_envelope_body(string::in) is semidet. is_envelope_body("Envelope"). is_envelope_body("Header"). is_envelope_body("Body"). :- pred is_body(string::in) is semidet. is_body("Body"). :- pred get_prefix(nsList::in, nsURI::in, string::in, string::out) is det. get_prefix(URIListRev, URI, ElementName0, ElementName) :- ( % element has prefix % search_prefix(URIList, Elem^eName^nsURI, Prefix) assoc_list__search(URIListRev, URI, Prefix) -> string__append(Prefix, ":", Name0), string__append(Name0, ElementName0, ElementName) ; % element has default namespace ElementName = ElementName0 ). :- pred format_attrs(list(nsAttribute), nsList, nsList, list(string)). :- mode format_attrs(in, in, in, out) is det. format_attrs([], _, _, [">\n"]). format_attrs([Attr|Attrs], URIList, URIListRev, StringList) :- ( assoc_list__search(URIList, Attr^aName^localName, _URI) -> Prefix = "\nxmlns:" ; assoc_list__search(URIListRev, Attr^aName^nsURI, Prefix0) -> string__append(Prefix0, ":", Prefix) ; Prefix = "\n" ), string__append(Prefix, Attr^aName^localName, Attr1), string__append(Attr1, "=\"", Attr2), string__append(Attr2, Attr^aValue, Attr3), string__append(Attr3, "\"", Attr4), ( Attrs \= [] -> string__append(Attr4, "\n", Attr5) ; Attr5 = Attr4 ), % string__append(Attr4, "\n", Attr4) StringList = [Attr5 | StringList0], format_attrs(Attrs, URIList, URIListRev, StringList0). :- pred generate_method_response(nsElement, string, string). :- mode generate_method_response(in, in, out) is det. generate_method_response(Method, Result, ResBody) :- assoc_list__reverse_members(Method^eNamespaces, URIListRev), get_prefix(URIListRev, Method^eName^nsURI, Method^eName^localName, ElementName), string__append("<", ElementName, ResBody0), string__append(ResBody0, "Response ", ResBody1), format_attrs(Method^eAttrs, Method^eNamespaces, URIListRev, Attrs), string__append_list(Attrs, AttrsString), string__append(ResBody1, AttrsString, ResBody2), string__append(ResBody2, Result, ResBody3), string__append(ResBody3, "\n", ResBody4), make_end_tag(ElementName, EndTag), string__append(ResBody4, EndTag, ResBody). :- pred make_end_tag(string::in, string::out) is det. make_end_tag(ElementName, EndTag) :- string__append("</", ElementName, EndTag0), string__append(EndTag0, ">\n", EndTag). :- pred doc_foldl(pred(array(nsContent), ref(nsContent), nsElement, string, nsList, list(string), list(string)), array(nsContent), list(ref(nsContent)), nsElement, string, nsList, list(string), list(string)). :- mode doc_foldl(pred(in, in, in, in, in, in, out) is det, in, in, in, in, in, in, out) is det. doc_foldl(_Pred, _, [], _, _, _, Acc, Acc). % get_first_element(ElemName0, FirstElem), % string__append("</", ElemName, FirstElem1), % string__append(FirstElem1, ">", FirstElem2), % list__reverse(Acc0, Acc1), % Acc = [FirstElem2|Acc0]. % list__reverse(Acc2, Acc), % my_delete(ElemName0, ElemName). doc_foldl(Pred, ContentArray, [Ref|Refs], Method, Result, URIs, Acc0, Acc) :- doc_foldl(Pred, ContentArray, Refs, Method, Result, URIs, Acc0, Acc1), call(Pred, ContentArray, Ref, Method, Result, URIs, Acc1, Acc). % :- pred insert_last(list(T)::in, T::in, list(T)::out) is det. % insert_last([], T, [T]). % insert_last([ :- pred my_delete(list(T)::in, list(T)::out) is det. my_delete([], []). my_delete([_H|T], T). ============================================================================ %---------------------------------------------------------------------------% :- module web. :- interface. :- import_module io, list, string, std_util. :- import_module http. :- import_module xml, xml:ns. % :- type web_func == (func(univ) = univ). % :- inst web_func == (func(in) = out is det). % % method :: (func(univ::in) = univ::out) gives error ?? % :- type web_method % ---> web_method( % method :: web_func, % calling function % name :: string % name of the web method % ). :- type web_method_request ---> web_method_request( params :: list(univ), name :: string, uri :: string ). % :- pred make_web_request(nsElement, list(nsContent), web_method_request). % :- mode make_web_request(in, in, out) is det. :- pred load_dynamic_library(string::in, maybe(string)::out, http_code::out, io__state::di, io__state::uo) is det. %---------------------------------------------------------------------------% :- implementation. :- import_module bool, int. :- import_module dl, name_mangle, foo. % make_web_request(Proc, Params, Request) :- % Request^name = Proc^eName^localName; % Request^uri = Proc^eName^nsURI; % Params = % assume web method is a function % after passing web_method_request, need to check arity and mode num ??? % inst_cast depends on which function .... so how to call which inst_cast ?? load_dynamic_library(L, Response, HttpCode) --> dl__open(L, lazy, local, MaybeHandle), ( % XXX do I need to send error Msg to TCP stream % or 500 Internal Server Error is sufficient { MaybeHandle = error(_Msg) }, { Response = no }, { HttpCode = 500 } ; { MaybeHandle = ok(Handle) }, { GetSPProc = mercury_proc(predicate, unqualified("foo"), "get_sp", 2, 0) } , dl__mercury_sym(Handle, GetSPProc, MaybeGetStockPrice), ( { MaybeGetStockPrice = error(_Msg1) }, { Response = no }, { HttpCode0 = 500 } ; { MaybeGetStockPrice = ok(SPFunc0) }, { SPFunc = inst_cast_sp(SPFunc0) }, { call(SPFunc, 2, SP) }, { string__int_to_string(SP, SPString) }, { Response = yes(SPString) }, { HttpCode0 = 200 } ), dl__close(Handle, Result), ( { Result = error(_CloseMsg) }, { HttpCode1 = 500 }, { ChangeHttpCode = yes } ; { Result = ok }, { HttpCode1 = HttpCode0 }, { ChangeHttpCode = no } ), ( { ChangeHttpCode = yes } -> { HttpCode = HttpCode1 } ; { HttpCode = HttpCode0 } ) ). % inst cast for get_stockprice :- type stockprice == (func(int, int) = int). :- type stockprice_wrapper ---> wrapper(stockprice). :- inst stockprice_wrapper ---> wrapper(func(in, in) = out is det). :- func inst_cast_stockprice(stockprice_wrapper) = stockprice_wrapper. :- mode inst_cast_stockprice(in) = out(stockprice_wrapper) is det. :- pragma c_code(inst_cast_stockprice(X::in) = (Y::out(stockprice_wrapper)), [will_not_call_mercury, thread_safe], "Y=X"). :- type sp_pred == pred(int, int). :- inst sp_pred == (pred(in, out) is det). :- func inst_cast_sp(sp_pred) = sp_pred. :- mode inst_cast_sp(in) = out(sp_pred) is det. :- pragma c_code(inst_cast_sp(X::in) = (Y::out(sp_pred)), [will_not_call_mercury, thread_safe], "Y=X"). %---------------------------------------------------------------------------% |
From: Tyson D. <ty...@ty...> - 2001-01-11 10:03:00
|
On 11-Jan-2001, Peter Ross <pet...@mi...> wrote: > On Thu, Jan 11, 2001 at 05:00:24PM +1100, Tyson Dowd wrote: > > > > You can commit this when it looks OK -- Pete, would you perfer a branch > > or is the main line OK for you? > > > Main line is fine because as far as I can work out the SOAP stuff is > completely independent of the http stuff (suprise, suprise). Well, it will increase the build time (xml and dynamic_linking). But since it uses POST, it should be fine. -- Tyson Dowd # # Surreal humour isn't everyone's cup of fur. tr...@cs... # http://www.cs.mu.oz.au/~trd # |
From: Peter R. <pet...@mi...> - 2001-01-11 09:36:06
|
On Thu, Jan 11, 2001 at 05:00:24PM +1100, Tyson Dowd wrote: > > You can commit this when it looks OK -- Pete, would you perfer a branch > or is the main line OK for you? > Main line is fine because as far as I can work out the SOAP stuff is completely independent of the http stuff (suprise, suprise). Pete |
From: Tyson D. <tr...@cs...> - 2001-01-11 06:00:11
|
Hi, Fergus just posted a diff to mercury-developers that fixes the problems with dynamic linking in the MLDS grade. This should bring us a step closer to getting SOAP support going. Ina -- could you get that patch into your version of dl.m and perhaps work on submitting a diff to *this* mailing list (quicksilver-developers) containing: - the webserver with the dynamic_linking and xml libraries added (plus Makefile changes and stuff) - the changes you have made to get the SOAP server going (just make sure it doesn't interfere with the normal functioning of the webserver). You can commit this when it looks OK -- Pete, would you perfer a branch or is the main line OK for you? This will help me, because when Ina has problems I have to reconstruct all this stuff from scratch. -- Tyson Dowd # # Surreal humour isn't everyone's cup of fur. tr...@cs... # http://www.cs.mu.oz.au/~trd # |
From: Tyson D. <tr...@cs...> - 2001-01-03 11:28:07
|
Peter, I thought you might like to see this too. Should we be discussing this on the quicksilver-devel mailing list? On 03-Jan-2001, Ina Cheng <in...@st...> wrote: > Hi Tyson, > > I want to apologise to you because I had forgotten the stuff that you > taught me on the last day before the holiday. I've tried my best to figure > out what those code were meant to do, but I'm still a bit lost. Could you > explain that again if you have time? Thanks. > > Ina > > :- type web_method --> > web_method( > method :: func(univ::in) = univ::out, > name :: string > ). Just a structure that stores a web method. It keeps the name of the web method (so you can look it up by name when there is a call to it) and the func is just a very generic function. Actually it might be better if it were func(list(univ)::in) = list(univ)::out since in general web methods may have multiple input and output parameters. We were thinking that we might use this to represent web methods, but remember that we found more general code in the dynamic linking module and so it might be better to use that instead. But the important thing is to rememember this: This represents a call site, that is, a place where a function is defined that other people can call. The name defines the call site. I guess we might also describe call sites using URIs too -- the URI might act as a "module" while the name acts as a "predicate name". SOAP doesn't really make any assumptions here, you can do what you like. At first I suggest you ignore the URI. > :- type web_method_request --> > web_method_request( > params :: univ, > name :: string, > name :: uri > ). This represents a call. It describes the call site (the uri and the name of the web method), and it also provides some parameters. Note that list(univ) might be better than univ for the parameters. You create a web_method_request, pass it to some utility predicate in a SOAP library, and it will call the web server and give you back a response. > server --> > run_soap_server, > get_libs_from_configuration_file(Libs), > load_dynamic_libraries(Libs). > > load_dynamic_library(L) --> > load_library(L, LibraryCode), > run_predicate(LibraryCode, "get_all_soap_methods", 3, Results), > soap__bind_web_services(Results). > > get_all_soap_methods(Methods) --> > RotFunc = (func(Univ::in) = (Y::out) :- > ( univ_to_type(Univ, [X]) -> > rot13(X, Y0), > Y = type_to_univ(Y0)) > ; > error("....") > ), > WebMethod = web_method(RotFunc, "encrypt_character"), > > Methods = [WebMethod] This code is a sketch of how you might implement the server. Remember we thought that using dynamic linking would handle this OK, so the "get_all_soap_methods" stuff would actually do dl_open and dl_sym calls instead of directly referencing `rot13' (which was just a sample predicate). > client --> > Params = type_to_univ('a'), > URI = "http://roy.cs.mu.oz.au:8080/", > WebMethod = web_method_request(Params, "encrypt_character", URI), > soap__call_web_method(WebMethod, Response), > ( > CharOut = univ_to_type(Response) > -> > io__write_char(CharOut) > ; > error("...") > ). Here's an example of the how the client code might work -- we make a web_method_request and then we call it, and then we extract the response. -- Tyson Dowd # # Surreal humour isn't everyone's cup of fur. tr...@cs... # http://www.cs.mu.oz.au/~trd # |
From: Peter R. <pet...@mi...> - 2000-11-27 10:10:47
|
Hi, =================================================================== Estimated hours taken: 2 server/options.m: server/server.m: Process options passed in from the command line. Index: server/options.m =================================================================== RCS file: options.m diff -N options.m --- /dev/null Tue May 5 13:32:27 1998 +++ options.m Mon Nov 27 02:01:40 2000 @@ -0,0 +1,120 @@ +%-----------------------------------------------------------------------------% +% Copyright (C) 2000 Peter Ross +% This file may only be copied under the terms of the GNU General +% Public License - see the file COPYING +%-----------------------------------------------------------------------------% +% +% File: options.m. +% Main author: petdr. +% +% This defines the stuff necessary so that getopt.m +% can parse the command-line options. +% +%-----------------------------------------------------------------------------% + +:- module options. +:- interface. +:- import_module bool, string, io, getopt. + +:- type option + % Verbosity options + ---> verbose + ; very_verbose + % Server options + % ; config_file + ; host + ; port + ; root + + % Miscellaneous Options + ; help. + +:- type option_table == option_table(option). + +:- pred short_option(character::in, option::out) is semidet. +:- pred long_option(string::in, option::out) is semidet. +:- pred option_defaults(option::out, option_data::out) is nondet. +:- pred option_default(option::out, option_data::out) is multidet. + +:- pred options_help(io__state::di, io__state::uo) is det. + +% A couple of misc utilities + +:- pred maybe_write_string(bool::input, string::input, + io__state::di, io__state::uo) is det. +:- pred maybe_flush_output(bool::in, io__state::di, io__state::uo) is det. + +%-----------------------------------------------------------------------------% + +:- implementation. +:- import_module std_util, list. + +option_defaults(Option, Default) :- + semidet_succeed, + option_default(Option, Default). + + % Verbosity Options +option_default(verbose, bool(no)). +option_default(very_verbose, bool(no)). + + % General server options +% option_default(config_file, string("/etc/quicksilver.conf")). +option_default(host, string("localhost")). +option_default(port, int(8080)). +option_default(root, string("/var/www")). + + % Miscellaneous Options +option_default(help, bool(no)). + + % please keep this in alphabetic order +% short_option('f', config_file). +short_option('h', help). +short_option('H', host). +short_option('P', port). +short_option('R', root). +short_option('v', verbose). +short_option('V', very_verbose). + +% long_option("config-file", config_file). +long_option("help", help). +long_option("host", host). +long_option("port", port). +long_option("root", root). +long_option("verbose", verbose). +long_option("very-verbose", very_verbose). + +options_help --> + io__write_strings([ + "Usage: quicksilver [<options>]\n", + "Options:\n", + "\t-h, --help\n", + "\t\tPrint this usage message.\n", + + "\nServer Options:\n", + % "\t-f, --config-file\n", + % "\t\tLocation of the quicksilver configuration file.\n", + "\t-H, --host\n", + "\t\tName of the host which will be listening for requests.\n", + "\t-P, --port\n", + "\t\tWhich port quicksilver listens on.\n", + "\t-R, --root\n", + "\t\tThe root directory for the html files to be served.\n", + + "\nVerbosity Options:\n", + "\t-v, --verbose\n", + "\t\tOutput progress messages at each stage.\n", + "\t-V, --very-verbose\n", + "\t\tOutput very verbose progress messages.\n" + ]). + +%-----------------------------------------------------------------------------% + +maybe_write_string(yes, String) --> io__write_string(String). +maybe_write_string(no, _) --> []. + +maybe_flush_output(yes) --> io__flush_output. +maybe_flush_output(no) --> []. + +:- end_module options. + +%-----------------------------------------------------------------------------% Index: server/server.m =================================================================== RCS file: /cvsroot/quicksilver/webserver/server/server.m,v retrieving revision 1.3 diff -u -r1.3 server.m --- server/server.m 2000/11/24 14:21:17 1.3 +++ server/server.m 2000/11/27 10:01:40 @@ -14,21 +14,42 @@ %-----------------------------------------------------------------------------% :- implementation. -:- import_module http. +:- import_module http, options. + :- import_module channel, spawn, stream, tcp. -:- import_module bool, char, exception, int, list, require, std_util, string. + +:- import_module bool, char, exception, getopt. +:- import_module int, list, require, std_util, string. main --> - { Port = 8080 }, - tcp__bind("localhost", Port, Result), - % tcp__bind("193.121.72.12", Port, Result), + io__command_line_arguments(Args0), + { OptionOpts = option_ops(short_option, long_option, option_defaults) }, + { getopt__process_options(OptionOpts, Args0, _Args, OptionsResult) }, ( - { Result = ok(Listen) }, - service_connections(Listen) + { OptionsResult = ok(OptTable) }, + { getopt__lookup_bool_option(OptTable, help, Help) }, + ( + { Help = yes }, + options_help + ; + { Help = no }, + { getopt__lookup_string_option(OptTable, host, Host) }, + { getopt__lookup_int_option(OptTable, port, Port) }, + tcp__bind(Host, Port, Result), + ( + { Result = ok(Listen) }, + service_connections(Listen) + ; + { Result = error(String) }, + io__write_string(String), + io__nl + ) + ) ; - { Result = error(String) }, - io__write_string(String), - io__nl + { OptionsResult = error(OptionErrorString) }, + io__write_string(OptionErrorString), + io__nl, + options_help ). %-----------------------------------------------------------------------------% |
From: Peter R. <pet...@mi...> - 2000-11-24 14:26:53
|
Hi, After this patch the linux version of the webserver works correctly. =================================================================== Estimated hours taken: 2 net/Mmakefile: net/tcp.m: Add tcp__shutdown. server/Mmakefile: server/server.m: Change so that we default to binding to lo interface. The socket needs to be shutdown after the request has been sent so that the client doesn't wait for any more data. Parse the request line. stream/impure.m: stream/lowlevel.m: stream/stream.m: Add some suggested changes from fjh. Index: net/Mmakefile =================================================================== RCS file: /cvsroot/quicksilver/webserver/net/Mmakefile,v retrieving revision 1.2 diff -u -r1.2 Mmakefile --- net/Mmakefile 2000/11/20 17:11:38 1.2 +++ net/Mmakefile 2000/11/24 14:17:08 @@ -3,7 +3,7 @@ -include ../Mmake.params VPATH=../stream:$(MMAKE_VPATH) -MCFLAGS=-I ../stream -MGNUCFLAGS=-I ../stream +MCFLAGS+=-I ../stream +MGNUCFLAGS+=-I ../stream depend: net.depend Index: net/tcp.m =================================================================== RCS file: /cvsroot/quicksilver/webserver/net/tcp.m,v retrieving revision 1.2 diff -u -r1.2 tcp.m --- net/tcp.m 2000/11/20 17:11:39 1.2 +++ net/tcp.m 2000/11/24 14:17:08 @@ -1,4 +1,4 @@ -%---------------------------------------------------------------------------% +%-----------------------------------------------------------------------------% % Copyright (C) 2000 The University of Melbourne % This file may only be copied under the terms of the GNU Library General % Public License - see the file COPYING.LIB @@ -38,6 +38,8 @@ :- pred tcp__accept(bound_tcp::in, tcp__result(tcp)::out, io__state::di, io__state::uo) is det. +:- pred tcp__shutdown(tcp::in, io__state::di, io__state::uo) is det. + :- instance stream(tcp). :- instance stream__input(tcp). :- instance stream__output(tcp). @@ -89,6 +91,7 @@ }. %-----------------------------------------------------------------------------% +%-----------------------------------------------------------------------------% tcp__bind(Host, Port, Result) --> handle_bind(Host, Port, Socket, Addr, Errno), @@ -111,6 +114,32 @@ %-----------------------------------------------------------------------------% +tcp__shutdown(tcp(_, Handle)) --> + handle_shutdown(get_orig_type(Handle)). + +:- pred handle_shutdown(tcp_handle::in, io__state::di, io__state::uo) is det. + +:- pragma c_code(handle_shutdown(TCP::in, IO0::di, IO::uo), + [will_not_call_mercury, thread_safe], "{ + + struct linger sockets_linger = { TRUE, 2 }; + ML_tcp *sock; + + sock = (ML_tcp *) TCP; + + setsockopt(sock->socket, SOL_SOCKET, SO_LINGER, + &sockets_linger, sizeof(sockets_linger)); + + if (shutdown(sock->socket, FULL) == SOCKET_ERROR) { + ML_throw_stream_error(""tcp__shutdown failed""); + } + + + IO = IO0; +}"). + +%-----------------------------------------------------------------------------% + :- type tcp_handle ---> socket(c_pointer). :- pragma c_header_code(" @@ -137,6 +166,7 @@ #define ADDRLEN 16 #define BACKLOG 16 +#define FULL 2 typedef struct { int socket; @@ -286,7 +316,7 @@ sock = MR_NEW(ML_tcp); addr = (struct sockaddr_in *) Addr; - sock->socket = accept(Socket, addr, ADDRLEN); + sock->socket = accept(Socket, addr, NULL); sock->error = 0; sock->eof = FALSE; Index: server/Mmakefile =================================================================== RCS file: /cvsroot/quicksilver/webserver/server/Mmakefile,v retrieving revision 1.2 diff -u -r1.2 Mmakefile --- server/Mmakefile 2000/11/20 17:11:39 1.2 +++ server/Mmakefile 2000/11/24 14:17:08 @@ -3,7 +3,9 @@ -include ../Mmake.params VPATH=../concurrency:../net:../stream:$(MMAKE_VPATH) -MCFLAGS=-I ../concurrency -I ../net -I ../stream -MGNUCFLAGS=-I ../concurrency -I ../net -I ../stream +MCFLAGS+=-I ../concurrency -I ../net -I ../stream +MGNUCFLAGS+=-I ../concurrency -I ../net -I ../stream MLLIBS=../net/libnet.$A ../stream/libstream.$A ../concurrency/libconcurrency.$A + depend: server.depend +server: $(MLLIBS) Index: server/server.m =================================================================== RCS file: /cvsroot/quicksilver/webserver/server/server.m,v retrieving revision 1.2 diff -u -r1.2 server.m --- server/server.m 2000/11/20 17:11:39 1.2 +++ server/server.m 2000/11/24 14:17:08 @@ -20,8 +20,8 @@ main --> { Port = 8080 }, - % { tcp__bind("localhost", Port, Result) }, - tcp__bind("193.121.72.12", Port, Result), + tcp__bind("localhost", Port, Result), + % tcp__bind("193.121.72.12", Port, Result), ( { Result = ok(Listen) }, service_connections(Listen) @@ -33,7 +33,8 @@ %-----------------------------------------------------------------------------% -:- pred service_connections(bound_tcp::in, io__state::di, io__state::uo) is cc_multi. +:- pred service_connections(bound_tcp::in, + io__state::di, io__state::uo) is cc_multi. service_connections(Listen) --> tcp__accept(Listen, Result), @@ -58,10 +59,8 @@ ; { RequestOrResponse = right(Response) } ), - send_response(TCP, Response). - /* - { tcp__shutdown(TCP) }. - */ + send_response(TCP, Response), + tcp__shutdown(TCP). %-----------------------------------------------------------------------------% @@ -108,9 +107,7 @@ Response = response(501, [], no_body, yes), RequestOrResponse = right(Response). parse_request([RequestLine | RequestLines], Either) :- - word(Cmd, RequestLine, RL0), - word(URI, RL0, RL1), - word(HTTP_Version, RL1, _RL), + three_words(Cmd, URI, HTTP_Version, RequestLine, _), ( Cmd \= [], URI \= [], HTTP_Version \= [] -> @@ -123,6 +120,26 @@ ; Response = response(501, [], no_body, yes), Either = right(Response) + ). + +:- pred three_words(list(char)::out, list(char)::out, list(char)::out, + list(char)::in, list(char)::out) is det. + +three_words(One, Two, Three) --> + ws, + word(One), + ws, + word(Two), + ws, + word(Three). + +:- pred ws(list(char)::in, list(char)::out) is det. + +ws --> + ( [Char], { char__is_whitespace(Char) } -> + ws + ; + [] ). :- pred word(list(char)::out, list(char)::in, list(char)::out) is det. Index: stream/impure.m =================================================================== RCS file: /cvsroot/quicksilver/webserver/stream/impure.m,v retrieving revision 1.1 diff -u -r1.1 impure.m --- stream/impure.m 2000/11/20 17:40:40 1.1 +++ stream/impure.m 2000/11/24 14:17:08 @@ -8,7 +8,8 @@ % Main author: petdr % Stability: exceptionally low. % -% An impure interface for describing streams. +% An impure interface for describing streams. You may want to also look +% at the pure lowlevel interface in `lowlevel.m'. % % This file provides a typeclass for people who want to map streams % to a foreign language binding while doing the minimum amount of work. In @@ -22,16 +23,6 @@ % have to do and get right every time you implement a stream, so we have % done it for you. % -% An instance of the pure interface is then easily obtained, as shown by -% the following instance declarations. -% -% :- instance stream__input(impure(your_type)) where [ -% (stream__read_char(S, R) --> impure__read_char(S, R)) -% ]. -% :- instance stream__output(impure(your_type)) where [ -% (stream__write_char(S, C) --> impure__write_char(S, C)) -% ]. -% %-----------------------------------------------------------------------------% %-----------------------------------------------------------------------------% @@ -68,6 +59,8 @@ :- pred impure_init(S::in, impure(S)::out, io__state::di, io__state::uo) is det. +:- func impure__get_orig_type(impure(S)) = S. + %-----------------------------------------------------------------------------% % Read one character of input. This read character @@ -105,6 +98,8 @@ impure_init(S, impure(S, MVar)) --> mutvar__init(MVar), mutvar__put(MVar, unit). + +impure__get_orig_type(impure(S, _)) = S. :- pragma promise_pure(pure_read_char/4). pure_read_char(impure(Stream, MVar), Result, IO0, IO) :- Index: stream/lowlevel.m =================================================================== RCS file: /cvsroot/quicksilver/webserver/stream/lowlevel.m,v retrieving revision 1.1 diff -u -r1.1 lowlevel.m --- stream/lowlevel.m 2000/11/21 10:23:20 1.1 +++ stream/lowlevel.m 2000/11/24 14:17:08 @@ -8,7 +8,8 @@ % Main author: petdr % Stability: exceptionally low. % -% A lowlevel pure interface for describing streams. +% A lowlevel pure interface for describing streams. You may also want +% to look at the impure lowlevel interface in `impure.m'. % % This file provides a typeclass for people who want to map streams % to a foreign language binding while doing the minimizing the amount of @@ -17,7 +18,7 @@ % defined interface. % % This file provides throwing exceptions, grabbing error messages and -% results packaged into ok/error/eof. +% packaging results into ok/error/eof. % %-----------------------------------------------------------------------------% %-----------------------------------------------------------------------------% @@ -36,25 +37,29 @@ % Did an error occur processing the stream? % This predicate must also clear the error status of a % stream after reporting the error. - % The bool indicates whether the predicate succeded. + % The bool indicates whether there was an error. If the + % bool is yes, then the string returned holds the error + % message. pred get_error(S::in, string::out, bool::out, io__state::di, io__state::uo) is det ]. :- typeclass lowlevel__input(S) <= lowlevel(S) where [ - % Read one character from the stream described by S. - % The bool indicates whether the predicate succeded. + % Attempt to read one character from the stream + % described by S. + % The bool indicates whether the character was + % successfully read. pred read_char(S::in, char::out, bool::out, io__state::di, io__state::uo) is det, - % Have we reached the eof for S? - % The bool indicates whether the predicate succeded. + % The bool will be yes iff S is at the end-of-file (eof). pred is_eof(S::in, bool::out, io__state::di, io__state::uo) is det ]. :- typeclass output(S) <= lowlevel(S) where [ - % Read one character from the current stream. - % The bool indicates whether the predicate succeded. + % Attempt to write one character to the current stream. + % The bool indicates whether the character was + % successfully written. pred write_char(S::in, char::in, bool::out, io__state::di, io__state::uo) is det ]. Index: stream/stream.m =================================================================== RCS file: /cvsroot/quicksilver/webserver/stream/stream.m,v retrieving revision 1.3 diff -u -r1.3 stream.m --- stream/stream.m 2000/11/21 10:23:20 1.3 +++ stream/stream.m 2000/11/24 14:17:08 @@ -195,11 +195,13 @@ :- implementation. - % XXX needed so that we can build the library version. + % These two imports are only so that when building a stand-alone + % stream library we include the following modules in the + % library. :- import_module (impure), lowlevel. :- import_module mutvar. -:- import_module int, string. +:- import_module exception, int, string. :- type putback(S) ---> pb( @@ -430,5 +432,13 @@ { Result = error(Error) } ). +%-----------------------------------------------------------------------------% +%-----------------------------------------------------------------------------% + +:- pred throw_stream_error(string::in) is erroneous. +:- pragma export(throw_stream_error(in), "ML_throw_stream_error"). + +throw_stream_error(String) :- + throw(stream_error(String)). %-----------------------------------------------------------------------------% %-----------------------------------------------------------------------------% |