4 * Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org>
5 * Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include <sys/types.h>
24 #include <sys/ioctl.h>
31 #include <stdint.h> /* intmax_t */
40 #include <termios.h> /* tcflush */
44 #include <alpm_list.h>
52 int trans_init(pmtransflag_t flags
)
56 ret
= alpm_trans_init(config
->handle
, flags
, NULL
, NULL
, NULL
);
58 ret
= alpm_trans_init(config
->handle
, flags
, cb_trans_evt
, cb_trans_conv
,
63 pm_fprintf(stderr
, PM_LOG_ERROR
, _("failed to init transaction (%s)\n"),
65 if(pm_errno
== PM_ERR_HANDLE_LOCK
) {
66 fprintf(stderr
, _(" if you're sure a package manager is not already\n"
67 " running, you can remove %s\n"),
68 alpm_option_get_lockfile(config
->handle
));
70 else if(pm_errno
== PM_ERR_DB_VERSION
) {
71 fprintf(stderr
, _(" try running pacman-db-upgrade\n"));
79 int trans_release(void)
81 if(alpm_trans_release(config
->handle
) == -1) {
82 pm_fprintf(stderr
, PM_LOG_ERROR
, _("failed to release transaction (%s)\n"),
96 return !config
->print
;
98 return (config
->op_s_clean
|| config
->op_s_sync
||
99 (!config
->group
&& !config
->op_s_info
&& !config
->op_q_list
&&
100 !config
->op_s_search
&& !config
->print
));
106 /* discard unhandled input on the terminal's input buffer */
107 static int flush_term_input(void) {
109 if(isatty(fileno(stdin
))) {
110 return(tcflush(fileno(stdin
), TCIFLUSH
));
118 /* gets the current screen column width */
123 if(ioctl(1, TIOCGSIZE
, &win
) == 0) {
126 #elif defined(TIOCGWINSZ)
128 if(ioctl(1, TIOCGWINSZ
, &win
) == 0) {
135 /* does the same thing as 'rm -rf' */
136 int rmrf(const char *path
)
145 if(errno
== ENOENT
) {
147 } else if(errno
== EPERM
) {
149 } else if(errno
== EISDIR
) {
151 } else if(errno
== ENOTDIR
) {
154 /* not a directory */
158 dirp
= opendir(path
);
162 for(dp
= readdir(dirp
); dp
!= NULL
; dp
= readdir(dirp
)) {
165 sprintf(name
, "%s/%s", path
, dp
->d_name
);
166 if(strcmp(dp
->d_name
, "..") != 0 && strcmp(dp
->d_name
, ".") != 0) {
167 errflag
+= rmrf(name
);
179 /** Parse the basename of a program from a path.
180 * @param path path to parse basename from
182 * @return everything following the final '/'
184 const char *mbasename(const char *path
)
186 const char *last
= strrchr(path
, '/');
193 /** Parse the dirname of a program from a path.
194 * The path returned should be freed.
195 * @param path path to parse dirname from
197 * @return everything preceding the final '/'
199 char *mdirname(const char *path
)
203 /* null or empty path */
204 if(path
== NULL
|| path
== '\0') {
209 last
= strrchr(ret
, '/');
212 /* we found a '/', so terminate our string */
221 /* output a string, but wrap words properly with a specified indentation
223 void indentprint(const char *str
, int indent
)
228 const int cols
= getcols(0);
234 /* if we're not a tty, print without indenting */
240 len
= strlen(str
) + 1;
241 wcstr
= calloc(len
, sizeof(wchar_t));
242 len
= mbstowcs(wcstr
, str
, len
);
252 const wchar_t *q
, *next
;
254 if(p
== NULL
|| *p
== L
' ') continue;
255 next
= wcschr(p
, L
' ');
257 next
= p
+ wcslen(p
);
259 /* len captures # cols */
263 len
+= wcwidth(*q
++);
265 if(len
> (cols
- cidx
- 1)) {
266 /* wrap to a newline and reindent */
267 printf("\n%-*s", indent
, "");
275 printf("%lc", (wint_t)*p
);
282 /* Convert a string to uppercase
284 char *strtoupper(char *str
)
289 (*ptr
) = (char)toupper((unsigned char)*ptr
);
295 /* Trim whitespace and newlines from a string
297 char *strtrim(char *str
)
301 if(str
== NULL
|| *str
== '\0') {
302 /* string is empty, so we're done. */
306 while(isspace((unsigned char)*pch
)) {
310 memmove(str
, pch
, (strlen(pch
) + 1));
313 /* check if there wasn't anything but whitespace in the string. */
318 pch
= (str
+ (strlen(str
) - 1));
319 while(isspace((unsigned char)*pch
)) {
327 /* Replace all occurances of 'needle' with 'replace' in 'str', returning
328 * a new string (must be free'd) */
329 char *strreplace(const char *str
, const char *needle
, const char *replace
)
331 const char *p
= NULL
, *q
= NULL
;
332 char *newstr
= NULL
, *newp
= NULL
;
333 alpm_list_t
*i
= NULL
, *list
= NULL
;
334 size_t needlesz
= strlen(needle
), replacesz
= strlen(replace
);
342 q
= strstr(p
, needle
);
344 list
= alpm_list_add(list
, (char *)q
);
346 q
= strstr(p
, needle
);
349 /* no occurences of needle found */
353 /* size of new string = size of old string + "number of occurences of needle"
354 * x "size difference between replace and needle" */
355 newsz
= strlen(str
) + 1 +
356 alpm_list_count(list
) * (replacesz
- needlesz
);
357 newstr
= malloc(newsz
);
365 for(i
= list
; i
; i
= alpm_list_next(i
)) {
366 q
= alpm_list_getdata(i
);
368 /* add chars between this occurence and last occurence, if any */
369 strncpy(newp
, p
, (size_t)(q
- p
));
372 strncpy(newp
, replace
, replacesz
);
376 alpm_list_free(list
);
379 /* add the rest of 'p' */
388 /** Splits a string into a list of strings using the chosen character as
391 * @param str the string to split
392 * @param splitchar the character to split at
394 * @return a list containing the duplicated strings
396 alpm_list_t
*strsplit(const char *str
, const char splitchar
)
398 alpm_list_t
*list
= NULL
;
399 const char *prev
= str
;
402 while((str
= strchr(str
, splitchar
))) {
403 dup
= strndup(prev
, (size_t)(str
- prev
));
407 list
= alpm_list_add(list
, dup
);
417 list
= alpm_list_add(list
, dup
);
422 static int string_length(const char *s
)
430 /* len goes from # bytes -> # chars -> # cols */
432 wcstr
= calloc(len
, sizeof(wchar_t));
433 len
= mbstowcs(wcstr
, s
, len
);
434 len
= wcswidth(wcstr
, len
);
440 void string_display(const char *title
, const char *string
)
443 printf("%s ", title
);
445 if(string
== NULL
|| string
[0] == '\0') {
448 /* compute the length of title + a space */
449 int len
= string_length(title
) + 1;
450 indentprint(string
, len
);
455 static void table_print_line(const alpm_list_t
*line
,
456 const alpm_list_t
*formats
)
458 const alpm_list_t
*curformat
= formats
;
459 const alpm_list_t
*curcell
= line
;
461 while(curcell
&& curformat
) {
462 printf(alpm_list_getdata(curformat
), alpm_list_getdata(curcell
));
463 curcell
= alpm_list_next(curcell
);
464 curformat
= alpm_list_next(curformat
);
470 /* creates format strings by checking max cell lengths in cols */
471 static alpm_list_t
*table_create_format(const alpm_list_t
*header
,
472 const alpm_list_t
*rows
)
474 alpm_list_t
*longest_str
, *longest_strs
= NULL
;
475 alpm_list_t
*formats
= NULL
;
476 const alpm_list_t
*i
, *row
, *cell
;
477 char *str
, *formatstr
;
478 const int padding
= 2;
479 int colwidth
, totalwidth
= 0;
482 /* header determines column count and initial values of longest_strs */
483 for(i
= header
; i
; i
= alpm_list_next(i
)) {
484 longest_strs
= alpm_list_add(longest_strs
, alpm_list_getdata(i
));
487 /* now find the longest string in each column */
488 for(longest_str
= longest_strs
; longest_str
;
489 longest_str
= alpm_list_next(longest_str
), curcol
++) {
490 for(i
= rows
; i
; i
= alpm_list_next(i
)) {
491 row
= alpm_list_getdata(i
);
492 cell
= alpm_list_nth(row
, curcol
);
493 str
= alpm_list_getdata(cell
);
495 if(strlen(str
) > strlen(alpm_list_getdata(longest_str
))) {
496 longest_str
->data
= str
;
501 /* now use the column width info to generate format strings */
502 for(i
= longest_strs
; i
; i
= alpm_list_next(i
)) {
504 colwidth
= strlen(alpm_list_getdata(i
)) + padding
;
505 totalwidth
+= colwidth
;
507 /* right align the last column for a cleaner table display */
508 display
= (alpm_list_next(i
) != NULL
) ? "%%-%ds" : "%%%ds";
509 pm_asprintf(&formatstr
, display
, colwidth
);
511 formats
= alpm_list_add(formats
, formatstr
);
514 alpm_list_free(longest_strs
);
516 /* return NULL if terminal is not wide enough */
517 if(totalwidth
> getcols(80)) {
518 fprintf(stderr
, _("insufficient columns available for table display\n"));
526 /** Displays the list in table format
528 * @param title the tables title
529 * @param header the column headers. column count is determined by the nr
531 * @param rows the rows to display as a list of lists of strings. the outer
532 * list represents the rows, the inner list the cells (= columns)
534 * @return -1 if not enough terminal cols available, else 0
536 int table_display(const char *title
, const alpm_list_t
*header
,
537 const alpm_list_t
*rows
)
539 const alpm_list_t
*i
;
540 alpm_list_t
*formats
;
542 if(rows
== NULL
|| header
== NULL
) {
546 formats
= table_create_format(header
, rows
);
547 if(formats
== NULL
) {
552 printf("%s\n\n", title
);
555 table_print_line(header
, formats
);
558 for(i
= rows
; i
; i
= alpm_list_next(i
)) {
559 table_print_line(alpm_list_getdata(i
), formats
);
566 void list_display(const char *title
, const alpm_list_t
*list
)
568 const alpm_list_t
*i
;
572 len
= string_length(title
) + 1;
573 printf("%s ", title
);
577 printf("%s\n", _("None"));
580 const int maxcols
= getcols(80);
581 for(i
= list
, cols
= len
; i
; i
= alpm_list_next(i
)) {
582 char *str
= alpm_list_getdata(i
);
583 int s
= string_length(str
);
584 if(cols
+ s
+ 2 >= maxcols
) {
588 for (j
= 1; j
<= len
; j
++) {
591 } else if(cols
!= len
) {
592 /* 2 spaces are added if this is not the first element on a line. */
603 void list_display_linebreak(const char *title
, const alpm_list_t
*list
)
605 const alpm_list_t
*i
;
609 len
= string_length(title
) + 1;
610 printf("%s ", title
);
614 printf("%s\n", _("None"));
616 /* Print the first element */
617 indentprint((const char *) alpm_list_getdata(list
), len
);
620 for(i
= alpm_list_next(list
); i
; i
= alpm_list_next(i
)) {
622 for(j
= 1; j
<= len
; j
++) {
625 indentprint((const char *) alpm_list_getdata(i
), len
);
631 /* creates a header row for use with table_display */
632 static alpm_list_t
*create_verbose_header(int install
)
634 alpm_list_t
*res
= NULL
;
637 pm_asprintf(&str
, "%s", _("Name"));
638 res
= alpm_list_add(res
, str
);
639 pm_asprintf(&str
, "%s", _("Old Version"));
640 res
= alpm_list_add(res
, str
);
642 pm_asprintf(&str
, "%s", _("New Version"));
643 res
= alpm_list_add(res
, str
);
645 pm_asprintf(&str
, "%s", _("Size"));
646 res
= alpm_list_add(res
, str
);
651 /* returns package info as list of strings */
652 static alpm_list_t
*create_verbose_row(pmpkg_t
*pkg
, int install
)
657 alpm_list_t
*ret
= NULL
;
658 pmdb_t
*ldb
= alpm_option_get_localdb(config
->handle
);
660 /* a row consists of the package name, */
661 pm_asprintf(&str
, "%s", alpm_pkg_get_name(pkg
));
662 ret
= alpm_list_add(ret
, str
);
664 /* old and new versions */
666 pmpkg_t
*oldpkg
= alpm_db_get_pkg(ldb
, alpm_pkg_get_name(pkg
));
667 pm_asprintf(&str
, "%s",
668 oldpkg
!= NULL
? alpm_pkg_get_version(oldpkg
) : "");
669 ret
= alpm_list_add(ret
, str
);
672 pm_asprintf(&str
, "%s", alpm_pkg_get_version(pkg
));
673 ret
= alpm_list_add(ret
, str
);
676 size
= humanize_size(alpm_pkg_get_size(pkg
), 'M', 1, &label
);
677 pm_asprintf(&str
, "%.2f %s", size
, label
);
678 ret
= alpm_list_add(ret
, str
);
683 /* prepare a list of pkgs to display */
684 void display_targets(const alpm_list_t
*pkgs
, int install
)
687 const char *title
, *label
;
689 const alpm_list_t
*i
;
690 off_t isize
= 0, rsize
= 0, dlsize
= 0;
691 alpm_list_t
*j
, *lp
, *header
= NULL
, *targets
= NULL
;
692 pmdb_t
*db_local
= alpm_option_get_localdb(config
->handle
);
698 /* gather pkg infos */
699 for(i
= pkgs
; i
; i
= alpm_list_next(i
)) {
700 pmpkg_t
*pkg
= alpm_list_getdata(i
);
703 pmpkg_t
*lpkg
= alpm_db_get_pkg(db_local
, alpm_pkg_get_name(pkg
));
704 dlsize
+= alpm_pkg_download_size(pkg
);
706 /* add up size of all removed packages */
707 rsize
+= alpm_pkg_get_isize(lpkg
);
710 isize
+= alpm_pkg_get_isize(pkg
);
712 if(config
->verbosepkglists
) {
713 targets
= alpm_list_add(targets
, create_verbose_row(pkg
, install
));
715 pm_asprintf(&str
, "%s-%s", alpm_pkg_get_name(pkg
),
716 alpm_pkg_get_version(pkg
));
717 targets
= alpm_list_add(targets
, str
);
721 /* print to screen */
722 title
= install
? _("Targets (%d):") : _("Remove (%d):");
723 pm_asprintf(&str
, title
, alpm_list_count(pkgs
));
726 if(config
->verbosepkglists
) {
727 header
= create_verbose_header(install
);
728 if(table_display(str
, header
, targets
) != 0) {
729 config
->verbosepkglists
= 0;
730 display_targets(pkgs
, install
);
734 list_display(str
, targets
);
739 size
= humanize_size(dlsize
, 'M', 1, &label
);
740 printf(_("Total Download Size: %.2f %s\n"), size
, label
);
741 if(!(config
->flags
& PM_TRANS_FLAG_DOWNLOADONLY
)) {
742 size
= humanize_size(isize
, 'M', 1, &label
);
743 printf(_("Total Installed Size: %.2f %s\n"), size
, label
);
744 /* only show this net value if different from raw installed size */
746 size
= humanize_size(isize
- rsize
, 'M', 1, &label
);
747 printf(_("Net Upgrade Size: %.2f %s\n"), size
, label
);
751 size
= humanize_size(isize
, 'M', 1, &label
);
752 printf(_("Total Removed Size: %.2f %s\n"), size
, label
);
757 if(config
->verbosepkglists
) {
758 /* targets is a list of lists of strings, free inner lists here */
759 for(j
= alpm_list_first(targets
); j
; j
= alpm_list_next(j
)) {
760 lp
= alpm_list_getdata(j
);
763 alpm_list_free(targets
);
771 static off_t
pkg_get_size(pmpkg_t
*pkg
)
775 return alpm_pkg_download_size(pkg
);
777 return alpm_pkg_get_size(pkg
);
779 return alpm_pkg_get_isize(pkg
);
783 static char *pkg_get_location(pmpkg_t
*pkg
)
790 db
= alpm_pkg_get_db(pkg
);
791 dburl
= alpm_db_get_url(db
);
794 pm_asprintf(&pkgurl
, "%s/%s", dburl
, alpm_pkg_get_filename(pkg
));
798 return strdup(alpm_pkg_get_filename(pkg
));
801 pm_asprintf(&string
, "%s-%s", alpm_pkg_get_name(pkg
), alpm_pkg_get_version(pkg
));
806 /** Converts sizes in bytes into human readable units.
808 * @param bytes the size in bytes
809 * @param target_unit '\0' or a short label. If equal to one of the short unit
810 * labels ('B', 'K', ...) bytes is converted to target_unit; if '\0', the first
811 * unit which will bring the value to below a threshold of 2048 will be chosen.
812 * @param long_labels whether to use short ("K") or long ("KiB") unit labels
813 * @param label will be set to the appropriate unit label
815 * @return the size in the appropriate unit
817 double humanize_size(off_t bytes
, const char target_unit
, int long_labels
,
820 static const char *shortlabels
[] = {"B", "K", "M", "G", "T", "P"};
821 static const char *longlabels
[] = {"B", "KiB", "MiB", "GiB", "TiB", "PiB"};
822 static const int unitcount
= sizeof(shortlabels
) / sizeof(shortlabels
[0]);
824 const char **labels
= long_labels
? longlabels
: shortlabels
;
825 double val
= (double)bytes
;
828 for(index
= 0; index
< unitcount
- 1; index
++) {
829 if(target_unit
!= '\0' && shortlabels
[index
][0] == target_unit
) {
831 } else if(target_unit
== '\0' && val
<= 2048.0) {
838 *label
= labels
[index
];
844 void print_packages(const alpm_list_t
*packages
)
846 const alpm_list_t
*i
;
847 if(!config
->print_format
) {
848 config
->print_format
= strdup("%l");
850 for(i
= packages
; i
; i
= alpm_list_next(i
)) {
851 pmpkg_t
*pkg
= alpm_list_getdata(i
);
852 char *string
= strdup(config
->print_format
);
855 if(strstr(temp
,"%n")) {
856 string
= strreplace(temp
, "%n", alpm_pkg_get_name(pkg
));
861 if(strstr(temp
,"%v")) {
862 string
= strreplace(temp
, "%v", alpm_pkg_get_version(pkg
));
867 if(strstr(temp
,"%l")) {
868 char *pkgloc
= pkg_get_location(pkg
);
869 string
= strreplace(temp
, "%l", pkgloc
);
875 if(strstr(temp
,"%r")) {
876 const char *repo
= "local";
877 pmdb_t
*db
= alpm_pkg_get_db(pkg
);
879 repo
= alpm_db_get_name(db
);
881 string
= strreplace(temp
, "%r", repo
);
886 if(strstr(temp
,"%s")) {
888 pm_asprintf(&size
, "%jd", (intmax_t)pkg_get_size(pkg
));
889 string
= strreplace(temp
, "%s", size
);
893 printf("%s\n",string
);
898 /* Helper function for comparing strings using the
899 * alpm "compare func" signature */
900 int str_cmp(const void *s1
, const void *s2
)
902 return strcmp(s1
, s2
);
905 void display_new_optdepends(pmpkg_t
*oldpkg
, pmpkg_t
*newpkg
)
907 alpm_list_t
*old
= alpm_pkg_get_optdepends(oldpkg
);
908 alpm_list_t
*new = alpm_pkg_get_optdepends(newpkg
);
909 alpm_list_t
*optdeps
= alpm_list_diff(new,old
,str_cmp
);
911 printf(_("New optional dependencies for %s\n"), alpm_pkg_get_name(newpkg
));
912 list_display_linebreak(" ", optdeps
);
914 alpm_list_free(optdeps
);
917 void display_optdepends(pmpkg_t
*pkg
)
919 alpm_list_t
*optdeps
= alpm_pkg_get_optdepends(pkg
);
921 printf(_("Optional dependencies for %s\n"), alpm_pkg_get_name(pkg
));
922 list_display_linebreak(" ", optdeps
);
926 static void display_repo_list(const char *dbname
, alpm_list_t
*list
)
928 const char *prefix
= " ";
931 printf(_("Repository %s\n"), dbname
);
932 list_display(prefix
, list
);
935 void select_display(const alpm_list_t
*pkglist
)
937 const alpm_list_t
*i
;
939 alpm_list_t
*list
= NULL
;
941 const char *dbname
= NULL
;
943 for (i
= pkglist
; i
; i
= i
->next
) {
944 pmpkg_t
*pkg
= alpm_list_getdata(i
);
945 pmdb_t
*db
= alpm_pkg_get_db(pkg
);
948 dbname
= alpm_db_get_name(db
);
949 if(strcmp(alpm_db_get_name(db
), dbname
) != 0) {
950 display_repo_list(dbname
, list
);
952 dbname
= alpm_db_get_name(db
);
955 pm_asprintf(&string
, "%d) %s", nth
, alpm_pkg_get_name(pkg
));
956 list
= alpm_list_add(list
, string
);
959 display_repo_list(dbname
, list
);
963 static int parseindex(char *s
, int *val
, int min
, int max
)
966 int n
= strtol(s
, &endptr
, 10);
967 if(*endptr
== '\0') {
968 if(n
< min
|| n
> max
) {
969 fprintf(stderr
, _("Invalid value: %d is not between %d and %d\n"),
976 fprintf(stderr
, _("Invalid number: %s\n"), s
);
981 static int multiselect_parse(char *array
, int count
, char *response
)
985 for (str
= response
; ; str
= NULL
) {
989 char *starts
= strtok_r(str
, " ", &saveptr
);
995 int len
= strlen(starts
);
1004 /* if first token is including, we unselect all targets */
1005 memset(array
, 0, count
);
1009 /* check for range */
1011 if((p
= strchr(starts
+ 1, '-'))) {
1017 if(parseindex(starts
, &start
, 1, count
) != 0)
1021 array
[start
-1] = include
;
1024 if(parseindex(ends
, &end
, start
, count
) != 0) {
1027 for(d
= start
; d
<= end
; d
++) {
1028 array
[d
-1] = include
;
1036 int multiselect_question(char *array
, int count
)
1041 if(config
->noconfirm
) {
1044 /* Use stderr so questions are always displayed when redirecting output */
1049 memset(array
, 1, count
);
1051 fprintf(stream
, "\n");
1052 fprintf(stream
, _("Enter a selection (default=all)"));
1053 fprintf(stream
, ": ");
1055 if(config
->noconfirm
) {
1056 fprintf(stream
, "\n");
1062 if(fgets(response
, sizeof(response
), stdin
)) {
1064 if(strlen(response
) > 0) {
1065 if(multiselect_parse(array
, count
, response
) == -1) {
1066 /* only loop if user gave an invalid answer */
1076 int select_question(int count
)
1082 if(config
->noconfirm
) {
1085 /* Use stderr so questions are always displayed when redirecting output */
1090 fprintf(stream
, "\n");
1091 fprintf(stream
, _("Enter a number (default=%d)"), preset
);
1092 fprintf(stream
, ": ");
1094 if(config
->noconfirm
) {
1095 fprintf(stream
, "\n");
1101 if(fgets(response
, sizeof(response
), stdin
)) {
1103 if(strlen(response
) > 0) {
1105 if(parseindex(response
, &n
, 1, count
) != 0)
1113 return (preset
- 1);
1117 /* presents a prompt and gets a Y/N answer */
1118 static int question(short preset
, char *fmt
, va_list args
)
1123 if(config
->noconfirm
) {
1126 /* Use stderr so questions are always displayed when redirecting output */
1130 /* ensure all text makes it to the screen before we prompt the user */
1134 vfprintf(stream
, fmt
, args
);
1137 fprintf(stream
, " %s ", _("[Y/n]"));
1139 fprintf(stream
, " %s ", _("[y/N]"));
1142 if(config
->noconfirm
) {
1143 fprintf(stream
, "\n");
1150 if(fgets(response
, sizeof(response
), stdin
)) {
1152 if(strlen(response
) == 0) {
1156 if(strcasecmp(response
, _("Y")) == 0 || strcasecmp(response
, _("YES")) == 0) {
1158 } else if(strcasecmp(response
, _("N")) == 0 || strcasecmp(response
, _("NO")) == 0) {
1165 int yesno(char *fmt
, ...)
1170 va_start(args
, fmt
);
1171 ret
= question(1, fmt
, args
);
1177 int noyes(char *fmt
, ...)
1182 va_start(args
, fmt
);
1183 ret
= question(0, fmt
, args
);
1189 int pm_printf(pmloglevel_t level
, const char *format
, ...)
1194 /* print the message using va_arg list */
1195 va_start(args
, format
);
1196 ret
= pm_vfprintf(stdout
, level
, format
, args
);
1202 int pm_fprintf(FILE *stream
, pmloglevel_t level
, const char *format
, ...)
1207 /* print the message using va_arg list */
1208 va_start(args
, format
);
1209 ret
= pm_vfprintf(stream
, level
, format
, args
);
1215 int pm_asprintf(char **string
, const char *format
, ...)
1220 /* print the message using va_arg list */
1221 va_start(args
, format
);
1222 if(vasprintf(string
, format
, args
) == -1) {
1223 pm_fprintf(stderr
, PM_LOG_ERROR
, _("failed to allocate string\n"));
1231 int pm_vasprintf(char **string
, pmloglevel_t level
, const char *format
, va_list args
)
1236 /* if current logmask does not overlap with level, do not print msg */
1237 if(!(config
->logmask
& level
)) {
1241 /* print the message using va_arg list */
1242 ret
= vasprintf(&msg
, format
, args
);
1244 /* print a prefix to the message */
1247 pm_asprintf(string
, _("error: %s"), msg
);
1249 case PM_LOG_WARNING
:
1250 pm_asprintf(string
, _("warning: %s"), msg
);
1253 pm_asprintf(string
, "debug: %s", msg
);
1255 case PM_LOG_FUNCTION
:
1256 pm_asprintf(string
, "function: %s", msg
);
1259 pm_asprintf(string
, "%s", msg
);
1267 int pm_vfprintf(FILE *stream
, pmloglevel_t level
, const char *format
, va_list args
)
1271 /* if current logmask does not overlap with level, do not print msg */
1272 if(!(config
->logmask
& level
)) {
1276 #if defined(PACMAN_DEBUG)
1277 /* If debug is on, we'll timestamp the output */
1278 if(config
->logmask
& PM_LOG_DEBUG
) {
1281 char timestr
[10] = {0};
1284 tmp
= localtime(&t
);
1285 strftime(timestr
, 9, "%H:%M:%S", tmp
);
1288 printf("[%s] ", timestr
);
1292 /* print a prefix to the message */
1295 fprintf(stream
, _("error: "));
1297 case PM_LOG_WARNING
:
1298 fprintf(stream
, _("warning: "));
1301 fprintf(stream
, "debug: ");
1303 case PM_LOG_FUNCTION
:
1304 fprintf(stream
, "function: ");
1310 /* print the message using va_arg list */
1311 ret
= vfprintf(stream
, format
, args
);
1315 #ifndef HAVE_STRNDUP
1316 /* A quick and dirty implementation derived from glibc */
1317 static size_t strnlen(const char *s
, size_t max
)
1319 register const char *p
;
1320 for(p
= s
; *p
&& max
--; ++p
);
1324 char *strndup(const char *s
, size_t n
)
1326 size_t len
= strnlen(s
, n
);
1327 char *new = (char *) malloc(len
+ 1);
1333 return (char *)memcpy(new, s
, len
);
1337 /* vim: set ts=2 sw=2 noet: */