/* * util.c * * Copyright (c) 2002-2006 by Judd Vinet * * 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 * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * 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, * USA. */ #if defined(__APPLE__) || defined(__OpenBSD__) #include #include #endif #include #include #include #include "config.h" #include #include #include #include #include #include #include #include #include #ifdef CYGWIN #include /* PATH_MAX */ #endif #include #include /* pacman */ #include "util.h" #include "conf.h" #include "log.h" extern config_t *config; /* gets the current screen column width */ unsigned int getcols() { if(!isatty(1)) { /* We will default to 80 columns if we're not a tty * this seems a fairly standard file width. */ return 80; } else { #ifdef TIOCGSIZE struct ttysize win; if(ioctl(1, TIOCGSIZE, &win) == 0) { return win.ts_cols; } #elif defined(TIOCGWINSZ) struct winsize win; if(ioctl(1, TIOCGWINSZ, &win) == 0) { return win.ws_col; } #endif /* If we can't figure anything out, we'll just assume 80 columns */ /* TODO any problems caused by this assumption? */ return 80; } /* Original envvar way - prone to display issues const char *cenv = getenv("COLUMNS"); if(cenv != NULL) { return atoi(cenv); } return -1; */ } /* does the same thing as 'mkdir -p' */ int makepath(char *path) { char *orig, *str, *ptr; char full[PATH_MAX] = ""; mode_t oldmask; oldmask = umask(0000); orig = strdup(path); str = orig; while((ptr = strsep(&str, "/"))) { if(strlen(ptr)) { struct stat buf; strcat(full, "/"); strcat(full, ptr); if(stat(full, &buf)) { if(mkdir(full, 0755)) { free(orig); umask(oldmask); return(1); } } } } free(orig); umask(oldmask); return(0); } /* does the same thing as 'rm -rf' */ int rmrf(char *path) { int errflag = 0; struct dirent *dp; DIR *dirp; if(!unlink(path)) { return(0); } else { if(errno == ENOENT) { return(0); } else if(errno == EPERM) { /* fallthrough */ } else if(errno == EISDIR) { /* fallthrough */ } else if(errno == ENOTDIR) { return(1); } else { /* not a directory */ return(1); } if((dirp = opendir(path)) == (DIR *)-1) { return(1); } for(dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) { if(dp->d_ino) { char name[PATH_MAX]; sprintf(name, "%s/%s", path, dp->d_name); if(strcmp(dp->d_name, "..") && strcmp(dp->d_name, ".")) { errflag += rmrf(name); } } } closedir(dirp); if(rmdir(path)) { errflag++; } return(errflag); } } /* output a string, but wrap words properly with a specified indentation */ void indentprint(const char *str, unsigned int indent) { const char *p = str; unsigned int cidx = indent; while(*p) { if(*p == ' ') { const char *next = NULL; unsigned int len; p++; if(p == NULL || *p == ' ') continue; next = strchr(p, ' '); if(next == NULL) { next = p + strlen(p); } len = next - p; if(len > (getcols()-cidx-1)) { /* newline */ unsigned int i; fprintf(stdout, "\n"); for(i = 0; i < indent; i++) { fprintf(stdout, " "); } cidx = indent; } else { printf(" "); cidx++; } } fprintf(stdout, "%c", *p); p++; cidx++; } } /* Convert a string to uppercase */ char *strtoupper(char *str) { char *ptr = str; while(*ptr) { (*ptr) = toupper(*ptr); ptr++; } return str; } /* Trim whitespace and newlines from a string */ char *strtrim(char *str) { char *pch = str; while(isspace(*pch)) { pch++; } if(pch != str) { memmove(str, pch, (strlen(pch) + 1)); } pch = (char *)(str + (strlen(str) - 1)); while(isspace(*pch)) { pch--; } *++pch = '\0'; return str; } void list_display(const char *title, alpm_list_t *list) { alpm_list_t *i; int cols, len; len = strlen(title); 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; unsigned int maxcols = getcols(); if(s + cols >= maxcols) { int i; cols = len; printf("\n"); for (i = 0; i <= len; ++i) { printf(" "); } } printf("%s ", str); cols += s; } printf("\n"); } else { printf(_("None\n")); } } /* Display a list of transaction targets. * `pkgs` should be a list of pmsyncpkg_t's, * retrieved from a transaction object */ void display_targets(alpm_list_t *syncpkgs) { char *str; alpm_list_t *i, *j; alpm_list_t *targets = NULL, *to_remove = NULL; unsigned long totalsize = 0, totalisize = 0, totalrsize = 0; for(i = syncpkgs; i; i = alpm_list_next(i)) { pmsyncpkg_t *sync = alpm_list_getdata(i); pmpkg_t *pkg = alpm_sync_get_package(sync); /* If this sync record is a replacement, the data member contains * a list of packages to be removed due to the package that is being * 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); if(!alpm_list_find_str(to_remove, name)) { totalrsize += alpm_pkg_get_isize(rp); to_remove = alpm_list_add(to_remove, strdup(name)); } } } totalsize += alpm_pkg_get_size(pkg); totalisize += alpm_pkg_get_isize(pkg); asprintf(&str, "%s-%s", alpm_pkg_get_name(pkg), alpm_pkg_get_version(pkg)); targets = alpm_list_add(targets, str); } if(to_remove) { MSG(NL, "\n"); /* TODO ugly hack. printing a single NL should be easy */ list_display(_("Remove:"), to_remove); FREELIST(to_remove); double rmb = (double)(totalrsize) / (1024.0 * 1024.0); if(rmb > 0) { if(rmb < 0.1) { rmb = 0.1; } MSG(NL, _("\nTotal Removed Size: %.2f MB\n"), rmb); } } MSG(NL, "\n"); /* TODO ugly hack. printing a single NL should be easy */ list_display(_("Targets:"), targets); double mb = (double)(totalsize) / (1024.0 * 1024.0); if(mb < 0.1) { mb = 0.1; } MSG(NL, _("\nTotal Package Size: %.2f MB\n"), mb); double umb = (double)(totalisize) / (1024.0 * 1024.0); if(umb > 0) { if(umb < 0.1) { umb = 0.1; } MSG(NL, _("Total Installed Size: %.2f MB\n"), umb); } 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) { float retval = 0.0; static struct timeval last_time = {0}; struct timeval this_time; if(first_call) { /* always update on the first call */ retval = 1.0; } else { gettimeofday(&this_time, NULL); float diff_sec = this_time.tv_sec - last_time.tv_sec; float diff_usec = this_time.tv_usec - last_time.tv_usec; retval = diff_sec + (diff_usec / 1000000.0f); /*printf("update time: %fs %fus = %f\n", diff_sec, diff_usec, retval);*/ if(retval < UPDATE_SPEED_SEC) { /* maintain the last_time value for the next call */ return(0.0); } } /* set the time for the next call */ gettimeofday(&last_time, NULL); return(retval); } /* refactored from cb_trans_progress */ void fill_progress(const int percent, const int proglen) { const unsigned short chomp = alpm_option_get_chomp(); const unsigned int hashlen = proglen - 8; const unsigned int hash = percent * hashlen / 100; unsigned int lasthash = 0, mouth = 0; unsigned int i; 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("] %3d%%\r", percent); if(percent == 100) { printf("\n"); } fflush(stdout); } /* vim: set ts=2 sw=2 noet: */