2 * Copyright 1995, 2003 Perforce Software. All rights reserved.
6 * Spec.h - spec manipulation
10 * A 'spec' is one of those dumb ascii forms that user edits
11 * to specify various information -- clients, labels, etc.
13 * The Spec class is a spec definition, indicating what fields
14 * there are and their format. For formatting and parsing,
15 * Spec::Format() and Spec::Parse() expect a subclassed
16 * SpecData object, with SpecData::Get() and SpecData::Put()
17 * defined for moving data between the actual object and the spec.
19 * The Spec object contains SpecElems to describe each element
22 * A Spec can be encoded into a simple string for passing between
23 * processes. Spec::Encode() and Spec::Decode() do this. They
24 * are built for interoperability. Namely, Decode() ignores fields
25 * it doesn't understand.
27 * Finally, a Spec is also be represented as a 'jobspec': this is
28 * actually a form (formatted by Spec) that describes another Spec
29 * (in jobspec's case, a job's Spec). The SpecData that does this
30 * is part of the jobspec code, but that uses Spec::Add(), Get()
31 * and SpecElem::Fmt*() and Set*() for low level construction/
32 * examination of the spec.
34 * Spec definition strings:
36 * A Spec is described by a definition string, parsed by
37 * Spec::Encode() and regenerated (if needed) by Spec::Decode().
38 * Each item on the form is describe by a substring separated by
39 * other items by ";;". That substring contains a number of codes
40 * separated by ";". Each code is one of the following:
44 * type:word single line with N words each
45 * type:wlist list of lines with N words each
46 * type:select single line with a word selected from a list
47 * type:line single line of arbitrary data
48 * type:llist list of lines of arbitrary data
49 * type:date single line with a date on it
50 * type:text block of text spanning any number of lines
51 * type:bulk text that doesn't get indexed (for jobs)
53 * opt:X how optional the field is
55 * opt:optional not required
56 * opt:default required, and has a default
57 * opt:required required, but no default
58 * opt:once read-only; set automatically before user gets it
59 * opt:always read-only; field set automatically after user
61 * code:X a unique numeric code identifying the field
62 * len:X advisory length for displaying field
63 * pre=X preset value for opt:once, opt:always
64 * ro old name for opt:always
65 * rq old name for opt:required
66 * seq:X advisory sequence for display field
67 * val:X /-separated list of values for type:select
68 * words:X the number of words for a word/wlist field
70 * fmt:X advisory format for displaying field
72 * fmt:none normal (full width)
73 * fmt:L left half only
74 * fmt:R right half only; if follows L goes on same line
79 * Spec - the definition of a spec, for parsing and formatting
80 * SpecElem - the definition of a single item type in a spec
81 * SpecData - a spec-specific formatter/parser helper
82 * SpecWords -- array of words in a spec value, allowing surrounding "'s
83 * SpecDataTable -- a SpecData interface to a StrDict
85 * Virtual methods, to be defined by caller:
87 * SpecData::Get() - get a data value for stuffing into a spec
88 * SpecData::Set() - set a data value parsed from a spec
92 * Spec::Add() -- add a single SpecElem manually, with default values
93 * Spec::Decode() -- decode a spec definition from a string
94 * Spec::Encode() -- encode a spec definition in a transmittable string
95 * Spec::Find() -- find a SpecElem in the spec
96 * Spec::Get() -- find n'th SpecElem in the spec
97 * Spec::GetComment() -- return the spec's comment string
98 * Spec::Format() -- turn SpecData into a spec string
99 * Spec::Parse() -- parse a spec string into SpecData
100 * Spec::ParseNoValid() -- parse without validating 'select' items
101 * Spec::SetComment() -- set the spec's comment string
103 * SpecElem::FmtOpt() - format the SpecOpt for jobspec
104 * SpecElem::FmtType() - format the SpecType for jobspec
105 * SpecElem::FmtFmt() - format the SpecFmt for jobspec
106 * SpecElem::Is*() - ask various questions about the SpecType
107 * SpecElem::SetOpt() - parse the SpecOpt from a jobspec
108 * SpecElem::SetType() - format the SpecOpt for a jobspec
109 * SpecElem::Compare() - compare SpecElems from different specs
120 const int SpecWordsMax
= 10; // for SDT_WORD, WLIST, SELECT
123 SDT_WORD
, // single line, N words
124 SDT_WLIST
, // multiple lines, N words
125 SDT_SELECT
, // SDT_WORD from a list of words
126 SDT_LINE
, // single line of text (arbitrary words)
127 SDT_LLIST
, // multiple lines of text (arbitrary words)
128 SDT_DATE
, // SDT_LINE that is a date
129 SDT_TEXT
, // block of text,
130 SDT_BULK
// SDT_TEXT not indexed
134 SDO_OPTIONAL
, // not required, user updatable, no default
135 SDO_DEFAULT
, // not required, user updatable, default provided
136 SDO_REQUIRED
, // required, user updatable, default provided
137 SDO_ONCE
, // required, not updatable, set once after creation
138 SDO_ALWAYS
, // required, not updatable, set after every update
139 SDO_KEY
// required, not updatable, set once before creation
143 SDF_NORMAL
, // no hint given
144 SDF_LEFT
, // left half only
145 SDF_RIGHT
, // right half only; if follows LEFT goes on same line
146 SDF_INDENT
// indented
153 Spec( const char *encoded
, const char *cmt
);
156 // Using the Spec -- formatting and parsing forms
158 StrBuf
* Format( SpecData
*data
)
159 { StrBuf
*s
= new StrBuf
; Format( data
, s
); return s
; }
161 void Format( SpecData
*data
, StrBuf
*result
);
162 void Format( SpecData
*data
, StrDict
*result
);
164 void Parse( const char *buf
, SpecData
*data
, Error
*e
, int valid
);
166 void Parse( const char *buf
, SpecData
*data
, Error
*e
)
167 { Parse( buf
, data
, e
, 1 ); }
168 void ParseNoValid( const char *buf
, SpecData
*data
, Error
*e
)
169 { Parse( buf
, data
, e
, 0 ); }
171 // Manipulating the Spec itself -- building and examining it
173 SpecElem
* Add( const StrPtr
&tag
);
174 SpecElem
* Get( int i
);
175 SpecElem
* Find( const StrPtr
&tag
, Error
*e
= 0 );
176 SpecElem
* Find( int code
, Error
*e
= 0 );
179 void Decode( StrPtr
*encoded
, Error
*e
);
180 void Encode( StrBuf
*encoded
);
182 const StrPtr
* GetComment() { return &comment
; }
183 void SetComment( const StrPtr
&c
) { comment
= c
; }
185 SpecElem
* Add( char *t
) { return Add( StrRef( t
) ); }
191 StrBuf decoderBuffer
;
200 int IsDate() { return type
== SDT_DATE
; }
201 int IsSelect() { return type
== SDT_SELECT
; }
202 int IsText() { return type
== SDT_TEXT
203 || type
== SDT_BULK
; }
204 int IsList() { return type
== SDT_WLIST
205 || type
== SDT_LLIST
; }
206 int IsWords() { return type
== SDT_WORD
208 || type
== SDT_SELECT
; }
209 int IsSingle() { return type
== SDT_WORD
210 || type
== SDT_SELECT
212 || type
== SDT_DATE
; }
214 int CheckValue( StrBuf
&value
);
218 int IsRequired() { return opt
== SDO_REQUIRED
221 int IsReadOnly() { return opt
== SDO_ONCE
227 SpecFmt
GetFmt() { return fmt
; }
228 int GetSeq() { return seq
; }
230 // Type building -- so jobspec can create a spec
232 const char * FmtOpt();
233 const char * FmtType();
234 const char * FmtFmt();
235 void SetSeq( int s
) { seq
= s
; }
236 void SetOpt( const char *optName
, Error
*e
);
237 void SetFmt( const char *fmtName
, Error
*e
);
238 void SetType( const char *s
, Error
*e
);
240 int Compare( const SpecElem
&other
);
242 public: // only to SpecData's subclasses
244 SpecType type
; // how it is formatted
245 StrBuf tag
; // name of the field
246 StrBuf preset
; // default preset value
247 StrBuf values
; // what values can be had
248 int code
; // what it's use it
249 StrBuf subCode
; // user's code
250 char nWords
; // how many words on the line
251 short maxLength
; // advisory
252 SpecOpt opt
; // how field is updated
257 void Decode( StrRef
*s
, Error
*e
);
258 void Encode( StrBuf
*s
, int code
);
262 SpecFmt fmt
; // format code
263 int seq
; // display sequence number
265 // reference back to Get(index)
270 class SpecWords
: public StrBuf
275 const char *wv
[ SpecWordsMax
+ 1 ];
281 virtual ~SpecData() {}
282 // Extract data from or build data into user's data structure.
283 // Spec::Format() calls Get(); Spec::Parse() calls Set().
285 // One of the two sets of Get/Set must be replaced in the subclass.
287 // This interface assumes whole lines. Its default implementation
288 // calls the word-oriented Get/Set and Joins/Splits them into
291 virtual StrPtr
*GetLine( SpecElem
*sd
, int x
, const char **cmt
);
292 virtual void SetLine( SpecElem
*sd
, int x
, const StrPtr
*val
,
295 // This interface has words-oriented lines split apart.
296 // The const version casts and calls the non-const version,
297 // for compatibility.
299 // The non-const one has a bogus default implementation.
301 virtual int Get( SpecElem
*sd
, int x
, const char **wv
, const char **cmt
);
302 virtual void Set( SpecElem
*sd
, int x
, const char **wv
, Error
*e
);
304 virtual int Get( SpecElem
*sd
, int x
, char **wv
, char **cmt
);
305 virtual void Set( SpecElem
*sd
, int x
, char **wv
, Error
*e
);
313 class SpecDataTable
: public SpecData
{
317 virtual ~SpecDataTable();
319 virtual StrPtr
*GetLine( SpecElem
*sd
, int x
, const char **cmt
);
320 virtual void SetLine( SpecElem
*sd
, int x
, const StrPtr
*val
,
323 StrDict
* Dict() { return table
; }
331 #endif /* _spec_h_ */