summaryrefslogtreecommitdiff
path: root/src/pacman/util.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/pacman/util.c')
-rw-r--r--src/pacman/util.c437
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: */