Branch data Line data Source code
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 *
857 : 0 : format_annotations(xstring *buf, const void *data, struct percent_esc *p)
858 : : {
859 : 0 : const struct pkg *pkg = data;
860 : : struct pkg_kv *kv;
861 : : int count;
862 : :
863 [ # # ]: 0 : if (p->flags & (PP_ALTERNATE_FORM1|PP_ALTERNATE_FORM2)) {
864 [ # # ]: 0 : LL_COUNT(pkg->annotations, kv, count);
865 : 0 : return (list_count(buf, count, p));
866 : : } else {
867 : 0 : set_list_defaults(p, "%An: %Av\n", "");
868 : :
869 : 0 : count = 1;
870 : 0 : fflush(p->sep_fmt->fp);
871 : 0 : fflush(p->item_fmt->fp);
872 [ # # ]: 0 : LL_FOREACH(pkg->annotations, kv) {
873 [ # # ]: 0 : if (count > 1)
874 : 0 : iterate_item(buf, pkg, p->sep_fmt->buf,
875 : 0 : kv, count, PP_A);
876 : :
877 : 0 : iterate_item(buf, pkg, p->item_fmt->buf,
878 : 0 : kv, count, PP_A);
879 : 0 : count++;
880 : 0 : }
881 : : }
882 : 0 : return (buf);
883 : 0 : }
884 : :
885 : : /*
886 : : * %An -- Annotation tag name.
887 : : */
888 : : xstring *
889 : 0 : format_annotation_name(xstring *buf, const void *data, struct percent_esc *p)
890 : : {
891 : 0 : const struct pkg_kv *kv = data;
892 : :
893 : 0 : return (string_val(buf, kv->key, p));
894 : : }
895 : :
896 : : /*
897 : : * %Av -- Annotation value.
898 : : */
899 : : xstring *
900 : 0 : format_annotation_value(xstring *buf, const void *data, struct percent_esc *p)
901 : : {
902 : 0 : const struct pkg_kv *kv = data;
903 : :
904 : 0 : 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 *
913 : 0 : format_shlibs_required(xstring *buf, const void *data, struct percent_esc *p)
914 : : {
915 : 0 : const struct pkg *pkg = data;
916 : :
917 [ # # ]: 0 : if (p->flags & (PP_ALTERNATE_FORM1|PP_ALTERNATE_FORM2))
918 : 0 : return (list_count(buf, pkg_list_count(pkg, PKG_SHLIBS_REQUIRED), p));
919 : : else {
920 : : pkghash_it it;
921 : : int count;
922 : :
923 : 0 : set_list_defaults(p, "%Bn\n", "");
924 : :
925 : 0 : count = 1;
926 : 0 : fflush(p->sep_fmt->fp);
927 : 0 : fflush(p->item_fmt->fp);
928 : 0 : it = pkghash_iterator(pkg->shlibs_required);
929 [ # # ]: 0 : while (pkghash_next(&it)) {
930 [ # # ]: 0 : if (count > 1)
931 : 0 : iterate_item(buf, pkg, p->sep_fmt->buf,
932 : 0 : it.key, count, PP_B);
933 : :
934 : 0 : iterate_item(buf, pkg, p->item_fmt->buf,
935 : 0 : it.key, count, PP_B);
936 : 0 : count++;
937 : : }
938 : : }
939 : 0 : return (buf);
940 : 0 : }
941 : :
942 : : /*
943 : : * %Bn -- Required Shared Library name or %bn -- Provided Shared
944 : : * Library name
945 : : */
946 : : xstring *
947 : 0 : format_shlib_name(xstring *buf, const void *data, struct percent_esc *p)
948 : : {
949 : 0 : const char *shlib = data;
950 : :
951 : 0 : return (string_val(buf, shlib, p));
952 : : }
953 : :
954 : : /*
955 : : * %C -- Categories. List of Category names (strings). 1ary category
956 : : * is not distinguished -- look at the package origin for that.
957 : : * Optionally accepts per-field format in %{ %| %}, where %n is
958 : : * replaced by the category name. Default %{%Cn%|, %}
959 : : */
960 : : xstring *
961 : 0 : format_categories(xstring *buf, const void *data, struct percent_esc *p)
962 : : {
963 : 0 : const struct pkg *pkg = data;
964 : 0 : int count = 0;
965 : :
966 [ # # ]: 0 : if (p->flags & (PP_ALTERNATE_FORM1|PP_ALTERNATE_FORM2)) {
967 : 0 : return (list_count(buf, pkg_list_count(pkg, PKG_CATEGORIES), p));
968 : : } else {
969 : 0 : set_list_defaults(p, "%Cn", ", ");
970 : :
971 : 0 : count = 1;
972 : 0 : fflush(p->sep_fmt->fp);
973 : 0 : fflush(p->item_fmt->fp);
974 : 0 : pkghash_it it = pkghash_iterator(pkg->categories);
975 [ # # ]: 0 : while (pkghash_next(&it)) {
976 [ # # ]: 0 : if (count > 1)
977 : 0 : iterate_item(buf, pkg, p->sep_fmt->buf,
978 : 0 : it.key, count, PP_C);
979 : :
980 : 0 : iterate_item(buf, pkg, p->item_fmt->buf, it.key,
981 : 0 : count, PP_C);
982 : 0 : count++;
983 : : }
984 : : }
985 : 0 : return (buf);
986 : 0 : }
987 : :
988 : : /*
989 : : * %Cn -- Category name.
990 : : */
991 : : xstring *
992 : 0 : format_category_name(xstring *buf, const void *data, struct percent_esc *p)
993 : : {
994 : 0 : const char *cat = data;
995 : :
996 : 0 : return (string_val(buf, cat, p));
997 : : }
998 : :
999 : : /*
1000 : : * %D -- Directories. List of directory names (strings) possibly with
1001 : : * other meta-data. Optionally accepts following per-field format in
1002 : : * %{ %| %}, where %Dn is replaced by the directory name. Default
1003 : : * %{%Dn\n%|%}
1004 : : */
1005 : : xstring *
1006 : 0 : format_directories(xstring *buf, const void *data, struct percent_esc *p)
1007 : : {
1008 : 0 : const struct pkg *pkg = data;
1009 : :
1010 [ # # ]: 0 : if (p->flags & (PP_ALTERNATE_FORM1|PP_ALTERNATE_FORM2))
1011 : 0 : return (list_count(buf, pkg_list_count(pkg, PKG_DIRS), p));
1012 : : else {
1013 : 0 : struct pkg_dir *dir = NULL;
1014 : : int count;
1015 : :
1016 : 0 : set_list_defaults(p, "%Dn\n", "");
1017 : :
1018 : 0 : count = 1;
1019 : 0 : fflush(p->sep_fmt->fp);
1020 : 0 : fflush(p->item_fmt->fp);
1021 [ # # ]: 0 : while (pkg_dirs(pkg, &dir) == EPKG_OK) {
1022 [ # # ]: 0 : if (count > 1)
1023 : 0 : iterate_item(buf, pkg, p->sep_fmt->buf,
1024 : 0 : dir, count, PP_D);
1025 : :
1026 : 0 : iterate_item(buf, pkg, p->item_fmt->buf,
1027 : 0 : dir, count, PP_D);
1028 : 0 : count++;
1029 : : }
1030 : : }
1031 : 0 : return (buf);
1032 : 0 : }
1033 : :
1034 : : /*
1035 : : * %Dg -- Directory group. TODO: numeric gid
1036 : : */
1037 : : xstring *
1038 : 0 : format_directory_group(xstring *buf, const void *data,
1039 : : struct percent_esc *p)
1040 : : {
1041 : 0 : const struct pkg_dir *dir = data;
1042 : :
1043 : 0 : return (string_val(buf, dir->gname, p));
1044 : : }
1045 : :
1046 : : /*
1047 : : * %Dn -- Directory path name.
1048 : : */
1049 : : xstring *
1050 : 0 : format_directory_path(xstring *buf, const void *data, struct percent_esc *p)
1051 : : {
1052 : 0 : const struct pkg_dir *dir = data;
1053 : :
1054 : 0 : return (string_val(buf, dir->path, p));
1055 : : }
1056 : :
1057 : : /*
1058 : : * %Dp -- Directory permissions.
1059 : : */
1060 : : xstring *
1061 : 0 : format_directory_perms(xstring *buf, const void *data,
1062 : : struct percent_esc *p)
1063 : : {
1064 : 0 : const struct pkg_dir *dir = data;
1065 : :
1066 : 0 : return (mode_val(buf, dir->perm, p));
1067 : : }
1068 : :
1069 : : /*
1070 : : * %Du -- Directory user. TODO: numeric UID
1071 : : */
1072 : : xstring *
1073 : 0 : format_directory_user(xstring *buf, const void *data,
1074 : : struct percent_esc *p)
1075 : : {
1076 : 0 : const struct pkg_dir *dir = data;
1077 : :
1078 : 0 : return (string_val(buf, dir->uname, p));
1079 : : }
1080 : :
1081 : : /*
1082 : : * %F -- Files. List of filenames (strings) possibly with other
1083 : : * meta-data. Optionally accepts following per-field format in %{ %|
1084 : : * %}, where %n is replaced by the filename, %s by the checksum, etc.
1085 : : * Default %{%Fn\n%|%}
1086 : : */
1087 : : xstring *
1088 : 0 : format_files(xstring *buf, const void *data, struct percent_esc *p)
1089 : : {
1090 : 0 : const struct pkg *pkg = data;
1091 : :
1092 [ # # ]: 0 : if (p->flags & (PP_ALTERNATE_FORM1|PP_ALTERNATE_FORM2))
1093 : 0 : return (list_count(buf, pkg_list_count(pkg, PKG_FILES), p));
1094 : : else {
1095 : 0 : struct pkg_file *file = NULL;
1096 : : int count;
1097 : :
1098 : 0 : set_list_defaults(p, "%Fn\n", "");
1099 : :
1100 : 0 : count = 1;
1101 : 0 : fflush(p->sep_fmt->fp);
1102 : 0 : fflush(p->item_fmt->fp);
1103 [ # # ]: 0 : LL_FOREACH(pkg->files, file) {
1104 [ # # ]: 0 : if (count > 1)
1105 : 0 : iterate_item(buf, pkg, p->sep_fmt->buf,
1106 : 0 : file, count, PP_F);
1107 : :
1108 : 0 : iterate_item(buf, pkg, p->item_fmt->buf,
1109 : 0 : file, count, PP_F);
1110 : 0 : count++;
1111 : 0 : }
1112 : : }
1113 : 0 : return (buf);
1114 : 0 : }
1115 : :
1116 : : /*
1117 : : * %Fg -- File group.
1118 : : */
1119 : : xstring *
1120 : 0 : format_file_group(xstring *buf, const void *data, struct percent_esc *p)
1121 : : {
1122 : 0 : const struct pkg_file *file = data;
1123 : :
1124 : 0 : return (string_val(buf, file->gname, p));
1125 : : }
1126 : :
1127 : : /*
1128 : : * %Fn -- File path name.
1129 : : */
1130 : : xstring *
1131 : 0 : format_file_path(xstring *buf, const void *data, struct percent_esc *p)
1132 : : {
1133 : 0 : const struct pkg_file *file = data;
1134 : :
1135 : 0 : return (string_val(buf, file->path, p));
1136 : : }
1137 : :
1138 : : /*
1139 : : * %Fp -- File permissions.
1140 : : */
1141 : : xstring *
1142 : 0 : format_file_perms(xstring *buf, const void *data, struct percent_esc *p)
1143 : : {
1144 : 0 : const struct pkg_file *file = data;
1145 : :
1146 : 0 : return (mode_val(buf, file->perm, p));
1147 : : }
1148 : :
1149 : : /*
1150 : : * %Fs -- File SHA256 Checksum.
1151 : : */
1152 : : xstring *
1153 : 0 : format_file_sha256(xstring *buf, const void *data, struct percent_esc *p)
1154 : : {
1155 : 0 : const struct pkg_file *file = data;
1156 : :
1157 : 0 : return (string_val(buf, file->sum, p));
1158 : : }
1159 : :
1160 : : /*
1161 : : * %Fu -- File user.
1162 : : */
1163 : : xstring *
1164 : 0 : format_file_user(xstring *buf, const void *data, struct percent_esc *p)
1165 : : {
1166 : 0 : const struct pkg_file *file = data;
1167 : :
1168 : 0 : return (string_val(buf, file->uname, p));
1169 : : }
1170 : :
1171 : : /*
1172 : : * %G -- Groups. list of string values. Optionally accepts following
1173 : : * per-field format in %{ %| %} where %Gn will be replaced by each
1174 : : * groupname or %#Gn by the gid -- a line from
1175 : : * /etc/group. Default %{%Gn\n%|%}
1176 : : */
1177 : : xstring *
1178 : 0 : format_groups(xstring *buf, const void *data, struct percent_esc *p)
1179 : : {
1180 : 0 : const struct pkg *pkg = data;
1181 : :
1182 [ # # ]: 0 : if (p->flags & (PP_ALTERNATE_FORM1|PP_ALTERNATE_FORM2))
1183 : 0 : return (list_count(buf, pkg_list_count(pkg, PKG_GROUPS), p));
1184 : : else {
1185 : : int count;
1186 : :
1187 : 0 : set_list_defaults(p, "%Gn\n", "");
1188 : :
1189 : 0 : count = 1;
1190 : 0 : fflush(p->sep_fmt->fp);
1191 : 0 : fflush(p->item_fmt->fp);
1192 : 0 : pkghash_it it = pkghash_iterator(pkg->users);
1193 [ # # ]: 0 : while (pkghash_next(&it)) {
1194 [ # # ]: 0 : if (count > 1)
1195 : 0 : iterate_item(buf, pkg, p->sep_fmt->buf,
1196 : 0 : it.key, count, PP_G);
1197 : :
1198 : 0 : iterate_item(buf, pkg,p->item_fmt->buf,
1199 : 0 : it.key, count, PP_G);
1200 : 0 : count++;
1201 : : }
1202 : : }
1203 : 0 : return (buf);
1204 : 0 : }
1205 : :
1206 : : /*
1207 : : * %Gn -- Group name.
1208 : : */
1209 : : xstring *
1210 : 0 : format_group_name(xstring *buf, const void *data, struct percent_esc *p)
1211 : : {
1212 : 0 : const char *group = data;
1213 : :
1214 : 0 : return (string_val(buf, group, p));
1215 : : }
1216 : :
1217 : : /*
1218 : : * %I -- Row counter (integer*). Usually used only in per-field format.
1219 : : */
1220 : : xstring *
1221 : 0 : format_row_counter(xstring *buf, const void *data, struct percent_esc *p)
1222 : : {
1223 : 0 : const int *counter = data;
1224 : :
1225 : 0 : return (int_val(buf, *counter, p));
1226 : : }
1227 : :
1228 : : /*
1229 : : * %L -- Licences. List of string values. Optionally accepts
1230 : : * following per-field format in %{ %| %} where %Ln is replaced by the
1231 : : * license name and %l by the license logic. Default %{%n%| %l %}
1232 : : */
1233 : : xstring *
1234 : 0 : format_licenses(xstring *buf, const void *data, struct percent_esc *p)
1235 : : {
1236 : 0 : const struct pkg *pkg = data;
1237 : 0 : int count = 0;
1238 : :
1239 [ # # ]: 0 : if (p->flags & (PP_ALTERNATE_FORM1|PP_ALTERNATE_FORM2)) {
1240 : 0 : return (list_count(buf, pkg_list_count(pkg, PKG_LICENSES), p));
1241 : : } else {
1242 : 0 : set_list_defaults(p, "%Ln", " %l ");
1243 : :
1244 : 0 : count = 1;
1245 : 0 : fflush(p->sep_fmt->fp);
1246 : 0 : fflush(p->item_fmt->fp);
1247 : 0 : pkghash_it it = pkghash_iterator(pkg->licenses);
1248 [ # # ]: 0 : while (pkghash_next(&it)) {
1249 [ # # ]: 0 : if (count > 1)
1250 : 0 : iterate_item(buf, pkg, p->sep_fmt->buf,
1251 : 0 : it.key, count, PP_L);
1252 : :
1253 : 0 : iterate_item(buf, pkg, p->item_fmt->buf, it.key,
1254 : 0 : count, PP_L);
1255 : 0 : count++;
1256 : : }
1257 : : }
1258 : 0 : return (buf);
1259 : 0 : }
1260 : :
1261 : : /*
1262 : : * %Ln -- License name.
1263 : : */
1264 : : xstring *
1265 : 0 : format_license_name(xstring *buf, const void *data, struct percent_esc *p)
1266 : : {
1267 : 0 : const char *lic = data;
1268 : :
1269 : 0 : return (string_val(buf, lic, p));
1270 : : }
1271 : :
1272 : : /*
1273 : : * %M -- Pkg message. string. Accepts field-width, left-align
1274 : : */
1275 : : xstring *
1276 : 0 : format_message(xstring *buffer, const void *data, struct percent_esc *p)
1277 : : {
1278 : 0 : xstring *buf, *bufmsg = NULL;
1279 : 0 : const struct pkg *pkg = data;
1280 : : struct pkg_message *msg;
1281 : : char *message;
1282 : :
1283 [ # # ]: 0 : LL_FOREACH(pkg->message, msg) {
1284 [ # # ]: 0 : if (bufmsg == NULL) {
1285 : 0 : bufmsg = xstring_new();
1286 : 0 : } else {
1287 : 0 : fputc('\n', bufmsg->fp);
1288 : : }
1289 [ # # # # : 0 : switch(msg->type) {
# ]
1290 : : case PKG_MESSAGE_ALWAYS:
1291 : 0 : fprintf(bufmsg->fp, "Always:\n");
1292 : 0 : break;
1293 : : case PKG_MESSAGE_UPGRADE:
1294 : 0 : fprintf(bufmsg->fp, "On upgrade");
1295 [ # # # # ]: 0 : if (msg->minimum_version != NULL ||
1296 : 0 : msg->maximum_version != NULL) {
1297 : 0 : fprintf(bufmsg->fp, " from %s", pkg->name);
1298 : 0 : }
1299 [ # # ]: 0 : if (msg->minimum_version != NULL) {
1300 : 0 : fprintf(bufmsg->fp, ">%s", msg->minimum_version);
1301 : 0 : }
1302 [ # # ]: 0 : if (msg->maximum_version != NULL) {
1303 : 0 : fprintf(bufmsg->fp, "<%s", msg->maximum_version);
1304 : 0 : }
1305 : 0 : fprintf(bufmsg->fp, ":\n");
1306 : 0 : break;
1307 : : case PKG_MESSAGE_INSTALL:
1308 : 0 : fprintf(bufmsg->fp, "On install:\n");
1309 : 0 : break;
1310 : : case PKG_MESSAGE_REMOVE:
1311 : 0 : fprintf(bufmsg->fp, "On remove:\n");
1312 : 0 : break;
1313 : : }
1314 : 0 : fprintf(bufmsg->fp, "%s\n", msg->str);
1315 : 0 : }
1316 [ # # ]: 0 : if (bufmsg == NULL)
1317 : 0 : message = NULL;
1318 : : else {
1319 : 0 : fflush(bufmsg->fp);
1320 : 0 : message = bufmsg->buf;
1321 : : }
1322 : :
1323 : 0 : buf = string_val(buffer, message, p);
1324 : 0 : xstring_free(bufmsg);
1325 : :
1326 : 0 : return (buf);
1327 : : }
1328 : :
1329 : : /*
1330 : : * %N -- Repository identity. string. Accepts field-width, left-align
1331 : : */
1332 : : xstring *
1333 : 0 : format_repo_ident(xstring *buf, const void *data, struct percent_esc *p)
1334 : : {
1335 : 0 : const struct pkg *pkg = data;
1336 : : const char *reponame;
1337 : :
1338 : 0 : reponame = pkg->reponame;
1339 [ # # ]: 0 : if (reponame == NULL) {
1340 : 0 : reponame = pkg_kv_get(&pkg->annotations, "repository");
1341 [ # # ]: 0 : if (reponame == NULL)
1342 : 0 : reponame = "unknown-repository";
1343 : 0 : }
1344 : 0 : return (string_val(buf, reponame, p));
1345 : : }
1346 : :
1347 : : /*
1348 : : * %O -- Options. list of {option,value} tuples. Optionally accepts
1349 : : * following per-field format in %{ %| %}, where %On is replaced by the
1350 : : * option name and %Ov by the value. Default %{%On %Ov\n%|%}
1351 : : */
1352 : : xstring *
1353 : 0 : format_options(xstring *buf, const void *data, struct percent_esc *p)
1354 : : {
1355 : 0 : const struct pkg *pkg = data;
1356 : :
1357 [ # # ]: 0 : if (p->flags & (PP_ALTERNATE_FORM1|PP_ALTERNATE_FORM2))
1358 : 0 : return (list_count(buf, pkg_list_count(pkg, PKG_OPTIONS), p));
1359 : : else {
1360 : 0 : struct pkg_option *opt = NULL;
1361 : : int count;
1362 : :
1363 : 0 : set_list_defaults(p, "%On %Ov\n", "");
1364 : :
1365 : 0 : count = 1;
1366 : 0 : fflush(p->sep_fmt->fp);
1367 : 0 : fflush(p->item_fmt->fp);
1368 [ # # ]: 0 : while (pkg_options(pkg, &opt) == EPKG_OK) {
1369 [ # # ]: 0 : if (count > 1)
1370 : 0 : iterate_item(buf, pkg, p->sep_fmt->buf,
1371 : 0 : opt, count, PP_O);
1372 : :
1373 : 0 : iterate_item(buf, pkg, p->item_fmt->buf,
1374 : 0 : opt, count, PP_O);
1375 : 0 : count++;
1376 : : }
1377 : : }
1378 : 0 : return (buf);
1379 : 0 : }
1380 : :
1381 : : /*
1382 : : * %On -- Option name.
1383 : : */
1384 : : xstring *
1385 : 0 : format_option_name(xstring *buf, const void *data, struct percent_esc *p)
1386 : : {
1387 : 0 : const struct pkg_option *option = data;
1388 : :
1389 : 0 : return (string_val(buf, option->key, p));
1390 : : }
1391 : :
1392 : : /*
1393 : : * %Ov -- Option value.
1394 : : */
1395 : : xstring *
1396 : 0 : format_option_value(xstring *buf, const void *data, struct percent_esc *p)
1397 : : {
1398 : 0 : const struct pkg_option *option = data;
1399 : :
1400 : 0 : return (string_val(buf, option->value, p));
1401 : : }
1402 : :
1403 : : /*
1404 : : * %Od -- Option default value.
1405 : : */
1406 : : xstring *
1407 : 0 : format_option_default(xstring *buf, const void *data, struct percent_esc *p)
1408 : : {
1409 : 0 : const struct pkg_option *option = data;
1410 : :
1411 : 0 : return (string_val(buf, option->value, p));
1412 : : }
1413 : :
1414 : : /*
1415 : : * %OD -- Option description
1416 : : */
1417 : : xstring *
1418 : 0 : format_option_description(xstring *buf, const void *data, struct percent_esc *p)
1419 : : {
1420 : 0 : const struct pkg_option *option = data;
1421 : :
1422 : 0 : return (string_val(buf, option->description, p));
1423 : : }
1424 : :
1425 : : /*
1426 : : * %Q -- pkg architecture a.k.a ABI string. Accepts field-width, left-align
1427 : : */
1428 : : xstring *
1429 : 0 : format_altabi(xstring *buf, const void *data, struct percent_esc *p)
1430 : : {
1431 : 0 : const struct pkg *pkg = data;
1432 : :
1433 : 0 : return (string_val(buf, pkg->arch, p));
1434 : : }
1435 : :
1436 : : /*
1437 : : * %R -- Repo path. string.
1438 : : */
1439 : : xstring *
1440 : 0 : format_repo_path(xstring *buf, const void *data, struct percent_esc *p)
1441 : : {
1442 : 0 : const struct pkg *pkg = data;
1443 : :
1444 : 0 : return (string_val(buf, pkg->repopath, p));
1445 : : }
1446 : :
1447 : : /*
1448 : : * %S -- Character string.
1449 : : */
1450 : : xstring *
1451 : 0 : format_char_string(xstring *buf, const void *data, struct percent_esc *p)
1452 : : {
1453 : 0 : const char *charstring = data;
1454 : :
1455 : 0 : return (string_val(buf, charstring, p));
1456 : : }
1457 : :
1458 : : /*
1459 : : * %U -- Users. list of string values. Optionally accepts following
1460 : : * per-field format in %{ %| %} where %Un will be replaced by each
1461 : : * username or %#Un by the uid -- a line from
1462 : : * /etc/passwd. Default %{%Un\n%|%}
1463 : : */
1464 : : xstring *
1465 : 0 : format_users(xstring *buf, const void *data, struct percent_esc *p)
1466 : : {
1467 : 0 : const struct pkg *pkg = data;
1468 : :
1469 [ # # ]: 0 : if (p->flags & (PP_ALTERNATE_FORM1|PP_ALTERNATE_FORM2))
1470 : 0 : return (list_count(buf, pkg_list_count(pkg, PKG_USERS), p));
1471 : : else {
1472 : : int count;
1473 : :
1474 : 0 : set_list_defaults(p, "%Un\n", "");
1475 : :
1476 : 0 : count = 1;
1477 : 0 : fflush(p->sep_fmt->fp);
1478 : 0 : fflush(p->item_fmt->fp);
1479 : 0 : pkghash_it it = pkghash_iterator(pkg->users);
1480 [ # # ]: 0 : while (pkghash_next(&it)) {
1481 [ # # ]: 0 : if (count > 1)
1482 : 0 : iterate_item(buf, pkg, p->sep_fmt->buf,
1483 : 0 : it.key, count, PP_U);
1484 : :
1485 : 0 : iterate_item(buf, pkg, p->item_fmt->buf,
1486 : 0 : it.key, count, PP_U);
1487 : 0 : count++;
1488 : : }
1489 : : }
1490 : 0 : return (buf);
1491 : 0 : }
1492 : :
1493 : : /*
1494 : : * %Un -- User name.
1495 : : */
1496 : : xstring *
1497 : 0 : format_user_name(xstring *buf, const void *data, struct percent_esc *p)
1498 : : {
1499 : 0 : const char *user = data;
1500 : :
1501 : 0 : return (string_val(buf, user, p));
1502 : : }
1503 : :
1504 : : /*
1505 : : * %V -- Old package version. string. Accepts field width, left align
1506 : : */
1507 : : xstring *
1508 : 0 : format_old_version(xstring *buf, const void *data, struct percent_esc *p)
1509 : : {
1510 : 0 : const struct pkg *pkg = data;
1511 : :
1512 : 0 : return (string_val(buf, pkg->old_version, p));
1513 : : }
1514 : :
1515 : : /*
1516 : : * %X -- Package checksum. string. Accepts field width, left align
1517 : : */
1518 : : xstring *
1519 : 0 : format_int_checksum(xstring *buf, const void *data, struct percent_esc *p)
1520 : : {
1521 : 0 : struct pkg *pkg = (struct pkg *)data;
1522 : :
1523 : 0 : pkg_checksum_calculate(pkg, NULL, true, false, true);
1524 : 0 : return (string_val(buf, pkg->digest, p));
1525 : : }
1526 : :
1527 : : /*
1528 : : * %Y -- Required pattern. List of pattern required by
1529 : : * binaries in the pkg. Optionally accepts per-field format in %{ %|
1530 : : * %}. Default %{%Yn\n%|%}
1531 : : */
1532 : : xstring *
1533 : 0 : format_required(xstring *buf, const void *data, struct percent_esc *p)
1534 : : {
1535 : 0 : const struct pkg *pkg = data;
1536 : :
1537 [ # # ]: 0 : if (p->flags & (PP_ALTERNATE_FORM1|PP_ALTERNATE_FORM2))
1538 : 0 : return (list_count(buf, pkg_list_count(pkg, PKG_REQUIRES), p));
1539 : : else {
1540 : : int count;
1541 : :
1542 : 0 : set_list_defaults(p, "%Yn\n", "");
1543 : :
1544 : 0 : count = 1;
1545 : 0 : fflush(p->sep_fmt->fp);
1546 : 0 : fflush(p->item_fmt->fp);
1547 : 0 : pkghash_it it = pkghash_iterator(pkg->requires);
1548 [ # # ]: 0 : while (pkghash_next(&it)) {
1549 [ # # ]: 0 : if (count > 1)
1550 : 0 : iterate_item(buf, pkg, p->sep_fmt->buf,
1551 : 0 : it.key, count, PP_Y);
1552 : :
1553 : 0 : iterate_item(buf, pkg, p->item_fmt->buf,
1554 : 0 : it.key, count, PP_Y);
1555 : 0 : count++;
1556 : : }
1557 : : }
1558 : 0 : return (buf);
1559 : 0 : }
1560 : :
1561 : : /*
1562 : : * %Yn -- Required name or %yn -- Provided name
1563 : : */
1564 : : xstring *
1565 : 0 : format_provide_name(xstring *buf, const void *data, struct percent_esc *p)
1566 : : {
1567 : 0 : const char *provide = data;
1568 : :
1569 : 0 : return (string_val(buf, provide, p));
1570 : : }
1571 : : /*
1572 : : * %a -- Autoremove flag. boolean. Accepts field-width, left-align.
1573 : : * Standard form: 0, 1. Alternate form1: no, yes. Alternate form2:
1574 : : * false, true
1575 : : */
1576 : : xstring *
1577 : 0 : format_autoremove(xstring *buf, const void *data, struct percent_esc *p)
1578 : : {
1579 : 0 : const struct pkg *pkg = data;
1580 : :
1581 : 0 : return (bool_val(buf, pkg->automatic, p));
1582 : : }
1583 : :
1584 : :
1585 : : /*
1586 : : * %b -- Provided Shared Libraries. List of shlibs provided by
1587 : : * binaries in the pkg. Optionally accepts per-field format in %{ %|
1588 : : * %}, where %n is replaced by the shlib name. Default %{%bn\n%|%}
1589 : : */
1590 : : xstring *
1591 : 0 : format_shlibs_provided(xstring *buf, const void *data, struct percent_esc *p)
1592 : : {
1593 : 0 : const struct pkg *pkg = data;
1594 : :
1595 [ # # ]: 0 : if (p->flags & (PP_ALTERNATE_FORM1|PP_ALTERNATE_FORM2))
1596 : 0 : return (list_count(buf, pkg_list_count(pkg, PKG_SHLIBS_PROVIDED), p));
1597 : : else {
1598 : : pkghash_it it;
1599 : : int count;
1600 : :
1601 : 0 : set_list_defaults(p, "%bn\n", "");
1602 : :
1603 : 0 : count = 1;
1604 : 0 : fflush(p->sep_fmt->fp);
1605 : 0 : fflush(p->item_fmt->fp);
1606 : 0 : it = pkghash_iterator(pkg->shlibs_provided);
1607 [ # # ]: 0 : while (pkghash_next(&it)) {
1608 [ # # ]: 0 : if (count > 1)
1609 : 0 : iterate_item(buf, pkg, p->sep_fmt->buf,
1610 : 0 : it.key, count, PP_b);
1611 : :
1612 : 0 : iterate_item(buf, pkg, p->item_fmt->buf,
1613 : 0 : it.key, count, PP_b);
1614 : 0 : count++;
1615 : : }
1616 : : }
1617 : 0 : return (buf);
1618 : 0 : }
1619 : :
1620 : : /*
1621 : : * %c -- Comment. string. Accepts field-width, left-align
1622 : : */
1623 : : xstring *
1624 : 0 : format_comment(xstring *buf, const void *data, struct percent_esc *p)
1625 : : {
1626 : 0 : const struct pkg *pkg = data;
1627 : :
1628 : 0 : return (string_val(buf, pkg->comment, p));
1629 : : }
1630 : :
1631 : : /*
1632 : : * %d -- Dependencies. List of pkgs. Can be optionally followed by
1633 : : * per-field format string in %{ %| %} using any pkg_printf() *scalar*
1634 : : * formats. Defaults to printing "%dn-%dv\n" for each dependency.
1635 : : */
1636 : : xstring *
1637 : 0 : format_dependencies(xstring *buf, const void *data, struct percent_esc *p)
1638 : : {
1639 : 0 : const struct pkg *pkg = data;
1640 : :
1641 [ # # ]: 0 : if (p->flags & (PP_ALTERNATE_FORM1|PP_ALTERNATE_FORM2))
1642 : 0 : return (list_count(buf, pkg_list_count(pkg, PKG_DEPS), p));
1643 : : else {
1644 : 0 : struct pkg_dep *dep = NULL;
1645 : : int count;
1646 : :
1647 : 0 : set_list_defaults(p, "%dn-%dv\n", "");
1648 : :
1649 : 0 : count = 1;
1650 : 0 : fflush(p->sep_fmt->fp);
1651 : 0 : fflush(p->item_fmt->fp);
1652 [ # # ]: 0 : while (pkg_deps(pkg, &dep) == EPKG_OK) {
1653 [ # # ]: 0 : if (count > 1)
1654 : 0 : iterate_item(buf, pkg, p->sep_fmt->buf,
1655 : 0 : dep, count, PP_d);
1656 : :
1657 : 0 : iterate_item(buf, pkg, p->item_fmt->buf,
1658 : 0 : dep, count, PP_d);
1659 : 0 : count++;
1660 : : }
1661 : : }
1662 : 0 : return (buf);
1663 : 0 : }
1664 : :
1665 : : /*
1666 : : * %dk -- Dependency lock status or %rk -- Requirement lock status.
1667 : : */
1668 : : xstring *
1669 : 0 : format_dependency_lock(xstring *buf, const void *data,
1670 : : struct percent_esc *p)
1671 : : {
1672 : 0 : const struct pkg_dep *dep = data;
1673 : :
1674 : 0 : return (bool_val(buf, pkg_dep_is_locked(dep), p));
1675 : : }
1676 : :
1677 : : /*
1678 : : * %dn -- Dependency name or %rn -- Requirement name.
1679 : : */
1680 : : xstring *
1681 : 0 : format_dependency_name(xstring *buf, const void *data,
1682 : : struct percent_esc *p)
1683 : : {
1684 : 0 : const struct pkg_dep *dep = data;
1685 : :
1686 : 0 : return (string_val(buf, dep->name, p));
1687 : : }
1688 : :
1689 : : /*
1690 : : * %do -- Dependency origin or %ro -- Requirement origin.
1691 : : */
1692 : : xstring *
1693 : 0 : format_dependency_origin(xstring *buf, const void *data,
1694 : : struct percent_esc *p)
1695 : : {
1696 : 0 : const struct pkg_dep *dep = data;
1697 : :
1698 : 0 : return (string_val(buf, dep->origin, p));
1699 : : }
1700 : :
1701 : : /*
1702 : : * %dv -- Dependency version or %rv -- Requirement version.
1703 : : */
1704 : : xstring *
1705 : 0 : format_dependency_version(xstring *buf, const void *data,
1706 : : struct percent_esc *p)
1707 : : {
1708 : 0 : const struct pkg_dep *dep = data;
1709 : :
1710 : 0 : return (string_val(buf, dep->version, p));
1711 : : }
1712 : :
1713 : : /*
1714 : : * %e -- Description. string. Accepts field-width, left-align
1715 : : */
1716 : : xstring *
1717 : 0 : format_description(xstring *buf, const void *data, struct percent_esc *p)
1718 : : {
1719 : 0 : const struct pkg *pkg = data;
1720 : :
1721 : 0 : return (string_val(buf, pkg->desc, p));
1722 : : }
1723 : :
1724 : : /*
1725 : : * %k -- Locked flag. boolean. Accepts field-width, left-align.
1726 : : * Standard form: 0, 1. Alternate form1: no, yes. Alternate form2:
1727 : : * false, true
1728 : : */
1729 : : xstring *
1730 : 0 : format_lock_status(xstring *buf, const void *data, struct percent_esc *p)
1731 : : {
1732 : 0 : const struct pkg *pkg = data;
1733 : :
1734 : 0 : return (bool_val(buf, pkg->locked, p));
1735 : : }
1736 : :
1737 : : /*
1738 : : * %l -- Licence logic. string. Accepts field-width, left-align.
1739 : : * Standard form: and, or, single. Alternate form 1: &, |, ''.
1740 : : * Alternate form 2: &&, ||, ==
1741 : : */
1742 : : xstring *
1743 : 0 : format_license_logic(xstring *buf, const void *data, struct percent_esc *p)
1744 : : {
1745 : 0 : const struct pkg *pkg = data;
1746 : :
1747 : 0 : return (liclog_val(buf, pkg->licenselogic, p));
1748 : : }
1749 : :
1750 : : /*
1751 : : * %m -- Maintainer e-mail address. string. Accepts field-width, left-align
1752 : : */
1753 : : xstring *
1754 : 0 : format_maintainer(xstring *buf, const void *data, struct percent_esc *p)
1755 : : {
1756 : 0 : const struct pkg *pkg = data;
1757 : :
1758 : 0 : return (string_val(buf, pkg->maintainer, p));
1759 : : }
1760 : :
1761 : : /*
1762 : : * %n -- Package name. string. Accepts field-width, left-align
1763 : : */
1764 : : xstring *
1765 : 0 : format_name(xstring *buf, const void *data, struct percent_esc *p)
1766 : : {
1767 : 0 : const struct pkg *pkg = data;
1768 : :
1769 : 0 : return (string_val(buf, pkg->name, p));
1770 : : }
1771 : :
1772 : : /*
1773 : : * %o -- Package origin. string. Accepts field-width, left-align
1774 : : */
1775 : : xstring *
1776 : 0 : format_origin(xstring *buf, const void *data, struct percent_esc *p)
1777 : : {
1778 : 0 : const struct pkg *pkg = data;
1779 : :
1780 : 0 : return (string_val(buf, pkg->origin, p));
1781 : : }
1782 : :
1783 : : /*
1784 : : * %p -- Installation prefix. string. Accepts field-width, left-align
1785 : : */
1786 : : xstring *
1787 : 0 : format_prefix(xstring *buf, const void *data, struct percent_esc *p)
1788 : : {
1789 : 0 : const struct pkg *pkg = data;
1790 : :
1791 : 0 : return (string_val(buf, pkg->prefix, p));
1792 : : }
1793 : :
1794 : : /*
1795 : : * %q -- pkg architecture a.k.a ABI string. Accepts field-width, left-align
1796 : : */
1797 : : xstring *
1798 : 0 : format_architecture(xstring *buf, const void *data, struct percent_esc *p)
1799 : : {
1800 : 0 : const struct pkg *pkg = data;
1801 : :
1802 : 0 : return (string_val(buf, pkg->abi, p));
1803 : : }
1804 : :
1805 : : /*
1806 : : * %r -- Requirements. List of pkgs. Can be optionally followed by
1807 : : * per-field format string in %{ %| %} using any pkg_printf() *scalar*
1808 : : * formats. Defaults to printing "%{%rn-%rv\n%|%}" for each dependency.
1809 : : */
1810 : : xstring *
1811 : 0 : format_requirements(xstring *buf, const void *data, struct percent_esc *p)
1812 : : {
1813 : 0 : const struct pkg *pkg = data;
1814 : :
1815 [ # # ]: 0 : if (p->flags & (PP_ALTERNATE_FORM1|PP_ALTERNATE_FORM2))
1816 : 0 : return(list_count(buf, pkg_list_count(pkg, PKG_RDEPS), p));
1817 : : else {
1818 : 0 : struct pkg_dep *req = NULL;
1819 : : int count;
1820 : :
1821 : 0 : set_list_defaults(p, "%rn-%rv\n", "");
1822 : :
1823 : 0 : count = 1;
1824 : 0 : fflush(p->sep_fmt->fp);
1825 : 0 : fflush(p->item_fmt->fp);
1826 [ # # ]: 0 : while (pkg_rdeps(pkg, &req) == EPKG_OK) {
1827 [ # # ]: 0 : if (count > 1)
1828 : 0 : iterate_item(buf, pkg, p->sep_fmt->buf,
1829 : 0 : req, count, PP_r);
1830 : :
1831 : 0 : iterate_item(buf, pkg, p->item_fmt->buf,
1832 : 0 : req, count, PP_r);
1833 : 0 : count++;
1834 : : }
1835 : : }
1836 : 0 : return (buf);
1837 : 0 : }
1838 : :
1839 : : /*
1840 : : * %s -- Size of installed package. integer. Accepts field-width,
1841 : : * left-align, zero-fill, space-for-plus, explicit-plus and
1842 : : * alternate-form. Alternate form is a humanized number using decimal
1843 : : * exponents (k, M, G). Alternate form 2, ditto, but using binary
1844 : : * scale prefixes (ki, Mi, Gi etc.)
1845 : : */
1846 : : xstring *
1847 : 0 : format_flatsize(xstring *buf, const void *data, struct percent_esc *p)
1848 : : {
1849 : 0 : const struct pkg *pkg = data;
1850 : :
1851 : 0 : return (int_val(buf, pkg->flatsize, p));
1852 : : }
1853 : :
1854 : : /*
1855 : : * %t -- Installation timestamp (Unix time). integer. Accepts
1856 : : * field-width, left-align. Can be followed by optional strftime
1857 : : * format string in %{ %}. Default is to print seconds-since-epoch as
1858 : : * an integer applying our integer format modifiers.
1859 : : */
1860 : : xstring *
1861 : 0 : format_install_tstamp(xstring *buf, const void *data, struct percent_esc *p)
1862 : : {
1863 : 0 : const struct pkg *pkg = data;
1864 : :
1865 : 0 : fflush(p->item_fmt->fp);
1866 [ # # ]: 0 : if (strlen(p->item_fmt->buf) == 0)
1867 : 0 : return (int_val(buf, pkg->timestamp, p));
1868 : : else {
1869 : : char buffer[1024];
1870 : : time_t tsv;
1871 : :
1872 : 0 : tsv = (time_t)pkg->timestamp;
1873 : 0 : strftime(buffer, sizeof(buffer), p->item_fmt->buf,
1874 : 0 : localtime(&tsv));
1875 : 0 : fprintf(buf->fp, "%s", buffer);
1876 : : }
1877 : 0 : return (buf);
1878 : 0 : }
1879 : :
1880 : : /*
1881 : : * %v -- Package version. string. Accepts field width, left align
1882 : : */
1883 : : xstring *
1884 : 0 : format_version(xstring *buf, const void *data, struct percent_esc *p)
1885 : : {
1886 : 0 : const struct pkg *pkg = data;
1887 : :
1888 : 0 : return (string_val(buf, pkg->version, p));
1889 : : }
1890 : :
1891 : : /*
1892 : : * %u -- Package checksum. string. Accepts field width, left align
1893 : : */
1894 : : xstring *
1895 : 0 : format_checksum(xstring *buf, const void *data, struct percent_esc *p)
1896 : : {
1897 : 0 : const struct pkg *pkg = data;
1898 : :
1899 : 0 : return (string_val(buf, pkg->sum, p));
1900 : : }
1901 : :
1902 : : /*
1903 : : * %w -- Home page URL. string. Accepts field width, left align
1904 : : */
1905 : : xstring *
1906 : 0 : format_home_url(xstring *buf, const void *data, struct percent_esc *p)
1907 : : {
1908 : 0 : const struct pkg *pkg = data;
1909 : :
1910 : 0 : return (string_val(buf, pkg->www, p));
1911 : : }
1912 : :
1913 : : /*
1914 : : * %x - Package tarball size. Integer. Accepts field-width,
1915 : : * left-align, zero-fill, space-for-plus, explicit-plus and
1916 : : * alternate-form. Alternate form is a humanized number using decimal
1917 : : * exponents (k, M, G). Alternate form 2, ditto, but using binary
1918 : : * scale prefixes (ki, Mi, Gi etc.)
1919 : : */
1920 : : xstring *
1921 : 0 : format_pkgsize(xstring *buf, const void *data, struct percent_esc *p)
1922 : : {
1923 : 0 : const struct pkg *pkg = data;
1924 : :
1925 : 0 : return (int_val(buf, pkg->pkgsize, p));
1926 : : }
1927 : :
1928 : : /*
1929 : : * %y -- Provided pattern. List of pattern provided by
1930 : : * binaries in the pkg. Optionally accepts per-field format in %{ %|
1931 : : * %}. Default %{%yn\n%|%}
1932 : : */
1933 : : xstring *
1934 : 0 : format_provided(xstring *buf, const void *data, struct percent_esc *p)
1935 : : {
1936 : 0 : const struct pkg *pkg = data;
1937 : :
1938 [ # # ]: 0 : if (p->flags & (PP_ALTERNATE_FORM1|PP_ALTERNATE_FORM2))
1939 : 0 : return (list_count(buf, pkg_list_count(pkg, PKG_PROVIDES), p));
1940 : : else {
1941 : : pkghash_it it;
1942 : : int count;
1943 : :
1944 : 0 : set_list_defaults(p, "%yn\n", "");
1945 : :
1946 : 0 : count = 1;
1947 : 0 : fflush(p->sep_fmt->fp);
1948 : 0 : fflush(p->item_fmt->fp);
1949 : 0 : it = pkghash_iterator(pkg->provides);
1950 [ # # ]: 0 : while (pkghash_next(&it)) {
1951 [ # # ]: 0 : if (count > 1)
1952 : 0 : iterate_item(buf, pkg, p->sep_fmt->buf,
1953 : 0 : it.key, count, PP_y);
1954 : :
1955 : 0 : iterate_item(buf, pkg, p->item_fmt->buf,
1956 : 0 : it.key, count, PP_y);
1957 : 0 : count++;
1958 : : }
1959 : : }
1960 : 0 : return (buf);
1961 : 0 : }
1962 : :
1963 : : /*
1964 : : * %z -- Package short checksum. string. Accepts field width, left align
1965 : : */
1966 : : xstring *
1967 : 0 : format_short_checksum(xstring *buf, const void *data, struct percent_esc *p)
1968 : : {
1969 : 0 : const struct pkg *pkg = data;
1970 : : char csum[PKG_FILE_CKSUM_CHARS + 1];
1971 : : int slen;
1972 : :
1973 [ # # ]: 0 : if (pkg->sum != NULL)
1974 [ # # ]: 0 : slen = MIN(PKG_FILE_CKSUM_CHARS, strlen(pkg->sum));
1975 : : else
1976 : 0 : slen = 0;
1977 : 0 : memcpy(csum, pkg->sum, slen);
1978 : 0 : csum[slen] = '\0';
1979 : :
1980 : 0 : return (string_val(buf, csum, p));
1981 : : }
1982 : : /*
1983 : : * %% -- Output a literal '%' character
1984 : : */
1985 : : xstring *
1986 : 0 : format_literal_percent(xstring *buf, __unused const void *data,
1987 : : __unused struct percent_esc *p)
1988 : : {
1989 : 0 : fputc('%', buf->fp);
1990 : 0 : return (buf);
1991 : : }
1992 : :
1993 : : /*
1994 : : * Unknown format code -- return NULL to signal upper layers to pass
1995 : : * the text through unchanged.
1996 : : */
1997 : : xstring *
1998 : 0 : format_unknown(xstring *buf, __unused const void *data,
1999 : : __unused struct percent_esc *p)
2000 : : {
2001 : 0 : fputc('%', buf->fp);
2002 : 0 : return (NULL);
2003 : : }
2004 : :
2005 : : /* -------------------------------------------------------------- */
2006 : :
2007 : : struct percent_esc *
2008 : 156 : new_percent_esc(void)
2009 : : {
2010 : : struct percent_esc *p;
2011 : :
2012 : 156 : p = xcalloc(1, sizeof(struct percent_esc));
2013 : 156 : p->item_fmt = xstring_new();
2014 : 156 : p->sep_fmt = xstring_new();
2015 : 156 : return (p);
2016 : : }
2017 : :
2018 : : struct percent_esc *
2019 : 221 : clear_percent_esc(struct percent_esc *p)
2020 : : {
2021 : 221 : p->flags = 0;
2022 : 221 : p->width = 0;
2023 : 221 : p->trailer_status = 0;
2024 : 221 : xstring_reset(p->item_fmt);
2025 : 221 : xstring_reset(p->sep_fmt);
2026 : :
2027 : 221 : p->fmt_code = '\0';
2028 : :
2029 : 221 : return (p);
2030 : : }
2031 : :
2032 : : void
2033 : 156 : free_percent_esc(struct percent_esc *p)
2034 : : {
2035 [ - + ]: 156 : if (p) {
2036 [ + - ]: 156 : if (p->item_fmt)
2037 : 156 : xstring_free(p->item_fmt);
2038 [ + - ]: 156 : if (p->sep_fmt)
2039 : 156 : xstring_free(p->sep_fmt);
2040 : 156 : free(p);
2041 : 156 : }
2042 : 156 : return;
2043 : : }
2044 : :
2045 : : char *
2046 : 6396 : gen_format(char *buf, size_t buflen, unsigned flags, const char *tail)
2047 : : {
2048 : 6396 : int bp = 0;
2049 : : size_t tlen;
2050 : :
2051 : : /* We need the length of tail plus at least 3 characters '%'
2052 : : '*' '\0' but maybe as many as 7 '%' '#' '-' '+' '\'' '*'
2053 : : '\0' */
2054 : :
2055 : 6396 : tlen = strlen(tail);
2056 : :
2057 [ - + ]: 6396 : if (buflen - bp < tlen + 3)
2058 : 0 : return (NULL);
2059 : :
2060 : 6396 : buf[bp++] = '%';
2061 : :
2062 : : /* PP_ALTERNATE_FORM1 is not used by regular printf(3) */
2063 : :
2064 : : /* If PP_EXPLICIT_PLUS and PP_SPACE_FOR_PLUS are both set,
2065 : : the result is formatted according to PP_EXPLICIT_PLUS */
2066 : :
2067 [ + + ]: 6396 : if ((flags & (PP_EXPLICIT_PLUS|PP_SPACE_FOR_PLUS)) ==
2068 : : (PP_EXPLICIT_PLUS|PP_SPACE_FOR_PLUS))
2069 : 221 : flags &= ~(PP_SPACE_FOR_PLUS);
2070 : :
2071 : : /* If PP_LEFT_ALIGN and PP_ZERO_PAD are given together,
2072 : : PP_LEFT_ALIGN applies */
2073 : :
2074 [ + + ]: 6396 : if ((flags & (PP_LEFT_ALIGN|PP_ZERO_PAD)) ==
2075 : : (PP_LEFT_ALIGN|PP_ZERO_PAD))
2076 : 338 : flags &= ~(PP_ZERO_PAD);
2077 : :
2078 [ + + ]: 6396 : if (flags & PP_ALTERNATE_FORM2)
2079 : 611 : buf[bp++] = '#';
2080 : :
2081 [ + + ]: 6396 : if (flags & PP_LEFT_ALIGN)
2082 : 1391 : buf[bp++] = '-';
2083 : :
2084 [ + + ]: 6396 : if (flags & PP_ZERO_PAD)
2085 : 1001 : buf[bp++] = '0';
2086 : :
2087 [ - + ]: 6396 : if (buflen - bp < tlen + 2)
2088 : 0 : return (NULL);
2089 : :
2090 [ + + ]: 6396 : if (flags & PP_EXPLICIT_PLUS)
2091 : 1235 : buf[bp++] = '+';
2092 : :
2093 [ + + ]: 6396 : if (flags & PP_SPACE_FOR_PLUS)
2094 : 1144 : buf[bp++] = ' ';
2095 : :
2096 [ + + ]: 6396 : if (flags & PP_THOUSANDS_SEP)
2097 : 442 : buf[bp++] = '\'';
2098 : :
2099 [ - + ]: 6396 : if (buflen - bp < tlen + 2)
2100 : 0 : return (NULL);
2101 : :
2102 : : /* The effect of 0 meaning 'zero fill' is indisinguishable
2103 : : from 0 meaning 'a field width of zero' */
2104 : :
2105 : 6396 : buf[bp++] = '*';
2106 : 6396 : buf[bp] = '\0';
2107 : :
2108 : 6396 : strlcat(buf, tail, buflen);
2109 : :
2110 : 6396 : return (buf);
2111 : 6396 : }
2112 : :
2113 : :
2114 : : xstring *
2115 : 1885 : human_number(xstring *buf, int64_t number, struct percent_esc *p)
2116 : : {
2117 : : double num;
2118 : : int sign;
2119 : : int width;
2120 : : int scale_width;
2121 : : int divisor;
2122 : : int scale;
2123 : : int precision;
2124 : : bool bin_scale;
2125 : :
2126 : : #define MAXSCALE 7
2127 : :
2128 : 1885 : const char *bin_pfx[MAXSCALE] =
2129 : : { "", "Ki", "Mi", "Gi", "Ti", "Pi", "Ei" };
2130 : 1885 : const char *si_pfx[MAXSCALE] =
2131 : : { "", "k", "M", "G", "T", "P", "E" };
2132 : : char format[16];
2133 : :
2134 : 1885 : bin_scale = ((p->flags & PP_ALTERNATE_FORM2) != 0);
2135 : :
2136 : 1885 : p->flags &= ~(PP_ALTERNATE_FORM1|PP_ALTERNATE_FORM2);
2137 : :
2138 [ + - ]: 1885 : if (gen_format(format, sizeof(format), p->flags, ".*f") == NULL)
2139 : 0 : return (NULL);
2140 : :
2141 [ + + ]: 1885 : if (number >= 0) {
2142 : 1638 : num = number;
2143 : 1638 : sign = 1;
2144 : 1638 : } else {
2145 : 247 : num = -number;
2146 : 247 : sign = -1;
2147 : : }
2148 : :
2149 : 1885 : divisor = bin_scale ? 1024 : 1000;
2150 : :
2151 [ - + ]: 4628 : for (scale = 0; scale < MAXSCALE; scale++) {
2152 [ + + ]: 4628 : if (num < divisor)
2153 : 1885 : break;
2154 : 2743 : num /= divisor;
2155 : 2743 : }
2156 : :
2157 [ + - ]: 1885 : if (scale == MAXSCALE)
2158 : 0 : scale--;
2159 : :
2160 [ + + ]: 1885 : if (scale == 0)
2161 : 624 : scale_width = 0;
2162 [ + + ]: 1261 : else if (bin_scale)
2163 : 520 : scale_width = 2;
2164 : : else
2165 : 741 : scale_width = 1;
2166 : :
2167 [ + + ]: 1885 : if (p->width == 0)
2168 : 689 : width = 0;
2169 [ + + ]: 1196 : else if (p->width <= scale_width)
2170 : 117 : width = 1;
2171 : : else
2172 : 1079 : width = p->width - scale_width;
2173 : :
2174 [ + + ]: 1885 : if (num >= 100)
2175 : 858 : precision = 0;
2176 [ + + ]: 1027 : else if (num >= 10) {
2177 [ + + + + ]: 299 : if (width == 0 || width > 3)
2178 : 182 : precision = 1;
2179 : : else
2180 : 117 : precision = 0;
2181 : 299 : } else {
2182 [ + + + + ]: 728 : if (width == 0 || width > 3)
2183 : 611 : precision = 2;
2184 [ + + ]: 117 : else if (width == 3)
2185 : 26 : precision = 1;
2186 : : else
2187 : 91 : precision = 0;
2188 : : }
2189 : :
2190 : 1885 : fprintf(buf->fp, format, width, precision, num * sign);
2191 : :
2192 [ + + ]: 1885 : if (scale > 0)
2193 : 2522 : fprintf(buf->fp, "%s",
2194 [ + + ]: 1261 : bin_scale ? bin_pfx[scale] : si_pfx[scale]);
2195 : :
2196 : 1885 : return (buf);
2197 : 1885 : }
2198 : :
2199 : : xstring *
2200 : 793 : string_val(xstring *buf, const char *str, struct percent_esc *p)
2201 : : {
2202 : : char format[16];
2203 : :
2204 : : /* The '#' '?' '+' ' ' '0' and '\'' modifiers have no meaning
2205 : : for strings */
2206 : :
2207 : 793 : p->flags &= ~(PP_ALTERNATE_FORM1 |
2208 : : PP_ALTERNATE_FORM2 |
2209 : : PP_EXPLICIT_PLUS |
2210 : : PP_SPACE_FOR_PLUS |
2211 : : PP_ZERO_PAD |
2212 : : PP_THOUSANDS_SEP);
2213 : :
2214 [ - + ]: 793 : if (gen_format(format, sizeof(format), p->flags, "s") == NULL)
2215 : 0 : return (NULL);
2216 : :
2217 : 793 : fprintf(buf->fp, format, p->width, str);
2218 : 793 : return (buf);
2219 : 793 : }
2220 : :
2221 : : xstring *
2222 : 2301 : int_val(xstring *buf, int64_t value, struct percent_esc *p)
2223 : : {
2224 [ - + ]: 2301 : if (p->flags & (PP_ALTERNATE_FORM1|PP_ALTERNATE_FORM2))
2225 : 0 : return (human_number(buf, value, p));
2226 : : else {
2227 : : char format[16];
2228 : :
2229 [ - + - + ]: 4602 : if (gen_format(format, sizeof(format), p->flags, PRId64)
2230 : 2301 : == NULL)
2231 : 0 : return (NULL);
2232 : :
2233 : 2301 : fprintf(buf->fp, format, p->width, value);
2234 : : }
2235 : 2301 : return (buf);
2236 : 2301 : }
2237 : :
2238 : : xstring *
2239 : 78 : bool_val(xstring *buf, bool value, struct percent_esc *p)
2240 : : {
2241 : : static const char *boolean_str[2][3] = {
2242 : : [false] = { "false", "no", "" },
2243 : : [true] = { "true", "yes", "(*)" },
2244 : : };
2245 : : int alternate;
2246 : :
2247 [ + + ]: 78 : if (p->flags & PP_ALTERNATE_FORM2)
2248 : 26 : alternate = 2;
2249 [ + + ]: 52 : else if (p->flags & PP_ALTERNATE_FORM1)
2250 : 26 : alternate = 1;
2251 : : else
2252 : 26 : alternate = 0;
2253 : :
2254 : 78 : p->flags &= ~(PP_ALTERNATE_FORM1|PP_ALTERNATE_FORM2);
2255 : :
2256 : 78 : return (string_val(buf, boolean_str[value][alternate], p));
2257 : : }
2258 : :
2259 : : xstring *
2260 : 741 : mode_val(xstring *buf, mode_t mode, struct percent_esc *p)
2261 : : {
2262 : : /*
2263 : : * Print mode as an octal integer '%o' by default.
2264 : : * PP_ALTERNATE_FORM2 generates '%#o' pased to regular
2265 : : * printf(). PP_ALTERNATE_FORM1 will generate 'drwxr-x--- '
2266 : : * style from strmode(3).
2267 : : */
2268 : :
2269 [ + + ]: 741 : if (p->flags & PP_ALTERNATE_FORM1) {
2270 : : char modebuf[12];
2271 : :
2272 : 169 : strmode(mode, modebuf);
2273 : :
2274 : 169 : return (string_val(buf, modebuf, p));
2275 : : } else {
2276 : : char format[16];
2277 : :
2278 : : /*
2279 : : * Should the mode when expressed as a numeric value
2280 : : * in octal include the bits that indicate the inode
2281 : : * type? Generally no, but since mode is
2282 : : * intrinsically an unsigned type, overload
2283 : : * PP_EXPLICIT_PLUS to mean 'show bits for the inode
2284 : : * type'
2285 : : */
2286 : :
2287 [ + + ]: 572 : if ( (p->flags & PP_EXPLICIT_PLUS) == 0 )
2288 : 481 : mode &= ALLPERMS;
2289 : :
2290 : 572 : p->flags &= ~(PP_ALTERNATE_FORM1|PP_EXPLICIT_PLUS);
2291 : :
2292 [ - + - + ]: 1144 : if (gen_format(format, sizeof(format), p->flags, PRIo16)
2293 : 572 : == NULL)
2294 : 0 : return (NULL);
2295 : :
2296 : 572 : fprintf(buf->fp, format, p->width, mode);
2297 : : }
2298 : 572 : return (buf);
2299 : 741 : }
2300 : :
2301 : : xstring *
2302 : 117 : liclog_val(xstring *buf, lic_t licenselogic, struct percent_esc *p)
2303 : : {
2304 : : int alternate;
2305 : 117 : int llogic = PP_LIC_SINGLE;
2306 : :
2307 : : static const char *liclog_str[3][3] = {
2308 : : [PP_LIC_SINGLE] = { "single", "", "==" },
2309 : : [PP_LIC_OR] = { "or", "|", "||" },
2310 : : [PP_LIC_AND] = { "and", "&", "&&" },
2311 : : };
2312 : :
2313 [ - + + + ]: 117 : switch (licenselogic) {
2314 : : case LICENSE_SINGLE:
2315 : 39 : llogic = PP_LIC_SINGLE;
2316 : 39 : break;
2317 : : case LICENSE_OR:
2318 : 39 : llogic = PP_LIC_OR;
2319 : 39 : break;
2320 : : case LICENSE_AND:
2321 : 39 : llogic = PP_LIC_AND;
2322 : 39 : break;
2323 : : }
2324 : :
2325 [ + + ]: 117 : if (p->flags & PP_ALTERNATE_FORM2)
2326 : 39 : alternate = 2;
2327 [ + + ]: 78 : else if (p->flags & PP_ALTERNATE_FORM1)
2328 : 39 : alternate = 1;
2329 : : else
2330 : 39 : alternate = 0;
2331 : :
2332 : 117 : p->flags &= ~(PP_ALTERNATE_FORM1|PP_ALTERNATE_FORM2);
2333 : :
2334 : 117 : return (string_val(buf, liclog_str[llogic][alternate], p));
2335 : : }
2336 : :
2337 : : xstring *
2338 : 39 : list_count(xstring *buf, int64_t count, struct percent_esc *p)
2339 : : {
2340 : : /* Convert to 0 or 1 for %?X */
2341 [ + + ]: 39 : if (p->flags & PP_ALTERNATE_FORM1)
2342 : 13 : count = (count > 0);
2343 : :
2344 : : /* Turn off %#X and %?X flags, then print as a normal integer */
2345 : 39 : p->flags &= ~(PP_ALTERNATE_FORM1|PP_ALTERNATE_FORM2);
2346 : :
2347 : 39 : return (int_val(buf, count, p));
2348 : : }
2349 : :
2350 : : struct percent_esc *
2351 : 0 : set_list_defaults(struct percent_esc *p, const char *item_fmt,
2352 : : const char *sep_fmt)
2353 : : {
2354 [ # # ]: 0 : if ((p->trailer_status & ITEM_FMT_SET) != ITEM_FMT_SET) {
2355 : 0 : fprintf(p->item_fmt->fp, "%s", item_fmt);
2356 : 0 : p->trailer_status |= ITEM_FMT_SET;
2357 : 0 : }
2358 [ # # ]: 0 : if ((p->trailer_status & SEP_FMT_SET) != SEP_FMT_SET) {
2359 : 0 : fprintf(p->sep_fmt->fp, "%s", sep_fmt);
2360 : 0 : p->trailer_status |= SEP_FMT_SET;
2361 : 0 : }
2362 : 0 : return (p);
2363 : : }
2364 : :
2365 : : xstring *
2366 : 0 : iterate_item(xstring *buf, const struct pkg *pkg, const char *format,
2367 : : const void *data, int count, unsigned context)
2368 : : {
2369 : : const char *f;
2370 : : struct percent_esc *p;
2371 : :
2372 : : /* Scan the format string and interpret any escapes */
2373 : :
2374 : 0 : f = format;
2375 : 0 : p = new_percent_esc();
2376 : :
2377 [ # # ]: 0 : if (p == NULL) {
2378 : 0 : xstring_reset(buf);
2379 : 0 : return (buf); /* Out of memory */
2380 : : }
2381 : :
2382 [ # # ]: 0 : while ( *f != '\0' ) {
2383 [ # # # ]: 0 : switch(*f) {
2384 : : case '%':
2385 : 0 : f = process_format_trailer(buf, p, f, pkg, data, count, context);
2386 : 0 : break;
2387 : : case '\\':
2388 : 0 : f = process_escape(buf, f);
2389 : 0 : break;
2390 : : default:
2391 : 0 : fprintf(buf->fp, "%c", *f);
2392 : 0 : f++;
2393 : 0 : break;
2394 : : }
2395 [ # # ]: 0 : if (f == NULL) {
2396 : 0 : xstring_reset(buf);
2397 : 0 : break; /* Out of memory */
2398 : : }
2399 : : }
2400 : :
2401 : 0 : free_percent_esc(p);
2402 : 0 : return (buf);
2403 : 0 : }
2404 : :
2405 : : const char *
2406 : 429 : field_modifier(const char *f, struct percent_esc *p)
2407 : : {
2408 : : bool done;
2409 : :
2410 : : /* Field modifiers, if any:
2411 : : '?' alternate form 1
2412 : : '#' alternate form 2
2413 : : '-' left align
2414 : : '+' explicit plus sign (numerics only)
2415 : : ' ' space instead of plus sign (numerics only)
2416 : : '0' pad with zeroes (numerics only)
2417 : : '\'' use thousands separator (numerics only)
2418 : : Note '*' (dynamic field width) is not supported */
2419 : :
2420 : 429 : done = false;
2421 [ + + ]: 1378 : while (!done) {
2422 [ + + + + : 949 : switch (*f) {
+ + + + ]
2423 : : case '?':
2424 : 78 : p->flags |= PP_ALTERNATE_FORM1;
2425 : 78 : break;
2426 : : case '#':
2427 : 364 : p->flags |= PP_ALTERNATE_FORM2;
2428 : 364 : break;
2429 : : case '-':
2430 : 26 : p->flags |= PP_LEFT_ALIGN;
2431 : 26 : break;
2432 : : case '+':
2433 : 13 : p->flags |= PP_EXPLICIT_PLUS;
2434 : 13 : break;
2435 : : case ' ':
2436 : 13 : p->flags |= PP_SPACE_FOR_PLUS;
2437 : 13 : break;
2438 : : case '0':
2439 : 13 : p->flags |= PP_ZERO_PAD;
2440 : 13 : break;
2441 : : case '\'':
2442 : 13 : p->flags |= PP_THOUSANDS_SEP;
2443 : 13 : break;
2444 : : default:
2445 : 429 : done = true;
2446 : 429 : break;
2447 : : }
2448 [ + + ]: 949 : if (!done)
2449 : 520 : f++;
2450 : : }
2451 : 429 : return (f);
2452 : : }
2453 : :
2454 : : const char *
2455 : 468 : field_width(const char *f, struct percent_esc *p)
2456 : : {
2457 : : bool done;
2458 : :
2459 : : /* Field width, if any -- some number of decimal digits.
2460 : : Note: field width set to zero could be interpreted as using
2461 : : 0 to request zero padding: it doesn't matter which -- the
2462 : : result on output is exactly the same. */
2463 : :
2464 : 468 : done = false;
2465 [ + + ]: 1456 : while (!done) {
2466 [ + + + + : 988 : switch(*f) {
+ + + + +
+ + ]
2467 : : case '0':
2468 : 117 : p->width = p->width * 10 + 0;
2469 : 117 : break;
2470 : : case '1':
2471 : 78 : p->width = p->width * 10 + 1;
2472 : 78 : break;
2473 : : case '2':
2474 : 52 : p->width = p->width * 10 + 2;
2475 : 52 : break;
2476 : : case '3':
2477 : 39 : p->width = p->width * 10 + 3;
2478 : 39 : break;
2479 : : case '4':
2480 : 39 : p->width = p->width * 10 + 4;
2481 : 39 : break;
2482 : : case '5':
2483 : 39 : p->width = p->width * 10 + 5;
2484 : 39 : break;
2485 : : case '6':
2486 : 39 : p->width = p->width * 10 + 6;
2487 : 39 : break;
2488 : : case '7':
2489 : 39 : p->width = p->width * 10 + 7;
2490 : 39 : break;
2491 : : case '8':
2492 : 39 : p->width = p->width * 10 + 8;
2493 : 39 : break;
2494 : : case '9':
2495 : 39 : p->width = p->width * 10 + 9;
2496 : 39 : break;
2497 : : default:
2498 : 468 : done = true;
2499 : 468 : break;
2500 : : }
2501 [ + + ]: 988 : if (!done)
2502 : 520 : f++;
2503 : : }
2504 : 468 : return (f);
2505 : : }
2506 : :
2507 : : const char *
2508 : 91 : format_trailer(const char *f, struct percent_esc *p)
2509 : : {
2510 : :
2511 : : /* is the trailer even present? */
2512 : :
2513 [ + + - + ]: 91 : if (f[0] == '%' && f[1] == '{') {
2514 : 78 : bool sep = false;
2515 : 78 : bool done = false;
2516 : : const char *f1;
2517 : : const char *f2;
2518 : :
2519 : 78 : p->trailer_status |= ITEM_FMT_SET;
2520 : 78 : f1 = f + 2;
2521 : :
2522 [ + + ]: 299 : for (f2 = f1; *f2 != '\0'; f2++) {
2523 [ + + + + : 286 : if (f2[0] == '%' && ( f2[1] == '}' || f2[1] == '|')) {
+ + ]
2524 [ + + ]: 65 : if (f2[1] == '|')
2525 : 52 : sep = true;
2526 : : else
2527 : 13 : done = true;
2528 : 65 : f1 = f2 + 2;
2529 : 65 : break;
2530 : : }
2531 : 221 : fputc(*f2, p->item_fmt->fp);
2532 : 221 : fflush(p->item_fmt->fp);
2533 : 221 : }
2534 : :
2535 : :
2536 [ + + ]: 78 : if (sep) {
2537 : 52 : p->trailer_status |= SEP_FMT_SET;
2538 : 52 : done = false;
2539 : :
2540 [ + + ]: 221 : for (f2 = f1; *f2 != '\0'; f2++) {
2541 [ + + + + ]: 208 : if (f2[0] == '%' && f2[1] == '}') {
2542 : 39 : done = true;
2543 : 39 : f1 = f2 + 2;
2544 : 39 : break;
2545 : : }
2546 : 169 : fputc(*f2, p->sep_fmt->fp);
2547 : 169 : fflush(p->sep_fmt->fp);
2548 : 169 : }
2549 : :
2550 : 52 : }
2551 : :
2552 [ + + ]: 78 : if (done) {
2553 : 52 : f = f1;
2554 : 52 : } else {
2555 : 26 : xstring_reset(p->item_fmt);
2556 : 26 : xstring_reset(p->sep_fmt);
2557 : : }
2558 : 78 : }
2559 : :
2560 : 91 : return (f);
2561 : : }
2562 : :
2563 : : const char *
2564 : 10361 : format_code(const char *f, unsigned context, struct percent_esc *p)
2565 : : {
2566 : : fmt_code_t fmt_code;
2567 : :
2568 : 10361 : p->fmt_code = PP_UNKNOWN; /* Assume unknown, for contradiction */
2569 : :
2570 : : /* The next character or two will be a format code -- look
2571 : : these up in the fmt table to make sure they are allowed in
2572 : : context. This could be optimized since the format codes
2573 : : are arranged alphabetically in the fmt[] array. */
2574 : :
2575 [ + + ]: 625781 : for (fmt_code = 0; fmt_code < PP_END_MARKER; fmt_code++) {
2576 [ + + ]: 619970 : if ((fmt[fmt_code].context & context) != context)
2577 : 370929 : continue;
2578 [ + + ]: 249041 : if (fmt[fmt_code].fmt_main != f[0])
2579 : 242814 : continue;
2580 [ + + + + ]: 6227 : if (fmt[fmt_code].fmt_sub == f[1] && f[1] != '\0') {
2581 : 728 : p->fmt_code = fmt_code;
2582 : 728 : f += 2;
2583 : 728 : break;
2584 : : }
2585 [ + + ]: 5499 : if (fmt[fmt_code].fmt_sub == '\0') {
2586 : 3822 : p->fmt_code = fmt_code;
2587 : 3822 : f++;
2588 : 3822 : break;
2589 : : }
2590 : 1677 : }
2591 : :
2592 : 10361 : return (f);
2593 : : }
2594 : :
2595 : : const char *
2596 : 143 : parse_format(const char *f, unsigned context, struct percent_esc *p)
2597 : : {
2598 : 143 : f++; /* Eat the % */
2599 : :
2600 : 143 : f = field_modifier(f, p);
2601 : :
2602 : 143 : f = field_width(f, p);
2603 : :
2604 : 143 : f = format_code(f, context, p);
2605 : :
2606 : : /* Does this format take a trailing list item/separator format
2607 : : like %{...%|...%} ? It's only the list-valued items that
2608 : : do, and they can only take it at the top level (context ==
2609 : : PP_PKG). Also, they only take the trailing stuff in the
2610 : : absence of %?X or %#X modifiers. */
2611 : :
2612 [ + + + + ]: 182 : if ((context & PP_PKG) == PP_PKG &&
2613 [ + + ]: 117 : fmt[p->fmt_code].has_trailer &&
2614 : 39 : (p->flags & (PP_ALTERNATE_FORM1|PP_ALTERNATE_FORM2)) == 0)
2615 : 13 : f = format_trailer(f, p);
2616 : :
2617 : 143 : return (f);
2618 : : }
2619 : :
2620 : : const char*
2621 : 689 : maybe_read_hex_byte(xstring *buf, const char *f)
2622 : : {
2623 : : /* Hex escapes are of the form \xNN -- always two hex digits */
2624 : :
2625 : 689 : f++; /* eat the x */
2626 : :
2627 [ + + + + ]: 689 : if (isxdigit(f[0]) && isxdigit(f[1])) {
2628 : : int val;
2629 : :
2630 [ + + + + : 624 : switch(*f) {
+ + + + +
+ - + + +
+ + + ]
2631 : : case '0':
2632 : 286 : val = 0x0;
2633 : 286 : break;
2634 : : case '1':
2635 : 13 : val = 0x10;
2636 : 13 : break;
2637 : : case '2':
2638 : 13 : val = 0x20;
2639 : 13 : break;
2640 : : case '3':
2641 : 13 : val = 0x30;
2642 : 13 : break;
2643 : : case '4':
2644 : 26 : val = 0x40;
2645 : 26 : break;
2646 : : case '5':
2647 : 13 : val = 0x50;
2648 : 13 : break;
2649 : : case '6':
2650 : 26 : val = 0x60;
2651 : 26 : break;
2652 : : case '7':
2653 : 13 : val = 0x70;
2654 : 13 : break;
2655 : : case '8':
2656 : 13 : val = 0x80;
2657 : 13 : break;
2658 : : case '9':
2659 : 13 : val = 0x90;
2660 : 13 : break;
2661 : : case 'a':
2662 : : case 'A':
2663 : 26 : val = 0xa0;
2664 : 26 : break;
2665 : : case 'b':
2666 : : case 'B':
2667 : 26 : val = 0xb0;
2668 : 26 : break;
2669 : : case 'c':
2670 : : case 'C':
2671 : 26 : val = 0xc0;
2672 : 26 : break;
2673 : : case 'd':
2674 : : case 'D':
2675 : 26 : val = 0xd0;
2676 : 26 : break;
2677 : : case 'e':
2678 : : case 'E':
2679 : 26 : val = 0xe0;
2680 : 26 : break;
2681 : : case 'f':
2682 : : case 'F':
2683 : 65 : val = 0xf0;
2684 : 65 : break;
2685 : : default:
2686 : : /* This case is to shut up the over-picky
2687 : : * compiler warnings about use of an
2688 : : * uninitialised value. It can't actually
2689 : : * be reached. */
2690 : 0 : val = 0x0;
2691 : 0 : break;
2692 : : }
2693 : :
2694 : 624 : f++;
2695 : :
2696 [ + + + + : 624 : switch(*f) {
+ + + + +
+ + + + +
+ + - ]
2697 : : case '0':
2698 : 286 : val += 0x0;
2699 : 286 : break;
2700 : : case '1':
2701 : 26 : val += 0x1;
2702 : 26 : break;
2703 : : case '2':
2704 : 13 : val += 0x2;
2705 : 13 : break;
2706 : : case '3':
2707 : 13 : val += 0x3;
2708 : 13 : break;
2709 : : case '4':
2710 : 13 : val += 0x4;
2711 : 13 : break;
2712 : : case '5':
2713 : 13 : val += 0x5;
2714 : 13 : break;
2715 : : case '6':
2716 : 13 : val += 0x6;
2717 : 13 : break;
2718 : : case '7':
2719 : 13 : val += 0x7;
2720 : 13 : break;
2721 : : case '8':
2722 : 13 : val += 0x8;
2723 : 13 : break;
2724 : : case '9':
2725 : 13 : val += 0x9;
2726 : 13 : break;
2727 : : case 'a':
2728 : : case 'A':
2729 : 26 : val += 0xa;
2730 : 26 : break;
2731 : : case 'b':
2732 : : case 'B':
2733 : 26 : val += 0xb;
2734 : 26 : break;
2735 : : case 'c':
2736 : : case 'C':
2737 : 39 : val += 0xc;
2738 : 39 : break;
2739 : : case 'd':
2740 : : case 'D':
2741 : 26 : val += 0xd;
2742 : 26 : break;
2743 : : case 'e':
2744 : : case 'E':
2745 : 26 : val += 0xe;
2746 : 26 : break;
2747 : : case 'f':
2748 : : case 'F':
2749 : 65 : val += 0xf;
2750 : 65 : break;
2751 : : }
2752 : :
2753 : 624 : fputc(val, buf->fp);
2754 : 624 : f++;
2755 : 624 : } else {
2756 : : /* Pass through unchanged if it's not a recognizable
2757 : : hex byte. */
2758 : 65 : fputc('\\', buf->fp);
2759 : 65 : fputc('x', buf->fp);
2760 : : }
2761 : 689 : return (f);
2762 : : }
2763 : :
2764 : : const char*
2765 : 728 : read_oct_byte(xstring *buf, const char *f)
2766 : : {
2767 : 728 : int val = 0;
2768 : 728 : int count = 0;
2769 : :
2770 : : /* Octal escapes are upto three octal digits: \N, \NN or \NNN
2771 : : up to a max of \377. Note: this treats \400 as \40
2772 : : followed by character 0 passed through unchanged. */
2773 : :
2774 [ + + + + ]: 2457 : while (val < 32 && count++ < 3) {
2775 [ + + + + : 2002 : switch (*f) {
+ + + +
+ ]
2776 : : case '0':
2777 : 845 : val = val * 8 + 0;
2778 : 845 : break;
2779 : : case '1':
2780 : 130 : val = val * 8 + 1;
2781 : 130 : break;
2782 : : case '2':
2783 : 104 : val = val * 8 + 2;
2784 : 104 : break;
2785 : : case '3':
2786 : 208 : val = val * 8 + 3;
2787 : 208 : break;
2788 : : case '4':
2789 : 104 : val = val * 8 + 4;
2790 : 104 : break;
2791 : : case '5':
2792 : 78 : val = val * 8 + 5;
2793 : 78 : break;
2794 : : case '6':
2795 : 78 : val = val * 8 + 6;
2796 : 78 : break;
2797 : : case '7':
2798 : 182 : val = val * 8 + 7;
2799 : 182 : break;
2800 : : default: /* Non-octal digit */
2801 : 273 : goto done;
2802 : : }
2803 : :
2804 : 1729 : f++;
2805 : : }
2806 : : done:
2807 : 728 : fputc(val, buf->fp);
2808 : :
2809 : 728 : return (f);
2810 : : }
2811 : :
2812 : : const char *
2813 : 182 : process_escape(xstring *buf, const char *f)
2814 : : {
2815 : 182 : f++; /* Eat the \ */
2816 : :
2817 [ + + + + : 182 : switch (*f) {
+ + + + +
+ + + ]
2818 : : case 'a':
2819 : 13 : fputc('\a', buf->fp);
2820 : 13 : f++;
2821 : 13 : break;
2822 : : case 'b':
2823 : 13 : fputc('\b', buf->fp);
2824 : 13 : f++;
2825 : 13 : break;
2826 : : case 'f':
2827 : 13 : fputc('\f', buf->fp);
2828 : 13 : f++;
2829 : 13 : break;
2830 : : case 'n':
2831 : 13 : fputc('\n', buf->fp);
2832 : 13 : f++;
2833 : 13 : break;
2834 : : case 't':
2835 : 13 : fputc('\t', buf->fp);
2836 : 13 : f++;
2837 : 13 : break;
2838 : : case 'v':
2839 : 13 : fputc('\v', buf->fp);
2840 : 13 : f++;
2841 : 13 : break;
2842 : : case '\'':
2843 : 13 : fputc('\'', buf->fp);
2844 : 13 : f++;
2845 : 13 : break;
2846 : : case '"':
2847 : 13 : fputc('"', buf->fp);
2848 : 13 : f++;
2849 : 13 : break;
2850 : : case '\\':
2851 : 13 : fputc('\\', buf->fp);
2852 : 13 : f++;
2853 : 13 : break;
2854 : : case 'x': /* Hex escape: \xNN */
2855 : 26 : f = maybe_read_hex_byte(buf, f);
2856 : 26 : break;
2857 : : case '0':
2858 : : case '1':
2859 : : case '2':
2860 : : case '3':
2861 : : case '4':
2862 : : case '5':
2863 : : case '6':
2864 : : case '7': /* Oct escape: all fall through */
2865 : 13 : f = read_oct_byte(buf, f);
2866 : 13 : break;
2867 : : default: /* If it's not a recognised escape,
2868 : : leave f pointing at the escaped
2869 : : character */
2870 : 26 : fputc('\\', buf->fp);
2871 : 26 : break;
2872 : : }
2873 : :
2874 : 182 : return (f);
2875 : : }
2876 : :
2877 : : const char *
2878 : 0 : process_format_trailer(xstring *buf, struct percent_esc *p,
2879 : : const char *f, const struct pkg *pkg,
2880 : : const void *data, int count, unsigned context)
2881 : : {
2882 : : const char *fstart;
2883 : : xstring *s;
2884 : :
2885 : 0 : fstart = f;
2886 : 0 : f = parse_format(f, context, p);
2887 : :
2888 [ # # ]: 0 : if (p->fmt_code == PP_ROW_COUNTER)
2889 : 0 : s = fmt[p->fmt_code].fmt_handler(buf, &count, p);
2890 [ # # ]: 0 : else if (p->fmt_code > PP_LAST_FORMAT)
2891 : 0 : s = fmt[p->fmt_code].fmt_handler(buf, NULL, p);
2892 [ # # ]: 0 : else if (fmt[p->fmt_code].struct_pkg)
2893 : 0 : s = fmt[p->fmt_code].fmt_handler(buf, pkg, p);
2894 : : else
2895 : 0 : s = fmt[p->fmt_code].fmt_handler(buf, data, p);
2896 : :
2897 : :
2898 [ # # ]: 0 : if (s == NULL) {
2899 : 0 : f = fstart + 1; /* Eat just the % on error */
2900 : 0 : }
2901 : :
2902 : 0 : clear_percent_esc(p);
2903 : :
2904 : 0 : return (f);
2905 : : }
2906 : :
2907 : : const char *
2908 : 0 : process_format_main(xstring *buf, struct percent_esc *p,
2909 : : const char *fstart, const char *fend, void *data)
2910 : : {
2911 : : xstring *s;
2912 : :
2913 : 0 : s = fmt[p->fmt_code].fmt_handler(buf, data, p);
2914 : :
2915 : 0 : clear_percent_esc(p);
2916 : :
2917 : : /* Pass through unprocessed on error */
2918 [ # # ]: 0 : return (s == NULL ? fstart : fend);
2919 : : }
2920 : :
2921 : : /**
2922 : : * print to stdout data from pkg as indicated by the format code format
2923 : : * @param ... Varargs list of struct pkg etc. supplying the data
2924 : : * @param format String with embedded %-escapes indicating what to print
2925 : : * @return count of the number of characters printed
2926 : : */
2927 : : int
2928 : 0 : pkg_printf(const char * restrict format, ...)
2929 : : {
2930 : : int count;
2931 : : va_list ap;
2932 : :
2933 : 0 : va_start(ap, format);
2934 : 0 : count = pkg_vprintf(format, ap);
2935 : 0 : va_end(ap);
2936 : :
2937 : 0 : return (count);
2938 : : }
2939 : :
2940 : : /**
2941 : : * print to stdout data from pkg as indicated by the format code format
2942 : : * @param ap Varargs list of struct pkg etc. supplying the data
2943 : : * @param format String with embedded %-escapes indicating what to print
2944 : : * @return count of the number of characters printed
2945 : : */
2946 : : int
2947 : 0 : pkg_vprintf(const char * restrict format, va_list ap)
2948 : : {
2949 : : xstring *buf;
2950 : : int count;
2951 : :
2952 : 0 : buf = xstring_new();
2953 : :
2954 [ # # ]: 0 : if (buf)
2955 : 0 : buf = pkg_xstring_vprintf(buf, format, ap);
2956 : 0 : fflush(buf->fp);
2957 [ # # # # ]: 0 : if (buf && strlen(buf->buf) > 0) {
2958 : 0 : count = printf("%s", buf->buf);
2959 : 0 : } else
2960 : 0 : count = -1;
2961 [ # # ]: 0 : if (buf)
2962 : 0 : xstring_free(buf);
2963 : 0 : return (count);
2964 : : }
2965 : :
2966 : : /**
2967 : : * print to named stream from pkg as indicated by the format code format
2968 : : * @param ... Varargs list of struct pkg etc. supplying the data
2969 : : * @param format String with embedded %-escapes indicating what to output
2970 : : * @return count of the number of characters printed
2971 : : */
2972 : : int
2973 : 0 : pkg_fprintf(FILE * restrict stream, const char * restrict format, ...)
2974 : : {
2975 : : int count;
2976 : : va_list ap;
2977 : :
2978 : 0 : va_start(ap, format);
2979 : 0 : count = pkg_vfprintf(stream, format, ap);
2980 : 0 : va_end(ap);
2981 : :
2982 : 0 : return (count);
2983 : : }
2984 : :
2985 : : /**
2986 : : * print to named stream from pkg as indicated by the format code format
2987 : : * @param ap Varargs list of struct pkg etc. supplying the data
2988 : : * @param format String with embedded %-escapes indicating what to output
2989 : : * @return count of the number of characters printed
2990 : : */
2991 : : int
2992 : 0 : pkg_vfprintf(FILE * restrict stream, const char * restrict format, va_list ap)
2993 : : {
2994 : : xstring *buf;
2995 : : int count;
2996 : :
2997 : 0 : buf = xstring_new();
2998 : :
2999 [ # # ]: 0 : if (buf)
3000 : 0 : buf = pkg_xstring_vprintf(buf, format, ap);
3001 : 0 : fflush(buf->fp);
3002 [ # # # # ]: 0 : if (buf && strlen(buf->buf) > 0) {
3003 : 0 : count = fprintf(stream, "%s", buf->buf);
3004 : 0 : } else
3005 : 0 : count = -1;
3006 [ # # ]: 0 : if (buf)
3007 : 0 : xstring_free(buf);
3008 : 0 : return (count);
3009 : : }
3010 : :
3011 : : /**
3012 : : * print to file descriptor fd data from pkg as indicated by the format
3013 : : * code format
3014 : : * @param fd Previously opened file descriptor to print to
3015 : : * @param ... Varargs list of struct pkg etc. supplying the data
3016 : : * @param format String with embedded %-escapes indicating what to print
3017 : : * @return count of the number of characters printed
3018 : : */
3019 : : int
3020 : 0 : pkg_dprintf(int fd, const char * restrict format, ...)
3021 : : {
3022 : : int count;
3023 : : va_list ap;
3024 : :
3025 : 0 : va_start(ap, format);
3026 : 0 : count = pkg_vdprintf(fd, format, ap);
3027 : 0 : va_end(ap);
3028 : :
3029 : 0 : return (count);
3030 : : }
3031 : :
3032 : : /**
3033 : : * print to file descriptor fd data from pkg as indicated by the format
3034 : : * code format
3035 : : * @param fd Previously opened file descriptor to print to
3036 : : * @param ap Varargs list of struct pkg etc. supplying the data
3037 : : * @param format String with embedded %-escapes indicating what to print
3038 : : * @return count of the number of characters printed
3039 : : */
3040 : : int
3041 : 0 : pkg_vdprintf(int fd, const char * restrict format, va_list ap)
3042 : : {
3043 : : xstring *buf;
3044 : : int count;
3045 : :
3046 : 0 : buf = xstring_new();
3047 : :
3048 [ # # ]: 0 : if (buf)
3049 : 0 : buf = pkg_xstring_vprintf(buf, format, ap);
3050 : 0 : fflush(buf->fp);
3051 [ # # # # ]: 0 : if (buf && strlen(buf->buf) > 0) {
3052 : 0 : count = dprintf(fd, "%s", buf->buf);
3053 : 0 : } else
3054 : 0 : count = -1;
3055 [ # # ]: 0 : if (buf)
3056 : 0 : xstring_free(buf);
3057 : 0 : return (count);
3058 : : }
3059 : :
3060 : : /**
3061 : : * print to buffer str of given size data from pkg as indicated by the
3062 : : * format code format as a NULL-terminated string
3063 : : * @param str Character array buffer to receive output
3064 : : * @param size Length of the buffer str
3065 : : * @param ... Varargs list of struct pkg etc. supplying the data
3066 : : * @param format String with embedded %-escapes indicating what to output
3067 : : * @return count of the number of characters that would have been output
3068 : : * disregarding truncation to fit size
3069 : : */
3070 : : int
3071 : 0 : pkg_snprintf(char * restrict str, size_t size, const char * restrict format, ...)
3072 : : {
3073 : : int count;
3074 : : va_list ap;
3075 : :
3076 : 0 : va_start(ap, format);
3077 : 0 : count = pkg_vsnprintf(str, size, format, ap);
3078 : 0 : va_end(ap);
3079 : :
3080 : 0 : return (count);
3081 : : }
3082 : :
3083 : : /**
3084 : : * print to buffer str of given size data from pkg as indicated by the
3085 : : * format code format as a NULL-terminated string
3086 : : * @param str Character array buffer to receive output
3087 : : * @param size Length of the buffer str
3088 : : * @param ap Varargs list of struct pkg etc. supplying the data
3089 : : * @param format String with embedded %-escapes indicating what to output
3090 : : * @return count of the number of characters that would have been output
3091 : : * disregarding truncation to fit size
3092 : : */
3093 : : int
3094 : 0 : pkg_vsnprintf(char * restrict str, size_t size, const char * restrict format,
3095 : : va_list ap)
3096 : : {
3097 : : xstring *buf;
3098 : : int count;
3099 : :
3100 : 0 : buf = xstring_new();
3101 : :
3102 [ # # ]: 0 : if (buf)
3103 : 0 : buf = pkg_xstring_vprintf(buf, format, ap);
3104 : 0 : fflush(buf->fp);
3105 [ # # # # ]: 0 : if (buf && strlen(buf->buf) > 0) {
3106 : 0 : count = snprintf(str, size, "%s", buf->buf);
3107 : 0 : } else
3108 : 0 : count = -1;
3109 [ # # ]: 0 : if (buf)
3110 : 0 : xstring_free(buf);
3111 : :
3112 : 0 : return (count);
3113 : : }
3114 : :
3115 : : /**
3116 : : * Allocate a string buffer ret sufficiently big to contain formatted
3117 : : * data data from pkg as indicated by the format code format
3118 : : * @param ret location of pointer to be set to point to buffer containing
3119 : : * result
3120 : : * @param ... Varargs list of struct pkg etc. supplying the data
3121 : : * @param format String with embedded %-escapes indicating what to output
3122 : : * @return count of the number of characters printed
3123 : : */
3124 : : int
3125 : 0 : pkg_asprintf(char **ret, const char * restrict format, ...)
3126 : : {
3127 : : int count;
3128 : : va_list ap;
3129 : :
3130 : 0 : va_start(ap, format);
3131 : 0 : count = pkg_vasprintf(ret, format, ap);
3132 : 0 : va_end(ap);
3133 : :
3134 : 0 : return (count);
3135 : : }
3136 : :
3137 : : /**
3138 : : * Allocate a string buffer ret sufficiently big to contain formatted
3139 : : * data data from pkg as indicated by the format code format
3140 : : * @param ret location of pointer to be set to point to buffer containing
3141 : : * result
3142 : : * @param ap Varargs list of struct pkg etc. supplying the data
3143 : : * @param format String with embedded %-escapes indicating what to output
3144 : : * @return count of the number of characters printed
3145 : : */
3146 : : int
3147 : 0 : pkg_vasprintf(char **ret, const char * restrict format, va_list ap)
3148 : : {
3149 : : xstring *buf;
3150 : : int count;
3151 : :
3152 : 0 : buf = xstring_new();
3153 : :
3154 [ # # ]: 0 : if (buf)
3155 : 0 : buf = pkg_xstring_vprintf(buf, format, ap);
3156 : 0 : fflush(buf->fp);
3157 [ # # # # ]: 0 : if (buf && strlen(buf->buf) > 0) {
3158 : 0 : count = xasprintf(ret, "%s", buf->buf);
3159 : 0 : } else {
3160 : 0 : count = -1;
3161 : 0 : *ret = NULL;
3162 : : }
3163 [ # # ]: 0 : if (buf)
3164 : 0 : xstring_free(buf);
3165 : 0 : return (count);
3166 : : }
3167 : :
3168 : : /**
3169 : : * store data from pkg into buf as indicated by the format code format.
3170 : : * This is the core function called by all the other pkg_printf() family.
3171 : : * @param buf contains the result
3172 : : * @param ap Arglist with struct pkg etc. supplying the data
3173 : : * @param format String with embedded %-escapes indicating what to output
3174 : : * @return count of the number of characters in the result
3175 : : */
3176 : : static xstring *
3177 : 0 : pkg_xstring_vprintf(xstring * restrict buf, const char * restrict format,
3178 : : va_list ap)
3179 : : {
3180 : : const char *f, *fend;
3181 : : struct percent_esc *p;
3182 : : void *data;
3183 : :
3184 [ # # ]: 0 : assert(buf != NULL);
3185 [ # # ]: 0 : assert(format != NULL);
3186 : :
3187 : 0 : f = format;
3188 : 0 : p = new_percent_esc();
3189 : :
3190 [ # # ]: 0 : if (p == NULL) {
3191 : 0 : xstring_reset(buf);
3192 : 0 : return (buf); /* Out of memory */
3193 : : }
3194 : :
3195 [ # # ]: 0 : while ( *f != '\0' ) {
3196 [ # # # ]: 0 : switch(*f) {
3197 : : case '%':
3198 : 0 : fend = parse_format(f, PP_PKG, p);
3199 : :
3200 [ # # ]: 0 : if (p->fmt_code <= PP_LAST_FORMAT)
3201 [ # # ]: 0 : data = va_arg(ap, void *);
3202 : : else
3203 : 0 : data = NULL;
3204 : 0 : f = process_format_main(buf, p, f, fend, data);
3205 : 0 : break;
3206 : : case '\\':
3207 : 0 : f = process_escape(buf, f);
3208 : 0 : break;
3209 : : default:
3210 : 0 : fputc(*f, buf->fp);
3211 : 0 : f++;
3212 : 0 : break;
3213 : : }
3214 [ # # ]: 0 : if (f == NULL) {
3215 : 0 : xstring_reset(buf);
3216 : 0 : break; /* Error: out of memory */
3217 : : }
3218 : : }
3219 : :
3220 : 0 : free_percent_esc(p);
3221 : 0 : return (buf);
3222 : 0 : }
3223 : : /*
3224 : : * That's All Folks!
3225 : : */
|