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