Drawings SDK Developer Guide > Working with .dwg Files > Working with Databases > Working with Database Containers > Examples of Using the Record-Table and Dictionary Interfaces > Example of Entering Characters for String Objects
Example of Entering Characters for String Objects

This example demonstrates entering characters in a string implemented by the OdString class. An instance of this class can contain arbitrary letters, however some objects require additional conditions for an entered value. For example, the string cannot be empty, the string must contain only alphabetic letters, or the string is the object name or dictionary key which can contain letters (a–z and A–Z), digits (0–9), underscores (_), some special characters ($,!,+,-, etc.), blank spaces and cannot contain inadmissible letters (< > / \ " ` : ; , ? * | =). Some objects can not contain blank spaces before and after the name. The example considers these situations for console input.

To check an entered string, the example declares the enumCheckText enumerator that defines four values: kArbitrary – do not check the entered value (any string), kNonEmpty – the entered value must not be empty, kCorrectName – the entered value must not be empty and must not contain inadmissible letters (usually specifies an object name), and kAlphabetic – the entered value must contain only alphabetic letters. Each number is a combination of flags: 0x01 – clear the spaces before and after the value and check whether the value is empty, 0x02 – check inadmissible letters, 0x04 – check alphabetic letters. This enumerator has the following implementation:


enum enumCheckText { 
  kArbitrary = 0,
  kNonEmpty = 1,
  kCorrectName = 3,
  kAlphabetic = 5
};

The EntryTextAs() function requires the check flags as an argument of the enumCheckName enumerator and returns the value entered by the user as a non-empty OdString instance, or it returns an empty string if the value does not satisfy the check flags or the user cancels entry. The function declares an array of wide-characters and requests entry by a user using the standard stream operations. Then the function checks the flags and calls the TrimAll() function to delete empty symbols before and after the value, calls the IsContainAnyLetter() function to check whether the value specified by first argument contains a letter specified by the second argument, and calls the IsConsistAlphabeticLetters() function to check whether the value contains only alphabetic letters. If the entered value is incorrect, the function displays a corresponding error message and returns an empty string. If the entered value is empty, that is, the user cancels entry using '\0' as a value, the function returns an empty string.

The EntryTextAs() function has the following implementation:


OdString EntryTextAs(enum enumCheckText isTextAs)
{
  wchar_t buffer[64];

  wcin.sync();
  wcin.getline(buffer, 64, 10);

  if(buffer[0] == L'\0')
  {
    wcout << L"Entry is canceled\n";
    return OdString::kEmpty;
  }

  if(isTextAs & 0x01)
    if(TrimAll(buffer) == 0)
    {
      wcout << L"Error: string is empty\n";
      return OdString::kEmpty;
    }

  if(isTextAs & 0x02)
    if(IsContainAnyLetters(buffer, L"\t<>/\\\":;?,|=`") != (-1))
    {
      wcout << L"Error: the name contains inadmissible letters: <>/\\\":;?,|=`\n";
      return OdString::kEmpty;
    }

  if(isTextAs & 0x04)
    if(!IsConsistAlphabeticLetters(buffer))
    {
      wcout << L"Error: string must contain alphabetic letters except spaces\n";
      return OdString::kEmpty;
    }

  return OdString(buffer);
}

The TrimAll() function requires the pointer to the string to be processed for wide-character type as an argument and returns the number of symbols after deleting empty symbols (space, tab, line-feed) before and after non-empty values inside the string. The function declares two variables for left and right indices and initializes them to zero. The function uses these indices for moving inside the string to delete empty symbols and to move a non-empty value. First, the function organizes the loop in which it moves the right index to the first non-empty symbol inside the string. If the string contains empty symbols before the value, the right index becomes non-zero. Then the function copies all symbols, beginning from the position of the right index to the position of the left index, and moves left and right indices together to the end of the string, replacing empty symbols before non-empty values. Therefore, the value moves to the start of the string. Next, the function moves the left index to the end of the string and organizes the second loop in which it moves the left index from the end of the string to the first non-empty symbol at the end. When the function finds a non-empty symbol at the end, it keeps the end of line symbol in the next position after the left index. The left index keeps the number of symbols in the string after deleting empty symbols. If the string is empty or contains only empty letters, the function returns zero.

The TrimAll() function has the following implementation:


static bool isEmptyLetter(wchar_t ch)
{
  return (ch == L' ' || ch == L'\t' || ch == L'\n');
}

int TrimAll(wchar_t* buffer)
{
  register wchar_t ch;
  register int left, right;

  if((ch = buffer[0]) == L'\0') return 0;

  left = 0;  
  right = 0; 
  
  while(isEmptyLetter(ch))
    ch = buffer[++right];

  if(right > 0)
  {
    buffer[0] = ch;
    while(ch != L'\0')
    {
      ch = buffer[++right];
      buffer[++left] = ch;
    }
  }
  do {  ++left;
     }
     while(buffer[left] != L'\0');

  do {  ch = buffer[--left];
     }
     while(left > 0 && isEmptyLetter(ch));
  
  buffer[++left] = L'\0';
  return left;
}

The IsContainsAnyLetters() function requires two arguments — the pointer to the string to be checked for wide-character type and the pointer to the string containing the wide-character letters used for searching the first string — and returns the index of one of the letters from the second string found in the first string, or returns (–1) if letters of the second string are not found in the first string. The function organizes two nested loops and compares the letters of both strings. The first loop iterates through the letters of the first string until its end is not found. The second loop iterates through the letters of the second string until its end is not found. If one of the letters of the second string coincides with a letter from the first string, the function breaks these loops.

The IsContainsAnyLetters() function has the following implementation:


int IsContainsAnyLetters(const wchar_t *sLine, const wchar_t *sLetter)
{
  register int iSymbol, iLetter;
  for(iSymbol=0 ; sLine[iSymbol] != L'\0' ; iSymbol++)
    for(iLetter=0 ; sLetter[iLetter] != L'\0' ; iLetter++)
      if(sLine[iSymbol] == sLetter[iLetter])
        return iSymbol;
  return (-1);
}

The IsConsistAlphabeticLetters() function requires the pointer to the string to be checked for wide-character type as an argument, and it returns True if the string contains only alphabetic letters or False if the string contains any other letters, including spaces. The function organizes the loop in which it checks each letter in the range (a–z and A–Z). The loop iterates through the letters of the string until its end is not found. If one of the letters is not an alphabetic letter, the function breaks this loop.

The IsConsistAlphabeticLetters() function has the following implementation:


bool IsConsistAlphabeticLetters(const wchar_t* sLine)
{
  register wchar_t ch;
  register int iSymbol;
  for(iSymbol=0 ; (ch = sLine[iSymbol]) != L'\0' ; iSymbol++)
    if(!(ch >= L'a' && ch <= L'z' || ch >= L'A' && ch <= L'Z'))
      return false;
  return true;
}

Note: The EntryTextAs() function is used in the documented examples that require entry of a string.

See Also

Naming objects

Copyright © 2002 – 2020. Open Design Alliance. All rights reserved.