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 : */
|