/ libpkg / pkg_printf.c
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   */