Fix some easy to find double translations
[pacman-ng.git] / src / pacman / util.c
blob833680850604966fa1b068ddd126b2d904d1de43
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>
41 #include <alpm.h>
42 #include <alpm_list.h>
44 /* pacman */
45 #include "util.h"
46 #include "conf.h"
47 #include "callback.h"
50 int trans_init(pmtransflag_t flags)
52 int ret;
53 if(config->print) {
54 ret = alpm_trans_init(flags, NULL, NULL, NULL);
55 } else {
56 ret = alpm_trans_init(flags, cb_trans_evt, cb_trans_conv,
57 cb_trans_progress);
60 if(ret == -1) {
61 pm_fprintf(stderr, PM_LOG_ERROR, _("failed to init transaction (%s)\n"),
62 alpm_strerrorlast());
63 if(pm_errno == PM_ERR_HANDLE_LOCK) {
64 fprintf(stderr, _(" if you're sure a package manager is not already\n"
65 " running, you can remove %s\n"), alpm_option_get_lockfile());
67 else if(pm_errno == PM_ERR_DB_VERSION) {
68 fprintf(stderr, _(" try running pacman-db-upgrade\n"));
71 return(-1);
73 return(0);
76 int trans_release(void)
78 if(alpm_trans_release() == -1) {
79 pm_fprintf(stderr, PM_LOG_ERROR, _("failed to release transaction (%s)\n"),
80 alpm_strerrorlast());
81 return(-1);
83 return(0);
86 int needs_root(void)
88 switch(config->op) {
89 case PM_OP_DATABASE:
90 return(1);
91 case PM_OP_UPGRADE:
92 case PM_OP_REMOVE:
93 return(!config->print);
94 case PM_OP_SYNC:
95 return(config->op_s_clean || config->op_s_sync ||
96 (!config->group && !config->op_s_info && !config->op_q_list &&
97 !config->op_s_search && !config->print));
98 default:
99 return(0);
103 /* gets the current screen column width */
104 int getcols(void)
106 #ifdef TIOCGSIZE
107 struct ttysize win;
108 if(ioctl(1, TIOCGSIZE, &win) == 0) {
109 return win.ts_cols;
111 #elif defined(TIOCGWINSZ)
112 struct winsize win;
113 if(ioctl(1, TIOCGWINSZ, &win) == 0) {
114 return win.ws_col;
116 #endif
117 return 0;
120 /* does the same thing as 'rm -rf' */
121 int rmrf(const char *path)
123 int errflag = 0;
124 struct dirent *dp;
125 DIR *dirp;
127 if(!unlink(path)) {
128 return(0);
129 } else {
130 if(errno == ENOENT) {
131 return(0);
132 } else if(errno == EPERM) {
133 /* fallthrough */
134 } else if(errno == EISDIR) {
135 /* fallthrough */
136 } else if(errno == ENOTDIR) {
137 return(1);
138 } else {
139 /* not a directory */
140 return(1);
143 dirp = opendir(path);
144 if(!dirp) {
145 return(1);
147 for(dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) {
148 if(dp->d_ino) {
149 char name[PATH_MAX];
150 sprintf(name, "%s/%s", path, dp->d_name);
151 if(strcmp(dp->d_name, "..") != 0 && strcmp(dp->d_name, ".") != 0) {
152 errflag += rmrf(name);
156 closedir(dirp);
157 if(rmdir(path)) {
158 errflag++;
160 return(errflag);
164 /** Parse the basename of a program from a path.
165 * @param path path to parse basename from
167 * @return everything following the final '/'
169 const char *mbasename(const char *path)
171 const char *last = strrchr(path, '/');
172 if(last) {
173 return(last + 1);
175 return(path);
178 /** Parse the dirname of a program from a path.
179 * The path returned should be freed.
180 * @param path path to parse dirname from
182 * @return everything preceding the final '/'
184 char *mdirname(const char *path)
186 char *ret, *last;
188 /* null or empty path */
189 if(path == NULL || path == '\0') {
190 return(strdup("."));
193 ret = strdup(path);
194 last = strrchr(ret, '/');
196 if(last != NULL) {
197 /* we found a '/', so terminate our string */
198 *last = '\0';
199 return(ret);
201 /* no slash found */
202 free(ret);
203 return(strdup("."));
206 /* output a string, but wrap words properly with a specified indentation
208 void indentprint(const char *str, int indent)
210 wchar_t *wcstr;
211 const wchar_t *p;
212 int len, cidx, cols;
214 if(!str) {
215 return;
218 cols = getcols();
220 /* if we're not a tty, print without indenting */
221 if(cols == 0) {
222 printf("%s", str);
223 return;
226 len = strlen(str) + 1;
227 wcstr = calloc(len, sizeof(wchar_t));
228 len = mbstowcs(wcstr, str, len);
229 p = wcstr;
230 cidx = indent;
232 if(!p || !len) {
233 return;
236 while(*p) {
237 if(*p == L' ') {
238 const wchar_t *q, *next;
239 p++;
240 if(p == NULL || *p == L' ') continue;
241 next = wcschr(p, L' ');
242 if(next == NULL) {
243 next = p + wcslen(p);
245 /* len captures # cols */
246 len = 0;
247 q = p;
248 while(q < next) {
249 len += wcwidth(*q++);
251 if(len > (cols - cidx - 1)) {
252 /* wrap to a newline and reindent */
253 printf("\n%-*s", indent, "");
254 cidx = indent;
255 } else {
256 printf(" ");
257 cidx++;
259 continue;
261 printf("%lc", (wint_t)*p);
262 cidx += wcwidth(*p);
263 p++;
265 free(wcstr);
268 /* Convert a string to uppercase
270 char *strtoupper(char *str)
272 char *ptr = str;
274 while(*ptr) {
275 (*ptr) = (char)toupper((unsigned char)*ptr);
276 ptr++;
278 return str;
281 /* Trim whitespace and newlines from a string
283 char *strtrim(char *str)
285 char *pch = str;
287 if(str == NULL || *str == '\0') {
288 /* string is empty, so we're done. */
289 return(str);
292 while(isspace((unsigned char)*pch)) {
293 pch++;
295 if(pch != str) {
296 memmove(str, pch, (strlen(pch) + 1));
299 /* check if there wasn't anything but whitespace in the string. */
300 if(*str == '\0') {
301 return(str);
304 pch = (str + (strlen(str) - 1));
305 while(isspace((unsigned char)*pch)) {
306 pch--;
308 *++pch = '\0';
310 return(str);
313 /* Replace all occurances of 'needle' with 'replace' in 'str', returning
314 * a new string (must be free'd) */
315 char *strreplace(const char *str, const char *needle, const char *replace)
317 const char *p = NULL, *q = NULL;
318 char *newstr = NULL, *newp = NULL;
319 alpm_list_t *i = NULL, *list = NULL;
320 size_t needlesz = strlen(needle), replacesz = strlen(replace);
321 size_t newsz;
323 if(!str) {
324 return(NULL);
327 p = str;
328 q = strstr(p, needle);
329 while(q) {
330 list = alpm_list_add(list, (char *)q);
331 p = q + needlesz;
332 q = strstr(p, needle);
335 /* no occurences of needle found */
336 if(!list) {
337 return(strdup(str));
339 /* size of new string = size of old string + "number of occurences of needle"
340 * x "size difference between replace and needle" */
341 newsz = strlen(str) + 1 +
342 alpm_list_count(list) * (replacesz - needlesz);
343 newstr = malloc(newsz);
344 if(!newstr) {
345 return(NULL);
347 *newstr = '\0';
349 p = str;
350 newp = newstr;
351 for(i = list; i; i = alpm_list_next(i)) {
352 q = alpm_list_getdata(i);
353 if(q > p){
354 /* add chars between this occurence and last occurence, if any */
355 strncpy(newp, p, (size_t)(q - p));
356 newp += q - p;
358 strncpy(newp, replace, replacesz);
359 newp += replacesz;
360 p = q + needlesz;
362 alpm_list_free(list);
364 if(*p) {
365 /* add the rest of 'p' */
366 strcpy(newp, p);
367 newp += strlen(p);
369 *newp = '\0';
371 return(newstr);
374 /** Splits a string into a list of strings using the chosen character as
375 * a delimiter.
377 * @param str the string to split
378 * @param splitchar the character to split at
380 * @return a list containing the duplicated strings
382 alpm_list_t *strsplit(const char *str, const char splitchar)
384 alpm_list_t *list = NULL;
385 const char *prev = str;
386 char *dup = NULL;
388 while((str = strchr(str, splitchar))) {
389 dup = strndup(prev, (size_t)(str - prev));
390 if(dup == NULL) {
391 return(NULL);
393 list = alpm_list_add(list, dup);
395 str++;
396 prev = str;
399 dup = strdup(prev);
400 if(dup == NULL) {
401 return(NULL);
403 list = alpm_list_add(list, dup);
405 return(list);
408 static int string_length(const char *s)
410 int len;
411 wchar_t *wcstr;
413 if(!s) {
414 return(0);
416 /* len goes from # bytes -> # chars -> # cols */
417 len = strlen(s) + 1;
418 wcstr = calloc(len, sizeof(wchar_t));
419 len = mbstowcs(wcstr, s, len);
420 len = wcswidth(wcstr, len);
421 free(wcstr);
423 return(len);
426 void string_display(const char *title, const char *string)
428 int len = 0;
430 if(title) {
431 printf("%s ", title);
433 if(string == NULL || string[0] == '\0') {
434 printf(_("None"));
435 } else {
436 /* compute the length of title + a space */
437 len = string_length(title) + 1;
438 indentprint(string, len);
440 printf("\n");
443 void list_display(const char *title, const alpm_list_t *list)
445 const alpm_list_t *i;
446 int cols, len = 0;
448 if(title) {
449 len = string_length(title) + 1;
450 printf("%s ", title);
453 if(!list) {
454 printf("%s\n", _("None"));
455 } else {
456 for(i = list, cols = len; i; i = alpm_list_next(i)) {
457 char *str = alpm_list_getdata(i);
458 int s = string_length(str);
459 int maxcols = getcols();
460 if(maxcols > 0 && (cols + s + 2) >= maxcols) {
461 int j;
462 cols = len;
463 printf("\n");
464 for (j = 1; j <= len; j++) {
465 printf(" ");
467 } else if (cols != len) {
468 /* 2 spaces are added if this is not the first element on a line. */
469 printf(" ");
470 cols += 2;
472 printf("%s", str);
473 cols += s;
475 printf("\n");
479 void list_display_linebreak(const char *title, const alpm_list_t *list)
481 const alpm_list_t *i;
482 int len = 0;
484 if(title) {
485 len = string_length(title) + 1;
486 printf("%s ", title);
489 if(!list) {
490 printf("%s\n", _("None"));
491 } else {
492 /* Print the first element */
493 indentprint((const char *) alpm_list_getdata(list), len);
494 printf("\n");
495 /* Print the rest */
496 for(i = alpm_list_next(list); i; i = alpm_list_next(i)) {
497 int j;
498 for(j = 1; j <= len; j++) {
499 printf(" ");
501 indentprint((const char *) alpm_list_getdata(i), len);
502 printf("\n");
506 /* prepare a list of pkgs to display */
507 void display_targets(const alpm_list_t *pkgs, int install)
509 char *str;
510 const alpm_list_t *i;
511 off_t isize = 0, dlsize = 0;
512 double mbisize = 0.0, mbdlsize = 0.0;
513 alpm_list_t *targets = NULL;
515 if(!pkgs) {
516 return;
519 printf("\n");
520 for(i = pkgs; i; i = alpm_list_next(i)) {
521 pmpkg_t *pkg = alpm_list_getdata(i);
523 if(install) {
524 dlsize += alpm_pkg_download_size(pkg);
526 isize += alpm_pkg_get_isize(pkg);
528 /* print the package size with the output if ShowSize option set */
529 if(config->showsize) {
530 double mbsize = (double)alpm_pkg_get_size(pkg) / (1024.0 * 1024.0);
532 pm_asprintf(&str, "%s-%s [%.2f MB]", alpm_pkg_get_name(pkg),
533 alpm_pkg_get_version(pkg), mbsize);
534 } else {
535 pm_asprintf(&str, "%s-%s", alpm_pkg_get_name(pkg),
536 alpm_pkg_get_version(pkg));
538 targets = alpm_list_add(targets, str);
541 /* Convert byte sizes to MB */
542 mbdlsize = (double)dlsize / (1024.0 * 1024.0);
543 mbisize = (double)isize / (1024.0 * 1024.0);
545 if(install) {
546 pm_asprintf(&str, _("Targets (%d):"), alpm_list_count(targets));
547 list_display(str, targets);
548 free(str);
549 printf("\n");
551 printf(_("Total Download Size: %.2f MB\n"), mbdlsize);
552 if(!(config->flags & PM_TRANS_FLAG_DOWNLOADONLY)) {
553 printf(_("Total Installed Size: %.2f MB\n"), mbisize);
555 } else {
556 pm_asprintf(&str, _("Remove (%d):"), alpm_list_count(targets));
557 list_display(str, targets);
558 free(str);
559 printf("\n");
561 printf(_("Total Removed Size: %.2f MB\n"), mbisize);
564 FREELIST(targets);
567 static off_t pkg_get_size(pmpkg_t *pkg)
569 switch(config->op) {
570 case PM_OP_SYNC:
571 return(alpm_pkg_download_size(pkg));
572 case PM_OP_UPGRADE:
573 return(alpm_pkg_get_size(pkg));
574 default:
575 return(alpm_pkg_get_isize(pkg));
579 static char *pkg_get_location(pmpkg_t *pkg)
581 pmdb_t *db;
582 const char *dburl;
583 char *string;
584 switch(config->op) {
585 case PM_OP_SYNC:
586 db = alpm_pkg_get_db(pkg);
587 dburl = alpm_db_get_url(db);
588 if(dburl) {
589 char *pkgurl = NULL;
590 pm_asprintf(&pkgurl, "%s/%s", dburl, alpm_pkg_get_filename(pkg));
591 return(pkgurl);
593 case PM_OP_UPGRADE:
594 return(strdup(alpm_pkg_get_filename(pkg)));
595 default:
596 string = NULL;
597 pm_asprintf(&string, "%s-%s", alpm_pkg_get_name(pkg), alpm_pkg_get_version(pkg));
598 return(string);
602 void print_packages(const alpm_list_t *packages)
604 const alpm_list_t *i;
605 if(!config->print_format) {
606 config->print_format = strdup("%l");
608 for(i = packages; i; i = alpm_list_next(i)) {
609 pmpkg_t *pkg = alpm_list_getdata(i);
610 char *string = strdup(config->print_format);
611 char *temp = string;
612 /* %n : pkgname */
613 if(strstr(temp,"%n")) {
614 string = strreplace(temp, "%n", alpm_pkg_get_name(pkg));
615 free(temp);
616 temp = string;
618 /* %v : pkgver */
619 if(strstr(temp,"%v")) {
620 string = strreplace(temp, "%v", alpm_pkg_get_version(pkg));
621 free(temp);
622 temp = string;
624 /* %l : location */
625 if(strstr(temp,"%l")) {
626 char *pkgloc = pkg_get_location(pkg);
627 string = strreplace(temp, "%l", pkgloc);
628 free(pkgloc);
629 free(temp);
630 temp = string;
632 /* %r : repo */
633 if(strstr(temp,"%r")) {
634 const char *repo = "local";
635 pmdb_t *db = alpm_pkg_get_db(pkg);
636 if(db) {
637 repo = alpm_db_get_name(db);
639 string = strreplace(temp, "%r", repo);
640 free(temp);
641 temp = string;
643 /* %s : size */
644 if(strstr(temp,"%s")) {
645 char *size;
646 pm_asprintf(&size, "%jd", (intmax_t)pkg_get_size(pkg));
647 string = strreplace(temp, "%s", size);
648 free(size);
649 free(temp);
651 printf("%s\n",string);
652 free(string);
656 /* Helper function for comparing strings using the
657 * alpm "compare func" signature */
658 int str_cmp(const void *s1, const void *s2)
660 return(strcmp(s1, s2));
663 void display_new_optdepends(pmpkg_t *oldpkg, pmpkg_t *newpkg)
665 alpm_list_t *old = alpm_pkg_get_optdepends(oldpkg);
666 alpm_list_t *new = alpm_pkg_get_optdepends(newpkg);
667 alpm_list_t *optdeps = alpm_list_diff(new,old,str_cmp);
668 if(optdeps) {
669 printf(_("New optional dependencies for %s\n"), alpm_pkg_get_name(newpkg));
670 list_display_linebreak(" ", optdeps);
672 alpm_list_free(optdeps);
675 void display_optdepends(pmpkg_t *pkg)
677 alpm_list_t *optdeps = alpm_pkg_get_optdepends(pkg);
678 if(optdeps) {
679 printf(_("Optional dependencies for %s\n"), alpm_pkg_get_name(pkg));
680 list_display_linebreak(" ", optdeps);
684 static void display_repo_list(const char *dbname, alpm_list_t *list)
686 const char *prefix= " ";
688 printf(":: ");
689 printf(_("Repository %s\n"), dbname);
690 list_display(prefix, list);
693 void select_display(const alpm_list_t *pkglist)
695 const alpm_list_t *i;
696 int nth = 1;
697 alpm_list_t *list = NULL;
698 char *string = NULL;
699 const char *dbname = NULL;
701 for (i = pkglist; i; i = i->next) {
702 pmpkg_t *pkg = alpm_list_getdata(i);
703 pmdb_t *db = alpm_pkg_get_db(pkg);
705 if(!dbname)
706 dbname = alpm_db_get_name(db);
707 if(strcmp(alpm_db_get_name(db), dbname) != 0) {
708 display_repo_list(dbname, list);
709 FREELIST(list);
710 dbname = alpm_db_get_name(db);
712 string = NULL;
713 pm_asprintf(&string, "%d) %s", nth, alpm_pkg_get_name(pkg));
714 list = alpm_list_add(list, string);
715 nth++;
717 display_repo_list(dbname, list);
718 FREELIST(list);
721 static int parseindex(char *s, int *val, int min, int max)
723 char *endptr = NULL;
724 int n = strtol(s, &endptr, 10);
725 if(*endptr == '\0') {
726 if(n < min || n > max) {
727 fprintf(stderr, _("Invalid value: %d is not between %d and %d\n"),
728 n, min, max);
729 return(-1);
731 *val = n;
732 return(0);
733 } else {
734 fprintf(stderr, _("Invalid number: %s\n"), s);
735 return(-1);
739 static int multiselect_parse(char *array, int count, char *response)
741 char *str, *saveptr;
743 for (str = response; ; str = NULL) {
744 int include = 1;
745 int start, end;
746 char *ends = NULL;
747 char *starts = strtok_r(str, " ", &saveptr);
749 if (starts == NULL)
750 break;
751 strtrim(starts);
752 int len = strlen(starts);
753 if(len == 0)
754 continue;
756 if (*starts == '^') {
757 starts++;
758 len--;
759 include = 0;
760 } else if(str) {
761 /* if first token is including, we unselect all targets */
762 memset(array, 0, count);
765 if(len > 1) {
766 /* check for range */
767 char *p;
768 if((p = strchr(starts+1, '-'))) {
769 *p = 0;
770 ends = p+1;
774 if(parseindex(starts, &start, 1, count) != 0)
775 return(-1);
777 if(!ends) {
778 array[start-1] = include;
779 } else {
780 if(parseindex(ends, &end, start, count) != 0)
781 return(-1);
782 for(int d = start; d <= end; d++) {
783 array[d-1] = include;
788 return(0);
791 int multiselect_question(char *array, int count)
793 char response[64];
794 FILE *stream;
796 if(config->noconfirm) {
797 stream = stdout;
798 } else {
799 /* Use stderr so questions are always displayed when redirecting output */
800 stream = stderr;
803 while(1) {
804 memset(array, 1, count);
806 fprintf(stream, "\n");
807 fprintf(stream, _("Enter a selection (default=all)"));
808 fprintf(stream, ": ");
810 if(config->noconfirm) {
811 fprintf(stream, "\n");
812 break;
815 if(fgets(response, sizeof(response), stdin)) {
816 strtrim(response);
817 if(strlen(response) > 0) {
818 if(multiselect_parse(array, count, response) == -1) {
819 /* only loop if user gave an invalid answer */
820 continue;
824 break;
826 return(0);
829 int select_question(int count)
831 char response[32];
832 FILE *stream;
833 int preset = 1;
835 if(config->noconfirm) {
836 stream = stdout;
837 } else {
838 /* Use stderr so questions are always displayed when redirecting output */
839 stream = stderr;
842 while(1) {
843 fprintf(stream, "\n");
844 fprintf(stream, _("Enter a number (default=%d)"), preset);
845 fprintf(stream, ": ");
847 if(config->noconfirm) {
848 fprintf(stream, "\n");
849 break;
852 if(fgets(response, sizeof(response), stdin)) {
853 strtrim(response);
854 if(strlen(response) > 0) {
855 int n;
856 if(parseindex(response, &n, 1, count) != 0)
857 continue;
858 return(n-1);
861 break;
864 return(preset-1);
868 /* presents a prompt and gets a Y/N answer */
869 static int question(short preset, char *fmt, va_list args)
871 char response[32];
872 FILE *stream;
874 if(config->noconfirm) {
875 stream = stdout;
876 } else {
877 /* Use stderr so questions are always displayed when redirecting output */
878 stream = stderr;
881 vfprintf(stream, fmt, args);
883 if(preset) {
884 fprintf(stream, " %s ", _("[Y/n]"));
885 } else {
886 fprintf(stream, " %s ", _("[y/N]"));
889 if(config->noconfirm) {
890 fprintf(stream, "\n");
891 return(preset);
894 if(fgets(response, sizeof(response), stdin)) {
895 strtrim(response);
896 if(strlen(response) == 0) {
897 return(preset);
900 if(strcasecmp(response, _("Y")) == 0 || strcasecmp(response, _("YES")) == 0) {
901 return(1);
902 } else if (strcasecmp(response, _("N")) == 0 || strcasecmp(response, _("NO")) == 0) {
903 return(0);
906 return(0);
909 int yesno(char *fmt, ...)
911 int ret;
912 va_list args;
914 va_start(args, fmt);
915 ret = question(1, fmt, args);
916 va_end(args);
918 return(ret);
921 int noyes(char *fmt, ...)
923 int ret;
924 va_list args;
926 va_start(args, fmt);
927 ret = question(0, fmt, args);
928 va_end(args);
930 return(ret);
933 int pm_printf(pmloglevel_t level, const char *format, ...)
935 int ret;
936 va_list args;
938 /* print the message using va_arg list */
939 va_start(args, format);
940 ret = pm_vfprintf(stdout, level, format, args);
941 va_end(args);
943 return(ret);
946 int pm_fprintf(FILE *stream, pmloglevel_t level, const char *format, ...)
948 int ret;
949 va_list args;
951 /* print the message using va_arg list */
952 va_start(args, format);
953 ret = pm_vfprintf(stream, level, format, args);
954 va_end(args);
956 return(ret);
959 int pm_asprintf(char **string, const char *format, ...)
961 int ret = 0;
962 va_list args;
964 /* print the message using va_arg list */
965 va_start(args, format);
966 if(vasprintf(string, format, args) == -1) {
967 pm_fprintf(stderr, PM_LOG_ERROR, _("failed to allocate string\n"));
968 ret = -1;
970 va_end(args);
972 return(ret);
975 int pm_vasprintf(char **string, pmloglevel_t level, const char *format, va_list args)
977 int ret = 0;
978 char *msg = NULL;
980 /* if current logmask does not overlap with level, do not print msg */
981 if(!(config->logmask & level)) {
982 return ret;
985 /* print the message using va_arg list */
986 ret = vasprintf(&msg, format, args);
988 /* print a prefix to the message */
989 switch(level) {
990 case PM_LOG_ERROR:
991 pm_asprintf(string, _("error: %s"), msg);
992 break;
993 case PM_LOG_WARNING:
994 pm_asprintf(string, _("warning: %s"), msg);
995 break;
996 case PM_LOG_DEBUG:
997 pm_asprintf(string, "debug: %s", msg);
998 break;
999 case PM_LOG_FUNCTION:
1000 pm_asprintf(string, "function: %s", msg);
1001 break;
1002 default:
1003 pm_asprintf(string, "%s", msg);
1004 break;
1006 free(msg);
1008 return(ret);
1011 int pm_vfprintf(FILE *stream, pmloglevel_t level, const char *format, va_list args)
1013 int ret = 0;
1015 /* if current logmask does not overlap with level, do not print msg */
1016 if(!(config->logmask & level)) {
1017 return ret;
1020 #if defined(PACMAN_DEBUG)
1021 /* If debug is on, we'll timestamp the output */
1022 if(config->logmask & PM_LOG_DEBUG) {
1023 time_t t;
1024 struct tm *tmp;
1025 char timestr[10] = {0};
1027 t = time(NULL);
1028 tmp = localtime(&t);
1029 strftime(timestr, 9, "%H:%M:%S", tmp);
1030 timestr[8] = '\0';
1032 printf("[%s] ", timestr);
1034 #endif
1036 /* print a prefix to the message */
1037 switch(level) {
1038 case PM_LOG_ERROR:
1039 fprintf(stream, _("error: "));
1040 break;
1041 case PM_LOG_WARNING:
1042 fprintf(stream, _("warning: "));
1043 break;
1044 case PM_LOG_DEBUG:
1045 fprintf(stream, "debug: ");
1046 break;
1047 case PM_LOG_FUNCTION:
1048 fprintf(stream, "function: ");
1049 break;
1050 default:
1051 break;
1054 /* print the message using va_arg list */
1055 ret = vfprintf(stream, format, args);
1056 return(ret);
1059 #ifndef HAVE_STRNDUP
1060 /* A quick and dirty implementation derived from glibc */
1061 static size_t strnlen(const char *s, size_t max)
1063 register const char *p;
1064 for(p = s; *p && max--; ++p);
1065 return(p - s);
1068 char *strndup(const char *s, size_t n)
1070 size_t len = strnlen(s, n);
1071 char *new = (char *) malloc(len + 1);
1073 if (new == NULL)
1074 return NULL;
1076 new[len] = '\0';
1077 return (char *) memcpy(new, s, len);
1079 #endif
1081 /* vim: set ts=2 sw=2 noet: */