blob: 7b26f6fa0ebc8703826f94a0d7d1c027ecac8c05 [file] [log] [blame]
Stuart McCullochbb014372012-06-07 21:57:32 +00001package aQute.libg.header;
2
3import java.util.*;
4
5import aQute.libg.generics.*;
6import aQute.libg.qtokens.*;
7import aQute.libg.reporter.*;
8
9public class OSGiHeader {
10
11 static public Parameters parseHeader(String value) {
12 return parseHeader(value, null);
13 }
14
15 /**
16 * Standard OSGi header parser. This parser can handle the format clauses
17 * ::= clause ( ',' clause ) + clause ::= name ( ';' name ) (';' key '='
18 * value )
19 *
20 * This is mapped to a Map { name => Map { attr|directive => value } }
21 *
22 * @param value
23 * A string
24 * @return a Map<String,Map<String,String>>
25 */
26 static public Parameters parseHeader(String value, Reporter logger) {
27 return parseHeader(value, logger, new Parameters());
28 }
29
30 static public Parameters parseHeader(String value, Reporter logger, Parameters result) {
31 if (value == null || value.trim().length() == 0)
32 return result;
33
34 QuotedTokenizer qt = new QuotedTokenizer(value, ";=,");
35 char del = 0;
36 do {
37 boolean hadAttribute = false;
38 Attrs clause = new Attrs();
39 List<String> aliases = Create.list();
40 String name = qt.nextToken(",;");
41
42 del = qt.getSeparator();
43 if (name == null || name.length() == 0) {
44 if (logger != null && logger.isPedantic()) {
45 logger.warning("Empty clause, usually caused by repeating a comma without any name field or by having spaces after the backslash of a property file: "
46 + value);
47 }
48 if (name == null)
49 break;
50 } else {
51 name = name.trim();
52
53 aliases.add(name);
54 while (del == ';') {
55 String adname = qt.nextToken();
56 if ((del = qt.getSeparator()) != '=') {
57 if (hadAttribute)
58 if (logger != null) {
59 logger.error("Header contains name field after attribute or directive: "
60 + adname
61 + " from "
62 + value
63 + ". Name fields must be consecutive, separated by a ';' like a;b;c;x=3;y=4");
64 }
65 if (adname != null && adname.length() > 0)
66 aliases.add(adname.trim());
67 } else {
68 String advalue = qt.nextToken();
69 if (clause.containsKey(adname)) {
70 if (logger != null && logger.isPedantic())
71 logger.warning("Duplicate attribute/directive name " + adname
72 + " in " + value
73 + ". This attribute/directive will be ignored");
74 }
75 if (advalue == null) {
76 if (logger != null)
77 logger.error("No value after '=' sign for attribute " + adname);
78 advalue = "";
79 }
80 clause.put(adname.trim(), advalue.trim());
81 del = qt.getSeparator();
82 hadAttribute = true;
83 }
84 }
85
86 // Check for duplicate names. The aliases list contains
87 // the list of nams, for each check if it exists. If so,
88 // add a number of "~" to make it unique.
89 for (String clauseName : aliases) {
90 if (result.containsKey(clauseName)) {
91 if (logger != null && logger.isPedantic())
92 logger.warning("Duplicate name "
93 + clauseName
94 + " used in header: '"
95 + clauseName
96 + "'. Duplicate names are specially marked in Bnd with a ~ at the end (which is stripped at printing time).");
97 while (result.containsKey(clauseName))
98 clauseName += "~";
99 }
100 result.put(clauseName, clause);
101 }
102 }
103 } while (del == ',');
104 return result;
105 }
106
107 public static Attrs parseProperties(String input) {
108 return parseProperties(input, null);
109 }
110
111 public static Attrs parseProperties(String input, Reporter logger) {
112 if (input == null || input.trim().length() == 0)
113 return new Attrs();
114
115 Attrs result = new Attrs();
116 QuotedTokenizer qt = new QuotedTokenizer(input, "=,");
117 char del = ',';
118
119 while (del == ',') {
120 String key = qt.nextToken(",=");
121 String value = "";
122 del = qt.getSeparator();
123 if (del == '=') {
124 value = qt.nextToken(",=");
125 del = qt.getSeparator();
126 }
127 result.put(key, value);
128 }
129 if (del != 0) {
130 if (logger == null)
131 throw new IllegalArgumentException("Invalid syntax for properties: " + input);
132 logger.error("Invalid syntax for properties: " + input);
133 }
134
135 return result;
136 }
137
138}