1 /*@ S-nail - a mail user agent derived from Berkeley Mail.
2 *@ String support routines.
4 * Copyright (c) 2000-2004 Gunnar Ritter, Freiburg i. Br., Germany.
5 * Copyright (c) 2012 - 2017 Steffen (Daode) Nurpmeso <steffen@sdaoden.eu>.
8 * Copyright (c) 1980, 1993
9 * The Regents of the University of California. All rights reserved.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 #define n_FILE strings
38 #ifndef HAVE_AMALGAMATION
45 (savestr
)(char const *str n_MEMORY_DEBUG_ARGS
)
51 size
= strlen(str
) +1;
52 news
= (n_autorec_alloc_from_pool
)(NULL
, size n_MEMORY_DEBUG_ARGSCALL
);
53 memcpy(news
, str
, size
);
59 (savestrbuf
)(char const *sbuf
, size_t sbuf_len n_MEMORY_DEBUG_ARGS
)
64 news
= (n_autorec_alloc_from_pool
)(NULL
, sbuf_len
+1
65 n_MEMORY_DEBUG_ARGSCALL
);
66 memcpy(news
, sbuf
, sbuf_len
);
73 (savecatsep
)(char const *s1
, char sep
, char const *s2 n_MEMORY_DEBUG_ARGS
)
79 l1
= (s1
!= NULL
) ? strlen(s1
) : 0;
81 news
= (n_autorec_alloc_from_pool
)(NULL
, l1
+ (sep
!= '\0') + l2
+1
82 n_MEMORY_DEBUG_ARGSCALL
);
84 memcpy(news
+ 0, s1
, l1
);
88 memcpy(news
+ l1
, s2
, l2
);
95 * Support routines, auto-reclaimed storage
99 (i_strdup
)(char const *src n_MEMORY_DEBUG_ARGS
)
106 dest
= (n_autorec_alloc_from_pool
)(NULL
, sz n_MEMORY_DEBUG_ARGSCALL
);
107 i_strcpy(dest
, src
, sz
);
113 str_concat_csvl(struct str
*self
, ...) /* XXX onepass maybe better here */
121 for (l
= 0; (cs
= va_arg(vl
, char const*)) != NULL
;)
126 self
->s
= salloc(l
+1);
129 for (l
= 0; (cs
= va_arg(vl
, char const*)) != NULL
;) {
130 size_t i
= strlen(cs
);
131 memcpy(self
->s
+ l
, cs
, i
);
141 (str_concat_cpa
)(struct str
*self
, char const * const *cpa
,
142 char const *sep_o_null n_MEMORY_DEBUG_ARGS
)
145 char const * const *xcpa
;
148 sonl
= (sep_o_null
!= NULL
) ? strlen(sep_o_null
) : 0;
150 for (l
= 0, xcpa
= cpa
; *xcpa
!= NULL
; ++xcpa
)
151 l
+= strlen(*xcpa
) + sonl
;
154 self
->s
= (n_autorec_alloc_from_pool
)(NULL
, l
+1 n_MEMORY_DEBUG_ARGSCALL
);
156 for (l
= 0, xcpa
= cpa
; *xcpa
!= NULL
; ++xcpa
) {
157 size_t i
= strlen(*xcpa
);
158 memcpy(self
->s
+ l
, *xcpa
, i
);
161 memcpy(self
->s
+ l
, sep_o_null
, sonl
);
171 * Routines that are not related to auto-reclaimed storage follow.
175 n_anyof_buf(char const *template, char const *dat
, size_t len
){
180 while((c
= *template++) != '\0')
181 if(strchr(dat
, c
) != NULL
)
184 while((c
= *template++) != '\0')
185 if(memchr(dat
, c
, len
) != NULL
)
194 n_strsep(char **iolist
, char sep
, bool_t ignore_empty
)
199 for (base
= *iolist
; base
!= NULL
; base
= *iolist
) {
200 while (*base
!= '\0' && blankspacechar(*base
))
202 cp
= strchr(base
, sep
);
207 cp
= base
+ strlen(base
);
209 while (cp
> base
&& blankspacechar(cp
[-1]))
212 if (*base
!= '\0' || !ignore_empty
)
220 i_strcpy(char *dest
, char const *src
, size_t size
)
224 for (;; ++dest
, ++src
)
225 if ((*dest
= lowerconv(*src
)) == '\0') {
227 } else if (--size
== 0) {
236 is_prefix(char const *as1
, char const *as2
) /* TODO arg order */
241 for (; (c
= *as1
) == *as2
&& c
!= '\0'; ++as1
, ++as2
)
249 string_quote(char const *v
) /* TODO too simpleminded (getrawlist(), +++ ..) */
256 for (i
= 0, cp
= v
; (c
= *cp
) != '\0'; ++i
, ++cp
)
257 if (c
== '"' || c
== '\\')
261 for (i
= 0, cp
= v
; (c
= *cp
) != '\0'; rv
[i
++] = c
, ++cp
)
262 if (c
== '"' || c
== '\\')
270 laststring(char *linebuf
, bool_t
*needs_list
, bool_t strip
)
272 char *cp
, *p
, quoted
;
275 /* Anything to do at all? */
276 if (*(cp
= linebuf
) == '\0')
278 cp
+= strlen(linebuf
) -1;
280 /* Strip away trailing blanks */
281 while (spacechar(*cp
) && cp
> linebuf
)
287 /* Now search for the BOS of the "last string" */
289 if (quoted
== '\'' || quoted
== '"') {
295 while (cp
> linebuf
) {
300 } else if (!spacechar(*cp
))
302 if (cp
== linebuf
|| cp
[-1] != '\\') {
303 /* When in whitespace mode, WS prefix doesn't belong */
308 /* Expand the escaped quote character */
309 for (p
= --cp
; (p
[0] = p
[1]) != '\0'; ++p
)
312 if (strip
&& quoted
!= ' ' && *cp
== quoted
)
313 for (p
= cp
; (p
[0] = p
[1]) != '\0'; ++p
)
316 /* The "last string" has been skipped over, but still, try to step backwards
317 * until we are at BOS or see whitespace, so as to make possible things like
318 * "? copy +'x y.mbox'" or even "? copy +x\ y.mbox" */
319 while (cp
> linebuf
) {
321 if (spacechar(*cp
)) {
324 /* We can furtherly release our callees if we now decide whether the
325 * remaining non-"last string" line content contains non-WS */
326 while (--p
>= linebuf
)
335 if (cp
!= NULL
&& *cp
== '\0')
337 *needs_list
= (cp
!= linebuf
&& *linebuf
!= '\0');
348 makelow(char *cp
) /* TODO isn't that crap? --> */
351 #ifdef HAVE_C90AMEND1
352 if (n_mb_cur_max
> 1) {
357 while (*cp
!= '\0') {
358 len
= mbtowc(&wc
, cp
, n_mb_cur_max
);
363 if (wctomb(tp
, wc
) == len
)
364 tp
+= len
, cp
+= len
;
366 *tp
++ = *cp
++; /* <-- at least here */
373 *cp
= tolower((uc_i
)*cp
);
374 while (*cp
++ != '\0');
380 substr(char const *str
, char const *sub
)
382 char const *cp
, *backup
;
387 while (*str
!= '\0' && *cp
!= '\0') {
388 #ifdef HAVE_C90AMEND1
389 if (n_mb_cur_max
> 1) {
393 if ((sz
= mbtowc(&c
, cp
, n_mb_cur_max
)) == -1)
396 if ((sz
= mbtowc(&c2
, str
, n_mb_cur_max
)) == -1)
402 if ((sz
= mbtowc(&c
, backup
, n_mb_cur_max
)) > 0) {
428 return (*cp
== '\0');
432 sstpcpy(char *dst
, char const *src
)
435 while ((*dst
= *src
++) != '\0')
442 (sstrdup
)(char const *cp n_MEMORY_DEBUG_ARGS
)
447 dp
= (cp
== NULL
) ? NULL
: (sbufdup
)(cp
, strlen(cp
) n_MEMORY_DEBUG_ARGSCALL
);
453 (sbufdup
)(char const *cp
, size_t len n_MEMORY_DEBUG_ARGS
)
458 dp
= (n_alloc
)(len
+1 n_MEMORY_DEBUG_ARGSCALL
);
467 n_strscpy(char *dst
, char const *src
, size_t dstsize
){
471 if(n_LIKELY(dstsize
> 0)){
474 if((dst
[rv
] = src
[rv
]) == '\0')
477 }while(--dstsize
> 0);
491 asccasecmp(char const *s1
, char const *s2
)
497 char c1
= *s1
++, c2
= *s2
++;
498 if ((cmp
= lowerconv(c1
) - lowerconv(c2
)) != 0 || c1
== '\0')
506 ascncasecmp(char const *s1
, char const *s2
, size_t sz
)
512 char c1
= *s1
++, c2
= *s2
++;
513 cmp
= (ui8_t
)lowerconv(c1
);
514 cmp
-= (ui8_t
)lowerconv(c2
);
515 if (cmp
!= 0 || c1
== '\0')
523 asccasestr(char const *s1
, char const *s2
)
528 for (c2
= *s2
++, c2
= lowerconv(c2
);;) {
529 if ((c1
= *s1
++) == '\0') {
533 if (lowerconv(c1
) == c2
&& is_asccaseprefix(s2
, s1
)) {
543 is_asccaseprefix(char const *as1
, char const *as2
) /* TODO arg order */
548 for(;; ++as1
, ++as2
){
554 if(c1
!= c2
|| c1
== '\0')
564 is_ascncaseprefix(char const *as1
, char const *as2
, size_t sz
)
570 for(rv
= TRU1
; sz
-- > 0; ++as1
, ++as2
){
576 if(!(rv
= (c1
== c2
)) || c1
== '\0')
587 (n_str_assign_buf
)(struct str
*self
, char const *buf
, uiz_t buflen
588 n_MEMORY_DEBUG_ARGS
){
590 if(buflen
== UIZ_MAX
)
591 buflen
= (buf
== NULL
) ? 0 : strlen(buf
);
593 assert(buflen
== 0 || buf
!= NULL
);
595 if(n_LIKELY(buflen
> 0)){
596 self
->s
= (n_realloc
)(self
->s
, (self
->l
= buflen
) +1
597 n_MEMORY_DEBUG_ARGSCALL
);
598 memcpy(self
->s
, buf
, buflen
);
599 self
->s
[buflen
] = '\0';
607 (n_str_add_buf
)(struct str
*self
, char const *buf
, uiz_t buflen
608 n_MEMORY_DEBUG_ARGS
){
610 if(buflen
== UIZ_MAX
)
611 buflen
= (buf
== NULL
) ? 0 : strlen(buf
);
613 assert(buflen
== 0 || buf
!= NULL
);
616 size_t osl
= self
->l
, nsl
= osl
+ buflen
;
618 self
->s
= (n_realloc
)(self
->s
, (self
->l
= nsl
) +1
619 n_MEMORY_DEBUG_ARGSCALL
);
620 memcpy(self
->s
+ osl
, buf
, buflen
);
628 n_str_trim(struct str
*self
){
635 if((l
= self
->l
) > 0){
636 while(spacechar(*cp
)){
641 self
->s
= n_UNCONST(cp
);
645 for(cp
+= l
-1; spacechar(*cp
); --cp
)
656 n_str_trim_ifs(struct str
*self
, bool_t dodefaults
){
658 char const *ifs
, *cp
;
662 if((l
= self
->l
) == 0)
665 ifs
= ok_vlook(ifs_ws
);
669 /* Check whether we can go fast(er) path */
670 for(i
= 0; (c
= ifs
[i
]) != '\0'; ++i
){
672 case ' ': s
= c
; break;
673 case '\t': t
= c
; break;
674 case '\n': n
= c
; break;
676 /* Need to go the slow path */
677 while(strchr(ifs
, *cp
) != NULL
){
682 self
->s
= n_UNCONST(cp
);
685 for(cp
+= l
-1; strchr(ifs
, *cp
) != NULL
;){
688 /* An uneven number of reverse solidus escapes last WS! */
689 else if(*--cp
== '\\'){
692 for(j
= 1; l
- (uiz_t
)j
> 0 && cp
[-j
] == '\\'; ++j
)
711 /* No ifs-ws? No more data? No trimming */
712 if(l
== 0 || (i
== 0 && !dodefaults
))
722 while((c
= *cp
) != '\0' && (c
== s
|| c
== t
|| c
== n
)){
727 self
->s
= n_UNCONST(cp
);
731 for(cp
+= l
-1; (c
= *cp
) != '\0' && (c
== s
|| c
== t
|| c
== n
);){
734 /* An uneven number of reverse solidus escapes last WS! */
735 else if(*--cp
== '\\'){
738 for(j
= 1; l
- (uiz_t
)j
> 0 && cp
[-j
] == '\\'; ++j
)
754 * struct n_string TODO extend, optimize
758 (n_string_clear
)(struct n_string
*self n_MEMORY_DEBUG_ARGS
){
761 assert(self
!= NULL
);
763 if(self
->s_size
!= 0){
765 (n_free
)(self
->s_dat n_MEMORY_DEBUG_ARGSCALL
);
767 self
->s_len
= self
->s_auto
= self
->s_size
= 0;
775 (n_string_reserve
)(struct n_string
*self
, size_t noof n_MEMORY_DEBUG_ARGS
){
779 assert(self
!= NULL
);
783 #if 0 /* FIXME memory alloc too large */
784 if(SI32_MAX
- n_ALIGN(1) - l
<= noof
)
785 n_panic(_("Memory allocation too large"));
788 if((i
= s
- l
) <= ++noof
){
789 i
+= l
+ (ui32_t
)noof
;
794 self
->s_dat
= (n_realloc
)(self
->s_dat
, i n_MEMORY_DEBUG_ARGSCALL
);
796 char *ndat
= (n_autorec_alloc_from_pool
)(NULL
, i
797 n_MEMORY_DEBUG_ARGSCALL
);
800 memcpy(ndat
, self
->s_dat
, l
);
809 (n_string_resize
)(struct n_string
*self
, size_t nlen n_MEMORY_DEBUG_ARGS
){
812 assert(self
!= NULL
);
813 #if 0 /* FIXME memory alloc too large */
814 if(SI32_MAX
- n_ALIGN(1) - l
<= noof
)
815 n_panic(_("Memory allocation too large"));
818 if(self
->s_len
< nlen
)
819 self
= (n_string_reserve
)(self
, nlen n_MEMORY_DEBUG_ARGSCALL
);
820 self
->s_len
= (ui32_t
)nlen
;
826 (n_string_push_buf
)(struct n_string
*self
, char const *buf
, size_t buflen
827 n_MEMORY_DEBUG_ARGS
){
830 assert(self
!= NULL
);
831 assert(buflen
== 0 || buf
!= NULL
);
833 if(buflen
== UIZ_MAX
)
834 buflen
= (buf
== NULL
) ? 0 : strlen(buf
);
839 self
= (n_string_reserve
)(self
, buflen n_MEMORY_DEBUG_ARGSCALL
);
840 memcpy(&self
->s_dat
[i
= self
->s_len
], buf
, buflen
);
841 self
->s_len
= (i
+= (ui32_t
)buflen
);
848 (n_string_push_c
)(struct n_string
*self
, char c n_MEMORY_DEBUG_ARGS
){
851 assert(self
!= NULL
);
853 if(self
->s_len
+ 1 >= self
->s_size
)
854 self
= (n_string_reserve
)(self
, 1 n_MEMORY_DEBUG_ARGSCALL
);
855 self
->s_dat
[self
->s_len
++] = c
;
861 (n_string_unshift_buf
)(struct n_string
*self
, char const *buf
, size_t buflen
862 n_MEMORY_DEBUG_ARGS
){
865 assert(self
!= NULL
);
866 assert(buflen
== 0 || buf
!= NULL
);
868 if(buflen
== UIZ_MAX
)
869 buflen
= (buf
== NULL
) ? 0 : strlen(buf
);
872 self
= (n_string_reserve
)(self
, buflen n_MEMORY_DEBUG_ARGSCALL
);
874 memmove(&self
->s_dat
[buflen
], self
->s_dat
, self
->s_len
);
875 memcpy(self
->s_dat
, buf
, buflen
);
876 self
->s_len
+= (ui32_t
)buflen
;
883 (n_string_unshift_c
)(struct n_string
*self
, char c n_MEMORY_DEBUG_ARGS
){
886 assert(self
!= NULL
);
888 if(self
->s_len
+ 1 >= self
->s_size
)
889 self
= (n_string_reserve
)(self
, 1 n_MEMORY_DEBUG_ARGSCALL
);
891 memmove(&self
->s_dat
[1], self
->s_dat
, self
->s_len
);
899 (n_string_insert_buf
)(struct n_string
*self
, size_t idx
,
900 char const *buf
, size_t buflen n_MEMORY_DEBUG_ARGS
){
903 assert(self
!= NULL
);
904 assert(buflen
== 0 || buf
!= NULL
);
905 assert(idx
<= self
->s_len
);
907 if(buflen
== UIZ_MAX
)
908 buflen
= (buf
== NULL
) ? 0 : strlen(buf
);
911 self
= (n_string_reserve
)(self
, buflen n_MEMORY_DEBUG_ARGSCALL
);
913 memmove(&self
->s_dat
[idx
+ buflen
], &self
->s_dat
[idx
],
915 memcpy(&self
->s_dat
[idx
], buf
, buflen
);
916 self
->s_len
+= (ui32_t
)buflen
;
923 (n_string_insert_c
)(struct n_string
*self
, size_t idx
,
924 char c n_MEMORY_DEBUG_ARGS
){
927 assert(self
!= NULL
);
928 assert(idx
<= self
->s_len
);
930 if(self
->s_len
+ 1 >= self
->s_size
)
931 self
= (n_string_reserve
)(self
, 1 n_MEMORY_DEBUG_ARGSCALL
);
933 memmove(&self
->s_dat
[idx
+ 1], &self
->s_dat
[idx
], self
->s_len
- idx
);
934 self
->s_dat
[idx
] = c
;
941 n_string_cut(struct n_string
*self
, size_t idx
, size_t len
){
944 assert(self
!= NULL
);
945 assert(UIZ_MAX
- idx
> len
);
946 assert(SI32_MAX
>= idx
+ len
);
947 assert(idx
+ len
<= self
->s_len
);
950 memmove(&self
->s_dat
[idx
], &self
->s_dat
[idx
+ len
],
951 (self
->s_len
-= len
) - idx
);
957 (n_string_cp
)(struct n_string
*self n_MEMORY_DEBUG_ARGS
){
961 assert(self
!= NULL
);
963 if(self
->s_size
== 0)
964 self
= (n_string_reserve
)(self
, 1 n_MEMORY_DEBUG_ARGSCALL
);
966 (rv
= self
->s_dat
)[self
->s_len
] = '\0';
972 n_string_cp_const(struct n_string
const *self
){
976 assert(self
!= NULL
);
978 if(self
->s_size
!= 0){
979 ((struct n_string
*)n_UNCONST(self
))->s_dat
[self
->s_len
] = '\0';
992 n_utf8_to_utf32(char const **bdat
, size_t *blen
) /* TODO check false UTF8 */
1006 if ((x
& 0xE0u
) == 0xC0u
) {
1011 } else if ((x
& 0xF0u
) == 0xE0u
) {
1047 n_utf32_to_utf8(ui32_t c
, char *buf
)
1054 ui8_t dec_leader_mask
;
1055 ui8_t dec_leader_val_mask
;
1056 ui8_t dec_bytes_togo
;
1060 {0x00000000, 0x00000000, 0x00, 0, 0x00, 0x00, 0, 0, {0,}},
1061 {0x00000000, 0x0000007F, 0x00, 1, 0x80, 0x7F, 1-1, 1, {0,}},
1062 {0x00000080, 0x000007FF, 0xC0, 2, 0xE0, 0xFF-0xE0, 2-1, 2, {0,}},
1063 /* We assume surrogates are U+D800 - U+DFFF, _cat index 3 */
1064 /* xxx _from_utf32() simply assumes magic code points for surrogates!
1065 * xxx (However, should we ever get yet another surrogate range we
1066 * xxx need to deal with that all over the place anyway? */
1067 {0x00000800, 0x0000FFFF, 0xE0, 3, 0xF0, 0xFF-0xF0, 3-1, 3, {0,}},
1068 {0x00010000, 0x0010FFFF, 0xF0, 4, 0xF8, 0xFF-0xF8, 4-1, 4, {0,}},
1072 if (c
<= _cat
[0].upper_bound
) { catp
+= 0; goto j0
; }
1073 if (c
<= _cat
[1].upper_bound
) { catp
+= 1; goto j1
; }
1074 if (c
<= _cat
[2].upper_bound
) { catp
+= 2; goto j2
; }
1075 if (c
<= _cat
[3].upper_bound
) {
1076 /* Surrogates may not be converted (Compatibility rule C10) */
1077 if (c
>= 0xD800u
&& c
<= 0xDFFFu
)
1082 if (c
<= _cat
[4].upper_bound
) { catp
+= 4; goto j4
; }
1084 c
= 0xFFFDu
; /* Unicode replacement character */
1088 buf
[3] = (char)0x80u
| (char)(c
& 0x3Fu
); c
>>= 6;
1090 buf
[2] = (char)0x80u
| (char)(c
& 0x3Fu
); c
>>= 6;
1092 buf
[1] = (char)0x80u
| (char)(c
& 0x3Fu
); c
>>= 6;
1094 buf
[0] = (char)catp
->enc_leader
| (char)(c
);
1096 buf
[catp
->enc_lval
] = '\0';
1103 * Our iconv(3) wrapper
1108 n_iconv_open(char const *tocode
, char const *fromcode
){
1112 if((!asccasecmp(fromcode
, "unknown-8bit") ||
1113 !asccasecmp(fromcode
, "binary")) &&
1114 (fromcode
= ok_vlook(charset_unknown_8bit
)) == NULL
)
1115 fromcode
= ok_vlook(CHARSET_8BIT_OKEY
);
1117 id
= iconv_open(tocode
, fromcode
);
1119 /* If the encoding names are equal at this point, they are just not
1120 * understood by iconv(), and we cannot sensibly use it in any way. We do
1121 * not perform this as an optimization above since iconv() can otherwise be
1122 * used to check the validity of the input even with identical encoding
1124 if (id
== (iconv_t
)-1 && !asccasecmp(tocode
, fromcode
))
1125 n_err_no
= n_ERR_NONE
;
1131 n_iconv_close(iconv_t cd
){
1135 iconvd
= (iconv_t
)-1;
1140 n_iconv_reset(iconv_t cd
){
1142 iconv(cd
, NULL
, NULL
, NULL
, NULL
);
1146 /* (2012-09-24: export and use it exclusively to isolate prototype problems
1147 * (*inb* is 'char const **' except in POSIX) in a single place.
1148 * GNU libiconv even allows for configuration time const/non-const..
1149 * In the end it's an ugly guess, but we can't do better since make(1) doesn't
1150 * support compiler invocations which bail on error, so no -Werror */
1151 /* Citrus project? */
1152 # if defined _ICONV_H_ && defined __ICONV_F_HIDE_INVALID
1153 /* DragonFly 3.2.1 is special TODO newer DragonFly too, but different */
1155 # define __INBCAST(S) (char ** __restrict__)n_UNCONST(S)
1157 # define __INBCAST(S) (char const **)n_UNCONST(S)
1159 # elif n_OS_SUNOS || n_OS_SOLARIS
1160 # define __INBCAST(S) (char const ** __restrict__)n_UNCONST(S)
1163 # define __INBCAST(S) (char **)n_UNCONST(S)
1167 n_iconv_buf(iconv_t cd
, enum n_iconv_flags icf
,
1168 char const **inb
, size_t *inbleft
, char **outb
, size_t *outbleft
){
1172 if((icf
& n_ICONV_UNIREPL
) && !(n_psonce
& n_PSO_UNICODE
))
1173 icf
&= ~n_ICONV_UNIREPL
;
1178 sz
= iconv(cd
, __INBCAST(inb
), inbleft
, outb
, outbleft
);
1179 if(sz
> 0 && !(icf
& n_ICONV_IGN_NOREVERSE
)){
1183 if(sz
!= (size_t)-1)
1187 if(!(icf
& n_ICONV_IGN_ILSEQ
) || err
!= n_ERR_ILSEQ
)
1192 if(icf
& n_ICONV_UNIREPL
){
1193 if(*outbleft
>= sizeof(n_unirepl
) -1){
1194 memcpy(*outb
, n_unirepl
, sizeof(n_unirepl
) -1);
1195 *outb
+= sizeof(n_unirepl
) -1;
1196 *outbleft
-= sizeof(n_unirepl
) -1;
1199 }else if(*outbleft
> 0){
1206 }else if(*outbleft
> 0){
1219 n_iconv_str(iconv_t cd
, enum n_iconv_flags icf
,
1220 struct str
*out
, struct str
const *in
, struct str
*in_rest_or_null
)
1233 ol
= (ol
<< 1) - (ol
>> 4);
1244 if((err
= n_iconv_buf(cd
, icf
, &ib
, &il
, &ob
, &ol
)) == 0 || err
!= E2BIG
)
1249 obb
= n_realloc(obb
, olb
+1);
1252 if (in_rest_or_null
!= NULL
) {
1253 in_rest_or_null
->s
= n_UNCONST(ib
);
1254 in_rest_or_null
->l
= il
;
1257 out
->s
[out
->l
= olb
- ol
] = '\0';
1263 n_iconv_onetime_cp(enum n_iconv_flags icf
,
1264 char const *tocode
, char const *fromcode
, char const *input
){
1272 tocode
= ok_vlook(ttycharset
);
1273 if(fromcode
== NULL
)
1276 if((icd
= iconv_open(tocode
, fromcode
)) == (iconv_t
)-1)
1279 in
.l
= strlen(in
.s
= n_UNCONST(input
)); /* logical */
1280 out
.s
= NULL
, out
.l
= 0;
1281 if(!n_iconv_str(icd
, icf
, &out
, &in
, NULL
))
1282 rv
= savestrbuf(out
.s
, out
.l
);
1291 #endif /* HAVE_ICONV */