diff options
Diffstat (limited to 'src/pacman/util.c')
-rw-r--r-- | src/pacman/util.c | 437 |
1 files changed, 296 insertions, 141 deletions
diff --git a/src/pacman/util.c b/src/pacman/util.c index 9c79cf5f..89313c83 100644 --- a/src/pacman/util.c +++ b/src/pacman/util.c @@ -1,8 +1,8 @@ /* * util.c - * + * * Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org> - * + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -15,32 +15,27 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. */ #include "config.h" -#if defined(__APPLE__) || defined(__OpenBSD__) -#include <sys/syslimits.h> -#include <sys/stat.h> -#endif #include <sys/types.h> #include <sys/ioctl.h> #include <sys/time.h> +#include <sys/stat.h> #include <stdio.h> #include <stdlib.h> +#include <stdarg.h> #include <string.h> #include <errno.h> #include <fcntl.h> #include <ctype.h> #include <dirent.h> #include <unistd.h> -#include <libintl.h> -#ifdef CYGWIN -#include <limits.h> /* PATH_MAX */ -#endif +#include <limits.h> #include <alpm.h> #include <alpm_list.h> @@ -48,9 +43,21 @@ /* pacman */ #include "util.h" #include "conf.h" -#include "log.h" -extern config_t *config; +int needs_transaction() +{ + if(config->op != PM_OP_MAIN && config->op != PM_OP_QUERY && config->op != PM_OP_DEPTEST) { + if((config->op == PM_OP_SYNC && !config->op_s_sync && + (config->op_s_search || config->group || config->op_q_list || config->op_q_info)) + || config->op == PM_OP_DEPTEST) { + /* special case: PM_OP_SYNC can be used w/ config->op_s_search by any user */ + return(0); + } else { + return(1); + } + } + return(0); +} /* gets the current screen column width */ int getcols() @@ -86,10 +93,10 @@ int getcols() } /* does the same thing as 'mkdir -p' */ -int makepath(char *path) +int makepath(const char *path) { char *orig, *str, *ptr; - char full[PATH_MAX] = ""; + char full[PATH_MAX+1] = ""; mode_t oldmask; oldmask = umask(0000); @@ -100,6 +107,7 @@ int makepath(char *path) if(strlen(ptr)) { struct stat buf; + /* TODO we should use strncat */ strcat(full, "/"); strcat(full, ptr); if(stat(full, &buf)) { @@ -117,7 +125,7 @@ int makepath(char *path) } /* does the same thing as 'rm -rf' */ -int rmrf(char *path) +int rmrf(const char *path) { int errflag = 0; struct dirent *dp; @@ -159,6 +167,28 @@ int rmrf(char *path) } } +/** Parse the basename of a program from a path. +* Grabbed from the uClibc source. +* @param path path to parse basename from +* +* @return everything following the final '/' +*/ +char *mbasename(const char *path) +{ + const char *s; + const char *p; + + p = s = path; + + while (*s) { + if (*s++ == '/') { + p = s; + } + } + + return (char *)p; +} + /* output a string, but wrap words properly with a specified indentation */ void indentprint(const char *str, int indent) @@ -169,12 +199,12 @@ void indentprint(const char *str, int indent) while(*p) { if(*p == ' ') { const char *next = NULL; - unsigned int len; + int len; p++; if(p == NULL || *p == ' ') continue; next = strchr(p, ' '); if(next == NULL) { - next = p + strlen(p); + next = p + mbstowcs(NULL, p, 0); } len = next - p; if(len > (getcols() - cidx - 1)) { @@ -214,34 +244,133 @@ char *strtoupper(char *str) char *strtrim(char *str) { char *pch = str; + + if(str == NULL || *str == '\0') { + /* string is empty, so we're done. */ + return(str); + } + while(isspace(*pch)) { pch++; } if(pch != str) { memmove(str, pch, (strlen(pch) + 1)); } - - pch = (char *)(str + (strlen(str) - 1)); + + /* check if there wasn't anything but whitespace in the string. */ + if(*str == '\0') { + return(str); + } + + pch = (str + (strlen(str) - 1)); while(isspace(*pch)) { pch--; } *++pch = '\0'; - return str; + return(str); +} + +/* Helper function for strreplace */ +static void _strnadd(char **str, const char *append, unsigned int count) +{ + if(*str) { + *str = realloc(*str, strlen(*str) + count + 1); + } else { + *str = calloc(sizeof(char), count + 1); + } + + strncat(*str, append, count); +} + +/* Replace all occurances of 'needle' with 'replace' in 'str', returning + * a new string (must be free'd) */ +char *strreplace(const char *str, const char *needle, const char *replace) +{ + const char *p, *q; + p = q = str; + + char *newstr = NULL; + unsigned int needlesz = strlen(needle), + replacesz = strlen(replace); + + while (1) { + q = strstr(p, needle); + if(!q) { /* not found */ + if(*p) { + /* add the rest of 'p' */ + _strnadd(&newstr, p, strlen(p)); + } + break; + } else { /* found match */ + if(q > p){ + /* add chars between this occurance and last occurance, if any */ + _strnadd(&newstr, p, q - p); + } + _strnadd(&newstr, replace, replacesz); + p = q + needlesz; + } + } + + return newstr; +} + +/** Splits a string into a list of strings using the chosen character as + * a delimiter. + * + * @param str the string to split + * @param splitchar the character to split at + * + * @return a list containing the duplicated strings + */ +alpm_list_t *strsplit(const char *str, const char splitchar) +{ + alpm_list_t *list = NULL; + const char *prev = str; + char *dup = NULL; + + while((str = strchr(str, splitchar))) { + dup = strndup(prev, str - prev); + if(dup == NULL) { + return(NULL); + } + list = alpm_list_add(list, dup); + + str++; + prev = str; + } + + dup = strdup(prev); + if(dup == NULL) { + return(NULL); + } + list = alpm_list_add(list, strdup(prev)); + + return(list); } -void list_display(const char *title, alpm_list_t *list) +void string_display(const char *title, const char *string) { - alpm_list_t *i; + printf("%s ", title); + if(string == NULL || string[0] == '\0') { + printf(_("None\n")); + } else { + printf("%s\n", string); + } +} + +void list_display(const char *title, const alpm_list_t *list) +{ + const alpm_list_t *i; int cols, len; - len = strlen(title); + len = mbstowcs(NULL, title, 0); printf("%s ", title); if(list) { for(i = list, cols = len; i; i = alpm_list_next(i)) { char *str = alpm_list_getdata(i); - int s = strlen(str) + 2; + int s = mbstowcs(NULL, str, 0) + 2; int maxcols = getcols(); if(s + cols >= maxcols) { int i; @@ -264,14 +393,15 @@ void list_display(const char *title, alpm_list_t *list) * `pkgs` should be a list of pmsyncpkg_t's, * retrieved from a transaction object */ -void display_targets(alpm_list_t *syncpkgs) +/* TODO move to output.c? or just combine util and output */ +void display_targets(const alpm_list_t *syncpkgs, pmdb_t *db_local) { char *str; - alpm_list_t *i, *j; + const alpm_list_t *i, *j; alpm_list_t *targets = NULL, *to_remove = NULL; /* TODO these are some messy variable names */ - unsigned long size = 0, isize = 0, rsize = 0; - double mbsize = 0.0, mbisize = 0.0, mbrsize = 0.0; + unsigned long isize = 0, rsize = 0, dispsize = 0, dlsize = 0; + double mbisize = 0.0, mbrsize = 0.0, mbdispsize = 0.0, mbdlsize = 0.0; for(i = syncpkgs; i; i = alpm_list_next(i)) { pmsyncpkg_t *sync = alpm_list_getdata(i); @@ -282,7 +412,7 @@ void display_targets(alpm_list_t *syncpkgs) * installed. */ if(alpm_sync_get_type(sync) == PM_SYNC_TYPE_REPLACE) { alpm_list_t *to_replace = alpm_sync_get_data(sync); - + for(j = to_replace; j; j = alpm_list_next(j)) { pmpkg_t *rp = alpm_list_getdata(j); const char *name = alpm_pkg_get_name(rp); @@ -294,153 +424,178 @@ void display_targets(alpm_list_t *syncpkgs) } } - size += alpm_pkg_get_size(pkg); + dispsize = alpm_pkg_get_size(pkg); + dlsize += alpm_pkg_download_size(pkg, db_local); isize += alpm_pkg_get_isize(pkg); - asprintf(&str, "%s-%s", alpm_pkg_get_name(pkg), alpm_pkg_get_version(pkg)); + /* print the package size with the output if ShowSize option set */ + if(config->showsize) { + /* Convert byte size to MB */ + mbdispsize = dispsize / (1024.0 * 1024.0); + + asprintf(&str, "%s-%s [%.2f MB]", alpm_pkg_get_name(pkg), + alpm_pkg_get_version(pkg), mbdispsize); + } else { + asprintf(&str, "%s-%s", alpm_pkg_get_name(pkg), + alpm_pkg_get_version(pkg)); + } targets = alpm_list_add(targets, str); } /* Convert byte sizes to MB */ - mbsize = (double)(size) / (1024.0 * 1024.0); - mbisize = (double)(isize) / (1024.0 * 1024.0); - mbrsize = (double)(rsize) / (1024.0 * 1024.0); + mbisize = isize / (1024.0 * 1024.0); + mbrsize = rsize / (1024.0 * 1024.0); + mbdlsize = dlsize / (1024.0 * 1024.0); + + /* start displaying information */ + printf("\n"); if(to_remove) { - MSG(NL, "\n"); /* TODO ugly hack. printing a single NL should be easy */ list_display(_("Remove:"), to_remove); + printf("\n"); FREELIST(to_remove); - - if(mbrsize > 0) { - /* round up if size is really small */ - if(mbrsize < 0.1) { - mbrsize = 0.1; - } - MSG(NL, _("\nTotal Removed Size: %.2f MB\n"), mbrsize); - } + + printf(_("Total Removed Size: %.2f MB\n"), mbrsize); + printf("\n"); } - MSG(NL, "\n"); /* TODO ugly hack. printing a single NL should be easy */ list_display(_("Targets:"), targets); + printf("\n"); - /* round up if size is really small */ - if(mbsize < 0.1) { - mbsize = 0.1; - } - MSG(NL, _("\nTotal Package Size: %.2f MB\n"), mbsize); - - if(mbisize > mbsize) { - /*round up if size is really small */ - if(mbisize < 0.1) { - mbisize = 0.1; - } - MSG(NL, _("Total Installed Size: %.2f MB\n"), mbisize); + printf(_("Total Download Size: %.2f MB\n"), mbdlsize); + + /* TODO because all pkgs don't include isize, this is a crude hack */ + if(mbisize > mbdlsize) { + printf(_("Total Installed Size: %.2f MB\n"), mbisize); } FREELIST(targets); } -/* Silly little helper function, determines if the caller needs a visual update - * since the last time this function was called. - * This is made for the two progress bar functions, to prevent flicker - * - * first_call indicates if this is the first time it is called, for - * initialization purposes */ -float get_update_timediff(int first_call) +/* presents a prompt and gets a Y/N answer */ +/* TODO there must be a better way */ +int yesno(char *fmt, ...) { - float retval = 0.0; - static struct timeval last_time = {0}; + char response[32]; + va_list args; - /* on first call, simply set the last time and return */ - if(first_call) { - gettimeofday(&last_time, NULL); - } else { - struct timeval this_time; - float diff_sec, diff_usec; + if(config->noconfirm) { + return(1); + } - gettimeofday(&this_time, NULL); - diff_sec = this_time.tv_sec - last_time.tv_sec; - diff_usec = this_time.tv_usec - last_time.tv_usec; + va_start(args, fmt); + /* Use stderr so questions are always displayed when redirecting output */ + vfprintf(stderr, fmt, args); + va_end(args); - retval = diff_sec + (diff_usec / 1000000.0); + if(fgets(response, 32, stdin)) { + if(strlen(response) != 0) { + strtrim(response); + } - /* return 0 and do not update last_time if interval was too short */ - if(retval < UPDATE_SPEED_SEC) { - retval = 0.0; - } else { - last_time = this_time; - /* printf("\nupdate retval: %f\n", retval); DEBUG*/ + if(!strcasecmp(response, _("Y")) || !strcasecmp(response, _("YES")) || strlen(response) == 0) { + return(1); } } - - return(retval); + return(0); } -/* refactored from cb_trans_progress */ -void fill_progress(const int percent, const int proglen) +int pm_printf(pmloglevel_t level, const char *format, ...) { - const unsigned short chomp = alpm_option_get_chomp(); - const unsigned int hashlen = proglen - 8; - const unsigned int hash = percent * hashlen / 100; - static unsigned int lasthash = 0, mouth = 0; - unsigned int i; + int ret; + va_list args; - /* printf("\ndebug: proglen: %i\n", proglen); DEBUG*/ + /* print the message using va_arg list */ + va_start(args, format); + ret = pm_vfprintf(stdout, level, format, args); + va_end(args); - if(percent == 0) { - lasthash = 0; - mouth = 0; - } + return(ret); +} - /* magic numbers, how I loathe thee */ - if(proglen > 8) { - printf(" ["); - for(i = hashlen; i > 1; --i) { - /* if special progress bar enabled */ - if(chomp) { - if(i > hashlen - hash) { - printf("-"); - } else if(i == hashlen - hash) { - if(lasthash == hash) { - if(mouth) { - printf("\033[1;33mC\033[m"); - } else { - printf("\033[1;33mc\033[m"); - } - } else { - lasthash = hash; - mouth = mouth == 1 ? 0 : 1; - if(mouth) { - printf("\033[1;33mC\033[m"); - } else { - printf("\033[1;33mc\033[m"); - } - } - } else if(i%3 == 0) { - printf("\033[0;37mo\033[m"); - } else { - printf("\033[0;37m \033[m"); - } - } /* else regular progress bar */ - else if(i > hashlen - hash) { - printf("#"); - } else { - printf("-"); - } - } - printf("]"); +int pm_fprintf(FILE *stream, pmloglevel_t level, const char *format, ...) +{ + int ret; + va_list args; + + /* print the message using va_arg list */ + va_start(args, format); + ret = pm_vfprintf(stream, level, format, args); + va_end(args); + + return(ret); +} + +int pm_vfprintf(FILE *stream, pmloglevel_t level, const char *format, va_list args) +{ + int ret = 0; + + /* if current logmask does not overlap with level, do not print msg */ + if(!(config->logmask & level)) { + return ret; } - /* print percent after progress bar */ - if(proglen > 5) { - printf(" %3d%%", percent); + +#if defined(PACMAN_DEBUG) + /* If debug is on, we'll timestamp the output */ + if(config->logmask & PM_LOG_DEBUG) { + time_t t; + struct tm *tmp; + char timestr[10] = {0}; + + t = time(NULL); + tmp = localtime(&t); + strftime(timestr, 9, "%H:%M:%S", tmp); + timestr[8] = '\0'; + + printf("[%s] ", timestr); } +#endif - if(percent == 100) { - printf("\n"); - } else { - printf("\r"); + /* print a prefix to the message */ + switch(level) { + case PM_LOG_DEBUG: + fprintf(stream, _("debug: ")); + break; + case PM_LOG_ERROR: + fprintf(stream, _("error: ")); + break; + case PM_LOG_WARNING: + fprintf(stream, _("warning: ")); + break; + case PM_LOG_FUNCTION: + /* TODO we should increase the indent level when this occurs so we can see + * program flow easier. It'll be fun */ + fprintf(stream, _("function: ")); + break; + default: + break; } - fflush(stdout); + + /* print the message using va_arg list */ + ret = vfprintf(stream, format, args); + return(ret); +} + +#ifndef HAVE_STRNDUP +/* A quick and dirty implementation derived from glibc */ +static size_t strnlen(const char *s, size_t max) +{ + register const char *p; + for(p = s; *p && max--; ++p); + return(p - s); } +char *strndup(const char *s, size_t n) +{ + size_t len = strnlen(s, n); + char *new = (char *) malloc(len + 1); + + if (new == NULL) + return NULL; + + new[len] = '\0'; + return (char *) memcpy(new, s, len); +} +#endif + /* vim: set ts=2 sw=2 noet: */ |