pkg_printf.c
1 /* 2 * Copyright (c) 2012-2015 Matthew Seaman <matthew@FreeBSD.org> 3 * Copyright (c) 2014-2020 Baptiste Daroussin <bapt@FreeBSD.org> 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer 11 * in this position and unchanged. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28 #include "bsd_compat.h" 29 #include <sys/types.h> 30 #include <sys/stat.h> 31 32 /* musl libc apparently does not have ALLPERMS */ 33 #ifndef ALLPERMS 34 #define ALLPERMS (S_ISUID|S_ISGID|S_ISTXT|S_IRWXU|S_IRWXG|S_IRWXO) 35 #endif 36 37 #include <assert.h> 38 #include <ctype.h> 39 #include <inttypes.h> 40 #include <stdarg.h> 41 #include <stdio.h> 42 #include <string.h> 43 #include <time.h> 44 #include <utlist.h> 45 46 #include "pkg.h" 47 #include <xstring.h> 48 #include <private/pkg_printf.h> 49 #include <private/pkg.h> 50 51 /* 52 * Format codes 53 * Arg Type What 54 * A pkg Package annotations 55 * An pkg_note Annotation tag name 56 * Av pkg_note Annotation value 57 * 58 * B pkg List of required shared libraries 59 * Bn pkg_shlib Shared library name 60 * 61 * C pkg List of categories 62 * Cn pkg_category Category name 63 * 64 * D pkg List of directories 65 * Df pkg_dir File flags of directory 66 * Dg pkg_dir Group owner of directory 67 * Dk pkg_dir Keep flag 68 * Dn pkg_dir Directory path name 69 * Dp pkg_dir Directory permissions 70 * Dt pkg_dir Try flag (@dirrmtry in plist) 71 * Du pkg_dir User owner of directory 72 * 73 * E 74 * 75 * F pkg List of files 76 * Ff pkg_file File flags of file 77 * Fg pkg_file Group owner of file 78 * Fk pkg_file Keep flag 79 * Fl pkg_file File modification time 80 * Fn pkg_file File path name 81 * Fp pkg_file File permissions 82 * Fs pkg_file File SHA256 checksum 83 * Ft pkg_file File symlink target 84 * Fu pkg_file User owner of file 85 * 86 * G pkg List of groups 87 * Gn pkg_group Group name 88 * 89 * H 90 * 91 * I int* Row counter 92 * 93 * J 94 * K 95 * 96 * L pkg List of licenses 97 * Ln pkg_license Licence name 98 * 99 * M pkg Message 100 * N pkg Reponame 101 * 102 * O pkg List of options 103 * On pkg_option Option name (key) 104 * Ov pkg_option Option value 105 * Od pkg_option Option default value (if known) 106 * OD pkg_option Option description 107 * 108 * P pkg 109 * Q 110 * 111 * R pkg Repopath 112 * S char* Arbitrary character string 113 * 114 * T 115 * 116 * U pkg List of users 117 * Un pkg_user User name 118 * 119 * V pkg old version 120 * W 121 * X pkg Internal Checksum 122 * Y pkg List of requires 123 * Yn pkg_provide Name of the require 124 * Z 125 * 126 * a pkg autoremove flag 127 * 128 * b pkg List of provided shared libraries 129 * bn pkg_shlib Shared library name 130 * 131 * c pkg comment 132 * 133 * d pkg List of dependencies 134 * dk pkg_dep dependency lock status 135 * dn pkg_dep dependency name 136 * do pkg_dep dependency origin 137 * dv pkg_dep dependency version 138 * 139 * e pkg Package description 140 * 141 * f 142 * g 143 * h 144 * i 145 * j 146 * 147 * k pkg lock status 148 * l pkg license logic 149 * m pkg maintainer 150 * n pkg name 151 * o pkg origin 152 * p pkg prefix 153 * q pkg architecture / ABI 154 * r pkg List of requirements 155 * rk pkg_dep requirement lock status 156 * rn pkg_dep requirement name 157 * ro pkg_dep requirement origin 158 * rv pkg_dep requirement version 159 * 160 * s pkg flatsize 161 * t pkg install timestamp 162 * u pkg checksum 163 * v pkg version 164 * w pkg home page URL 165 * 166 * x pkg pkg tarball size 167 * y pkg List of provides 168 * yn pkg_provide name of the provide 169 * 170 * z pkg short checksum 171 */ 172 static xstring *pkg_xstring_vprintf(xstring * restrict buf, const char * restrict format, va_list ap); 173 174 struct pkg_printf_fmt { 175 char fmt_main; 176 char fmt_sub; 177 bool has_trailer; 178 bool struct_pkg; /* or else a sub-type? */ 179 unsigned context; 180 xstring *(*fmt_handler)(xstring *, const void *, 181 struct percent_esc *); 182 }; 183 184 /* 185 * These are in pkg_fmt_t order, which is necessary for the parsing 186 * algorithm. 187 */ 188 189 static const struct pkg_printf_fmt fmt[] = { 190 [PP_PKG_ANNOTATION_NAME] = 191 { 192 'A', 193 'n', 194 false, 195 false, 196 PP_PKG|PP_A, 197 &format_annotation_name, 198 }, 199 [PP_PKG_ANNOTATION_VALUE] = 200 { 201 'A', 202 'v', 203 false, 204 false, 205 PP_PKG|PP_A, 206 &format_annotation_value, 207 }, 208 [PP_PKG_ANNOTATIONS] = 209 { 210 'A', 211 '\0', 212 true, 213 true, 214 PP_PKG, 215 &format_annotations, 216 }, 217 [PP_PKG_SHLIB_REQUIRED_NAME] = 218 { 219 'B', 220 'n', 221 false, 222 false, 223 PP_PKG|PP_B, 224 &format_shlib_name, 225 }, 226 [PP_PKG_SHLIBS_REQUIRED] = 227 { 228 'B', 229 '\0', 230 true, 231 true, 232 PP_PKG, 233 &format_shlibs_required, 234 }, 235 [PP_PKG_CATEGORY_NAME] = 236 { 237 'C', 238 'n', 239 false, 240 false, 241 PP_PKG|PP_C, 242 &format_category_name, 243 }, 244 [PP_PKG_CATEGORIES] = 245 { 246 'C', 247 '\0', 248 true, 249 true, 250 PP_PKG, 251 &format_categories, 252 }, 253 [PP_PKG_DIRECTORY_FFLAGS] = { 254 'D', 255 'f', 256 false, 257 false, 258 PP_PKG|PP_D, 259 &format_directory_fflags, 260 }, 261 [PP_PKG_DIRECTORY_GROUP] = 262 { 263 'D', 264 'g', 265 false, 266 false, 267 PP_PKG|PP_D, 268 &format_directory_group, 269 }, 270 [PP_PKG_DIRECTORY_PATH] = 271 { 272 'D', 273 'n', 274 false, 275 false, 276 PP_PKG|PP_D, 277 &format_directory_path, 278 }, 279 [PP_PKG_DIRECTORY_PERMS] = 280 { 281 'D', 282 'p', 283 false, 284 false, 285 PP_PKG|PP_D, 286 &format_directory_perms, 287 }, 288 [PP_PKG_DIRECTORY_USER] = 289 { 290 'D', 291 'u', 292 false, 293 false, 294 PP_PKG|PP_D, 295 &format_directory_user, 296 }, 297 [PP_PKG_DIRECTORIES] = 298 { 299 'D', 300 '\0', 301 true, 302 true, 303 PP_PKG, 304 &format_directories, 305 }, 306 [PP_PKG_FILE_FFLAGS] = 307 { 308 'F', 309 'f', 310 false, 311 false, 312 PP_PKG|PP_F, 313 &format_file_fflags, 314 }, 315 [PP_PKG_FILE_GROUP] = 316 { 317 'F', 318 'g', 319 false, 320 false, 321 PP_PKG|PP_F, 322 &format_file_group, 323 }, 324 [PP_PKG_FILE_MTIME] = 325 { 326 'F', 327 'l', 328 false, 329 false, 330 PP_PKG|PP_F, 331 &format_file_mtime, 332 }, 333 [PP_PKG_FILE_PATH] = 334 { 335 'F', 336 'n', 337 false, 338 false, 339 PP_PKG|PP_F, 340 &format_file_path, 341 }, 342 [PP_PKG_FILE_PERMS] = 343 { 344 'F', 345 'p', 346 false, 347 false, 348 PP_PKG|PP_F, 349 &format_file_perms, 350 }, 351 [PP_PKG_FILE_SHA256] = 352 { 353 'F', 354 's', 355 false, 356 false, 357 PP_PKG|PP_F, 358 &format_file_sha256, 359 }, 360 [PP_PKG_FILE_SYMLINK_TARGET] = 361 { 362 'F', 363 't', 364 false, 365 false, 366 PP_PKG|PP_F, 367 &format_file_symlink_target, 368 }, 369 [PP_PKG_FILE_USER] = 370 { 371 'F', 372 'u', 373 false, 374 false, 375 PP_PKG|PP_F, 376 &format_file_user, 377 }, 378 [PP_PKG_FILES] = 379 { 380 'F', 381 '\0', 382 true, 383 true, 384 PP_PKG, 385 &format_files, 386 }, 387 [PP_PKG_GROUP_NAME] = 388 { 389 'G', 390 'n', 391 false, 392 false, 393 PP_PKG|PP_G, 394 &format_group_name, 395 }, 396 [PP_PKG_GROUPS] = 397 { 398 'G', 399 '\0', 400 true, 401 true, 402 PP_PKG, 403 &format_groups, 404 }, 405 [PP_ROW_COUNTER] = 406 { 407 'I', 408 '\0', 409 false, 410 false, 411 PP_TRAILER, 412 &format_row_counter, 413 }, 414 [PP_PKG_LICENSE_NAME] = 415 { 416 'L', 417 'n', 418 false, 419 false, 420 PP_PKG|PP_L, 421 &format_license_name, 422 }, 423 [PP_PKG_LICENSES] = 424 { 425 'L', 426 '\0', 427 true, 428 true, 429 PP_PKG, 430 &format_licenses, 431 }, 432 [PP_PKG_MESSAGE] = 433 { 434 'M', 435 '\0', 436 false, 437 true, 438 PP_ALL, 439 &format_message, 440 }, 441 [PP_PKG_REPO_IDENT] = 442 { 443 'N', 444 '\0', 445 false, 446 true, 447 PP_ALL, 448 &format_repo_ident, 449 }, 450 [PP_PKG_OPTION_NAME] = 451 { 452 'O', 453 'n', 454 false, 455 false, 456 PP_PKG|PP_O, 457 &format_option_name, 458 }, 459 [PP_PKG_OPTION_VALUE] = 460 { 461 'O', 462 'v', 463 false, 464 false, 465 PP_PKG|PP_O, 466 &format_option_value, 467 }, 468 [PP_PKG_OPTION_DEFAULT] = 469 { 470 'O', 471 'd', 472 false, 473 false, 474 PP_PKG|PP_O, 475 &format_option_default, 476 }, 477 [PP_PKG_OPTION_DESCRIPTION] = 478 { 479 'O', 480 'D', 481 false, 482 false, 483 PP_PKG|PP_O, 484 &format_option_description, 485 }, 486 [PP_PKG_OPTIONS] = 487 { 488 'O', 489 '\0', 490 true, 491 true, 492 PP_PKG, 493 &format_options, 494 }, 495 [PP_PKG_ALTABI] = 496 { 497 'Q', 498 '\0', 499 false, 500 true, 501 PP_ALL, 502 &format_altabi, 503 }, 504 [PP_PKG_REPO_PATH] = 505 { 506 'R', 507 '\0', 508 false, 509 true, 510 PP_ALL, 511 &format_repo_path, 512 }, 513 [PP_PKG_CHAR_STRING] = 514 { 515 'S', 516 '\0', 517 false, 518 false, 519 PP_PKG, 520 &format_char_string, 521 }, 522 [PP_PKG_USER_NAME] = 523 { 524 'U', 525 'n', 526 false, 527 false, 528 PP_PKG|PP_U, 529 &format_user_name, 530 }, 531 [PP_PKG_USERS] = 532 { 533 'U', 534 '\0', 535 true, 536 true, 537 PP_PKG, 538 &format_users, 539 }, 540 [PP_PKG_OLD_VERSION] = 541 { 542 'V', 543 '\0', 544 false, 545 true, 546 PP_ALL, 547 &format_old_version, 548 }, 549 [PP_PKG_REQUIRED_NAME] = { 550 'Y', 551 'n', 552 false, 553 false, 554 PP_PKG|PP_Y, 555 &format_provide_name, 556 }, 557 [PP_PKG_REQUIRED] = { 558 'Y', 559 '\0', 560 true, 561 true, 562 PP_PKG, 563 &format_required, 564 }, 565 [PP_PKG_AUTOREMOVE] = 566 { 567 'a', 568 '\0', 569 false, 570 true, 571 PP_ALL, 572 &format_autoremove, 573 }, 574 [PP_PKG_SHLIB_PROVIDED_NAME] = 575 { 576 'b', 577 'n', 578 false, 579 false, 580 PP_PKG|PP_b, 581 &format_shlib_name, 582 }, 583 [PP_PKG_SHLIBS_PROVIDED] = 584 { 585 'b', 586 '\0', 587 true, 588 true, 589 PP_PKG, 590 &format_shlibs_provided, 591 }, 592 [PP_PKG_COMMENT] = 593 { 594 'c', 595 '\0', 596 false, 597 true, 598 PP_ALL, 599 &format_comment, 600 }, 601 [PP_PKG_DEPENDENCY_LOCK] = 602 { 603 'd', 604 'k', 605 false, 606 false, 607 PP_PKG|PP_d, 608 &format_dependency_lock, 609 }, 610 [PP_PKG_DEPENDENCY_NAME] = 611 { 612 'd', 613 'n', 614 false, 615 false, 616 PP_PKG|PP_d, 617 &format_dependency_name, 618 }, 619 [PP_PKG_DEPENDENCY_ORIGIN] = 620 { 621 'd', 622 'o', 623 false, 624 false, 625 PP_PKG|PP_d, 626 &format_dependency_origin, 627 }, 628 [PP_PKG_DEPENDENCY_VERSION] = 629 { 630 'd', 631 'v', 632 false, 633 false, 634 PP_PKG|PP_d, 635 &format_dependency_version, 636 }, 637 [PP_PKG_DEPENDENCIES] = 638 { 639 'd', 640 '\0', 641 true, 642 true, 643 PP_PKG, 644 &format_dependencies, 645 }, 646 [PP_PKG_DESCRIPTION] = 647 { 648 'e', 649 '\0', 650 false, 651 true, 652 PP_ALL, 653 &format_description, 654 }, 655 [PP_PKG_LOCK_STATUS] = 656 { 657 'k', 658 '\0', 659 false, 660 true, 661 PP_ALL, 662 &format_lock_status, 663 }, 664 [PP_PKG_LICENSE_LOGIC] = 665 { 666 'l', 667 '\0', 668 false, 669 true, 670 PP_ALL, 671 &format_license_logic, 672 }, 673 [PP_PKG_MAINTAINER] = 674 { 675 'm', 676 '\0', 677 false, 678 true, 679 PP_ALL, 680 &format_maintainer, 681 }, 682 [PP_PKG_NAME] = 683 { 684 'n', 685 '\0', 686 false, 687 true, 688 PP_ALL, 689 &format_name, }, 690 [PP_PKG_ORIGIN] = 691 { 692 'o', 693 '\0', 694 false, 695 true, 696 PP_ALL, 697 &format_origin, 698 }, 699 [PP_PKG_PREFIX] = 700 { 701 'p', 702 '\0', 703 false, 704 true, 705 PP_ALL, 706 &format_prefix, 707 }, 708 [PP_PKG_ARCHITECTURE] = 709 { 710 'q', 711 '\0', 712 false, 713 true, 714 PP_ALL, 715 &format_architecture, 716 }, 717 [PP_PKG_REQUIREMENT_LOCK] = 718 { 719 'r', 720 'k', 721 false, 722 false, 723 PP_PKG|PP_r, 724 &format_dependency_lock, 725 }, 726 [PP_PKG_REQUIREMENT_NAME] = 727 { 728 'r', 729 'n', 730 false, 731 false, 732 PP_PKG|PP_r, 733 &format_dependency_name, 734 }, 735 [PP_PKG_REQUIREMENT_ORIGIN] = 736 { 737 'r', 738 'o', 739 false, 740 false, 741 PP_PKG|PP_r, 742 &format_dependency_origin, 743 }, 744 [PP_PKG_REQUIREMENT_VERSION] = 745 { 746 'r', 747 'v', 748 false, 749 false, 750 PP_PKG|PP_r, 751 &format_dependency_version, 752 }, 753 [PP_PKG_REQUIREMENTS] = 754 { 755 'r', 756 '\0', 757 true, 758 true, 759 PP_PKG, 760 &format_requirements, 761 }, 762 [PP_PKG_FLATSIZE] = 763 { 764 's', 765 '\0', 766 false, 767 true, 768 PP_ALL, 769 &format_flatsize, 770 }, 771 [PP_PKG_INSTALL_TIMESTAMP] = 772 { 773 't', 774 '\0', 775 true, 776 true, 777 PP_ALL, 778 &format_install_tstamp, 779 }, 780 [PP_PKG_CHECKSUM] = 781 { 782 'u', 783 '\0', 784 false, 785 true, 786 PP_ALL, 787 &format_checksum, 788 }, 789 [PP_PKG_VERSION] = 790 { 791 'v', 792 '\0', 793 false, 794 true, 795 PP_ALL, 796 &format_version, 797 }, 798 [PP_PKG_HOME_PAGE] = 799 { 800 'w', 801 '\0', 802 false, 803 true, 804 PP_ALL, 805 &format_home_url, 806 }, 807 [PP_PKG_PKGSIZE] = 808 { 809 'x', 810 '\0', 811 false, 812 true, 813 PP_ALL, 814 &format_pkgsize, 815 }, 816 [PP_PKG_PROVIDED_NAME] = { 817 'y', 818 'n', 819 false, 820 false, 821 PP_PKG|PP_y, 822 &format_provide_name, 823 }, 824 [PP_PKG_PROVIDED] = { 825 'y', 826 '\0', 827 true, 828 true, 829 PP_PKG, 830 &format_provided, 831 }, 832 [PP_PKG_SHORT_CHECKSUM] = 833 { 834 'z', 835 '\0', 836 false, 837 true, 838 PP_ALL, 839 &format_short_checksum, 840 }, 841 [PP_PKG_INT_CHECKSUM] = 842 { 843 'X', 844 '\0', 845 false, 846 true, 847 PP_ALL, 848 &format_int_checksum, 849 }, 850 [PP_LITERAL_PERCENT] = 851 { 852 '%', 853 '\0', 854 false, 855 false, 856 PP_ALL, 857 &format_literal_percent, 858 }, 859 [PP_UNKNOWN] = 860 { 861 '\0', 862 '\0', 863 false, 864 false, 865 PP_ALL, 866 &format_unknown, 867 }, 868 [PP_END_MARKER] = 869 { 870 '\0', 871 '\0', 872 false, 873 false, 874 0, 875 NULL, 876 }, 877 }; 878 879 static xstring * 880 format_fflags(xstring *buf, u_long fflags, struct percent_esc *p) 881 { 882 xstring *ret; 883 884 if (fflags == 0) { 885 ret = string_val(buf, "-", p); 886 } else { 887 #ifdef HAVE_FFLAGSTOSTR 888 char *fflags_str = fflagstostr(fflags); 889 ret = string_val(buf, fflags_str, p); 890 free(fflags_str); 891 #else 892 ret = string_val(buf, "-", p); 893 #endif 894 } 895 return (ret); 896 } 897 898 static xstring * 899 format_time_t(xstring *buf, time_t timestamp, struct percent_esc *p) 900 { 901 fflush(p->item_fmt->fp); 902 if (strlen(p->item_fmt->buf) == 0) 903 return (int_val(buf, timestamp, p)); 904 else { 905 char buffer[1024]; 906 time_t tsv; 907 908 tsv = timestamp; 909 strftime(buffer, sizeof(buffer), p->item_fmt->buf, 910 localtime(&tsv)); 911 fprintf(buf->fp, "%s", buffer); 912 } 913 return (buf); 914 } 915 916 /* 917 * Note: List values -- special behaviour with ? and # modifiers. 918 * Affects %A %B %C %D %F %G %L %O %U %b %d %r 919 * 920 * With ? -- Flag values. Boolean. %?X returns 0 if the %X list is 921 * empty, 1 otherwise. 922 * 923 * With # -- Count values. Integer. %#X returns the number of items in 924 * the %X list. 925 */ 926 927 /* 928 * %A -- Annotations. Free-form tag+value text that can be added to 929 * packages. Optionally accepts per-field format in %{ %| %} Default 930 * %{%An: %Av\n%|%} 931 */ 932 xstring * 933 format_annotations(xstring *buf, const void *data, struct percent_esc *p) 934 { 935 const struct pkg *pkg = data; 936 int count; 937 938 if (p->flags & (PP_ALTERNATE_FORM1|PP_ALTERNATE_FORM2)) { 939 return (list_count(buf, vec_len(&pkg->annotations), p)); 940 } else { 941 set_list_defaults(p, "%An: %Av\n", ""); 942 943 count = 1; 944 fflush(p->sep_fmt->fp); 945 fflush(p->item_fmt->fp); 946 vec_foreach(pkg->annotations, i) { 947 if (count > 1) 948 iterate_item(buf, pkg, p->sep_fmt->buf, 949 pkg->annotations.d[i], count, PP_A); 950 951 iterate_item(buf, pkg, p->item_fmt->buf, 952 pkg->annotations.d[i], count, PP_A); 953 count++; 954 } 955 } 956 return (buf); 957 } 958 959 /* 960 * %An -- Annotation tag name. 961 */ 962 xstring * 963 format_annotation_name(xstring *buf, const void *data, struct percent_esc *p) 964 { 965 const struct pkg_kv *kv = data; 966 967 return (string_val(buf, kv == NULL ? NULL: kv->key, p)); 968 } 969 970 /* 971 * %Av -- Annotation value. 972 */ 973 xstring * 974 format_annotation_value(xstring *buf, const void *data, struct percent_esc *p) 975 { 976 const struct pkg_kv *kv = data; 977 978 return (string_val(buf, kv == NULL ? NULL: kv->value, p)); 979 } 980 981 /* 982 * %B -- Required Shared Libraries. List of shlibs required by 983 * binaries in the pkg. Optionally accepts per-field format in %{ %| 984 * %}. Default %{%Bn\n%|%} 985 */ 986 xstring * 987 format_shlibs_required(xstring *buf, const void *data, struct percent_esc *p) 988 { 989 const struct pkg *pkg = data; 990 991 if (p->flags & (PP_ALTERNATE_FORM1|PP_ALTERNATE_FORM2)) 992 return (list_count(buf, vec_len(&pkg->shlibs_required), p)); 993 else { 994 int count; 995 996 set_list_defaults(p, "%Bn\n", ""); 997 998 count = 1; 999 fflush(p->sep_fmt->fp); 1000 fflush(p->item_fmt->fp); 1001 vec_foreach(pkg->shlibs_required, i) { 1002 if (count > 1) 1003 iterate_item(buf, pkg, p->sep_fmt->buf, 1004 pkg->shlibs_required.d[i], count, PP_B); 1005 1006 iterate_item(buf, pkg, p->item_fmt->buf, 1007 pkg->shlibs_required.d[i], count, PP_B); 1008 count++; 1009 } 1010 } 1011 return (buf); 1012 } 1013 1014 /* 1015 * %Bn -- Required Shared Library name or %bn -- Provided Shared 1016 * Library name 1017 */ 1018 xstring * 1019 format_shlib_name(xstring *buf, const void *data, struct percent_esc *p) 1020 { 1021 const char *shlib = data; 1022 1023 return (string_val(buf, shlib, p)); 1024 } 1025 1026 /* 1027 * %C -- Categories. List of Category names (strings). 1ary category 1028 * is not distinguished -- look at the package origin for that. 1029 * Optionally accepts per-field format in %{ %| %}, where %n is 1030 * replaced by the category name. Default %{%Cn%|, %} 1031 */ 1032 xstring * 1033 format_categories(xstring *buf, const void *data, struct percent_esc *p) 1034 { 1035 const struct pkg *pkg = data; 1036 int count = 0; 1037 1038 if (p->flags & (PP_ALTERNATE_FORM1|PP_ALTERNATE_FORM2)) { 1039 return (list_count(buf, vec_len(&pkg->categories), p)); 1040 } else { 1041 set_list_defaults(p, "%Cn", ", "); 1042 1043 count = 1; 1044 fflush(p->sep_fmt->fp); 1045 fflush(p->item_fmt->fp); 1046 vec_foreach(pkg->categories, i) { 1047 if (count > 1) 1048 iterate_item(buf, pkg, p->sep_fmt->buf, 1049 pkg->categories.d[i], count, PP_C); 1050 1051 iterate_item(buf, pkg, p->item_fmt->buf, pkg->categories.d[i], 1052 count, PP_C); 1053 count++; 1054 } 1055 } 1056 return (buf); 1057 } 1058 1059 /* 1060 * %Cn -- Category name. 1061 */ 1062 xstring * 1063 format_category_name(xstring *buf, const void *data, struct percent_esc *p) 1064 { 1065 const char *cat = data; 1066 1067 return (string_val(buf, cat, p)); 1068 } 1069 1070 /* 1071 * %D -- Directories. List of directory names (strings) possibly with 1072 * other meta-data. Optionally accepts following per-field format in 1073 * %{ %| %}, where %Dn is replaced by the directory name. Default 1074 * %{%Dn\n%|%} 1075 */ 1076 xstring * 1077 format_directories(xstring *buf, const void *data, struct percent_esc *p) 1078 { 1079 const struct pkg *pkg = data; 1080 1081 if (p->flags & (PP_ALTERNATE_FORM1|PP_ALTERNATE_FORM2)) 1082 return (list_count(buf, pkg_list_count(pkg, PKG_DIRS), p)); 1083 else { 1084 struct pkg_dir *dir = NULL; 1085 int count; 1086 1087 set_list_defaults(p, "%Dn\n", ""); 1088 1089 count = 1; 1090 fflush(p->sep_fmt->fp); 1091 fflush(p->item_fmt->fp); 1092 while (pkg_dirs(pkg, &dir) == EPKG_OK) { 1093 if (count > 1) 1094 iterate_item(buf, pkg, p->sep_fmt->buf, 1095 dir, count, PP_D); 1096 1097 iterate_item(buf, pkg, p->item_fmt->buf, 1098 dir, count, PP_D); 1099 count++; 1100 } 1101 } 1102 return (buf); 1103 } 1104 1105 /* 1106 * %Df -- Directory flags. 1107 */ 1108 xstring * 1109 format_directory_fflags(xstring *buf, const void *data, struct percent_esc *p) 1110 { 1111 const struct pkg_dir *dir = data; 1112 return (format_fflags(buf, dir->fflags, p)); 1113 } 1114 1115 1116 /* 1117 * %Dg -- Directory group. TODO: numeric gid 1118 */ 1119 xstring * 1120 format_directory_group(xstring *buf, const void *data, 1121 struct percent_esc *p) 1122 { 1123 const struct pkg_dir *dir = data; 1124 1125 return (string_val(buf, dir == NULL ? NULL: dir->gname, p)); 1126 } 1127 1128 /* 1129 * %Dn -- Directory path name. 1130 */ 1131 xstring * 1132 format_directory_path(xstring *buf, const void *data, struct percent_esc *p) 1133 { 1134 const struct pkg_dir *dir = data; 1135 1136 return (string_val(buf, dir == NULL ? NULL: dir->path, p)); 1137 } 1138 1139 /* 1140 * %Dp -- Directory permissions. 1141 */ 1142 xstring * 1143 format_directory_perms(xstring *buf, const void *data, 1144 struct percent_esc *p) 1145 { 1146 const struct pkg_dir *dir = data; 1147 1148 return (mode_val(buf, dir->perm, p)); 1149 } 1150 1151 /* 1152 * %Du -- Directory user. TODO: numeric UID 1153 */ 1154 xstring * 1155 format_directory_user(xstring *buf, const void *data, 1156 struct percent_esc *p) 1157 { 1158 const struct pkg_dir *dir = data; 1159 1160 return (string_val(buf, dir == NULL ? NULL: dir->uname, p)); 1161 } 1162 1163 /* 1164 * %F -- Files. List of filenames (strings) possibly with other 1165 * meta-data. Optionally accepts following per-field format in %{ %| 1166 * %}, where %n is replaced by the filename, %s by the checksum, etc. 1167 * Default %{%Fn\n%|%} 1168 */ 1169 xstring * 1170 format_files(xstring *buf, const void *data, struct percent_esc *p) 1171 { 1172 const struct pkg *pkg = data; 1173 1174 if (p->flags & (PP_ALTERNATE_FORM1|PP_ALTERNATE_FORM2)) 1175 return (list_count(buf, pkg_list_count(pkg, PKG_FILES), p)); 1176 else { 1177 struct pkg_file *file = NULL; 1178 int count; 1179 1180 set_list_defaults(p, "%Fn\n", ""); 1181 1182 count = 1; 1183 fflush(p->sep_fmt->fp); 1184 fflush(p->item_fmt->fp); 1185 LL_FOREACH(pkg->files, file) { 1186 if (count > 1) 1187 iterate_item(buf, pkg, p->sep_fmt->buf, 1188 file, count, PP_F); 1189 1190 iterate_item(buf, pkg, p->item_fmt->buf, 1191 file, count, PP_F); 1192 count++; 1193 } 1194 } 1195 return (buf); 1196 } 1197 1198 /* 1199 * %Fm -- File modification time. 1200 */ 1201 xstring * 1202 format_file_mtime(xstring *buf, const void *data, struct percent_esc *p) 1203 { 1204 const struct pkg_file *file = data; 1205 1206 return (format_time_t(buf, file->time[1].tv_sec, p)); 1207 } 1208 1209 /* 1210 * %Fg -- File group. 1211 */ 1212 xstring * 1213 format_file_group(xstring *buf, const void *data, struct percent_esc *p) 1214 { 1215 const struct pkg_file *file = data; 1216 1217 return (string_val(buf, file == NULL ? NULL: file->gname, p)); 1218 } 1219 1220 /* 1221 * %Fn -- File path name. 1222 */ 1223 xstring * 1224 format_file_path(xstring *buf, const void *data, struct percent_esc *p) 1225 { 1226 const struct pkg_file *file = data; 1227 1228 return (string_val(buf, file == NULL ? NULL: file->path, p)); 1229 } 1230 1231 /* 1232 * %Fp -- File permissions. 1233 */ 1234 xstring * 1235 format_file_perms(xstring *buf, const void *data, struct percent_esc *p) 1236 { 1237 const struct pkg_file *file = data; 1238 1239 return (mode_val(buf, file->perm, p)); 1240 } 1241 1242 /* 1243 * %Fs -- File SHA256 Checksum. 1244 */ 1245 xstring * 1246 format_file_sha256(xstring *buf, const void *data, struct percent_esc *p) 1247 { 1248 const struct pkg_file *file = data; 1249 1250 return (string_val(buf, file == NULL ? NULL: file->sum, p)); 1251 } 1252 1253 /* 1254 * %Ft -- File symlink target. 1255 */ 1256 xstring * 1257 format_file_symlink_target(xstring *buf, const void *data, struct percent_esc *p) 1258 { 1259 const struct pkg_file *file = data; 1260 return (string_val(buf, file == NULL ? NULL: file->symlink_target ? file->symlink_target : "", p)); 1261 } 1262 1263 /* 1264 * %Fu -- File user. 1265 */ 1266 xstring * 1267 format_file_user(xstring *buf, const void *data, struct percent_esc *p) 1268 { 1269 const struct pkg_file *file = data; 1270 1271 return (string_val(buf, file == NULL ? NULL: file->uname, p)); 1272 } 1273 1274 /* 1275 * %Ff -- File fflags. 1276 */ 1277 xstring * 1278 format_file_fflags(xstring *buf, const void *data, struct percent_esc *p) 1279 { 1280 const struct pkg_file *file = data; 1281 return (format_fflags(buf, file->fflags, p)); 1282 } 1283 1284 /* 1285 * %G -- Groups. list of string values. Optionally accepts following 1286 * per-field format in %{ %| %} where %Gn will be replaced by each 1287 * groupname or %#Gn by the gid -- a line from 1288 * /etc/group. Default %{%Gn\n%|%} 1289 */ 1290 xstring * 1291 format_groups(xstring *buf, const void *data, struct percent_esc *p) 1292 { 1293 const struct pkg *pkg = data; 1294 1295 if (p->flags & (PP_ALTERNATE_FORM1|PP_ALTERNATE_FORM2)) 1296 return (list_count(buf, vec_len(&pkg->groups), p)); 1297 else { 1298 int count; 1299 1300 set_list_defaults(p, "%Gn\n", ""); 1301 1302 count = 1; 1303 fflush(p->sep_fmt->fp); 1304 fflush(p->item_fmt->fp); 1305 vec_foreach(pkg->groups, i) { 1306 if (count > 1) 1307 iterate_item(buf, pkg, p->sep_fmt->buf, 1308 pkg->groups.d[i], count, PP_G); 1309 1310 iterate_item(buf, pkg,p->item_fmt->buf, 1311 pkg->groups.d[i], count, PP_G); 1312 count++; 1313 } 1314 } 1315 return (buf); 1316 } 1317 1318 /* 1319 * %Gn -- Group name. 1320 */ 1321 xstring * 1322 format_group_name(xstring *buf, const void *data, struct percent_esc *p) 1323 { 1324 const char *group = data; 1325 1326 return (string_val(buf, group, p)); 1327 } 1328 1329 /* 1330 * %I -- Row counter (integer*). Usually used only in per-field format. 1331 */ 1332 xstring * 1333 format_row_counter(xstring *buf, const void *data, struct percent_esc *p) 1334 { 1335 const int *counter = data; 1336 1337 return (int_val(buf, *counter, p)); 1338 } 1339 1340 /* 1341 * %L -- Licences. List of string values. Optionally accepts 1342 * following per-field format in %{ %| %} where %Ln is replaced by the 1343 * license name and %l by the license logic. Default %{%n%| %l %} 1344 */ 1345 xstring * 1346 format_licenses(xstring *buf, const void *data, struct percent_esc *p) 1347 { 1348 const struct pkg *pkg = data; 1349 int count = 0; 1350 1351 if (p->flags & (PP_ALTERNATE_FORM1|PP_ALTERNATE_FORM2)) { 1352 return (list_count(buf, vec_len(&pkg->licenses), p)); 1353 } else { 1354 set_list_defaults(p, "%Ln", " %l "); 1355 1356 count = 1; 1357 fflush(p->sep_fmt->fp); 1358 fflush(p->item_fmt->fp); 1359 vec_foreach(pkg->licenses, i) { 1360 if (count > 1) 1361 iterate_item(buf, pkg, p->sep_fmt->buf, 1362 pkg->licenses.d[i], count, PP_L); 1363 1364 iterate_item(buf, pkg, p->item_fmt->buf, pkg->licenses.d[i], 1365 count, PP_L); 1366 count++; 1367 } 1368 } 1369 return (buf); 1370 } 1371 1372 /* 1373 * %Ln -- License name. 1374 */ 1375 xstring * 1376 format_license_name(xstring *buf, const void *data, struct percent_esc *p) 1377 { 1378 const char *lic = data; 1379 1380 return (string_val(buf, lic, p)); 1381 } 1382 1383 /* 1384 * %M -- Pkg message. string. Accepts field-width, left-align 1385 */ 1386 xstring * 1387 format_message(xstring *buffer, const void *data, struct percent_esc *p) 1388 { 1389 xstring *buf, *bufmsg = NULL; 1390 const struct pkg *pkg = data; 1391 struct pkg_message *msg; 1392 char *message; 1393 1394 vec_foreach(pkg->message, i) { 1395 msg = pkg->message.d[i]; 1396 if (bufmsg == NULL) { 1397 bufmsg = xstring_new(); 1398 } else { 1399 fputc('\n', bufmsg->fp); 1400 } 1401 switch(msg->type) { 1402 case PKG_MESSAGE_ALWAYS: 1403 fprintf(bufmsg->fp, "Always:\n"); 1404 break; 1405 case PKG_MESSAGE_UPGRADE: 1406 fprintf(bufmsg->fp, "On upgrade"); 1407 if (msg->minimum_version != NULL || 1408 msg->maximum_version != NULL) { 1409 fprintf(bufmsg->fp, " from %s", pkg->name); 1410 } 1411 if (msg->minimum_version != NULL) { 1412 fprintf(bufmsg->fp, ">%s", msg->minimum_version); 1413 } 1414 if (msg->maximum_version != NULL) { 1415 fprintf(bufmsg->fp, "<%s", msg->maximum_version); 1416 } 1417 fprintf(bufmsg->fp, ":\n"); 1418 break; 1419 case PKG_MESSAGE_INSTALL: 1420 fprintf(bufmsg->fp, "On install:\n"); 1421 break; 1422 case PKG_MESSAGE_REMOVE: 1423 fprintf(bufmsg->fp, "On remove:\n"); 1424 break; 1425 } 1426 fprintf(bufmsg->fp, "%s\n", msg->str); 1427 } 1428 if (bufmsg == NULL) 1429 message = NULL; 1430 else { 1431 fflush(bufmsg->fp); 1432 message = bufmsg->buf; 1433 } 1434 1435 buf = string_val(buffer, message, p); 1436 xstring_free(bufmsg); 1437 1438 return (buf); 1439 } 1440 1441 /* 1442 * %N -- Repository identity. string. Accepts field-width, left-align 1443 */ 1444 xstring * 1445 format_repo_ident(xstring *buf, const void *data, struct percent_esc *p) 1446 { 1447 const struct pkg *pkg = data; 1448 const char *reponame; 1449 1450 reponame = pkg->reponame; 1451 if (reponame == NULL) { 1452 reponame = pkg_kv_get(&pkg->annotations, "repository"); 1453 if (reponame == NULL) 1454 reponame = "unknown-repository"; 1455 } 1456 return (string_val(buf, reponame, p)); 1457 } 1458 1459 /* 1460 * %O -- Options. list of {option,value} tuples. Optionally accepts 1461 * following per-field format in %{ %| %}, where %On is replaced by the 1462 * option name and %Ov by the value. Default %{%On %Ov\n%|%} 1463 */ 1464 xstring * 1465 format_options(xstring *buf, const void *data, struct percent_esc *p) 1466 { 1467 const struct pkg *pkg = data; 1468 1469 if (p->flags & (PP_ALTERNATE_FORM1|PP_ALTERNATE_FORM2)) 1470 return (list_count(buf, pkg_list_count(pkg, PKG_OPTIONS), p)); 1471 else { 1472 struct pkg_option *opt = NULL; 1473 int count; 1474 1475 set_list_defaults(p, "%On %Ov\n", ""); 1476 1477 count = 1; 1478 fflush(p->sep_fmt->fp); 1479 fflush(p->item_fmt->fp); 1480 while (pkg_options(pkg, &opt) == EPKG_OK) { 1481 if (count > 1) 1482 iterate_item(buf, pkg, p->sep_fmt->buf, 1483 opt, count, PP_O); 1484 1485 iterate_item(buf, pkg, p->item_fmt->buf, 1486 opt, count, PP_O); 1487 count++; 1488 } 1489 } 1490 return (buf); 1491 } 1492 1493 /* 1494 * %On -- Option name. 1495 */ 1496 xstring * 1497 format_option_name(xstring *buf, const void *data, struct percent_esc *p) 1498 { 1499 const struct pkg_option *option = data; 1500 1501 return (string_val(buf, option == NULL ? NULL: option->key, p)); 1502 } 1503 1504 /* 1505 * %Ov -- Option value. 1506 */ 1507 xstring * 1508 format_option_value(xstring *buf, const void *data, struct percent_esc *p) 1509 { 1510 const struct pkg_option *option = data; 1511 1512 return (string_val(buf, option == NULL ? NULL: option->value, p)); 1513 } 1514 1515 /* 1516 * %Od -- Option default value. 1517 */ 1518 xstring * 1519 format_option_default(xstring *buf, const void *data, struct percent_esc *p) 1520 { 1521 const struct pkg_option *option = data; 1522 1523 return (string_val(buf, option == NULL ? NULL: option->value, p)); 1524 } 1525 1526 /* 1527 * %OD -- Option description 1528 */ 1529 xstring * 1530 format_option_description(xstring *buf, const void *data, struct percent_esc *p) 1531 { 1532 const struct pkg_option *option = data; 1533 1534 return (string_val(buf, option == NULL ? NULL: option->description, p)); 1535 } 1536 1537 /* 1538 * %Q -- pkg architecture a.k.a ABI string. Accepts field-width, left-align 1539 */ 1540 xstring * 1541 format_altabi(xstring *buf, const void *data, struct percent_esc *p) 1542 { 1543 const struct pkg *pkg = data; 1544 1545 return (string_val(buf, pkg == NULL ? NULL: pkg->altabi, p)); 1546 } 1547 1548 /* 1549 * %R -- Repo path. string. 1550 */ 1551 xstring * 1552 format_repo_path(xstring *buf, const void *data, struct percent_esc *p) 1553 { 1554 const struct pkg *pkg = data; 1555 1556 return (string_val(buf, pkg == NULL ? NULL: pkg->repopath, p)); 1557 } 1558 1559 /* 1560 * %S -- Character string. 1561 */ 1562 xstring * 1563 format_char_string(xstring *buf, const void *data, struct percent_esc *p) 1564 { 1565 const char *charstring = data; 1566 1567 return (string_val(buf, charstring, p)); 1568 } 1569 1570 /* 1571 * %U -- Users. list of string values. Optionally accepts following 1572 * per-field format in %{ %| %} where %Un will be replaced by each 1573 * username or %#Un by the uid -- a line from 1574 * /etc/passwd. Default %{%Un\n%|%} 1575 */ 1576 xstring * 1577 format_users(xstring *buf, const void *data, struct percent_esc *p) 1578 { 1579 const struct pkg *pkg = data; 1580 1581 if (p->flags & (PP_ALTERNATE_FORM1|PP_ALTERNATE_FORM2)) 1582 return (list_count(buf, vec_len(&pkg->users), p)); 1583 else { 1584 int count; 1585 1586 set_list_defaults(p, "%Un\n", ""); 1587 1588 count = 1; 1589 fflush(p->sep_fmt->fp); 1590 fflush(p->item_fmt->fp); 1591 vec_foreach(pkg->users, i) { 1592 if (count > 1) 1593 iterate_item(buf, pkg, p->sep_fmt->buf, 1594 pkg->users.d[i], count, PP_U); 1595 1596 iterate_item(buf, pkg, p->item_fmt->buf, 1597 pkg->users.d[i], count, PP_U); 1598 count++; 1599 } 1600 } 1601 return (buf); 1602 } 1603 1604 /* 1605 * %Un -- User name. 1606 */ 1607 xstring * 1608 format_user_name(xstring *buf, const void *data, struct percent_esc *p) 1609 { 1610 const char *user = data; 1611 1612 return (string_val(buf, user, p)); 1613 } 1614 1615 /* 1616 * %V -- Old package version. string. Accepts field width, left align 1617 */ 1618 xstring * 1619 format_old_version(xstring *buf, const void *data, struct percent_esc *p) 1620 { 1621 const struct pkg *pkg = data; 1622 1623 return (string_val(buf, pkg == NULL ? NULL: pkg->old_version, p)); 1624 } 1625 1626 /* 1627 * %X -- Package checksum. string. Accepts field width, left align 1628 */ 1629 xstring * 1630 format_int_checksum(xstring *buf, const void *data, struct percent_esc *p) 1631 { 1632 struct pkg *pkg = (struct pkg *)data; 1633 1634 pkg_checksum_calculate(pkg, NULL, true, false, true); 1635 return (string_val(buf, pkg == NULL ? NULL: pkg->digest, p)); 1636 } 1637 1638 /* 1639 * %Y -- Required pattern. List of pattern required by 1640 * binaries in the pkg. Optionally accepts per-field format in %{ %| 1641 * %}. Default %{%Yn\nr->item*/ 1642 xstring * 1643 format_required(xstring *buf, const void *data, struct percent_esc *p) 1644 { 1645 const struct pkg *pkg = data; 1646 1647 if (p->flags & (PP_ALTERNATE_FORM1|PP_ALTERNATE_FORM2)) 1648 return (list_count(buf, vec_len(&pkg->requires), p)); 1649 else { 1650 int count; 1651 1652 set_list_defaults(p, "%Yn\n", ""); 1653 1654 count = 1; 1655 fflush(p->sep_fmt->fp); 1656 fflush(p->item_fmt->fp); 1657 vec_foreach(pkg->requires, i) { 1658 if (count > 1) 1659 iterate_item(buf, pkg, p->sep_fmt->buf, 1660 pkg->requires.d[i], count, PP_Y); 1661 1662 iterate_item(buf, pkg, p->item_fmt->buf, 1663 pkg->requires.d[i], count, PP_Y); 1664 count++; 1665 } 1666 } 1667 return (buf); 1668 } 1669 1670 /* 1671 * %Yn -- Required name or %yn -- Provided name 1672 */ 1673 xstring * 1674 format_provide_name(xstring *buf, const void *data, struct percent_esc *p) 1675 { 1676 const char *provide = data; 1677 1678 return (string_val(buf, provide, p)); 1679 } 1680 /* 1681 * %a -- Autoremove flag. boolean. Accepts field-width, left-align. 1682 * Standard form: 0, 1. Alternate form1: no, yes. Alternate form2: 1683 * false, true 1684 */ 1685 xstring * 1686 format_autoremove(xstring *buf, const void *data, struct percent_esc *p) 1687 { 1688 const struct pkg *pkg = data; 1689 1690 return (bool_val(buf, pkg->automatic, p)); 1691 } 1692 1693 1694 /* 1695 * %b -- Provided Shared Libraries. List of shlibs provided by 1696 * binaries in the pkg. Optionally accepts per-field format in %{ %| 1697 * %}, where %n is replaced by the shlib name. Default %{%bn\n%|%} 1698 */ 1699 xstring * 1700 format_shlibs_provided(xstring *buf, const void *data, struct percent_esc *p) 1701 { 1702 const struct pkg *pkg = data; 1703 1704 if (p->flags & (PP_ALTERNATE_FORM1|PP_ALTERNATE_FORM2)) 1705 return (list_count(buf, vec_len(&pkg->shlibs_provided), p)); 1706 else { 1707 int count; 1708 1709 set_list_defaults(p, "%bn\n", ""); 1710 1711 count = 1; 1712 fflush(p->sep_fmt->fp); 1713 fflush(p->item_fmt->fp); 1714 vec_foreach(pkg->shlibs_provided, i) { 1715 if (count > 1) 1716 iterate_item(buf, pkg, p->sep_fmt->buf, 1717 pkg->shlibs_provided.d[i], count, PP_b); 1718 1719 iterate_item(buf, pkg, p->item_fmt->buf, 1720 pkg->shlibs_provided.d[i], count, PP_b); 1721 count++; 1722 } 1723 } 1724 return (buf); 1725 } 1726 1727 /* 1728 * %c -- Comment. string. Accepts field-width, left-align 1729 */ 1730 xstring * 1731 format_comment(xstring *buf, const void *data, struct percent_esc *p) 1732 { 1733 const struct pkg *pkg = data; 1734 1735 return (string_val(buf, pkg == NULL ? NULL: pkg->comment, p)); 1736 } 1737 1738 /* 1739 * %d -- Dependencies. List of pkgs. Can be optionally followed by 1740 * per-field format string in %{ %| %} using any pkg_printf() *scalar* 1741 * formats. Defaults to printing "%dn-%dv\n" for each dependency. 1742 */ 1743 xstring * 1744 format_dependencies(xstring *buf, const void *data, struct percent_esc *p) 1745 { 1746 const struct pkg *pkg = data; 1747 1748 if (p->flags & (PP_ALTERNATE_FORM1|PP_ALTERNATE_FORM2)) 1749 return (list_count(buf, pkg_list_count(pkg, PKG_DEPS), p)); 1750 else { 1751 struct pkg_dep *dep = NULL; 1752 int count; 1753 1754 set_list_defaults(p, "%dn-%dv\n", ""); 1755 1756 count = 1; 1757 fflush(p->sep_fmt->fp); 1758 fflush(p->item_fmt->fp); 1759 while (pkg_deps(pkg, &dep) == EPKG_OK) { 1760 if (count > 1) 1761 iterate_item(buf, pkg, p->sep_fmt->buf, 1762 dep, count, PP_d); 1763 1764 iterate_item(buf, pkg, p->item_fmt->buf, 1765 dep, count, PP_d); 1766 count++; 1767 } 1768 } 1769 return (buf); 1770 } 1771 1772 /* 1773 * %dk -- Dependency lock status or %rk -- Requirement lock status. 1774 */ 1775 xstring * 1776 format_dependency_lock(xstring *buf, const void *data, 1777 struct percent_esc *p) 1778 { 1779 const struct pkg_dep *dep = data; 1780 1781 return (bool_val(buf, pkg_dep_is_locked(dep), p)); 1782 } 1783 1784 /* 1785 * %dn -- Dependency name or %rn -- Requirement name. 1786 */ 1787 xstring * 1788 format_dependency_name(xstring *buf, const void *data, 1789 struct percent_esc *p) 1790 { 1791 const struct pkg_dep *dep = data; 1792 1793 return (string_val(buf, dep == NULL ? NULL : dep->name, p)); 1794 } 1795 1796 /* 1797 * %do -- Dependency origin or %ro -- Requirement origin. 1798 */ 1799 xstring * 1800 format_dependency_origin(xstring *buf, const void *data, 1801 struct percent_esc *p) 1802 { 1803 const struct pkg_dep *dep = data; 1804 1805 return (string_val(buf, dep == NULL ? NULL: dep->origin, p)); 1806 } 1807 1808 /* 1809 * %dv -- Dependency version or %rv -- Requirement version. 1810 */ 1811 xstring * 1812 format_dependency_version(xstring *buf, const void *data, 1813 struct percent_esc *p) 1814 { 1815 const struct pkg_dep *dep = data; 1816 1817 return (string_val(buf, dep == NULL ? NULL: dep->version, p)); 1818 } 1819 1820 /* 1821 * %e -- Description. string. Accepts field-width, left-align 1822 */ 1823 xstring * 1824 format_description(xstring *buf, const void *data, struct percent_esc *p) 1825 { 1826 const struct pkg *pkg = data; 1827 1828 return (string_val(buf, pkg == NULL ? NULL: pkg->desc, p)); 1829 } 1830 1831 /* 1832 * %k -- Locked flag. boolean. Accepts field-width, left-align. 1833 * Standard form: 0, 1. Alternate form1: no, yes. Alternate form2: 1834 * false, true 1835 */ 1836 xstring * 1837 format_lock_status(xstring *buf, const void *data, struct percent_esc *p) 1838 { 1839 const struct pkg *pkg = data; 1840 1841 return (bool_val(buf, pkg->locked, p)); 1842 } 1843 1844 /* 1845 * %l -- Licence logic. string. Accepts field-width, left-align. 1846 * Standard form: and, or, single. Alternate form 1: &, |, ''. 1847 * Alternate form 2: &&, ||, == 1848 */ 1849 xstring * 1850 format_license_logic(xstring *buf, const void *data, struct percent_esc *p) 1851 { 1852 const struct pkg *pkg = data; 1853 1854 return (liclog_val(buf, pkg->licenselogic, p)); 1855 } 1856 1857 /* 1858 * %m -- Maintainer e-mail address. string. Accepts field-width, left-align 1859 */ 1860 xstring * 1861 format_maintainer(xstring *buf, const void *data, struct percent_esc *p) 1862 { 1863 const struct pkg *pkg = data; 1864 1865 return (string_val(buf, pkg == NULL ? NULL: pkg->maintainer, p)); 1866 } 1867 1868 /* 1869 * %n -- Package name. string. Accepts field-width, left-align 1870 */ 1871 xstring * 1872 format_name(xstring *buf, const void *data, struct percent_esc *p) 1873 { 1874 const struct pkg *pkg = data; 1875 1876 return (string_val(buf, pkg == NULL ? NULL: pkg->name, p)); 1877 } 1878 1879 /* 1880 * %o -- Package origin. string. Accepts field-width, left-align 1881 */ 1882 xstring * 1883 format_origin(xstring *buf, const void *data, struct percent_esc *p) 1884 { 1885 const struct pkg *pkg = data; 1886 1887 return (string_val(buf, pkg == NULL ? NULL: pkg->origin, p)); 1888 } 1889 1890 /* 1891 * %p -- Installation prefix. string. Accepts field-width, left-align 1892 */ 1893 xstring * 1894 format_prefix(xstring *buf, const void *data, struct percent_esc *p) 1895 { 1896 const struct pkg *pkg = data; 1897 1898 return (string_val(buf, pkg == NULL ? NULL: pkg->prefix, p)); 1899 } 1900 1901 /* 1902 * %q -- pkg architecture a.k.a ABI string. Accepts field-width, left-align 1903 */ 1904 xstring * 1905 format_architecture(xstring *buf, const void *data, struct percent_esc *p) 1906 { 1907 const struct pkg *pkg = data; 1908 1909 return (string_val(buf, pkg == NULL ? NULL: pkg->abi, p)); 1910 } 1911 1912 /* 1913 * %r -- Requirements. List of pkgs. Can be optionally followed by 1914 * per-field format string in %{ %| %} using any pkg_printf() *scalar* 1915 * formats. Defaults to printing "%{%rn-%rv\n%|%}" for each dependency. 1916 */ 1917 xstring * 1918 format_requirements(xstring *buf, const void *data, struct percent_esc *p) 1919 { 1920 const struct pkg *pkg = data; 1921 1922 if (p->flags & (PP_ALTERNATE_FORM1|PP_ALTERNATE_FORM2)) 1923 return(list_count(buf, pkg_list_count(pkg, PKG_RDEPS), p)); 1924 else { 1925 struct pkg_dep *req = NULL; 1926 int count; 1927 1928 set_list_defaults(p, "%rn-%rv\n", ""); 1929 1930 count = 1; 1931 fflush(p->sep_fmt->fp); 1932 fflush(p->item_fmt->fp); 1933 while (pkg_rdeps(pkg, &req) == EPKG_OK) { 1934 if (count > 1) 1935 iterate_item(buf, pkg, p->sep_fmt->buf, 1936 req, count, PP_r); 1937 1938 iterate_item(buf, pkg, p->item_fmt->buf, 1939 req, count, PP_r); 1940 count++; 1941 } 1942 } 1943 return (buf); 1944 } 1945 1946 /* 1947 * %s -- Size of installed package. integer. Accepts field-width, 1948 * left-align, zero-fill, space-for-plus, explicit-plus and 1949 * alternate-form. Alternate form is a humanized number using decimal 1950 * exponents (k, M, G). Alternate form 2, ditto, but using binary 1951 * scale prefixes (ki, Mi, Gi etc.) 1952 */ 1953 xstring * 1954 format_flatsize(xstring *buf, const void *data, struct percent_esc *p) 1955 { 1956 const struct pkg *pkg = data; 1957 1958 return (int_val(buf, pkg->flatsize, p)); 1959 } 1960 1961 /* 1962 * %t -- Installation timestamp (Unix time). integer. Accepts 1963 * field-width, left-align. Can be followed by optional strftime 1964 * format string in %{ %}. Default is to print seconds-since-epoch as 1965 * an integer applying our integer format modifiers. 1966 */ 1967 xstring * 1968 format_install_tstamp(xstring *buf, const void *data, struct percent_esc *p) 1969 { 1970 const struct pkg *pkg = data; 1971 1972 return (format_time_t(buf, pkg->timestamp, p)); 1973 } 1974 1975 /* 1976 * %v -- Package version. string. Accepts field width, left align 1977 */ 1978 xstring * 1979 format_version(xstring *buf, const void *data, struct percent_esc *p) 1980 { 1981 const struct pkg *pkg = data; 1982 1983 return (string_val(buf, pkg == NULL ? NULL: pkg->version, p)); 1984 } 1985 1986 /* 1987 * %u -- Package checksum. string. Accepts field width, left align 1988 */ 1989 xstring * 1990 format_checksum(xstring *buf, const void *data, struct percent_esc *p) 1991 { 1992 const struct pkg *pkg = data; 1993 1994 return (string_val(buf, pkg == NULL ? NULL: pkg->sum, p)); 1995 } 1996 1997 /* 1998 * %w -- Home page URL. string. Accepts field width, left align 1999 */ 2000 xstring * 2001 format_home_url(xstring *buf, const void *data, struct percent_esc *p) 2002 { 2003 const struct pkg *pkg = data; 2004 2005 return (string_val(buf, pkg == NULL ? NULL: pkg->www, p)); 2006 } 2007 2008 /* 2009 * %x - Package tarball size. Integer. Accepts field-width, 2010 * left-align, zero-fill, space-for-plus, explicit-plus and 2011 * alternate-form. Alternate form is a humanized number using decimal 2012 * exponents (k, M, G). Alternate form 2, ditto, but using binary 2013 * scale prefixes (ki, Mi, Gi etc.) 2014 */ 2015 xstring * 2016 format_pkgsize(xstring *buf, const void *data, struct percent_esc *p) 2017 { 2018 const struct pkg *pkg = data; 2019 2020 return (int_val(buf, pkg->pkgsize, p)); 2021 } 2022 2023 /* 2024 * %y -- Provided pattern. List of pattern provided by 2025 * binaries in the pkg. Optionally accepts per-field format in %{ %| 2026 * %}. Default %{%yn\n%|%} 2027 */ 2028 xstring * 2029 format_provided(xstring *buf, const void *data, struct percent_esc *p) 2030 { 2031 const struct pkg *pkg = data; 2032 2033 if (p->flags & (PP_ALTERNATE_FORM1|PP_ALTERNATE_FORM2)) 2034 return (list_count(buf, vec_len(&pkg->provides), p)); 2035 else { 2036 int count; 2037 2038 set_list_defaults(p, "%yn\n", ""); 2039 2040 count = 1; 2041 fflush(p->sep_fmt->fp); 2042 fflush(p->item_fmt->fp); 2043 vec_foreach(pkg->provides, i) { 2044 if (count > 1) 2045 iterate_item(buf, pkg, p->sep_fmt->buf, 2046 pkg->provides.d[i], count, PP_y); 2047 2048 iterate_item(buf, pkg, p->item_fmt->buf, 2049 pkg->provides.d[i], count, PP_y); 2050 count++; 2051 } 2052 } 2053 return (buf); 2054 } 2055 2056 /* 2057 * %z -- Package short checksum. string. Accepts field width, left align 2058 */ 2059 xstring * 2060 format_short_checksum(xstring *buf, const void *data, struct percent_esc *p) 2061 { 2062 const struct pkg *pkg = data; 2063 char csum[PKG_FILE_CKSUM_CHARS + 1]; 2064 int slen; 2065 2066 if (pkg->sum != NULL) 2067 slen = MIN(PKG_FILE_CKSUM_CHARS, strlen(pkg->sum)); 2068 else 2069 slen = 0; 2070 memcpy(csum, pkg->sum, slen); 2071 csum[slen] = '\0'; 2072 2073 return (string_val(buf, csum, p)); 2074 } 2075 /* 2076 * %% -- Output a literal '%' character 2077 */ 2078 xstring * 2079 format_literal_percent(xstring *buf, __unused const void *data, 2080 __unused struct percent_esc *p) 2081 { 2082 fputc('%', buf->fp); 2083 return (buf); 2084 } 2085 2086 /* 2087 * Unknown format code -- return NULL to signal upper layers to pass 2088 * the text through unchanged. 2089 */ 2090 xstring * 2091 format_unknown(xstring *buf, __unused const void *data, 2092 __unused struct percent_esc *p) 2093 { 2094 fputc('%', buf->fp); 2095 return (NULL); 2096 } 2097 2098 /* -------------------------------------------------------------- */ 2099 2100 struct percent_esc * 2101 new_percent_esc(void) 2102 { 2103 struct percent_esc *p; 2104 2105 p = xcalloc(1, sizeof(struct percent_esc)); 2106 p->item_fmt = xstring_new(); 2107 p->sep_fmt = xstring_new(); 2108 return (p); 2109 } 2110 2111 struct percent_esc * 2112 clear_percent_esc(struct percent_esc *p) 2113 { 2114 p->flags = 0; 2115 p->width = 0; 2116 p->trailer_status = 0; 2117 xstring_reset(p->item_fmt); 2118 xstring_reset(p->sep_fmt); 2119 2120 p->fmt_code = '\0'; 2121 2122 return (p); 2123 } 2124 2125 void 2126 free_percent_esc(struct percent_esc *p) 2127 { 2128 if (p) { 2129 if (p->item_fmt) 2130 xstring_free(p->item_fmt); 2131 if (p->sep_fmt) 2132 xstring_free(p->sep_fmt); 2133 free(p); 2134 } 2135 return; 2136 } 2137 2138 char * 2139 gen_format(char *buf, size_t buflen, unsigned flags, const char *tail) 2140 { 2141 int bp = 0; 2142 size_t tlen; 2143 2144 /* We need the length of tail plus at least 3 characters '%' 2145 '*' '\0' but maybe as many as 7 '%' '#' '-' '+' '\'' '*' 2146 '\0' */ 2147 2148 tlen = strlen(tail); 2149 2150 if (buflen - bp < tlen + 3) 2151 return (NULL); 2152 2153 buf[bp++] = '%'; 2154 2155 /* PP_ALTERNATE_FORM1 is not used by regular printf(3) */ 2156 2157 /* If PP_EXPLICIT_PLUS and PP_SPACE_FOR_PLUS are both set, 2158 the result is formatted according to PP_EXPLICIT_PLUS */ 2159 2160 if ((flags & (PP_EXPLICIT_PLUS|PP_SPACE_FOR_PLUS)) == 2161 (PP_EXPLICIT_PLUS|PP_SPACE_FOR_PLUS)) 2162 flags &= ~(PP_SPACE_FOR_PLUS); 2163 2164 /* If PP_LEFT_ALIGN and PP_ZERO_PAD are given together, 2165 PP_LEFT_ALIGN applies */ 2166 2167 if ((flags & (PP_LEFT_ALIGN|PP_ZERO_PAD)) == 2168 (PP_LEFT_ALIGN|PP_ZERO_PAD)) 2169 flags &= ~(PP_ZERO_PAD); 2170 2171 if (flags & PP_ALTERNATE_FORM2) 2172 buf[bp++] = '#'; 2173 2174 if (flags & PP_LEFT_ALIGN) 2175 buf[bp++] = '-'; 2176 2177 if (flags & PP_ZERO_PAD) 2178 buf[bp++] = '0'; 2179 2180 if (buflen - bp < tlen + 2) 2181 return (NULL); 2182 2183 if (flags & PP_EXPLICIT_PLUS) 2184 buf[bp++] = '+'; 2185 2186 if (flags & PP_SPACE_FOR_PLUS) 2187 buf[bp++] = ' '; 2188 2189 if (flags & PP_THOUSANDS_SEP) 2190 buf[bp++] = '\''; 2191 2192 if (buflen - bp < tlen + 2) 2193 return (NULL); 2194 2195 /* The effect of 0 meaning 'zero fill' is indisinguishable 2196 from 0 meaning 'a field width of zero' */ 2197 2198 buf[bp++] = '*'; 2199 buf[bp] = '\0'; 2200 2201 strlcat(buf, tail, buflen); 2202 2203 return (buf); 2204 } 2205 2206 2207 xstring * 2208 human_number(xstring *buf, int64_t number, struct percent_esc *p) 2209 { 2210 double num; 2211 int sign; 2212 int width; 2213 int scale_width; 2214 int divisor; 2215 int scale; 2216 int precision; 2217 bool bin_scale; 2218 2219 #define MAXSCALE 7 2220 2221 const char *bin_pfx[MAXSCALE] = 2222 { "", "Ki", "Mi", "Gi", "Ti", "Pi", "Ei" }; 2223 const char *si_pfx[MAXSCALE] = 2224 { "", "k", "M", "G", "T", "P", "E" }; 2225 char format[16]; 2226 2227 bin_scale = ((p->flags & PP_ALTERNATE_FORM2) != 0); 2228 2229 p->flags &= ~(PP_ALTERNATE_FORM1|PP_ALTERNATE_FORM2); 2230 2231 if (gen_format(format, sizeof(format), p->flags, ".*f") == NULL) 2232 return (NULL); 2233 2234 if (number >= 0) { 2235 num = number; 2236 sign = 1; 2237 } else { 2238 num = -number; 2239 sign = -1; 2240 } 2241 2242 divisor = bin_scale ? 1024 : 1000; 2243 2244 for (scale = 0; scale < MAXSCALE; scale++) { 2245 if (num < divisor) 2246 break; 2247 num /= divisor; 2248 } 2249 2250 if (scale == MAXSCALE) 2251 scale--; 2252 2253 if (scale == 0) 2254 scale_width = 0; 2255 else if (bin_scale) 2256 scale_width = 2; 2257 else 2258 scale_width = 1; 2259 2260 if (p->width == 0) 2261 width = 0; 2262 else if (p->width <= scale_width) 2263 width = 1; 2264 else 2265 width = p->width - scale_width; 2266 2267 if (num >= 100) 2268 precision = 0; 2269 else if (num >= 10) { 2270 if (width == 0 || width > 3) 2271 precision = 1; 2272 else 2273 precision = 0; 2274 } else { 2275 if (width == 0 || width > 3) 2276 precision = 2; 2277 else if (width == 3) 2278 precision = 1; 2279 else 2280 precision = 0; 2281 } 2282 2283 fprintf(buf->fp, format, width, precision, num * sign); 2284 2285 if (scale > 0) 2286 fprintf(buf->fp, "%s", 2287 bin_scale ? bin_pfx[scale] : si_pfx[scale]); 2288 2289 return (buf); 2290 } 2291 2292 xstring * 2293 string_val(xstring *buf, const char *str, struct percent_esc *p) 2294 { 2295 char format[16]; 2296 2297 /* The '#' '?' '+' ' ' '0' and '\'' modifiers have no meaning 2298 for strings */ 2299 2300 p->flags &= ~(PP_ALTERNATE_FORM1 | 2301 PP_ALTERNATE_FORM2 | 2302 PP_EXPLICIT_PLUS | 2303 PP_SPACE_FOR_PLUS | 2304 PP_ZERO_PAD | 2305 PP_THOUSANDS_SEP); 2306 2307 if (gen_format(format, sizeof(format), p->flags, "s") == NULL) 2308 return (NULL); 2309 2310 fprintf(buf->fp, format, p->width, str == NULL ? "" : str); 2311 return (buf); 2312 } 2313 2314 xstring * 2315 int_val(xstring *buf, int64_t value, struct percent_esc *p) 2316 { 2317 if (p->flags & (PP_ALTERNATE_FORM1|PP_ALTERNATE_FORM2)) 2318 return (human_number(buf, value, p)); 2319 else { 2320 char format[16]; 2321 2322 if (gen_format(format, sizeof(format), p->flags, PRId64) 2323 == NULL) 2324 return (NULL); 2325 2326 fprintf(buf->fp, format, p->width, value); 2327 } 2328 return (buf); 2329 } 2330 2331 xstring * 2332 bool_val(xstring *buf, bool value, struct percent_esc *p) 2333 { 2334 static const char *boolean_str[2][3] = { 2335 [false] = { "false", "no", "" }, 2336 [true] = { "true", "yes", "(*)" }, 2337 }; 2338 int alternate; 2339 2340 if (p->flags & PP_ALTERNATE_FORM2) 2341 alternate = 2; 2342 else if (p->flags & PP_ALTERNATE_FORM1) 2343 alternate = 1; 2344 else 2345 alternate = 0; 2346 2347 p->flags &= ~(PP_ALTERNATE_FORM1|PP_ALTERNATE_FORM2); 2348 2349 return (string_val(buf, boolean_str[value][alternate], p)); 2350 } 2351 2352 xstring * 2353 mode_val(xstring *buf, mode_t mode, struct percent_esc *p) 2354 { 2355 /* 2356 * Print mode as an octal integer '%o' by default. 2357 * PP_ALTERNATE_FORM2 generates '%#o' pased to regular 2358 * printf(). PP_ALTERNATE_FORM1 will generate 'drwxr-x--- ' 2359 * style from strmode(3). 2360 */ 2361 2362 if (p->flags & PP_ALTERNATE_FORM1) { 2363 char modebuf[12]; 2364 2365 strmode(mode, modebuf); 2366 2367 return (string_val(buf, modebuf, p)); 2368 } else { 2369 char format[16]; 2370 2371 /* 2372 * Should the mode when expressed as a numeric value 2373 * in octal include the bits that indicate the inode 2374 * type? Generally no, but since mode is 2375 * intrinsically an unsigned type, overload 2376 * PP_EXPLICIT_PLUS to mean 'show bits for the inode 2377 * type' 2378 */ 2379 2380 if ( (p->flags & PP_EXPLICIT_PLUS) == 0 ) 2381 mode &= ALLPERMS; 2382 2383 p->flags &= ~(PP_ALTERNATE_FORM1|PP_EXPLICIT_PLUS); 2384 2385 if (gen_format(format, sizeof(format), p->flags, PRIo16) 2386 == NULL) 2387 return (NULL); 2388 2389 fprintf(buf->fp, format, p->width, mode); 2390 } 2391 return (buf); 2392 } 2393 2394 xstring * 2395 liclog_val(xstring *buf, lic_t licenselogic, struct percent_esc *p) 2396 { 2397 int alternate; 2398 int llogic = PP_LIC_SINGLE; 2399 2400 static const char *liclog_str[3][3] = { 2401 [PP_LIC_SINGLE] = { "single", "", "==" }, 2402 [PP_LIC_OR] = { "or", "|", "||" }, 2403 [PP_LIC_AND] = { "and", "&", "&&" }, 2404 }; 2405 2406 switch (licenselogic) { 2407 case LICENSE_SINGLE: 2408 llogic = PP_LIC_SINGLE; 2409 break; 2410 case LICENSE_OR: 2411 llogic = PP_LIC_OR; 2412 break; 2413 case LICENSE_AND: 2414 llogic = PP_LIC_AND; 2415 break; 2416 } 2417 2418 if (p->flags & PP_ALTERNATE_FORM2) 2419 alternate = 2; 2420 else if (p->flags & PP_ALTERNATE_FORM1) 2421 alternate = 1; 2422 else 2423 alternate = 0; 2424 2425 p->flags &= ~(PP_ALTERNATE_FORM1|PP_ALTERNATE_FORM2); 2426 2427 return (string_val(buf, liclog_str[llogic][alternate], p)); 2428 } 2429 2430 xstring * 2431 list_count(xstring *buf, int64_t count, struct percent_esc *p) 2432 { 2433 /* Convert to 0 or 1 for %?X */ 2434 if (p->flags & PP_ALTERNATE_FORM1) 2435 count = (count > 0); 2436 2437 /* Turn off %#X and %?X flags, then print as a normal integer */ 2438 p->flags &= ~(PP_ALTERNATE_FORM1|PP_ALTERNATE_FORM2); 2439 2440 return (int_val(buf, count, p)); 2441 } 2442 2443 struct percent_esc * 2444 set_list_defaults(struct percent_esc *p, const char *item_fmt, 2445 const char *sep_fmt) 2446 { 2447 if ((p->trailer_status & ITEM_FMT_SET) != ITEM_FMT_SET) { 2448 fprintf(p->item_fmt->fp, "%s", item_fmt); 2449 p->trailer_status |= ITEM_FMT_SET; 2450 } 2451 if ((p->trailer_status & SEP_FMT_SET) != SEP_FMT_SET) { 2452 fprintf(p->sep_fmt->fp, "%s", sep_fmt); 2453 p->trailer_status |= SEP_FMT_SET; 2454 } 2455 return (p); 2456 } 2457 2458 xstring * 2459 iterate_item(xstring *buf, const struct pkg *pkg, const char *format, 2460 const void *data, int count, unsigned context) 2461 { 2462 const char *f; 2463 struct percent_esc *p; 2464 2465 /* Scan the format string and interpret any escapes */ 2466 2467 f = format; 2468 p = new_percent_esc(); 2469 2470 if (p == NULL) { 2471 xstring_reset(buf); 2472 return (buf); /* Out of memory */ 2473 } 2474 2475 while ( *f != '\0' ) { 2476 switch(*f) { 2477 case '%': 2478 f = process_format_trailer(buf, p, f, pkg, data, count, context); 2479 break; 2480 case '\\': 2481 f = process_escape(buf, f); 2482 break; 2483 default: 2484 fprintf(buf->fp, "%c", *f); 2485 f++; 2486 break; 2487 } 2488 if (f == NULL) { 2489 xstring_reset(buf); 2490 break; /* Out of memory */ 2491 } 2492 } 2493 2494 free_percent_esc(p); 2495 return (buf); 2496 } 2497 2498 const char * 2499 field_modifier(const char *f, struct percent_esc *p) 2500 { 2501 bool done; 2502 2503 /* Field modifiers, if any: 2504 '?' alternate form 1 2505 '#' alternate form 2 2506 '-' left align 2507 '+' explicit plus sign (numerics only) 2508 ' ' space instead of plus sign (numerics only) 2509 '0' pad with zeroes (numerics only) 2510 '\'' use thousands separator (numerics only) 2511 Note '*' (dynamic field width) is not supported */ 2512 2513 done = false; 2514 while (!done) { 2515 switch (*f) { 2516 case '?': 2517 p->flags |= PP_ALTERNATE_FORM1; 2518 break; 2519 case '#': 2520 p->flags |= PP_ALTERNATE_FORM2; 2521 break; 2522 case '-': 2523 p->flags |= PP_LEFT_ALIGN; 2524 break; 2525 case '+': 2526 p->flags |= PP_EXPLICIT_PLUS; 2527 break; 2528 case ' ': 2529 p->flags |= PP_SPACE_FOR_PLUS; 2530 break; 2531 case '0': 2532 p->flags |= PP_ZERO_PAD; 2533 break; 2534 case '\'': 2535 p->flags |= PP_THOUSANDS_SEP; 2536 break; 2537 default: 2538 done = true; 2539 break; 2540 } 2541 if (!done) 2542 f++; 2543 } 2544 return (f); 2545 } 2546 2547 const char * 2548 field_width(const char *f, struct percent_esc *p) 2549 { 2550 bool done; 2551 2552 /* Field width, if any -- some number of decimal digits. 2553 Note: field width set to zero could be interpreted as using 2554 0 to request zero padding: it doesn't matter which -- the 2555 result on output is exactly the same. */ 2556 2557 done = false; 2558 while (!done) { 2559 switch(*f) { 2560 case '0': 2561 p->width = p->width * 10 + 0; 2562 break; 2563 case '1': 2564 p->width = p->width * 10 + 1; 2565 break; 2566 case '2': 2567 p->width = p->width * 10 + 2; 2568 break; 2569 case '3': 2570 p->width = p->width * 10 + 3; 2571 break; 2572 case '4': 2573 p->width = p->width * 10 + 4; 2574 break; 2575 case '5': 2576 p->width = p->width * 10 + 5; 2577 break; 2578 case '6': 2579 p->width = p->width * 10 + 6; 2580 break; 2581 case '7': 2582 p->width = p->width * 10 + 7; 2583 break; 2584 case '8': 2585 p->width = p->width * 10 + 8; 2586 break; 2587 case '9': 2588 p->width = p->width * 10 + 9; 2589 break; 2590 default: 2591 done = true; 2592 break; 2593 } 2594 if (!done) 2595 f++; 2596 } 2597 return (f); 2598 } 2599 2600 const char * 2601 format_trailer(const char *f, struct percent_esc *p) 2602 { 2603 2604 /* is the trailer even present? */ 2605 2606 if (f[0] == '%' && f[1] == '{') { 2607 bool sep = false; 2608 bool done = false; 2609 const char *f1; 2610 const char *f2; 2611 2612 p->trailer_status |= ITEM_FMT_SET; 2613 f1 = f + 2; 2614 2615 for (f2 = f1; *f2 != '\0'; f2++) { 2616 if (f2[0] == '%' && ( f2[1] == '}' || f2[1] == '|')) { 2617 if (f2[1] == '|') 2618 sep = true; 2619 else 2620 done = true; 2621 f1 = f2 + 2; 2622 break; 2623 } 2624 fputc(*f2, p->item_fmt->fp); 2625 fflush(p->item_fmt->fp); 2626 } 2627 2628 2629 if (sep) { 2630 p->trailer_status |= SEP_FMT_SET; 2631 done = false; 2632 2633 for (f2 = f1; *f2 != '\0'; f2++) { 2634 if (f2[0] == '%' && f2[1] == '}') { 2635 done = true; 2636 f1 = f2 + 2; 2637 break; 2638 } 2639 fputc(*f2, p->sep_fmt->fp); 2640 fflush(p->sep_fmt->fp); 2641 } 2642 2643 } 2644 2645 if (done) { 2646 f = f1; 2647 } else { 2648 xstring_reset(p->item_fmt); 2649 xstring_reset(p->sep_fmt); 2650 } 2651 } 2652 2653 return (f); 2654 } 2655 2656 const char * 2657 format_code(const char *f, unsigned context, struct percent_esc *p) 2658 { 2659 fmt_code_t fmt_code; 2660 2661 p->fmt_code = PP_UNKNOWN; /* Assume unknown, for contradiction */ 2662 2663 /* The next character or two will be a format code -- look 2664 these up in the fmt table to make sure they are allowed in 2665 context. This could be optimized since the format codes 2666 are arranged alphabetically in the fmt[] array. */ 2667 2668 for (fmt_code = 0; fmt_code < PP_END_MARKER; fmt_code++) { 2669 if ((fmt[fmt_code].context & context) != context) 2670 continue; 2671 if (fmt[fmt_code].fmt_main != f[0]) 2672 continue; 2673 if (fmt[fmt_code].fmt_sub == f[1] && f[1] != '\0') { 2674 p->fmt_code = fmt_code; 2675 f += 2; 2676 break; 2677 } 2678 if (fmt[fmt_code].fmt_sub == '\0') { 2679 p->fmt_code = fmt_code; 2680 f++; 2681 break; 2682 } 2683 } 2684 2685 return (f); 2686 } 2687 2688 const char * 2689 parse_format(const char *f, unsigned context, struct percent_esc *p) 2690 { 2691 f++; /* Eat the % */ 2692 2693 f = field_modifier(f, p); 2694 2695 f = field_width(f, p); 2696 2697 f = format_code(f, context, p); 2698 2699 /* Does this format take a trailing list item/separator format 2700 like %{...%|...%} ? It's only the list-valued items that 2701 do, and they can only take it at the top level (context == 2702 PP_PKG). Also, they only take the trailing stuff in the 2703 absence of %?X or %#X modifiers. */ 2704 2705 if ((context & PP_PKG) == PP_PKG && 2706 fmt[p->fmt_code].has_trailer && 2707 (p->flags & (PP_ALTERNATE_FORM1|PP_ALTERNATE_FORM2)) == 0) 2708 f = format_trailer(f, p); 2709 2710 return (f); 2711 } 2712 2713 const char* 2714 maybe_read_hex_byte(xstring *buf, const char *f) 2715 { 2716 /* Hex escapes are of the form \xNN -- always two hex digits */ 2717 2718 f++; /* eat the x */ 2719 2720 if (isxdigit(f[0]) && isxdigit(f[1])) { 2721 int val; 2722 2723 switch(*f) { 2724 case '0': 2725 val = 0x0; 2726 break; 2727 case '1': 2728 val = 0x10; 2729 break; 2730 case '2': 2731 val = 0x20; 2732 break; 2733 case '3': 2734 val = 0x30; 2735 break; 2736 case '4': 2737 val = 0x40; 2738 break; 2739 case '5': 2740 val = 0x50; 2741 break; 2742 case '6': 2743 val = 0x60; 2744 break; 2745 case '7': 2746 val = 0x70; 2747 break; 2748 case '8': 2749 val = 0x80; 2750 break; 2751 case '9': 2752 val = 0x90; 2753 break; 2754 case 'a': 2755 case 'A': 2756 val = 0xa0; 2757 break; 2758 case 'b': 2759 case 'B': 2760 val = 0xb0; 2761 break; 2762 case 'c': 2763 case 'C': 2764 val = 0xc0; 2765 break; 2766 case 'd': 2767 case 'D': 2768 val = 0xd0; 2769 break; 2770 case 'e': 2771 case 'E': 2772 val = 0xe0; 2773 break; 2774 case 'f': 2775 case 'F': 2776 val = 0xf0; 2777 break; 2778 default: 2779 /* This case is to shut up the over-picky 2780 * compiler warnings about use of an 2781 * uninitialised value. It can't actually 2782 * be reached. */ 2783 val = 0x0; 2784 break; 2785 } 2786 2787 f++; 2788 2789 switch(*f) { 2790 case '0': 2791 val += 0x0; 2792 break; 2793 case '1': 2794 val += 0x1; 2795 break; 2796 case '2': 2797 val += 0x2; 2798 break; 2799 case '3': 2800 val += 0x3; 2801 break; 2802 case '4': 2803 val += 0x4; 2804 break; 2805 case '5': 2806 val += 0x5; 2807 break; 2808 case '6': 2809 val += 0x6; 2810 break; 2811 case '7': 2812 val += 0x7; 2813 break; 2814 case '8': 2815 val += 0x8; 2816 break; 2817 case '9': 2818 val += 0x9; 2819 break; 2820 case 'a': 2821 case 'A': 2822 val += 0xa; 2823 break; 2824 case 'b': 2825 case 'B': 2826 val += 0xb; 2827 break; 2828 case 'c': 2829 case 'C': 2830 val += 0xc; 2831 break; 2832 case 'd': 2833 case 'D': 2834 val += 0xd; 2835 break; 2836 case 'e': 2837 case 'E': 2838 val += 0xe; 2839 break; 2840 case 'f': 2841 case 'F': 2842 val += 0xf; 2843 break; 2844 } 2845 2846 fputc(val, buf->fp); 2847 f++; 2848 } else { 2849 /* Pass through unchanged if it's not a recognizable 2850 hex byte. */ 2851 fputc('\\', buf->fp); 2852 fputc('x', buf->fp); 2853 } 2854 return (f); 2855 } 2856 2857 const char* 2858 read_oct_byte(xstring *buf, const char *f) 2859 { 2860 int val = 0; 2861 int count = 0; 2862 2863 /* Octal escapes are upto three octal digits: \N, \NN or \NNN 2864 up to a max of \377. Note: this treats \400 as \40 2865 followed by character 0 passed through unchanged. */ 2866 2867 while (val < 32 && count++ < 3) { 2868 switch (*f) { 2869 case '0': 2870 val = val * 8 + 0; 2871 break; 2872 case '1': 2873 val = val * 8 + 1; 2874 break; 2875 case '2': 2876 val = val * 8 + 2; 2877 break; 2878 case '3': 2879 val = val * 8 + 3; 2880 break; 2881 case '4': 2882 val = val * 8 + 4; 2883 break; 2884 case '5': 2885 val = val * 8 + 5; 2886 break; 2887 case '6': 2888 val = val * 8 + 6; 2889 break; 2890 case '7': 2891 val = val * 8 + 7; 2892 break; 2893 default: /* Non-octal digit */ 2894 goto done; 2895 } 2896 2897 f++; 2898 } 2899 done: 2900 fputc(val, buf->fp); 2901 2902 return (f); 2903 } 2904 2905 const char * 2906 process_escape(xstring *buf, const char *f) 2907 { 2908 f++; /* Eat the \ */ 2909 2910 switch (*f) { 2911 case 'a': 2912 fputc('\a', buf->fp); 2913 f++; 2914 break; 2915 case 'b': 2916 fputc('\b', buf->fp); 2917 f++; 2918 break; 2919 case 'f': 2920 fputc('\f', buf->fp); 2921 f++; 2922 break; 2923 case 'n': 2924 fputc('\n', buf->fp); 2925 f++; 2926 break; 2927 case 't': 2928 fputc('\t', buf->fp); 2929 f++; 2930 break; 2931 case 'v': 2932 fputc('\v', buf->fp); 2933 f++; 2934 break; 2935 case '\'': 2936 fputc('\'', buf->fp); 2937 f++; 2938 break; 2939 case '"': 2940 fputc('"', buf->fp); 2941 f++; 2942 break; 2943 case '\\': 2944 fputc('\\', buf->fp); 2945 f++; 2946 break; 2947 case 'x': /* Hex escape: \xNN */ 2948 f = maybe_read_hex_byte(buf, f); 2949 break; 2950 case '0': 2951 case '1': 2952 case '2': 2953 case '3': 2954 case '4': 2955 case '5': 2956 case '6': 2957 case '7': /* Oct escape: all fall through */ 2958 f = read_oct_byte(buf, f); 2959 break; 2960 default: /* If it's not a recognised escape, 2961 leave f pointing at the escaped 2962 character */ 2963 fputc('\\', buf->fp); 2964 break; 2965 } 2966 2967 return (f); 2968 } 2969 2970 const char * 2971 process_format_trailer(xstring *buf, struct percent_esc *p, 2972 const char *f, const struct pkg *pkg, 2973 const void *data, int count, unsigned context) 2974 { 2975 const char *fstart; 2976 xstring *s; 2977 2978 fstart = f; 2979 f = parse_format(f, context, p); 2980 2981 if (p->fmt_code == PP_ROW_COUNTER) 2982 s = fmt[p->fmt_code].fmt_handler(buf, &count, p); 2983 else if (p->fmt_code > PP_LAST_FORMAT) 2984 s = fmt[p->fmt_code].fmt_handler(buf, NULL, p); 2985 else if (fmt[p->fmt_code].struct_pkg) 2986 s = fmt[p->fmt_code].fmt_handler(buf, pkg, p); 2987 else 2988 s = fmt[p->fmt_code].fmt_handler(buf, data, p); 2989 2990 2991 if (s == NULL) { 2992 f = fstart + 1; /* Eat just the % on error */ 2993 } 2994 2995 clear_percent_esc(p); 2996 2997 return (f); 2998 } 2999 3000 const char * 3001 process_format_main(xstring *buf, struct percent_esc *p, 3002 const char *fstart, const char *fend, void *data) 3003 { 3004 xstring *s; 3005 3006 s = fmt[p->fmt_code].fmt_handler(buf, data, p); 3007 3008 clear_percent_esc(p); 3009 3010 /* Pass through unprocessed on error */ 3011 return (s == NULL ? fstart : fend); 3012 } 3013 3014 /** 3015 * print to stdout data from pkg as indicated by the format code format 3016 * @param ... Varargs list of struct pkg etc. supplying the data 3017 * @param format String with embedded %-escapes indicating what to print 3018 * @return count of the number of characters printed 3019 */ 3020 int 3021 pkg_printf(const char * restrict format, ...) 3022 { 3023 int count; 3024 va_list ap; 3025 3026 va_start(ap, format); 3027 count = pkg_vprintf(format, ap); 3028 va_end(ap); 3029 3030 return (count); 3031 } 3032 3033 /** 3034 * print to stdout data from pkg as indicated by the format code format 3035 * @param ap Varargs list of struct pkg etc. supplying the data 3036 * @param format String with embedded %-escapes indicating what to print 3037 * @return count of the number of characters printed 3038 */ 3039 int 3040 pkg_vprintf(const char * restrict format, va_list ap) 3041 { 3042 xstring *buf; 3043 int count; 3044 3045 buf = xstring_new(); 3046 3047 if (buf) 3048 buf = pkg_xstring_vprintf(buf, format, ap); 3049 fflush(buf->fp); 3050 if (buf && strlen(buf->buf) > 0) { 3051 count = printf("%s", buf->buf); 3052 } else 3053 count = -1; 3054 if (buf) 3055 xstring_free(buf); 3056 return (count); 3057 } 3058 3059 /** 3060 * print to named stream from pkg as indicated by the format code format 3061 * @param ... Varargs list of struct pkg etc. supplying the data 3062 * @param format String with embedded %-escapes indicating what to output 3063 * @return count of the number of characters printed 3064 */ 3065 int 3066 pkg_fprintf(FILE * restrict stream, const char * restrict format, ...) 3067 { 3068 int count; 3069 va_list ap; 3070 3071 va_start(ap, format); 3072 count = pkg_vfprintf(stream, format, ap); 3073 va_end(ap); 3074 3075 return (count); 3076 } 3077 3078 /** 3079 * print to named stream from pkg as indicated by the format code format 3080 * @param ap Varargs list of struct pkg etc. supplying the data 3081 * @param format String with embedded %-escapes indicating what to output 3082 * @return count of the number of characters printed 3083 */ 3084 int 3085 pkg_vfprintf(FILE * restrict stream, const char * restrict format, va_list ap) 3086 { 3087 xstring *buf; 3088 int count; 3089 3090 buf = xstring_new(); 3091 3092 if (buf) 3093 buf = pkg_xstring_vprintf(buf, format, ap); 3094 fflush(buf->fp); 3095 if (buf && strlen(buf->buf) > 0) { 3096 count = fprintf(stream, "%s", buf->buf); 3097 } else 3098 count = -1; 3099 if (buf) 3100 xstring_free(buf); 3101 return (count); 3102 } 3103 3104 /** 3105 * print to file descriptor fd data from pkg as indicated by the format 3106 * code format 3107 * @param fd Previously opened file descriptor to print to 3108 * @param ... Varargs list of struct pkg etc. supplying the data 3109 * @param format String with embedded %-escapes indicating what to print 3110 * @return count of the number of characters printed 3111 */ 3112 int 3113 pkg_dprintf(int fd, const char * restrict format, ...) 3114 { 3115 int count; 3116 va_list ap; 3117 3118 va_start(ap, format); 3119 count = pkg_vdprintf(fd, format, ap); 3120 va_end(ap); 3121 3122 return (count); 3123 } 3124 3125 /** 3126 * print to file descriptor fd data from pkg as indicated by the format 3127 * code format 3128 * @param fd Previously opened file descriptor to print to 3129 * @param ap Varargs list of struct pkg etc. supplying the data 3130 * @param format String with embedded %-escapes indicating what to print 3131 * @return count of the number of characters printed 3132 */ 3133 int 3134 pkg_vdprintf(int fd, const char * restrict format, va_list ap) 3135 { 3136 xstring *buf; 3137 int count; 3138 3139 buf = xstring_new(); 3140 3141 if (buf) 3142 buf = pkg_xstring_vprintf(buf, format, ap); 3143 fflush(buf->fp); 3144 if (buf && strlen(buf->buf) > 0) { 3145 count = dprintf(fd, "%s", buf->buf); 3146 } else 3147 count = -1; 3148 if (buf) 3149 xstring_free(buf); 3150 return (count); 3151 } 3152 3153 /** 3154 * print to buffer str of given size data from pkg as indicated by the 3155 * format code format as a NULL-terminated string 3156 * @param str Character array buffer to receive output 3157 * @param size Length of the buffer str 3158 * @param ... Varargs list of struct pkg etc. supplying the data 3159 * @param format String with embedded %-escapes indicating what to output 3160 * @return count of the number of characters that would have been output 3161 * disregarding truncation to fit size 3162 */ 3163 int 3164 pkg_snprintf(char * restrict str, size_t size, const char * restrict format, ...) 3165 { 3166 int count; 3167 va_list ap; 3168 3169 va_start(ap, format); 3170 count = pkg_vsnprintf(str, size, format, ap); 3171 va_end(ap); 3172 3173 return (count); 3174 } 3175 3176 /** 3177 * print to buffer str of given size data from pkg as indicated by the 3178 * format code format as a NULL-terminated string 3179 * @param str Character array buffer to receive output 3180 * @param size Length of the buffer str 3181 * @param ap Varargs list of struct pkg etc. supplying the data 3182 * @param format String with embedded %-escapes indicating what to output 3183 * @return count of the number of characters that would have been output 3184 * disregarding truncation to fit size 3185 */ 3186 int 3187 pkg_vsnprintf(char * restrict str, size_t size, const char * restrict format, 3188 va_list ap) 3189 { 3190 xstring *buf; 3191 int count; 3192 3193 buf = xstring_new(); 3194 3195 if (buf) 3196 buf = pkg_xstring_vprintf(buf, format, ap); 3197 fflush(buf->fp); 3198 if (buf && strlen(buf->buf) > 0) { 3199 count = snprintf(str, size, "%s", buf->buf); 3200 } else 3201 count = -1; 3202 if (buf) 3203 xstring_free(buf); 3204 3205 return (count); 3206 } 3207 3208 /** 3209 * Allocate a string buffer ret sufficiently big to contain formatted 3210 * data data from pkg as indicated by the format code format 3211 * @param ret location of pointer to be set to point to buffer containing 3212 * result 3213 * @param ... Varargs list of struct pkg etc. supplying the data 3214 * @param format String with embedded %-escapes indicating what to output 3215 * @return count of the number of characters printed 3216 */ 3217 int 3218 pkg_asprintf(char **ret, const char * restrict format, ...) 3219 { 3220 int count; 3221 va_list ap; 3222 3223 va_start(ap, format); 3224 count = pkg_vasprintf(ret, format, ap); 3225 va_end(ap); 3226 3227 return (count); 3228 } 3229 3230 /** 3231 * Allocate a string buffer ret sufficiently big to contain formatted 3232 * data data from pkg as indicated by the format code format 3233 * @param ret location of pointer to be set to point to buffer containing 3234 * result 3235 * @param ap Varargs list of struct pkg etc. supplying the data 3236 * @param format String with embedded %-escapes indicating what to output 3237 * @return count of the number of characters printed 3238 */ 3239 int 3240 pkg_vasprintf(char **ret, const char * restrict format, va_list ap) 3241 { 3242 xstring *buf; 3243 int count; 3244 3245 buf = xstring_new(); 3246 3247 if (buf) 3248 buf = pkg_xstring_vprintf(buf, format, ap); 3249 fflush(buf->fp); 3250 if (buf && strlen(buf->buf) > 0) { 3251 count = xasprintf(ret, "%s", buf->buf); 3252 } else { 3253 count = -1; 3254 *ret = NULL; 3255 } 3256 if (buf) 3257 xstring_free(buf); 3258 return (count); 3259 } 3260 3261 /** 3262 * store data from pkg into buf as indicated by the format code format. 3263 * This is the core function called by all the other pkg_printf() family. 3264 * @param buf contains the result 3265 * @param ap Arglist with struct pkg etc. supplying the data 3266 * @param format String with embedded %-escapes indicating what to output 3267 * @return count of the number of characters in the result 3268 */ 3269 static xstring * 3270 pkg_xstring_vprintf(xstring * restrict buf, const char * restrict format, 3271 va_list ap) 3272 { 3273 const char *f, *fend; 3274 struct percent_esc *p; 3275 void *data; 3276 3277 assert(buf != NULL); 3278 assert(format != NULL); 3279 3280 f = format; 3281 p = new_percent_esc(); 3282 3283 if (p == NULL) { 3284 xstring_reset(buf); 3285 return (buf); /* Out of memory */ 3286 } 3287 3288 while ( *f != '\0' ) { 3289 switch(*f) { 3290 case '%': 3291 fend = parse_format(f, PP_PKG, p); 3292 3293 if (p->fmt_code <= PP_LAST_FORMAT) 3294 data = va_arg(ap, void *); 3295 else 3296 data = NULL; 3297 f = process_format_main(buf, p, f, fend, data); 3298 break; 3299 case '\\': 3300 f = process_escape(buf, f); 3301 break; 3302 default: 3303 fputc(*f, buf->fp); 3304 f++; 3305 break; 3306 } 3307 if (f == NULL) { 3308 xstring_reset(buf); 3309 break; /* Error: out of memory */ 3310 } 3311 } 3312 3313 free_percent_esc(p); 3314 return (buf); 3315 } 3316 /* 3317 * That's All Folks! 3318 */