2005-01-12 06:25:57 +03:00
|
|
|
/* $Id$ */
|
|
|
|
/**************************************************************************
|
|
|
|
* chars.c *
|
|
|
|
* *
|
|
|
|
* Copyright (C) 2005 Chris Allegretta *
|
|
|
|
* This program is free software; you can redistribute it and/or modify *
|
|
|
|
* it under the terms of the GNU General Public License as published by *
|
|
|
|
* the Free Software Foundation; either version 2, or (at your option) *
|
|
|
|
* any later version. *
|
|
|
|
* *
|
2005-05-15 23:57:17 +04:00
|
|
|
* This program is distributed in the hope that it will be useful, but *
|
|
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
|
|
|
* General Public License for more details. *
|
2005-01-12 06:25:57 +03:00
|
|
|
* *
|
|
|
|
* You should have received a copy of the GNU General Public License *
|
|
|
|
* along with this program; if not, write to the Free Software *
|
2005-05-15 23:57:17 +04:00
|
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA *
|
|
|
|
* 02110-1301, USA. *
|
2005-01-12 06:25:57 +03:00
|
|
|
* *
|
|
|
|
**************************************************************************/
|
|
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
#include <config.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
2005-01-14 07:22:14 +03:00
|
|
|
#include <string.h>
|
2005-01-12 06:25:57 +03:00
|
|
|
#include <ctype.h>
|
|
|
|
#include <assert.h>
|
|
|
|
#include "proto.h"
|
|
|
|
|
2005-01-22 21:24:16 +03:00
|
|
|
#ifdef NANO_WIDE
|
|
|
|
#ifdef HAVE_WCHAR_H
|
2005-01-12 06:25:57 +03:00
|
|
|
#include <wchar.h>
|
|
|
|
#endif
|
2005-01-22 21:24:16 +03:00
|
|
|
#ifdef HAVE_WCTYPE_H
|
2005-01-12 06:25:57 +03:00
|
|
|
#include <wctype.h>
|
|
|
|
#endif
|
2005-01-22 21:24:16 +03:00
|
|
|
#endif
|
2005-01-12 06:25:57 +03:00
|
|
|
|
2005-06-12 21:48:46 +04:00
|
|
|
#ifndef HAVE_ISBLANK
|
|
|
|
/* This function is equivalent to isblank(). */
|
2005-06-13 23:51:56 +04:00
|
|
|
int nisblank(int c)
|
2005-01-15 00:33:47 +03:00
|
|
|
{
|
2005-06-12 21:48:46 +04:00
|
|
|
return isspace(c) && (c == '\t' || !is_cntrl_char(c));
|
2005-01-15 00:33:47 +03:00
|
|
|
}
|
2005-03-16 19:32:33 +03:00
|
|
|
#endif
|
2005-03-16 18:34:22 +03:00
|
|
|
|
2005-06-12 21:48:46 +04:00
|
|
|
#if defined(NANO_WIDE) && !defined(HAVE_ISWBLANK)
|
|
|
|
/* This function is equivalent to iswblank(). */
|
2005-06-15 20:07:14 +04:00
|
|
|
int niswblank(wchar_t wc)
|
2005-01-12 06:25:57 +03:00
|
|
|
{
|
2005-06-12 21:48:46 +04:00
|
|
|
return iswspace(wc) && (wc == '\t' || !is_cntrl_wchar(wc));
|
2005-01-12 06:25:57 +03:00
|
|
|
}
|
2005-06-12 21:48:46 +04:00
|
|
|
#endif
|
2005-01-12 06:25:57 +03:00
|
|
|
|
2005-06-13 23:51:56 +04:00
|
|
|
/* Return TRUE if the value of c is in byte range, and FALSE
|
|
|
|
* otherwise. */
|
|
|
|
bool is_byte(int c)
|
|
|
|
{
|
|
|
|
return ((unsigned int)c == (unsigned char)c);
|
|
|
|
}
|
|
|
|
|
2005-06-15 10:04:08 +04:00
|
|
|
/* This function is equivalent to isalnum() for multibyte characters. */
|
|
|
|
bool is_alnum_mbchar(const char *c)
|
|
|
|
{
|
|
|
|
assert(c != NULL);
|
|
|
|
|
|
|
|
#ifdef NANO_WIDE
|
2005-06-16 06:09:57 +04:00
|
|
|
if (ISSET(USE_UTF8)) {
|
2005-06-15 10:04:08 +04:00
|
|
|
wchar_t wc;
|
|
|
|
int c_mb_len = mbtowc(&wc, c, MB_CUR_MAX);
|
|
|
|
|
|
|
|
if (c_mb_len <= 0) {
|
|
|
|
mbtowc(NULL, NULL, 0);
|
|
|
|
wc = (unsigned char)*c;
|
|
|
|
}
|
|
|
|
|
|
|
|
return iswalnum(wc);
|
|
|
|
} else
|
|
|
|
#endif
|
|
|
|
return isalnum((unsigned char)*c);
|
|
|
|
}
|
|
|
|
|
2005-01-12 06:25:57 +03:00
|
|
|
/* This function is equivalent to isblank() for multibyte characters. */
|
|
|
|
bool is_blank_mbchar(const char *c)
|
|
|
|
{
|
|
|
|
assert(c != NULL);
|
|
|
|
|
|
|
|
#ifdef NANO_WIDE
|
2005-06-16 06:09:57 +04:00
|
|
|
if (ISSET(USE_UTF8)) {
|
2005-01-12 06:25:57 +03:00
|
|
|
wchar_t wc;
|
|
|
|
int c_mb_len = mbtowc(&wc, c, MB_CUR_MAX);
|
|
|
|
|
|
|
|
if (c_mb_len <= 0) {
|
|
|
|
mbtowc(NULL, NULL, 0);
|
|
|
|
wc = (unsigned char)*c;
|
|
|
|
}
|
|
|
|
|
2005-06-12 21:48:46 +04:00
|
|
|
return iswblank(wc);
|
2005-01-12 06:25:57 +03:00
|
|
|
} else
|
|
|
|
#endif
|
2005-06-12 21:48:46 +04:00
|
|
|
return isblank((unsigned char)*c);
|
2005-01-12 06:25:57 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/* This function is equivalent to iscntrl(), except in that it also
|
|
|
|
* handles control characters with their high bits set. */
|
2005-02-08 23:37:53 +03:00
|
|
|
bool is_cntrl_char(int c)
|
2005-01-12 06:25:57 +03:00
|
|
|
{
|
2005-02-08 23:37:53 +03:00
|
|
|
return (-128 <= c && c < -96) || (0 <= c && c < 32) ||
|
|
|
|
(127 <= c && c < 160);
|
2005-01-12 06:25:57 +03:00
|
|
|
}
|
|
|
|
|
2005-06-12 21:48:46 +04:00
|
|
|
#ifdef NANO_WIDE
|
|
|
|
/* This function is equivalent to iscntrl() for wide characters, except
|
|
|
|
* in that it also handles wide control characters with their high bits
|
|
|
|
* set. */
|
2005-06-15 20:07:14 +04:00
|
|
|
bool is_cntrl_wchar(wchar_t wc)
|
2005-06-12 21:48:46 +04:00
|
|
|
{
|
2005-06-15 11:18:30 +04:00
|
|
|
return (0 <= wc && wc < 32) || (127 <= wc && wc < 160);
|
2005-06-12 21:48:46 +04:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2005-01-12 06:25:57 +03:00
|
|
|
/* This function is equivalent to iscntrl() for multibyte characters,
|
|
|
|
* except in that it also handles multibyte control characters with
|
|
|
|
* their high bits set. */
|
|
|
|
bool is_cntrl_mbchar(const char *c)
|
|
|
|
{
|
|
|
|
assert(c != NULL);
|
|
|
|
|
|
|
|
#ifdef NANO_WIDE
|
2005-06-16 06:09:57 +04:00
|
|
|
if (ISSET(USE_UTF8)) {
|
2005-01-12 06:25:57 +03:00
|
|
|
wchar_t wc;
|
|
|
|
int c_mb_len = mbtowc(&wc, c, MB_CUR_MAX);
|
|
|
|
|
|
|
|
if (c_mb_len <= 0) {
|
|
|
|
mbtowc(NULL, NULL, 0);
|
|
|
|
wc = (unsigned char)*c;
|
|
|
|
}
|
|
|
|
|
|
|
|
return is_cntrl_wchar(wc);
|
|
|
|
} else
|
|
|
|
#endif
|
|
|
|
return is_cntrl_char((unsigned char)*c);
|
|
|
|
}
|
|
|
|
|
2005-06-15 10:04:08 +04:00
|
|
|
/* This function is equivalent to ispunct() for multibyte characters. */
|
|
|
|
bool is_punct_mbchar(const char *c)
|
2005-06-13 06:40:04 +04:00
|
|
|
{
|
|
|
|
assert(c != NULL);
|
|
|
|
|
|
|
|
#ifdef NANO_WIDE
|
2005-06-16 06:09:57 +04:00
|
|
|
if (ISSET(USE_UTF8)) {
|
2005-06-13 06:40:04 +04:00
|
|
|
wchar_t wc;
|
|
|
|
int c_mb_len = mbtowc(&wc, c, MB_CUR_MAX);
|
|
|
|
|
|
|
|
if (c_mb_len <= 0) {
|
|
|
|
mbtowc(NULL, NULL, 0);
|
|
|
|
wc = (unsigned char)*c;
|
|
|
|
}
|
|
|
|
|
2005-06-15 10:04:08 +04:00
|
|
|
return iswpunct(wc);
|
2005-06-13 06:40:04 +04:00
|
|
|
} else
|
|
|
|
#endif
|
2005-06-15 10:04:08 +04:00
|
|
|
return ispunct((unsigned char)*c);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Return TRUE for a multibyte character found in a word (currently only
|
2005-06-21 08:16:12 +04:00
|
|
|
* an alphanumeric or punctuation character, and only the latter if
|
2005-06-15 10:04:08 +04:00
|
|
|
* allow_punct is TRUE) and FALSE otherwise. */
|
|
|
|
bool is_word_mbchar(const char *c, bool allow_punct)
|
|
|
|
{
|
|
|
|
assert(c != NULL);
|
|
|
|
|
|
|
|
return is_alnum_mbchar(c) || (allow_punct ? is_punct_mbchar(c) :
|
|
|
|
FALSE);
|
2005-06-13 06:40:04 +04:00
|
|
|
}
|
|
|
|
|
2005-06-12 06:14:48 +04:00
|
|
|
/* c is a control character. It displays as ^@, ^?, or ^[ch], where ch
|
2005-01-12 06:25:57 +03:00
|
|
|
* is c + 64. We return that character. */
|
2005-06-12 22:05:42 +04:00
|
|
|
char control_rep(char c)
|
2005-01-12 06:25:57 +03:00
|
|
|
{
|
|
|
|
/* Treat newlines embedded in a line as encoded nulls. */
|
|
|
|
if (c == '\n')
|
|
|
|
return '@';
|
|
|
|
else if (c == NANO_CONTROL_8)
|
|
|
|
return '?';
|
|
|
|
else
|
|
|
|
return c + 64;
|
|
|
|
}
|
|
|
|
|
2005-06-12 21:48:46 +04:00
|
|
|
#ifdef NANO_WIDE
|
|
|
|
/* c is a wide control character. It displays as ^@, ^?, or ^[ch],
|
|
|
|
* where ch is c + 64. We return that wide character. */
|
|
|
|
wchar_t control_wrep(wchar_t wc)
|
|
|
|
{
|
|
|
|
/* Treat newlines embedded in a line as encoded nulls. */
|
|
|
|
if (wc == '\n')
|
|
|
|
return '@';
|
|
|
|
else if (wc == NANO_CONTROL_8)
|
|
|
|
return '?';
|
|
|
|
else
|
|
|
|
return wc + 64;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* c is a multibyte control character. It displays as ^@, ^?, or ^[ch],
|
2005-01-12 06:25:57 +03:00
|
|
|
* where ch is c + 64. We return that multibyte character. */
|
|
|
|
char *control_mbrep(const char *c, char *crep, int *crep_len)
|
|
|
|
{
|
2005-06-21 00:58:41 +04:00
|
|
|
assert(c != NULL && crep != NULL && crep_len != NULL);
|
2005-01-12 06:25:57 +03:00
|
|
|
|
|
|
|
#ifdef NANO_WIDE
|
2005-06-16 06:09:57 +04:00
|
|
|
if (ISSET(USE_UTF8)) {
|
2005-06-14 06:08:25 +04:00
|
|
|
wchar_t wc;
|
2005-01-12 06:25:57 +03:00
|
|
|
|
2005-06-21 00:58:41 +04:00
|
|
|
if (mbtowc(&wc, c, MB_CUR_MAX) <= 0) {
|
2005-01-12 06:25:57 +03:00
|
|
|
mbtowc(NULL, NULL, 0);
|
2005-01-12 07:32:43 +03:00
|
|
|
wc = (unsigned char)*c;
|
2005-01-12 06:25:57 +03:00
|
|
|
}
|
|
|
|
|
2005-06-21 00:58:41 +04:00
|
|
|
*crep_len = wctomb(crep, control_wrep(wc));
|
2005-01-12 06:25:57 +03:00
|
|
|
|
2005-06-21 01:03:57 +04:00
|
|
|
if (*crep_len <= 0) {
|
2005-01-12 06:25:57 +03:00
|
|
|
wctomb(NULL, 0);
|
2005-06-21 01:03:57 +04:00
|
|
|
*crep_len = 0;
|
2005-01-12 06:25:57 +03:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
#endif
|
|
|
|
*crep_len = 1;
|
2005-06-12 22:05:42 +04:00
|
|
|
*crep = control_rep(*c);
|
2005-01-12 06:25:57 +03:00
|
|
|
#ifdef NANO_WIDE
|
|
|
|
}
|
|
|
|
#endif
|
2005-06-13 17:25:36 +04:00
|
|
|
|
|
|
|
return crep;
|
2005-01-12 06:25:57 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/* This function is equivalent to wcwidth() for multibyte characters. */
|
|
|
|
int mbwidth(const char *c)
|
|
|
|
{
|
|
|
|
assert(c != NULL);
|
|
|
|
|
|
|
|
#ifdef NANO_WIDE
|
2005-06-16 06:09:57 +04:00
|
|
|
if (ISSET(USE_UTF8)) {
|
2005-01-12 06:25:57 +03:00
|
|
|
wchar_t wc;
|
|
|
|
int c_mb_len = mbtowc(&wc, c, MB_CUR_MAX), width;
|
|
|
|
|
|
|
|
if (c_mb_len <= 0) {
|
|
|
|
mbtowc(NULL, NULL, 0);
|
|
|
|
wc = (unsigned char)*c;
|
|
|
|
}
|
|
|
|
|
|
|
|
width = wcwidth(wc);
|
2005-06-14 06:08:25 +04:00
|
|
|
|
2005-01-12 06:25:57 +03:00
|
|
|
if (width == -1)
|
|
|
|
width++;
|
|
|
|
|
|
|
|
return width;
|
|
|
|
} else
|
|
|
|
#endif
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Return the maximum width in bytes of a multibyte character. */
|
|
|
|
int mb_cur_max(void)
|
|
|
|
{
|
2005-01-22 21:24:16 +03:00
|
|
|
return
|
2005-01-12 06:25:57 +03:00
|
|
|
#ifdef NANO_WIDE
|
2005-06-16 06:09:57 +04:00
|
|
|
ISSET(USE_UTF8) ? MB_CUR_MAX :
|
2005-01-12 06:25:57 +03:00
|
|
|
#endif
|
2005-01-22 21:24:16 +03:00
|
|
|
1;
|
2005-01-12 06:25:57 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Convert the value in chr to a multibyte character with the same
|
2005-06-15 03:36:13 +04:00
|
|
|
* wide character value as chr, if possible. If the conversion
|
|
|
|
* succeeds, return the (dynamically allocated) multibyte character and
|
|
|
|
* its length. Otherwise, return an undefined (dynamically allocated)
|
|
|
|
* multibyte character and a length of zero. */
|
2005-03-14 21:47:21 +03:00
|
|
|
char *make_mbchar(int chr, int *chr_mb_len)
|
2005-01-12 06:25:57 +03:00
|
|
|
{
|
2005-03-14 21:47:21 +03:00
|
|
|
char *chr_mb;
|
|
|
|
|
2005-03-26 09:54:36 +03:00
|
|
|
assert(chr_mb_len != NULL);
|
2005-03-15 09:34:09 +03:00
|
|
|
|
2005-01-12 06:25:57 +03:00
|
|
|
#ifdef NANO_WIDE
|
2005-06-16 06:09:57 +04:00
|
|
|
if (ISSET(USE_UTF8)) {
|
2005-03-14 21:47:21 +03:00
|
|
|
chr_mb = charalloc(MB_CUR_MAX);
|
2005-01-12 06:25:57 +03:00
|
|
|
*chr_mb_len = wctomb(chr_mb, chr);
|
|
|
|
|
|
|
|
if (*chr_mb_len <= 0) {
|
2005-01-12 07:32:43 +03:00
|
|
|
wctomb(NULL, 0);
|
|
|
|
*chr_mb_len = 0;
|
2005-01-12 06:25:57 +03:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
#endif
|
|
|
|
*chr_mb_len = 1;
|
2005-06-13 18:00:22 +04:00
|
|
|
chr_mb = mallocstrncpy(NULL, (char *)&chr, 1);
|
2005-01-12 06:25:57 +03:00
|
|
|
#ifdef NANO_WIDE
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return chr_mb;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Parse a multibyte character from buf. Return the number of bytes
|
|
|
|
* used. If chr isn't NULL, store the multibyte character in it. If
|
2005-02-11 23:09:11 +03:00
|
|
|
* bad_chr isn't NULL, set it to TRUE if we have a bad multibyte
|
|
|
|
* character. If col isn't NULL, store the new display width in it. If
|
|
|
|
* *str is '\t', we expect col to have the current display width. */
|
|
|
|
int parse_mbchar(const char *buf, char *chr, bool *bad_chr, size_t
|
|
|
|
*col)
|
2005-01-12 06:25:57 +03:00
|
|
|
{
|
|
|
|
int buf_mb_len;
|
|
|
|
|
|
|
|
assert(buf != NULL);
|
|
|
|
|
|
|
|
if (bad_chr != NULL)
|
|
|
|
*bad_chr = FALSE;
|
|
|
|
|
2005-02-11 23:09:11 +03:00
|
|
|
#ifdef NANO_WIDE
|
2005-06-16 06:09:57 +04:00
|
|
|
if (ISSET(USE_UTF8)) {
|
2005-01-12 06:25:57 +03:00
|
|
|
/* Get the number of bytes in the multibyte character. */
|
|
|
|
buf_mb_len = mblen(buf, MB_CUR_MAX);
|
|
|
|
|
|
|
|
/* If buf contains a null byte or an invalid multibyte
|
2005-02-11 23:09:11 +03:00
|
|
|
* character, set bad_chr to TRUE (if it contains the latter)
|
|
|
|
* and interpret buf's first byte. */
|
2005-01-12 06:25:57 +03:00
|
|
|
if (buf_mb_len <= 0) {
|
|
|
|
mblen(NULL, 0);
|
2005-02-11 23:09:11 +03:00
|
|
|
if (buf_mb_len < 0 && bad_chr != NULL)
|
2005-01-12 06:25:57 +03:00
|
|
|
*bad_chr = TRUE;
|
2005-02-11 23:09:11 +03:00
|
|
|
buf_mb_len = 1;
|
2005-01-12 06:25:57 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Save the multibyte character in chr. */
|
|
|
|
if (chr != NULL) {
|
|
|
|
int i;
|
2005-03-11 07:03:32 +03:00
|
|
|
|
2005-01-12 06:25:57 +03:00
|
|
|
for (i = 0; i < buf_mb_len; i++)
|
|
|
|
chr[i] = buf[i];
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Save the column width of the wide character in col. */
|
|
|
|
if (col != NULL) {
|
|
|
|
/* If we have a tab, get its width in columns using the
|
|
|
|
* current value of col. */
|
|
|
|
if (*buf == '\t')
|
|
|
|
*col += tabsize - *col % tabsize;
|
|
|
|
/* If we have a control character, get its width using one
|
|
|
|
* column for the "^" that will be displayed in front of it,
|
|
|
|
* and the width in columns of its visible equivalent as
|
2005-01-24 17:57:57 +03:00
|
|
|
* returned by control_mbrep(). */
|
2005-01-12 06:25:57 +03:00
|
|
|
else if (is_cntrl_mbchar(buf)) {
|
2005-01-24 04:21:09 +03:00
|
|
|
char *ctrl_buf_mb = charalloc(MB_CUR_MAX);
|
2005-01-12 06:25:57 +03:00
|
|
|
int ctrl_buf_mb_len;
|
|
|
|
|
|
|
|
(*col)++;
|
|
|
|
|
|
|
|
ctrl_buf_mb = control_mbrep(buf, ctrl_buf_mb,
|
|
|
|
&ctrl_buf_mb_len);
|
|
|
|
|
|
|
|
*col += mbwidth(ctrl_buf_mb);
|
|
|
|
|
|
|
|
free(ctrl_buf_mb);
|
|
|
|
/* If we have a normal character, get its width in columns
|
|
|
|
* normally. */
|
|
|
|
} else
|
|
|
|
*col += mbwidth(buf);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
#endif
|
|
|
|
/* Get the number of bytes in the byte character. */
|
|
|
|
buf_mb_len = 1;
|
|
|
|
|
|
|
|
/* Save the byte character in chr. */
|
|
|
|
if (chr != NULL)
|
|
|
|
*chr = *buf;
|
|
|
|
|
|
|
|
if (col != NULL) {
|
|
|
|
/* If we have a tab, get its width in columns using the
|
|
|
|
* current value of col. */
|
|
|
|
if (*buf == '\t')
|
|
|
|
*col += tabsize - *col % tabsize;
|
|
|
|
/* If we have a control character, it's two columns wide:
|
|
|
|
* one column for the "^" that will be displayed in front of
|
|
|
|
* it, and one column for its visible equivalent as returned
|
2005-01-24 17:57:57 +03:00
|
|
|
* by control_mbrep(). */
|
2005-01-12 06:25:57 +03:00
|
|
|
else if (is_cntrl_char((unsigned char)*buf))
|
|
|
|
*col += 2;
|
|
|
|
/* If we have a normal character, it's one column wide. */
|
|
|
|
else
|
|
|
|
(*col)++;
|
|
|
|
}
|
|
|
|
#ifdef NANO_WIDE
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return buf_mb_len;
|
|
|
|
}
|
2005-01-15 00:50:32 +03:00
|
|
|
|
|
|
|
/* Return the index in buf of the beginning of the multibyte character
|
|
|
|
* before the one at pos. */
|
|
|
|
size_t move_mbleft(const char *buf, size_t pos)
|
|
|
|
{
|
|
|
|
size_t pos_prev = pos;
|
|
|
|
|
2005-03-23 08:56:11 +03:00
|
|
|
assert(buf != NULL && pos <= strlen(buf));
|
2005-01-15 00:50:32 +03:00
|
|
|
|
|
|
|
/* There is no library function to move backward one multibyte
|
|
|
|
* character. Here is the naive, O(pos) way to do it. */
|
|
|
|
while (TRUE) {
|
2005-02-11 23:09:11 +03:00
|
|
|
int buf_mb_len = parse_mbchar(buf + pos - pos_prev, NULL, NULL,
|
|
|
|
NULL);
|
2005-01-15 00:50:32 +03:00
|
|
|
|
2005-02-08 23:37:53 +03:00
|
|
|
if (pos_prev <= (size_t)buf_mb_len)
|
2005-01-15 00:50:32 +03:00
|
|
|
break;
|
|
|
|
|
|
|
|
pos_prev -= buf_mb_len;
|
|
|
|
}
|
|
|
|
|
|
|
|
return pos - pos_prev;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Return the index in buf of the beginning of the multibyte character
|
|
|
|
* after the one at pos. */
|
|
|
|
size_t move_mbright(const char *buf, size_t pos)
|
|
|
|
{
|
2005-02-11 23:09:11 +03:00
|
|
|
return pos + parse_mbchar(buf + pos, NULL, NULL, NULL);
|
2005-01-15 00:50:32 +03:00
|
|
|
}
|
2005-01-16 21:49:19 +03:00
|
|
|
|
|
|
|
#ifndef HAVE_STRCASECMP
|
|
|
|
/* This function is equivalent to strcasecmp(). */
|
|
|
|
int nstrcasecmp(const char *s1, const char *s2)
|
|
|
|
{
|
2005-03-20 10:24:49 +03:00
|
|
|
return strncasecmp(s1, s2, (size_t)-1);
|
2005-01-16 21:49:19 +03:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* This function is equivalent to strcasecmp() for multibyte strings. */
|
|
|
|
int mbstrcasecmp(const char *s1, const char *s2)
|
|
|
|
{
|
2005-01-25 22:21:11 +03:00
|
|
|
return mbstrncasecmp(s1, s2, (size_t)-1);
|
2005-01-16 21:49:19 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
#ifndef HAVE_STRNCASECMP
|
|
|
|
/* This function is equivalent to strncasecmp(). */
|
|
|
|
int nstrncasecmp(const char *s1, const char *s2, size_t n)
|
|
|
|
{
|
|
|
|
assert(s1 != NULL && s2 != NULL);
|
|
|
|
|
|
|
|
for (; n > 0 && *s1 != '\0' && *s2 != '\0'; n--, s1++, s2++) {
|
|
|
|
if (tolower(*s1) != tolower(*s2))
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (n > 0)
|
2005-06-13 17:25:36 +04:00
|
|
|
return tolower(*s1) - tolower(*s2);
|
2005-01-16 21:49:19 +03:00
|
|
|
else
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* This function is equivalent to strncasecmp() for multibyte
|
|
|
|
* strings. */
|
|
|
|
int mbstrncasecmp(const char *s1, const char *s2, size_t n)
|
|
|
|
{
|
|
|
|
#ifdef NANO_WIDE
|
2005-06-16 06:09:57 +04:00
|
|
|
if (ISSET(USE_UTF8)) {
|
2005-01-22 21:24:16 +03:00
|
|
|
char *s1_mb = charalloc(MB_CUR_MAX);
|
|
|
|
char *s2_mb = charalloc(MB_CUR_MAX);
|
2005-01-16 21:49:19 +03:00
|
|
|
wchar_t ws1, ws2;
|
|
|
|
|
2005-01-16 21:58:03 +03:00
|
|
|
assert(s1 != NULL && s2 != NULL);
|
|
|
|
|
2005-01-16 21:49:19 +03:00
|
|
|
while (n > 0 && *s1 != '\0' && *s2 != '\0') {
|
2005-06-13 17:25:36 +04:00
|
|
|
bool bad_s1_mb = FALSE, bad_s2_mb = FALSE;
|
2005-01-22 21:24:16 +03:00
|
|
|
int s1_mb_len, s2_mb_len;
|
|
|
|
|
|
|
|
s1_mb_len = parse_mbchar(s1, s1_mb, NULL, NULL);
|
2005-01-16 21:49:19 +03:00
|
|
|
|
|
|
|
if (mbtowc(&ws1, s1_mb, s1_mb_len) <= 0) {
|
|
|
|
mbtowc(NULL, NULL, 0);
|
|
|
|
ws1 = (unsigned char)*s1_mb;
|
2005-06-13 17:25:36 +04:00
|
|
|
bad_s1_mb = TRUE;
|
2005-01-16 21:49:19 +03:00
|
|
|
}
|
|
|
|
|
2005-01-22 21:24:16 +03:00
|
|
|
s2_mb_len = parse_mbchar(s2, s2_mb, NULL, NULL);
|
2005-01-16 21:49:19 +03:00
|
|
|
|
|
|
|
if (mbtowc(&ws2, s2_mb, s2_mb_len) <= 0) {
|
|
|
|
mbtowc(NULL, NULL, 0);
|
|
|
|
ws2 = (unsigned char)*s2_mb;
|
2005-06-13 17:25:36 +04:00
|
|
|
bad_s2_mb = TRUE;
|
2005-01-16 21:49:19 +03:00
|
|
|
}
|
|
|
|
|
2005-06-13 17:25:36 +04:00
|
|
|
if (n == 0 || bad_s1_mb != bad_s2_mb ||
|
|
|
|
towlower(ws1) != towlower(ws2))
|
2005-01-16 21:49:19 +03:00
|
|
|
break;
|
|
|
|
|
|
|
|
s1 += s1_mb_len;
|
|
|
|
s2 += s2_mb_len;
|
2005-01-16 23:05:36 +03:00
|
|
|
n--;
|
2005-01-16 21:49:19 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
free(s1_mb);
|
|
|
|
free(s2_mb);
|
|
|
|
|
2005-06-13 17:25:36 +04:00
|
|
|
return towlower(ws1) - towlower(ws2);
|
2005-01-16 21:49:19 +03:00
|
|
|
} else
|
|
|
|
#endif
|
2005-03-20 10:24:49 +03:00
|
|
|
return strncasecmp(s1, s2, n);
|
2005-01-16 21:49:19 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
#ifndef HAVE_STRCASESTR
|
|
|
|
/* This function is equivalent to strcasestr(). It was adapted from
|
|
|
|
* mutt's mutt_stristr() function. */
|
|
|
|
const char *nstrcasestr(const char *haystack, const char *needle)
|
|
|
|
{
|
|
|
|
assert(haystack != NULL && needle != NULL);
|
|
|
|
|
|
|
|
for (; *haystack != '\0'; haystack++) {
|
2005-01-22 22:56:16 +03:00
|
|
|
const char *r = haystack, *q = needle;
|
2005-01-16 21:49:19 +03:00
|
|
|
|
2005-01-22 22:56:16 +03:00
|
|
|
for (; tolower(*r) == tolower(*q) && *q != '\0'; r++, q++)
|
2005-01-16 21:49:19 +03:00
|
|
|
;
|
|
|
|
|
|
|
|
if (*q == '\0')
|
|
|
|
return haystack;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2005-01-22 21:24:16 +03:00
|
|
|
/* This function is equivalent to strcasestr() for multibyte strings. */
|
|
|
|
const char *mbstrcasestr(const char *haystack, const char *needle)
|
|
|
|
{
|
|
|
|
#ifdef NANO_WIDE
|
2005-06-16 06:09:57 +04:00
|
|
|
if (ISSET(USE_UTF8)) {
|
2005-01-22 22:56:16 +03:00
|
|
|
char *r_mb = charalloc(MB_CUR_MAX);
|
2005-01-22 21:24:16 +03:00
|
|
|
char *q_mb = charalloc(MB_CUR_MAX);
|
2005-01-22 22:56:16 +03:00
|
|
|
wchar_t wr, wq;
|
2005-01-22 21:24:16 +03:00
|
|
|
bool found_needle = FALSE;
|
|
|
|
|
|
|
|
assert(haystack != NULL && needle != NULL);
|
|
|
|
|
|
|
|
while (*haystack != '\0') {
|
2005-01-22 22:56:16 +03:00
|
|
|
const char *r = haystack, *q = needle;
|
|
|
|
int r_mb_len, q_mb_len;
|
2005-01-22 21:24:16 +03:00
|
|
|
|
|
|
|
while (*q != '\0') {
|
2005-06-13 17:25:36 +04:00
|
|
|
bool bad_r_mb = FALSE, bad_q_mb = FALSE;
|
|
|
|
|
2005-01-22 22:56:16 +03:00
|
|
|
r_mb_len = parse_mbchar(r, r_mb, NULL, NULL);
|
2005-01-22 21:24:16 +03:00
|
|
|
|
2005-01-22 22:56:16 +03:00
|
|
|
if (mbtowc(&wr, r_mb, r_mb_len) <= 0) {
|
2005-01-22 21:24:16 +03:00
|
|
|
mbtowc(NULL, NULL, 0);
|
2005-01-22 22:56:16 +03:00
|
|
|
wr = (unsigned char)*r;
|
2005-06-13 17:25:36 +04:00
|
|
|
bad_r_mb = TRUE;
|
2005-01-22 21:24:16 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
q_mb_len = parse_mbchar(q, q_mb, NULL, NULL);
|
|
|
|
|
|
|
|
if (mbtowc(&wq, q_mb, q_mb_len) <= 0) {
|
|
|
|
mbtowc(NULL, NULL, 0);
|
|
|
|
wq = (unsigned char)*q;
|
2005-06-13 17:25:36 +04:00
|
|
|
bad_q_mb = TRUE;
|
2005-01-22 21:24:16 +03:00
|
|
|
}
|
|
|
|
|
2005-06-13 17:25:36 +04:00
|
|
|
if (bad_r_mb != bad_q_mb ||
|
|
|
|
towlower(wr) != towlower(wq))
|
2005-01-22 21:24:16 +03:00
|
|
|
break;
|
|
|
|
|
2005-01-22 22:56:16 +03:00
|
|
|
r += r_mb_len;
|
2005-01-22 21:24:16 +03:00
|
|
|
q += q_mb_len;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (*q == '\0') {
|
|
|
|
found_needle = TRUE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2005-01-22 23:49:14 +03:00
|
|
|
haystack += move_mbright(haystack, 0);
|
2005-01-22 21:24:16 +03:00
|
|
|
}
|
|
|
|
|
2005-01-22 22:56:16 +03:00
|
|
|
free(r_mb);
|
2005-01-22 21:24:16 +03:00
|
|
|
free(q_mb);
|
|
|
|
|
2005-06-15 07:03:45 +04:00
|
|
|
return found_needle ? haystack : NULL;
|
2005-01-22 21:24:16 +03:00
|
|
|
} else
|
|
|
|
#endif
|
2005-03-20 10:24:49 +03:00
|
|
|
return strcasestr(haystack, needle);
|
2005-01-22 21:24:16 +03:00
|
|
|
}
|
|
|
|
|
2005-06-15 10:30:05 +04:00
|
|
|
#if !defined(NANO_SMALL) || !defined(DISABLE_TABCOMP)
|
2005-01-18 20:00:00 +03:00
|
|
|
/* This function is equivalent to strstr(), except in that it scans the
|
2005-01-22 23:49:14 +03:00
|
|
|
* string in reverse, starting at rev_start. */
|
2005-01-18 20:00:00 +03:00
|
|
|
const char *revstrstr(const char *haystack, const char *needle, const
|
|
|
|
char *rev_start)
|
|
|
|
{
|
|
|
|
assert(haystack != NULL && needle != NULL && rev_start != NULL);
|
|
|
|
|
|
|
|
for (; rev_start >= haystack; rev_start--) {
|
|
|
|
const char *r, *q;
|
|
|
|
|
2005-01-22 23:49:14 +03:00
|
|
|
for (r = rev_start, q = needle; *r == *q && *q != '\0'; r++, q++)
|
2005-01-18 20:00:00 +03:00
|
|
|
;
|
|
|
|
|
|
|
|
if (*q == '\0')
|
|
|
|
return rev_start;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
2005-06-15 10:30:05 +04:00
|
|
|
#endif /* !NANO_SMALL || !DISABLE_TABCOMP */
|
2005-01-18 20:00:00 +03:00
|
|
|
|
2005-06-15 10:30:05 +04:00
|
|
|
#ifndef NANO_SMALL
|
2005-01-18 20:00:00 +03:00
|
|
|
/* This function is equivalent to strcasestr(), except in that it scans
|
2005-01-22 23:49:14 +03:00
|
|
|
* the string in reverse, starting at rev_start. */
|
2005-01-16 21:49:19 +03:00
|
|
|
const char *revstrcasestr(const char *haystack, const char *needle,
|
|
|
|
const char *rev_start)
|
|
|
|
{
|
|
|
|
assert(haystack != NULL && needle != NULL && rev_start != NULL);
|
|
|
|
|
|
|
|
for (; rev_start >= haystack; rev_start--) {
|
|
|
|
const char *r = rev_start, *q = needle;
|
|
|
|
|
2005-01-22 23:49:14 +03:00
|
|
|
for (; tolower(*r) == tolower(*q) && *q != '\0'; r++, q++)
|
2005-01-16 21:49:19 +03:00
|
|
|
;
|
|
|
|
|
|
|
|
if (*q == '\0')
|
|
|
|
return rev_start;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
2005-01-24 04:14:17 +03:00
|
|
|
|
|
|
|
/* This function is equivalent to strcasestr() for multibyte strings,
|
|
|
|
* except in that it scans the string in reverse, starting at
|
|
|
|
* rev_start. */
|
|
|
|
const char *mbrevstrcasestr(const char *haystack, const char *needle,
|
|
|
|
const char *rev_start)
|
|
|
|
{
|
|
|
|
#ifdef NANO_WIDE
|
2005-06-16 06:09:57 +04:00
|
|
|
if (ISSET(USE_UTF8)) {
|
2005-01-24 04:14:17 +03:00
|
|
|
char *r_mb = charalloc(MB_CUR_MAX);
|
|
|
|
char *q_mb = charalloc(MB_CUR_MAX);
|
|
|
|
wchar_t wr, wq;
|
|
|
|
bool begin_line = FALSE, found_needle = FALSE;
|
|
|
|
|
|
|
|
assert(haystack != NULL && needle != NULL && rev_start != NULL);
|
|
|
|
|
|
|
|
while (!begin_line) {
|
|
|
|
const char *r = rev_start, *q = needle;
|
|
|
|
int r_mb_len, q_mb_len;
|
|
|
|
|
|
|
|
while (*q != '\0') {
|
2005-06-13 17:25:36 +04:00
|
|
|
bool bad_r_mb = FALSE, bad_q_mb = FALSE;
|
|
|
|
|
2005-01-24 04:14:17 +03:00
|
|
|
r_mb_len = parse_mbchar(r, r_mb, NULL, NULL);
|
|
|
|
|
|
|
|
if (mbtowc(&wr, r_mb, r_mb_len) <= 0) {
|
|
|
|
mbtowc(NULL, NULL, 0);
|
|
|
|
wr = (unsigned char)*r;
|
2005-06-13 17:25:36 +04:00
|
|
|
bad_r_mb = TRUE;
|
2005-01-24 04:14:17 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
q_mb_len = parse_mbchar(q, q_mb, NULL, NULL);
|
|
|
|
|
|
|
|
if (mbtowc(&wq, q_mb, q_mb_len) <= 0) {
|
|
|
|
mbtowc(NULL, NULL, 0);
|
|
|
|
wq = (unsigned char)*q;
|
2005-06-13 17:25:36 +04:00
|
|
|
bad_q_mb = TRUE;
|
2005-01-24 04:14:17 +03:00
|
|
|
}
|
|
|
|
|
2005-06-13 17:25:36 +04:00
|
|
|
if (bad_r_mb != bad_q_mb ||
|
|
|
|
towlower(wr) != towlower(wq))
|
2005-01-24 04:14:17 +03:00
|
|
|
break;
|
|
|
|
|
|
|
|
r += r_mb_len;
|
|
|
|
q += q_mb_len;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (*q == '\0') {
|
|
|
|
found_needle = TRUE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rev_start == haystack)
|
|
|
|
begin_line = TRUE;
|
|
|
|
else
|
|
|
|
rev_start = haystack + move_mbleft(haystack, rev_start -
|
|
|
|
haystack);
|
|
|
|
}
|
|
|
|
|
|
|
|
free(r_mb);
|
|
|
|
free(q_mb);
|
|
|
|
|
2005-06-15 07:03:45 +04:00
|
|
|
return found_needle ? rev_start : NULL;
|
2005-01-24 04:14:17 +03:00
|
|
|
} else
|
|
|
|
#endif
|
|
|
|
return revstrcasestr(haystack, needle, rev_start);
|
|
|
|
}
|
2005-06-13 17:25:36 +04:00
|
|
|
#endif /* !NANO_SMALL */
|
2005-01-16 21:49:19 +03:00
|
|
|
|
2005-01-25 22:21:11 +03:00
|
|
|
/* This function is equivalent to strlen() for multibyte strings. */
|
|
|
|
size_t mbstrlen(const char *s)
|
|
|
|
{
|
|
|
|
return mbstrnlen(s, (size_t)-1);
|
|
|
|
}
|
|
|
|
|
2005-01-16 21:49:19 +03:00
|
|
|
#ifndef HAVE_STRNLEN
|
|
|
|
/* This function is equivalent to strnlen(). */
|
|
|
|
size_t nstrnlen(const char *s, size_t maxlen)
|
|
|
|
{
|
|
|
|
size_t n = 0;
|
|
|
|
|
|
|
|
assert(s != NULL);
|
|
|
|
|
|
|
|
for (; maxlen > 0 && *s != '\0'; maxlen--, n++, s++)
|
|
|
|
;
|
|
|
|
|
|
|
|
return n;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* This function is equivalent to strnlen() for multibyte strings. */
|
|
|
|
size_t mbstrnlen(const char *s, size_t maxlen)
|
|
|
|
{
|
|
|
|
assert(s != NULL);
|
|
|
|
|
|
|
|
#ifdef NANO_WIDE
|
2005-06-16 06:09:57 +04:00
|
|
|
if (ISSET(USE_UTF8)) {
|
2005-01-16 21:49:19 +03:00
|
|
|
size_t n = 0;
|
|
|
|
int s_mb_len;
|
|
|
|
|
|
|
|
while (*s != '\0') {
|
2005-06-13 17:25:36 +04:00
|
|
|
s_mb_len = parse_mbchar(s, NULL, NULL, NULL);
|
2005-01-16 21:49:19 +03:00
|
|
|
|
2005-01-16 23:05:36 +03:00
|
|
|
if (maxlen == 0)
|
2005-01-16 21:49:19 +03:00
|
|
|
break;
|
|
|
|
|
2005-01-16 23:05:36 +03:00
|
|
|
maxlen--;
|
2005-01-25 22:21:11 +03:00
|
|
|
s += s_mb_len;
|
|
|
|
n++;
|
2005-01-16 21:49:19 +03:00
|
|
|
}
|
|
|
|
|
2005-01-25 22:21:11 +03:00
|
|
|
return n;
|
2005-01-16 21:49:19 +03:00
|
|
|
} else
|
|
|
|
#endif
|
2005-03-20 10:24:49 +03:00
|
|
|
return strnlen(s, maxlen);
|
2005-01-16 21:49:19 +03:00
|
|
|
}
|
2005-03-15 08:44:03 +03:00
|
|
|
|
|
|
|
#ifndef DISABLE_JUSTIFY
|
2005-06-14 05:55:56 +04:00
|
|
|
#ifdef ENABLE_NANORC
|
|
|
|
/* Return TRUE if the string s contains one or more blank characters,
|
|
|
|
* and FALSE otherwise. */
|
|
|
|
bool has_blank_chars(const char *s)
|
|
|
|
{
|
|
|
|
assert(s != NULL);
|
|
|
|
|
|
|
|
for (; *s != '\0'; s++) {
|
|
|
|
if (isblank(*s))
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Return TRUE if the multibyte string s contains one or more blank
|
|
|
|
* multibyte characters, and FALSE otherwise. */
|
|
|
|
bool has_blank_mbchars(const char *s)
|
|
|
|
{
|
2005-06-16 16:17:23 +04:00
|
|
|
assert(s != NULL);
|
2005-06-14 05:55:56 +04:00
|
|
|
|
|
|
|
#ifdef NANO_WIDE
|
2005-06-16 06:09:57 +04:00
|
|
|
if (ISSET(USE_UTF8)) {
|
2005-06-14 05:55:56 +04:00
|
|
|
char *chr_mb = charalloc(MB_CUR_MAX);
|
|
|
|
bool retval = FALSE;
|
|
|
|
|
|
|
|
while (*s != '\0') {
|
|
|
|
int chr_mb_len;
|
|
|
|
|
|
|
|
chr_mb_len = parse_mbchar(s, chr_mb, NULL, NULL);
|
|
|
|
|
|
|
|
if (is_blank_mbchar(chr_mb)) {
|
|
|
|
retval = TRUE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
s += chr_mb_len;
|
|
|
|
}
|
|
|
|
|
|
|
|
free(chr_mb);
|
|
|
|
|
|
|
|
return retval;
|
|
|
|
} else
|
|
|
|
#endif
|
|
|
|
return has_blank_chars(s);
|
|
|
|
}
|
2005-06-14 08:22:32 +04:00
|
|
|
#endif /* ENABLE_NANORC */
|
2005-06-14 05:55:56 +04:00
|
|
|
|
2005-03-15 08:44:03 +03:00
|
|
|
/* This function is equivalent to strchr() for multibyte strings. */
|
|
|
|
char *mbstrchr(const char *s, char *c)
|
|
|
|
{
|
|
|
|
assert(s != NULL && c != NULL);
|
|
|
|
|
|
|
|
#ifdef NANO_WIDE
|
2005-06-16 06:09:57 +04:00
|
|
|
if (ISSET(USE_UTF8)) {
|
2005-03-15 08:44:03 +03:00
|
|
|
char *s_mb = charalloc(MB_CUR_MAX);
|
|
|
|
const char *q = s;
|
|
|
|
wchar_t ws, wc;
|
2005-06-14 00:19:03 +04:00
|
|
|
int c_mb_len = mbtowc(&wc, c, MB_CUR_MAX);
|
2005-03-15 08:44:03 +03:00
|
|
|
|
|
|
|
if (c_mb_len <= 0) {
|
|
|
|
mbtowc(NULL, NULL, 0);
|
|
|
|
wc = (unsigned char)*c;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (*s != '\0') {
|
2005-06-14 00:19:03 +04:00
|
|
|
int s_mb_len = parse_mbchar(s, s_mb, NULL, NULL);
|
2005-03-15 08:44:03 +03:00
|
|
|
|
|
|
|
if (mbtowc(&ws, s_mb, s_mb_len) <= 0) {
|
|
|
|
mbtowc(NULL, NULL, 0);
|
|
|
|
ws = (unsigned char)*s;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ws == wc)
|
|
|
|
break;
|
|
|
|
|
|
|
|
s += s_mb_len;
|
|
|
|
q += s_mb_len;
|
|
|
|
}
|
|
|
|
|
|
|
|
free(s_mb);
|
|
|
|
|
|
|
|
if (ws != wc)
|
|
|
|
q = NULL;
|
|
|
|
|
|
|
|
return (char *)q;
|
|
|
|
} else
|
|
|
|
#endif
|
|
|
|
return strchr(s, *c);
|
|
|
|
}
|
2005-06-13 17:25:36 +04:00
|
|
|
#endif /* !DISABLE_JUSTIFY */
|
2005-06-15 03:36:13 +04:00
|
|
|
|
|
|
|
#ifdef ENABLE_NANORC
|
|
|
|
/* Check if the string s is a valid multibyte string. Return TRUE if it
|
|
|
|
* is, and FALSE otherwise. */
|
|
|
|
bool is_valid_mbstring(const char *s)
|
|
|
|
{
|
|
|
|
assert(s != NULL);
|
|
|
|
|
|
|
|
return
|
|
|
|
#ifdef NANO_WIDE
|
2005-06-16 06:09:57 +04:00
|
|
|
ISSET(USE_UTF8) ?
|
2005-06-18 09:15:08 +04:00
|
|
|
(mbstowcs(NULL, s, 0) != (size_t)-1) :
|
2005-06-15 03:36:13 +04:00
|
|
|
#endif
|
|
|
|
|
|
|
|
TRUE;
|
|
|
|
}
|
|
|
|
#endif /* ENABLE_NANORC */
|
|
|
|
|
|
|
|
#ifdef NANO_EXTRA
|
|
|
|
/* Convert the string s to a valid multibyte string with the same wide
|
2005-06-21 01:17:01 +04:00
|
|
|
* character values as s. Return the (dynamically allocated) multibyte
|
|
|
|
* string. */
|
2005-06-15 03:36:13 +04:00
|
|
|
char *make_valid_mbstring(const char *s)
|
|
|
|
{
|
|
|
|
assert(s != NULL);
|
|
|
|
|
|
|
|
#ifdef NANO_WIDE
|
2005-06-16 06:09:57 +04:00
|
|
|
if (ISSET(USE_UTF8)) {
|
2005-06-15 03:36:13 +04:00
|
|
|
char *chr_mb = charalloc(MB_CUR_MAX);
|
|
|
|
char *s_mb = charalloc((MB_CUR_MAX * strlen(s)) + 1);
|
|
|
|
size_t s_mb_len = 0;
|
|
|
|
|
|
|
|
while (*s != '\0') {
|
|
|
|
int chr_mb_len, i;
|
|
|
|
bool bad_chr;
|
|
|
|
|
|
|
|
chr_mb_len = parse_mbchar(s, chr_mb, &bad_chr, NULL);
|
|
|
|
|
|
|
|
if (bad_chr) {
|
|
|
|
char *bad_chr_mb;
|
|
|
|
int bad_chr_mb_len;
|
|
|
|
|
|
|
|
bad_chr_mb = make_mbchar((unsigned char)*chr_mb,
|
|
|
|
&bad_chr_mb_len);
|
|
|
|
|
|
|
|
for (i = 0; i < bad_chr_mb_len; i++)
|
|
|
|
s_mb[s_mb_len + i] = bad_chr_mb[i];
|
|
|
|
s_mb_len += bad_chr_mb_len;
|
|
|
|
|
|
|
|
free(bad_chr_mb);
|
|
|
|
} else {
|
|
|
|
for (i = 0; i < chr_mb_len; i++)
|
|
|
|
s_mb[s_mb_len + i] = chr_mb[i];
|
|
|
|
s_mb_len += chr_mb_len;
|
|
|
|
}
|
|
|
|
|
|
|
|
s += chr_mb_len;
|
|
|
|
}
|
|
|
|
|
|
|
|
free(chr_mb);
|
|
|
|
null_at(&s_mb, s_mb_len);
|
|
|
|
|
|
|
|
return s_mb;
|
|
|
|
} else
|
|
|
|
#endif
|
|
|
|
return mallocstrcpy(NULL, s);
|
|
|
|
}
|
|
|
|
#endif /* NANO_EXTRA */
|