Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/pkg
Path: blob/main/libpkg/pkg_printf.c
2065 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
* 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
format_annotations(xstring *buf, const void *data, struct percent_esc *p)
858
{
859
const struct pkg *pkg = data;
860
int count;
861
862
if (p->flags & (PP_ALTERNATE_FORM1|PP_ALTERNATE_FORM2)) {
863
return (list_count(buf, vec_len(&pkg->annotations), p));
864
} else {
865
set_list_defaults(p, "%An: %Av\n", "");
866
867
count = 1;
868
fflush(p->sep_fmt->fp);
869
fflush(p->item_fmt->fp);
870
vec_foreach(pkg->annotations, i) {
871
if (count > 1)
872
iterate_item(buf, pkg, p->sep_fmt->buf,
873
pkg->annotations.d[i], count, PP_A);
874
875
iterate_item(buf, pkg, p->item_fmt->buf,
876
pkg->annotations.d[i], count, PP_A);
877
count++;
878
}
879
}
880
return (buf);
881
}
882
883
/*
884
* %An -- Annotation tag name.
885
*/
886
xstring *
887
format_annotation_name(xstring *buf, const void *data, struct percent_esc *p)
888
{
889
const struct pkg_kv *kv = data;
890
891
return (string_val(buf, kv->key, p));
892
}
893
894
/*
895
* %Av -- Annotation value.
896
*/
897
xstring *
898
format_annotation_value(xstring *buf, const void *data, struct percent_esc *p)
899
{
900
const struct pkg_kv *kv = data;
901
902
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
format_shlibs_required(xstring *buf, const void *data, struct percent_esc *p)
912
{
913
const struct pkg *pkg = data;
914
915
if (p->flags & (PP_ALTERNATE_FORM1|PP_ALTERNATE_FORM2))
916
return (list_count(buf, vec_len(&pkg->shlibs_required), p));
917
else {
918
int count;
919
920
set_list_defaults(p, "%Bn\n", "");
921
922
count = 1;
923
fflush(p->sep_fmt->fp);
924
fflush(p->item_fmt->fp);
925
vec_foreach(pkg->shlibs_required, i) {
926
if (count > 1)
927
iterate_item(buf, pkg, p->sep_fmt->buf,
928
pkg->shlibs_required.d[i], count, PP_B);
929
930
iterate_item(buf, pkg, p->item_fmt->buf,
931
pkg->shlibs_required.d[i], count, PP_B);
932
count++;
933
}
934
}
935
return (buf);
936
}
937
938
/*
939
* %Bn -- Required Shared Library name or %bn -- Provided Shared
940
* Library name
941
*/
942
xstring *
943
format_shlib_name(xstring *buf, const void *data, struct percent_esc *p)
944
{
945
const char *shlib = data;
946
947
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
format_categories(xstring *buf, const void *data, struct percent_esc *p)
958
{
959
const struct pkg *pkg = data;
960
int count = 0;
961
962
if (p->flags & (PP_ALTERNATE_FORM1|PP_ALTERNATE_FORM2)) {
963
return (list_count(buf, vec_len(&pkg->categories), p));
964
} else {
965
set_list_defaults(p, "%Cn", ", ");
966
967
count = 1;
968
fflush(p->sep_fmt->fp);
969
fflush(p->item_fmt->fp);
970
vec_foreach(pkg->categories, i) {
971
if (count > 1)
972
iterate_item(buf, pkg, p->sep_fmt->buf,
973
pkg->categories.d[i], count, PP_C);
974
975
iterate_item(buf, pkg, p->item_fmt->buf, pkg->categories.d[i],
976
count, PP_C);
977
count++;
978
}
979
}
980
return (buf);
981
}
982
983
/*
984
* %Cn -- Category name.
985
*/
986
xstring *
987
format_category_name(xstring *buf, const void *data, struct percent_esc *p)
988
{
989
const char *cat = data;
990
991
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
format_directories(xstring *buf, const void *data, struct percent_esc *p)
1002
{
1003
const struct pkg *pkg = data;
1004
1005
if (p->flags & (PP_ALTERNATE_FORM1|PP_ALTERNATE_FORM2))
1006
return (list_count(buf, pkg_list_count(pkg, PKG_DIRS), p));
1007
else {
1008
struct pkg_dir *dir = NULL;
1009
int count;
1010
1011
set_list_defaults(p, "%Dn\n", "");
1012
1013
count = 1;
1014
fflush(p->sep_fmt->fp);
1015
fflush(p->item_fmt->fp);
1016
while (pkg_dirs(pkg, &dir) == EPKG_OK) {
1017
if (count > 1)
1018
iterate_item(buf, pkg, p->sep_fmt->buf,
1019
dir, count, PP_D);
1020
1021
iterate_item(buf, pkg, p->item_fmt->buf,
1022
dir, count, PP_D);
1023
count++;
1024
}
1025
}
1026
return (buf);
1027
}
1028
1029
/*
1030
* %Dg -- Directory group. TODO: numeric gid
1031
*/
1032
xstring *
1033
format_directory_group(xstring *buf, const void *data,
1034
struct percent_esc *p)
1035
{
1036
const struct pkg_dir *dir = data;
1037
1038
return (string_val(buf, dir->gname, p));
1039
}
1040
1041
/*
1042
* %Dn -- Directory path name.
1043
*/
1044
xstring *
1045
format_directory_path(xstring *buf, const void *data, struct percent_esc *p)
1046
{
1047
const struct pkg_dir *dir = data;
1048
1049
return (string_val(buf, dir->path, p));
1050
}
1051
1052
/*
1053
* %Dp -- Directory permissions.
1054
*/
1055
xstring *
1056
format_directory_perms(xstring *buf, const void *data,
1057
struct percent_esc *p)
1058
{
1059
const struct pkg_dir *dir = data;
1060
1061
return (mode_val(buf, dir->perm, p));
1062
}
1063
1064
/*
1065
* %Du -- Directory user. TODO: numeric UID
1066
*/
1067
xstring *
1068
format_directory_user(xstring *buf, const void *data,
1069
struct percent_esc *p)
1070
{
1071
const struct pkg_dir *dir = data;
1072
1073
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
format_files(xstring *buf, const void *data, struct percent_esc *p)
1084
{
1085
const struct pkg *pkg = data;
1086
1087
if (p->flags & (PP_ALTERNATE_FORM1|PP_ALTERNATE_FORM2))
1088
return (list_count(buf, pkg_list_count(pkg, PKG_FILES), p));
1089
else {
1090
struct pkg_file *file = NULL;
1091
int count;
1092
1093
set_list_defaults(p, "%Fn\n", "");
1094
1095
count = 1;
1096
fflush(p->sep_fmt->fp);
1097
fflush(p->item_fmt->fp);
1098
LL_FOREACH(pkg->files, file) {
1099
if (count > 1)
1100
iterate_item(buf, pkg, p->sep_fmt->buf,
1101
file, count, PP_F);
1102
1103
iterate_item(buf, pkg, p->item_fmt->buf,
1104
file, count, PP_F);
1105
count++;
1106
}
1107
}
1108
return (buf);
1109
}
1110
1111
/*
1112
* %Fg -- File group.
1113
*/
1114
xstring *
1115
format_file_group(xstring *buf, const void *data, struct percent_esc *p)
1116
{
1117
const struct pkg_file *file = data;
1118
1119
return (string_val(buf, file->gname, p));
1120
}
1121
1122
/*
1123
* %Fn -- File path name.
1124
*/
1125
xstring *
1126
format_file_path(xstring *buf, const void *data, struct percent_esc *p)
1127
{
1128
const struct pkg_file *file = data;
1129
1130
return (string_val(buf, file->path, p));
1131
}
1132
1133
/*
1134
* %Fp -- File permissions.
1135
*/
1136
xstring *
1137
format_file_perms(xstring *buf, const void *data, struct percent_esc *p)
1138
{
1139
const struct pkg_file *file = data;
1140
1141
return (mode_val(buf, file->perm, p));
1142
}
1143
1144
/*
1145
* %Fs -- File SHA256 Checksum.
1146
*/
1147
xstring *
1148
format_file_sha256(xstring *buf, const void *data, struct percent_esc *p)
1149
{
1150
const struct pkg_file *file = data;
1151
1152
return (string_val(buf, file->sum, p));
1153
}
1154
1155
/*
1156
* %Fu -- File user.
1157
*/
1158
xstring *
1159
format_file_user(xstring *buf, const void *data, struct percent_esc *p)
1160
{
1161
const struct pkg_file *file = data;
1162
1163
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
format_groups(xstring *buf, const void *data, struct percent_esc *p)
1174
{
1175
const struct pkg *pkg = data;
1176
1177
if (p->flags & (PP_ALTERNATE_FORM1|PP_ALTERNATE_FORM2))
1178
return (list_count(buf, vec_len(&pkg->groups), p));
1179
else {
1180
int count;
1181
1182
set_list_defaults(p, "%Gn\n", "");
1183
1184
count = 1;
1185
fflush(p->sep_fmt->fp);
1186
fflush(p->item_fmt->fp);
1187
vec_foreach(pkg->groups, i) {
1188
if (count > 1)
1189
iterate_item(buf, pkg, p->sep_fmt->buf,
1190
pkg->groups.d[i], count, PP_G);
1191
1192
iterate_item(buf, pkg,p->item_fmt->buf,
1193
pkg->groups.d[i], count, PP_G);
1194
count++;
1195
}
1196
}
1197
return (buf);
1198
}
1199
1200
/*
1201
* %Gn -- Group name.
1202
*/
1203
xstring *
1204
format_group_name(xstring *buf, const void *data, struct percent_esc *p)
1205
{
1206
const char *group = data;
1207
1208
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
format_row_counter(xstring *buf, const void *data, struct percent_esc *p)
1216
{
1217
const int *counter = data;
1218
1219
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
format_licenses(xstring *buf, const void *data, struct percent_esc *p)
1229
{
1230
const struct pkg *pkg = data;
1231
int count = 0;
1232
1233
if (p->flags & (PP_ALTERNATE_FORM1|PP_ALTERNATE_FORM2)) {
1234
return (list_count(buf, vec_len(&pkg->licenses), p));
1235
} else {
1236
set_list_defaults(p, "%Ln", " %l ");
1237
1238
count = 1;
1239
fflush(p->sep_fmt->fp);
1240
fflush(p->item_fmt->fp);
1241
vec_foreach(pkg->licenses, i) {
1242
if (count > 1)
1243
iterate_item(buf, pkg, p->sep_fmt->buf,
1244
pkg->licenses.d[i], count, PP_L);
1245
1246
iterate_item(buf, pkg, p->item_fmt->buf, pkg->licenses.d[i],
1247
count, PP_L);
1248
count++;
1249
}
1250
}
1251
return (buf);
1252
}
1253
1254
/*
1255
* %Ln -- License name.
1256
*/
1257
xstring *
1258
format_license_name(xstring *buf, const void *data, struct percent_esc *p)
1259
{
1260
const char *lic = data;
1261
1262
return (string_val(buf, lic, p));
1263
}
1264
1265
/*
1266
* %M -- Pkg message. string. Accepts field-width, left-align
1267
*/
1268
xstring *
1269
format_message(xstring *buffer, const void *data, struct percent_esc *p)
1270
{
1271
xstring *buf, *bufmsg = NULL;
1272
const struct pkg *pkg = data;
1273
struct pkg_message *msg;
1274
char *message;
1275
1276
vec_foreach(pkg->message, i) {
1277
msg = pkg->message.d[i];
1278
if (bufmsg == NULL) {
1279
bufmsg = xstring_new();
1280
} else {
1281
fputc('\n', bufmsg->fp);
1282
}
1283
switch(msg->type) {
1284
case PKG_MESSAGE_ALWAYS:
1285
fprintf(bufmsg->fp, "Always:\n");
1286
break;
1287
case PKG_MESSAGE_UPGRADE:
1288
fprintf(bufmsg->fp, "On upgrade");
1289
if (msg->minimum_version != NULL ||
1290
msg->maximum_version != NULL) {
1291
fprintf(bufmsg->fp, " from %s", pkg->name);
1292
}
1293
if (msg->minimum_version != NULL) {
1294
fprintf(bufmsg->fp, ">%s", msg->minimum_version);
1295
}
1296
if (msg->maximum_version != NULL) {
1297
fprintf(bufmsg->fp, "<%s", msg->maximum_version);
1298
}
1299
fprintf(bufmsg->fp, ":\n");
1300
break;
1301
case PKG_MESSAGE_INSTALL:
1302
fprintf(bufmsg->fp, "On install:\n");
1303
break;
1304
case PKG_MESSAGE_REMOVE:
1305
fprintf(bufmsg->fp, "On remove:\n");
1306
break;
1307
}
1308
fprintf(bufmsg->fp, "%s\n", msg->str);
1309
}
1310
if (bufmsg == NULL)
1311
message = NULL;
1312
else {
1313
fflush(bufmsg->fp);
1314
message = bufmsg->buf;
1315
}
1316
1317
buf = string_val(buffer, message, p);
1318
xstring_free(bufmsg);
1319
1320
return (buf);
1321
}
1322
1323
/*
1324
* %N -- Repository identity. string. Accepts field-width, left-align
1325
*/
1326
xstring *
1327
format_repo_ident(xstring *buf, const void *data, struct percent_esc *p)
1328
{
1329
const struct pkg *pkg = data;
1330
const char *reponame;
1331
1332
reponame = pkg->reponame;
1333
if (reponame == NULL) {
1334
reponame = pkg_kv_get(&pkg->annotations, "repository");
1335
if (reponame == NULL)
1336
reponame = "unknown-repository";
1337
}
1338
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
format_options(xstring *buf, const void *data, struct percent_esc *p)
1348
{
1349
const struct pkg *pkg = data;
1350
1351
if (p->flags & (PP_ALTERNATE_FORM1|PP_ALTERNATE_FORM2))
1352
return (list_count(buf, pkg_list_count(pkg, PKG_OPTIONS), p));
1353
else {
1354
struct pkg_option *opt = NULL;
1355
int count;
1356
1357
set_list_defaults(p, "%On %Ov\n", "");
1358
1359
count = 1;
1360
fflush(p->sep_fmt->fp);
1361
fflush(p->item_fmt->fp);
1362
while (pkg_options(pkg, &opt) == EPKG_OK) {
1363
if (count > 1)
1364
iterate_item(buf, pkg, p->sep_fmt->buf,
1365
opt, count, PP_O);
1366
1367
iterate_item(buf, pkg, p->item_fmt->buf,
1368
opt, count, PP_O);
1369
count++;
1370
}
1371
}
1372
return (buf);
1373
}
1374
1375
/*
1376
* %On -- Option name.
1377
*/
1378
xstring *
1379
format_option_name(xstring *buf, const void *data, struct percent_esc *p)
1380
{
1381
const struct pkg_option *option = data;
1382
1383
return (string_val(buf, option->key, p));
1384
}
1385
1386
/*
1387
* %Ov -- Option value.
1388
*/
1389
xstring *
1390
format_option_value(xstring *buf, const void *data, struct percent_esc *p)
1391
{
1392
const struct pkg_option *option = data;
1393
1394
return (string_val(buf, option->value, p));
1395
}
1396
1397
/*
1398
* %Od -- Option default value.
1399
*/
1400
xstring *
1401
format_option_default(xstring *buf, const void *data, struct percent_esc *p)
1402
{
1403
const struct pkg_option *option = data;
1404
1405
return (string_val(buf, option->value, p));
1406
}
1407
1408
/*
1409
* %OD -- Option description
1410
*/
1411
xstring *
1412
format_option_description(xstring *buf, const void *data, struct percent_esc *p)
1413
{
1414
const struct pkg_option *option = data;
1415
1416
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
format_altabi(xstring *buf, const void *data, struct percent_esc *p)
1424
{
1425
const struct pkg *pkg = data;
1426
1427
return (string_val(buf, pkg->altabi, p));
1428
}
1429
1430
/*
1431
* %R -- Repo path. string.
1432
*/
1433
xstring *
1434
format_repo_path(xstring *buf, const void *data, struct percent_esc *p)
1435
{
1436
const struct pkg *pkg = data;
1437
1438
return (string_val(buf, pkg->repopath, p));
1439
}
1440
1441
/*
1442
* %S -- Character string.
1443
*/
1444
xstring *
1445
format_char_string(xstring *buf, const void *data, struct percent_esc *p)
1446
{
1447
const char *charstring = data;
1448
1449
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
format_users(xstring *buf, const void *data, struct percent_esc *p)
1460
{
1461
const struct pkg *pkg = data;
1462
1463
if (p->flags & (PP_ALTERNATE_FORM1|PP_ALTERNATE_FORM2))
1464
return (list_count(buf, vec_len(&pkg->users), p));
1465
else {
1466
int count;
1467
1468
set_list_defaults(p, "%Un\n", "");
1469
1470
count = 1;
1471
fflush(p->sep_fmt->fp);
1472
fflush(p->item_fmt->fp);
1473
vec_foreach(pkg->users, i) {
1474
if (count > 1)
1475
iterate_item(buf, pkg, p->sep_fmt->buf,
1476
pkg->users.d[i], count, PP_U);
1477
1478
iterate_item(buf, pkg, p->item_fmt->buf,
1479
pkg->users.d[i], count, PP_U);
1480
count++;
1481
}
1482
}
1483
return (buf);
1484
}
1485
1486
/*
1487
* %Un -- User name.
1488
*/
1489
xstring *
1490
format_user_name(xstring *buf, const void *data, struct percent_esc *p)
1491
{
1492
const char *user = data;
1493
1494
return (string_val(buf, user, p));
1495
}
1496
1497
/*
1498
* %V -- Old package version. string. Accepts field width, left align
1499
*/
1500
xstring *
1501
format_old_version(xstring *buf, const void *data, struct percent_esc *p)
1502
{
1503
const struct pkg *pkg = data;
1504
1505
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
format_int_checksum(xstring *buf, const void *data, struct percent_esc *p)
1513
{
1514
struct pkg *pkg = (struct pkg *)data;
1515
1516
pkg_checksum_calculate(pkg, NULL, true, false, true);
1517
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
format_required(xstring *buf, const void *data, struct percent_esc *p)
1526
{
1527
const struct pkg *pkg = data;
1528
1529
if (p->flags & (PP_ALTERNATE_FORM1|PP_ALTERNATE_FORM2))
1530
return (list_count(buf, vec_len(&pkg->requires), p));
1531
else {
1532
int count;
1533
1534
set_list_defaults(p, "%Yn\n", "");
1535
1536
count = 1;
1537
fflush(p->sep_fmt->fp);
1538
fflush(p->item_fmt->fp);
1539
vec_foreach(pkg->requires, i) {
1540
if (count > 1)
1541
iterate_item(buf, pkg, p->sep_fmt->buf,
1542
pkg->requires.d[i], count, PP_Y);
1543
1544
iterate_item(buf, pkg, p->item_fmt->buf,
1545
pkg->requires.d[i], count, PP_Y);
1546
count++;
1547
}
1548
}
1549
return (buf);
1550
}
1551
1552
/*
1553
* %Yn -- Required name or %yn -- Provided name
1554
*/
1555
xstring *
1556
format_provide_name(xstring *buf, const void *data, struct percent_esc *p)
1557
{
1558
const char *provide = data;
1559
1560
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
format_autoremove(xstring *buf, const void *data, struct percent_esc *p)
1569
{
1570
const struct pkg *pkg = data;
1571
1572
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
format_shlibs_provided(xstring *buf, const void *data, struct percent_esc *p)
1583
{
1584
const struct pkg *pkg = data;
1585
1586
if (p->flags & (PP_ALTERNATE_FORM1|PP_ALTERNATE_FORM2))
1587
return (list_count(buf, vec_len(&pkg->shlibs_provided), p));
1588
else {
1589
int count;
1590
1591
set_list_defaults(p, "%bn\n", "");
1592
1593
count = 1;
1594
fflush(p->sep_fmt->fp);
1595
fflush(p->item_fmt->fp);
1596
vec_foreach(pkg->shlibs_provided, i) {
1597
if (count > 1)
1598
iterate_item(buf, pkg, p->sep_fmt->buf,
1599
pkg->shlibs_provided.d[i], count, PP_b);
1600
1601
iterate_item(buf, pkg, p->item_fmt->buf,
1602
pkg->shlibs_provided.d[i], count, PP_b);
1603
count++;
1604
}
1605
}
1606
return (buf);
1607
}
1608
1609
/*
1610
* %c -- Comment. string. Accepts field-width, left-align
1611
*/
1612
xstring *
1613
format_comment(xstring *buf, const void *data, struct percent_esc *p)
1614
{
1615
const struct pkg *pkg = data;
1616
1617
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
format_dependencies(xstring *buf, const void *data, struct percent_esc *p)
1627
{
1628
const struct pkg *pkg = data;
1629
1630
if (p->flags & (PP_ALTERNATE_FORM1|PP_ALTERNATE_FORM2))
1631
return (list_count(buf, pkg_list_count(pkg, PKG_DEPS), p));
1632
else {
1633
struct pkg_dep *dep = NULL;
1634
int count;
1635
1636
set_list_defaults(p, "%dn-%dv\n", "");
1637
1638
count = 1;
1639
fflush(p->sep_fmt->fp);
1640
fflush(p->item_fmt->fp);
1641
while (pkg_deps(pkg, &dep) == EPKG_OK) {
1642
if (count > 1)
1643
iterate_item(buf, pkg, p->sep_fmt->buf,
1644
dep, count, PP_d);
1645
1646
iterate_item(buf, pkg, p->item_fmt->buf,
1647
dep, count, PP_d);
1648
count++;
1649
}
1650
}
1651
return (buf);
1652
}
1653
1654
/*
1655
* %dk -- Dependency lock status or %rk -- Requirement lock status.
1656
*/
1657
xstring *
1658
format_dependency_lock(xstring *buf, const void *data,
1659
struct percent_esc *p)
1660
{
1661
const struct pkg_dep *dep = data;
1662
1663
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
format_dependency_name(xstring *buf, const void *data,
1671
struct percent_esc *p)
1672
{
1673
const struct pkg_dep *dep = data;
1674
1675
return (string_val(buf, dep->name, p));
1676
}
1677
1678
/*
1679
* %do -- Dependency origin or %ro -- Requirement origin.
1680
*/
1681
xstring *
1682
format_dependency_origin(xstring *buf, const void *data,
1683
struct percent_esc *p)
1684
{
1685
const struct pkg_dep *dep = data;
1686
1687
return (string_val(buf, dep->origin, p));
1688
}
1689
1690
/*
1691
* %dv -- Dependency version or %rv -- Requirement version.
1692
*/
1693
xstring *
1694
format_dependency_version(xstring *buf, const void *data,
1695
struct percent_esc *p)
1696
{
1697
const struct pkg_dep *dep = data;
1698
1699
return (string_val(buf, dep->version, p));
1700
}
1701
1702
/*
1703
* %e -- Description. string. Accepts field-width, left-align
1704
*/
1705
xstring *
1706
format_description(xstring *buf, const void *data, struct percent_esc *p)
1707
{
1708
const struct pkg *pkg = data;
1709
1710
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
format_lock_status(xstring *buf, const void *data, struct percent_esc *p)
1720
{
1721
const struct pkg *pkg = data;
1722
1723
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
format_license_logic(xstring *buf, const void *data, struct percent_esc *p)
1733
{
1734
const struct pkg *pkg = data;
1735
1736
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
format_maintainer(xstring *buf, const void *data, struct percent_esc *p)
1744
{
1745
const struct pkg *pkg = data;
1746
1747
return (string_val(buf, pkg->maintainer, p));
1748
}
1749
1750
/*
1751
* %n -- Package name. string. Accepts field-width, left-align
1752
*/
1753
xstring *
1754
format_name(xstring *buf, const void *data, struct percent_esc *p)
1755
{
1756
const struct pkg *pkg = data;
1757
1758
return (string_val(buf, pkg->name, p));
1759
}
1760
1761
/*
1762
* %o -- Package origin. string. Accepts field-width, left-align
1763
*/
1764
xstring *
1765
format_origin(xstring *buf, const void *data, struct percent_esc *p)
1766
{
1767
const struct pkg *pkg = data;
1768
1769
return (string_val(buf, pkg->origin, p));
1770
}
1771
1772
/*
1773
* %p -- Installation prefix. string. Accepts field-width, left-align
1774
*/
1775
xstring *
1776
format_prefix(xstring *buf, const void *data, struct percent_esc *p)
1777
{
1778
const struct pkg *pkg = data;
1779
1780
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
format_architecture(xstring *buf, const void *data, struct percent_esc *p)
1788
{
1789
const struct pkg *pkg = data;
1790
1791
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
format_requirements(xstring *buf, const void *data, struct percent_esc *p)
1801
{
1802
const struct pkg *pkg = data;
1803
1804
if (p->flags & (PP_ALTERNATE_FORM1|PP_ALTERNATE_FORM2))
1805
return(list_count(buf, pkg_list_count(pkg, PKG_RDEPS), p));
1806
else {
1807
struct pkg_dep *req = NULL;
1808
int count;
1809
1810
set_list_defaults(p, "%rn-%rv\n", "");
1811
1812
count = 1;
1813
fflush(p->sep_fmt->fp);
1814
fflush(p->item_fmt->fp);
1815
while (pkg_rdeps(pkg, &req) == EPKG_OK) {
1816
if (count > 1)
1817
iterate_item(buf, pkg, p->sep_fmt->buf,
1818
req, count, PP_r);
1819
1820
iterate_item(buf, pkg, p->item_fmt->buf,
1821
req, count, PP_r);
1822
count++;
1823
}
1824
}
1825
return (buf);
1826
}
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
format_flatsize(xstring *buf, const void *data, struct percent_esc *p)
1837
{
1838
const struct pkg *pkg = data;
1839
1840
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
format_install_tstamp(xstring *buf, const void *data, struct percent_esc *p)
1851
{
1852
const struct pkg *pkg = data;
1853
1854
fflush(p->item_fmt->fp);
1855
if (strlen(p->item_fmt->buf) == 0)
1856
return (int_val(buf, pkg->timestamp, p));
1857
else {
1858
char buffer[1024];
1859
time_t tsv;
1860
1861
tsv = (time_t)pkg->timestamp;
1862
strftime(buffer, sizeof(buffer), p->item_fmt->buf,
1863
localtime(&tsv));
1864
fprintf(buf->fp, "%s", buffer);
1865
}
1866
return (buf);
1867
}
1868
1869
/*
1870
* %v -- Package version. string. Accepts field width, left align
1871
*/
1872
xstring *
1873
format_version(xstring *buf, const void *data, struct percent_esc *p)
1874
{
1875
const struct pkg *pkg = data;
1876
1877
return (string_val(buf, pkg->version, p));
1878
}
1879
1880
/*
1881
* %u -- Package checksum. string. Accepts field width, left align
1882
*/
1883
xstring *
1884
format_checksum(xstring *buf, const void *data, struct percent_esc *p)
1885
{
1886
const struct pkg *pkg = data;
1887
1888
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
format_home_url(xstring *buf, const void *data, struct percent_esc *p)
1896
{
1897
const struct pkg *pkg = data;
1898
1899
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
format_pkgsize(xstring *buf, const void *data, struct percent_esc *p)
1911
{
1912
const struct pkg *pkg = data;
1913
1914
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
format_provided(xstring *buf, const void *data, struct percent_esc *p)
1924
{
1925
const struct pkg *pkg = data;
1926
1927
if (p->flags & (PP_ALTERNATE_FORM1|PP_ALTERNATE_FORM2))
1928
return (list_count(buf, vec_len(&pkg->provides), p));
1929
else {
1930
int count;
1931
1932
set_list_defaults(p, "%yn\n", "");
1933
1934
count = 1;
1935
fflush(p->sep_fmt->fp);
1936
fflush(p->item_fmt->fp);
1937
vec_foreach(pkg->provides, i) {
1938
if (count > 1)
1939
iterate_item(buf, pkg, p->sep_fmt->buf,
1940
pkg->provides.d[i], count, PP_y);
1941
1942
iterate_item(buf, pkg, p->item_fmt->buf,
1943
pkg->provides.d[i], count, PP_y);
1944
count++;
1945
}
1946
}
1947
return (buf);
1948
}
1949
1950
/*
1951
* %z -- Package short checksum. string. Accepts field width, left align
1952
*/
1953
xstring *
1954
format_short_checksum(xstring *buf, const void *data, struct percent_esc *p)
1955
{
1956
const struct pkg *pkg = data;
1957
char csum[PKG_FILE_CKSUM_CHARS + 1];
1958
int slen;
1959
1960
if (pkg->sum != NULL)
1961
slen = MIN(PKG_FILE_CKSUM_CHARS, strlen(pkg->sum));
1962
else
1963
slen = 0;
1964
memcpy(csum, pkg->sum, slen);
1965
csum[slen] = '\0';
1966
1967
return (string_val(buf, csum, p));
1968
}
1969
/*
1970
* %% -- Output a literal '%' character
1971
*/
1972
xstring *
1973
format_literal_percent(xstring *buf, __unused const void *data,
1974
__unused struct percent_esc *p)
1975
{
1976
fputc('%', buf->fp);
1977
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
format_unknown(xstring *buf, __unused const void *data,
1986
__unused struct percent_esc *p)
1987
{
1988
fputc('%', buf->fp);
1989
return (NULL);
1990
}
1991
1992
/* -------------------------------------------------------------- */
1993
1994
struct percent_esc *
1995
new_percent_esc(void)
1996
{
1997
struct percent_esc *p;
1998
1999
p = xcalloc(1, sizeof(struct percent_esc));
2000
p->item_fmt = xstring_new();
2001
p->sep_fmt = xstring_new();
2002
return (p);
2003
}
2004
2005
struct percent_esc *
2006
clear_percent_esc(struct percent_esc *p)
2007
{
2008
p->flags = 0;
2009
p->width = 0;
2010
p->trailer_status = 0;
2011
xstring_reset(p->item_fmt);
2012
xstring_reset(p->sep_fmt);
2013
2014
p->fmt_code = '\0';
2015
2016
return (p);
2017
}
2018
2019
void
2020
free_percent_esc(struct percent_esc *p)
2021
{
2022
if (p) {
2023
if (p->item_fmt)
2024
xstring_free(p->item_fmt);
2025
if (p->sep_fmt)
2026
xstring_free(p->sep_fmt);
2027
free(p);
2028
}
2029
return;
2030
}
2031
2032
char *
2033
gen_format(char *buf, size_t buflen, unsigned flags, const char *tail)
2034
{
2035
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
tlen = strlen(tail);
2043
2044
if (buflen - bp < tlen + 3)
2045
return (NULL);
2046
2047
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
if ((flags & (PP_EXPLICIT_PLUS|PP_SPACE_FOR_PLUS)) ==
2055
(PP_EXPLICIT_PLUS|PP_SPACE_FOR_PLUS))
2056
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
if ((flags & (PP_LEFT_ALIGN|PP_ZERO_PAD)) ==
2062
(PP_LEFT_ALIGN|PP_ZERO_PAD))
2063
flags &= ~(PP_ZERO_PAD);
2064
2065
if (flags & PP_ALTERNATE_FORM2)
2066
buf[bp++] = '#';
2067
2068
if (flags & PP_LEFT_ALIGN)
2069
buf[bp++] = '-';
2070
2071
if (flags & PP_ZERO_PAD)
2072
buf[bp++] = '0';
2073
2074
if (buflen - bp < tlen + 2)
2075
return (NULL);
2076
2077
if (flags & PP_EXPLICIT_PLUS)
2078
buf[bp++] = '+';
2079
2080
if (flags & PP_SPACE_FOR_PLUS)
2081
buf[bp++] = ' ';
2082
2083
if (flags & PP_THOUSANDS_SEP)
2084
buf[bp++] = '\'';
2085
2086
if (buflen - bp < tlen + 2)
2087
return (NULL);
2088
2089
/* The effect of 0 meaning 'zero fill' is indisinguishable
2090
from 0 meaning 'a field width of zero' */
2091
2092
buf[bp++] = '*';
2093
buf[bp] = '\0';
2094
2095
strlcat(buf, tail, buflen);
2096
2097
return (buf);
2098
}
2099
2100
2101
xstring *
2102
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
const char *bin_pfx[MAXSCALE] =
2116
{ "", "Ki", "Mi", "Gi", "Ti", "Pi", "Ei" };
2117
const char *si_pfx[MAXSCALE] =
2118
{ "", "k", "M", "G", "T", "P", "E" };
2119
char format[16];
2120
2121
bin_scale = ((p->flags & PP_ALTERNATE_FORM2) != 0);
2122
2123
p->flags &= ~(PP_ALTERNATE_FORM1|PP_ALTERNATE_FORM2);
2124
2125
if (gen_format(format, sizeof(format), p->flags, ".*f") == NULL)
2126
return (NULL);
2127
2128
if (number >= 0) {
2129
num = number;
2130
sign = 1;
2131
} else {
2132
num = -number;
2133
sign = -1;
2134
}
2135
2136
divisor = bin_scale ? 1024 : 1000;
2137
2138
for (scale = 0; scale < MAXSCALE; scale++) {
2139
if (num < divisor)
2140
break;
2141
num /= divisor;
2142
}
2143
2144
if (scale == MAXSCALE)
2145
scale--;
2146
2147
if (scale == 0)
2148
scale_width = 0;
2149
else if (bin_scale)
2150
scale_width = 2;
2151
else
2152
scale_width = 1;
2153
2154
if (p->width == 0)
2155
width = 0;
2156
else if (p->width <= scale_width)
2157
width = 1;
2158
else
2159
width = p->width - scale_width;
2160
2161
if (num >= 100)
2162
precision = 0;
2163
else if (num >= 10) {
2164
if (width == 0 || width > 3)
2165
precision = 1;
2166
else
2167
precision = 0;
2168
} else {
2169
if (width == 0 || width > 3)
2170
precision = 2;
2171
else if (width == 3)
2172
precision = 1;
2173
else
2174
precision = 0;
2175
}
2176
2177
fprintf(buf->fp, format, width, precision, num * sign);
2178
2179
if (scale > 0)
2180
fprintf(buf->fp, "%s",
2181
bin_scale ? bin_pfx[scale] : si_pfx[scale]);
2182
2183
return (buf);
2184
}
2185
2186
xstring *
2187
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
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
if (gen_format(format, sizeof(format), p->flags, "s") == NULL)
2202
return (NULL);
2203
2204
fprintf(buf->fp, format, p->width, str);
2205
return (buf);
2206
}
2207
2208
xstring *
2209
int_val(xstring *buf, int64_t value, struct percent_esc *p)
2210
{
2211
if (p->flags & (PP_ALTERNATE_FORM1|PP_ALTERNATE_FORM2))
2212
return (human_number(buf, value, p));
2213
else {
2214
char format[16];
2215
2216
if (gen_format(format, sizeof(format), p->flags, PRId64)
2217
== NULL)
2218
return (NULL);
2219
2220
fprintf(buf->fp, format, p->width, value);
2221
}
2222
return (buf);
2223
}
2224
2225
xstring *
2226
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
if (p->flags & PP_ALTERNATE_FORM2)
2235
alternate = 2;
2236
else if (p->flags & PP_ALTERNATE_FORM1)
2237
alternate = 1;
2238
else
2239
alternate = 0;
2240
2241
p->flags &= ~(PP_ALTERNATE_FORM1|PP_ALTERNATE_FORM2);
2242
2243
return (string_val(buf, boolean_str[value][alternate], p));
2244
}
2245
2246
xstring *
2247
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
if (p->flags & PP_ALTERNATE_FORM1) {
2257
char modebuf[12];
2258
2259
strmode(mode, modebuf);
2260
2261
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
if ( (p->flags & PP_EXPLICIT_PLUS) == 0 )
2275
mode &= ALLPERMS;
2276
2277
p->flags &= ~(PP_ALTERNATE_FORM1|PP_EXPLICIT_PLUS);
2278
2279
if (gen_format(format, sizeof(format), p->flags, PRIo16)
2280
== NULL)
2281
return (NULL);
2282
2283
fprintf(buf->fp, format, p->width, mode);
2284
}
2285
return (buf);
2286
}
2287
2288
xstring *
2289
liclog_val(xstring *buf, lic_t licenselogic, struct percent_esc *p)
2290
{
2291
int alternate;
2292
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
switch (licenselogic) {
2301
case LICENSE_SINGLE:
2302
llogic = PP_LIC_SINGLE;
2303
break;
2304
case LICENSE_OR:
2305
llogic = PP_LIC_OR;
2306
break;
2307
case LICENSE_AND:
2308
llogic = PP_LIC_AND;
2309
break;
2310
}
2311
2312
if (p->flags & PP_ALTERNATE_FORM2)
2313
alternate = 2;
2314
else if (p->flags & PP_ALTERNATE_FORM1)
2315
alternate = 1;
2316
else
2317
alternate = 0;
2318
2319
p->flags &= ~(PP_ALTERNATE_FORM1|PP_ALTERNATE_FORM2);
2320
2321
return (string_val(buf, liclog_str[llogic][alternate], p));
2322
}
2323
2324
xstring *
2325
list_count(xstring *buf, int64_t count, struct percent_esc *p)
2326
{
2327
/* Convert to 0 or 1 for %?X */
2328
if (p->flags & PP_ALTERNATE_FORM1)
2329
count = (count > 0);
2330
2331
/* Turn off %#X and %?X flags, then print as a normal integer */
2332
p->flags &= ~(PP_ALTERNATE_FORM1|PP_ALTERNATE_FORM2);
2333
2334
return (int_val(buf, count, p));
2335
}
2336
2337
struct percent_esc *
2338
set_list_defaults(struct percent_esc *p, const char *item_fmt,
2339
const char *sep_fmt)
2340
{
2341
if ((p->trailer_status & ITEM_FMT_SET) != ITEM_FMT_SET) {
2342
fprintf(p->item_fmt->fp, "%s", item_fmt);
2343
p->trailer_status |= ITEM_FMT_SET;
2344
}
2345
if ((p->trailer_status & SEP_FMT_SET) != SEP_FMT_SET) {
2346
fprintf(p->sep_fmt->fp, "%s", sep_fmt);
2347
p->trailer_status |= SEP_FMT_SET;
2348
}
2349
return (p);
2350
}
2351
2352
xstring *
2353
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
f = format;
2362
p = new_percent_esc();
2363
2364
if (p == NULL) {
2365
xstring_reset(buf);
2366
return (buf); /* Out of memory */
2367
}
2368
2369
while ( *f != '\0' ) {
2370
switch(*f) {
2371
case '%':
2372
f = process_format_trailer(buf, p, f, pkg, data, count, context);
2373
break;
2374
case '\\':
2375
f = process_escape(buf, f);
2376
break;
2377
default:
2378
fprintf(buf->fp, "%c", *f);
2379
f++;
2380
break;
2381
}
2382
if (f == NULL) {
2383
xstring_reset(buf);
2384
break; /* Out of memory */
2385
}
2386
}
2387
2388
free_percent_esc(p);
2389
return (buf);
2390
}
2391
2392
const char *
2393
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
done = false;
2408
while (!done) {
2409
switch (*f) {
2410
case '?':
2411
p->flags |= PP_ALTERNATE_FORM1;
2412
break;
2413
case '#':
2414
p->flags |= PP_ALTERNATE_FORM2;
2415
break;
2416
case '-':
2417
p->flags |= PP_LEFT_ALIGN;
2418
break;
2419
case '+':
2420
p->flags |= PP_EXPLICIT_PLUS;
2421
break;
2422
case ' ':
2423
p->flags |= PP_SPACE_FOR_PLUS;
2424
break;
2425
case '0':
2426
p->flags |= PP_ZERO_PAD;
2427
break;
2428
case '\'':
2429
p->flags |= PP_THOUSANDS_SEP;
2430
break;
2431
default:
2432
done = true;
2433
break;
2434
}
2435
if (!done)
2436
f++;
2437
}
2438
return (f);
2439
}
2440
2441
const char *
2442
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
done = false;
2452
while (!done) {
2453
switch(*f) {
2454
case '0':
2455
p->width = p->width * 10 + 0;
2456
break;
2457
case '1':
2458
p->width = p->width * 10 + 1;
2459
break;
2460
case '2':
2461
p->width = p->width * 10 + 2;
2462
break;
2463
case '3':
2464
p->width = p->width * 10 + 3;
2465
break;
2466
case '4':
2467
p->width = p->width * 10 + 4;
2468
break;
2469
case '5':
2470
p->width = p->width * 10 + 5;
2471
break;
2472
case '6':
2473
p->width = p->width * 10 + 6;
2474
break;
2475
case '7':
2476
p->width = p->width * 10 + 7;
2477
break;
2478
case '8':
2479
p->width = p->width * 10 + 8;
2480
break;
2481
case '9':
2482
p->width = p->width * 10 + 9;
2483
break;
2484
default:
2485
done = true;
2486
break;
2487
}
2488
if (!done)
2489
f++;
2490
}
2491
return (f);
2492
}
2493
2494
const char *
2495
format_trailer(const char *f, struct percent_esc *p)
2496
{
2497
2498
/* is the trailer even present? */
2499
2500
if (f[0] == '%' && f[1] == '{') {
2501
bool sep = false;
2502
bool done = false;
2503
const char *f1;
2504
const char *f2;
2505
2506
p->trailer_status |= ITEM_FMT_SET;
2507
f1 = f + 2;
2508
2509
for (f2 = f1; *f2 != '\0'; f2++) {
2510
if (f2[0] == '%' && ( f2[1] == '}' || f2[1] == '|')) {
2511
if (f2[1] == '|')
2512
sep = true;
2513
else
2514
done = true;
2515
f1 = f2 + 2;
2516
break;
2517
}
2518
fputc(*f2, p->item_fmt->fp);
2519
fflush(p->item_fmt->fp);
2520
}
2521
2522
2523
if (sep) {
2524
p->trailer_status |= SEP_FMT_SET;
2525
done = false;
2526
2527
for (f2 = f1; *f2 != '\0'; f2++) {
2528
if (f2[0] == '%' && f2[1] == '}') {
2529
done = true;
2530
f1 = f2 + 2;
2531
break;
2532
}
2533
fputc(*f2, p->sep_fmt->fp);
2534
fflush(p->sep_fmt->fp);
2535
}
2536
2537
}
2538
2539
if (done) {
2540
f = f1;
2541
} else {
2542
xstring_reset(p->item_fmt);
2543
xstring_reset(p->sep_fmt);
2544
}
2545
}
2546
2547
return (f);
2548
}
2549
2550
const char *
2551
format_code(const char *f, unsigned context, struct percent_esc *p)
2552
{
2553
fmt_code_t fmt_code;
2554
2555
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
for (fmt_code = 0; fmt_code < PP_END_MARKER; fmt_code++) {
2563
if ((fmt[fmt_code].context & context) != context)
2564
continue;
2565
if (fmt[fmt_code].fmt_main != f[0])
2566
continue;
2567
if (fmt[fmt_code].fmt_sub == f[1] && f[1] != '\0') {
2568
p->fmt_code = fmt_code;
2569
f += 2;
2570
break;
2571
}
2572
if (fmt[fmt_code].fmt_sub == '\0') {
2573
p->fmt_code = fmt_code;
2574
f++;
2575
break;
2576
}
2577
}
2578
2579
return (f);
2580
}
2581
2582
const char *
2583
parse_format(const char *f, unsigned context, struct percent_esc *p)
2584
{
2585
f++; /* Eat the % */
2586
2587
f = field_modifier(f, p);
2588
2589
f = field_width(f, p);
2590
2591
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
if ((context & PP_PKG) == PP_PKG &&
2600
fmt[p->fmt_code].has_trailer &&
2601
(p->flags & (PP_ALTERNATE_FORM1|PP_ALTERNATE_FORM2)) == 0)
2602
f = format_trailer(f, p);
2603
2604
return (f);
2605
}
2606
2607
const char*
2608
maybe_read_hex_byte(xstring *buf, const char *f)
2609
{
2610
/* Hex escapes are of the form \xNN -- always two hex digits */
2611
2612
f++; /* eat the x */
2613
2614
if (isxdigit(f[0]) && isxdigit(f[1])) {
2615
int val;
2616
2617
switch(*f) {
2618
case '0':
2619
val = 0x0;
2620
break;
2621
case '1':
2622
val = 0x10;
2623
break;
2624
case '2':
2625
val = 0x20;
2626
break;
2627
case '3':
2628
val = 0x30;
2629
break;
2630
case '4':
2631
val = 0x40;
2632
break;
2633
case '5':
2634
val = 0x50;
2635
break;
2636
case '6':
2637
val = 0x60;
2638
break;
2639
case '7':
2640
val = 0x70;
2641
break;
2642
case '8':
2643
val = 0x80;
2644
break;
2645
case '9':
2646
val = 0x90;
2647
break;
2648
case 'a':
2649
case 'A':
2650
val = 0xa0;
2651
break;
2652
case 'b':
2653
case 'B':
2654
val = 0xb0;
2655
break;
2656
case 'c':
2657
case 'C':
2658
val = 0xc0;
2659
break;
2660
case 'd':
2661
case 'D':
2662
val = 0xd0;
2663
break;
2664
case 'e':
2665
case 'E':
2666
val = 0xe0;
2667
break;
2668
case 'f':
2669
case 'F':
2670
val = 0xf0;
2671
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
val = 0x0;
2678
break;
2679
}
2680
2681
f++;
2682
2683
switch(*f) {
2684
case '0':
2685
val += 0x0;
2686
break;
2687
case '1':
2688
val += 0x1;
2689
break;
2690
case '2':
2691
val += 0x2;
2692
break;
2693
case '3':
2694
val += 0x3;
2695
break;
2696
case '4':
2697
val += 0x4;
2698
break;
2699
case '5':
2700
val += 0x5;
2701
break;
2702
case '6':
2703
val += 0x6;
2704
break;
2705
case '7':
2706
val += 0x7;
2707
break;
2708
case '8':
2709
val += 0x8;
2710
break;
2711
case '9':
2712
val += 0x9;
2713
break;
2714
case 'a':
2715
case 'A':
2716
val += 0xa;
2717
break;
2718
case 'b':
2719
case 'B':
2720
val += 0xb;
2721
break;
2722
case 'c':
2723
case 'C':
2724
val += 0xc;
2725
break;
2726
case 'd':
2727
case 'D':
2728
val += 0xd;
2729
break;
2730
case 'e':
2731
case 'E':
2732
val += 0xe;
2733
break;
2734
case 'f':
2735
case 'F':
2736
val += 0xf;
2737
break;
2738
}
2739
2740
fputc(val, buf->fp);
2741
f++;
2742
} else {
2743
/* Pass through unchanged if it's not a recognizable
2744
hex byte. */
2745
fputc('\\', buf->fp);
2746
fputc('x', buf->fp);
2747
}
2748
return (f);
2749
}
2750
2751
const char*
2752
read_oct_byte(xstring *buf, const char *f)
2753
{
2754
int val = 0;
2755
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
while (val < 32 && count++ < 3) {
2762
switch (*f) {
2763
case '0':
2764
val = val * 8 + 0;
2765
break;
2766
case '1':
2767
val = val * 8 + 1;
2768
break;
2769
case '2':
2770
val = val * 8 + 2;
2771
break;
2772
case '3':
2773
val = val * 8 + 3;
2774
break;
2775
case '4':
2776
val = val * 8 + 4;
2777
break;
2778
case '5':
2779
val = val * 8 + 5;
2780
break;
2781
case '6':
2782
val = val * 8 + 6;
2783
break;
2784
case '7':
2785
val = val * 8 + 7;
2786
break;
2787
default: /* Non-octal digit */
2788
goto done;
2789
}
2790
2791
f++;
2792
}
2793
done:
2794
fputc(val, buf->fp);
2795
2796
return (f);
2797
}
2798
2799
const char *
2800
process_escape(xstring *buf, const char *f)
2801
{
2802
f++; /* Eat the \ */
2803
2804
switch (*f) {
2805
case 'a':
2806
fputc('\a', buf->fp);
2807
f++;
2808
break;
2809
case 'b':
2810
fputc('\b', buf->fp);
2811
f++;
2812
break;
2813
case 'f':
2814
fputc('\f', buf->fp);
2815
f++;
2816
break;
2817
case 'n':
2818
fputc('\n', buf->fp);
2819
f++;
2820
break;
2821
case 't':
2822
fputc('\t', buf->fp);
2823
f++;
2824
break;
2825
case 'v':
2826
fputc('\v', buf->fp);
2827
f++;
2828
break;
2829
case '\'':
2830
fputc('\'', buf->fp);
2831
f++;
2832
break;
2833
case '"':
2834
fputc('"', buf->fp);
2835
f++;
2836
break;
2837
case '\\':
2838
fputc('\\', buf->fp);
2839
f++;
2840
break;
2841
case 'x': /* Hex escape: \xNN */
2842
f = maybe_read_hex_byte(buf, f);
2843
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
f = read_oct_byte(buf, f);
2853
break;
2854
default: /* If it's not a recognised escape,
2855
leave f pointing at the escaped
2856
character */
2857
fputc('\\', buf->fp);
2858
break;
2859
}
2860
2861
return (f);
2862
}
2863
2864
const char *
2865
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
fstart = f;
2873
f = parse_format(f, context, p);
2874
2875
if (p->fmt_code == PP_ROW_COUNTER)
2876
s = fmt[p->fmt_code].fmt_handler(buf, &count, p);
2877
else if (p->fmt_code > PP_LAST_FORMAT)
2878
s = fmt[p->fmt_code].fmt_handler(buf, NULL, p);
2879
else if (fmt[p->fmt_code].struct_pkg)
2880
s = fmt[p->fmt_code].fmt_handler(buf, pkg, p);
2881
else
2882
s = fmt[p->fmt_code].fmt_handler(buf, data, p);
2883
2884
2885
if (s == NULL) {
2886
f = fstart + 1; /* Eat just the % on error */
2887
}
2888
2889
clear_percent_esc(p);
2890
2891
return (f);
2892
}
2893
2894
const char *
2895
process_format_main(xstring *buf, struct percent_esc *p,
2896
const char *fstart, const char *fend, void *data)
2897
{
2898
xstring *s;
2899
2900
s = fmt[p->fmt_code].fmt_handler(buf, data, p);
2901
2902
clear_percent_esc(p);
2903
2904
/* Pass through unprocessed on error */
2905
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
pkg_printf(const char * restrict format, ...)
2916
{
2917
int count;
2918
va_list ap;
2919
2920
va_start(ap, format);
2921
count = pkg_vprintf(format, ap);
2922
va_end(ap);
2923
2924
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
pkg_vprintf(const char * restrict format, va_list ap)
2935
{
2936
xstring *buf;
2937
int count;
2938
2939
buf = xstring_new();
2940
2941
if (buf)
2942
buf = pkg_xstring_vprintf(buf, format, ap);
2943
fflush(buf->fp);
2944
if (buf && strlen(buf->buf) > 0) {
2945
count = printf("%s", buf->buf);
2946
} else
2947
count = -1;
2948
if (buf)
2949
xstring_free(buf);
2950
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
pkg_fprintf(FILE * restrict stream, const char * restrict format, ...)
2961
{
2962
int count;
2963
va_list ap;
2964
2965
va_start(ap, format);
2966
count = pkg_vfprintf(stream, format, ap);
2967
va_end(ap);
2968
2969
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
pkg_vfprintf(FILE * restrict stream, const char * restrict format, va_list ap)
2980
{
2981
xstring *buf;
2982
int count;
2983
2984
buf = xstring_new();
2985
2986
if (buf)
2987
buf = pkg_xstring_vprintf(buf, format, ap);
2988
fflush(buf->fp);
2989
if (buf && strlen(buf->buf) > 0) {
2990
count = fprintf(stream, "%s", buf->buf);
2991
} else
2992
count = -1;
2993
if (buf)
2994
xstring_free(buf);
2995
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
pkg_dprintf(int fd, const char * restrict format, ...)
3008
{
3009
int count;
3010
va_list ap;
3011
3012
va_start(ap, format);
3013
count = pkg_vdprintf(fd, format, ap);
3014
va_end(ap);
3015
3016
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
pkg_vdprintf(int fd, const char * restrict format, va_list ap)
3029
{
3030
xstring *buf;
3031
int count;
3032
3033
buf = xstring_new();
3034
3035
if (buf)
3036
buf = pkg_xstring_vprintf(buf, format, ap);
3037
fflush(buf->fp);
3038
if (buf && strlen(buf->buf) > 0) {
3039
count = dprintf(fd, "%s", buf->buf);
3040
} else
3041
count = -1;
3042
if (buf)
3043
xstring_free(buf);
3044
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
pkg_snprintf(char * restrict str, size_t size, const char * restrict format, ...)
3059
{
3060
int count;
3061
va_list ap;
3062
3063
va_start(ap, format);
3064
count = pkg_vsnprintf(str, size, format, ap);
3065
va_end(ap);
3066
3067
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
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
buf = xstring_new();
3088
3089
if (buf)
3090
buf = pkg_xstring_vprintf(buf, format, ap);
3091
fflush(buf->fp);
3092
if (buf && strlen(buf->buf) > 0) {
3093
count = snprintf(str, size, "%s", buf->buf);
3094
} else
3095
count = -1;
3096
if (buf)
3097
xstring_free(buf);
3098
3099
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
pkg_asprintf(char **ret, const char * restrict format, ...)
3113
{
3114
int count;
3115
va_list ap;
3116
3117
va_start(ap, format);
3118
count = pkg_vasprintf(ret, format, ap);
3119
va_end(ap);
3120
3121
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
pkg_vasprintf(char **ret, 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 = xasprintf(ret, "%s", buf->buf);
3146
} else {
3147
count = -1;
3148
*ret = NULL;
3149
}
3150
if (buf)
3151
xstring_free(buf);
3152
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
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
assert(buf != NULL);
3172
assert(format != NULL);
3173
3174
f = format;
3175
p = new_percent_esc();
3176
3177
if (p == NULL) {
3178
xstring_reset(buf);
3179
return (buf); /* Out of memory */
3180
}
3181
3182
while ( *f != '\0' ) {
3183
switch(*f) {
3184
case '%':
3185
fend = parse_format(f, PP_PKG, p);
3186
3187
if (p->fmt_code <= PP_LAST_FORMAT)
3188
data = va_arg(ap, void *);
3189
else
3190
data = NULL;
3191
f = process_format_main(buf, p, f, fend, data);
3192
break;
3193
case '\\':
3194
f = process_escape(buf, f);
3195
break;
3196
default:
3197
fputc(*f, buf->fp);
3198
f++;
3199
break;
3200
}
3201
if (f == NULL) {
3202
xstring_reset(buf);
3203
break; /* Error: out of memory */
3204
}
3205
}
3206
3207
free_percent_esc(p);
3208
return (buf);
3209
}
3210
/*
3211
* That's All Folks!
3212
*/
3213
3214