OWLNext    7.0
Borland's Object Windows Library for the modern age
Loading...
Searching...
No Matches
pictval.cpp
Go to the documentation of this file.
1//----------------------------------------------------------------------------
2// ObjectWindows
3// Copyright (c) 1993, 1996 by Borland International, All Rights Reserved
4//
5/// \file
6/// Implementation of TPXPictureValidator, Paradox-picture input validator
7//----------------------------------------------------------------------------
8#include <owl/pch.h>
9
10#include <owl/validate.h>
11#include <owl/validate.rh>
12#include <owl/applicat.h>
13#include <owl/appdict.h>
14#include <owl/framewin.h>
15#include <ctype.h>
16#include <stdio.h>
17
18namespace owl {
19
21
22
23//
24/// Constructs a picture validator object by first calling the constructor inherited
25/// from TValidator and setting pic to point to it. Then sets the voFill bit in
26/// Options if AutoFill is true and sets Options to voOnAppend. Throws a TXValidator
27/// exception if the picture is invalid.
28//
36
37//
38/// String-aware overload
39//
41:
42 TValidator(),
43 Pic(pic)
44{
45 Init(autoFill);
46}
47
48//
49/// Shared initialization
50//
51void TPXPictureValidator::Init(bool autoFill)
52{
54 if (autoFill)
55 Options |= voFill;
56 if (!SyntaxCheck())
58}
59
60//
61/// Overrides TValidator's virtual function and displays a message box that indicates
62/// an error in the picture format and displays the string pointed to by Pic.
63//
64void
66{
68 owner->FormatMessageBox(owner->LoadString(IDS_VALPXPCONFORM), owner->LoadString(IDS_VALCAPTION), MB_ICONERROR | MB_OK, Pic.c_str());
69}
70
71//
72/// IsValidInput overrides TValidator's virtual function and checks the string
73/// passed in str against the format picture specified in Pic. IsValid returns true
74/// if Pic is NULL or Picture does not return Error for str; otherwise, it returns
75/// false. The suppressFill parameter overrides the value in voFill for the duration
76/// of the call to IsValidInput.
77/// If suppressFill is false and voFill is set, the call to Picture returns a filled
78/// string based on str, so the image in the edit control automatically reflects the
79/// format specified in Pic.
80//
81bool
88
89//
90/// IsValid overrides TValidator's virtual function and compares the string passed
91/// in str with the format picture specified in Pic. IsValid returns true if Pic is
92/// NULL or if Picture returns Complete for str, indicating that str needs no
93/// further input to meet the specified format; otherwise, it returns false.
94//
95bool
97{
98 if (Pic.empty())
99 return true;
100
102 return rslt == prComplete || rslt == prEmpty;
103}
104
105//
106/// Adjusts the 'value' of the text, given a cursor position and an amount. Returns
107/// the actual amount adjusted.
108//
109int
110TPXPictureValidator::Adjust(tstring& /*text*/, int& /*begPos*/, int& /*endPos*/, int /*amount*/)
111{
112 return 0;
113}
114
115//
116//
117//
118inline bool
119TPXPictureValidator::IsComplete(TPicResult rslt)
120{
121 return rslt == prComplete || rslt == prAmbiguous;
122}
123
124//
125//
126//
127inline bool
128TPXPictureValidator::IsIncomplete(TPicResult rslt)
129{
130 return rslt == prIncomplete || rslt == prIncompNoFill;
131}
132
133//
134// Skip a character or a picture group
135//
136void
137TPXPictureValidator::ToGroupEnd(uint termCh, uint& i)
138{
139 int brkLevel = 0;
140 int brcLevel = 0;
141
142 do {
143 if (i == termCh)
144 return;
145 switch (Pic[i]) {
146 case _T('['): brkLevel++; break;
147 case _T(']'): brkLevel--; break;
148 case _T('{'): brcLevel++; break;
149 case _T('}'): brcLevel--; break;
150 case _T(';'): i++; break;
151 case _T('*'):
152 i++;
153 while (_istdigit((tchar)Pic[i]))
154 i++;
155 ToGroupEnd(termCh, i);
156 continue;
157 }
158 i += CharSize((LPCTSTR)Pic.c_str() + i) / sizeof(tchar);
159 } while (brkLevel || brcLevel);
160}
161
162//
163/// Find the next comma separator
164//
165bool
166TPXPictureValidator::SkipToComma(uint termCh, uint& i)
167{
168 for (;;) {
169 ToGroupEnd(termCh, i);
170 if (i == termCh)
171 return false;
172 if (Pic[i] == _T(',')) {
173 i++;
174 return i < termCh;
175 }
176 }
177}
178
179//
180/// Calculate the end of a group (does not modify i)
181//
182uint
183TPXPictureValidator::CalcTerm(uint termCh, uint i)
184{
185 ToGroupEnd(termCh, i);
186 return i;
187}
188
189//
190/// The next group is repeated X times
191//
193TPXPictureValidator::Iteration(LPTSTR input, uint termCh, uint& i, uint& j)
194{
197
198 i++; // Skip '*'
199
200 // Retrieve number
201
202 uint itr = 0;
203 for (; _istdigit((tchar)Pic[i]); i++)
204 itr = itr * 10 + Pic[i] - _T('0');
205
206 if (i >= termCh)
207 return prSyntax;
208
209 newTermCh = CalcTerm(termCh, i);
210
211 //
212 // if itr is 0 allow any number, otherwise enforce the number
213 //
214 uint k = i;
215 if (itr) {
216 for (uint m = 0; m < itr; m++) {
217 i = k;
218 rslt = Process(input, newTermCh, i, j);
219 if (!IsComplete(rslt)) {
220 if (rslt == prEmpty) // Empty means incomplete since all are required
222 return rslt;
223 }
224 }
225 }
226 else {
227 do {
228 i = k;
229 rslt = Process(input, newTermCh, i, j);
230 } while (IsComplete(rslt));
231 if (rslt == prEmpty || rslt == prError) {
232 i++;
234 }
235 }
236 i = newTermCh;
237 return rslt;
238}
239
240//
241/// Process a picture group
242//
244TPXPictureValidator::Group(LPTSTR input, uint termCh, uint& i, uint& j)
245{
246 uint groupTermCh = CalcTerm(termCh, i);
247 i++;
248 TPicResult rslt = Process(input, groupTermCh - 1, i, j);
249 if (!IsIncomplete(rslt))
250 i = groupTermCh;
251 return rslt;
252}
253
254//
255//
256//
258TPXPictureValidator::CheckComplete(uint termCh, uint& i, TPicResult rslt)
259{
260 uint j = i;
261 if (IsIncomplete(rslt)) {
262 // Skip optional pieces
263 for (;;) {
264 if (Pic[j] == _T('['))
265 ToGroupEnd(termCh, j);
266
267 else if (Pic[j] == _T('*')) {
268 if (!isdigit((tchar)Pic[j+1])) {
269 j++;
270 ToGroupEnd(termCh, j);
271 }
272 else
273 break;
274 }
275 else
276 break;
277
278 if (j == termCh)
279 return prAmbiguous; // end of the string, don't know if complete
280 }
281 }
282 return rslt;
283}
284
285//
286// Check for UNICODE !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
287//
288#if !defined(__GNUC__)
289#pragma warn -aus
290#endif
291
293TPXPictureValidator::Scan(LPTSTR input, uint termCh, uint& i, uint& j)
294{
295 tchar ch;
297
298 uint len = static_cast<uint>(::_tcslen(input));
299 while (i != termCh && Pic[i] != _T(',')) {
300 if (j >= len)
301 return CheckComplete(termCh, i, rslt);
302
303 ch = input[j];
304 switch (Pic[i]) {
305 case _T('#'):
306 if (!_istdigit((tchar)ch))
308 else {
309 input[j++] = ch;
310 i++;
311 }
312 break;
313 case _T('?'):
314 if (!_istalpha((tchar)ch))
316 else {
317 input[j++] = ch;
318 i++;
319 }
320 break;
321 case _T('&'):
322 if (!_istalpha((tchar)ch))
324 else {
325 input[j++] = (tchar)_totupper(ch);
326 i++;
327 }
328 break;
329 case _T('!'): {
330#if defined(BI_DBCS_SUPPORT)
331 uint n = CharSize(&input[j]) / sizeof(tchar);
332 if (j + n >= len)
333 j = len;
334 else{
335 if (n == 1)
336 input[j++] = (tchar)_totupper((tchar)ch);
337 else
338 j += n;
339 }
340#else
341 input[j++] = (tchar)_totupper(ch);
342#endif
343 i++;
344 break;
345 }
346 case _T('@'): {
347#if defined(BI_DBCS_SUPPORT)
348 uint n = CharSize(&input[j]) / sizeof(tchar);
349 if (j + n >= len)
350 j = len;
351 else
352 j += n;
353#else
354 input[j++] = ch;
355#endif
356 i++;
357 break;
358 }
359 case _T('*'):
360 rslt = Iteration(input, termCh, i, j);
361 if (!IsComplete(rslt))
362 return rslt;
363 if (rslt == prError)
365 break;
366 case _T('{'):
367 rslt = Group(input, termCh, i, j);
368 if (!IsComplete(rslt))
369 return rslt;
370 break;
371 case _T('['):
372 rslt = Group(input, termCh, i, j);
373 if (IsIncomplete(rslt))
374 return rslt;
375 if (rslt == prError)
377 break;
378 default: {
379#if defined(BI_DBCS_SUPPORT)
380 if (Pic[i] == _T(';'))
381 i++;
382 uint n = CharSize(&input[j]) / sizeof(tchar);
383 uint n2 = CharSize((LPCTSTR)Pic.c_str() + i) / sizeof(tchar);
384 if (j + n >= len)
385 n = len - j;
386 if (n == 1) {
387 if (ch == _T(' ')) {
388#if defined(BI_AUTO_COMPLETION_DBCS_BY_SPACE)
389// But, couldn't expand input buffer TValidator classes.
390//
391 if (n < n2) {
392 memmove(input+n2, input+n, len-n+1);
393 len += n2 - n;
394 n = n2;
395 }
396 while (n-- > 0)
397 input[j++] = Pic[i++];
398#else
399 if (n != n2)
400 return prError;
401 input[j++] = Pic[i++];
402#endif
403 }
404 else {
405 if (n != n2)
406 return prError;
407 if (_totupper((tchar)Pic[i]) != _totupper((tchar)ch))
408 return prError;
409 input[j++] = Pic[i++];
410 }
411 }
412 else {
413 if (n > n2)
414 return prError;
415 for (uint i1 = 0; i1 < n; i1++)
416 if (input[j+i1] != Pic[i+i1])
417 return prError;
418 while (n-- > 0)
419 input[j++] = Pic[i++];
420 }
421#else
422 if (Pic[i] == _T(';'))
423 i++;
424 if (_totupper(Pic[i]) != _totupper(ch))
425 {
426 if (ch == _T(' '))
427 ch = Pic[i];
428 else
429 return prError;
430 }
431 input[j++] = Pic[i];
432 i++;
433#endif
434 }
435 }
436 if (rslt == prAmbiguous)
438 else
440 }
441
443}
444#if !defined(__GNUC__)
445#pragma warn .aus
446#endif
447
448//
449//
450//
452TPXPictureValidator::Process(LPTSTR input, uint termCh, uint& i, uint& j)
453{
456 incompJ = incompI = 0;
457
458 bool incomp = false;
459 uint oldI = i;
460 uint oldJ = j;
461 do {
462 rslt = Scan(input, termCh, i, j);
463
464 //
465 // Only accept completes if they make it farther in the input
466 // stream from the last incomplete
467 //
468 if ((rslt==prComplete || rslt==prAmbiguous) && incomp && j < incompJ) {
470 j = incompJ;
471 }
472
473 if (rslt == prError || rslt == prIncomplete) {
474 if (!incomp && rslt == prIncomplete) {
475 incomp = true;
476 incompI = i;
477 incompJ = j;
478 }
479 i = oldI;
480 j = oldJ;
481 if (!SkipToComma(termCh, i)) {
482 if (incomp) {
483 i = incompI;
484 j = incompJ;
485 return prIncomplete;
486 }
487 return rslt;
488 }
489 oldI = i;
490 }
491 } while (rslt == prError || rslt == prIncomplete);
492
493 return (rslt == prComplete && incomp) ? prAmbiguous : rslt;
494}
495
496//
497//
498//
499bool
500TPXPictureValidator::SyntaxCheck()
501{
502 const auto n = static_cast<int>(Pic.length());
503 if (Pic.empty() ||
504 (Pic.back() == _T(';')) ||
505 (Pic.back() == _T('*') && Pic[n - 2] != _T(';')))
506 {
507 return false;
508 }
509
510 auto brkLevel = 0;
511 auto brcLevel = 0;
512 auto next = [&](int& i) { i += CharSize(&Pic[i]) / sizeof(tchar); };
513 for (auto i = 0; i < n; next(i))
514 {
515 switch (Pic[i])
516 {
517 case _T('['): ++brkLevel; break;
518 case _T(']'): --brkLevel; break;
519 case _T('{'): ++brcLevel; break;
520 case _T('}'): --brcLevel; break;
521 case _T(';'): next(i); break;
522 case _T('*'):
523 next(i);
524 if (!_istdigit(Pic[i]))
525 return false;
526 break;
527 }
528 }
529 return brkLevel == 0 && brcLevel == 0;
530}
531
532//
533/// Checks the validity of the input according to the format specified by the
534/// picture string, possibly adding fill characters to the end of the input.
535//
536/// Formats the string passed in input according to the format specified by the
537/// picture string pointed to by Pic. Picture returns prError if there is an error
538/// in the picture string or if input contains data that cannot fit the specified
539/// picture. Returns prComplete if input can fully satisfy the specified picture.
540/// Returns prIncomplete if input contains data that incompletely fits the specified
541/// picture.
542//
543/// The following characters are used in creating format pictures:
544///
545/// Special
546/// - \b # Accept only a digit
547/// - \b ? Accept only a letter (case_insensitive)
548/// - \b & Accept only a letter, force to uppercase
549/// - \b @ Accept any character
550/// - \b ! Accept any character, force to uppercase
551/// Match
552/// - \b ; Take next character literally
553/// - \b * Repetition count
554/// - \b [] Option
555/// - \b {} Grouping operators
556/// - \b , Set of alternatives
557/// - All others Taken literally
558//
561{
562 // Check if any input data.
563 //
564 if (!input || !*input)
565 return prEmpty;
566
567 // Indexes for Pic[] and input[].
568 //
569 uint iPic = 0;
570 uint iInput = 0;
571
572 // Process the given input to check for an error.
573 //
574 TPicResult rslt = Process(input, static_cast<uint>(Pic.length()), iPic, iInput);
575
576 if ((rslt != prError) && (rslt != prSyntax) && (iInput < ::_tcslen(input)))
577 rslt = prError;
578
579 // If the result is incomplete and autofill is requested, then copy literal
580 // characters from the picture over to the input.
581 //
582 if ((rslt == prIncomplete) && autoFill) {
583 bool reprocess = false;
584 while (iPic < Pic.length() && !_tcschr(_T("#?&!@*{}[],"), Pic[iPic]))
585 {
586 if (Pic[iPic] == _T(';'))
587 iPic++;
588#if defined(BI_DBCS_SUPPORT)
589 uint k = static_cast<uint>(::_tcslen(input));
590 uint n = CharSize((LPCTSTR)Pic.c_str() + iPic) / sizeof(tchar);
591 memmove(input + k, Pic.c_str() + iPic, n);
592 input[k + n] = _T('\0');
593 iPic += n;
594 iInput += n;
595#else
596 input[iInput++] = Pic[iPic++];
597#endif
598 reprocess = true;
599 }
600 if (reprocess)
601 {
602 input[iInput] = _T('\0'); // Terminate the copy, since we are probably appending
603 iInput = iPic = 0;
604 rslt = Process(input, static_cast<uint>(Pic.length()), iPic, iInput);
605 }
606 }
607
608 // We perform an additional check here because SyntaxCheck may not catch them
609 // all with it using different logic.
610 //
611 if (rslt == prSyntax)
613
615
616}
617
618
620
621#if OWL_PERSISTENT_STREAMS
622
623//
624//
625//
626void*
627TPXPictureValidator::Streamer::Read(ipstream& is, uint32 /*version*/) const
628{
629 ReadBaseObject((TValidator*)GetObject(), is);
630 is >> GetObject()->Pic;
631 return GetObject();
632}
633
634//
635//
636//
637void
638TPXPictureValidator::Streamer::Write(opstream& os) const
639{
640 WriteBaseObject((TValidator*)GetObject(), os);
641 os << GetObject()->Pic;
642}
643
644#endif
645
646} // OWL namespace
Definition of class TAppDictionary.
Definition of class TApplication.
#define PRECONDITION(condition)
Definition checks.h:227
TPXPictureValidator objects compare user input with a picture of a data format to determine the valid...
Definition validate.h:145
int Adjust(tstring &text, int &begPos, int &endPos, int amount)
Adjusts the 'value' of the text, given a cursor position and an amount.
Definition pictval.cpp:110
virtual TPicResult Picture(TCHAR *input, bool autoFill=false)
Checks the validity of the input according to the format specified by the picture string,...
Definition pictval.cpp:560
TPXPictureValidator(LPCTSTR pic, bool autoFill=false)
Constructs a picture validator object by first calling the constructor inherited from TValidator and ...
Definition pictval.cpp:29
bool IsValid(LPCTSTR str)
IsValid overrides TValidator's virtual function and compares the string passed in str with the format...
Definition pictval.cpp:96
void Error(TWindow *owner)
Overrides TValidator's virtual function and displays a message box that indicates an error in the pic...
Definition pictval.cpp:65
bool IsValidInput(TCHAR *str, bool suppressFill)
IsValidInput overrides TValidator's virtual function and checks the string passed in str against the ...
Definition pictval.cpp:82
A streamable class, TValidator defines an abstract data validation object.
Definition validate.h:71
uint16 Options
A bitmap member used to control options for various descendants of TValidator.
Definition validate.h:94
TWindow, derived from TEventHandler and TStreamableBase, provides window-specific behavior and encaps...
Definition window.h:414
static void Raise()
Creates an instance of TXValidator and throws it.
Definition validate.cpp:165
ipstream, a specialized input stream derivative of pstream, is the base class for reading (extracting...
Definition objstrm.h:391
#define _istdigit
Definition cygwin.h:70
#define _istalpha
Definition cygwin.h:71
#define _totupper
Definition cygwin.h:73
#define _tcslen
Definition cygwin.h:74
#define _T(x)
Definition cygwin.h:51
#define _tcschr
Definition cygwin.h:85
Definition of class TFrameWindow.
void ReadBaseObject(Base *base, ipstream &in)
Definition objstrm.h:1159
#define IMPLEMENT_STREAMABLE1(cls, base1)
Definition objstrm.h:1725
void WriteBaseObject(Base *base, opstream &out)
Definition objstrm.h:1150
TPicResult
Validation result type.
Definition validate.h:128
@ voOnAppend
Option to only validate input on appending.
Definition validate.h:43
@ voFill
Option to fill in chars on IsValidInput checks.
Definition validate.h:35
@ prEmpty
Definition validate.h:131
@ prAmbiguous
Definition validate.h:134
@ prError
Definition validate.h:132
@ prComplete
Definition validate.h:129
@ prIncomplete
Definition validate.h:130
@ prSyntax
Definition validate.h:133
@ prIncompNoFill
Definition validate.h:135
UINT CharSize(const TCHAR *s)
Return the number of bytes of the first character of the passed string.
Definition memory.h:56
Object Windows Library (OWLNext Core)
Definition animctrl.h:22
unsigned long uint32
Definition number.h:34
char tchar
Definition defs.h:77
OWL_DIAGINFO
Definition animctrl.cpp:14
std::string tstring
Definition defs.h:79
unsigned int uint
Definition number.h:25
#define CONST_CAST(targetType, object)
Definition defs.h:273