"Fossies" - the Fresh Open Source Software Archive

Member "s-nail-14.9.11/strings.c" (8 Aug 2018, 32238 Bytes) of package /linux/misc/s-nail-14.9.11.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "strings.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 14.9.10_vs_14.9.11.

    1 /*@ S-nail - a mail user agent derived from Berkeley Mail.
    2  *@ String support routines.
    3  *
    4  * Copyright (c) 2000-2004 Gunnar Ritter, Freiburg i. Br., Germany.
    5  * Copyright (c) 2012 - 2018 Steffen (Daode) Nurpmeso <steffen@sdaoden.eu>.
    6  * SPDX-License-Identifier: BSD-3-Clause
    7  */
    8 /*
    9  * Copyright (c) 1980, 1993
   10  *      The Regents of the University of California.  All rights reserved.
   11  *
   12  * Redistribution and use in source and binary forms, with or without
   13  * modification, are permitted provided that the following conditions
   14  * are met:
   15  * 1. Redistributions of source code must retain the above copyright
   16  *    notice, this list of conditions and the following disclaimer.
   17  * 2. Redistributions in binary form must reproduce the above copyright
   18  *    notice, this list of conditions and the following disclaimer in the
   19  *    documentation and/or other materials provided with the distribution.
   20  * 3. Neither the name of the University nor the names of its contributors
   21  *    may be used to endorse or promote products derived from this software
   22  *    without specific prior written permission.
   23  *
   24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   34  * SUCH DAMAGE.
   35  */
   36 #undef n_FILE
   37 #define n_FILE strings
   38 
   39 #ifndef HAVE_AMALGAMATION
   40 # include "nail.h"
   41 #endif
   42 
   43 #include <ctype.h>
   44 
   45 FL char *
   46 (savestr)(char const *str n_MEMORY_DEBUG_ARGS)
   47 {
   48    size_t size;
   49    char *news;
   50    NYD_ENTER;
   51 
   52    size = strlen(str);
   53    news = (n_autorec_alloc_from_pool)(NULL, size +1 n_MEMORY_DEBUG_ARGSCALL);
   54    if(size > 0)
   55       memcpy(news, str, size);
   56    news[size] = '\0';
   57    NYD_LEAVE;
   58    return news;
   59 }
   60 
   61 FL char *
   62 (savestrbuf)(char const *sbuf, size_t sbuf_len n_MEMORY_DEBUG_ARGS)
   63 {
   64    char *news;
   65    NYD_ENTER;
   66 
   67    news = (n_autorec_alloc_from_pool)(NULL, sbuf_len +1
   68          n_MEMORY_DEBUG_ARGSCALL);
   69    if(sbuf_len > 0)
   70       memcpy(news, sbuf, sbuf_len);
   71    news[sbuf_len] = 0;
   72    NYD_LEAVE;
   73    return news;
   74 }
   75 
   76 FL char *
   77 (savecatsep)(char const *s1, char sep, char const *s2 n_MEMORY_DEBUG_ARGS)
   78 {
   79    size_t l1, l2;
   80    char *news;
   81    NYD_ENTER;
   82 
   83    l1 = (s1 != NULL) ? strlen(s1) : 0;
   84    l2 = strlen(s2);
   85    news = (n_autorec_alloc_from_pool)(NULL, l1 + (sep != '\0') + l2 +1
   86          n_MEMORY_DEBUG_ARGSCALL);
   87    if (l1 > 0) {
   88       memcpy(news + 0, s1, l1);
   89       if (sep != '\0')
   90          news[l1++] = sep;
   91    }
   92    if(l2 > 0)
   93       memcpy(news + l1, s2, l2);
   94    news[l1 + l2] = '\0';
   95    NYD_LEAVE;
   96    return news;
   97 }
   98 
   99 /*
  100  * Support routines, auto-reclaimed storage
  101  */
  102 
  103 FL struct str *
  104 str_concat_csvl(struct str *self, ...) /* XXX onepass maybe better here */
  105 {
  106    va_list vl;
  107    size_t l;
  108    char const *cs;
  109    NYD_ENTER;
  110 
  111    va_start(vl, self);
  112    for (l = 0; (cs = va_arg(vl, char const*)) != NULL;)
  113       l += strlen(cs);
  114    va_end(vl);
  115 
  116    self->l = l;
  117    self->s = n_autorec_alloc(l +1);
  118 
  119    va_start(vl, self);
  120    for (l = 0; (cs = va_arg(vl, char const*)) != NULL;) {
  121       size_t i;
  122 
  123       i = strlen(cs);
  124       if(i > 0){
  125          memcpy(self->s + l, cs, i);
  126          l += i;
  127       }
  128    }
  129    self->s[l] = '\0';
  130    va_end(vl);
  131    NYD_LEAVE;
  132    return self;
  133 }
  134 
  135 FL struct str *
  136 (str_concat_cpa)(struct str *self, char const * const *cpa,
  137    char const *sep_o_null n_MEMORY_DEBUG_ARGS)
  138 {
  139    size_t sonl, l;
  140    char const * const *xcpa;
  141    NYD_ENTER;
  142 
  143    sonl = (sep_o_null != NULL) ? strlen(sep_o_null) : 0;
  144 
  145    for (l = 0, xcpa = cpa; *xcpa != NULL; ++xcpa)
  146       l += strlen(*xcpa) + sonl;
  147 
  148    self->l = l;
  149    self->s = (n_autorec_alloc_from_pool)(NULL, l +1 n_MEMORY_DEBUG_ARGSCALL);
  150 
  151    for (l = 0, xcpa = cpa; *xcpa != NULL; ++xcpa) {
  152       size_t i;
  153 
  154       i = strlen(*xcpa);
  155       if(i > 0){
  156          memcpy(self->s + l, *xcpa, i);
  157          l += i;
  158       }
  159       if (sonl > 0) {
  160          memcpy(self->s + l, sep_o_null, sonl);
  161          l += sonl;
  162       }
  163    }
  164    self->s[l] = '\0';
  165    NYD_LEAVE;
  166    return self;
  167 }
  168 
  169 /*
  170  * Routines that are not related to auto-reclaimed storage follow.
  171  */
  172 
  173 FL bool_t
  174 n_anyof_buf(char const *template, char const *dat, size_t len){
  175    char c;
  176    NYD2_ENTER;
  177 
  178    if(len == UIZ_MAX){
  179       while((c = *template++) != '\0')
  180          if(strchr(dat, c) != NULL)
  181             break;
  182    }else if(len > 0){
  183       while((c = *template++) != '\0')
  184          if(memchr(dat, c, len) != NULL)
  185             break;
  186    }else
  187       c = '\0';
  188    NYD2_LEAVE;
  189    return (c != '\0');
  190 }
  191 
  192 FL char *
  193 n_strsep(char **iolist, char sep, bool_t ignore_empty){
  194    char *base, *cp;
  195    NYD2_ENTER;
  196 
  197    for(base = *iolist; base != NULL; base = *iolist){
  198       while(*base != '\0' && blankspacechar(*base))
  199          ++base;
  200 
  201       cp = strchr(base, sep);
  202       if(cp != NULL)
  203          *iolist = &cp[1];
  204       else{
  205          *iolist = NULL;
  206          cp = &base[strlen(base)];
  207       }
  208       while(cp > base && blankspacechar(cp[-1]))
  209          --cp;
  210       *cp = '\0';
  211       if(*base != '\0' || !ignore_empty)
  212          break;
  213    }
  214    NYD2_LEAVE;
  215    return base;
  216 }
  217 
  218 FL char *
  219 n_strsep_esc(char **iolist, char sep, bool_t ignore_empty){
  220    char *cp, c, *base;
  221    bool_t isesc, anyesc;
  222    NYD2_ENTER;
  223 
  224    for(base = *iolist; base != NULL; base = *iolist){
  225       while((c = *base) != '\0' && blankspacechar(c))
  226          ++base;
  227 
  228       for(isesc = anyesc = FAL0, cp = base;; ++cp){
  229          if(n_UNLIKELY((c = *cp) == '\0')){
  230             *iolist = NULL;
  231             break;
  232          }else if(!isesc){
  233             if(c == sep){
  234                *iolist = &cp[1];
  235                break;
  236             }
  237             isesc = (c == '\\');
  238          }else{
  239             isesc = FAL0;
  240             anyesc |= (c == sep);
  241          }
  242       }
  243 
  244       while(cp > base && blankspacechar(cp[-1]))
  245          --cp;
  246       *cp = '\0';
  247 
  248       if(*base != '\0'){
  249          if(anyesc){
  250             char *ins;
  251 
  252             for(ins = cp = base;; ++ins)
  253                if((c = *cp) == '\\' && cp[1] == sep){
  254                   *ins = sep;
  255                   cp += 2;
  256                }else if((*ins = (++cp, c)) == '\0')
  257                   break;
  258          }
  259       }
  260 
  261       if(*base != '\0' || !ignore_empty)
  262          break;
  263    }
  264    NYD2_LEAVE;
  265    return base;
  266 }
  267 
  268 FL bool_t
  269 is_prefix(char const *as1, char const *as2) /* TODO arg order */
  270 {
  271    char c;
  272    NYD2_ENTER;
  273 
  274    for (; (c = *as1) == *as2 && c != '\0'; ++as1, ++as2)
  275       if (*as2 == '\0')
  276          break;
  277    NYD2_LEAVE;
  278    return (c == '\0');
  279 }
  280 
  281 FL char *
  282 string_quote(char const *v) /* TODO too simpleminded (getrawlist(), +++ ..) */
  283 {
  284    char const *cp;
  285    size_t i;
  286    char c, *rv;
  287    NYD2_ENTER;
  288 
  289    for (i = 0, cp = v; (c = *cp) != '\0'; ++i, ++cp)
  290       if (c == '"' || c == '\\')
  291          ++i;
  292    rv = n_autorec_alloc(i +1);
  293 
  294    for (i = 0, cp = v; (c = *cp) != '\0'; rv[i++] = c, ++cp)
  295       if (c == '"' || c == '\\')
  296          rv[i++] = '\\';
  297    rv[i] = '\0';
  298    NYD2_LEAVE;
  299    return rv;
  300 }
  301 
  302 FL void
  303 makelow(char *cp) /* TODO isn't that crap? --> */
  304 {
  305       NYD_ENTER;
  306 #ifdef HAVE_C90AMEND1
  307    if (n_mb_cur_max > 1) {
  308       char *tp = cp;
  309       wchar_t wc;
  310       int len;
  311 
  312       while (*cp != '\0') {
  313          len = mbtowc(&wc, cp, n_mb_cur_max);
  314          if (len < 0)
  315             *tp++ = *cp++;
  316          else {
  317             wc = towlower(wc);
  318             if (wctomb(tp, wc) == len)
  319                tp += len, cp += len;
  320             else
  321                *tp++ = *cp++; /* <-- at least here */
  322          }
  323       }
  324    } else
  325 #endif
  326    {
  327       do
  328          *cp = tolower((uc_i)*cp);
  329       while (*cp++ != '\0');
  330    }
  331    NYD_LEAVE;
  332 }
  333 
  334 FL bool_t
  335 substr(char const *str, char const *sub)
  336 {
  337    char const *cp, *backup;
  338    NYD_ENTER;
  339 
  340    cp = sub;
  341    backup = str;
  342    while (*str != '\0' && *cp != '\0') {
  343 #ifdef HAVE_C90AMEND1
  344       if (n_mb_cur_max > 1) {
  345          wchar_t c, c2;
  346          int sz;
  347 
  348          if ((sz = mbtowc(&c, cp, n_mb_cur_max)) == -1)
  349             goto Jsinglebyte;
  350          cp += sz;
  351          if ((sz = mbtowc(&c2, str, n_mb_cur_max)) == -1)
  352             goto Jsinglebyte;
  353          str += sz;
  354          c = towupper(c);
  355          c2 = towupper(c2);
  356          if (c != c2) {
  357             if ((sz = mbtowc(&c, backup, n_mb_cur_max)) > 0) {
  358                backup += sz;
  359                str = backup;
  360             } else
  361                str = ++backup;
  362             cp = sub;
  363          }
  364       } else
  365 Jsinglebyte:
  366 #endif
  367       {
  368          int c, c2;
  369 
  370          c = *cp++ & 0377;
  371          if (islower(c))
  372             c = toupper(c);
  373          c2 = *str++ & 0377;
  374          if (islower(c2))
  375             c2 = toupper(c2);
  376          if (c != c2) {
  377             str = ++backup;
  378             cp = sub;
  379          }
  380       }
  381    }
  382    NYD_LEAVE;
  383    return (*cp == '\0');
  384 }
  385 
  386 FL char *
  387 sstpcpy(char *dst, char const *src)
  388 {
  389    NYD2_ENTER;
  390    while ((*dst = *src++) != '\0')
  391       ++dst;
  392    NYD2_LEAVE;
  393    return dst;
  394 }
  395 
  396 FL char *
  397 (sstrdup)(char const *cp n_MEMORY_DEBUG_ARGS)
  398 {
  399    char *dp;
  400    NYD2_ENTER;
  401 
  402    dp = (cp == NULL) ? NULL : (sbufdup)(cp, strlen(cp) n_MEMORY_DEBUG_ARGSCALL);
  403    NYD2_LEAVE;
  404    return dp;
  405 }
  406 
  407 FL char *
  408 (sbufdup)(char const *cp, size_t len n_MEMORY_DEBUG_ARGS)
  409 {
  410    char *dp = NULL;
  411    NYD2_ENTER;
  412 
  413    dp = (n_alloc)(len +1 n_MEMORY_DEBUG_ARGSCALL);
  414    if (cp != NULL)
  415       memcpy(dp, cp, len);
  416    dp[len] = '\0';
  417    NYD2_LEAVE;
  418    return dp;
  419 }
  420 
  421 FL ssize_t
  422 n_strscpy(char *dst, char const *src, size_t dstsize){
  423    ssize_t rv;
  424    NYD2_ENTER;
  425 
  426    if(n_LIKELY(dstsize > 0)){
  427       rv = 0;
  428       do{
  429          if((dst[rv] = src[rv]) == '\0')
  430             goto jleave;
  431          ++rv;
  432       }while(--dstsize > 0);
  433       dst[--rv] = '\0';
  434    }
  435 #ifdef HAVE_DEVEL
  436    else
  437       assert(dstsize > 0);
  438 #endif
  439    rv = -1;
  440 jleave:
  441    NYD2_LEAVE;
  442    return rv;
  443 }
  444 
  445 FL int
  446 asccasecmp(char const *s1, char const *s2)
  447 {
  448    int cmp;
  449    NYD2_ENTER;
  450 
  451    for (;;) {
  452       char c1 = *s1++, c2 = *s2++;
  453       if ((cmp = lowerconv(c1) - lowerconv(c2)) != 0 || c1 == '\0')
  454          break;
  455    }
  456    NYD2_LEAVE;
  457    return cmp;
  458 }
  459 
  460 FL int
  461 ascncasecmp(char const *s1, char const *s2, size_t sz)
  462 {
  463    int cmp = 0;
  464    NYD2_ENTER;
  465 
  466    while (sz-- > 0) {
  467       char c1 = *s1++, c2 = *s2++;
  468       cmp = (ui8_t)lowerconv(c1);
  469       cmp -= (ui8_t)lowerconv(c2);
  470       if (cmp != 0 || c1 == '\0')
  471          break;
  472    }
  473    NYD2_LEAVE;
  474    return cmp;
  475 }
  476 
  477 FL char const *
  478 asccasestr(char const *s1, char const *s2)
  479 {
  480    char c2, c1;
  481    NYD2_ENTER;
  482 
  483    for (c2 = *s2++, c2 = lowerconv(c2);;) {
  484       if ((c1 = *s1++) == '\0') {
  485          s1 = NULL;
  486          break;
  487       }
  488       if (lowerconv(c1) == c2 && is_asccaseprefix(s2, s1)) {
  489          --s1;
  490          break;
  491       }
  492    }
  493    NYD2_LEAVE;
  494    return s1;
  495 }
  496 
  497 FL bool_t
  498 is_asccaseprefix(char const *as1, char const *as2) /* TODO arg order */
  499 {
  500    char c1, c2;
  501    NYD2_ENTER;
  502 
  503    for(;; ++as1, ++as2){
  504       c1 = *as1;
  505       c1 = lowerconv(c1);
  506       c2 = *as2;
  507       c2 = lowerconv(c2);
  508 
  509       if(c1 != c2 || c1 == '\0')
  510          break;
  511       if(c2 == '\0')
  512          break;
  513    }
  514    NYD2_LEAVE;
  515    return (c1 == '\0');
  516 }
  517 
  518 FL bool_t
  519 is_ascncaseprefix(char const *as1, char const *as2, size_t sz)
  520 {
  521    char c1, c2;
  522    bool_t rv;
  523    NYD2_ENTER;
  524 
  525    for(rv = TRU1; sz-- > 0; ++as1, ++as2){
  526       c1 = *as1;
  527       c1 = lowerconv(c1);
  528       c2 = *as2;
  529       c2 = lowerconv(c2);
  530 
  531       if(!(rv = (c1 == c2)) || c1 == '\0')
  532          break;
  533       if(c2 == '\0')
  534          break;
  535    }
  536    NYD2_LEAVE;
  537    return rv;
  538 }
  539 
  540 
  541 FL struct str *
  542 (n_str_assign_buf)(struct str *self, char const *buf, uiz_t buflen
  543       n_MEMORY_DEBUG_ARGS){
  544    NYD_ENTER;
  545    if(buflen == UIZ_MAX)
  546       buflen = (buf == NULL) ? 0 : strlen(buf);
  547 
  548    assert(buflen == 0 || buf != NULL);
  549 
  550    if(n_LIKELY(buflen > 0)){
  551       self->s = (n_realloc)(self->s, (self->l = buflen) +1
  552             n_MEMORY_DEBUG_ARGSCALL);
  553       memcpy(self->s, buf, buflen);
  554       self->s[buflen] = '\0';
  555    }else
  556       self->l = 0;
  557    NYD_LEAVE;
  558    return self;
  559 }
  560 
  561 FL struct str *
  562 (n_str_add_buf)(struct str *self, char const *buf, uiz_t buflen
  563       n_MEMORY_DEBUG_ARGS){
  564    NYD_ENTER;
  565    if(buflen == UIZ_MAX)
  566       buflen = (buf == NULL) ? 0 : strlen(buf);
  567 
  568    assert(buflen == 0 || buf != NULL);
  569 
  570    if(buflen > 0) {
  571       size_t osl = self->l, nsl = osl + buflen;
  572 
  573       self->s = (n_realloc)(self->s, (self->l = nsl) +1
  574             n_MEMORY_DEBUG_ARGSCALL);
  575       memcpy(self->s + osl, buf, buflen);
  576       self->s[nsl] = '\0';
  577    }
  578    NYD_LEAVE;
  579    return self;
  580 }
  581 
  582 FL struct str *
  583 n_str_trim(struct str *self, enum n_str_trim_flags stf){
  584    size_t l;
  585    char const *cp;
  586    NYD2_ENTER;
  587 
  588    cp = self->s;
  589 
  590    if((l = self->l) > 0 && (stf & n_STR_TRIM_FRONT)){
  591       while(spacechar(*cp)){
  592          ++cp;
  593          if(--l == 0)
  594             break;
  595       }
  596       self->s = n_UNCONST(cp);
  597    }
  598 
  599    if(l > 0 && (stf & n_STR_TRIM_END)){
  600       for(cp += l -1; spacechar(*cp); --cp)
  601          if(--l == 0)
  602             break;
  603    }
  604    self->l = l;
  605 
  606    NYD2_LEAVE;
  607    return self;
  608 }
  609 
  610 FL struct str *
  611 n_str_trim_ifs(struct str *self, bool_t dodefaults){
  612    char s, t, n, c;
  613    char const *ifs, *cp;
  614    size_t l, i;
  615    NYD2_ENTER;
  616 
  617    if((l = self->l) == 0)
  618       goto jleave;
  619 
  620    ifs = ok_vlook(ifs_ws);
  621    cp = self->s;
  622    s = t = n = '\0';
  623 
  624    /* Check whether we can go fast(er) path */
  625    for(i = 0; (c = ifs[i]) != '\0'; ++i){
  626       switch(c){
  627       case ' ': s = c; break;
  628       case '\t': t = c; break;
  629       case '\n': n = c; break;
  630       default:
  631          /* Need to go the slow path */
  632          while(strchr(ifs, *cp) != NULL){
  633             ++cp;
  634             if(--l == 0)
  635                break;
  636          }
  637          self->s = n_UNCONST(cp);
  638 
  639          if(l > 0){
  640             for(cp += l -1; strchr(ifs, *cp) != NULL;){
  641                if(--l == 0)
  642                   break;
  643                /* An uneven number of reverse solidus escapes last WS! */
  644                else if(*--cp == '\\'){
  645                   siz_t j;
  646 
  647                   for(j = 1; l - (uiz_t)j > 0 && cp[-j] == '\\'; ++j)
  648                      ;
  649                   if(j & 1){
  650                      ++l;
  651                      break;
  652                   }
  653                }
  654             }
  655          }
  656          self->l = l;
  657 
  658          if(!dodefaults)
  659             goto jleave;
  660          cp = self->s;
  661          ++i;
  662          break;
  663       }
  664    }
  665 
  666    /* No ifs-ws?  No more data?  No trimming */
  667    if(l == 0 || (i == 0 && !dodefaults))
  668       goto jleave;
  669 
  670    if(dodefaults){
  671       s = ' ';
  672       t = '\t';
  673       n = '\n';
  674    }
  675 
  676    if(l > 0){
  677       while((c = *cp) != '\0' && (c == s || c == t || c == n)){
  678          ++cp;
  679          if(--l == 0)
  680             break;
  681       }
  682       self->s = n_UNCONST(cp);
  683    }
  684 
  685    if(l > 0){
  686       for(cp += l -1; (c = *cp) != '\0' && (c == s || c == t || c == n);){
  687          if(--l == 0)
  688             break;
  689          /* An uneven number of reverse solidus escapes last WS! */
  690          else if(*--cp == '\\'){
  691             siz_t j;
  692 
  693             for(j = 1; l - (uiz_t)j > 0 && cp[-j] == '\\'; ++j)
  694                ;
  695             if(j & 1){
  696                ++l;
  697                break;
  698             }
  699          }
  700       }
  701    }
  702    self->l = l;
  703 jleave:
  704    NYD2_LEAVE;
  705    return self;
  706 }
  707 
  708 /*
  709  * struct n_string TODO extend, optimize
  710  */
  711 
  712 FL struct n_string *
  713 (n_string_clear)(struct n_string *self n_MEMORY_DEBUG_ARGS){
  714    NYD_ENTER;
  715 
  716    assert(self != NULL);
  717 
  718    if(self->s_size != 0){
  719       if(!self->s_auto){
  720          (n_free)(self->s_dat n_MEMORY_DEBUG_ARGSCALL);
  721       }
  722       self->s_len = self->s_auto = self->s_size = 0;
  723       self->s_dat = NULL;
  724    }
  725    NYD_LEAVE;
  726    return self;
  727 }
  728 
  729 FL struct n_string *
  730 (n_string_reserve)(struct n_string *self, size_t noof n_MEMORY_DEBUG_ARGS){
  731    ui32_t i, l, s;
  732    NYD_ENTER;
  733    assert(self != NULL);
  734 
  735    s = self->s_size;
  736    l = self->s_len;
  737    if((size_t)SI32_MAX - n_ALIGN(1) - l <= noof)
  738       n_panic(_("Memory allocation too large"));
  739 
  740    if((i = s - l) <= ++noof){
  741       i += l + (ui32_t)noof;
  742       i = n_ALIGN(i);
  743       self->s_size = i -1;
  744 
  745       if(!self->s_auto)
  746          self->s_dat = (n_realloc)(self->s_dat, i n_MEMORY_DEBUG_ARGSCALL);
  747       else{
  748          char *ndat = (n_autorec_alloc_from_pool)(NULL, i
  749                n_MEMORY_DEBUG_ARGSCALL);
  750 
  751          if(l > 0)
  752             memcpy(ndat, self->s_dat, l);
  753          self->s_dat = ndat;
  754       }
  755    }
  756    NYD_LEAVE;
  757    return self;
  758 }
  759 
  760 FL struct n_string *
  761 (n_string_resize)(struct n_string *self, size_t nlen n_MEMORY_DEBUG_ARGS){
  762    NYD_ENTER;
  763    assert(self != NULL);
  764 
  765    if(UICMP(z, SI32_MAX, <=, nlen))
  766       n_panic(_("Memory allocation too large"));
  767 
  768    if(self->s_len < nlen)
  769       self = (n_string_reserve)(self, nlen n_MEMORY_DEBUG_ARGSCALL);
  770    self->s_len = (ui32_t)nlen;
  771    NYD_LEAVE;
  772    return self;
  773 }
  774 
  775 FL struct n_string *
  776 (n_string_push_buf)(struct n_string *self, char const *buf, size_t buflen
  777       n_MEMORY_DEBUG_ARGS){
  778    NYD_ENTER;
  779 
  780    assert(self != NULL);
  781    assert(buflen == 0 || buf != NULL);
  782 
  783    if(buflen == UIZ_MAX)
  784       buflen = (buf == NULL) ? 0 : strlen(buf);
  785 
  786    if(buflen > 0){
  787       ui32_t i;
  788 
  789       self = (n_string_reserve)(self, buflen n_MEMORY_DEBUG_ARGSCALL);
  790       memcpy(&self->s_dat[i = self->s_len], buf, buflen);
  791       self->s_len = (i += (ui32_t)buflen);
  792    }
  793    NYD_LEAVE;
  794    return self;
  795 }
  796 
  797 FL struct n_string *
  798 (n_string_push_c)(struct n_string *self, char c n_MEMORY_DEBUG_ARGS){
  799    NYD_ENTER;
  800 
  801    assert(self != NULL);
  802 
  803    if(self->s_len + 1 >= self->s_size)
  804       self = (n_string_reserve)(self, 1 n_MEMORY_DEBUG_ARGSCALL);
  805    self->s_dat[self->s_len++] = c;
  806    NYD_LEAVE;
  807    return self;
  808 }
  809 
  810 FL struct n_string *
  811 (n_string_unshift_buf)(struct n_string *self, char const *buf, size_t buflen
  812       n_MEMORY_DEBUG_ARGS){
  813    NYD_ENTER;
  814 
  815    assert(self != NULL);
  816    assert(buflen == 0 || buf != NULL);
  817 
  818    if(buflen == UIZ_MAX)
  819       buflen = (buf == NULL) ? 0 : strlen(buf);
  820 
  821    if(buflen > 0){
  822       self = (n_string_reserve)(self, buflen n_MEMORY_DEBUG_ARGSCALL);
  823       if(self->s_len > 0)
  824          memmove(&self->s_dat[buflen], self->s_dat, self->s_len);
  825       memcpy(self->s_dat, buf, buflen);
  826       self->s_len += (ui32_t)buflen;
  827    }
  828    NYD_LEAVE;
  829    return self;
  830 }
  831 
  832 FL struct n_string *
  833 (n_string_unshift_c)(struct n_string *self, char c n_MEMORY_DEBUG_ARGS){
  834    NYD_ENTER;
  835 
  836    assert(self != NULL);
  837 
  838    if(self->s_len + 1 >= self->s_size)
  839       self = (n_string_reserve)(self, 1 n_MEMORY_DEBUG_ARGSCALL);
  840    if(self->s_len > 0)
  841       memmove(&self->s_dat[1], self->s_dat, self->s_len);
  842    self->s_dat[0] = c;
  843    ++self->s_len;
  844    NYD_LEAVE;
  845    return self;
  846 }
  847 
  848 FL struct n_string *
  849 (n_string_insert_buf)(struct n_string *self, size_t idx,
  850       char const *buf, size_t buflen n_MEMORY_DEBUG_ARGS){
  851    NYD_ENTER;
  852 
  853    assert(self != NULL);
  854    assert(buflen == 0 || buf != NULL);
  855    assert(idx <= self->s_len);
  856 
  857    if(buflen == UIZ_MAX)
  858       buflen = (buf == NULL) ? 0 : strlen(buf);
  859 
  860    if(buflen > 0){
  861       self = (n_string_reserve)(self, buflen n_MEMORY_DEBUG_ARGSCALL);
  862       if(self->s_len > 0)
  863          memmove(&self->s_dat[idx + buflen], &self->s_dat[idx],
  864             self->s_len - idx);
  865       memcpy(&self->s_dat[idx], buf, buflen);
  866       self->s_len += (ui32_t)buflen;
  867    }
  868    NYD_LEAVE;
  869    return self;
  870 }
  871 
  872 FL struct n_string *
  873 (n_string_insert_c)(struct n_string *self, size_t idx,
  874       char c n_MEMORY_DEBUG_ARGS){
  875    NYD_ENTER;
  876 
  877    assert(self != NULL);
  878    assert(idx <= self->s_len);
  879 
  880    if(self->s_len + 1 >= self->s_size)
  881       self = (n_string_reserve)(self, 1 n_MEMORY_DEBUG_ARGSCALL);
  882    if(self->s_len > 0)
  883       memmove(&self->s_dat[idx + 1], &self->s_dat[idx], self->s_len - idx);
  884    self->s_dat[idx] = c;
  885    ++self->s_len;
  886    NYD_LEAVE;
  887    return self;
  888 }
  889 
  890 FL struct n_string *
  891 n_string_cut(struct n_string *self, size_t idx, size_t len){
  892    NYD_ENTER;
  893 
  894    assert(self != NULL);
  895    assert(UIZ_MAX - idx > len);
  896    assert(SI32_MAX >= idx + len);
  897    assert(idx + len <= self->s_len);
  898 
  899    if(len > 0)
  900       memmove(&self->s_dat[idx], &self->s_dat[idx + len],
  901          (self->s_len -= len) - idx);
  902    NYD_LEAVE;
  903    return self;
  904 }
  905 
  906 FL char *
  907 (n_string_cp)(struct n_string *self n_MEMORY_DEBUG_ARGS){
  908    char *rv;
  909    NYD2_ENTER;
  910 
  911    assert(self != NULL);
  912 
  913    if(self->s_size == 0)
  914       self = (n_string_reserve)(self, 1 n_MEMORY_DEBUG_ARGSCALL);
  915 
  916    (rv = self->s_dat)[self->s_len] = '\0';
  917    NYD2_LEAVE;
  918    return rv;
  919 }
  920 
  921 FL char const *
  922 n_string_cp_const(struct n_string const *self){
  923    char const *rv;
  924    NYD2_ENTER;
  925 
  926    assert(self != NULL);
  927 
  928    if(self->s_size != 0){
  929       ((struct n_string*)n_UNCONST(self))->s_dat[self->s_len] = '\0';
  930       rv = self->s_dat;
  931    }else
  932       rv = n_empty;
  933    NYD2_LEAVE;
  934    return rv;
  935 }
  936 
  937 /*
  938  * UTF-8
  939  */
  940 
  941 FL ui32_t
  942 n_utf8_to_utf32(char const **bdat, size_t *blen){
  943    ui32_t c, x, x1;
  944    char const *cp, *cpx;
  945    size_t l, lx;
  946    NYD2_ENTER;
  947 
  948    lx = l = *blen - 1;
  949    x = (ui8_t)*(cp = *bdat);
  950    cpx = ++cp;
  951 
  952    if(n_LIKELY(x <= 0x7Fu))
  953       c = x;
  954    /* 0xF8, but Unicode guarantees maximum of 0x10FFFFu -> F4 8F BF BF.
  955     * Unicode 9.0, 3.9, UTF-8, Table 3-7. Well-Formed UTF-8 Byte Sequences */
  956    else if(n_LIKELY(x > 0xC0u && x <= 0xF4u)){
  957       if(n_LIKELY(x < 0xE0u)){
  958          if(n_UNLIKELY(l < 1))
  959             goto jenobuf;
  960          --l;
  961 
  962          c = (x &= 0x1Fu);
  963       }else if(n_LIKELY(x < 0xF0u)){
  964          if(n_UNLIKELY(l < 2))
  965             goto jenobuf;
  966          l -= 2;
  967 
  968          x1 = x;
  969          c = (x &= 0x0Fu);
  970 
  971          /* Second byte constraints */
  972          x = (ui8_t)*cp++;
  973          switch(x1){
  974          case 0xE0u:
  975             if(n_UNLIKELY(x < 0xA0u || x > 0xBFu))
  976                goto jerr;
  977             break;
  978          case 0xEDu:
  979             if(n_UNLIKELY(x < 0x80u || x > 0x9Fu))
  980                goto jerr;
  981             break;
  982          default:
  983             if(n_UNLIKELY((x & 0xC0u) != 0x80u))
  984                goto jerr;
  985             break;
  986          }
  987          c <<= 6;
  988          c |= (x &= 0x3Fu);
  989       }else{
  990          if(n_UNLIKELY(l < 3))
  991             goto jenobuf;
  992          l -= 3;
  993 
  994          x1 = x;
  995          c = (x &= 0x07u);
  996 
  997          /* Second byte constraints */
  998          x = (ui8_t)*cp++;
  999          switch(x1){
 1000          case 0xF0u:
 1001             if(n_UNLIKELY(x < 0x90u || x > 0xBFu))
 1002                goto jerr;
 1003             break;
 1004          case 0xF4u:
 1005             if(n_UNLIKELY((x & 0xF0u) != 0x80u)) /* 80..8F */
 1006                goto jerr;
 1007             break;
 1008          default:
 1009             if(n_UNLIKELY((x & 0xC0u) != 0x80u))
 1010                goto jerr;
 1011             break;
 1012          }
 1013          c <<= 6;
 1014          c |= (x &= 0x3Fu);
 1015 
 1016          x = (ui8_t)*cp++;
 1017          if(n_UNLIKELY((x & 0xC0u) != 0x80u))
 1018             goto jerr;
 1019          c <<= 6;
 1020          c |= (x &= 0x3Fu);
 1021       }
 1022 
 1023       x = (ui8_t)*cp++;
 1024       if(n_UNLIKELY((x & 0xC0u) != 0x80u))
 1025          goto jerr;
 1026       c <<= 6;
 1027       c |= x & 0x3Fu;
 1028    }else
 1029       goto jerr;
 1030 
 1031    cpx = cp;
 1032    lx = l;
 1033 jleave:
 1034    *bdat = cpx;
 1035    *blen = lx;
 1036    NYD2_LEAVE;
 1037    return c;
 1038 jenobuf:
 1039 jerr:
 1040    c = UI32_MAX;
 1041    goto jleave;
 1042 }
 1043 
 1044 FL size_t
 1045 n_utf32_to_utf8(ui32_t c, char *buf)
 1046 {
 1047    struct {
 1048       ui32_t   lower_bound;
 1049       ui32_t   upper_bound;
 1050       ui8_t    enc_leader;
 1051       ui8_t    enc_lval;
 1052       ui8_t    dec_leader_mask;
 1053       ui8_t    dec_leader_val_mask;
 1054       ui8_t    dec_bytes_togo;
 1055       ui8_t    cat_index;
 1056       ui8_t    __dummy[2];
 1057    } const _cat[] = {
 1058       {0x00000000, 0x00000000, 0x00, 0, 0x00,      0x00,   0, 0, {0,}},
 1059       {0x00000000, 0x0000007F, 0x00, 1, 0x80,      0x7F, 1-1, 1, {0,}},
 1060       {0x00000080, 0x000007FF, 0xC0, 2, 0xE0, 0xFF-0xE0, 2-1, 2, {0,}},
 1061       /* We assume surrogates are U+D800 - U+DFFF, _cat index 3 */
 1062       /* xxx _from_utf32() simply assumes magic code points for surrogates!
 1063        * xxx (However, should we ever get yet another surrogate range we
 1064        * xxx need to deal with that all over the place anyway? */
 1065       {0x00000800, 0x0000FFFF, 0xE0, 3, 0xF0, 0xFF-0xF0, 3-1, 3, {0,}},
 1066       {0x00010000, 0x0010FFFF, 0xF0, 4, 0xF8, 0xFF-0xF8, 4-1, 4, {0,}},
 1067    }, *catp = _cat;
 1068    size_t l;
 1069 
 1070    if (c <= _cat[0].upper_bound) { catp += 0; goto j0; }
 1071    if (c <= _cat[1].upper_bound) { catp += 1; goto j1; }
 1072    if (c <= _cat[2].upper_bound) { catp += 2; goto j2; }
 1073    if (c <= _cat[3].upper_bound) {
 1074       /* Surrogates may not be converted (Compatibility rule C10) */
 1075       if (c >= 0xD800u && c <= 0xDFFFu)
 1076          goto jerr;
 1077       catp += 3;
 1078       goto j3;
 1079    }
 1080    if (c <= _cat[4].upper_bound) { catp += 4; goto j4; }
 1081 jerr:
 1082    c = 0xFFFDu; /* Unicode replacement character */
 1083    catp += 3;
 1084    goto j3;
 1085 j4:
 1086    buf[3] = (char)0x80u | (char)(c & 0x3Fu); c >>= 6;
 1087 j3:
 1088    buf[2] = (char)0x80u | (char)(c & 0x3Fu); c >>= 6;
 1089 j2:
 1090    buf[1] = (char)0x80u | (char)(c & 0x3Fu); c >>= 6;
 1091 j1:
 1092    buf[0] = (char)catp->enc_leader | (char)(c);
 1093 j0:
 1094    buf[catp->enc_lval] = '\0';
 1095    l = catp->enc_lval;
 1096    NYD2_LEAVE;
 1097    return l;
 1098 }
 1099 
 1100 /*
 1101  * Our iconv(3) wrapper
 1102  */
 1103 
 1104 FL char *
 1105 n_iconv_normalize_name(char const *cset){
 1106    char *cp, c, *tcp, tc;
 1107    bool_t any;
 1108    NYD2_ENTER;
 1109 
 1110    /* We need to strip //SUFFIXes off, we want to normalize to all lowercase,
 1111     * and we perform some slight content testing, too */
 1112    for(any = FAL0, cp = n_UNCONST(cset); (c = *cp) != '\0'; ++cp){
 1113       if(!alnumchar(c) && !punctchar(c)){
 1114          n_err(_("Invalid character set name %s\n"),
 1115             n_shexp_quote_cp(cset, FAL0));
 1116          cset = NULL;
 1117          goto jleave;
 1118       }else if(c == '/')
 1119          break;
 1120       else if(upperchar(c))
 1121          any = TRU1;
 1122    }
 1123 
 1124    if(any || c != '\0'){
 1125       cp = savestrbuf(cset, PTR2SIZE(cp - cset));
 1126       for(tcp = cp; (tc = *tcp) != '\0'; ++tcp)
 1127          *tcp = lowerconv(tc);
 1128 
 1129       if(c != '\0' && (n_poption & n_PO_D_V))
 1130          n_err(_("Stripped off character set suffix: %s -> %s\n"),
 1131             n_shexp_quote_cp(cset, FAL0), n_shexp_quote_cp(cp, FAL0));
 1132 
 1133       cset = cp;
 1134    }
 1135 jleave:
 1136    NYD2_LEAVE;
 1137    return n_UNCONST(cset);
 1138 }
 1139 
 1140 FL bool_t
 1141 n_iconv_name_is_ascii(char const *cset){ /* TODO ctext/su */
 1142    bool_t rv;
 1143    NYD2_ENTER;
 1144 
 1145    /* In MIME preference order */
 1146    rv = (!asccasecmp(cset, "US-ASCII") || !asccasecmp(cset, "ASCII") ||
 1147          !asccasecmp(cset, "ANSI_X3.4-1968") ||
 1148          !asccasecmp(cset, "iso-ir-6") ||
 1149          !asccasecmp(cset, "ANSI_X3.4-1986") ||
 1150          !asccasecmp(cset, "ISO_646.irv:1991") ||
 1151          !asccasecmp(cset, "ISO646-US") || !asccasecmp(cset, "us") ||
 1152          !asccasecmp(cset, "IBM367") || !asccasecmp(cset, "cp367") ||
 1153          !asccasecmp(cset, "csASCII"));
 1154    NYD2_LEAVE;
 1155    return rv;
 1156 }
 1157 
 1158 #ifdef HAVE_ICONV
 1159 FL iconv_t
 1160 n_iconv_open(char const *tocode, char const *fromcode){
 1161    iconv_t id;
 1162    NYD_ENTER;
 1163 
 1164    if((!asccasecmp(fromcode, "unknown-8bit") ||
 1165             !asccasecmp(fromcode, "binary")) &&
 1166          (fromcode = ok_vlook(charset_unknown_8bit)) == NULL)
 1167       fromcode = ok_vlook(CHARSET_8BIT_OKEY);
 1168 
 1169    id = iconv_open(tocode, fromcode);
 1170 
 1171    /* If the encoding names are equal at this point, they are just not
 1172     * understood by iconv(), and we cannot sensibly use it in any way.  We do
 1173     * not perform this as an optimization above since iconv() can otherwise be
 1174     * used to check the validity of the input even with identical encoding
 1175     * names */
 1176    if (id == (iconv_t)-1 && !asccasecmp(tocode, fromcode))
 1177       n_err_no = n_ERR_NONE;
 1178    NYD_LEAVE;
 1179    return id;
 1180 }
 1181 
 1182 FL void
 1183 n_iconv_close(iconv_t cd){
 1184    NYD_ENTER;
 1185    iconv_close(cd);
 1186    if(cd == iconvd)
 1187       iconvd = (iconv_t)-1;
 1188    NYD_LEAVE;
 1189 }
 1190 
 1191 FL void
 1192 n_iconv_reset(iconv_t cd){
 1193    NYD_ENTER;
 1194    iconv(cd, NULL, NULL, NULL, NULL);
 1195    NYD_LEAVE;
 1196 }
 1197 
 1198 /* (2012-09-24: export and use it exclusively to isolate prototype problems
 1199  * (*inb* is 'char const **' except in POSIX) in a single place.
 1200  * GNU libiconv even allows for configuration time const/non-const..
 1201  * In the end it's an ugly guess, but we can't do better since make(1) doesn't
 1202  * support compiler invocations which bail on error, so no -Werror */
 1203 /* Citrus project? */
 1204 # if defined _ICONV_H_ && defined __ICONV_F_HIDE_INVALID
 1205   /* DragonFly 3.2.1 is special TODO newer DragonFly too, but different */
 1206 #  if n_OS_DRAGONFLY
 1207 #   define __INBCAST(S) (char ** __restrict__)n_UNCONST(S)
 1208 #  else
 1209 #   define __INBCAST(S) (char const **)n_UNCONST(S)
 1210 #  endif
 1211 # elif n_OS_SUNOS || n_OS_SOLARIS
 1212 #  define __INBCAST(S) (char const ** __restrict__)n_UNCONST(S)
 1213 # endif
 1214 # ifndef __INBCAST
 1215 #  define __INBCAST(S)  (char **)n_UNCONST(S)
 1216 # endif
 1217 
 1218 FL int
 1219 n_iconv_buf(iconv_t cd, enum n_iconv_flags icf,
 1220    char const **inb, size_t *inbleft, char **outb, size_t *outbleft){
 1221    int err;
 1222    NYD2_ENTER;
 1223 
 1224    if((icf & n_ICONV_UNIREPL) && !(n_psonce & n_PSO_UNICODE))
 1225       icf &= ~n_ICONV_UNIREPL;
 1226 
 1227    for(;;){
 1228       size_t sz;
 1229 
 1230       if((sz = iconv(cd, __INBCAST(inb), inbleft, outb, outbleft)) == 0)
 1231          break;
 1232       if(sz != (size_t)-1){
 1233          if(!(icf & n_ICONV_IGN_NOREVERSE)){
 1234             err = n_ERR_NOENT;
 1235             goto jleave;
 1236          }
 1237          break;
 1238       }
 1239 
 1240       if((err = n_err_no) == n_ERR_2BIG)
 1241          goto jleave;
 1242 
 1243       if(!(icf & n_ICONV_IGN_ILSEQ) || err != n_ERR_ILSEQ)
 1244          goto jleave;
 1245       if(*inbleft > 0){
 1246          ++(*inb);
 1247          --(*inbleft);
 1248          if(icf & n_ICONV_UNIREPL){
 1249             if(*outbleft >= sizeof(n_unirepl) -1){
 1250                memcpy(*outb, n_unirepl, sizeof(n_unirepl) -1);
 1251                *outb += sizeof(n_unirepl) -1;
 1252                *outbleft -= sizeof(n_unirepl) -1;
 1253                continue;
 1254             }
 1255          }else if(*outbleft > 0){
 1256             *(*outb)++ = '?';
 1257             --*outbleft;
 1258             continue;
 1259          }
 1260          err = n_ERR_2BIG;
 1261          goto jleave;
 1262       }else if(*outbleft > 0){
 1263          **outb = '\0';
 1264          goto jleave;
 1265       }
 1266    }
 1267    err = 0;
 1268 jleave:
 1269    n_iconv_err_no = err;
 1270    NYD2_LEAVE;
 1271    return err;
 1272 }
 1273 # undef __INBCAST
 1274 
 1275 FL int
 1276 n_iconv_str(iconv_t cd, enum n_iconv_flags icf,
 1277       struct str *out, struct str const *in, struct str *in_rest_or_null){
 1278    struct n_string s, *sp = &s;
 1279    char const *ib;
 1280    int err;
 1281    size_t il;
 1282    NYD2_ENTER;
 1283 
 1284    il = in->l;
 1285    if(!n_string_get_can_book(il) || !n_string_get_can_book(out->l)){
 1286       err = n_ERR_INVAL;
 1287       goto j_leave;
 1288    }
 1289    ib = in->s;
 1290 
 1291    sp = n_string_creat(sp);
 1292    sp = n_string_take_ownership(sp, out->s, out->l, 0);
 1293 
 1294    for(;;){
 1295       char *ob_base, *ob;
 1296       size_t ol, nol;
 1297 
 1298       if((nol = ol = sp->s_len) < il)
 1299          nol = il;
 1300       assert(sizeof(sp->s_len) == sizeof(ui32_t));
 1301       if(nol < 128)
 1302          nol += 32;
 1303       else{
 1304          ui64_t xnol;
 1305 
 1306          xnol = (ui64_t)(nol << 1) - (nol >> 4);
 1307          if(!n_string_can_book(sp, xnol)){
 1308             xnol = ol + 64;
 1309             if(!n_string_can_book(sp, xnol)){
 1310                err = n_ERR_INVAL;
 1311                goto jleave;
 1312             }
 1313          }
 1314          nol = (size_t)xnol;
 1315       }
 1316       sp = n_string_resize(sp, nol);
 1317 
 1318       ob = ob_base = &sp->s_dat[ol];
 1319       nol -= ol;
 1320       err = n_iconv_buf(cd, icf, &ib, &il, &ob, &nol);
 1321 
 1322       sp = n_string_trunc(sp, ol + PTR2SIZE(ob - ob_base));
 1323       if(err == 0 || err != n_ERR_2BIG)
 1324          break;
 1325    }
 1326 
 1327    if(in_rest_or_null != NULL){
 1328       in_rest_or_null->s = n_UNCONST(ib);
 1329       in_rest_or_null->l = il;
 1330    }
 1331 
 1332 jleave:
 1333    out->s = n_string_cp(sp);
 1334    out->l = sp->s_len;
 1335    sp = n_string_drop_ownership(sp);
 1336    /* n_string_gut(sp)*/
 1337 j_leave:
 1338    NYD2_LEAVE;
 1339    return err;
 1340 }
 1341 
 1342 FL char *
 1343 n_iconv_onetime_cp(enum n_iconv_flags icf,
 1344       char const *tocode, char const *fromcode, char const *input){
 1345    struct str out, in;
 1346    iconv_t icd;
 1347    char *rv;
 1348    NYD2_ENTER;
 1349 
 1350    rv = NULL;
 1351    if(tocode == NULL)
 1352       tocode = ok_vlook(ttycharset);
 1353    if(fromcode == NULL)
 1354       fromcode = "utf-8";
 1355 
 1356    if((icd = iconv_open(tocode, fromcode)) == (iconv_t)-1)
 1357       goto jleave;
 1358 
 1359    in.l = strlen(in.s = n_UNCONST(input)); /* logical */
 1360    out.s = NULL, out.l = 0;
 1361    if(!n_iconv_str(icd, icf, &out, &in, NULL))
 1362       rv = savestrbuf(out.s, out.l);
 1363    if(out.s != NULL)
 1364       n_free(out.s);
 1365 
 1366    iconv_close(icd);
 1367 jleave:
 1368    NYD2_LEAVE;
 1369    return rv;
 1370 }
 1371 #endif /* HAVE_ICONV */
 1372 
 1373 /* s-it-mode */