"Fossies" - the Fresh Open Source Software Archive

Member "s-nail-14.9.11/cmd-misc.c" (8 Aug 2018, 17322 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 "cmd-misc.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  *@ Miscellaneous user commands, like `echo', `pwd', etc.
    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 cmd_misc
   38 
   39 #ifndef HAVE_AMALGAMATION
   40 # include "nail.h"
   41 #endif
   42 
   43 #include <sys/utsname.h>
   44 
   45 /* Expand the shell escape by expanding unescaped !'s into the last issued
   46  * command where possible */
   47 static char const *a_cmisc_bangexp(char const *cp);
   48 
   49 /* c_n?echo(), c_n?echoerr() */
   50 static int a_cmisc_echo(void *vp, FILE *fp, bool_t donl);
   51 
   52 /* c_read() */
   53 static bool_t a_cmisc_read_set(char const *cp, char const *value);
   54 
   55 /* c_version() */
   56 static int a_cmisc_version_cmp(void const *s1, void const *s2);
   57 
   58 static char const *
   59 a_cmisc_bangexp(char const *cp){
   60    static struct str last_bang;
   61 
   62    struct n_string xbang, *bang;
   63    char c;
   64    bool_t changed;
   65    NYD_ENTER;
   66 
   67    if(!ok_blook(bang))
   68       goto jleave;
   69 
   70    changed = FAL0;
   71 
   72    for(bang = n_string_creat(&xbang); (c = *cp++) != '\0';){
   73       if(c == '!'){
   74          if(last_bang.l > 0)
   75             bang = n_string_push_buf(bang, last_bang.s, last_bang.l);
   76          changed = TRU1;
   77       }else{
   78          if(c == '\\' && *cp == '!'){
   79             ++cp;
   80             c = '!';
   81             changed = TRU1;
   82          }
   83          bang = n_string_push_c(bang, c);
   84       }
   85    }
   86 
   87    if(last_bang.s != NULL)
   88       n_free(last_bang.s);
   89    last_bang.s = n_string_cp(bang);
   90    last_bang.l = bang->s_len;
   91    bang = n_string_drop_ownership(bang);
   92    n_string_gut(bang);
   93 
   94    cp = last_bang.s;
   95    if(changed)
   96       fprintf(n_stdout, "!%s\n", cp);
   97 jleave:
   98    NYD_LEAVE;
   99    return cp;
  100 }
  101 
  102 static int
  103 a_cmisc_echo(void *vp, FILE *fp, bool_t donl){
  104    struct n_string s, *sp;
  105    int rv;
  106    bool_t doerr;
  107    char const **argv, *varname, **ap, *cp;
  108    NYD2_ENTER;
  109 
  110    argv = vp;
  111    varname = (n_pstate & n_PS_ARGMOD_VPUT) ? *argv++ : NULL;
  112    sp = n_string_reserve(n_string_creat_auto(&s), 121/* XXX */);
  113 #ifdef HAVE_ERRORS
  114    doerr = (fp == n_stderr &&  (n_psonce & n_PSO_INTERACTIVE));
  115 #else
  116    doerr = FAL0;
  117 #endif
  118 
  119    for(ap = argv; *ap != NULL; ++ap){
  120       if(ap != argv)
  121          sp = n_string_push_c(sp, ' ');
  122       if((cp = fexpand(*ap, FEXP_NSHORTCUT | FEXP_NVAR)) == NULL)
  123          cp = *ap;
  124       sp = n_string_push_cp(sp, cp);
  125    }
  126    if(donl)
  127       sp = n_string_push_c(sp, '\n');
  128    cp = n_string_cp(sp);
  129 
  130    if(varname == NULL){
  131       si32_t e;
  132 
  133       e = n_ERR_NONE;
  134       if(doerr){
  135          /* xxx Ensure *log-prefix* will be placed by n_err() for next msg */
  136          if(donl)
  137             cp = n_string_cp(n_string_trunc(sp, sp->s_len - 1));
  138          n_err((donl ? "%s\n" : "%s"), cp);
  139       }else if(fputs(cp, fp) == EOF)
  140          e = n_err_no;
  141       if((rv = (fflush(fp) == EOF)))
  142          e = n_err_no;
  143       rv |= ferror(fp) ? 1 : 0;
  144       n_pstate_err_no = e;
  145    }else if(!n_var_vset(varname, (uintptr_t)cp)){
  146       n_pstate_err_no = n_ERR_NOTSUP;
  147       rv = -1;
  148    }else{
  149       n_pstate_err_no = n_ERR_NONE;
  150       rv = (int)sp->s_len;
  151    }
  152    NYD2_LEAVE;
  153    return rv;
  154 }
  155 
  156 static bool_t
  157 a_cmisc_read_set(char const *cp, char const *value){
  158    bool_t rv;
  159    NYD2_ENTER;
  160 
  161    if(!n_shexp_is_valid_varname(cp))
  162       value = N_("not a valid variable name");
  163    else if(!n_var_is_user_writable(cp))
  164       value = N_("variable is read-only");
  165    else if(!n_var_vset(cp, (uintptr_t)value))
  166       value = N_("failed to update variable value");
  167    else{
  168       rv = TRU1;
  169       goto jleave;
  170    }
  171    n_err("`read': %s: %s\n", V_(value), n_shexp_quote_cp(cp, FAL0));
  172    rv = FAL0;
  173 jleave:
  174    NYD2_LEAVE;
  175    return rv;
  176 }
  177 
  178 static int
  179 a_cmisc_version_cmp(void const *s1, void const *s2){
  180    char const * const *cp1, * const *cp2;
  181    int rv;
  182    NYD2_ENTER;
  183 
  184    cp1 = s1;
  185    cp2 = s2;
  186    rv = strcmp(&(*cp1)[1], &(*cp2)[1]);
  187    NYD2_LEAVE;
  188    return rv;
  189 }
  190 
  191 FL int
  192 c_sleep(void *v){
  193    uiz_t sec, msec;
  194    char **argv;
  195    NYD_ENTER;
  196 
  197    argv = v;
  198 
  199    if((n_idec_uiz_cp(&sec, argv[0], 0, NULL) &
  200          (n_IDEC_STATE_EMASK | n_IDEC_STATE_CONSUMED)
  201          ) != n_IDEC_STATE_CONSUMED)
  202       goto jesyn;
  203 
  204    if(argv[1] == NULL)
  205       msec = 0;
  206    else if((n_idec_uiz_cp(&msec, argv[1], 0, NULL) &
  207          (n_IDEC_STATE_EMASK | n_IDEC_STATE_CONSUMED)
  208          ) != n_IDEC_STATE_CONSUMED)
  209       goto jesyn;
  210 
  211    if(UIZ_MAX / n_DATE_MILLISSEC < sec)
  212       goto jeover;
  213    sec *= n_DATE_MILLISSEC;
  214 
  215    if(UIZ_MAX - sec < msec)
  216       goto jeover;
  217    msec += sec;
  218 
  219    n_pstate_err_no = (n_msleep(msec, (argv[2] == NULL)) > 0)
  220          ? n_ERR_INTR : n_ERR_NONE;
  221 jleave:
  222    NYD_LEAVE;
  223    return (argv == NULL);
  224 jeover:
  225    n_err(_("`sleep': argument(s) overflow(s) datatype\n"));
  226    n_pstate_err_no = n_ERR_OVERFLOW;
  227    argv = NULL;
  228    goto jleave;
  229 jesyn:
  230    n_err(_("Synopsis: sleep: <seconds> [<milliseconds>] [uninterruptible]\n"));
  231    n_pstate_err_no = n_ERR_INVAL;
  232    argv = NULL;
  233    goto jleave;
  234 }
  235 
  236 FL int
  237 c_shell(void *v)
  238 {
  239    sigset_t mask;
  240    int rv;
  241    FILE *fp;
  242    char const **argv, *varname, *varres, *cp;
  243    NYD_ENTER;
  244 
  245    n_pstate_err_no = n_ERR_NONE;
  246    argv = v;
  247    varname = (n_pstate & n_PS_ARGMOD_VPUT) ? *argv++ : NULL;
  248    varres = n_empty;
  249    fp = NULL;
  250 
  251    if(varname != NULL &&
  252          (fp = Ftmp(NULL, "shell", OF_RDWR | OF_UNLINK | OF_REGISTER)
  253             ) == NULL){
  254       n_pstate_err_no = n_ERR_CANCELED;
  255       rv = -1;
  256    }else{
  257       cp = a_cmisc_bangexp(*argv);
  258 
  259       sigemptyset(&mask);
  260       if(n_child_run(ok_vlook(SHELL), &mask,
  261             n_CHILD_FD_PASS, (fp != NULL ? fileno(fp) : n_CHILD_FD_PASS),
  262             "-c", cp, NULL, NULL, &rv) < 0){
  263          n_pstate_err_no = n_err_no;
  264          rv = -1;
  265       }else{
  266          rv = WEXITSTATUS(rv);
  267 
  268          if(fp != NULL){
  269             int c;
  270             char *x;
  271             off_t l;
  272 
  273             fflush_rewind(fp);
  274             l = fsize(fp);
  275             if(UICMP(64, l, >=, UIZ_MAX -42)){
  276                n_pstate_err_no = n_ERR_NOMEM;
  277                varres = n_empty;
  278             }else{
  279                varres = x = n_autorec_alloc(l +1);
  280 
  281                for(; l > 0 && (c = getc(fp)) != EOF; --l)
  282                   *x++ = c;
  283                *x++ = '\0';
  284                if(l != 0){
  285                   n_pstate_err_no = n_err_no;
  286                   varres = n_empty; /* xxx hmmm */
  287                }
  288             }
  289          }
  290       }
  291    }
  292 
  293    if(fp != NULL)
  294       Fclose(fp);
  295 
  296    if(varname != NULL){
  297       if(!n_var_vset(varname, (uintptr_t)varres)){
  298          n_pstate_err_no = n_ERR_NOTSUP;
  299          rv = -1;
  300       }
  301    }else if(rv >= 0 && (n_psonce & n_PSO_INTERACTIVE)){
  302       fprintf(n_stdout, "!\n");
  303       /* Line buffered fflush(n_stdout); */
  304    }
  305    NYD_LEAVE;
  306    return rv;
  307 }
  308 
  309 FL int
  310 c_dosh(void *v)
  311 {
  312    int rv;
  313    NYD_ENTER;
  314    n_UNUSED(v);
  315 
  316    if(n_child_run(ok_vlook(SHELL), 0, n_CHILD_FD_PASS, n_CHILD_FD_PASS, NULL,
  317          NULL, NULL, NULL, &rv) < 0){
  318       n_pstate_err_no = n_err_no;
  319       rv = -1;
  320    }else{
  321       putc('\n', n_stdout);
  322       /* Line buffered fflush(n_stdout); */
  323       n_pstate_err_no = n_ERR_NONE;
  324       rv = WEXITSTATUS(rv);
  325    }
  326    NYD_LEAVE;
  327    return rv;
  328 }
  329 
  330 FL int
  331 c_cwd(void *v){
  332    struct n_string s_b, *sp;
  333    size_t l;
  334    char const *varname;
  335    NYD_ENTER;
  336 
  337    sp = n_string_creat_auto(&s_b);
  338    varname = (n_pstate & n_PS_ARGMOD_VPUT) ? *(char const**)v : NULL;
  339    l = PATH_MAX;
  340 
  341    for(;; l += PATH_MAX){
  342       sp = n_string_resize(n_string_trunc(sp, 0), l);
  343 
  344       if(getcwd(sp->s_dat, sp->s_len) == NULL){
  345          int e;
  346 
  347          e = n_err_no;
  348          if(e == n_ERR_RANGE)
  349             continue;
  350          n_perr(_("Failed to getcwd(3)"), e);
  351          v = NULL;
  352          break;
  353       }
  354 
  355       if(varname != NULL){
  356          if(!n_var_vset(varname, (uintptr_t)sp->s_dat))
  357             v = NULL;
  358       }else{
  359          l = strlen(sp->s_dat);
  360          sp = n_string_trunc(sp, l);
  361          if(fwrite(sp->s_dat, 1, sp->s_len, n_stdout) == sp->s_len &&
  362                putc('\n', n_stdout) == EOF)
  363             v = NULL;
  364       }
  365       break;
  366    }
  367    NYD_LEAVE;
  368    return (v == NULL);
  369 }
  370 
  371 FL int
  372 c_chdir(void *v)
  373 {
  374    char **arglist = v;
  375    char const *cp;
  376    NYD_ENTER;
  377 
  378    if (*arglist == NULL)
  379       cp = ok_vlook(HOME);
  380    else if ((cp = fexpand(*arglist, FEXP_LOCAL | FEXP_NOPROTO)) == NULL)
  381       goto jleave;
  382    if (chdir(cp) == -1) {
  383       n_perr(cp, 0);
  384       cp = NULL;
  385    }
  386 jleave:
  387    NYD_LEAVE;
  388    return (cp == NULL);
  389 }
  390 
  391 FL int
  392 c_echo(void *v){
  393    int rv;
  394    NYD_ENTER;
  395 
  396    rv = a_cmisc_echo(v, n_stdout, TRU1);
  397    NYD_LEAVE;
  398    return rv;
  399 }
  400 
  401 FL int
  402 c_echoerr(void *v){
  403    int rv;
  404    NYD_ENTER;
  405 
  406    rv = a_cmisc_echo(v, n_stderr, TRU1);
  407    NYD_LEAVE;
  408    return rv;
  409 }
  410 
  411 FL int
  412 c_echon(void *v){
  413    int rv;
  414    NYD_ENTER;
  415 
  416    rv = a_cmisc_echo(v, n_stdout, FAL0);
  417    NYD_LEAVE;
  418    return rv;
  419 }
  420 
  421 FL int
  422 c_echoerrn(void *v){
  423    int rv;
  424    NYD_ENTER;
  425 
  426    rv = a_cmisc_echo(v, n_stderr, FAL0);
  427    NYD_LEAVE;
  428    return rv;
  429 }
  430 
  431 FL int
  432 c_read(void * volatile vp){
  433    struct n_sigman sm;
  434    struct str trim;
  435    struct n_string s, *sp;
  436    char *linebuf;
  437    size_t linesize, i;
  438    int rv;
  439    char const *ifs, **argv, *cp;
  440    NYD2_ENTER;
  441 
  442    sp = n_string_creat_auto(&s);
  443    sp = n_string_reserve(sp, 64 -1);
  444 
  445    ifs = ok_vlook(ifs);
  446    linesize = 0;
  447    linebuf = NULL;
  448    argv = vp;
  449 
  450    n_SIGMAN_ENTER_SWITCH(&sm, n_SIGMAN_ALL){
  451    case 0:
  452       break;
  453    default:
  454       n_pstate_err_no = n_ERR_INTR;
  455       rv = -1;
  456       goto jleave;
  457    }
  458 
  459    n_pstate_err_no = n_ERR_NONE;
  460    rv = n_go_input(((n_pstate & n_PS_COMPOSE_MODE
  461             ? n_GO_INPUT_CTX_COMPOSE : n_GO_INPUT_CTX_DEFAULT) |
  462          n_GO_INPUT_FORCE_STDIN | n_GO_INPUT_NL_ESC |
  463          n_GO_INPUT_PROMPT_NONE /* XXX POSIX: PS2: yes! */),
  464          NULL, &linebuf, &linesize, NULL, NULL);
  465    if(rv < 0){
  466       if(!n_go_input_is_eof())
  467          n_pstate_err_no = n_ERR_BADF;
  468       goto jleave;
  469    }else if(rv == 0){
  470       if(n_go_input_is_eof()){
  471          rv = -1;
  472          goto jleave;
  473       }
  474    }else{
  475       trim.s = linebuf;
  476       trim.l = rv;
  477 
  478       for(; *argv != NULL; ++argv){
  479          if(trim.l == 0 || n_str_trim_ifs(&trim, FAL0)->l == 0)
  480             break;
  481 
  482          /* The last variable gets the remaining line less trailing IFS-WS */
  483          if(argv[1] == NULL){
  484 jitall:
  485             sp = n_string_assign_buf(sp, trim.s, trim.l);
  486             trim.l = 0;
  487          }else for(cp = trim.s, i = 1;; ++cp, ++i){
  488             if(strchr(ifs, *cp) != NULL){
  489                sp = n_string_assign_buf(sp, trim.s, i - 1);
  490                trim.s += i;
  491                trim.l -= i;
  492                break;
  493             }
  494             if(i == trim.l)
  495                goto jitall;
  496          }
  497 
  498          if(!a_cmisc_read_set(*argv, n_string_cp(sp))){
  499             n_pstate_err_no = n_ERR_NOTSUP;
  500             rv = -1;
  501             break;
  502          }
  503       }
  504    }
  505 
  506    /* Set the remains to the empty string */
  507    for(; *argv != NULL; ++argv)
  508       if(!a_cmisc_read_set(*argv, n_empty)){
  509          n_pstate_err_no = n_ERR_NOTSUP;
  510          rv = -1;
  511          break;
  512       }
  513 
  514    n_sigman_cleanup_ping(&sm);
  515 jleave:
  516    if(linebuf != NULL)
  517       n_free(linebuf);
  518    NYD2_LEAVE;
  519    n_sigman_leave(&sm, n_SIGMAN_VIPSIGS_NTTYOUT);
  520    return rv;
  521 }
  522 
  523 FL int
  524 c_readall(void * vp){ /* TODO 64-bit retval */
  525    struct n_sigman sm;
  526    struct n_string s, *sp;
  527    char *linebuf;
  528    size_t linesize;
  529    int rv;
  530    char const **argv;
  531    NYD2_ENTER;
  532 
  533    sp = n_string_creat_auto(&s);
  534    sp = n_string_reserve(sp, 64 -1);
  535 
  536    linesize = 0;
  537    linebuf = NULL;
  538    argv = vp;
  539 
  540    n_SIGMAN_ENTER_SWITCH(&sm, n_SIGMAN_ALL){
  541    case 0:
  542       break;
  543    default:
  544       n_pstate_err_no = n_ERR_INTR;
  545       rv = -1;
  546       goto jleave;
  547    }
  548 
  549    n_pstate_err_no = n_ERR_NONE;
  550 
  551    for(;;){
  552       rv = n_go_input(((n_pstate & n_PS_COMPOSE_MODE
  553                ? n_GO_INPUT_CTX_COMPOSE : n_GO_INPUT_CTX_DEFAULT) |
  554             n_GO_INPUT_FORCE_STDIN | /*n_GO_INPUT_NL_ESC |*/
  555             n_GO_INPUT_PROMPT_NONE),
  556             NULL, &linebuf, &linesize, NULL, NULL);
  557       if(rv < 0){
  558          if(!n_go_input_is_eof()){
  559             n_pstate_err_no = n_ERR_BADF;
  560             goto jleave;
  561          }
  562          if(sp->s_len == 0)
  563             goto jleave;
  564          break;
  565       }
  566 
  567       if(n_pstate & n_PS_READLINE_NL)
  568          linebuf[rv++] = '\n'; /* Replace NUL with it */
  569 
  570       if(n_UNLIKELY(rv == 0)){ /* xxx will not get*/
  571          if(n_go_input_is_eof()){
  572             if(sp->s_len == 0){
  573                rv = -1;
  574                goto jleave;
  575             }
  576             break;
  577          }
  578       }else if(n_LIKELY(UICMP(32, SI32_MAX - sp->s_len, >, rv)))
  579          sp = n_string_push_buf(sp, linebuf, rv);
  580       else{
  581          n_pstate_err_no = n_ERR_OVERFLOW;
  582          rv = -1;
  583          goto jleave;
  584       }
  585    }
  586 
  587    if(!a_cmisc_read_set(argv[0], n_string_cp(sp))){
  588       n_pstate_err_no = n_ERR_NOTSUP;
  589       rv = -1;
  590       goto jleave;
  591    }
  592    rv = sp->s_len;
  593 
  594    n_sigman_cleanup_ping(&sm);
  595 jleave:
  596    if(linebuf != NULL)
  597       n_free(linebuf);
  598    NYD2_LEAVE;
  599    n_sigman_leave(&sm, n_SIGMAN_VIPSIGS_NTTYOUT);
  600    return rv;
  601 }
  602 
  603 FL int
  604 c_version(void *vp){
  605    struct utsname ut;
  606    struct n_string s, *sp = &s;
  607    int rv;
  608    char *iop;
  609    char const *cp, **arr;
  610    size_t i, lnlen, j;
  611    NYD_ENTER;
  612 
  613    sp = n_string_creat_auto(sp);
  614    sp = n_string_book(sp, 1024);
  615 
  616    /* First two lines */
  617    sp = n_string_push_cp(sp, n_uagent);
  618    sp = n_string_push_c(sp, ' ');
  619    sp = n_string_push_cp(sp, ok_vlook(version));
  620    sp = n_string_push_c(sp, ',');
  621    sp = n_string_push_c(sp, ' ');
  622    sp = n_string_push_cp(sp, ok_vlook(version_date));
  623    sp = n_string_push_c(sp, ' ');
  624    sp = n_string_push_c(sp, '(');
  625    sp = n_string_push_cp(sp, _("build for "));
  626    sp = n_string_push_cp(sp, ok_vlook(build_os));
  627    sp = n_string_push_c(sp, ')');
  628    sp = n_string_push_cp(sp, _("\nFeatures included (+) or not (-):\n"));
  629 
  630    /* Some lines with the features.
  631     * *features* starts with dummy byte to avoid + -> *folder* expansions */
  632    i = strlen(cp = &ok_vlook(features)[1]) +1;
  633    iop = n_autorec_alloc(i);
  634    memcpy(iop, cp, i);
  635 
  636    arr = n_autorec_alloc(sizeof(cp) * VAL_FEATURES_CNT);
  637    for(i = 0; (cp = n_strsep(&iop, ',', TRU1)) != NULL; ++i)
  638       arr[i] = cp;
  639    qsort(arr, i, sizeof(cp), &a_cmisc_version_cmp);
  640 
  641    for(lnlen = 0; i-- > 0;){
  642       cp = *(arr++);
  643       j = strlen(cp);
  644 
  645       if((lnlen += j + 1) > 72){
  646          sp = n_string_push_c(sp, '\n');
  647          lnlen = j + 1;
  648       }
  649       sp = n_string_push_c(sp, ' ');
  650       sp = n_string_push_buf(sp, cp, j);
  651    }
  652    sp = n_string_push_c(sp, '\n');
  653 
  654    /* */
  655    if(n_poption & n_PO_VERB){
  656       sp = n_string_push_cp(sp, "Compile: ");
  657       sp = n_string_push_cp(sp, ok_vlook(build_cc));
  658       sp = n_string_push_cp(sp, "\nLink: ");
  659       sp = n_string_push_cp(sp, ok_vlook(build_ld));
  660       if(*(cp = ok_vlook(build_rest)) != '\0'){
  661          sp = n_string_push_cp(sp, "\nRest: ");
  662          sp = n_string_push_cp(sp, cp);
  663       }
  664       sp = n_string_push_c(sp, '\n');
  665 
  666       /* A trailing line with info of the running machine */
  667       uname(&ut);
  668       sp = n_string_push_c(sp, '@');
  669       sp = n_string_push_cp(sp, ut.sysname);
  670       sp = n_string_push_c(sp, ' ');
  671       sp = n_string_push_cp(sp, ut.release);
  672       sp = n_string_push_c(sp, ' ');
  673       sp = n_string_push_cp(sp, ut.version);
  674       sp = n_string_push_c(sp, ' ');
  675       sp = n_string_push_cp(sp, ut.machine);
  676       sp = n_string_push_c(sp, '\n');
  677    }
  678 
  679    /* Done */
  680    cp = n_string_cp(sp);
  681 
  682    if(n_pstate & n_PS_ARGMOD_VPUT){
  683       if(n_var_vset(*(char const**)vp, (uintptr_t)cp))
  684          rv = 0;
  685       else
  686          rv = -1;
  687    }else{
  688       if(fputs(cp, n_stdout) != EOF)
  689          rv = 0;
  690       else{
  691          clearerr(n_stdout);
  692          rv = 1;
  693       }
  694    }
  695    NYD_LEAVE;
  696    return rv;
  697 }
  698 
  699 /* s-it-mode */