2009-07-17 Richard Guenther <rguenther@suse.de>
[official-gcc.git] / gcc / ada / g-cgi.adb
blobdad37381129d9f835585df1bf4e352b30ac54fa2
1 ------------------------------------------------------------------------------
2 -- --
3 -- GNAT COMPILER COMPONENTS --
4 -- --
5 -- G N A T . C G I --
6 -- --
7 -- B o d y --
8 -- --
9 -- Copyright (C) 2001-2009, AdaCore --
10 -- --
11 -- GNAT is free software; you can redistribute it and/or modify it under --
12 -- terms of the GNU General Public License as published by the Free Soft- --
13 -- ware Foundation; either version 2, or (at your option) any later ver- --
14 -- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
15 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
16 -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License --
17 -- for more details. You should have received a copy of the GNU General --
18 -- Public License distributed with GNAT; see file COPYING. If not, write --
19 -- to the Free Software Foundation, 51 Franklin Street, Fifth Floor, --
20 -- Boston, MA 02110-1301, USA. --
21 -- --
22 -- As a special exception, if other files instantiate generics from this --
23 -- unit, or you link this unit with other files to produce an executable, --
24 -- this unit does not by itself cause the resulting executable to be --
25 -- covered by the GNU General Public License. This exception does not --
26 -- however invalidate any other reasons why the executable file might be --
27 -- covered by the GNU Public License. --
28 -- --
29 -- GNAT was originally developed by the GNAT team at New York University. --
30 -- Extensive contributions were provided by Ada Core Technologies Inc. --
31 -- --
32 ------------------------------------------------------------------------------
34 with Ada.Text_IO;
35 with Ada.Strings.Fixed;
36 with Ada.Characters.Handling;
37 with Ada.Strings.Maps;
39 with GNAT.OS_Lib;
40 with GNAT.Table;
42 package body GNAT.CGI is
44 use Ada;
46 Valid_Environment : Boolean := True;
47 -- This boolean will be set to False if the initialization was not
48 -- completed correctly. It must be set to true there because the
49 -- Initialize routine (called during elaboration) will use some of the
50 -- services exported by this unit.
52 Current_Method : Method_Type;
53 -- This is the current method used to pass CGI parameters
55 Header_Sent : Boolean := False;
56 -- Will be set to True when the header will be sent
58 -- Key/Value table declaration
60 type String_Access is access String;
62 type Key_Value is record
63 Key : String_Access;
64 Value : String_Access;
65 end record;
67 package Key_Value_Table is new Table (Key_Value, Positive, 1, 1, 50);
69 -----------------------
70 -- Local subprograms --
71 -----------------------
73 procedure Check_Environment;
74 pragma Inline (Check_Environment);
75 -- This procedure will raise Data_Error if Valid_Environment is False
77 procedure Initialize;
78 -- Initialize CGI package by reading the runtime environment. This
79 -- procedure is called during elaboration. All exceptions raised during
80 -- this procedure are deferred.
82 --------------------
83 -- Argument_Count --
84 --------------------
86 function Argument_Count return Natural is
87 begin
88 Check_Environment;
89 return Key_Value_Table.Last;
90 end Argument_Count;
92 -----------------------
93 -- Check_Environment --
94 -----------------------
96 procedure Check_Environment is
97 begin
98 if not Valid_Environment then
99 raise Data_Error;
100 end if;
101 end Check_Environment;
103 ------------
104 -- Decode --
105 ------------
107 function Decode (S : String) return String is
108 Result : String (S'Range);
109 K : Positive := S'First;
110 J : Positive := Result'First;
112 begin
113 while K <= S'Last loop
114 if K + 2 <= S'Last
115 and then S (K) = '%'
116 and then Characters.Handling.Is_Hexadecimal_Digit (S (K + 1))
117 and then Characters.Handling.Is_Hexadecimal_Digit (S (K + 2))
118 then
119 -- Here we have '%HH' which is an encoded character where 'HH' is
120 -- the character number in hexadecimal.
122 Result (J) := Character'Val
123 (Natural'Value ("16#" & S (K + 1 .. K + 2) & '#'));
124 K := K + 3;
126 -- Plus sign is decoded as a space
128 elsif S (K) = '+' then
129 Result (J) := ' ';
130 K := K + 1;
132 else
133 Result (J) := S (K);
134 K := K + 1;
135 end if;
137 J := J + 1;
138 end loop;
140 return Result (Result'First .. J - 1);
141 end Decode;
143 -------------------------
144 -- For_Every_Parameter --
145 -------------------------
147 procedure For_Every_Parameter is
148 Quit : Boolean;
150 begin
151 Check_Environment;
153 for K in 1 .. Key_Value_Table.Last loop
155 Quit := False;
157 Action (Key_Value_Table.Table (K).Key.all,
158 Key_Value_Table.Table (K).Value.all,
160 Quit);
162 exit when Quit;
164 end loop;
165 end For_Every_Parameter;
167 ----------------
168 -- Initialize --
169 ----------------
171 procedure Initialize is
173 Request_Method : constant String :=
174 Characters.Handling.To_Upper
175 (Metavariable (CGI.Request_Method));
177 procedure Initialize_GET;
178 -- Read CGI parameters for a GET method. In this case the parameters
179 -- are passed into QUERY_STRING environment variable.
181 procedure Initialize_POST;
182 -- Read CGI parameters for a POST method. In this case the parameters
183 -- are passed with the standard input. The total number of characters
184 -- for the data is passed in CONTENT_LENGTH environment variable.
186 procedure Set_Parameter_Table (Data : String);
187 -- Parse the parameter data and set the parameter table
189 --------------------
190 -- Initialize_GET --
191 --------------------
193 procedure Initialize_GET is
194 Data : constant String := Metavariable (Query_String);
195 begin
196 Current_Method := Get;
198 if Data /= "" then
199 Set_Parameter_Table (Data);
200 end if;
201 end Initialize_GET;
203 ---------------------
204 -- Initialize_POST --
205 ---------------------
207 procedure Initialize_POST is
208 Content_Length : constant Natural :=
209 Natural'Value (Metavariable (CGI.Content_Length));
210 Data : String (1 .. Content_Length);
212 begin
213 Current_Method := Post;
215 if Content_Length /= 0 then
216 Text_IO.Get (Data);
217 Set_Parameter_Table (Data);
218 end if;
219 end Initialize_POST;
221 -------------------------
222 -- Set_Parameter_Table --
223 -------------------------
225 procedure Set_Parameter_Table (Data : String) is
227 procedure Add_Parameter (K : Positive; P : String);
228 -- Add a single parameter into the table at index K. The parameter
229 -- format is "key=value".
231 Count : constant Positive :=
232 1 + Strings.Fixed.Count (Data, Strings.Maps.To_Set ("&"));
233 -- Count is the number of parameters in the string. Parameters are
234 -- separated by ampersand character.
236 Index : Positive := Data'First;
237 Amp : Natural;
239 -------------------
240 -- Add_Parameter --
241 -------------------
243 procedure Add_Parameter (K : Positive; P : String) is
244 Equal : constant Natural := Strings.Fixed.Index (P, "=");
246 begin
247 if Equal = 0 then
248 raise Data_Error;
250 else
251 Key_Value_Table.Table (K) :=
252 Key_Value'(new String'(Decode (P (P'First .. Equal - 1))),
253 new String'(Decode (P (Equal + 1 .. P'Last))));
254 end if;
255 end Add_Parameter;
257 -- Start of processing for Set_Parameter_Table
259 begin
260 Key_Value_Table.Set_Last (Count);
262 for K in 1 .. Count - 1 loop
263 Amp := Strings.Fixed.Index (Data (Index .. Data'Last), "&");
265 Add_Parameter (K, Data (Index .. Amp - 1));
267 Index := Amp + 1;
268 end loop;
270 -- add last parameter
272 Add_Parameter (Count, Data (Index .. Data'Last));
273 end Set_Parameter_Table;
275 -- Start of processing for Initialize
277 begin
278 if Request_Method = "GET" then
279 Initialize_GET;
281 elsif Request_Method = "POST" then
282 Initialize_POST;
284 else
285 Valid_Environment := False;
286 end if;
288 exception
289 when others =>
291 -- If we have an exception during initialization of this unit we
292 -- just declare it invalid.
294 Valid_Environment := False;
295 end Initialize;
297 ---------
298 -- Key --
299 ---------
301 function Key (Position : Positive) return String is
302 begin
303 Check_Environment;
305 if Position <= Key_Value_Table.Last then
306 return Key_Value_Table.Table (Position).Key.all;
307 else
308 raise Parameter_Not_Found;
309 end if;
310 end Key;
312 ----------------
313 -- Key_Exists --
314 ----------------
316 function Key_Exists (Key : String) return Boolean is
317 begin
318 Check_Environment;
320 for K in 1 .. Key_Value_Table.Last loop
321 if Key_Value_Table.Table (K).Key.all = Key then
322 return True;
323 end if;
324 end loop;
326 return False;
327 end Key_Exists;
329 ------------------
330 -- Metavariable --
331 ------------------
333 function Metavariable
334 (Name : Metavariable_Name;
335 Required : Boolean := False) return String
337 function Get_Environment (Variable_Name : String) return String;
338 -- Returns the environment variable content
340 ---------------------
341 -- Get_Environment --
342 ---------------------
344 function Get_Environment (Variable_Name : String) return String is
345 Value : OS_Lib.String_Access := OS_Lib.Getenv (Variable_Name);
346 Result : constant String := Value.all;
347 begin
348 OS_Lib.Free (Value);
349 return Result;
350 end Get_Environment;
352 Result : constant String :=
353 Get_Environment (Metavariable_Name'Image (Name));
355 -- Start of processing for Metavariable
357 begin
358 Check_Environment;
360 if Result = "" and then Required then
361 raise Parameter_Not_Found;
362 else
363 return Result;
364 end if;
365 end Metavariable;
367 -------------------------
368 -- Metavariable_Exists --
369 -------------------------
371 function Metavariable_Exists (Name : Metavariable_Name) return Boolean is
372 begin
373 Check_Environment;
375 if Metavariable (Name) = "" then
376 return False;
377 else
378 return True;
379 end if;
380 end Metavariable_Exists;
382 ------------
383 -- Method --
384 ------------
386 function Method return Method_Type is
387 begin
388 Check_Environment;
389 return Current_Method;
390 end Method;
392 --------
393 -- Ok --
394 --------
396 function Ok return Boolean is
397 begin
398 return Valid_Environment;
399 end Ok;
401 ----------------
402 -- Put_Header --
403 ----------------
405 procedure Put_Header
406 (Header : String := Default_Header;
407 Force : Boolean := False)
409 begin
410 if Header_Sent = False or else Force then
411 Check_Environment;
412 Text_IO.Put_Line (Header);
413 Text_IO.New_Line;
414 Header_Sent := True;
415 end if;
416 end Put_Header;
418 ---------
419 -- URL --
420 ---------
422 function URL return String is
424 function Exists_And_Not_80 (Server_Port : String) return String;
425 -- Returns ':' & Server_Port if Server_Port is not "80" and the empty
426 -- string otherwise (80 is the default sever port).
428 -----------------------
429 -- Exists_And_Not_80 --
430 -----------------------
432 function Exists_And_Not_80 (Server_Port : String) return String is
433 begin
434 if Server_Port = "80" then
435 return "";
436 else
437 return ':' & Server_Port;
438 end if;
439 end Exists_And_Not_80;
441 -- Start of processing for URL
443 begin
444 Check_Environment;
446 return "http://"
447 & Metavariable (Server_Name)
448 & Exists_And_Not_80 (Metavariable (Server_Port))
449 & Metavariable (Script_Name);
450 end URL;
452 -----------
453 -- Value --
454 -----------
456 function Value
457 (Key : String;
458 Required : Boolean := False)
459 return String
461 begin
462 Check_Environment;
464 for K in 1 .. Key_Value_Table.Last loop
465 if Key_Value_Table.Table (K).Key.all = Key then
466 return Key_Value_Table.Table (K).Value.all;
467 end if;
468 end loop;
470 if Required then
471 raise Parameter_Not_Found;
472 else
473 return "";
474 end if;
475 end Value;
477 -----------
478 -- Value --
479 -----------
481 function Value (Position : Positive) return String is
482 begin
483 Check_Environment;
485 if Position <= Key_Value_Table.Last then
486 return Key_Value_Table.Table (Position).Value.all;
487 else
488 raise Parameter_Not_Found;
489 end if;
490 end Value;
492 begin
494 Initialize;
496 end GNAT.CGI;