modules.c revision 17721
1/* 2 * Copyright (c) 1992, Brian Berliner and Jeff Polk 3 * Copyright (c) 1989-1992, Brian Berliner 4 * 5 * You may distribute under the terms of the GNU General Public License 6 * as specified in the README file that comes with the CVS 1.4 kit. 7 * 8 * Modules 9 * 10 * Functions for accessing the modules file. 11 * 12 * The modules file supports basically three formats of lines: 13 * key [options] directory files... [ -x directory [files] ] ... 14 * key [options] directory [ -x directory [files] ] ... 15 * key -a aliases... 16 * 17 * The -a option allows an aliasing step in the parsing of the modules 18 * file. The "aliases" listed on a line following the -a are 19 * processed one-by-one, as if they were specified as arguments on the 20 * command line. 21 */ 22 23#include "cvs.h" 24#include "savecwd.h" 25 26 27/* Defines related to the syntax of the modules file. */ 28 29/* Options in modules file. Note that it is OK to use GNU getopt features; 30 we already are arranging to make sure we are using the getopt distributed 31 with CVS. */ 32#define CVSMODULE_OPTS "+ad:i:lo:e:s:t:u:" 33 34/* Special delimiter. */ 35#define CVSMODULE_SPEC '&' 36 37struct sortrec 38{ 39 char *modname; 40 char *status; 41 char *rest; 42 char *comment; 43}; 44 45static int sort_order PROTO((const PTR l, const PTR r)); 46static void save_d PROTO((char *k, int ks, char *d, int ds)); 47 48 49/* 50 * Open the modules file, and die if the CVSROOT environment variable 51 * was not set. If the modules file does not exist, that's fine, and 52 * a warning message is displayed and a NULL is returned. 53 */ 54DBM * 55open_module () 56{ 57 char mfile[PATH_MAX]; 58 59 if (CVSroot == NULL) 60 { 61 (void) fprintf (stderr, 62 "%s: must set the CVSROOT environment variable\n", 63 program_name); 64 error (1, 0, "or specify the '-d' option to %s", program_name); 65 } 66 (void) sprintf (mfile, "%s/%s/%s", CVSroot, CVSROOTADM, CVSROOTADM_MODULES); 67 return (dbm_open (mfile, O_RDONLY, 0666)); 68} 69 70/* 71 * Close the modules file, if the open succeeded, that is 72 */ 73void 74close_module (db) 75 DBM *db; 76{ 77 if (db != NULL) 78 dbm_close (db); 79} 80 81/* 82 * This is the recursive function that processes a module name. 83 * It calls back the passed routine for each directory of a module 84 * It runs the post checkout or post tag proc from the modules file 85 */ 86int 87do_module (db, mname, m_type, msg, callback_proc, where, 88 shorten, local_specified, run_module_prog, extra_arg) 89 DBM *db; 90 char *mname; 91 enum mtype m_type; 92 char *msg; 93 CALLBACKPROC callback_proc; 94 char *where; 95 int shorten; 96 int local_specified; 97 int run_module_prog; 98 char *extra_arg; 99{ 100 char *checkin_prog = NULL; 101 char *checkout_prog = NULL; 102 char *export_prog = NULL; 103 char *tag_prog = NULL; 104 char *update_prog = NULL; 105 struct saved_cwd cwd; 106 char *line; 107 int modargc; 108 int xmodargc; 109 char **modargv; 110 char *xmodargv[MAXFILEPERDIR]; 111 char *value; 112 char *zvalue; 113 char *mwhere = NULL; 114 char *mfile = NULL; 115 char *spec_opt = NULL; 116 char xvalue[PATH_MAX]; 117 int alias = 0; 118 datum key, val; 119 char *cp; 120 int c, err = 0; 121 122#ifdef SERVER_SUPPORT 123 if (trace) 124 { 125 fprintf (stderr, "%s%c-> do_module (%s, %s, %s, %s)\n", 126 error_use_protocol ? "E " : "", 127 (server_active) ? 'S' : ' ', 128 mname, msg, where ? where : "", 129 extra_arg ? extra_arg : ""); 130 } 131#endif 132 133 /* if this is a directory to ignore, add it to that list */ 134 if (mname[0] == '!' && mname[1] != '\0') 135 { 136 ign_dir_add (mname+1); 137 return(err); 138 } 139 140 /* strip extra stuff from the module name */ 141 strip_path (mname); 142 143 /* 144 * Look up the module using the following scheme: 145 * 1) look for mname as a module name 146 * 2) look for mname as a directory 147 * 3) look for mname as a file 148 * 4) take mname up to the first slash and look it up as a module name 149 * (this is for checking out only part of a module) 150 */ 151 152 /* look it up as a module name */ 153 key.dptr = mname; 154 key.dsize = strlen (key.dptr); 155 if (db != NULL) 156 val = dbm_fetch (db, key); 157 else 158 val.dptr = NULL; 159 if (val.dptr != NULL) 160 { 161 /* null terminate the value XXX - is this space ours? */ 162 val.dptr[val.dsize] = '\0'; 163 164 /* If the line ends in a comment, strip it off */ 165 if ((cp = strchr (val.dptr, '#')) != NULL) 166 { 167 do 168 *cp-- = '\0'; 169 while (isspace (*cp)); 170 } 171 else 172 { 173 /* Always strip trailing spaces */ 174 cp = strchr (val.dptr, '\0'); 175 while (cp > val.dptr && isspace(*--cp)) 176 *cp = '\0'; 177 } 178 179 value = val.dptr; 180 mwhere = xstrdup (mname); 181 goto found; 182 } 183 else 184 { 185 char file[PATH_MAX]; 186 char attic_file[PATH_MAX]; 187 char *acp; 188 189 /* check to see if mname is a directory or file */ 190 191 (void) sprintf (file, "%s/%s", CVSroot, mname); 192 if ((acp = strrchr (mname, '/')) != NULL) 193 { 194 *acp = '\0'; 195 (void) sprintf (attic_file, "%s/%s/%s/%s%s", CVSroot, mname, 196 CVSATTIC, acp + 1, RCSEXT); 197 *acp = '/'; 198 } 199 else 200 (void) sprintf (attic_file, "%s/%s/%s%s", CVSroot, CVSATTIC, 201 mname, RCSEXT); 202 203 if (isdir (file)) 204 { 205 value = mname; 206 goto found; 207 } 208 else 209 { 210 (void) strcat (file, RCSEXT); 211 if (isfile (file) || isfile (attic_file)) 212 { 213 /* if mname was a file, we have to split it into "dir file" */ 214 if ((cp = strrchr (mname, '/')) != NULL && cp != mname) 215 { 216 char *slashp; 217 218 /* put the ' ' in a copy so we don't mess up the original */ 219 value = strcpy (xvalue, mname); 220 slashp = strrchr (value, '/'); 221 *slashp = ' '; 222 } 223 else 224 { 225 /* 226 * the only '/' at the beginning or no '/' at all 227 * means the file we are interested in is in CVSROOT 228 * itself so the directory should be '.' 229 */ 230 if (cp == mname) 231 { 232 /* drop the leading / if specified */ 233 value = strcpy (xvalue, ". "); 234 (void) strcat (xvalue, mname + 1); 235 } 236 else 237 { 238 /* otherwise just copy it */ 239 value = strcpy (xvalue, ". "); 240 (void) strcat (xvalue, mname); 241 } 242 } 243 goto found; 244 } 245 } 246 } 247 248 /* look up everything to the first / as a module */ 249 if (mname[0] != '/' && (cp = strchr (mname, '/')) != NULL) 250 { 251 /* Make the slash the new end of the string temporarily */ 252 *cp = '\0'; 253 key.dptr = mname; 254 key.dsize = strlen (key.dptr); 255 256 /* do the lookup */ 257 if (db != NULL) 258 val = dbm_fetch (db, key); 259 else 260 val.dptr = NULL; 261 262 /* if we found it, clean up the value and life is good */ 263 if (val.dptr != NULL) 264 { 265 char *cp2; 266 267 /* null terminate the value XXX - is this space ours? */ 268 val.dptr[val.dsize] = '\0'; 269 270 /* If the line ends in a comment, strip it off */ 271 if ((cp2 = strchr (val.dptr, '#')) != NULL) 272 { 273 do 274 *cp2-- = '\0'; 275 while (isspace (*cp2)); 276 } 277 value = val.dptr; 278 279 /* mwhere gets just the module name */ 280 mwhere = xstrdup (mname); 281 mfile = cp + 1; 282 283 /* put the / back in mname */ 284 *cp = '/'; 285 286 goto found; 287 } 288 289 /* put the / back in mname */ 290 *cp = '/'; 291 } 292 293 /* if we got here, we couldn't find it using our search, so give up */ 294 error (0, 0, "cannot find module `%s' - ignored", mname); 295 err++; 296 if (mwhere) 297 free (mwhere); 298 return (err); 299 300 301 /* 302 * At this point, we found what we were looking for in one 303 * of the many different forms. 304 */ 305 found: 306 307 /* remember where we start */ 308 if (save_cwd (&cwd)) 309 exit (EXIT_FAILURE); 310 311 /* copy value to our own string since if we go recursive we'll be 312 really screwed if we do another dbm lookup */ 313 zvalue = xstrdup (value); 314 value = zvalue; 315 316 /* search the value for the special delimiter and save for later */ 317 if ((cp = strchr (value, CVSMODULE_SPEC)) != NULL) 318 { 319 *cp = '\0'; /* null out the special char */ 320 spec_opt = cp + 1; /* save the options for later */ 321 322 if (cp != value) /* strip whitespace if necessary */ 323 while (isspace (*--cp)) 324 *cp = '\0'; 325 326 if (cp == value) 327 { 328 /* 329 * we had nothing but special options, so skip arg 330 * parsing and regular stuff entirely 331 * 332 * If there were only special ones though, we must 333 * make the appropriate directory and cd to it 334 */ 335 char *dir; 336 337 /* XXX - XXX - MAJOR HACK - DO NOT SHIP - this needs to 338 be !pipeout, but we don't know that here yet */ 339 if (!run_module_prog) 340 goto out; 341 342 dir = where ? where : mname; 343 /* XXX - think about making null repositories at each dir here 344 instead of just at the bottom */ 345 make_directories (dir); 346 if (chdir (dir) < 0) 347 { 348 error (0, errno, "cannot chdir to %s", dir); 349 spec_opt = NULL; 350 err++; 351 goto out; 352 } 353 if (!isfile (CVSADM)) 354 { 355 char nullrepos[PATH_MAX]; 356 357 (void) sprintf (nullrepos, "%s/%s/%s", CVSroot, 358 CVSROOTADM, CVSNULLREPOS); 359 if (!isfile (nullrepos)) 360 { 361 mode_t omask; 362 omask = umask (cvsumask); 363 (void) CVS_MKDIR (nullrepos, 0777); 364 (void) umask (omask); 365 } 366 if (!isdir (nullrepos)) 367 error (1, 0, "there is no repository %s", nullrepos); 368 369 Create_Admin (".", dir, 370 nullrepos, (char *) NULL, (char *) NULL); 371 if (!noexec) 372 { 373 FILE *fp; 374 375 fp = open_file (CVSADM_ENTSTAT, "w+"); 376 if (fclose (fp) == EOF) 377 error (1, errno, "cannot close %s", CVSADM_ENTSTAT); 378#ifdef SERVER_SUPPORT 379 if (server_active) 380 server_set_entstat (dir, nullrepos); 381#endif 382 } 383 } 384 out: 385 goto do_special; 386 } 387 } 388 389 /* don't do special options only part of a module was specified */ 390 if (mfile != NULL) 391 spec_opt = NULL; 392 393 /* 394 * value now contains one of the following: 395 * 1) dir 396 * 2) dir file 397 * 3) the value from modules without any special args 398 * [ args ] dir [file] [file] ... 399 * or -a module [ module ] ... 400 */ 401 402 /* Put the value on a line with XXX prepended for getopt to eat */ 403 line = xmalloc (strlen (value) + 10); 404 (void) sprintf (line, "%s %s", "XXX", value); 405 406 /* turn the line into an argv[] array */ 407 line2argv (&xmodargc, xmodargv, line); 408 free (line); 409 modargc = xmodargc; 410 modargv = xmodargv; 411 412 /* parse the args */ 413 optind = 1; 414 while ((c = getopt (modargc, modargv, CVSMODULE_OPTS)) != -1) 415 { 416 switch (c) 417 { 418 case 'a': 419 alias = 1; 420 break; 421 case 'd': 422 if (mwhere) 423 free (mwhere); 424 mwhere = xstrdup (optarg); 425 break; 426 case 'i': 427 checkin_prog = optarg; 428 break; 429 case 'l': 430 local_specified = 1; 431 break; 432 case 'o': 433 checkout_prog = optarg; 434 break; 435 case 'e': 436 export_prog = optarg; 437 break; 438 case 't': 439 tag_prog = optarg; 440 break; 441 case 'u': 442 update_prog = optarg; 443 break; 444 case '?': 445 error (0, 0, 446 "modules file has invalid option for key %s value %s", 447 key.dptr, val.dptr); 448 err++; 449 if (mwhere) 450 free (mwhere); 451 free (zvalue); 452 free_cwd (&cwd); 453 return (err); 454 } 455 } 456 modargc -= optind; 457 modargv += optind; 458 if (modargc == 0) 459 { 460 error (0, 0, "modules file missing directory for module %s", mname); 461 if (mwhere) 462 free (mwhere); 463 free (zvalue); 464 free_cwd (&cwd); 465 return (++err); 466 } 467 468 /* if this was an alias, call ourselves recursively for each module */ 469 if (alias) 470 { 471 int i; 472 473 for (i = 0; i < modargc; i++) 474 { 475 if (strcmp (mname, modargv[i]) == 0) 476 error (0, 0, 477 "module `%s' in modules file contains infinite loop", 478 mname); 479 else 480 err += do_module (db, modargv[i], m_type, msg, callback_proc, 481 where, shorten, local_specified, 482 run_module_prog, extra_arg); 483 } 484 if (mwhere) 485 free (mwhere); 486 free (zvalue); 487 free_cwd (&cwd); 488 return (err); 489 } 490 491 /* otherwise, process this module */ 492 err += callback_proc (&modargc, modargv, where, mwhere, mfile, shorten, 493 local_specified, mname, msg); 494 495#if 0 496 /* FIXME: I've fixed this so that the correct arguments are called, 497 but now this fails because there is code below this point that 498 uses optarg values extracted from the arg vector. */ 499 free_names (&xmodargc, xmodargv); 500#endif 501 502 /* if there were special include args, process them now */ 503 504 do_special: 505 506 /* blow off special options if -l was specified */ 507 if (local_specified) 508 spec_opt = NULL; 509 510 while (spec_opt != NULL) 511 { 512 char *next_opt; 513 514 cp = strchr (spec_opt, CVSMODULE_SPEC); 515 if (cp != NULL) 516 { 517 /* save the beginning of the next arg */ 518 next_opt = cp + 1; 519 520 /* strip whitespace off the end */ 521 do 522 *cp = '\0'; 523 while (isspace (*--cp)); 524 } 525 else 526 next_opt = NULL; 527 528 /* strip whitespace from front */ 529 while (isspace (*spec_opt)) 530 spec_opt++; 531 532 if (*spec_opt == '\0') 533 error (0, 0, "Mal-formed %c option for module %s - ignored", 534 CVSMODULE_SPEC, mname); 535 else 536 err += do_module (db, spec_opt, m_type, msg, callback_proc, 537 (char *) NULL, 0, local_specified, 538 run_module_prog, extra_arg); 539 spec_opt = next_opt; 540 } 541 542 /* write out the checkin/update prog files if necessary */ 543#ifdef SERVER_SUPPORT 544 if (err == 0 && !noexec && m_type == CHECKOUT && server_expanding) 545 { 546 if (checkin_prog != NULL) 547 server_prog (where ? where : mname, checkin_prog, PROG_CHECKIN); 548 if (update_prog != NULL) 549 server_prog (where ? where : mname, update_prog, PROG_UPDATE); 550 } 551 else 552#endif 553 if (err == 0 && !noexec && m_type == CHECKOUT && run_module_prog) 554 { 555 FILE *fp; 556 557 if (checkin_prog != NULL) 558 { 559 fp = open_file (CVSADM_CIPROG, "w+"); 560 (void) fprintf (fp, "%s\n", checkin_prog); 561 if (fclose (fp) == EOF) 562 error (1, errno, "cannot close %s", CVSADM_CIPROG); 563 } 564 if (update_prog != NULL) 565 { 566 fp = open_file (CVSADM_UPROG, "w+"); 567 (void) fprintf (fp, "%s\n", update_prog); 568 if (fclose (fp) == EOF) 569 error (1, errno, "cannot close %s", CVSADM_UPROG); 570 } 571 } 572 573 /* cd back to where we started */ 574 if (restore_cwd (&cwd, NULL)) 575 exit (EXIT_FAILURE); 576 free_cwd (&cwd); 577 578 /* run checkout or tag prog if appropriate */ 579 if (err == 0 && run_module_prog) 580 { 581 if ((m_type == TAG && tag_prog != NULL) || 582 (m_type == CHECKOUT && checkout_prog != NULL) || 583 (m_type == EXPORT && export_prog != NULL)) 584 { 585 /* 586 * If a relative pathname is specified as the checkout, tag 587 * or export proc, try to tack on the current "where" value. 588 * if we can't find a matching program, just punt and use 589 * whatever is specified in the modules file. 590 */ 591 char real_prog[PATH_MAX]; 592 char *prog = (m_type == TAG ? tag_prog : 593 (m_type == CHECKOUT ? checkout_prog : export_prog)); 594 char *real_where = (where != NULL ? where : mwhere); 595 596 if ((*prog != '/') && (*prog != '.')) 597 { 598 (void) sprintf (real_prog, "%s/%s", real_where, prog); 599 if (isfile (real_prog)) 600 prog = real_prog; 601 } 602 603 run_setup ("%s %s", prog, real_where); 604 if (extra_arg) 605 run_arg (extra_arg); 606 607 if (!quiet) 608 { 609 (void) printf ("%s %s: Executing '", program_name, 610 command_name); 611 run_print (stdout); 612 (void) printf ("'\n"); 613 } 614 err += run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL); 615 } 616 } 617 618 /* clean up */ 619 if (mwhere) 620 free (mwhere); 621 free (zvalue); 622 623 return (err); 624} 625 626/* - Read all the records from the modules database into an array. 627 - Sort the array depending on what format is desired. 628 - Print the array in the format desired. 629 630 Currently, there are only two "desires": 631 632 1. Sort by module name and format the whole entry including switches, 633 files and the comment field: (Including aliases) 634 635 modulename -s switches, one per line, even if 636 -i it has many switches. 637 Directories and files involved, formatted 638 to cover multiple lines if necessary. 639 # Comment, also formatted to cover multiple 640 # lines if necessary. 641 642 2. Sort by status field string and print: (*not* including aliases) 643 644 modulename STATUS Directories and files involved, formatted 645 to cover multiple lines if necessary. 646 # Comment, also formatted to cover multiple 647 # lines if necessary. 648*/ 649 650static struct sortrec *s_head; 651 652static int s_max = 0; /* Number of elements allocated */ 653static int s_count = 0; /* Number of elements used */ 654 655static int Status; /* Nonzero if the user is 656 interested in status 657 information as well as 658 module name */ 659static char def_status[] = "NONE"; 660 661/* Sort routine for qsort: 662 - If we want the "Status" field to be sorted, check it first. 663 - Then compare the "module name" fields. Since they are unique, we don't 664 have to look further. 665*/ 666static int 667sort_order (l, r) 668 const PTR l; 669 const PTR r; 670{ 671 int i; 672 const struct sortrec *left = (const struct sortrec *) l; 673 const struct sortrec *right = (const struct sortrec *) r; 674 675 if (Status) 676 { 677 /* If Sort by status field, compare them. */ 678 if ((i = strcmp (left->status, right->status)) != 0) 679 return (i); 680 } 681 return (strcmp (left->modname, right->modname)); 682} 683 684static void 685save_d (k, ks, d, ds) 686 char *k; 687 int ks; 688 char *d; 689 int ds; 690{ 691 char *cp, *cp2; 692 struct sortrec *s_rec; 693 694 if (Status && *d == '-' && *(d + 1) == 'a') 695 return; /* We want "cvs co -s" and it is an alias! */ 696 697 if (s_count == s_max) 698 { 699 s_max += 64; 700 s_head = (struct sortrec *) xrealloc ((char *) s_head, s_max * sizeof (*s_head)); 701 } 702 s_rec = &s_head[s_count]; 703 s_rec->modname = cp = xmalloc (ks + 1); 704 (void) strncpy (cp, k, ks); 705 *(cp + ks) = '\0'; 706 707 s_rec->rest = cp2 = xmalloc (ds + 1); 708 cp = d; 709 *(cp + ds) = '\0'; /* Assumes an extra byte at end of static dbm buffer */ 710 711 while (isspace (*cp)) 712 cp++; 713 /* Turn <spaces> into one ' ' -- makes the rest of this routine simpler */ 714 while (*cp) 715 { 716 if (isspace (*cp)) 717 { 718 *cp2++ = ' '; 719 while (isspace (*cp)) 720 cp++; 721 } 722 else 723 *cp2++ = *cp++; 724 } 725 *cp2 = '\0'; 726 727 /* Look for the "-s statusvalue" text */ 728 if (Status) 729 { 730 s_rec->status = def_status; 731 732 /* Minor kluge, but general enough to maintain */ 733 for (cp = s_rec->rest; (cp2 = strchr (cp, '-')) != NULL; cp = ++cp2) 734 { 735 if (*(cp2 + 1) == 's' && *(cp2 + 2) == ' ') 736 { 737 s_rec->status = (cp2 += 3); 738 while (*cp2 != ' ') 739 cp2++; 740 *cp2++ = '\0'; 741 cp = cp2; 742 break; 743 } 744 } 745 } 746 else 747 cp = s_rec->rest; 748 749 /* Find comment field, clean up on all three sides & compress blanks */ 750 if ((cp2 = cp = strchr (cp, '#')) != NULL) 751 { 752 if (*--cp2 == ' ') 753 *cp2 = '\0'; 754 if (*++cp == ' ') 755 cp++; 756 s_rec->comment = cp; 757 } 758 else 759 s_rec->comment = ""; 760 761 s_count++; 762} 763 764/* Print out the module database as we know it. If STATUS is 765 non-zero, print out status information for each module. */ 766 767void 768cat_module (status) 769 int status; 770{ 771 DBM *db; 772 datum key, val; 773 int i, c, wid, argc, cols = 80, indent, fill; 774 int moduleargc; 775 struct sortrec *s_h; 776 char *cp, *cp2, **argv; 777 char *line; 778 char *moduleargv[MAXFILEPERDIR]; 779 780#ifdef sun 781#ifdef TIOCGSIZE 782 struct ttysize ts; 783 784 (void) ioctl (0, TIOCGSIZE, &ts); 785 cols = ts.ts_cols; 786#endif 787#else 788#ifdef TIOCGWINSZ 789 struct winsize ws; 790 791 (void) ioctl (0, TIOCGWINSZ, &ws); 792 cols = ws.ws_col; 793#endif 794#endif 795 796 Status = status; 797 798 /* Read the whole modules file into allocated records */ 799 if (!(db = open_module ())) 800 error (1, 0, "failed to open the modules file"); 801 802 for (key = dbm_firstkey (db); key.dptr != NULL; key = dbm_nextkey (db)) 803 { 804 val = dbm_fetch (db, key); 805 if (val.dptr != NULL) 806 save_d (key.dptr, key.dsize, val.dptr, val.dsize); 807 } 808 809 /* Sort the list as requested */ 810 qsort ((PTR) s_head, s_count, sizeof (struct sortrec), sort_order); 811 812 /* 813 * Run through the sorted array and format the entries 814 * indent = space for modulename + space for status field 815 */ 816 indent = 12 + (status * 12); 817 fill = cols - (indent + 2); 818 for (s_h = s_head, i = 0; i < s_count; i++, s_h++) 819 { 820 /* Print module name (and status, if wanted) */ 821 (void) printf ("%-12s", s_h->modname); 822 if (status) 823 { 824 (void) printf (" %-11s", s_h->status); 825 if (s_h->status != def_status) 826 *(s_h->status + strlen (s_h->status)) = ' '; 827 } 828 829 /* Parse module file entry as command line and print options */ 830 line = xmalloc (strlen (s_h->modname) + strlen (s_h->rest) + 10); 831 (void) sprintf (line, "%s %s", s_h->modname, s_h->rest); 832 line2argv (&moduleargc, moduleargv, line); 833 free (line); 834 argc = moduleargc; 835 argv = moduleargv; 836 837 optind = 0; 838 wid = 0; 839 while ((c = getopt (argc, argv, CVSMODULE_OPTS)) != -1) 840 { 841 if (!status) 842 { 843 if (c == 'a' || c == 'l') 844 { 845 (void) printf (" -%c", c); 846 wid += 3; /* Could just set it to 3 */ 847 } 848 else 849 { 850 if (strlen (optarg) + 4 + wid > (unsigned) fill) 851 { 852 (void) printf ("\n%*s", indent, ""); 853 wid = 0; 854 } 855 (void) printf (" -%c %s", c, optarg); 856 wid += strlen (optarg) + 4; 857 } 858 } 859 } 860 argc -= optind; 861 argv += optind; 862 863 /* Format and Print all the files and directories */ 864 for (; argc--; argv++) 865 { 866 if (strlen (*argv) + wid > (unsigned) fill) 867 { 868 (void) printf ("\n%*s", indent, ""); 869 wid = 0; 870 } 871 (void) printf (" %s", *argv); 872 wid += strlen (*argv) + 1; 873 } 874 (void) printf ("\n"); 875 876 /* Format the comment field -- save_d (), compressed spaces */ 877 for (cp2 = cp = s_h->comment; *cp; cp2 = cp) 878 { 879 (void) printf ("%*s # ", indent, ""); 880 if (strlen (cp2) < (unsigned) (fill - 2)) 881 { 882 (void) printf ("%s\n", cp2); 883 break; 884 } 885 cp += fill - 2; 886 while (*cp != ' ' && cp > cp2) 887 cp--; 888 if (cp == cp2) 889 { 890 (void) printf ("%s\n", cp2); 891 break; 892 } 893 894 *cp++ = '\0'; 895 (void) printf ("%s\n", cp2); 896 } 897 898 free_names(&moduleargc, moduleargv); 899 } 900} 901