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