libalpm
Arch Linux Package Manager Library
|
00001 /* 00002 * util.c 00003 * 00004 * Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org> 00005 * Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org> 00006 * 00007 * This program is free software; you can redistribute it and/or modify 00008 * it under the terms of the GNU General Public License as published by 00009 * the Free Software Foundation; either version 2 of the License, or 00010 * (at your option) any later version. 00011 * 00012 * This program is distributed in the hope that it will be useful, 00013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00015 * GNU General Public License for more details. 00016 * 00017 * You should have received a copy of the GNU General Public License 00018 * along with this program. If not, see <http://www.gnu.org/licenses/>. 00019 */ 00020 00021 #include <sys/types.h> 00022 #include <sys/ioctl.h> 00023 #include <sys/stat.h> 00024 #include <time.h> 00025 00026 #include <stdio.h> 00027 #include <stdlib.h> 00028 #include <stdarg.h> 00029 #include <stdint.h> /* intmax_t */ 00030 #include <string.h> 00031 #include <errno.h> 00032 #include <ctype.h> 00033 #include <dirent.h> 00034 #include <unistd.h> 00035 #include <limits.h> 00036 #include <wchar.h> 00037 #ifdef HAVE_TERMIOS_H 00038 #include <termios.h> /* tcflush */ 00039 #endif 00040 00041 #include <alpm.h> 00042 #include <alpm_list.h> 00043 00044 /* pacman */ 00045 #include "util.h" 00046 #include "conf.h" 00047 #include "callback.h" 00048 00049 00050 int trans_init(alpm_transflag_t flags, int check_valid) 00051 { 00052 int ret; 00053 00054 check_syncdbs(0, check_valid); 00055 00056 ret = alpm_trans_init(config->handle, flags); 00057 if(ret == -1) { 00058 trans_init_error(); 00059 return -1; 00060 } 00061 return 0; 00062 } 00063 00064 void trans_init_error(void) 00065 { 00066 alpm_errno_t err = alpm_errno(config->handle); 00067 pm_printf(ALPM_LOG_ERROR, _("failed to init transaction (%s)\n"), 00068 alpm_strerror(err)); 00069 if(err == ALPM_ERR_HANDLE_LOCK) { 00070 fprintf(stderr, _(" if you're sure a package manager is not already\n" 00071 " running, you can remove %s\n"), 00072 alpm_option_get_lockfile(config->handle)); 00073 } 00074 } 00075 00076 int trans_release(void) 00077 { 00078 if(alpm_trans_release(config->handle) == -1) { 00079 pm_printf(ALPM_LOG_ERROR, _("failed to release transaction (%s)\n"), 00080 alpm_strerror(alpm_errno(config->handle))); 00081 return -1; 00082 } 00083 return 0; 00084 } 00085 00086 int needs_root(void) 00087 { 00088 switch(config->op) { 00089 case PM_OP_DATABASE: 00090 return 1; 00091 case PM_OP_UPGRADE: 00092 case PM_OP_REMOVE: 00093 return !config->print; 00094 case PM_OP_SYNC: 00095 return (config->op_s_clean || config->op_s_sync || 00096 (!config->group && !config->op_s_info && !config->op_q_list && 00097 !config->op_s_search && !config->print)); 00098 default: 00099 return 0; 00100 } 00101 } 00102 00103 int check_syncdbs(size_t need_repos, int check_valid) 00104 { 00105 int ret = 0; 00106 alpm_list_t *i; 00107 alpm_list_t *sync_dbs = alpm_option_get_syncdbs(config->handle); 00108 00109 if(need_repos && sync_dbs == NULL) { 00110 pm_printf(ALPM_LOG_ERROR, _("no usable package repositories configured.\n")); 00111 return 1; 00112 } 00113 00114 if(check_valid) { 00115 /* ensure all known dbs are valid */ 00116 for(i = sync_dbs; i; i = alpm_list_next(i)) { 00117 alpm_db_t *db = i->data; 00118 if(alpm_db_get_valid(db)) { 00119 pm_printf(ALPM_LOG_ERROR, _("database '%s' is not valid (%s)\n"), 00120 alpm_db_get_name(db), alpm_strerror(alpm_errno(config->handle))); 00121 ret = 1; 00122 } 00123 } 00124 } 00125 return ret; 00126 } 00127 00128 /* discard unhandled input on the terminal's input buffer */ 00129 static int flush_term_input(void) { 00130 #ifdef HAVE_TCFLUSH 00131 if(isatty(fileno(stdin))) { 00132 return tcflush(fileno(stdin), TCIFLUSH); 00133 } 00134 #endif 00135 00136 /* fail silently */ 00137 return 0; 00138 } 00139 00140 /* gets the current screen column width */ 00141 unsigned short getcols(void) 00142 { 00143 const unsigned short default_tty = 80; 00144 const unsigned short default_notty = 0; 00145 unsigned short termwidth = 0; 00146 00147 if(!isatty(fileno(stdout))) { 00148 return default_notty; 00149 } 00150 00151 #ifdef TIOCGSIZE 00152 struct ttysize win; 00153 if(ioctl(1, TIOCGSIZE, &win) == 0) { 00154 termwidth = win.ts_cols; 00155 } 00156 #elif defined(TIOCGWINSZ) 00157 struct winsize win; 00158 if(ioctl(1, TIOCGWINSZ, &win) == 0) { 00159 termwidth = win.ws_col; 00160 } 00161 #endif 00162 return termwidth == 0 ? default_tty : termwidth; 00163 } 00164 00165 /* does the same thing as 'rm -rf' */ 00166 int rmrf(const char *path) 00167 { 00168 int errflag = 0; 00169 struct dirent *dp; 00170 DIR *dirp; 00171 00172 if(!unlink(path)) { 00173 return 0; 00174 } else { 00175 if(errno == ENOENT) { 00176 return 0; 00177 } else if(errno == EPERM) { 00178 /* fallthrough */ 00179 } else if(errno == EISDIR) { 00180 /* fallthrough */ 00181 } else if(errno == ENOTDIR) { 00182 return 1; 00183 } else { 00184 /* not a directory */ 00185 return 1; 00186 } 00187 00188 dirp = opendir(path); 00189 if(!dirp) { 00190 return 1; 00191 } 00192 for(dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) { 00193 if(dp->d_ino) { 00194 char name[PATH_MAX]; 00195 sprintf(name, "%s/%s", path, dp->d_name); 00196 if(strcmp(dp->d_name, "..") != 0 && strcmp(dp->d_name, ".") != 0) { 00197 errflag += rmrf(name); 00198 } 00199 } 00200 } 00201 closedir(dirp); 00202 if(rmdir(path)) { 00203 errflag++; 00204 } 00205 return errflag; 00206 } 00207 } 00208 00209 /** Parse the basename of a program from a path. 00210 * @param path path to parse basename from 00211 * 00212 * @return everything following the final '/' 00213 */ 00214 const char *mbasename(const char *path) 00215 { 00216 const char *last = strrchr(path, '/'); 00217 if(last) { 00218 return last + 1; 00219 } 00220 return path; 00221 } 00222 00223 /** Parse the dirname of a program from a path. 00224 * The path returned should be freed. 00225 * @param path path to parse dirname from 00226 * 00227 * @return everything preceding the final '/' 00228 */ 00229 char *mdirname(const char *path) 00230 { 00231 char *ret, *last; 00232 00233 /* null or empty path */ 00234 if(path == NULL || path == '\0') { 00235 return strdup("."); 00236 } 00237 00238 ret = strdup(path); 00239 last = strrchr(ret, '/'); 00240 00241 if(last != NULL) { 00242 /* we found a '/', so terminate our string */ 00243 *last = '\0'; 00244 return ret; 00245 } 00246 /* no slash found */ 00247 free(ret); 00248 return strdup("."); 00249 } 00250 00251 /* output a string, but wrap words properly with a specified indentation 00252 */ 00253 void indentprint(const char *str, size_t indent) 00254 { 00255 wchar_t *wcstr; 00256 const wchar_t *p; 00257 int len, cidx; 00258 const unsigned short cols = getcols(); 00259 00260 if(!str) { 00261 return; 00262 } 00263 00264 /* if we're not a tty, or our tty is not wide enough that wrapping even makes 00265 * sense, print without indenting */ 00266 if(cols == 0 || indent > cols) { 00267 fputs(str, stdout); 00268 return; 00269 } 00270 00271 len = strlen(str) + 1; 00272 wcstr = calloc(len, sizeof(wchar_t)); 00273 len = mbstowcs(wcstr, str, len); 00274 p = wcstr; 00275 cidx = indent; 00276 00277 if(!p || !len) { 00278 return; 00279 } 00280 00281 while(*p) { 00282 if(*p == L' ') { 00283 const wchar_t *q, *next; 00284 p++; 00285 if(p == NULL || *p == L' ') continue; 00286 next = wcschr(p, L' '); 00287 if(next == NULL) { 00288 next = p + wcslen(p); 00289 } 00290 /* len captures # cols */ 00291 len = 0; 00292 q = p; 00293 while(q < next) { 00294 len += wcwidth(*q++); 00295 } 00296 if(len > (cols - cidx - 1)) { 00297 /* wrap to a newline and reindent */ 00298 printf("\n%-*s", (int)indent, ""); 00299 cidx = indent; 00300 } else { 00301 printf(" "); 00302 cidx++; 00303 } 00304 continue; 00305 } 00306 printf("%lc", (wint_t)*p); 00307 cidx += wcwidth(*p); 00308 p++; 00309 } 00310 free(wcstr); 00311 } 00312 00313 /* Convert a string to uppercase 00314 */ 00315 char *strtoupper(char *str) 00316 { 00317 char *ptr = str; 00318 00319 while(*ptr) { 00320 (*ptr) = (char)toupper((unsigned char)*ptr); 00321 ptr++; 00322 } 00323 return str; 00324 } 00325 00326 /* Trim whitespace and newlines from a string 00327 */ 00328 size_t strtrim(char *str) 00329 { 00330 char *end, *pch = str; 00331 00332 if(str == NULL || *str == '\0') { 00333 /* string is empty, so we're done. */ 00334 return 0; 00335 } 00336 00337 while(isspace((unsigned char)*pch)) { 00338 pch++; 00339 } 00340 if(pch != str) { 00341 size_t len = strlen(pch); 00342 if(len) { 00343 memmove(str, pch, len + 1); 00344 } else { 00345 *str = '\0'; 00346 } 00347 } 00348 00349 /* check if there wasn't anything but whitespace in the string. */ 00350 if(*str == '\0') { 00351 return 0; 00352 } 00353 00354 end = (str + strlen(str) - 1); 00355 while(isspace((unsigned char)*end)) { 00356 end--; 00357 } 00358 *++end = '\0'; 00359 00360 return end - pch; 00361 } 00362 00363 /* Replace all occurances of 'needle' with 'replace' in 'str', returning 00364 * a new string (must be free'd) */ 00365 char *strreplace(const char *str, const char *needle, const char *replace) 00366 { 00367 const char *p = NULL, *q = NULL; 00368 char *newstr = NULL, *newp = NULL; 00369 alpm_list_t *i = NULL, *list = NULL; 00370 size_t needlesz = strlen(needle), replacesz = strlen(replace); 00371 size_t newsz; 00372 00373 if(!str) { 00374 return NULL; 00375 } 00376 00377 p = str; 00378 q = strstr(p, needle); 00379 while(q) { 00380 list = alpm_list_add(list, (char *)q); 00381 p = q + needlesz; 00382 q = strstr(p, needle); 00383 } 00384 00385 /* no occurences of needle found */ 00386 if(!list) { 00387 return strdup(str); 00388 } 00389 /* size of new string = size of old string + "number of occurences of needle" 00390 * x "size difference between replace and needle" */ 00391 newsz = strlen(str) + 1 + 00392 alpm_list_count(list) * (replacesz - needlesz); 00393 newstr = calloc(newsz, sizeof(char)); 00394 if(!newstr) { 00395 return NULL; 00396 } 00397 00398 p = str; 00399 newp = newstr; 00400 for(i = list; i; i = alpm_list_next(i)) { 00401 q = i->data; 00402 if(q > p) { 00403 /* add chars between this occurence and last occurence, if any */ 00404 memcpy(newp, p, (size_t)(q - p)); 00405 newp += q - p; 00406 } 00407 memcpy(newp, replace, replacesz); 00408 newp += replacesz; 00409 p = q + needlesz; 00410 } 00411 alpm_list_free(list); 00412 00413 if(*p) { 00414 /* add the rest of 'p' */ 00415 strcpy(newp, p); 00416 } 00417 00418 return newstr; 00419 } 00420 00421 /** Splits a string into a list of strings using the chosen character as 00422 * a delimiter. 00423 * 00424 * @param str the string to split 00425 * @param splitchar the character to split at 00426 * 00427 * @return a list containing the duplicated strings 00428 */ 00429 alpm_list_t *strsplit(const char *str, const char splitchar) 00430 { 00431 alpm_list_t *list = NULL; 00432 const char *prev = str; 00433 char *dup = NULL; 00434 00435 while((str = strchr(str, splitchar))) { 00436 dup = strndup(prev, (size_t)(str - prev)); 00437 if(dup == NULL) { 00438 return NULL; 00439 } 00440 list = alpm_list_add(list, dup); 00441 00442 str++; 00443 prev = str; 00444 } 00445 00446 dup = strdup(prev); 00447 if(dup == NULL) { 00448 return NULL; 00449 } 00450 list = alpm_list_add(list, dup); 00451 00452 return list; 00453 } 00454 00455 static size_t string_length(const char *s) 00456 { 00457 int len; 00458 wchar_t *wcstr; 00459 00460 if(!s || s[0] == '\0') { 00461 return 0; 00462 } 00463 /* len goes from # bytes -> # chars -> # cols */ 00464 len = strlen(s) + 1; 00465 wcstr = calloc(len, sizeof(wchar_t)); 00466 len = mbstowcs(wcstr, s, len); 00467 len = wcswidth(wcstr, len); 00468 free(wcstr); 00469 00470 return len; 00471 } 00472 00473 void string_display(const char *title, const char *string) 00474 { 00475 if(title) { 00476 printf("%s ", title); 00477 } 00478 if(string == NULL || string[0] == '\0') { 00479 printf(_("None")); 00480 } else { 00481 /* compute the length of title + a space */ 00482 size_t len = string_length(title) + 1; 00483 indentprint(string, len); 00484 } 00485 printf("\n"); 00486 } 00487 00488 static void table_print_line(const alpm_list_t *line, short col_padding, 00489 size_t colcount, size_t *widths, int *has_data) 00490 { 00491 size_t i, lastcol = 0; 00492 int need_padding = 0; 00493 const alpm_list_t *curcell; 00494 00495 for(i = colcount; i > 0; i--) { 00496 if(has_data[i - 1]) { 00497 lastcol = i - 1; 00498 break; 00499 } 00500 } 00501 00502 for(i = 0, curcell = line; curcell && i < colcount; 00503 i++, curcell = alpm_list_next(curcell)) { 00504 const char *value; 00505 int cell_padding; 00506 00507 if(!has_data[i]) { 00508 continue; 00509 } 00510 00511 value = curcell->data; 00512 /* silly printf requires padding size to be an int */ 00513 cell_padding = (int)widths[i] - (int)string_length(value); 00514 if(cell_padding < 0) { 00515 cell_padding = 0; 00516 } 00517 if(need_padding) { 00518 printf("%*s", col_padding, ""); 00519 } 00520 /* left-align all but the last column */ 00521 if(i != lastcol) { 00522 printf("%s%*s", value, cell_padding, ""); 00523 } else { 00524 printf("%*s%s", cell_padding, "", value); 00525 } 00526 need_padding = 1; 00527 } 00528 00529 printf("\n"); 00530 } 00531 00532 00533 00534 /** 00535 * Find the max string width of each column. Also determines whether values 00536 * exist in the column and sets the value in has_data accordingly. 00537 * @param header a list of header strings 00538 * @param rows a list of lists of rows as strings 00539 * @param padding the amount of padding between columns 00540 * @param totalcols the total number of columns in the header and each row 00541 * @param widths a pointer to store width data 00542 * @param has_data a pointer to store whether column has data 00543 * 00544 * @return the total width of the table; 0 on failure 00545 */ 00546 static size_t table_calc_widths(const alpm_list_t *header, 00547 const alpm_list_t *rows, short padding, size_t totalcols, 00548 size_t **widths, int **has_data) 00549 { 00550 const alpm_list_t *i; 00551 size_t curcol, totalwidth = 0, usefulcols = 0; 00552 size_t *colwidths; 00553 int *coldata; 00554 00555 if(totalcols <= 0) { 00556 return 0; 00557 } 00558 00559 colwidths = malloc(totalcols * sizeof(size_t)); 00560 coldata = calloc(totalcols, sizeof(int)); 00561 if(!colwidths || !coldata) { 00562 return 0; 00563 } 00564 /* header determines column count and initial values of longest_strs */ 00565 for(i = header, curcol = 0; i; i = alpm_list_next(i), curcol++) { 00566 colwidths[curcol] = string_length(i->data); 00567 /* note: header does not determine whether column has data */ 00568 } 00569 00570 /* now find the longest string in each column */ 00571 for(i = rows; i; i = alpm_list_next(i)) { 00572 /* grab first column of each row and iterate through columns */ 00573 const alpm_list_t *j = i->data; 00574 for(curcol = 0; j; j = alpm_list_next(j), curcol++) { 00575 const char *str = j->data; 00576 size_t str_len = string_length(str); 00577 00578 if(str_len > colwidths[curcol]) { 00579 colwidths[curcol] = str_len; 00580 } 00581 if(str_len > 0) { 00582 coldata[curcol] = 1; 00583 } 00584 } 00585 } 00586 00587 for(i = header, curcol = 0; i; i = alpm_list_next(i), curcol++) { 00588 /* only include columns that have data */ 00589 if(coldata[curcol]) { 00590 usefulcols++; 00591 totalwidth += colwidths[curcol]; 00592 } 00593 } 00594 00595 /* add padding between columns */ 00596 if(usefulcols > 0) { 00597 totalwidth += padding * (usefulcols - 1); 00598 } 00599 00600 *widths = colwidths; 00601 *has_data = coldata; 00602 return totalwidth; 00603 } 00604 00605 /** Displays the list in table format 00606 * 00607 * @param title the tables title 00608 * @param header the column headers. column count is determined by the nr 00609 * of headers 00610 * @param rows the rows to display as a list of lists of strings. the outer 00611 * list represents the rows, the inner list the cells (= columns) 00612 * 00613 * @return -1 if not enough terminal cols available, else 0 00614 */ 00615 int table_display(const char *title, const alpm_list_t *header, 00616 const alpm_list_t *rows) 00617 { 00618 const unsigned short padding = 2; 00619 const alpm_list_t *i; 00620 size_t *widths = NULL, totalcols, totalwidth; 00621 int *has_data = NULL; 00622 00623 if(rows == NULL || header == NULL) { 00624 return 0; 00625 } 00626 00627 totalcols = alpm_list_count(header); 00628 totalwidth = table_calc_widths(header, rows, padding, totalcols, 00629 &widths, &has_data); 00630 /* return -1 if terminal is not wide enough */ 00631 if(totalwidth > getcols()) { 00632 pm_printf(ALPM_LOG_WARNING, 00633 _("insufficient columns available for table display\n")); 00634 return -1; 00635 } 00636 if(!totalwidth || !widths || !has_data) { 00637 return -1; 00638 } 00639 00640 if(title != NULL) { 00641 printf("%s\n\n", title); 00642 } 00643 00644 table_print_line(header, padding, totalcols, widths, has_data); 00645 printf("\n"); 00646 00647 for(i = rows; i; i = alpm_list_next(i)) { 00648 table_print_line(i->data, padding, totalcols, widths, has_data); 00649 } 00650 00651 free(widths); 00652 free(has_data); 00653 return 0; 00654 } 00655 00656 void list_display(const char *title, const alpm_list_t *list) 00657 { 00658 const alpm_list_t *i; 00659 size_t len = 0; 00660 00661 if(title) { 00662 len = string_length(title) + 1; 00663 printf("%s ", title); 00664 } 00665 00666 if(!list) { 00667 printf("%s\n", _("None")); 00668 } else { 00669 const unsigned short maxcols = getcols(); 00670 size_t cols = len; 00671 const char *str = list->data; 00672 fputs(str, stdout); 00673 cols += string_length(str); 00674 for(i = alpm_list_next(list); i; i = alpm_list_next(i)) { 00675 str = i->data; 00676 size_t s = string_length(str); 00677 /* wrap only if we have enough usable column space */ 00678 if(maxcols > len && cols + s + 2 >= maxcols) { 00679 size_t j; 00680 cols = len; 00681 printf("\n"); 00682 for(j = 1; j <= len; j++) { 00683 printf(" "); 00684 } 00685 } else if(cols != len) { 00686 /* 2 spaces are added if this is not the first element on a line. */ 00687 printf(" "); 00688 cols += 2; 00689 } 00690 fputs(str, stdout); 00691 cols += s; 00692 } 00693 putchar('\n'); 00694 } 00695 } 00696 00697 void list_display_linebreak(const char *title, const alpm_list_t *list) 00698 { 00699 size_t len = 0; 00700 00701 if(title) { 00702 len = string_length(title) + 1; 00703 printf("%s ", title); 00704 } 00705 00706 if(!list) { 00707 printf("%s\n", _("None")); 00708 } else { 00709 const alpm_list_t *i; 00710 /* Print the first element */ 00711 indentprint((const char *)list->data, len); 00712 printf("\n"); 00713 /* Print the rest */ 00714 for(i = alpm_list_next(list); i; i = alpm_list_next(i)) { 00715 size_t j; 00716 for(j = 1; j <= len; j++) { 00717 printf(" "); 00718 } 00719 indentprint((const char *)i->data, len); 00720 printf("\n"); 00721 } 00722 } 00723 } 00724 00725 void signature_display(const char *title, alpm_siglist_t *siglist) 00726 { 00727 size_t len = 0; 00728 00729 if(title) { 00730 len = string_length(title) + 1; 00731 printf("%s ", title); 00732 } 00733 if(siglist->count == 0) { 00734 printf(_("None")); 00735 } else { 00736 size_t i; 00737 for(i = 0; i < siglist->count; i++) { 00738 char *sigline; 00739 const char *status, *validity, *name; 00740 int ret; 00741 alpm_sigresult_t *result = siglist->results + i; 00742 /* Don't re-indent the first result */ 00743 if(i != 0) { 00744 size_t j; 00745 for(j = 1; j <= len; j++) { 00746 printf(" "); 00747 } 00748 } 00749 switch(result->status) { 00750 case ALPM_SIGSTATUS_VALID: 00751 status = _("Valid"); 00752 break; 00753 case ALPM_SIGSTATUS_KEY_EXPIRED: 00754 status = _("Key expired"); 00755 break; 00756 case ALPM_SIGSTATUS_SIG_EXPIRED: 00757 status = _("Expired"); 00758 break; 00759 case ALPM_SIGSTATUS_INVALID: 00760 status = _("Invalid"); 00761 break; 00762 case ALPM_SIGSTATUS_KEY_UNKNOWN: 00763 status = _("Key unknown"); 00764 break; 00765 case ALPM_SIGSTATUS_KEY_DISABLED: 00766 status = _("Key disabled"); 00767 break; 00768 default: 00769 status = _("Signature error"); 00770 break; 00771 } 00772 switch(result->validity) { 00773 case ALPM_SIGVALIDITY_FULL: 00774 validity = _("full trust"); 00775 break; 00776 case ALPM_SIGVALIDITY_MARGINAL: 00777 validity = _("marginal trust"); 00778 break; 00779 case ALPM_SIGVALIDITY_NEVER: 00780 validity = _("never trust"); 00781 break; 00782 case ALPM_SIGVALIDITY_UNKNOWN: 00783 default: 00784 validity = _("unknown trust"); 00785 break; 00786 } 00787 name = result->key.uid ? result->key.uid : result->key.fingerprint; 00788 ret = pm_asprintf(&sigline, _("%s, %s from \"%s\""), 00789 status, validity, name); 00790 if(ret == -1) { 00791 pm_printf(ALPM_LOG_ERROR, _("failed to allocate string\n")); 00792 continue; 00793 } 00794 indentprint(sigline, len); 00795 printf("\n"); 00796 free(sigline); 00797 } 00798 } 00799 } 00800 00801 /* creates a header row for use with table_display */ 00802 static alpm_list_t *create_verbose_header(int dl_size) 00803 { 00804 alpm_list_t *res = NULL; 00805 char *str; 00806 00807 str = _("Name"); 00808 res = alpm_list_add(res, str); 00809 str = _("Old Version"); 00810 res = alpm_list_add(res, str); 00811 str = _("New Version"); 00812 res = alpm_list_add(res, str); 00813 str = _("Net Change"); 00814 res = alpm_list_add(res, str); 00815 if(dl_size) { 00816 str = _("Download Size"); 00817 res = alpm_list_add(res, str); 00818 } 00819 00820 return res; 00821 } 00822 00823 /* returns package info as list of strings */ 00824 static alpm_list_t *create_verbose_row(pm_target_t *target, int dl_size) 00825 { 00826 char *str; 00827 off_t size = 0; 00828 double human_size; 00829 const char *label; 00830 alpm_list_t *ret = NULL; 00831 00832 /* a row consists of the package name, */ 00833 if(target->install) { 00834 const alpm_db_t *db = alpm_pkg_get_db(target->install); 00835 if(db) { 00836 pm_asprintf(&str, "%s/%s", alpm_db_get_name(db), alpm_pkg_get_name(target->install)); 00837 } else { 00838 pm_asprintf(&str, "%s", alpm_pkg_get_name(target->install)); 00839 } 00840 } else { 00841 pm_asprintf(&str, "%s", alpm_pkg_get_name(target->remove)); 00842 } 00843 ret = alpm_list_add(ret, str); 00844 00845 /* old and new versions */ 00846 pm_asprintf(&str, "%s", 00847 target->remove != NULL ? alpm_pkg_get_version(target->remove) : ""); 00848 ret = alpm_list_add(ret, str); 00849 00850 pm_asprintf(&str, "%s", 00851 target->install != NULL ? alpm_pkg_get_version(target->install) : ""); 00852 ret = alpm_list_add(ret, str); 00853 00854 /* and size */ 00855 size -= target->remove ? alpm_pkg_get_isize(target->remove) : 0; 00856 size += target->install ? alpm_pkg_get_isize(target->install) : 0; 00857 human_size = humanize_size(size, 'M', &label); 00858 pm_asprintf(&str, "%.2f %s", human_size, label); 00859 ret = alpm_list_add(ret, str); 00860 00861 if(dl_size) { 00862 size = target->install ? alpm_pkg_download_size(target->install) : 0; 00863 human_size = humanize_size(size, 'M', &label); 00864 if(size != 0) { 00865 pm_asprintf(&str, "%.2f %s", human_size, label); 00866 } else { 00867 str = strdup(""); 00868 } 00869 ret = alpm_list_add(ret, str); 00870 } 00871 00872 return ret; 00873 } 00874 00875 /* prepare a list of pkgs to display */ 00876 static void _display_targets(alpm_list_t *targets, int verbose) 00877 { 00878 char *str; 00879 const char *label; 00880 double size; 00881 off_t isize = 0, rsize = 0, dlsize = 0; 00882 alpm_list_t *i, *rows = NULL, *names = NULL; 00883 int show_dl_size = config->op == PM_OP_SYNC; 00884 00885 if(!targets) { 00886 return; 00887 } 00888 00889 /* gather package info */ 00890 for(i = targets; i; i = alpm_list_next(i)) { 00891 pm_target_t *target = i->data; 00892 00893 if(target->install) { 00894 dlsize += alpm_pkg_download_size(target->install); 00895 isize += alpm_pkg_get_isize(target->install); 00896 } 00897 if(target->remove) { 00898 /* add up size of all removed packages */ 00899 rsize += alpm_pkg_get_isize(target->remove); 00900 } 00901 00902 /* form data for both verbose and non-verbose display */ 00903 rows = alpm_list_add(rows, create_verbose_row(target, show_dl_size)); 00904 if(target->install) { 00905 pm_asprintf(&str, "%s-%s", alpm_pkg_get_name(target->install), 00906 alpm_pkg_get_version(target->install)); 00907 } else if(isize == 0) { 00908 pm_asprintf(&str, "%s-%s", alpm_pkg_get_name(target->remove), 00909 alpm_pkg_get_version(target->remove)); 00910 } else { 00911 pm_asprintf(&str, "%s-%s [removal]", alpm_pkg_get_name(target->remove), 00912 alpm_pkg_get_version(target->remove)); 00913 } 00914 names = alpm_list_add(names, str); 00915 } 00916 00917 /* print to screen */ 00918 pm_asprintf(&str, _("Targets (%d):"), alpm_list_count(targets)); 00919 00920 printf("\n"); 00921 if(verbose) { 00922 alpm_list_t *header = create_verbose_header(show_dl_size); 00923 if(table_display(str, header, rows) != 0) { 00924 /* fallback to list display if table wouldn't fit */ 00925 list_display(str, names); 00926 } 00927 alpm_list_free(header); 00928 } else { 00929 list_display(str, names); 00930 } 00931 printf("\n"); 00932 00933 /* rows is a list of lists of strings, free inner lists here */ 00934 for(i = rows; i; i = alpm_list_next(i)) { 00935 alpm_list_t *lp = i->data; 00936 FREELIST(lp); 00937 } 00938 alpm_list_free(rows); 00939 FREELIST(names); 00940 free(str); 00941 00942 if(dlsize > 0 || config->op_s_downloadonly) { 00943 size = humanize_size(dlsize, 'M', &label); 00944 printf(_("Total Download Size: %.2f %s\n"), size, label); 00945 } 00946 if(!config->op_s_downloadonly) { 00947 if(isize > 0) { 00948 size = humanize_size(isize, 'M', &label); 00949 printf(_("Total Installed Size: %.2f %s\n"), size, label); 00950 } 00951 if(rsize > 0 && isize == 0) { 00952 size = humanize_size(rsize, 'M', &label); 00953 printf(_("Total Removed Size: %.2f %s\n"), size, label); 00954 } 00955 /* only show this net value if different from raw installed size */ 00956 if(isize > 0 && rsize > 0) { 00957 size = humanize_size(isize - rsize, 'M', &label); 00958 printf(_("Net Upgrade Size: %.2f %s\n"), size, label); 00959 } 00960 } 00961 } 00962 00963 static int target_cmp(const void *p1, const void *p2) 00964 { 00965 const pm_target_t *targ1 = p1; 00966 const pm_target_t *targ2 = p2; 00967 /* explicit are always sorted after implicit (e.g. deps, pulled targets) */ 00968 if(targ1->is_explicit != targ2->is_explicit) { 00969 return targ1->is_explicit > targ2->is_explicit; 00970 } 00971 const char *name1 = targ1->install ? 00972 alpm_pkg_get_name(targ1->install) : alpm_pkg_get_name(targ1->remove); 00973 const char *name2 = targ2->install ? 00974 alpm_pkg_get_name(targ2->install) : alpm_pkg_get_name(targ2->remove); 00975 return strcmp(name1, name2); 00976 } 00977 00978 static int pkg_cmp(const void *p1, const void *p2) 00979 { 00980 /* explicit cast due to (un)necessary removal of const */ 00981 alpm_pkg_t *pkg1 = (alpm_pkg_t *)p1; 00982 alpm_pkg_t *pkg2 = (alpm_pkg_t *)p2; 00983 return strcmp(alpm_pkg_get_name(pkg1), alpm_pkg_get_name(pkg2)); 00984 } 00985 00986 void display_targets(void) 00987 { 00988 alpm_list_t *i, *targets = NULL; 00989 alpm_db_t *db_local = alpm_option_get_localdb(config->handle); 00990 00991 for(i = alpm_trans_get_add(config->handle); i; i = alpm_list_next(i)) { 00992 alpm_pkg_t *pkg = i->data; 00993 pm_target_t *targ = calloc(1, sizeof(pm_target_t)); 00994 if(!targ) return; 00995 targ->install = pkg; 00996 targ->remove = alpm_db_get_pkg(db_local, alpm_pkg_get_name(pkg)); 00997 if(alpm_list_find(config->explicit_adds, pkg, pkg_cmp)) { 00998 targ->is_explicit = 1; 00999 } 01000 targets = alpm_list_add(targets, targ); 01001 } 01002 for(i = alpm_trans_get_remove(config->handle); i; i = alpm_list_next(i)) { 01003 alpm_pkg_t *pkg = i->data; 01004 pm_target_t *targ = calloc(1, sizeof(pm_target_t)); 01005 if(!targ) return; 01006 targ->remove = pkg; 01007 if(alpm_list_find(config->explicit_removes, pkg, pkg_cmp)) { 01008 targ->is_explicit = 1; 01009 } 01010 targets = alpm_list_add(targets, targ); 01011 } 01012 01013 targets = alpm_list_msort(targets, alpm_list_count(targets), target_cmp); 01014 _display_targets(targets, config->verbosepkglists); 01015 FREELIST(targets); 01016 } 01017 01018 static off_t pkg_get_size(alpm_pkg_t *pkg) 01019 { 01020 switch(config->op) { 01021 case PM_OP_SYNC: 01022 return alpm_pkg_download_size(pkg); 01023 case PM_OP_UPGRADE: 01024 return alpm_pkg_get_size(pkg); 01025 default: 01026 return alpm_pkg_get_isize(pkg); 01027 } 01028 } 01029 01030 static char *pkg_get_location(alpm_pkg_t *pkg) 01031 { 01032 alpm_list_t *servers; 01033 char *string = NULL; 01034 switch(config->op) { 01035 case PM_OP_SYNC: 01036 servers = alpm_db_get_servers(alpm_pkg_get_db(pkg)); 01037 if(servers) { 01038 pm_asprintf(&string, "%s/%s", servers->data, 01039 alpm_pkg_get_filename(pkg)); 01040 return string; 01041 } 01042 case PM_OP_UPGRADE: 01043 return strdup(alpm_pkg_get_filename(pkg)); 01044 default: 01045 pm_asprintf(&string, "%s-%s", alpm_pkg_get_name(pkg), alpm_pkg_get_version(pkg)); 01046 return string; 01047 } 01048 } 01049 01050 /** Converts sizes in bytes into human readable units. 01051 * 01052 * @param bytes the size in bytes 01053 * @param target_unit '\0' or a short label. If equal to one of the short unit 01054 * labels ('B', 'K', ...) bytes is converted to target_unit; if '\0', the first 01055 * unit which will bring the value to below a threshold of 2048 will be chosen. 01056 * @param long_labels whether to use short ("K") or long ("KiB") unit labels 01057 * @param label will be set to the appropriate unit label 01058 * 01059 * @return the size in the appropriate unit 01060 */ 01061 double humanize_size(off_t bytes, const char target_unit, const char **label) 01062 { 01063 static const char *labels[] = {"B", "KiB", "MiB", "GiB", 01064 "TiB", "PiB", "EiB", "ZiB", "YiB"}; 01065 static const int unitcount = sizeof(labels) / sizeof(labels[0]); 01066 01067 double val = (double)bytes; 01068 int index; 01069 01070 for(index = 0; index < unitcount - 1; index++) { 01071 if(target_unit != '\0' && labels[index][0] == target_unit) { 01072 break; 01073 } else if(target_unit == '\0' && val <= 2048.0 && val >= -2048.0) { 01074 break; 01075 } 01076 val /= 1024.0; 01077 } 01078 01079 if(label) { 01080 *label = labels[index]; 01081 } 01082 01083 return val; 01084 } 01085 01086 void print_packages(const alpm_list_t *packages) 01087 { 01088 const alpm_list_t *i; 01089 if(!config->print_format) { 01090 config->print_format = strdup("%l"); 01091 } 01092 for(i = packages; i; i = alpm_list_next(i)) { 01093 alpm_pkg_t *pkg = i->data; 01094 char *string = strdup(config->print_format); 01095 char *temp = string; 01096 /* %n : pkgname */ 01097 if(strstr(temp, "%n")) { 01098 string = strreplace(temp, "%n", alpm_pkg_get_name(pkg)); 01099 free(temp); 01100 temp = string; 01101 } 01102 /* %v : pkgver */ 01103 if(strstr(temp, "%v")) { 01104 string = strreplace(temp, "%v", alpm_pkg_get_version(pkg)); 01105 free(temp); 01106 temp = string; 01107 } 01108 /* %l : location */ 01109 if(strstr(temp, "%l")) { 01110 char *pkgloc = pkg_get_location(pkg); 01111 string = strreplace(temp, "%l", pkgloc); 01112 free(pkgloc); 01113 free(temp); 01114 temp = string; 01115 } 01116 /* %r : repo */ 01117 if(strstr(temp, "%r")) { 01118 const char *repo = "local"; 01119 alpm_db_t *db = alpm_pkg_get_db(pkg); 01120 if(db) { 01121 repo = alpm_db_get_name(db); 01122 } 01123 string = strreplace(temp, "%r", repo); 01124 free(temp); 01125 temp = string; 01126 } 01127 /* %s : size */ 01128 if(strstr(temp, "%s")) { 01129 char *size; 01130 pm_asprintf(&size, "%jd", (intmax_t)pkg_get_size(pkg)); 01131 string = strreplace(temp, "%s", size); 01132 free(size); 01133 free(temp); 01134 } 01135 printf("%s\n",string); 01136 free(string); 01137 } 01138 } 01139 01140 /* Helper function for comparing strings using the 01141 * alpm "compare func" signature */ 01142 int str_cmp(const void *s1, const void *s2) 01143 { 01144 return strcmp(s1, s2); 01145 } 01146 01147 void display_new_optdepends(alpm_pkg_t *oldpkg, alpm_pkg_t *newpkg) 01148 { 01149 alpm_list_t *old = alpm_pkg_get_optdepends(oldpkg); 01150 alpm_list_t *new = alpm_pkg_get_optdepends(newpkg); 01151 alpm_list_t *optdeps = alpm_list_diff(new,old,str_cmp); 01152 if(optdeps) { 01153 printf(_("New optional dependencies for %s\n"), alpm_pkg_get_name(newpkg)); 01154 list_display_linebreak(" ", optdeps); 01155 } 01156 alpm_list_free(optdeps); 01157 } 01158 01159 void display_optdepends(alpm_pkg_t *pkg) 01160 { 01161 alpm_list_t *optdeps = alpm_pkg_get_optdepends(pkg); 01162 if(optdeps) { 01163 printf(_("Optional dependencies for %s\n"), alpm_pkg_get_name(pkg)); 01164 list_display_linebreak(" ", optdeps); 01165 } 01166 } 01167 01168 static void display_repo_list(const char *dbname, alpm_list_t *list) 01169 { 01170 const char *prefix= " "; 01171 01172 printf(":: "); 01173 printf(_("Repository %s\n"), dbname); 01174 list_display(prefix, list); 01175 } 01176 01177 void select_display(const alpm_list_t *pkglist) 01178 { 01179 const alpm_list_t *i; 01180 int nth = 1; 01181 alpm_list_t *list = NULL; 01182 char *string = NULL; 01183 const char *dbname = NULL; 01184 01185 for(i = pkglist; i; i = i->next) { 01186 alpm_pkg_t *pkg = i->data; 01187 alpm_db_t *db = alpm_pkg_get_db(pkg); 01188 01189 if(!dbname) 01190 dbname = alpm_db_get_name(db); 01191 if(strcmp(alpm_db_get_name(db), dbname) != 0) { 01192 display_repo_list(dbname, list); 01193 FREELIST(list); 01194 dbname = alpm_db_get_name(db); 01195 } 01196 string = NULL; 01197 pm_asprintf(&string, "%d) %s", nth, alpm_pkg_get_name(pkg)); 01198 list = alpm_list_add(list, string); 01199 nth++; 01200 } 01201 display_repo_list(dbname, list); 01202 FREELIST(list); 01203 } 01204 01205 static int parseindex(char *s, int *val, int min, int max) 01206 { 01207 char *endptr = NULL; 01208 int n = strtol(s, &endptr, 10); 01209 if(*endptr == '\0') { 01210 if(n < min || n > max) { 01211 pm_printf(ALPM_LOG_ERROR, 01212 _("invalid value: %d is not between %d and %d\n"), 01213 n, min, max); 01214 return -1; 01215 } 01216 *val = n; 01217 return 0; 01218 } else { 01219 pm_printf(ALPM_LOG_ERROR, _("invalid number: %s\n"), s); 01220 return -1; 01221 } 01222 } 01223 01224 static int multiselect_parse(char *array, int count, char *response) 01225 { 01226 char *str, *saveptr; 01227 01228 for(str = response; ; str = NULL) { 01229 int include = 1; 01230 int start, end; 01231 size_t len; 01232 char *ends = NULL; 01233 char *starts = strtok_r(str, " ", &saveptr); 01234 01235 if(starts == NULL) { 01236 break; 01237 } 01238 len = strtrim(starts); 01239 if(len == 0) 01240 continue; 01241 01242 if(*starts == '^') { 01243 starts++; 01244 len--; 01245 include = 0; 01246 } else if(str) { 01247 /* if first token is including, we unselect all targets */ 01248 memset(array, 0, count); 01249 } 01250 01251 if(len > 1) { 01252 /* check for range */ 01253 char *p; 01254 if((p = strchr(starts + 1, '-'))) { 01255 *p = 0; 01256 ends = p + 1; 01257 } 01258 } 01259 01260 if(parseindex(starts, &start, 1, count) != 0) 01261 return -1; 01262 01263 if(!ends) { 01264 array[start-1] = include; 01265 } else { 01266 int d; 01267 if(parseindex(ends, &end, start, count) != 0) { 01268 return -1; 01269 } 01270 for(d = start; d <= end; d++) { 01271 array[d-1] = include; 01272 } 01273 } 01274 } 01275 01276 return 0; 01277 } 01278 01279 int multiselect_question(char *array, int count) 01280 { 01281 char *response, *lastchar; 01282 FILE *stream; 01283 size_t response_len = 64; 01284 01285 if(config->noconfirm) { 01286 stream = stdout; 01287 } else { 01288 /* Use stderr so questions are always displayed when redirecting output */ 01289 stream = stderr; 01290 } 01291 01292 response = malloc(response_len); 01293 if(!response) { 01294 return -1; 01295 } 01296 lastchar = response + response_len - 1; 01297 /* sentinel byte to later see if we filled up the entire string */ 01298 *lastchar = 1; 01299 01300 while(1) { 01301 memset(array, 1, count); 01302 01303 fprintf(stream, "\n"); 01304 fprintf(stream, _("Enter a selection (default=all)")); 01305 fprintf(stream, ": "); 01306 fflush(stream); 01307 01308 if(config->noconfirm) { 01309 fprintf(stream, "\n"); 01310 break; 01311 } 01312 01313 flush_term_input(); 01314 01315 if(fgets(response, response_len, stdin)) { 01316 const size_t response_incr = 64; 01317 size_t len; 01318 /* handle buffer not being large enough to read full line case */ 01319 while(*lastchar == '\0' && lastchar[-1] != '\n') { 01320 response_len += response_incr; 01321 response = realloc(response, response_len); 01322 if(!response) { 01323 return -1; 01324 } 01325 lastchar = response + response_len - 1; 01326 /* sentinel byte */ 01327 *lastchar = 1; 01328 if(fgets(response + response_len - response_incr - 1, 01329 response_incr + 1, stdin) == 0) { 01330 free(response); 01331 return -1; 01332 } 01333 } 01334 01335 len = strtrim(response); 01336 if(len > 0) { 01337 if(multiselect_parse(array, count, response) == -1) { 01338 /* only loop if user gave an invalid answer */ 01339 continue; 01340 } 01341 } 01342 break; 01343 } else { 01344 free(response); 01345 return -1; 01346 } 01347 } 01348 01349 free(response); 01350 return 0; 01351 } 01352 01353 int select_question(int count) 01354 { 01355 char response[32]; 01356 FILE *stream; 01357 int preset = 1; 01358 01359 if(config->noconfirm) { 01360 stream = stdout; 01361 } else { 01362 /* Use stderr so questions are always displayed when redirecting output */ 01363 stream = stderr; 01364 } 01365 01366 while(1) { 01367 fprintf(stream, "\n"); 01368 fprintf(stream, _("Enter a number (default=%d)"), preset); 01369 fprintf(stream, ": "); 01370 01371 if(config->noconfirm) { 01372 fprintf(stream, "\n"); 01373 break; 01374 } 01375 01376 flush_term_input(); 01377 01378 if(fgets(response, sizeof(response), stdin)) { 01379 size_t len = strtrim(response); 01380 if(len > 0) { 01381 int n; 01382 if(parseindex(response, &n, 1, count) != 0) 01383 continue; 01384 return (n - 1); 01385 } 01386 } 01387 break; 01388 } 01389 01390 return (preset - 1); 01391 } 01392 01393 01394 /* presents a prompt and gets a Y/N answer */ 01395 static int question(short preset, char *fmt, va_list args) 01396 { 01397 char response[32]; 01398 FILE *stream; 01399 01400 if(config->noconfirm) { 01401 stream = stdout; 01402 } else { 01403 /* Use stderr so questions are always displayed when redirecting output */ 01404 stream = stderr; 01405 } 01406 01407 /* ensure all text makes it to the screen before we prompt the user */ 01408 fflush(stdout); 01409 fflush(stderr); 01410 01411 vfprintf(stream, fmt, args); 01412 01413 if(preset) { 01414 fprintf(stream, " %s ", _("[Y/n]")); 01415 } else { 01416 fprintf(stream, " %s ", _("[y/N]")); 01417 } 01418 01419 if(config->noconfirm) { 01420 fprintf(stream, "\n"); 01421 return preset; 01422 } 01423 01424 fflush(stream); 01425 flush_term_input(); 01426 01427 if(fgets(response, sizeof(response), stdin)) { 01428 size_t len = strtrim(response); 01429 if(len == 0) { 01430 return preset; 01431 } 01432 01433 if(strcasecmp(response, _("Y")) == 0 || strcasecmp(response, _("YES")) == 0) { 01434 return 1; 01435 } else if(strcasecmp(response, _("N")) == 0 || strcasecmp(response, _("NO")) == 0) { 01436 return 0; 01437 } 01438 } 01439 return 0; 01440 } 01441 01442 int yesno(char *fmt, ...) 01443 { 01444 int ret; 01445 va_list args; 01446 01447 va_start(args, fmt); 01448 ret = question(1, fmt, args); 01449 va_end(args); 01450 01451 return ret; 01452 } 01453 01454 int noyes(char *fmt, ...) 01455 { 01456 int ret; 01457 va_list args; 01458 01459 va_start(args, fmt); 01460 ret = question(0, fmt, args); 01461 va_end(args); 01462 01463 return ret; 01464 } 01465 01466 int pm_printf(alpm_loglevel_t level, const char *format, ...) 01467 { 01468 int ret; 01469 va_list args; 01470 01471 /* print the message using va_arg list */ 01472 va_start(args, format); 01473 ret = pm_vfprintf(stderr, level, format, args); 01474 va_end(args); 01475 01476 return ret; 01477 } 01478 01479 int pm_asprintf(char **string, const char *format, ...) 01480 { 01481 int ret = 0; 01482 va_list args; 01483 01484 /* print the message using va_arg list */ 01485 va_start(args, format); 01486 if(vasprintf(string, format, args) == -1) { 01487 pm_printf(ALPM_LOG_ERROR, _("failed to allocate string\n")); 01488 ret = -1; 01489 } 01490 va_end(args); 01491 01492 return ret; 01493 } 01494 01495 int pm_vasprintf(char **string, alpm_loglevel_t level, const char *format, va_list args) 01496 { 01497 int ret = 0; 01498 char *msg = NULL; 01499 01500 /* if current logmask does not overlap with level, do not print msg */ 01501 if(!(config->logmask & level)) { 01502 return ret; 01503 } 01504 01505 /* print the message using va_arg list */ 01506 ret = vasprintf(&msg, format, args); 01507 01508 /* print a prefix to the message */ 01509 switch(level) { 01510 case ALPM_LOG_ERROR: 01511 pm_asprintf(string, _("error: %s"), msg); 01512 break; 01513 case ALPM_LOG_WARNING: 01514 pm_asprintf(string, _("warning: %s"), msg); 01515 break; 01516 case ALPM_LOG_DEBUG: 01517 pm_asprintf(string, "debug: %s", msg); 01518 break; 01519 case ALPM_LOG_FUNCTION: 01520 pm_asprintf(string, "function: %s", msg); 01521 break; 01522 default: 01523 pm_asprintf(string, "%s", msg); 01524 break; 01525 } 01526 free(msg); 01527 01528 return ret; 01529 } 01530 01531 int pm_vfprintf(FILE *stream, alpm_loglevel_t level, const char *format, va_list args) 01532 { 01533 int ret = 0; 01534 01535 /* if current logmask does not overlap with level, do not print msg */ 01536 if(!(config->logmask & level)) { 01537 return ret; 01538 } 01539 01540 #if defined(PACMAN_DEBUG) 01541 /* If debug is on, we'll timestamp the output */ 01542 if(config->logmask & ALPM_LOG_DEBUG) { 01543 time_t t; 01544 struct tm *tmp; 01545 char timestr[10] = {0}; 01546 01547 t = time(NULL); 01548 tmp = localtime(&t); 01549 strftime(timestr, 9, "%H:%M:%S", tmp); 01550 timestr[8] = '\0'; 01551 01552 fprintf(stream, "[%s] ", timestr); 01553 } 01554 #endif 01555 01556 /* print a prefix to the message */ 01557 switch(level) { 01558 case ALPM_LOG_ERROR: 01559 fprintf(stream, _("error: ")); 01560 break; 01561 case ALPM_LOG_WARNING: 01562 fprintf(stream, _("warning: ")); 01563 break; 01564 case ALPM_LOG_DEBUG: 01565 fprintf(stream, "debug: "); 01566 break; 01567 case ALPM_LOG_FUNCTION: 01568 fprintf(stream, "function: "); 01569 break; 01570 default: 01571 break; 01572 } 01573 01574 /* print the message using va_arg list */ 01575 ret = vfprintf(stream, format, args); 01576 return ret; 01577 } 01578 01579 #ifndef HAVE_STRNDUP 01580 /* A quick and dirty implementation derived from glibc */ 01581 static size_t strnlen(const char *s, size_t max) 01582 { 01583 register const char *p; 01584 for(p = s; *p && max--; ++p); 01585 return (p - s); 01586 } 01587 01588 char *strndup(const char *s, size_t n) 01589 { 01590 size_t len = strnlen(s, n); 01591 char *new = (char *) malloc(len + 1); 01592 01593 if(new == NULL) 01594 return NULL; 01595 01596 new[len] = '\0'; 01597 return (char *)memcpy(new, s, len); 01598 } 01599 #endif 01600 01601 /* vim: set ts=2 sw=2 noet: */