Exemplo n.º 1
0
void DataValue::parse(const ustring &text, DataType type, void *value) {
	switch(type) {
		case data_int:
		case data_combo:
		case data_flags:
		case data_comboEx:
			*(int *)value = atoi(text.c_str());
			break;
		case data_str:
			if(text[0] == '"')
				((ustring*)value)->assign(text, 1, text.length() - 2);
			else if(text[0] == '#')
				parseStrList(text, value);
			else
				*(ustring*)value = text;
			break;
		case data_stock:
		case data_element:
			if(text[0] == '"')
				((ustring*)value)->assign(text, 1, text.length() - 2);
			else
				*(ustring*)value = text;
			break;
		case data_real:
			*(double *)value = atof(text.c_str());
			break;
		case data_data: {
			int i;
			static const int dtypes[] = { data_int, data_str, data_real };

			for(int t = 0; t < 3; t++)
				if(strncmp(text.c_str(), dataNames[dtypes[t]], i = strlen(dataNames[dtypes[t]])) == 0) {
					ustring s = ustring(text, i+1, text.length() - i - 2);
					switch(t) {
						case 0: *(TData*)value = atoi(s.c_str()); break;
						case 1: *(TData*)value = s; break;
						case 2: *(TData*)value = atof(s.c_str()); break;
					}
				}
			break;
		}
		case data_list:
			parseStrList(text, value);
			break;
		case data_pixbuf:
			parsePixbuf(text, value);
			break;
		case data_array:
			parseArray(text, value);
			break;
		case data_color:
			((TypeColor*)value)->set(text);
			break;
		case data_font:
			parseFont(text, value);
			break;
		default:
			;
	}
}
Exemplo n.º 2
0
void CDate::Import(ustring a)
{
	do
	{
		int dem = 0;
		int dk = 0;
		int j = 0;
		char** temp = new char*[3]; //Tạo con trỏ hai chiều kiểu char
		for(int i = 0; i < 3; i++) //Vòng lặp khởi tạo vùng nhớ cho biến
			temp[i] = new char[a.length()];

		for(int i = 0; i < a.length(); i++) //Vòng lặp chạy từ cuối chuỗi
		{
			if(a[i] >= '0' && a[i] <= '9') //Nếu gặp phần tử là số thì thêm vào biến tạm thứ dem.
			{
				temp[dem][j] = a[i];
				j++;
			}
			else //Nếu gặp thì tăng dem lên 1 để chuyển biến tạm và j = 0 để trở về vị trí ban đầu của biến tạm mới
			{
				dem++;
				j = 0;
			}
		}

		this->m_day = atoi(temp[0]); //Chuyển giá trị trong chuỗi thành kiểu nguyên và gán cho thuộc tính của con trỏ this
		this->m_month = atoi(temp[1]); //Tương tự
		this->m_year = atoi(temp[2]); //Tương tự

	} while(this->m_year < 0 || this->m_month < 0 || this->m_month > 12 || (CheckYear(this->m_year) == 0 && this->m_day > SizeMonth[this->m_month - 1] || this->m_day < 0) || (CheckYear(this->m_year) == 1 && this->m_day > _SizeMonth[this->m_month - 1] || this->m_day < 0)); //Điều kiện dùng của vòng lặp nhập thời gian
}
Exemplo n.º 3
0
void WindowsOutpost::send_line(const ustring & command)
// Sends "command" to the windows outpost.
{
  int result = 0;
  if (connected) {
    // Discard any previous reply.
    char buf[1024];
#ifdef WIN32
    if (recv(sock, buf, sizeof(buf), 0)) ;
    if (send(sock, command.c_str(), command.length(), 0)) ;
    result = send(sock, "\n", 1, 0);
#else
    if (read(sock, buf, sizeof(buf))) ;
    if (write(sock, command.c_str(), command.length())) ;
    result = write(sock, "\n", 1);
#endif
    // Give some time to allow the reply to come back.
    g_usleep(1000000);
  }
  if (result < 0) {
    connected = false;
#ifndef WIN32
    perror(NULL);
#endif
    log(_("Error sending data"));
    clear();
  }
}
Exemplo n.º 4
0
void Highlight::searchwords_find_fast(GtkTextBuffer * textbuffer, GtkTextIter * beginbound, GtkTextIter * endbound, const ustring & searchword, bool casesensitive, vector < GtkTextIter > &wordstart, vector < GtkTextIter > &wordend)
// Searches for words to highlight. For simple highligthing. 
// Is much faster than the slow routine, see there fore more information.
{
  // Variable.
  GtkTextIter begin;
  GtkTextIter end;
  // Extract the line.
  ustring line = gtk_text_buffer_get_slice(textbuffer, beginbound, endbound, false);
  // Deal with case sensitivity.
  ustring case_considerate_search_word(searchword);
  if (!casesensitive)
    case_considerate_search_word = case_considerate_search_word.casefold();
  // Go through the line looking for matches.
  for (unsigned int i = 0; i < line.length(); i++) {
    if (interrupt_thread)
      continue;
    ustring compareline(line.substr(i, searchword.length()));
    // Deal with case sensitivity.
    if (!casesensitive)
      compareline = compareline.casefold();
    // Now compare.
    if (case_considerate_search_word == compareline) {
      // Get the iterators in the textbuffer that belong to this possible match.
      begin = *beginbound;
      gtk_text_iter_forward_chars(&begin, i);
      end = begin;
      gtk_text_iter_forward_chars(&end, searchword.length());
      // Add the boundaries of the word to highlight.
      wordstart.push_back(begin);
      wordend.push_back(end);
    }
  }
}
Exemplo n.º 5
0
void TextSupervisor::Draw(const ustring &text, const TextStyle &style)
{
    if(text.empty()) {
        IF_PRINT_WARNING(VIDEO_DEBUG) << "empty string was passed to function" << std::endl;
        return;
    }

    if(IsFontValid(style.font) == false) {
        IF_PRINT_WARNING(VIDEO_DEBUG) << "failed because font was invalid: " << style.font << std::endl;
        return;
    }

    FontProperties *fp = _font_map[style.font];
    VideoManager->PushState();

    // Break the string into lines and render the shadow and text for each line
    uint16 buffer[2048];
    const uint16 NEWLINE = '\n';
    size_t last_line = 0;
    do {
        // Find the next new line character in the string and save the line
        size_t next_line;
        for(next_line = last_line; next_line < text.length(); next_line++) {
            if(text[next_line] == NEWLINE)
                break;

            buffer[next_line - last_line] = text[next_line];
        }
        buffer[next_line - last_line] = 0;
        last_line = next_line + 1;

        // If this line is empty, skip on to the next one
        if(buffer[0] == 0) {
            VideoManager->MoveRelative(0, -fp->line_skip * VideoManager->_current_context.coordinate_system.GetVerticalDirection());
            continue;
        }

        // Save the draw cursor position before drawing this text
        VideoManager->PushMatrix();

        // If text shadows are enabled, draw the shadow first
        if(style.shadow_style != VIDEO_TEXT_SHADOW_NONE) {
            VideoManager->PushMatrix();
            const float dx = VideoManager->_current_context.coordinate_system.GetHorizontalDirection() * style.shadow_offset_x;
            const float dy = VideoManager->_current_context.coordinate_system.GetVerticalDirection() * style.shadow_offset_y;
            VideoManager->MoveRelative(dx, dy);
            _DrawTextHelper(buffer, fp, _GetTextShadowColor(style));
            VideoManager->PopMatrix();
        }

        // Now draw the text itself, restore the position of the draw cursor, and move the draw cursor one line down
        _DrawTextHelper(buffer, fp, style.color);
        VideoManager->PopMatrix();
        VideoManager->MoveRelative(0, -fp->line_skip * VideoManager->_current_context.coordinate_system.GetVerticalDirection());

    } while(last_line < text.length());

    VideoManager->PopState();
} // void TextSupervisor::Draw(const ustring& text)
Exemplo n.º 6
0
bool replace_text(ustring & line, const ustring & look_for, const ustring & replace_with)
// Replaces some text. Returns true if any replacement was done.
{
  bool replacements_done = false;
  size_t offposition = line.find (look_for);
  while (offposition != string::npos) {
    line.replace (offposition, look_for.length (), replace_with);
    offposition = line.find (look_for, offposition + replace_with.length ());
    replacements_done = true;
  }
  return replacements_done;
}
Exemplo n.º 7
0
bool PubAddr::loadKeys(ustring Skey, ustring Ekey, int nonce, int extra)
{
	std::unique_lock<std::shared_timed_mutex> mlock(this->mutex_);
	this->extra_bytes = extra;
	this->nonce_trials = nonce;

	this->pubEncryptionKey.clear();
	this->pubSigningKey.clear();

	int length = Ekey.length();
	if (length == 64)
	{

		this->pubEncryptionKey += 0x04;
		this->pubEncryptionKey += Ekey;
	}
	else if (length == 65)
	{
		if (Ekey.c_str()[0] != 0x04)
		{
			mlock.unlock();
			return false;
		}
		this->pubEncryptionKey += Ekey;
	}

	length = Skey.length();
	if (length == 64)
	{


		this->pubSigningKey += 0x04;
		this->pubSigningKey += Skey;


	}
	else if (length == 65)
	{
		if (Skey.c_str()[0] != 0x04)
		{
			mlock.unlock();
			return false;
		}
		this->pubSigningKey += Skey;
	}

	this->empty = false;
	mlock.unlock();
	return true;
}
Exemplo n.º 8
0
bool replace_text_between(ustring & line, const ustring & start, const ustring & end, const ustring & replacement)
// Replaces text that starts with "start" and ends with "end" with "replacement".
// Returns true if replacement was done.
{
  bool replacements_done = false;
  size_t beginpos = line.find(start);
  size_t endpos = line.find(end);
  while ((beginpos != string::npos) && (endpos != string::npos) && (endpos > beginpos)) {
    line.replace(beginpos, endpos - beginpos + end.length(), replacement);
    beginpos = line.find(start, beginpos + replacement.length());
    endpos = line.find(end, beginpos + replacement.length());
    replacements_done = true;
  }
  return replacements_done;
}
Exemplo n.º 9
0
  int strtol(long &value, ustring str, long &value2, ustring str2, int base)
  {
    const char *nptr = str.c_str();
    const char *nptr2 = str.c_str();
    char *eptr, *eptr2;
    value = ::strtol(nptr, &eptr, base);
    value2 = ::strtol(nptr2, &eptr2, base);

    if ( (nptr==eptr) || (nptr2==eptr2) )
      return -1;
    else if ( (eptr<(char*)nptr+str.length()) && (eptr2<(char*)nptr2+str2.length()) )
      return 0;
    else
      return 1;
  }
Exemplo n.º 10
0
    ustringArrayT analyseWord (ustring str) {
        typedef bool (*_TrivialPointerToFunctions_) (ustring);

        ustringArrayT res(3);
        _TrivialPointerToFunctions_ testFuncs[3] =
            { isConsonant, isVowel, isConsonant };

        // First part: Consonant 1
        // Second part: Vowel
        // Third part: Consonant 2

        for (int part = 0; part < 3; part++) {
            res[part] = "";
            // This is safe due to short-circuit logic
            while (str.length () > 0 && testFuncs[part] (_(str[0]))) {
                res[part] += _(str[0]);
                str.replace (0, 1, "");
            }
        }

        // Special case: "qu" and "gi" are considered consonants
        if (analyseWordCheckSpecialConsonants (res, "qu") ||
            analyseWordCheckSpecialConsonants (res, "gi")) {
            res[0] += _(res[1][0]);
            res[1] = res[1].replace (0, 1, "");
        }

        return res;
    }
Exemplo n.º 11
0
float CFont::GetStringWidth( const ustring& text, bool offsetFirstCharacter /*= false*/ )
{
    float totalW = 0;

    uchar lastChar = 0;
    for ( int i = 0; i < text.length(); ++i )
    {
        uchar c = text[i];
        auto descIt = m_chars.find(c);

        if ( descIt == m_chars.end() )
        {
            descIt = m_chars.find( -1 );
        }
        auto & desc = descIt->second;

        if (i != 0 || offsetFirstCharacter)
        {
            totalW += desc.offset.x;
        }
        totalW += desc.xAdvance;

        auto kernIt = m_kernings.find( std::make_pair( lastChar, c ) );
        if ( kernIt != m_kernings.end() )
        {
            totalW += kernIt->second;
        }

        lastChar = c;
    }


    return totalW;
}
Exemplo n.º 12
0
ustring string_reverse(const ustring & s)
{
  ustring returnvalue;
  for (int i = s.length() - 1; i >= 0; i--)
    returnvalue.append(s.substr(i, 1));
  return returnvalue;
}
Exemplo n.º 13
0
// Heavy lifting of OSL regex operations.
OSL_SHADEOP int
osl_regex_impl2 (OSL::ShadingContext *ctx, ustring subject_,
                 int *results, int nresults, ustring pattern,
                 int fullmatch)
{
    const std::string &subject (subject_.string());
    boost::match_results<std::string::const_iterator> mresults;
    const boost::regex &regex (ctx->find_regex (pattern));
    if (nresults > 0) {
        std::string::const_iterator start = subject.begin();
        int res = fullmatch ? boost::regex_match (subject, mresults, regex)
                            : boost::regex_search (subject, mresults, regex);
        int *m = (int *)results;
        for (int r = 0;  r < nresults;  ++r) {
            if (r/2 < (int)mresults.size()) {
                if ((r & 1) == 0)
                    m[r] = mresults[r/2].first - start;
                else
                    m[r] = mresults[r/2].second - start;
            } else {
                m[r] = pattern.length();
            }
        }
        return res;
    } else {
        return fullmatch ? boost::regex_match (subject, regex)
                         : boost::regex_search (subject, regex);
    }
}
Exemplo n.º 14
0
int
Dictionary::get_document_index (ustring dictionaryname)
{
    DocMap::iterator dm = m_document_map.find(dictionaryname);
    int dindex;
    if (dm == m_document_map.end()) {
        dindex = m_documents.size();
        m_document_map[dictionaryname] = dindex;
        pugi::xml_document *doc = new pugi::xml_document;
        m_documents.push_back (doc);
        pugi::xml_parse_result parse_result;
        if (boost::ends_with (dictionaryname.string(), ".xml")) {
            // xml file -- read it
            parse_result = doc->load_file (dictionaryname.c_str());
        } else {
            // load xml directly from the string
            parse_result = doc->load_buffer (dictionaryname.c_str(),
                                             dictionaryname.length());
        }
        if (! parse_result) {
            m_context->error ("XML parsed with errors: %s, at offset %d",
                              parse_result.description(),
                              parse_result.offset);
            m_document_map[dictionaryname] = -1;
            return -1;
        }
    } else {
        dindex = dm->second;
    }

    DASSERT (dindex < (int)m_documents.size());
    return dindex;
}
Exemplo n.º 15
0
ustring lowerCase(const ustring & s)
{
// Make a lowercase copy of s
  string lower(s);
  for (size_t i = 0; i < s.length(); ++i)
    lower[i] = tolower(lower[i]);
  return lower;
}
Exemplo n.º 16
0
ustring upperCase(const ustring & s)
{
// Make an uppercase copy of s
  string upper(s);
  for (size_t i = 0; i < s.length(); ++i)
    upper[i] = toupper(upper[i]);
  return upper;
}
Exemplo n.º 17
0
void CGlobalRecords::wide2str16(const ustring& str1, u16string& str2)
{
	ustring::const_iterator	cBegin, cEnd;
	size_t len;

	str2.clear();

	len = str1.length();
	str2.reserve(len);

	cBegin	= str1.begin();
	cEnd	= str1.end();

	while(cBegin != cEnd) {
		str2.push_back((unsigned16_t)*cBegin++);
	}
	XL_ASSERT(str2.length() == str1.length());
}
Exemplo n.º 18
0
uint64_t StringTable::addString (ustring str, ustring var_name)
{
    ASSERT (m_ptr && "StringTable has not been initialized");

    // The strings are laid out in the table as a struct:
    //
    //   struct TableRep {
    //       size_t len;
    //       size_t hash;
    //       char   str[len+1];
    //   };

    // Compute the size of the entry before adding it to the table 
    size_t size = sizeof(size_t) + sizeof(size_t) + str.size() + 1;
    if (((m_offset + size) >= m_size)) {
        reallocTable();
    }

    // It should be hard to trigger this assert, unless the table size is
    // very small and the string is very large.
    ASSERT (m_offset + size <= m_size && "String table allocation error");

    int offset = getOffset(str.string());
    if (offset < 0) {
        // Place the hash and length of the string before the characters
        size_t hash = str.hash();
        cudaMemcpy (m_ptr + m_offset, (void*)&hash, sizeof(size_t), cudaMemcpyHostToDevice);
        m_offset += sizeof(size_t);

        size_t len = str.length();
        cudaMemcpy (m_ptr + m_offset, (void*)&len, sizeof(size_t), cudaMemcpyHostToDevice);
        m_offset += sizeof(size_t);

        offset = m_offset;
        m_offset_map [str] = offset;
        m_name_map   [str] = var_name;

        // Copy the raw characters to the table
        cudaMemcpy (m_ptr + m_offset, str.c_str(), str.size() + 1, cudaMemcpyHostToDevice);
        m_offset += str.size() + 1;

        // Align the offset for the next entry to 8-byte boundaries
        m_offset = (m_offset + 0x7u) & ~0x7u;
    }

    uint64_t addr = reinterpret_cast<uint64_t>(m_ptr + offset);

    // Optionally create an OptiX variable for the string. It's not necessary to
    // create a variable for strings that do not appear by name in compiled code
    // (in either the OSL library functions or in the renderer).
    if (! var_name.empty()) {
        m_optix_ctx [var_name.string()]->setUserData (8, &addr);
    }

    return addr;
}
Exemplo n.º 19
0
  ustring replace(ustring source, ustring fromStr, ustring toStr, int offset, int times)
  {
    int total = 0;
    ustring::size_type pos=offset;
    while ( ( (pos = source.find(fromStr, pos)) < Glib::ustring::npos) && ( (times==0) || (total++<times) ) )
      {
	source.replace(pos, fromStr.length(), toStr);
	pos+=toStr.size();
      }
    return source;
  }
Exemplo n.º 20
0
float CFont::GetLineWidth(const ustring& text, size_t start /*= 0*/)
{
    size_t count = text.length()-start;
    for (int i = 0; i+start < text.size(); ++i)
    {
        if (text[i+start] == '\n')
        {
            count = i;
            break;
        }
    }
    return GetStringWidth(text.substr(start, count));
}
Exemplo n.º 21
0
void Text::append_next( const ustring& ustr )
{
  data.push_back( ustr );
  
  height = font_height * data.size();

  int new_length = ustr.length();
  if( new_length > width )
  {
    width = new_length;
  }

}
Exemplo n.º 22
0
  int strtod(double &value, ustring str)
  {
    const char *nptr = str.c_str();
    char *eptr;
    value = ::strtod(nptr, &eptr);

    if (nptr==eptr)
      return -1;
    else if (eptr<(char*)nptr+str.length())
      return 0;
    else
      return 1;
  }
Exemplo n.º 23
0
  int strtol(long &value, ustring str, int base)
  {
    const char *nptr = str.c_str();
    char *eptr;
    value = ::strtol(nptr, &eptr, base);

    if (nptr==eptr)
      return -1;
    else if (eptr<(char*)nptr+str.length())
      return 0;
    else
      return 1;
  }
Exemplo n.º 24
0
/**
 Search the page for some text.

 \param text the text to search
 \param[in,out] r the area where to start search, which will be set to the area
                  of the match (if any)
 \param direction in which direction search for text
 \param case_sensitivity whether search in a case sensitive way
 \param rotation the rotation assumed for the page
 */
bool page::search(const ustring &text, rectf &r, search_direction_enum direction,
                  case_sensitivity_enum case_sensitivity, rotation_enum rotation) const
{
    const size_t len = text.length();
    std::vector<Unicode> u(len);
    for (size_t i = 0; i < len; ++i) {
        u[i] = text[i];
    }

    const GBool sCase = case_sensitivity == case_sensitive ? gTrue : gFalse;
    const int rotation_value = (int)rotation * 90;

    bool found = false;
    double rect_left = r.left();
    double rect_top = r.top();
    double rect_right = r.right();
    double rect_bottom = r.bottom();

    TextOutputDev td(NULL, gTrue, 0, gFalse, gFalse);
    d->doc->doc->displayPage(&td, d->index + 1, 72, 72, rotation_value, false, true, false);
    TextPage *text_page = td.takeText();

    switch (direction) {
    case search_from_top:
        found = text_page->findText(&u[0], len,
                    gTrue, gTrue, gFalse, gFalse, sCase, gFalse, gFalse,
                    &rect_left, &rect_top, &rect_right, &rect_bottom);
        break;
    case search_next_result:
        found = text_page->findText(&u[0], len,
                    gFalse, gTrue, gTrue, gFalse, sCase, gFalse, gFalse,
                    &rect_left, &rect_top, &rect_right, &rect_bottom);
        break;
    case search_previous_result:
        found = text_page->findText(&u[0], len,
                    gFalse, gTrue, gTrue, gFalse, sCase, gTrue, gFalse,
                    &rect_left, &rect_top, &rect_right, &rect_bottom);
        break;
    }

    text_page->decRefCnt();
    r.set_left(rect_left);
    r.set_top(rect_top);
    r.set_right(rect_right);
    r.set_bottom(rect_bottom);

    return found;
}
Exemplo n.º 25
0
void DataValue::parseArray(const ustring &text, void *value) {
	ArrayValue *arr = (ArrayValue*)value;
	int i = 1;	// skip [
	while (text[i] != ']') {
		i++;	// skip '
		int p = text.find('\'', i);
		void *v = arr->add(ustring(text, i, p - i));
		i = p + 2;	// skip =
		p = text.find(',', i);
		if(p == -1)
			p = text.length() - 1;
		parse(ustring(text, i, p - i), arr->type, v);
		i = p;
		if(text[i] == ',') i++;
	}
}
Exemplo n.º 26
0
    InputMethodT makeIMFromString (ustring imStr) {
        InputMethodT im;
        _size_t_ eolPos;
        ustring transPortion;
        ustring specialToken = (imStr.find (" -> ") != ustring::npos) ?
            _(" -> ") : _(" ");

        while (imStr.length () > 1) {
            eolPos = imStr.find ("\n");
            transPortion = imStr.substr (0, eolPos);
            imStr = imStr.replace (0, eolPos + 1, "");
            im = addTransformation
                (im, transPortion.replace (1, specialToken.length (), ""));
        }
        return standardizeIM (im);
    }
Exemplo n.º 27
0
void findCommon(vector<ustring>& vec, const ustring& search, unsigned int& atchar)
{
    if (atchar > search.length())
          return;

    for (vector<ustring>::const_iterator i = vec.begin(); i != vec.end(); ++i)
    {
        if (atchar > i->length() ||
                search.substr(0, atchar).lowercase() != i->substr(0, atchar).lowercase()) {
            atchar--;
            return;
        }
    }
    findCommon(vec, search, ++atchar);

}
Exemplo n.º 28
0
    sstring base64_encode(ustring const& input) {
        BIO* b64 = BIO_new(BIO_f_base64());
        BIO* bmem = BIO_new(BIO_s_mem());
        b64 = BIO_push(b64, bmem);
        BIO_write(b64, input.c_str(), input.length());
        BIO_flush(b64);

        BUF_MEM* bptr;
        BIO_get_mem_ptr(b64, &bptr);

        sstring buffer(bptr->data, bptr->length - 1);

        BIO_free_all(b64);

        return buffer;
    }
Exemplo n.º 29
0
void CategorizeLine::clear_out_any_marker(ustring & line)
{
  size_t startpos = 0;
  startpos = line.find("\\", startpos);
  while (startpos != string::npos) {
    ustring marker;
    size_t endpos = line.find_first_of(" *", startpos);
    if (endpos == string::npos) {
      marker = line.substr(startpos + 1, line.length() - startpos);
    } else {
      marker = line.substr(startpos + 1, endpos - startpos - 1);
    }
    line.erase(startpos, marker.length() + 2);
    startpos++;
    startpos = line.find("\\", startpos);
  }
}
Exemplo n.º 30
0
void CheckMatchingPairs::check_matched_pairs(ustring & text)
// Checks on matched pairs. Output any problems found.
{
  for (unsigned int i = 0; i < text.length(); i++) {
    // Get the unicode character;
    gunichar unichar;
    unichar = g_utf8_get_char(text.substr(i, 1).c_str());
    // If we found a mirror character, investigate further.
    gunichar mirror;
    if (g_unichar_get_mirror_char(unichar, &mirror)) {
      // Do we ignore this one?
      if (ignores.find(unichar) != ignores.end())
        continue;
      // See whether this one opens or closes a pair.
      if (gopeners.find(unichar) != gopeners.end()) {
        // It opens: Add data.
        MatchingPairOpener opener(text.substr(i, 1), unichar, book, chapter, verse, get_context(text, i));
        openers.push_back(opener);
        continue;
      } else {
        // It closes: check for previously seen opener.
        bool give_message = false;
        if (openers.empty()) {
          give_message = true;
        }
        if (!give_message) {
          if (openers[openers.size() - 1].unichar == mirror) {
            // Remove last one.
            openers.pop_back();
          } else {
            // Flag message.
            give_message = true;
          }
        }
        if (give_message) {
          // Give message;
          message(book, chapter, verse, _("Pair not opened: ") + get_context(text, i));
        }
      }
    }
  }
}