LCOV - code coverage report
Current view: top level - libpkg - pkg_printf.c (source / functions) Hit Total Coverage
Test: cov.info Lines: 277 909 30.5 %
Date: 2015-08-15 Functions: 33 99 33.3 %

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

Generated by: LCOV version 1.10