pacman/util: flush terminal input before reading response
[pacman-ng.git] / src / pacman / util.c
blob0cb6a9f494ba78c7a2ec02988fa984be047329c6
1 /*
2 * util.c
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/>.
21 #include "config.h"
23 #include <sys/types.h>
24 #include <sys/ioctl.h>
25 #include <sys/stat.h>
26 #include <sys/time.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <stdarg.h>
31 #include <stdint.h> /* intmax_t */
32 #include <string.h>
33 #include <errno.h>
34 #include <fcntl.h>
35 #include <ctype.h>
36 #include <dirent.h>
37 #include <unistd.h>
38 #include <limits.h>
39 #include <wchar.h>
40 #ifdef HAVE_TERMIOS_H
41 #include <termios.h> /* tcflush */
42 #endif
44 #include <alpm.h>
45 #include <alpm_list.h>
47 /* pacman */
48 #include "util.h"
49 #include "conf.h"
50 #include "callback.h"
53 int trans_init(pmtransflag_t flags)
55 int ret;
56 if(config->print) {
57 ret = alpm_trans_init(flags, NULL, NULL, NULL);
58 } else {
59 ret = alpm_trans_init(flags, cb_trans_evt, cb_trans_conv,
60 cb_trans_progress);
63 if(ret == -1) {
64 pm_fprintf(stderr, PM_LOG_ERROR, _("failed to init transaction (%s)\n"),
65 alpm_strerrorlast());
66 if(pm_errno == PM_ERR_HANDLE_LOCK) {
67 fprintf(stderr, _(" if you're sure a package manager is not already\n"
68 " running, you can remove %s\n"), alpm_option_get_lockfile());
70 else if(pm_errno == PM_ERR_DB_VERSION) {
71 fprintf(stderr, _(" try running pacman-db-upgrade\n"));
74 return(-1);
76 return(0);
79 int trans_release(void)
81 if(alpm_trans_release() == -1) {
82 pm_fprintf(stderr, PM_LOG_ERROR, _("failed to release transaction (%s)\n"),
83 alpm_strerrorlast());
84 return(-1);
86 return(0);
89 int needs_root(void)
91 switch(config->op) {
92 case PM_OP_DATABASE:
93 return(1);
94 case PM_OP_UPGRADE:
95 case PM_OP_REMOVE:
96 return(!config->print);
97 case PM_OP_SYNC:
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));
101 default:
102 return(0);
106 /* discard unhandled input on the terminal's input buffer */
107 static int flush_term_input(void) {
108 #ifdef HAVE_TCFLUSH
109 if(isatty(fileno(stdin))) {
110 return(tcflush(fileno(stdin), TCIFLUSH));
112 #endif
114 /* fail silently */
115 return 0;
118 /* gets the current screen column width */
119 int getcols(int def)
121 #ifdef TIOCGSIZE
122 struct ttysize win;
123 if(ioctl(1, TIOCGSIZE, &win) == 0) {
124 return win.ts_cols;
126 #elif defined(TIOCGWINSZ)
127 struct winsize win;
128 if(ioctl(1, TIOCGWINSZ, &win) == 0) {
129 return win.ws_col;
131 #endif
132 return def;
135 /* does the same thing as 'rm -rf' */
136 int rmrf(const char *path)
138 int errflag = 0;
139 struct dirent *dp;
140 DIR *dirp;
142 if(!unlink(path)) {
143 return(0);
144 } else {
145 if(errno == ENOENT) {
146 return(0);
147 } else if(errno == EPERM) {
148 /* fallthrough */
149 } else if(errno == EISDIR) {
150 /* fallthrough */
151 } else if(errno == ENOTDIR) {
152 return(1);
153 } else {
154 /* not a directory */
155 return(1);
158 dirp = opendir(path);
159 if(!dirp) {
160 return(1);
162 for(dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) {
163 if(dp->d_ino) {
164 char name[PATH_MAX];
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);
171 closedir(dirp);
172 if(rmdir(path)) {
173 errflag++;
175 return(errflag);
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, '/');
187 if(last) {
188 return(last + 1);
190 return(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)
201 char *ret, *last;
203 /* null or empty path */
204 if(path == NULL || path == '\0') {
205 return(strdup("."));
208 ret = strdup(path);
209 last = strrchr(ret, '/');
211 if(last != NULL) {
212 /* we found a '/', so terminate our string */
213 *last = '\0';
214 return(ret);
216 /* no slash found */
217 free(ret);
218 return(strdup("."));
221 /* output a string, but wrap words properly with a specified indentation
223 void indentprint(const char *str, int indent)
225 wchar_t *wcstr;
226 const wchar_t *p;
227 int len, cidx;
228 const int cols = getcols(0);
230 if(!str) {
231 return;
234 /* if we're not a tty, or our tty is not wide enough that wrapping even makes
235 * sense, print without indenting */
236 if(cols == 0 || indent > cols) {
237 printf("%s", str);
238 return;
241 len = strlen(str) + 1;
242 wcstr = calloc(len, sizeof(wchar_t));
243 len = mbstowcs(wcstr, str, len);
244 p = wcstr;
245 cidx = indent;
247 if(!p || !len) {
248 return;
251 while(*p) {
252 if(*p == L' ') {
253 const wchar_t *q, *next;
254 p++;
255 if(p == NULL || *p == L' ') continue;
256 next = wcschr(p, L' ');
257 if(next == NULL) {
258 next = p + wcslen(p);
260 /* len captures # cols */
261 len = 0;
262 q = p;
263 while(q < next) {
264 len += wcwidth(*q++);
266 if(len > (cols - cidx - 1)) {
267 /* wrap to a newline and reindent */
268 printf("\n%-*s", indent, "");
269 cidx = indent;
270 } else {
271 printf(" ");
272 cidx++;
274 continue;
276 printf("%lc", (wint_t)*p);
277 cidx += wcwidth(*p);
278 p++;
280 free(wcstr);
283 /* Convert a string to uppercase
285 char *strtoupper(char *str)
287 char *ptr = str;
289 while(*ptr) {
290 (*ptr) = (char)toupper((unsigned char)*ptr);
291 ptr++;
293 return str;
296 /* Trim whitespace and newlines from a string
298 char *strtrim(char *str)
300 char *pch = str;
302 if(str == NULL || *str == '\0') {
303 /* string is empty, so we're done. */
304 return(str);
307 while(isspace((unsigned char)*pch)) {
308 pch++;
310 if(pch != str) {
311 memmove(str, pch, (strlen(pch) + 1));
314 /* check if there wasn't anything but whitespace in the string. */
315 if(*str == '\0') {
316 return(str);
319 pch = (str + (strlen(str) - 1));
320 while(isspace((unsigned char)*pch)) {
321 pch--;
323 *++pch = '\0';
325 return(str);
328 /* Replace all occurances of 'needle' with 'replace' in 'str', returning
329 * a new string (must be free'd) */
330 char *strreplace(const char *str, const char *needle, const char *replace)
332 const char *p = NULL, *q = NULL;
333 char *newstr = NULL, *newp = NULL;
334 alpm_list_t *i = NULL, *list = NULL;
335 size_t needlesz = strlen(needle), replacesz = strlen(replace);
336 size_t newsz;
338 if(!str) {
339 return(NULL);
342 p = str;
343 q = strstr(p, needle);
344 while(q) {
345 list = alpm_list_add(list, (char *)q);
346 p = q + needlesz;
347 q = strstr(p, needle);
350 /* no occurences of needle found */
351 if(!list) {
352 return(strdup(str));
354 /* size of new string = size of old string + "number of occurences of needle"
355 * x "size difference between replace and needle" */
356 newsz = strlen(str) + 1 +
357 alpm_list_count(list) * (replacesz - needlesz);
358 newstr = malloc(newsz);
359 if(!newstr) {
360 return(NULL);
362 *newstr = '\0';
364 p = str;
365 newp = newstr;
366 for(i = list; i; i = alpm_list_next(i)) {
367 q = alpm_list_getdata(i);
368 if(q > p){
369 /* add chars between this occurence and last occurence, if any */
370 strncpy(newp, p, (size_t)(q - p));
371 newp += q - p;
373 strncpy(newp, replace, replacesz);
374 newp += replacesz;
375 p = q + needlesz;
377 alpm_list_free(list);
379 if(*p) {
380 /* add the rest of 'p' */
381 strcpy(newp, p);
382 newp += strlen(p);
384 *newp = '\0';
386 return(newstr);
389 /** Splits a string into a list of strings using the chosen character as
390 * a delimiter.
392 * @param str the string to split
393 * @param splitchar the character to split at
395 * @return a list containing the duplicated strings
397 alpm_list_t *strsplit(const char *str, const char splitchar)
399 alpm_list_t *list = NULL;
400 const char *prev = str;
401 char *dup = NULL;
403 while((str = strchr(str, splitchar))) {
404 dup = strndup(prev, (size_t)(str - prev));
405 if(dup == NULL) {
406 return(NULL);
408 list = alpm_list_add(list, dup);
410 str++;
411 prev = str;
414 dup = strdup(prev);
415 if(dup == NULL) {
416 return(NULL);
418 list = alpm_list_add(list, dup);
420 return(list);
423 static int string_length(const char *s)
425 int len;
426 wchar_t *wcstr;
428 if(!s) {
429 return(0);
431 /* len goes from # bytes -> # chars -> # cols */
432 len = strlen(s) + 1;
433 wcstr = calloc(len, sizeof(wchar_t));
434 len = mbstowcs(wcstr, s, len);
435 len = wcswidth(wcstr, len);
436 free(wcstr);
438 return(len);
441 void string_display(const char *title, const char *string)
443 if(title) {
444 printf("%s ", title);
446 if(string == NULL || string[0] == '\0') {
447 printf(_("None"));
448 } else {
449 /* compute the length of title + a space */
450 int len = string_length(title) + 1;
451 indentprint(string, len);
453 printf("\n");
456 void list_display(const char *title, const alpm_list_t *list)
458 const alpm_list_t *i;
459 int len = 0;
461 if(title) {
462 len = string_length(title) + 1;
463 printf("%s ", title);
466 if(!list) {
467 printf("%s\n", _("None"));
468 } else {
469 const int maxcols = getcols(0);
470 int cols = len;
471 const char *str = alpm_list_getdata(list);
472 printf("%s", str);
473 cols += string_length(str);
474 for(i = alpm_list_next(list); i; i = alpm_list_next(i)) {
475 const char *str = alpm_list_getdata(i);
476 int s = string_length(str);
477 /* wrap only if we have enough usable column space */
478 if(maxcols > len && cols + s + 2 >= maxcols) {
479 int j;
480 cols = len;
481 printf("\n");
482 for (j = 1; j <= len; j++) {
483 printf(" ");
485 } else if (cols != len) {
486 /* 2 spaces are added if this is not the first element on a line. */
487 printf(" ");
488 cols += 2;
490 printf("%s", str);
491 cols += s;
493 printf("\n");
497 void list_display_linebreak(const char *title, const alpm_list_t *list)
499 const alpm_list_t *i;
500 int len = 0;
502 if(title) {
503 len = string_length(title) + 1;
504 printf("%s ", title);
507 if(!list) {
508 printf("%s\n", _("None"));
509 } else {
510 /* Print the first element */
511 indentprint((const char *) alpm_list_getdata(list), len);
512 printf("\n");
513 /* Print the rest */
514 for(i = alpm_list_next(list); i; i = alpm_list_next(i)) {
515 int j;
516 for(j = 1; j <= len; j++) {
517 printf(" ");
519 indentprint((const char *) alpm_list_getdata(i), len);
520 printf("\n");
524 /* prepare a list of pkgs to display */
525 void display_targets(const alpm_list_t *pkgs, int install)
527 char *str;
528 const alpm_list_t *i;
529 off_t isize = 0, dlsize = 0;
530 double mbisize = 0.0, mbdlsize = 0.0;
531 alpm_list_t *targets = NULL;
533 if(!pkgs) {
534 return;
537 printf("\n");
538 for(i = pkgs; i; i = alpm_list_next(i)) {
539 pmpkg_t *pkg = alpm_list_getdata(i);
541 if(install) {
542 dlsize += alpm_pkg_download_size(pkg);
544 isize += alpm_pkg_get_isize(pkg);
546 /* print the package size with the output if ShowSize option set */
547 if(config->showsize) {
548 double mbsize = (double)alpm_pkg_get_size(pkg) / (1024.0 * 1024.0);
550 pm_asprintf(&str, "%s-%s [%.2f MB]", alpm_pkg_get_name(pkg),
551 alpm_pkg_get_version(pkg), mbsize);
552 } else {
553 pm_asprintf(&str, "%s-%s", alpm_pkg_get_name(pkg),
554 alpm_pkg_get_version(pkg));
556 targets = alpm_list_add(targets, str);
559 /* Convert byte sizes to MB */
560 mbdlsize = (double)dlsize / (1024.0 * 1024.0);
561 mbisize = (double)isize / (1024.0 * 1024.0);
563 if(install) {
564 pm_asprintf(&str, _("Targets (%d):"), alpm_list_count(targets));
565 list_display(str, targets);
566 free(str);
567 printf("\n");
569 printf(_("Total Download Size: %.2f MB\n"), mbdlsize);
570 if(!(config->flags & PM_TRANS_FLAG_DOWNLOADONLY)) {
571 printf(_("Total Installed Size: %.2f MB\n"), mbisize);
573 } else {
574 pm_asprintf(&str, _("Remove (%d):"), alpm_list_count(targets));
575 list_display(str, targets);
576 free(str);
577 printf("\n");
579 printf(_("Total Removed Size: %.2f MB\n"), mbisize);
582 FREELIST(targets);
585 static off_t pkg_get_size(pmpkg_t *pkg)
587 switch(config->op) {
588 case PM_OP_SYNC:
589 return(alpm_pkg_download_size(pkg));
590 case PM_OP_UPGRADE:
591 return(alpm_pkg_get_size(pkg));
592 default:
593 return(alpm_pkg_get_isize(pkg));
597 static char *pkg_get_location(pmpkg_t *pkg)
599 pmdb_t *db;
600 const char *dburl;
601 char *string;
602 switch(config->op) {
603 case PM_OP_SYNC:
604 db = alpm_pkg_get_db(pkg);
605 dburl = alpm_db_get_url(db);
606 if(dburl) {
607 char *pkgurl = NULL;
608 pm_asprintf(&pkgurl, "%s/%s", dburl, alpm_pkg_get_filename(pkg));
609 return(pkgurl);
611 case PM_OP_UPGRADE:
612 return(strdup(alpm_pkg_get_filename(pkg)));
613 default:
614 string = NULL;
615 pm_asprintf(&string, "%s-%s", alpm_pkg_get_name(pkg), alpm_pkg_get_version(pkg));
616 return(string);
620 void print_packages(const alpm_list_t *packages)
622 const alpm_list_t *i;
623 if(!config->print_format) {
624 config->print_format = strdup("%l");
626 for(i = packages; i; i = alpm_list_next(i)) {
627 pmpkg_t *pkg = alpm_list_getdata(i);
628 char *string = strdup(config->print_format);
629 char *temp = string;
630 /* %n : pkgname */
631 if(strstr(temp,"%n")) {
632 string = strreplace(temp, "%n", alpm_pkg_get_name(pkg));
633 free(temp);
634 temp = string;
636 /* %v : pkgver */
637 if(strstr(temp,"%v")) {
638 string = strreplace(temp, "%v", alpm_pkg_get_version(pkg));
639 free(temp);
640 temp = string;
642 /* %l : location */
643 if(strstr(temp,"%l")) {
644 char *pkgloc = pkg_get_location(pkg);
645 string = strreplace(temp, "%l", pkgloc);
646 free(pkgloc);
647 free(temp);
648 temp = string;
650 /* %r : repo */
651 if(strstr(temp,"%r")) {
652 const char *repo = "local";
653 pmdb_t *db = alpm_pkg_get_db(pkg);
654 if(db) {
655 repo = alpm_db_get_name(db);
657 string = strreplace(temp, "%r", repo);
658 free(temp);
659 temp = string;
661 /* %s : size */
662 if(strstr(temp,"%s")) {
663 char *size;
664 pm_asprintf(&size, "%jd", (intmax_t)pkg_get_size(pkg));
665 string = strreplace(temp, "%s", size);
666 free(size);
667 free(temp);
669 printf("%s\n",string);
670 free(string);
674 /* Helper function for comparing strings using the
675 * alpm "compare func" signature */
676 int str_cmp(const void *s1, const void *s2)
678 return(strcmp(s1, s2));
681 void display_new_optdepends(pmpkg_t *oldpkg, pmpkg_t *newpkg)
683 alpm_list_t *old = alpm_pkg_get_optdepends(oldpkg);
684 alpm_list_t *new = alpm_pkg_get_optdepends(newpkg);
685 alpm_list_t *optdeps = alpm_list_diff(new,old,str_cmp);
686 if(optdeps) {
687 printf(_("New optional dependencies for %s\n"), alpm_pkg_get_name(newpkg));
688 list_display_linebreak(" ", optdeps);
690 alpm_list_free(optdeps);
693 void display_optdepends(pmpkg_t *pkg)
695 alpm_list_t *optdeps = alpm_pkg_get_optdepends(pkg);
696 if(optdeps) {
697 printf(_("Optional dependencies for %s\n"), alpm_pkg_get_name(pkg));
698 list_display_linebreak(" ", optdeps);
702 static void display_repo_list(const char *dbname, alpm_list_t *list)
704 const char *prefix= " ";
706 printf(":: ");
707 printf(_("Repository %s\n"), dbname);
708 list_display(prefix, list);
711 void select_display(const alpm_list_t *pkglist)
713 const alpm_list_t *i;
714 int nth = 1;
715 alpm_list_t *list = NULL;
716 char *string = NULL;
717 const char *dbname = NULL;
719 for (i = pkglist; i; i = i->next) {
720 pmpkg_t *pkg = alpm_list_getdata(i);
721 pmdb_t *db = alpm_pkg_get_db(pkg);
723 if(!dbname)
724 dbname = alpm_db_get_name(db);
725 if(strcmp(alpm_db_get_name(db), dbname) != 0) {
726 display_repo_list(dbname, list);
727 FREELIST(list);
728 dbname = alpm_db_get_name(db);
730 string = NULL;
731 pm_asprintf(&string, "%d) %s", nth, alpm_pkg_get_name(pkg));
732 list = alpm_list_add(list, string);
733 nth++;
735 display_repo_list(dbname, list);
736 FREELIST(list);
739 static int parseindex(char *s, int *val, int min, int max)
741 char *endptr = NULL;
742 int n = strtol(s, &endptr, 10);
743 if(*endptr == '\0') {
744 if(n < min || n > max) {
745 fprintf(stderr, _("Invalid value: %d is not between %d and %d\n"),
746 n, min, max);
747 return(-1);
749 *val = n;
750 return(0);
751 } else {
752 fprintf(stderr, _("Invalid number: %s\n"), s);
753 return(-1);
757 static int multiselect_parse(char *array, int count, char *response)
759 char *str, *saveptr;
761 for (str = response; ; str = NULL) {
762 int include = 1;
763 int start, end;
764 char *ends = NULL;
765 char *starts = strtok_r(str, " ", &saveptr);
767 if (starts == NULL) {
768 break;
770 strtrim(starts);
771 int len = strlen(starts);
772 if(len == 0)
773 continue;
775 if (*starts == '^') {
776 starts++;
777 len--;
778 include = 0;
779 } else if(str) {
780 /* if first token is including, we unselect all targets */
781 memset(array, 0, count);
784 if(len > 1) {
785 /* check for range */
786 char *p;
787 if((p = strchr(starts + 1, '-'))) {
788 *p = 0;
789 ends = p + 1;
793 if(parseindex(starts, &start, 1, count) != 0)
794 return(-1);
796 if(!ends) {
797 array[start-1] = include;
798 } else {
799 int d;
800 if(parseindex(ends, &end, start, count) != 0) {
801 return(-1);
803 for(d = start; d <= end; d++) {
804 array[d-1] = include;
809 return(0);
812 int multiselect_question(char *array, int count)
814 char *response, *lastchar;
815 FILE *stream;
816 size_t response_len = 64;
818 if(config->noconfirm) {
819 stream = stdout;
820 } else {
821 /* Use stderr so questions are always displayed when redirecting output */
822 stream = stderr;
825 response = malloc(response_len);
826 if(!response) {
827 return -1;
829 lastchar = response + response_len - 1;
830 /* sentinel byte to later see if we filled up the entire string */
831 *lastchar = 1;
833 while(1) {
834 memset(array, 1, count);
836 fprintf(stream, "\n");
837 fprintf(stream, _("Enter a selection (default=all)"));
838 fprintf(stream, ": ");
839 fflush(stream);
841 if(config->noconfirm) {
842 fprintf(stream, "\n");
843 break;
846 flush_term_input();
848 if(fgets(response, response_len, stdin)) {
849 const size_t response_incr = 64;
850 /* handle buffer not being large enough to read full line case */
851 while(*lastchar == '\0' && lastchar[-1] != '\n') {
852 response_len += response_incr;
853 response = realloc(response, response_len);
854 if(!response) {
855 return -1;
857 lastchar = response + response_len - 1;
858 /* sentinel byte */
859 *lastchar = 1;
860 if(fgets(response + response_len - response_incr - 1,
861 response_incr + 1, stdin) == 0) {
862 free(response);
863 return -1;
866 strtrim(response);
867 if(strlen(response) > 0) {
868 if(multiselect_parse(array, count, response) == -1) {
869 /* only loop if user gave an invalid answer */
870 continue;
873 break;
874 } else {
875 free(response);
876 return -1;
880 free(response);
881 return(0);
884 int select_question(int count)
886 char response[32];
887 FILE *stream;
888 int preset = 1;
890 if(config->noconfirm) {
891 stream = stdout;
892 } else {
893 /* Use stderr so questions are always displayed when redirecting output */
894 stream = stderr;
897 while(1) {
898 fprintf(stream, "\n");
899 fprintf(stream, _("Enter a number (default=%d)"), preset);
900 fprintf(stream, ": ");
902 if(config->noconfirm) {
903 fprintf(stream, "\n");
904 break;
907 flush_term_input();
909 if(fgets(response, sizeof(response), stdin)) {
910 strtrim(response);
911 if(strlen(response) > 0) {
912 int n;
913 if(parseindex(response, &n, 1, count) != 0)
914 continue;
915 return(n-1);
918 break;
921 return(preset-1);
925 /* presents a prompt and gets a Y/N answer */
926 static int question(short preset, char *fmt, va_list args)
928 char response[32];
929 FILE *stream;
931 if(config->noconfirm) {
932 stream = stdout;
933 } else {
934 /* Use stderr so questions are always displayed when redirecting output */
935 stream = stderr;
938 /* ensure all text makes it to the screen before we prompt the user */
939 fflush(stdout);
940 fflush(stderr);
942 vfprintf(stream, fmt, args);
944 if(preset) {
945 fprintf(stream, " %s ", _("[Y/n]"));
946 } else {
947 fprintf(stream, " %s ", _("[y/N]"));
950 if(config->noconfirm) {
951 fprintf(stream, "\n");
952 return(preset);
955 fflush(stream);
956 flush_term_input();
958 if(fgets(response, sizeof(response), stdin)) {
959 strtrim(response);
960 if(strlen(response) == 0) {
961 return(preset);
964 if(strcasecmp(response, _("Y")) == 0 || strcasecmp(response, _("YES")) == 0) {
965 return(1);
966 } else if (strcasecmp(response, _("N")) == 0 || strcasecmp(response, _("NO")) == 0) {
967 return(0);
970 return(0);
973 int yesno(char *fmt, ...)
975 int ret;
976 va_list args;
978 va_start(args, fmt);
979 ret = question(1, fmt, args);
980 va_end(args);
982 return(ret);
985 int noyes(char *fmt, ...)
987 int ret;
988 va_list args;
990 va_start(args, fmt);
991 ret = question(0, fmt, args);
992 va_end(args);
994 return(ret);
997 int pm_printf(pmloglevel_t level, const char *format, ...)
999 int ret;
1000 va_list args;
1002 /* print the message using va_arg list */
1003 va_start(args, format);
1004 ret = pm_vfprintf(stdout, level, format, args);
1005 va_end(args);
1007 return(ret);
1010 int pm_fprintf(FILE *stream, pmloglevel_t level, const char *format, ...)
1012 int ret;
1013 va_list args;
1015 /* print the message using va_arg list */
1016 va_start(args, format);
1017 ret = pm_vfprintf(stream, level, format, args);
1018 va_end(args);
1020 return(ret);
1023 int pm_asprintf(char **string, const char *format, ...)
1025 int ret = 0;
1026 va_list args;
1028 /* print the message using va_arg list */
1029 va_start(args, format);
1030 if(vasprintf(string, format, args) == -1) {
1031 pm_fprintf(stderr, PM_LOG_ERROR, _("failed to allocate string\n"));
1032 ret = -1;
1034 va_end(args);
1036 return(ret);
1039 int pm_vasprintf(char **string, pmloglevel_t level, const char *format, va_list args)
1041 int ret = 0;
1042 char *msg = NULL;
1044 /* if current logmask does not overlap with level, do not print msg */
1045 if(!(config->logmask & level)) {
1046 return ret;
1049 /* print the message using va_arg list */
1050 ret = vasprintf(&msg, format, args);
1052 /* print a prefix to the message */
1053 switch(level) {
1054 case PM_LOG_ERROR:
1055 pm_asprintf(string, _("error: %s"), msg);
1056 break;
1057 case PM_LOG_WARNING:
1058 pm_asprintf(string, _("warning: %s"), msg);
1059 break;
1060 case PM_LOG_DEBUG:
1061 pm_asprintf(string, "debug: %s", msg);
1062 break;
1063 case PM_LOG_FUNCTION:
1064 pm_asprintf(string, "function: %s", msg);
1065 break;
1066 default:
1067 pm_asprintf(string, "%s", msg);
1068 break;
1070 free(msg);
1072 return(ret);
1075 int pm_vfprintf(FILE *stream, pmloglevel_t level, const char *format, va_list args)
1077 int ret = 0;
1079 /* if current logmask does not overlap with level, do not print msg */
1080 if(!(config->logmask & level)) {
1081 return ret;
1084 #if defined(PACMAN_DEBUG)
1085 /* If debug is on, we'll timestamp the output */
1086 if(config->logmask & PM_LOG_DEBUG) {
1087 time_t t;
1088 struct tm *tmp;
1089 char timestr[10] = {0};
1091 t = time(NULL);
1092 tmp = localtime(&t);
1093 strftime(timestr, 9, "%H:%M:%S", tmp);
1094 timestr[8] = '\0';
1096 printf("[%s] ", timestr);
1098 #endif
1100 /* print a prefix to the message */
1101 switch(level) {
1102 case PM_LOG_ERROR:
1103 fprintf(stream, _("error: "));
1104 break;
1105 case PM_LOG_WARNING:
1106 fprintf(stream, _("warning: "));
1107 break;
1108 case PM_LOG_DEBUG:
1109 fprintf(stream, "debug: ");
1110 break;
1111 case PM_LOG_FUNCTION:
1112 fprintf(stream, "function: ");
1113 break;
1114 default:
1115 break;
1118 /* print the message using va_arg list */
1119 ret = vfprintf(stream, format, args);
1120 return(ret);
1123 #ifndef HAVE_STRNDUP
1124 /* A quick and dirty implementation derived from glibc */
1125 static size_t strnlen(const char *s, size_t max)
1127 register const char *p;
1128 for(p = s; *p && max--; ++p);
1129 return(p - s);
1132 char *strndup(const char *s, size_t n)
1134 size_t len = strnlen(s, n);
1135 char *new = (char *) malloc(len + 1);
1137 if (new == NULL)
1138 return NULL;
1140 new[len] = '\0';
1141 return (char *) memcpy(new, s, len);
1143 #endif
1145 /* vim: set ts=2 sw=2 noet: */