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 defined(BI_PDOXWINJ_SUPPORT)
381 // Paradox for Windows/J database program has two special picture to
382 // support Japanese characters in CodePage 932
383 //
384 // '' 0x81+0x93 - (2 byte '%' symbol)
385 // 1 byte KATAKANA and KATAKANA symbols (0xA1 - 0xDF)
386 // '' 0x81+0x97 - (2 byte '@' symbol)
387 // any 2 byte characters except 2 byte space (0x81+0x40)
388 //
389 // This is hard coded, because we don't know how to get current
390 // code page in Windows 3.1
391 //
392 uint n = CharSize(&input[j]) / sizeof(tchar);
393 uint n2 = CharSize(((const char *))Pic.c_str() + i) / sizeof(tchar);
394 if (n2 == 2) {
395 utchar uc1, uc2;
396 uc1 = (utchar)Pic[i];
397 uc2 = (utchar)Pic[i+1];
398 if (uc1 == 0x81 && uc2 == 0x93) {
399 if ((utchar)ch >= 0xA1 && (utchar)ch <= 0xDF){
400 i += n2;
401 j += n;
402 break;
403 }
404 else
405 return prError;
406 }
407 else if (uc1 == 0x81 && uc2 == 0x97){
408 if (n == 2 && j + n < len &&
409 ((utchar)ch != 0x81 || (utchar)input[j+1] != 0x40)) {
410 i += n2;
411 j += n;
412 break;
413 } else
414 return prError;
415 }
416 }
417 if (n2 == 1 && Pic[i] == ';'){
418 i++;
419 n2 = CharSize((const char *)Pic.c_str() + i) / sizeof(tchar);
420 }
421#else
422 if (Pic[i] == _T(';'))
423 i++;
424 uint n = CharSize(&input[j]) / sizeof(tchar);
425 uint n2 = CharSize((LPCTSTR)Pic.c_str() + i) / sizeof(tchar);
426#endif
427 if (j + n >= len)
428 n = len - j;
429 if (n == 1) {
430 if (ch == _T(' ')) {
431#if defined(BI_AUTO_COMPLETION_DBCS_BY_SPACE)
432// But, couldn't expand input buffer TValidator classes.
433//
434 if (n < n2) {
435 memmove(input+n2, input+n, len-n+1);
436 len += n2 - n;
437 n = n2;
438 }
439 while (n-- > 0)
440 input[j++] = Pic[i++];
441#else
442 if (n != n2)
443 return prError;
444 input[j++] = Pic[i++];
445#endif
446 }
447 else {
448 if (n != n2)
449 return prError;
450 if (_totupper((tchar)Pic[i]) != _totupper((tchar)ch))
451 return prError;
452 input[j++] = Pic[i++];
453 }
454 }
455 else {
456 if (n > n2)
457 return prError;
458 for (uint i1 = 0; i1 < n; i1++)
459 if (input[j+i1] != Pic[i+i1])
460 return prError;
461 while (n-- > 0)
462 input[j++] = Pic[i++];
463 }
464#else
465 if (Pic[i] == _T(';'))
466 i++;
467 if (_totupper(Pic[i]) != _totupper(ch))
468 {
469 if (ch == _T(' '))
470 ch = Pic[i];
471 else
472 return prError;
473 }
474 input[j++] = Pic[i];
475 i++;
476#endif
477 }
478 }
479 if (rslt == prAmbiguous)
481 else
483 }
484
486}
487#if !defined(__GNUC__)
488#pragma warn .aus
489#endif
490
491//
492//
493//
495TPXPictureValidator::Process(LPTSTR input, uint termCh, uint& i, uint& j)
496{
499 incompJ = incompI = 0;
500
501 bool incomp = false;
502 uint oldI = i;
503 uint oldJ = j;
504 do {
505 rslt = Scan(input, termCh, i, j);
506
507 //
508 // Only accept completes if they make it farther in the input
509 // stream from the last incomplete
510 //
511 if ((rslt==prComplete || rslt==prAmbiguous) && incomp && j < incompJ) {
513 j = incompJ;
514 }
515
516 if (rslt == prError || rslt == prIncomplete) {
517 if (!incomp && rslt == prIncomplete) {
518 incomp = true;
519 incompI = i;
520 incompJ = j;
521 }
522 i = oldI;
523 j = oldJ;
524 if (!SkipToComma(termCh, i)) {
525 if (incomp) {
526 i = incompI;
527 j = incompJ;
528 return prIncomplete;
529 }
530 return rslt;
531 }
532 oldI = i;
533 }
534 } while (rslt == prError || rslt == prIncomplete);
535
536 return (rslt == prComplete && incomp) ? prAmbiguous : rslt;
537}
538
539//
540//
541//
542bool
543TPXPictureValidator::SyntaxCheck()
544{
545 const auto n = static_cast<int>(Pic.length());
546 if (Pic.empty() ||
547 (Pic.back() == _T(';')) ||
548 (Pic.back() == _T('*') && Pic[n - 2] != _T(';')))
549 {
550 return false;
551 }
552
553 auto brkLevel = 0;
554 auto brcLevel = 0;
555 auto next = [&](int& i) { i += CharSize(&Pic[i]) / sizeof(tchar); };
556 for (auto i = 0; i < n; next(i))
557 {
558 switch (Pic[i])
559 {
560 case _T('['): ++brkLevel; break;
561 case _T(']'): --brkLevel; break;
562 case _T('{'): ++brcLevel; break;
563 case _T('}'): --brcLevel; break;
564 case _T(';'): next(i); break;
565 case _T('*'):
566 next(i);
567 if (!_istdigit(Pic[i]))
568 return false;
569 break;
570 }
571 }
572 return brkLevel == 0 && brcLevel == 0;
573}
574
575
576#if defined(BI_DBCS_SUPPORT)
577#if defined(BI_PDOXWINJ_SUPPORT)
578namespace {
580 {
581 uint n2 = CharSize(s2) / sizeof(tchar);
582 do {
583 uint n1 = CharSize(s1) / sizeof(tchar);
584 if (n1 == n2 && memcmp(s1, s2, n1) == 0)
585 return (char *)s1;
586 for ( ; n1-- > 0; s1++)
587 if( !*s1 )
588 break;
589 } while (*s1) ;
590 return (char *)NULL;
591 }
592}
593#endif
594#endif
595
596//
597/// Checks the validity of the input according to the format specified by the
598/// picture string, possibly adding fill characters to the end of the input.
599//
600/// Formats the string passed in input according to the format specified by the
601/// picture string pointed to by Pic. Picture returns prError if there is an error
602/// in the picture string or if input contains data that cannot fit the specified
603/// picture. Returns prComplete if input can fully satisfy the specified picture.
604/// Returns prIncomplete if input contains data that incompletely fits the specified
605/// picture.
606//
607/// The following characters are used in creating format pictures:
608///
609/// Special
610/// - \b # Accept only a digit
611/// - \b ? Accept only a letter (case_insensitive)
612/// - \b & Accept only a letter, force to uppercase
613/// - \b @ Accept any character
614/// - \b ! Accept any character, force to uppercase
615/// Match
616/// - \b ; Take next character literally
617/// - \b * Repetition count
618/// - \b [] Option
619/// - \b {} Grouping operators
620/// - \b , Set of alternatives
621/// - All others Taken literally
622//
625{
626 // Check if any input data.
627 //
628 if (!input || !*input)
629 return prEmpty;
630
631 // Indexes for Pic[] and input[].
632 //
633 uint iPic = 0;
634 uint iInput = 0;
635
636 // Process the given input to check for an error.
637 //
638 TPicResult rslt = Process(input, static_cast<uint>(Pic.length()), iPic, iInput);
639
640 if ((rslt != prError) && (rslt != prSyntax) && (iInput < ::_tcslen(input)))
641 rslt = prError;
642
643 // If the result is incomplete and autofill is requested, then copy literal
644 // characters from the picture over to the input.
645 //
646 if ((rslt == prIncomplete) && autoFill) {
647 bool reprocess = false;
648
649#if defined(BI_PDOXWINJ_SUPPORT)
650 // ""
651 while (iPic < Pic.length() && !lstrchrp("#?&!@*{}[],\x81\x93\x81\x97", (LPCSTR)Pic.c_str() + iPic))
652#else
653 while (iPic < Pic.length() && !_tcschr(_T("#?&!@*{}[],"), Pic[iPic]))
654#endif
655 {
656 if (Pic[iPic] == _T(';'))
657 iPic++;
658#if defined(BI_DBCS_SUPPORT)
659 uint k = static_cast<uint>(::_tcslen(input));
660 uint n = CharSize((LPCTSTR)Pic.c_str() + iPic) / sizeof(tchar);
661 memmove(input + k, Pic.c_str() + iPic, n);
662 input[k + n] = _T('\0');
663 iPic += n;
664 iInput += n;
665#else
666 input[iInput++] = Pic[iPic++];
667#endif
668 reprocess = true;
669 }
670 if (reprocess)
671 {
672 input[iInput] = _T('\0'); // Terminate the copy, since we are probably appending
673 iInput = iPic = 0;
674 rslt = Process(input, static_cast<uint>(Pic.length()), iPic, iInput);
675 }
676 }
677
678 // We perform an additional check here because SyntaxCheck may not catch them
679 // all with it using different logic.
680 //
681 if (rslt == prSyntax)
683
685
686}
687
688
690
691#if OWL_PERSISTENT_STREAMS
692
693//
694//
695//
696void*
697TPXPictureValidator::Streamer::Read(ipstream& is, uint32 /*version*/) const
698{
699 ReadBaseObject((TValidator*)GetObject(), is);
700 is >> GetObject()->Pic;
701 return GetObject();
702}
703
704//
705//
706//
707void
708TPXPictureValidator::Streamer::Write(opstream& os) const
709{
710 WriteBaseObject((TValidator*)GetObject(), os);
711 os << GetObject()->Pic;
712}
713
714#endif
715
716} // 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:624
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
unsigned char utchar
Definition defs.h:78
#define CONST_CAST(targetType, object)
Definition defs.h:273