about summary refs log blame commit diff stats
path: root/CHANGELOG.md
blob: cf232972d98783973650c65f0423427cddb21270 (plain) (tree)
1
2
3
4
5
6
7
8
9

                                                   






                                                                         
                                                                           




                                                                              
 


































































































































































































































































                                                                               
This log documents changes between stable versions.

# 2015-10-04: version 1.7.2
* Fixed file name arguments passed to `sxiv` and `feh` when using `:flat`
* Fixed removal of empty directories when using `:rename`
* Fixed free disk space display on Mac OS X
* Fixed `examples/vim_file_chooser` to work with gvim too
* Fixed some other rare crashes and bugs
* Fixed downward mouse wheel scrolling
* Fixed warning about regex splits being drawn in title bar since python3.5
* Really fixed `S` key binding not working when SHELL=fish
* Improved `doc/cheatsheet.svg`
* Added some entries to rifle.conf
* Added key bindings `pO` and `pP` which work like `po` and `pp` but queue the
  operation in a first-in-first-out order.

# 2015-05-04: version 1.7.1
* Added `doc/cheatsheet.svg`
* Added `examples/rc_emacs.conf`, a config file adding emacs-like key bindings
* Added `env` keyword in rifle.conf
* Fixed `:bulkrename` command in python3
* Fixed `S` key binding not working when SHELL=fish

# 2015-04-13: version 1.7.0
* The default editor is now `vim` instead of `nano`
* Added automatic updates of tags when a file is renamed from within ranger
* Added `preview_images_method` which can be set to `iterm2` to use native
  iTerm2 image previews
* Added `:rename_append` command to rename files without the file extension
* Added `:linemode` command to change the way the files are displayed
  Try this out by pressing M followed by one of the suggested keys.
  New linemodes can be added with `ranger.api.register_linemode()`.
* Added `:filter_inode_type` command to only show directories, files or links
* Added `:meta` command for managing custom file metadata
* Added `:flat` command for displaying subdirectories
* Added `solarized` colorscheme
* Added generic ability to use scope.sh for image previews
* Added video previews in scope.sh
* Added option `sort_unicode` to sort according to unicode, not ASCII
* `:mkdir` can now create multiple directory levels (like `mkdir -p`)
* `:help` (key binding `?`) is now interactive
* `:find` (key binding `/`) is now case insensitive by default
* `ranger --copy-config=all` now copies a short sample commands.py rather than
  the full one, so that you can update ranger without having broken commands.
  The full commands.py is still copied to `~/.config/ranger/commands_full.py`.
* Fixed broken copying of symlinks

# 2013-05-24: Version 1.6.1
* Added support for version control systems, see:
  http://lists.nongnu.org/archive/html/ranger-users/2013-03/msg00007.html
* Added :scout command as a unified backend to :find, :search, etc
* Added `open_all_images` setting to remove the need for external scripts
  to handle opening of all images in a directory at once.
* Now previewing with `i` uses the whole available width.

# 2013-02-22: Version 1.6.0
* Overhauled all config files.  Please update them or use the --clean switch
* Added `examples/` directory to source code which contains sample programs or
  plugins that can be used together with ranger
* Added progress bars to copying, moving and directory loading processes
* Added feature to draw images inside the console using w3mimgdisplay (you need
  to add `set preview_images true` in rc.conf)
* Added a plugin system like in the program `anki`, i.e. place any python file
  into ~/.config/ranger/plugins/ and it will be imported by ranger
* Added a separate file launcher named `rifle` that is configured through
  rifle.conf and is installed as a standalone program.
  Using `ranger [filename]` from the shell for opening files is deprecated now,
  please use `rifle [filename]` instead.
* Added `uq` keybinding to undo closed tabs
* Added :setlocal command to change settings for specific directories only
* Added :travel command to move more quickly to your destination
* Added 256 color support for scope.sh
* Added a real yes/no prompt for :delete command
* Added settings: `confirm_on_delete`, `draw_progress_bar_in_status_bar`,
  `preview_images`, `status_bar_on_top`, `update_tmux_title`
* Added commands: `:mark_tag`, `:unmark_tag`
* Added BSD-friendly setsid implementation
* Added as-you-type filtering for `:filter` command
* Replaced `options.py` file by :set commands in rc.conf
* Replaced `apps.py` file with rifle.conf
* Improved `r` key to interface with rifle
* Rewritten `scope.sh` in POSIX shell
* Changed copying/moving code to work without GNU coreutils
* Changed key to untag files from `T` to `ut`
* Changed the flag `d` (for detached) to `f` (for fork) in program launcher
* Changed appearance of keybinding-hints and bookmarks
* Changed tabs with 4 spaces in the source code (see PEP 8)
* Removed ranger.core.environment class
* Removed settings: `colorscheme_overlay`, `draw_bookmark_borders`,
  `init_function`, `load_default_rc`
* Fixed zombie process apocalypse
* Fixed `draw_borders=true` in combination with `padding_right=false`

# 2012-08-10: Version 1.5.5
* Ensure that detached programs continue to run when ranger is killed

# 2012-05-03: Version 1.5.4
* Added exiftool to scope.sh by default
* Fixed a crash when entering a directory with a unicode name
* Speedup in `ranger.ext.get_executables`

# 2012-03-05: Version 1.5.3
* Added --selectfile option that selects a certain file on startup
* Added --list-tagged-files option
* Added --cmd option to run commands on startup
* Added --profile option for additional debug information on exit
* Added a visual mode (activate with `V`, deactivate with Esc)
* Added a reversed visual mode (activate with `uV`)
* Added `$RANGER_LEVEL` environment variable which ranger sets to `1` or higher
  so programs can know that they were spawned from ranger
* Added run flag `r` for running with root privileges (needs sudo)
* Added run flag `t` for running in a new terminal (as specified in $TERMCMD)
* Added :relink command to change destinations of symlinks
* Added `dc` binding for getting the cumulative size of a directory
* Added `autoupdate_cumulative_size` option
* Added `pht` binding to Paste Hardlinked subTrees (like cp -l)
* Improved sorting speed of signals (noticable when caching many directories)
* Improved drawing speed
* Fixed unexpected behavior when displaying nonprintable characters
* Fixed :bulkrename to work with files starting with a minus sign
* Fixed RangerChooser example in man page
* Fixed crash when opening images with sxiv/feh by running `ranger <image>`

# 2011-10-23: Version 1.5.2
* Fixed graphical bug that appears in certian cases when drawing
  characters at the right edge.

# 2011-10-23: Version 1.5.1
* Added `fm.select_file(path)`
* Added --choosefiles option (like --choosefile, but chooses multiple files)
* Fixed --list-unused-keys
* Fixed Zombie processes
* Fixed handling of filenames with undecodable bytes (unicode surrogates)
* Fixed crashes due to incomplete loading of directories
* Fixed tab completion of the command `shell`
* Fixed `ot` and `oT` keys in rc.conf
* Fixed parsing of chained commands (like in the binding `om`)

# 2011-10-11: Version 1.5.0
* Full python3.2 compatibility
* Added new configuration file `rc.conf` which contains a list
  of commands that are executed on startup - mainly used for keybindings
* Added --list-unused-keys
* Added new program handlers to apps.py
* Added pop-up window for keychains and bookmarks
* Added `load_default_rc` option
* Fixed all known unicode issues
* Fixed crash when $TERM is unknown to the system
* Fixed scrolling in colored preview
* Changed the default `column_ratios` to 1/3/4 and sorting method to `natural`
* Changed :rename so it doesn't overwrite existing files
* Internal actions are now accessible as commands
* Replaced unittests by doctests
* Replaced integrated help with an extended man page and dynamic lists
  of keybindings, commands and settings.
* Removed `keys.py` configuration file in favor of `rc.conf`
* Removed `texas` colorscheme
* apps.py: Now able to define programs that only run with Xorg
* commands.py: Using parse(self.line) to parse the line is unnecessary now.
  parse(self.line).rest(n) is now written as self.rest(n).
  However, parse(self.line).chunk(n) has been renamed to self.arg(n).
* commands.py: parse(self.line) + X is now self.firstpart + X
* commands.py: New special attribute `resolve_macros` which decides whether
  strings like %f should be expanded to the name of the current file, etc.
* commands.py: New special attribute `escape_macros_for_shell` to toggle
  whether or not macros should be escaped, so you can use them in other
  commands than :shell, for example :edit %f
* Countless small fixes and improvements

# 2011-10-02: Version 1.4.4
* Added keys for chmod (like +ow for `chmod o+w`, etc)
* Added `c` flag for running files
* Added various key bindings
* Added wavpack and webm types to mime.types
* Added option `display_tags_in_all_columns`
* Added command.cancel method which is called when pressing ESC in console
* Added sorting and cycling by ctime and atime
* Added custom tags (press "x)
* Added bittorrent preview
* Fixed blocking when using interactive scripts in scope.sh
* Fixed issues with ALT key
* Fixed pager crash when trying to read non-readable file
* Forbid piping things into ranger
* Improved hints

# 2011-04-05: Version 1.4.3
* Fixed mimetype checking when invoking ranger with a filename
* Fixed loss of bookmarks when disk is full
* Minor improvements

# 2011-03-05: Version 1.4.2
* Added --choosefile and --choosedir flag
* Added use of bookmarks in tab completion of the :cd command
* Fixed bug with detached programs and python 3.2

# 2011-01-04: Version 1.4.1
* Fixed crash when preview failed under some circumstances
* Fixed graphical bug when pressing i

# 2010-12-22: Version 1.4.0
* Added option to use any external scripts for previews (see scope.sh)
* Added key: zv to toggle the use of the external script
* Added indicator for the used filter (type `zf`)
* Added option `padding_right` to remove whitespace if theres no preview
* Added command `:search_inc` for incremental search
* Added commands `:save_copy_buffer` and `:load_copy_buffer` to share
  the copied files between ranger instances
* Added mimeopen as a fallback if no useful application can be found
* Added natural sort, sorts 1foo before 10foo. (type `on`)
* Added keys: yp, yd and yb to copy path, dirname or basename to seleciton
* Let `open_with` use the selection, not just one file
* Run files with right mouse click
* Implemented copying via coreutils rather than internal python code
* Improved handling of unicode
* Some restructuration of the source code

# 2010-12-13: Version 1.2.3
* Enable binding to alt-keys
* Fixed memory leak in garbage collecting of old, unused directory objects
* Fixed python3 incompatibilities
* Fixed problems with identifying changes of files
* Fixed lazy lookup of some FSObject attributes

# 2010-10-10: Version 1.2.2
* Prevent currently used directories from being garbage collected
* Disable mouse buttons when console is open
* Fixed :cd command: Without arguments, cd's into $HOME
* Fixed bug which prevented pydoc to work on some config files
* Fixed some bugs in `snow` and `jungle` colorschemes
* Several other clean-ups and fixes

# 2010-09-16: Version 1.2.1
* Fixed yy/pp bug when yanking multiple directories

# 2010-09-13: Version 1.2.0
* !!! Changed the default configuration directory to ~/.config/ranger !!!
* Removed `Console Modes`, each old mode is now a simple command
* Disabled file previews by default if ranger is used by root
* Allow to jump to specific help sections by typing two numbers, e.g. 13?
* Added keys: da, dr, ya, yr for adding and removing files from copy buffer
* Added keys: gl and gL to resolve links, see 11?
* Added key: pL to create a relative symlink
* Added %<LETTER> and %<N><LETTER> macros for the console, see 33?
* Fixed ansi codes for colors in the pager
* Use the file ~/.mime.types for mime type detection
* Several clean-ups and fixes

# 2010-07-17: Version 1.1.2
* Fix crash when using scrollwheel to scroll down in some cases
* The command `ranger dir1 dir2 ...` opens multiple directories in tabs
* Removed pydoc html documentation by default, re-create it with `make doc`
* Minor fixes

# 2010-06-18: Version 1.1.1
* New install script, `setup.py`
* New flag for running programs: `w` (waits for enter press)
* Minor fixes

# 2010-06-09: Version 1.1.0
* Added a man page
* Tab support
* Improved directory loading performance
* Commands are definable in ~/.ranger/commands.py
* Case insensitive sorting (type zs)
* Better UTF support
* Possibility to turn off previews (zp and zP)
* Changing options with :set (e.g. `:set column_ratios=1,2,3,4`)
* Ask for confirmation when using :delete
* New invocation flag: --fail-unless-cd
* New hotkeys, commands, options.
* New syntax for ~/.ranger/keys.py
* Several user contributions
* And tons of general improvements

NOTE: The syntax for configuration is still subject to change.
/span>; return(dlen + (s - src)); /* count does not include NUL */ } /* --------------------------------------------------------------------------- */ /* $NetBSD: fgetln.c,v 1.3 2007/08/07 02:06:58 lukem Exp $ */ /*- * Copyright (c) 1998 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Christos Zoulas. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of The NetBSD Foundation nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ char * fgetln(fp, len) FILE *fp; size_t *len; { static char *buf = NULL; static size_t bufsiz = 0; char *ptr; if (buf == NULL) { bufsiz = BUFSIZ; if ((buf = malloc(bufsiz)) == NULL) return NULL; } if (fgets(buf, bufsiz, fp) == NULL) return NULL; *len = 0; while ((ptr = strchr(&buf[*len], '\n')) == NULL) { size_t nbufsiz = bufsiz + BUFSIZ; char *nbuf = realloc(buf, nbufsiz); if (nbuf == NULL) { int oerrno = errno; free(buf); errno = oerrno; buf = NULL; return NULL; } else buf = nbuf; *len = bufsiz; if (fgets(&buf[bufsiz], BUFSIZ, fp) == NULL) return buf; bufsiz = nbufsiz; } *len = (ptr - buf) + 1; return buf; } /* --------------------------------------------------------------------------- */ /* $OpenBSD: fparseln.c,v 1.6 2005/08/02 21:46:23 espie Exp $ */ /* $NetBSD: fparseln.c,v 1.7 1999/07/02 15:49:12 simonb Exp $ */ /* * Copyright (c) 1997 Christos Zoulas. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Christos Zoulas. * 4. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define FPARSELN_UNESCESC 0x01 #define FPARSELN_UNESCCONT 0x02 #define FPARSELN_UNESCCOMM 0x04 #define FPARSELN_UNESCREST 0x08 #define FPARSELN_UNESCALL 0x0f static int isescaped(const char *, const char *, int); /* isescaped(): * Return true if the character in *p that belongs to a string * that starts in *sp, is escaped by the escape character esc. */ static int isescaped(const char *sp, const char *p, int esc) { const char *cp; size_t ne; /* No escape character */ if (esc == '\0') return 1; /* Count the number of escape characters that precede ours */ for (ne = 0, cp = p; --cp >= sp && *cp == esc; ne++) continue; /* Return true if odd number of escape characters */ return (ne & 1) != 0; } /* fparseln(): * Read a line from a file parsing continuations ending in \ * and eliminating trailing newlines, or comments starting with * the comment char. */ char * fparseln(FILE *fp, size_t *size, size_t *lineno, const char str[3], int flags) { static const char dstr[3] = { '\\', '\\', '#' }; char *buf = NULL, *ptr, *cp, esc, con, nl, com; size_t s, len = 0; int cnt = 1; if (str == NULL) str = dstr; esc = str[0]; con = str[1]; com = str[2]; /* * XXX: it would be cool to be able to specify the newline character, * but unfortunately, fgetln does not let us */ nl = '\n'; while (cnt) { cnt = 0; if (lineno) (*lineno)++; if ((ptr = fgetln(fp, &s)) == NULL) break; if (s && com) { /* Check and eliminate comments */ for (cp = ptr; cp < ptr + s; cp++) if (*cp == com && !isescaped(ptr, cp, esc)) { s = cp - ptr; cnt = s == 0 && buf == NULL; break; } } if (s && nl) { /* Check and eliminate newlines */ cp = &ptr[s - 1]; if (*cp == nl) s--; /* forget newline */ } if (s && con) { /* Check and eliminate continuations */ cp = &ptr[s - 1]; if (*cp == con && !isescaped(ptr, cp, esc)) { s--; /* forget escape */ cnt = 1; } } if (s == 0 && buf != NULL) continue; if ((cp = realloc(buf, len + s + 1)) == NULL) { free(buf); return NULL; } buf = cp; (void) memcpy(buf + len, ptr, s); len += s; buf[len] = '\0'; } if ((flags & FPARSELN_UNESCALL) != 0 && esc && buf != NULL && strchr(buf, esc) != NULL) { ptr = cp = buf; while (cp[0] != '\0') { int skipesc; while (cp[0] != '\0' && cp[0] != esc) *ptr++ = *cp++; if (cp[0] == '\0' || cp[1] == '\0') break; skipesc = 0; if (cp[1] == com) skipesc += (flags & FPARSELN_UNESCCOMM); if (cp[1] == con) skipesc += (flags & FPARSELN_UNESCCONT); if (cp[1] == esc) skipesc += (flags & FPARSELN_UNESCESC); if (cp[1] != com && cp[1] != con && cp[1] != esc) skipesc = (flags & FPARSELN_UNESCREST); if (skipesc) cp++; else *ptr++ = *cp++; *ptr++ = *cp++; } *ptr = '\0'; len = strlen(buf); } if (size) *size = len; return buf; } /* --------------------------------------------------------------------------- */ /* $OpenBSD: strtonum.c,v 1.6 2004/08/03 19:38:01 millert Exp $ */ /* * Copyright (c) 2004 Ted Unangst and Todd Miller * All rights reserved. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #define INVALID 1 #define TOOSMALL 2 #define TOOLARGE 3 long long strtonum(const char *numstr, long long minval, long long maxval, const char **errstrp) { long long ll = 0; char *ep; int error = 0; struct errval { const char *errstr; int err; } ev[4] = { { NULL, 0 }, { "invalid", EINVAL }, { "too small", ERANGE }, { "too large", ERANGE }, }; ev[0].err = errno; errno = 0; if (minval > maxval) error = INVALID; else { ll = strtoll(numstr, &ep, 10); if (numstr == ep || *ep != '\0') error = INVALID; else if ((ll == LLONG_MIN && errno == ERANGE) || ll < minval) error = TOOSMALL; else if ((ll == LLONG_MAX && errno == ERANGE) || ll > maxval) error = TOOLARGE; } if (errstrp != NULL) *errstrp = ev[error].errstr; errno = ev[error].err; if (error) ll = 0; return (ll); } /* $OpenBSD: fmt_scaled.c,v 1.10 2009/06/20 15:00:04 martynas Exp $ */ /* * Copyright (c) 2001, 2002, 2003 Ian F. Darwin. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * fmt_scaled: Format numbers scaled for human comprehension * scan_scaled: Scan numbers in this format. * * "Human-readable" output uses 4 digits max, and puts a unit suffix at * the end. Makes output compact and easy-to-read esp. on huge disks. * Formatting code was originally in OpenBSD "df", converted to library routine. * Scanning code written for OpenBSD libutil. */ #include <stdio.h> #include <stdlib.h> #include <errno.h> #include <string.h> #include <ctype.h> #include <limits.h> #include "util.h" typedef enum { NONE = 0, KILO = 1, MEGA = 2, GIGA = 3, TERA = 4, PETA = 5, EXA = 6 } unit_type; /* These three arrays MUST be in sync! XXX make a struct */ static unit_type units[] = { NONE, KILO, MEGA, GIGA, TERA, PETA, EXA }; static char scale_chars[] = "BKMGTPE"; static long long scale_factors[] = { 1LL, 1024LL, 1024LL*1024, 1024LL*1024*1024, 1024LL*1024*1024*1024, 1024LL*1024*1024*1024*1024, 1024LL*1024*1024*1024*1024*1024, }; #define SCALE_LENGTH (sizeof(units)/sizeof(units[0])) #define MAX_DIGITS (SCALE_LENGTH * 3) /* XXX strlen(sprintf("%lld", -1)? */ /* Convert the given input string "scaled" into numeric in "result". * Return 0 on success, -1 and errno set on error. */ int scan_scaled(char *scaled, long long *result) { char *p = scaled; int sign = 0; unsigned int i, ndigits = 0, fract_digits = 0; long long scale_fact = 1, whole = 0, fpart = 0; /* Skip leading whitespace */ while (isascii(*p) && isspace(*p)) ++p; /* Then at most one leading + or - */ while (*p == '-' || *p == '+') { if (*p == '-') { if (sign) { errno = EINVAL; return -1; } sign = -1; ++p; } else if (*p == '+') { if (sign) { errno = EINVAL; return -1; } sign = +1; ++p; } } /* Main loop: Scan digits, find decimal point, if present. * We don't allow exponentials, so no scientific notation * (but note that E for Exa might look like e to some!). * Advance 'p' to end, to get scale factor. */ for (; isascii(*p) && (isdigit(*p) || *p=='.'); ++p) { if (*p == '.') { if (fract_digits > 0) { /* oops, more than one '.' */ errno = EINVAL; return -1; } fract_digits = 1; continue; } i = (*p) - '0'; /* whew! finally a digit we can use */ if (fract_digits > 0) { if (fract_digits >= MAX_DIGITS-1) /* ignore extra fractional digits */ continue; fract_digits++; /* for later scaling */ fpart *= 10; fpart += i; } else { /* normal digit */ if (++ndigits >= MAX_DIGITS) { errno = ERANGE; return -1; } whole *= 10; whole += i; } } if (sign) { whole *= sign; fpart *= sign; } /* If no scale factor given, we're done. fraction is discarded. */ if (!*p) { *result = whole; return 0; } /* Validate scale factor, and scale whole and fraction by it. */ for (i = 0; i < SCALE_LENGTH; i++) { /* Are we there yet? */ if (*p == scale_chars[i] || *p == tolower(scale_chars[i])) { /* If it ends with alphanumerics after the scale char, bad. */ if (isalnum(*(p+1))) { errno = EINVAL; return -1; } scale_fact = scale_factors[i]; /* scale whole part */ whole *= scale_fact; /* truncate fpart so it does't overflow. * then scale fractional part. */ while (fpart >= LLONG_MAX / scale_fact) { fpart /= 10; fract_digits--; } fpart *= scale_fact; if (fract_digits > 0) { for (i = 0; i < fract_digits -1; i++) fpart /= 10; } whole += fpart; *result = whole; return 0; } } errno = ERANGE; return -1; } /* Format the given "number" into human-readable form in "result". * Result must point to an allocated buffer of length FMT_SCALED_STRSIZE. * Return 0 on success, -1 and errno set if error. */ int fmt_scaled(long long number, char *result) { long long abval, fract = 0; unsigned int i; unit_type unit = NONE; abval = llabs(number); /* Not every negative long long has a positive representation. * Also check for numbers that are just too darned big to format */ if (abval < 0 || abval / 1024 >= scale_factors[SCALE_LENGTH-1]) { errno = ERANGE; return -1; } /* scale whole part; get unscaled fraction */ for (i = 0; i < SCALE_LENGTH; i++) { if (abval/1024 < scale_factors[i]) { unit = units[i]; fract = (i == 0) ? 0 : abval % scale_factors[i]; number /= scale_factors[i]; if (i > 0) fract /= scale_factors[i - 1]; break; } } fract = (10 * fract + 512) / 1024; /* if the result would be >= 10, round main number */ if (fract == 10) { if (number >= 0) number++; else number--; fract = 0; } if (number == 0) strlcpy(result, "0B", FMT_SCALED_STRSIZE); else if (unit == NONE || number >= 100 || number <= -100) { if (fract >= 5) { if (number >= 0) number++; else number--; } (void)snprintf(result, FMT_SCALED_STRSIZE, "%lld%c", number, scale_chars[unit]); } else (void)snprintf(result, FMT_SCALED_STRSIZE, "%lld.%1lld%c", number, fract, scale_chars[unit]); return 0; } /* --------------------------------------------------------------------------- */ /* * Copyright (c) 2002,2004 Damien Miller <djm@mindrot.org> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* Get effective user and group identification of locally-connected * peer. */ int getpeereid(int s, uid_t *euid, gid_t *gid) { struct ucred cred; socklen_t len = sizeof(cred); if (getsockopt(s, SOL_SOCKET, SO_PEERCRED, &cred, &len) < 0) return (-1); *euid = cred.uid; *gid = cred.gid; return (0); } #ifdef MAIN /* * This is the original version of the program in the man page. * Copy-and-paste whatever you need from it. */ int main(int argc, char **argv) { char *cinput = "1.5K", buf[FMT_SCALED_STRSIZE]; long long ninput = 10483892, result; if (scan_scaled(cinput, &result) == 0) printf("\"%s\" -> %lld\n", cinput, result); else perror(cinput); if (fmt_scaled(ninput, buf) == 0) printf("%lld -> \"%s\"\n", ninput, buf); else fprintf(stderr, "%lld invalid (%s)\n", ninput, strerror(errno)); return 0; } #endif