1
-------------------------------------------------------------------------------
3
-- This file is part of AdaBrowse.
5
-- <STRONG>Copyright (c) 2002 by Thomas Wolf.</STRONG>
7
-- AdaBrowse is free software; you can redistribute it and/or modify it
8
-- under the terms of the GNU General Public License as published by the
9
-- Free Software Foundation; either version 2, or (at your option) any
10
-- later version. AdaBrowse is distributed in the hope that it will be
11
-- useful, but <EM>without any warranty</EM>; without even the implied
12
-- warranty of <EM>merchantability or fitness for a particular purpose.</EM>
13
-- See the GNU General Public License for more details. You should have
14
-- received a copy of the GNU General Public License with this distribution,
15
-- see file "<A HREF="GPL.txt">GPL.txt</A>". If not, write to the Free
16
-- Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307,
21
-- Author:</STRONG><DD>
23
-- <ADDRESS><A HREF="mailto:twolf@acm.org">twolf@acm.org</A></ADDRESS></DL>
26
-- Purpose:</STRONG><DD>
27
-- Configuration file management.</DL>
32
-- 05-FEB-2002 TW Created from stuff that had piled up in AD.HTML.
33
-- 18-FEB-2002 TW 'Configure' now skips empty lines.
34
-- 22-FEB-2002 TW 'Configure' now skips any non-empty lines that start
35
-- with '#': this allows comments in configuration files.
36
-- Also improved some error messages.
37
-- 12-MAR-2002 TW Uses Util.Files.Text_IO.Next_Line now to read the
38
-- configuration file.
39
-- 13-MAR-2002 TW Added key 'Index_XRef'.
40
-- 14-MAR-2002 TW Added key 'Index_Title'.
41
-- 02-MAY-2002 TW Added key 'Include_File', rewrote 'Configure' to do file
42
-- inclusion and check for recursive inclusions.
43
-- 24-JUN-2002 TW Changed to use new package 'Util.Files.Config'.
44
-- 28-JUN-2002 TW Unquotes now the compile command and index titles.
45
-- 03-JUL-2002 TW Handled the case-sensitivity bug for the "Path." keys
46
-- at the source: I mistakenly used 'Key' instead of 'K'.
47
-- 04-JUN-2002 TW Added "include" and "xref" keys.
48
-- 08-JUN-2003 TW Added 'Full_Name' to 'Set_File_Name'.
49
-- 02-JUL-2003 TW Added support for the "index" and "rule" keys.
50
-- 18-NOV-2003 TW Use AD.Environment.Get to make sure to account for -X
53
-------------------------------------------------------------------------------
58
with Ada.Strings.Maps;
59
with Ada.Strings.Unbounded;
60
with Ada.Unchecked_Deallocation;
70
with AD.Indices.Configuration;
73
with AD.Printers.HTML;
76
with Util.Environment.Bash;
77
with Util.Files.Config;
81
package body AD.Config is
83
package ASU renames Ada.Strings.Unbounded;
89
procedure Deallocate is
90
new Ada.Unchecked_Deallocation (String, ASU.String_Access);
92
Reorder : constant Boolean := True;
94
Config_Files : ASU.Unbounded_String;
95
Nof_Config_Files : Natural := 0;
97
function Get_Nof_Config_Files
101
return Nof_Config_Files;
102
end Get_Nof_Config_Files;
104
function Get_Config_Files
108
return ASU.To_String (Config_Files);
109
end Get_Config_Files;
118
----------------------------------------------------------------------------
120
type Add_Procedure is access procedure (Key : in String);
122
----------------------------------------------------------------------------
124
type Environment_Expander is
125
new Util.Environment.Bash.Bash_Expander with
127
File_Name : ASU.String_Access;
131
(Self : access Environment_Expander;
136
(Self : access Environment_Expander;
141
(Self : access Environment_Expander;
146
if Source'Last >= Source'First and then
147
(Source (Source'First) = '@' or else Source (Source'First) = '$')
152
return Util.Environment.Bash.Legal_Name
153
(Util.Environment.Bash.Bash_Expander (Self.all)'Access,
158
(Self : access Environment_Expander;
164
return Util.Pathes.Name (Self.File_Name.all);
165
elsif Name = "@" then
166
return Util.Pathes.Normalize (Util.Pathes.Path (Self.File_Name.all));
168
return AD.Environment.Get (Name);
170
-- return Util.Environment.Bash.Get
171
-- (Util.Environment.Bash.Bash_Expander (Self.all)'Access,
175
----------------------------------------------------------------------------
177
type Reader (Expander : access Environment_Expander) is
178
new Util.Files.Config.Reader with null record;
180
procedure Set_File_Name
181
(Self : in out Reader;
183
Full_Name : in String);
187
return Ada.Strings.Maps.Character_Set;
192
Delim : in Character)
201
(Self : in out Reader;
203
Operator : in String;
206
procedure Set_File_Name
207
(Self : in out Reader;
209
Full_Name : in String)
211
pragma Warnings (Off, Self); -- silence -gnatwa
213
if Nof_Config_Files = 0 then
214
Config_Files := ASU.To_Unbounded_String (Name);
216
ASU.Append (Config_Files, ", " & Name);
218
Nof_Config_Files := Nof_Config_Files + 1;
219
Self.Expander.File_Name := new String'(Full_Name);
224
return Ada.Strings.Maps.Character_Set
226
pragma Warnings (Off, Self); -- silence -gnatwa
228
return Util.Strings.Shell_Quotes;
234
Delim : in Character)
237
pragma Warnings (Off, Self); -- silence -gnatwa
239
-- Ada format: enclosed delimiters must be doubled.
240
return Util.Strings.Skip_String (Line, Delim, Delim);
250
I := Util.Files.Config.Parse_Key (Util.Files.Config.Reader (Self), Line);
251
-- "Format." key may be followed by a string!
252
if I > 0 and then I + 1 < Line'Last then
253
if Line (I + 1) = '.' and then
254
Is_In (String_Quotes, Line (I + 2)) and then
255
To_Lower (Line (Line'First .. I + 1)) = "format."
257
-- Last component may be a string!
258
I := Skip_String (Self, Line (I + 2 .. Line'Last), Line (I + 2));
260
Ada.Exceptions.Raise_Exception
261
(Invalid_Config'Identity,
262
"unterminated string found");
270
(Self : in out Reader;
272
Operator : in String;
276
pragma Warnings (Off, Operator); -- silence -gnatwa
279
(Add : in Add_Procedure;
285
while I <= Value'Last loop
286
J := Index (Value (I .. Value'Last), ',');
287
if J = 0 then J := Value'Last + 1; end if;
289
Prefix : constant String := Trim (Value (I .. J - 1));
291
if Prefix'Last >= Prefix'First then
292
Add (To_Lower (Prefix));
304
return Boolean'Value (To_Upper (Str));
307
Ada.Exceptions.Raise_Exception
308
(Invalid_Config'Identity,
309
"value must be either 'True' or 'False'");
313
K : constant String := To_Lower (Key);
316
if K = "include_file" then
317
-- Recursive include of a configuration file.
319
use type ASU.String_Access;
320
Old_File : constant ASU.String_Access := Self.Expander.File_Name;
321
Name : constant String :=
322
Expand (Self.Expander, Value);
324
-- Note: expansion still uses the old file name!
325
if Name'Last >= Name'First then
326
Util.Files.Config.Read (Name, Self);
327
if Self.Expander.File_Name /= Old_File then
328
Deallocate (Self.Expander.File_Name);
329
Self.Expander.File_Name := Old_File;
334
if Self.Expander.File_Name /= Old_File then
335
Deallocate (Self.Expander.File_Name);
336
Self.Expander.File_Name := Old_File;
340
elsif K = "refs_to_standard" then
341
AD.Crossrefs.Set_Standard_Units (Read_Bool (Value));
342
elsif K = "compile" then
343
AD.Compiler.Set_Compile_Command
344
(Expand (Self.Expander, Unquote_All (Value, Shell_Quotes)));
345
elsif K = "index_title" then
346
AD.Indices.Configuration.Set_Title
347
(AD.Indices.Configuration.Unit_Index, Value);
348
elsif K = "index_xref" then
349
AD.Printers.HTML.Set_Index_XRef (Value);
350
elsif K = "char_set" then
351
Set_Char_Set (Value);
352
elsif K = "style_sheet" then
353
Set_Style_Sheet (Expand (Self.Expander, Value));
354
elsif K = "body" then
356
elsif K = "title.before" then
357
Set_Title (Before, Value);
358
elsif K = "title.after" then
359
Set_Title (After, Value);
360
elsif K = "sub_title.before" then
361
Set_Subtitle (Before, Value);
362
elsif K = "sub_title.after" then
363
Set_Subtitle (After, Value);
364
elsif K = "keyword.before" then
365
Set_Keyword (Before, Value);
366
elsif K = "keyword.after" then
367
Set_Keyword (After, Value);
368
elsif K = "attribute.before" then
369
Set_Attribute (Before, Value);
370
elsif K = "attribute.after" then
371
Set_Attribute (After, Value);
372
elsif K = "definition.before" then
373
Set_Definition (Before, Value);
374
elsif K = "definition.after" then
375
Set_Definition (After, Value);
376
elsif K = "comment.before" then
377
Set_Comment (Before, Value);
378
elsif K = "comment.after" then
379
Set_Comment (After, Value);
380
elsif K = "literal.before" then
381
Set_Literal (Before, Value);
382
elsif K = "literal.after" then
383
Set_Literal (After, Value);
384
elsif K = "no_xref" then
385
Parse_List (AD.Exclusions.Add_No_XRef'Access, Value);
386
elsif K = "xref" then
387
Parse_List (AD.Exclusions.Add_No_XRef_Exception'Access, Value);
388
elsif K = "exclude" then
389
if Value'Last < Value'First then
390
AD.Exclusions.Clear_Exclusions;
392
Parse_List (AD.Exclusions.Add_Exclusion'Access, Value);
394
elsif K = "include" then
395
if Value'Last < Value'First then
396
AD.Exclusions.Clear_Exclusion_Exceptions;
398
Parse_List (AD.Exclusions.Add_Exclusion_Exception'Access, Value);
400
elsif Is_Prefix (K, "path.") then
402
AD.HTML.Pathes.Add_Path
403
(K (K'First + 5 .. K'Last), Expand (Self.Expander, Value));
405
Ada.Exceptions.Raise_Exception
406
(Invalid_Config'Identity, ''' & Key & "' is an invalid key.");
408
elsif Is_Prefix (K, "description.") then
409
AD.Descriptions.Parse (K (K'First + 12 .. K'Last), Value);
410
elsif Is_Prefix (K, "index_title.") then
412
use AD.Indices.Configuration;
416
Idx := Index_Type'Value (To_Upper (K (K'First + 12 .. K'Last)));
419
Ada.Exceptions.Raise_Exception
420
(Invalid_Config'Identity,
421
''' & Key & "' is an invalid key.");
423
AD.Indices.Configuration.Set_Title
424
(Idx, Unquote_All (Value, Shell_Quotes));
426
elsif Is_Prefix (K, "user_tag.") then
428
AD.User_Tags.Parse_Tag
429
(K (K'First + 9 .. K'Last), Value, Self.Expander);
431
when E : AD.User_Tags.Invalid_Tag =>
432
Ada.Exceptions.Raise_Exception
433
(Invalid_Config'Identity,
434
Ada.Exceptions.Exception_Message (E));
436
elsif Is_Prefix (K, "format.") then
440
-- Use 'Key' here, for the string must be case sensitive!!
441
if Key'Length > 8 then
442
if Is_In (String_Quotes, Key (Key'First + 7)) then
445
(Self, Key (Key'First + 7 .. Key'Last),
446
Key (Key'First + 7));
450
Ada.Exceptions.Raise_Exception
451
(Invalid_Config'Identity,
452
"'Format.' must be followed by a string");
454
Ada.Exceptions.Raise_Exception
455
(Invalid_Config'Identity,
456
"Unterminated string after 'Format.'");
458
if not Is_Prefix (Key (A + 1 .. B - 1), "--") then
459
Ada.Exceptions.Raise_Exception
460
(Invalid_Config'Identity,
461
"Format comment prefix must start with ""--""");
465
(Unquote (Key (A + 1 .. B - 1), Key (A), Key (A)),
466
AD.Filters.Parse (Expand (Self.Expander, Value)));
468
when E : AD.Filters.Parse_Error =>
469
Ada.Exceptions.Raise_Exception
470
(Invalid_Config'Identity,
471
Ada.Exceptions.Exception_Message (E));
474
elsif Is_Prefix (K, "rule.") then
475
-- Must be followed by an identifier.
477
I : constant Natural := Identifier (K (K'First + 5 .. K'Last));
480
Ada.Exceptions.Raise_Exception
481
(Invalid_Config'Identity,
482
"'Rule.' must be followed by an identifier");
483
elsif I /= K'Last then
484
Ada.Exceptions.Raise_Exception
485
(Invalid_Config'Identity,
486
"Key must have the form 'Rule.<Identifier>'");
490
Expr : AD.Expressions.Expression;
493
Expr := AD.Expressions.Parse (Value);
494
AD.Expressions.Define_Macro
495
(Key (Key'First + 5 .. Key'Last), Expr, Redefined);
498
(Key & " redefined in " & Self.Expander.File_Name.all);
501
when E : AD.Expressions.Parse_Error =>
502
Ada.Exceptions.Raise_Exception
503
(Invalid_Config'Identity,
504
Ada.Exceptions.Exception_Message (E));
506
elsif Is_Prefix (K, "index.") then
507
AD.Indices.Configuration.Parse
508
(Key (Key'First + 6 .. Key'Last), Expand (Self.Expander, Value));
510
Ada.Exceptions.Raise_Exception
511
(Invalid_Config'Identity, "unknown key '" & Key & ''');
515
----------------------------------------------------------------------------
518
(File_Name : in String)
521
Expander : aliased Environment_Expander;
522
Parser : Reader (Expander'Access);
525
Util.Files.Config.Read (File_Name, Parser);
526
Deallocate (Expander.File_Name);
529
Deallocate (Expander.File_Name);
530
Ada.Exceptions.Raise_Exception
531
(Invalid_Config'Identity,
532
Ada.Exceptions.Exception_Message (E));