cmd3.c revision 302968
11590Srgrimes/* 21590Srgrimes * Copyright (c) 1980, 1993 31590Srgrimes * The Regents of the University of California. All rights reserved. 41590Srgrimes * 51590Srgrimes * Redistribution and use in source and binary forms, with or without 61590Srgrimes * modification, are permitted provided that the following conditions 71590Srgrimes * are met: 81590Srgrimes * 1. Redistributions of source code must retain the above copyright 91590Srgrimes * notice, this list of conditions and the following disclaimer. 101590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111590Srgrimes * notice, this list of conditions and the following disclaimer in the 121590Srgrimes * documentation and/or other materials provided with the distribution. 131590Srgrimes * 4. Neither the name of the University nor the names of its contributors 141590Srgrimes * may be used to endorse or promote products derived from this software 151590Srgrimes * without specific prior written permission. 161590Srgrimes * 171590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 181590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 191590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 201590Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 211590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 221590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 231590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 241590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 251590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 261590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 271590Srgrimes * SUCH DAMAGE. 281590Srgrimes */ 291590Srgrimes 3087701Smarkm#ifndef lint 3187701Smarkm#if 0 3287701Smarkmstatic char sccsid[] = "@(#)cmd3.c 8.2 (Berkeley) 4/20/95"; 3387701Smarkm#endif 341590Srgrimes#endif /* not lint */ 3528370Scharnier#include <sys/cdefs.h> 361590Srgrimes__FBSDID("$FreeBSD: stable/10/usr.bin/mail/cmd3.c 302968 2016-07-17 18:32:33Z pfg $"); 371590Srgrimes 3887701Smarkm#include "rcv.h" 391590Srgrimes#include "extern.h" 401590Srgrimes 4187701Smarkm/* 4228370Scharnier * Mail -- a mail program 431590Srgrimes * 441590Srgrimes * Still more user commands. 451590Srgrimes */ 4687701Smarkm 4728370Scharnier/* 4828370Scharnier * Process a shell escape by saving signals, ignoring signals, 4928370Scharnier * and forking a sh -c 501590Srgrimes */ 511590Srgrimesint 52200419Sdelphijshell(char *str) 5387701Smarkm{ 5428370Scharnier sig_t sigint = signal(SIGINT, SIG_IGN); 5587701Smarkm char *sh; 561590Srgrimes char cmd[BUFSIZ]; 571590Srgrimes 5892922Simp if (strlcpy(cmd, str, sizeof(cmd)) >= sizeof(cmd)) 5992922Simp return (1); 6092922Simp if (bangexp(cmd, sizeof(cmd)) < 0) 611590Srgrimes return (1); 621590Srgrimes if ((sh = value("SHELL")) == NULL) 631590Srgrimes sh = _PATH_CSHELL; 6468617Sdg (void)run_command(sh, 0, -1, -1, "-c", cmd, NULL); 651590Srgrimes (void)signal(SIGINT, sigint); 661590Srgrimes printf("!\n"); 6768617Sdg return (0); 6850638Speter} 692599Sache 701590Srgrimes/* 711590Srgrimes * Fork an interactive shell. 72102944Sdwmalone */ 731590Srgrimes/*ARGSUSED*/ 741590Srgrimesint 751590Srgrimesdosh(char *str __unused) 761590Srgrimes{ 771590Srgrimes sig_t sigint = signal(SIGINT, SIG_IGN); 7887701Smarkm char *sh; 7987701Smarkm 801590Srgrimes if ((sh = value("SHELL")) == NULL) 811590Srgrimes sh = _PATH_CSHELL; 8228370Scharnier (void)run_command(sh, 0, -1, -1, NULL, NULL, NULL); 831590Srgrimes (void)signal(SIGINT, sigint); 841590Srgrimes printf("\n"); 852599Sache return (0); 863397Sache} 8728370Scharnier 881590Srgrimes/* 891590Srgrimes * Expand the shell escape by expanding unescaped !'s into the 901590Srgrimes * last issued command where possible. 911590Srgrimes */ 921590Srgrimesint 931590Srgrimesbangexp(char *str, size_t strsize) 941590Srgrimes{ 951590Srgrimes char bangbuf[BUFSIZ]; 961590Srgrimes static char lastbang[BUFSIZ]; 971590Srgrimes char *cp, *cp2; 981590Srgrimes int n, changed = 0; 9924360Simp 1001590Srgrimes cp = str; 1011590Srgrimes cp2 = bangbuf; 1021590Srgrimes n = sizeof(bangbuf); 1031590Srgrimes while (*cp != '\0') { 1041590Srgrimes if (*cp == '!') { 1051590Srgrimes if (n < strlen(lastbang)) { 1061590Srgrimesoverf: 1071590Srgrimes printf("Command buffer overflow\n"); 1081590Srgrimes return (-1); 1091590Srgrimes } 1101590Srgrimes changed++; 11168617Sdg if (strlcpy(cp2, lastbang, sizeof(bangbuf) - (cp2 - bangbuf)) 1121590Srgrimes >= sizeof(bangbuf) - (cp2 - bangbuf)) 1131590Srgrimes goto overf; 1141590Srgrimes cp2 += strlen(lastbang); 1151590Srgrimes n -= strlen(lastbang); 1161590Srgrimes cp++; 1171590Srgrimes continue; 1181590Srgrimes } 1191590Srgrimes if (*cp == '\\' && cp[1] == '!') { 1201590Srgrimes if (--n <= 1) 1211590Srgrimes goto overf; 1221590Srgrimes *cp2++ = '!'; 1231590Srgrimes cp += 2; 12468617Sdg changed++; 1251590Srgrimes } 1261590Srgrimes if (--n <= 1) 1271590Srgrimes goto overf; 1281590Srgrimes *cp2++ = *cp++; 1291590Srgrimes } 1301590Srgrimes *cp2 = 0; 1311590Srgrimes if (changed) { 1321590Srgrimes printf("!%s\n", bangbuf); 1331590Srgrimes (void)fflush(stdout); 1341590Srgrimes } 1351590Srgrimes if (strlcpy(str, bangbuf, strsize) >= strsize) 1361590Srgrimes goto overf; 1371590Srgrimes if (strlcpy(lastbang, bangbuf, sizeof(lastbang)) >= sizeof(lastbang)) 1381590Srgrimes goto overf; 1391590Srgrimes return (0); 1401590Srgrimes} 1411590Srgrimes 1421590Srgrimes/* 1431590Srgrimes * Print out a nice help message from some file or another. 1441590Srgrimes */ 1451590Srgrimes 1461590Srgrimesint 1471590Srgrimeshelp(void) 1481590Srgrimes{ 1491590Srgrimes int c; 1501590Srgrimes FILE *f; 1511590Srgrimes 1521590Srgrimes if ((f = Fopen(_PATH_HELP, "r")) == NULL) { 1531590Srgrimes warn("%s", _PATH_HELP); 1541590Srgrimes return (1); 1551590Srgrimes } 1561590Srgrimes while ((c = getc(f)) != EOF) 1571590Srgrimes putchar(c); 1581590Srgrimes (void)Fclose(f); 1591590Srgrimes return (0); 1601590Srgrimes} 1611590Srgrimes 16250638Speter/* 16350638Speter * Change user's working directory. 1641590Srgrimes */ 1651590Srgrimesint 1661590Srgrimesschdir(char **arglist) 1671590Srgrimes{ 1681590Srgrimes char *cp; 16950638Speter 17050638Speter if (*arglist == NULL) { 17150638Speter if (homedir == NULL) 1721590Srgrimes return (1); 1731590Srgrimes cp = homedir; 1741590Srgrimes } else 1751590Srgrimes if ((cp = expand(*arglist)) == NULL) 1761590Srgrimes return (1); 1771590Srgrimes if (chdir(cp) < 0) { 1781590Srgrimes warn("%s", cp); 1791590Srgrimes return (1); 1801590Srgrimes } 1811590Srgrimes return (0); 1821590Srgrimes} 1831590Srgrimes 1841590Srgrimesint 1851590Srgrimesrespond(int *msgvec) 1861590Srgrimes{ 1871590Srgrimes if (value("Replyall") == NULL && value("flipr") == NULL) 1881590Srgrimes return (dorespond(msgvec)); 1891590Srgrimes else 1901590Srgrimes return (doRespond(msgvec)); 1911590Srgrimes} 1921590Srgrimes 1931590Srgrimes/* 1941590Srgrimes * Reply to a list of messages. Extract each name from the 1951590Srgrimes * message header and send them off to mail1() 1961590Srgrimes */ 1971590Srgrimesint 1981590Srgrimesdorespond(int *msgvec) 1991590Srgrimes{ 2001590Srgrimes struct message *mp; 2011590Srgrimes char *cp, *rcv, *replyto; 2021590Srgrimes char **ap; 2031590Srgrimes struct name *np; 20450638Speter struct header head; 20550638Speter 2061590Srgrimes if (msgvec[1] != 0) { 2071590Srgrimes printf("Sorry, can't reply to multiple messages at once\n"); 2081590Srgrimes return (1); 2091590Srgrimes } 2101590Srgrimes mp = &message[msgvec[0] - 1]; 2111590Srgrimes touch(mp); 2121590Srgrimes dot = mp; 2131590Srgrimes if ((rcv = skin(hfield("from", mp))) == NULL) 2141590Srgrimes rcv = skin(nameof(mp, 1)); 21550638Speter if ((replyto = skin(hfield("reply-to", mp))) != NULL) 21650638Speter np = extract(replyto, GTO); 21750638Speter else if ((cp = skin(hfield("to", mp))) != NULL) 21850638Speter np = extract(cp, GTO); 21950638Speter else 22050638Speter np = NULL; 22150638Speter np = elide(np); 2221590Srgrimes /* 22350638Speter * Delete my name from the reply list, 22450638Speter * and with it, all my alternate names. 22550638Speter */ 22650638Speter np = delname(np, myname); 22750638Speter if (altnames) 22850638Speter for (ap = altnames; *ap != NULL; ap++) 22950638Speter np = delname(np, *ap); 2301590Srgrimes if (np != NULL && replyto == NULL) 2311590Srgrimes np = cat(np, extract(rcv, GTO)); 2321590Srgrimes else if (np == NULL) { 2331590Srgrimes if (replyto != NULL) 2341590Srgrimes printf("Empty reply-to field -- replying to author\n"); 2351590Srgrimes np = extract(rcv, GTO); 2361590Srgrimes } 2371590Srgrimes head.h_to = np; 2381590Srgrimes if ((head.h_subject = hfield("subject", mp)) == NULL) 2391590Srgrimes head.h_subject = hfield("subj", mp); 240102944Sdwmalone head.h_subject = reedit(head.h_subject); 2411590Srgrimes if (replyto == NULL && (cp = skin(hfield("cc", mp))) != NULL) { 2421590Srgrimes np = elide(extract(cp, GCC)); 2431590Srgrimes np = delname(np, myname); 2441590Srgrimes if (altnames != 0) 2451590Srgrimes for (ap = altnames; *ap != NULL; ap++) 2461590Srgrimes np = delname(np, *ap); 2471590Srgrimes head.h_cc = np; 2481590Srgrimes } else 2491590Srgrimes head.h_cc = NULL; 2501590Srgrimes head.h_bcc = NULL; 2511590Srgrimes head.h_smopts = NULL; 2528524Sache head.h_replyto = value("REPLYTO"); 2531590Srgrimes head.h_inreplyto = skin(hfield("message-id", mp)); 2541590Srgrimes mail1(&head, 1); 2551590Srgrimes return (0); 2561590Srgrimes} 2571590Srgrimes 2581590Srgrimes/* 2591590Srgrimes * Modify the subject we are replying to to begin with Re: if 2601590Srgrimes * it does not already. 2611590Srgrimes */ 2621590Srgrimeschar * 2631590Srgrimesreedit(char *subj) 2641590Srgrimes{ 2651590Srgrimes char *newsubj; 2661590Srgrimes 2671590Srgrimes if (subj == NULL) 268102944Sdwmalone return (NULL); 2691590Srgrimes if ((subj[0] == 'r' || subj[0] == 'R') && 2701590Srgrimes (subj[1] == 'e' || subj[1] == 'E') && 27128370Scharnier subj[2] == ':') 27228370Scharnier return (subj); 27328370Scharnier newsubj = salloc(strlen(subj) + 5); 2741590Srgrimes sprintf(newsubj, "Re: %s", subj); 2751590Srgrimes return (newsubj); 2761590Srgrimes} 27787701Smarkm 2781590Srgrimes/* 2791590Srgrimes * Preserve the named messages, so that they will be sent 28087701Smarkm * back to the system mailbox. 2811590Srgrimes */ 2821590Srgrimesint 28387701Smarkmpreserve(int *msgvec) 2841590Srgrimes{ 2851590Srgrimes int *ip, mesg; 2861590Srgrimes struct message *mp; 2871590Srgrimes 2881590Srgrimes if (edit) { 2891590Srgrimes printf("Cannot \"preserve\" in edit mode\n"); 290102944Sdwmalone return (1); 2911590Srgrimes } 29228370Scharnier for (ip = msgvec; *ip != 0; ip++) { 29328370Scharnier mesg = *ip; 29428370Scharnier mp = &message[mesg-1]; 2951590Srgrimes mp->m_flag |= MPRESERVE; 2961590Srgrimes mp->m_flag &= ~MBOX; 29728370Scharnier dot = mp; 298 } 299 return (0); 300} 301 302/* 303 * Mark all given messages as unread. 304 */ 305int 306unread(int msgvec[]) 307{ 308 int *ip; 309 310 for (ip = msgvec; *ip != 0; ip++) { 311 dot = &message[*ip-1]; 312 dot->m_flag &= ~(MREAD|MTOUCH); 313 dot->m_flag |= MSTATUS; 314 } 315 return (0); 316} 317 318/* 319 * Print the size of each message. 320 */ 321int 322messize(int *msgvec) 323{ 324 struct message *mp; 325 int *ip, mesg; 326 327 for (ip = msgvec; *ip != 0; ip++) { 328 mesg = *ip; 329 mp = &message[mesg-1]; 330 printf("%d: %ld/%ld\n", mesg, mp->m_lines, mp->m_size); 331 } 332 return (0); 333} 334 335/* 336 * Quit quickly. If we are sourcing, just pop the input level 337 * by returning an error. 338 */ 339int 340rexit(int e __unused) 341{ 342 if (sourcing) 343 return (1); 344 exit(0); 345 /*NOTREACHED*/ 346} 347 348/* 349 * Set or display a variable value. Syntax is similar to that 350 * of csh. 351 */ 352int 353set(char **arglist) 354{ 355 struct var *vp; 356 char *cp, *cp2; 357 char varbuf[BUFSIZ], **ap, **p; 358 int errs, h, s; 359 360 if (*arglist == NULL) { 361 for (h = 0, s = 1; h < HSHSIZE; h++) 362 for (vp = variables[h]; vp != NULL; vp = vp->v_link) 363 s++; 364 ap = (char **)salloc(s * sizeof(*ap)); 365 for (h = 0, p = ap; h < HSHSIZE; h++) 366 for (vp = variables[h]; vp != NULL; vp = vp->v_link) 367 *p++ = vp->v_name; 368 *p = NULL; 369 sort(ap); 370 for (p = ap; *p != NULL; p++) 371 printf("%s\t%s\n", *p, value(*p)); 372 return (0); 373 } 374 errs = 0; 375 for (ap = arglist; *ap != NULL; ap++) { 376 cp = *ap; 377 cp2 = varbuf; 378 while (cp2 < varbuf + sizeof(varbuf) - 1 && *cp != '=' && *cp != '\0') 379 *cp2++ = *cp++; 380 *cp2 = '\0'; 381 if (*cp == '\0') 382 cp = ""; 383 else 384 cp++; 385 if (equal(varbuf, "")) { 386 printf("Non-null variable name required\n"); 387 errs++; 388 continue; 389 } 390 assign(varbuf, cp); 391 } 392 return (errs); 393} 394 395/* 396 * Unset a bunch of variable values. 397 */ 398int 399unset(char **arglist) 400{ 401 struct var *vp, *vp2; 402 int errs, h; 403 char **ap; 404 405 errs = 0; 406 for (ap = arglist; *ap != NULL; ap++) { 407 if ((vp2 = lookup(*ap)) == NULL) { 408 if (getenv(*ap)) 409 unsetenv(*ap); 410 else if (!sourcing) { 411 printf("\"%s\": undefined variable\n", *ap); 412 errs++; 413 } 414 continue; 415 } 416 h = hash(*ap); 417 if (vp2 == variables[h]) { 418 variables[h] = variables[h]->v_link; 419 vfree(vp2->v_name); 420 vfree(vp2->v_value); 421 (void)free(vp2); 422 continue; 423 } 424 for (vp = variables[h]; vp->v_link != vp2; vp = vp->v_link) 425 ; 426 vp->v_link = vp2->v_link; 427 vfree(vp2->v_name); 428 vfree(vp2->v_value); 429 (void)free(vp2); 430 } 431 return (errs); 432} 433 434/* 435 * Put add users to a group. 436 */ 437int 438group(char **argv) 439{ 440 struct grouphead *gh; 441 struct group *gp; 442 char **ap, *gname, **p; 443 int h, s; 444 445 if (*argv == NULL) { 446 for (h = 0, s = 1; h < HSHSIZE; h++) 447 for (gh = groups[h]; gh != NULL; gh = gh->g_link) 448 s++; 449 ap = (char **)salloc(s * sizeof(*ap)); 450 for (h = 0, p = ap; h < HSHSIZE; h++) 451 for (gh = groups[h]; gh != NULL; gh = gh->g_link) 452 *p++ = gh->g_name; 453 *p = NULL; 454 sort(ap); 455 for (p = ap; *p != NULL; p++) 456 printgroup(*p); 457 return (0); 458 } 459 if (argv[1] == NULL) { 460 printgroup(*argv); 461 return (0); 462 } 463 gname = *argv; 464 h = hash(gname); 465 if ((gh = findgroup(gname)) == NULL) { 466 if ((gh = calloc(1, sizeof(*gh))) == NULL) 467 err(1, "Out of memory"); 468 gh->g_name = vcopy(gname); 469 gh->g_list = NULL; 470 gh->g_link = groups[h]; 471 groups[h] = gh; 472 } 473 474 /* 475 * Insert names from the command list into the group. 476 * Who cares if there are duplicates? They get tossed 477 * later anyway. 478 */ 479 480 for (ap = argv+1; *ap != NULL; ap++) { 481 if ((gp = calloc(1, sizeof(*gp))) == NULL) 482 err(1, "Out of memory"); 483 gp->ge_name = vcopy(*ap); 484 gp->ge_link = gh->g_list; 485 gh->g_list = gp; 486 } 487 return (0); 488} 489 490/* 491 * Sort the passed string vecotor into ascending dictionary 492 * order. 493 */ 494void 495sort(char **list) 496{ 497 char **ap; 498 499 for (ap = list; *ap != NULL; ap++) 500 ; 501 if (ap-list < 2) 502 return; 503 qsort(list, ap-list, sizeof(*list), diction); 504} 505 506/* 507 * Do a dictionary order comparison of the arguments from 508 * qsort. 509 */ 510int 511diction(const void *a, const void *b) 512{ 513 return (strcmp(*(const char **)a, *(const char **)b)); 514} 515 516/* 517 * The do nothing command for comments. 518 */ 519 520/*ARGSUSED*/ 521int 522null(int e __unused) 523{ 524 return (0); 525} 526 527/* 528 * Change to another file. With no argument, print information about 529 * the current file. 530 */ 531int 532file(char **argv) 533{ 534 535 if (argv[0] == NULL) { 536 newfileinfo(0); 537 return (0); 538 } 539 if (setfile(*argv) < 0) 540 return (1); 541 announce(); 542 return (0); 543} 544 545/* 546 * Expand file names like echo 547 */ 548int 549echo(char **argv) 550{ 551 char **ap, *cp; 552 553 for (ap = argv; *ap != NULL; ap++) { 554 cp = *ap; 555 if ((cp = expand(cp)) != NULL) { 556 if (ap != argv) 557 printf(" "); 558 printf("%s", cp); 559 } 560 } 561 printf("\n"); 562 return (0); 563} 564 565int 566Respond(int *msgvec) 567{ 568 if (value("Replyall") == NULL && value("flipr") == NULL) 569 return (doRespond(msgvec)); 570 else 571 return (dorespond(msgvec)); 572} 573 574/* 575 * Reply to a series of messages by simply mailing to the senders 576 * and not messing around with the To: and Cc: lists as in normal 577 * reply. 578 */ 579int 580doRespond(int msgvec[]) 581{ 582 struct header head; 583 struct message *mp; 584 int *ap; 585 char *cp, *mid; 586 587 head.h_to = NULL; 588 for (ap = msgvec; *ap != 0; ap++) { 589 mp = &message[*ap - 1]; 590 touch(mp); 591 dot = mp; 592 if ((cp = skin(hfield("from", mp))) == NULL) 593 cp = skin(nameof(mp, 2)); 594 head.h_to = cat(head.h_to, extract(cp, GTO)); 595 mid = skin(hfield("message-id", mp)); 596 } 597 if (head.h_to == NULL) 598 return (0); 599 mp = &message[msgvec[0] - 1]; 600 if ((head.h_subject = hfield("subject", mp)) == NULL) 601 head.h_subject = hfield("subj", mp); 602 head.h_subject = reedit(head.h_subject); 603 head.h_cc = NULL; 604 head.h_bcc = NULL; 605 head.h_smopts = NULL; 606 head.h_replyto = value("REPLYTO"); 607 head.h_inreplyto = mid; 608 mail1(&head, 1); 609 return (0); 610} 611 612/* 613 * Conditional commands. These allow one to parameterize one's 614 * .mailrc and do some things if sending, others if receiving. 615 */ 616int 617ifcmd(char **argv) 618{ 619 char *cp; 620 621 if (cond != CANY) { 622 printf("Illegal nested \"if\"\n"); 623 return (1); 624 } 625 cond = CANY; 626 cp = argv[0]; 627 switch (*cp) { 628 case 'r': case 'R': 629 cond = CRCV; 630 break; 631 632 case 's': case 'S': 633 cond = CSEND; 634 break; 635 636 default: 637 printf("Unrecognized if-keyword: \"%s\"\n", cp); 638 return (1); 639 } 640 return (0); 641} 642 643/* 644 * Implement 'else'. This is pretty simple -- we just 645 * flip over the conditional flag. 646 */ 647int 648elsecmd(void) 649{ 650 651 switch (cond) { 652 case CANY: 653 printf("\"Else\" without matching \"if\"\n"); 654 return (1); 655 656 case CSEND: 657 cond = CRCV; 658 break; 659 660 case CRCV: 661 cond = CSEND; 662 break; 663 664 default: 665 printf("Mail's idea of conditions is screwed up\n"); 666 cond = CANY; 667 break; 668 } 669 return (0); 670} 671 672/* 673 * End of if statement. Just set cond back to anything. 674 */ 675int 676endifcmd(void) 677{ 678 679 if (cond == CANY) { 680 printf("\"Endif\" without matching \"if\"\n"); 681 return (1); 682 } 683 cond = CANY; 684 return (0); 685} 686 687/* 688 * Set the list of alternate names. 689 */ 690int 691alternates(char **namelist) 692{ 693 int c; 694 char **ap, **ap2, *cp; 695 696 c = argcount(namelist) + 1; 697 if (c == 1) { 698 if (altnames == 0) 699 return (0); 700 for (ap = altnames; *ap != NULL; ap++) 701 printf("%s ", *ap); 702 printf("\n"); 703 return (0); 704 } 705 if (altnames != 0) 706 (void)free(altnames); 707 if ((altnames = calloc((unsigned)c, sizeof(char *))) == NULL) 708 err(1, "Out of memory"); 709 for (ap = namelist, ap2 = altnames; *ap != NULL; ap++, ap2++) { 710 cp = calloc((unsigned)strlen(*ap) + 1, sizeof(char)); 711 strcpy(cp, *ap); 712 *ap2 = cp; 713 } 714 *ap2 = 0; 715 return (0); 716} 717