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