index 72bcf8b8883c0a97ffbc32c4892b2915c526155e..718e6c2d186254f5cca36a5fcee1742d7b9265ed 100644 (file)
--- a/tig.c
+++ b/tig.c
* GNU General Public License for more details.
*/
* GNU General Public License for more details.
*/
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#ifndef TIG_VERSION
-#define TIG_VERSION "unknown-version"
-#endif
-
-#ifndef DEBUG
-#define NDEBUG
-#endif
-
-#include <assert.h>
-#include <errno.h>
-#include <ctype.h>
-#include <signal.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <sys/stat.h>
-#include <sys/select.h>
-#include <unistd.h>
-#include <sys/time.h>
-#include <time.h>
-#include <fcntl.h>
-
-#include <regex.h>
-
-#include <locale.h>
-#include <langinfo.h>
-#include <iconv.h>
-
-/* ncurses(3): Must be defined to have extended wide-character functions. */
-#define _XOPEN_SOURCE_EXTENDED
-
-#ifdef HAVE_NCURSESW_H
-#include <ncursesw/ncurses.h>
-#else
-#include <ncurses.h>
-#endif
-
-#if __GNUC__ >= 3
-#define __NORETURN __attribute__((__noreturn__))
-#else
-#define __NORETURN
-#endif
+#include "tig.h"
static void __NORETURN die(const char *err, ...);
static void warn(const char *msg, ...);
static void report(const char *msg, ...);
static void __NORETURN die(const char *err, ...);
static void warn(const char *msg, ...);
static void report(const char *msg, ...);
-#define ABS(x) ((x) >= 0 ? (x) : -(x))
-#define MIN(x, y) ((x) < (y) ? (x) : (y))
-#define MAX(x, y) ((x) > (y) ? (x) : (y))
-
-#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
-#define STRING_SIZE(x) (sizeof(x) - 1)
-
-#define SIZEOF_STR 1024 /* Default string size. */
-#define SIZEOF_REF 256 /* Size of symbolic or SHA1 ID. */
-#define SIZEOF_REV 41 /* Holds a SHA-1 and an ending NUL. */
-#define SIZEOF_ARG 32 /* Default argument array size. */
-
-/* Revision graph */
-
-#define REVGRAPH_INIT 'I'
-#define REVGRAPH_MERGE 'M'
-#define REVGRAPH_BRANCH '+'
-#define REVGRAPH_COMMIT '*'
-#define REVGRAPH_BOUND '^'
-
-#define SIZEOF_REVGRAPH 19 /* Size of revision ancestry graphics. */
-
-/* This color name can be used to refer to the default term colors. */
-#define COLOR_DEFAULT (-1)
-
-#define ICONV_NONE ((iconv_t) -1)
-#ifndef ICONV_CONST
-#define ICONV_CONST /* nothing */
-#endif
-
-/* The format and size of the date column in the main view. */
-#define DATE_FORMAT "%Y-%m-%d %H:%M"
-#define DATE_COLS STRING_SIZE("2006-04-29 14:21 ")
-#define DATE_SHORT_COLS STRING_SIZE("2006-04-29 ")
-
-#define ID_COLS 8
-#define AUTHOR_COLS 19
-
-#define MIN_VIEW_HEIGHT 4
-
-#define NULL_ID "0000000000000000000000000000000000000000"
-
-#define S_ISGITLINK(mode) (((mode) & S_IFMT) == 0160000)
-
-/* Some ASCII-shorthands fitted into the ncurses namespace. */
-#define KEY_CTL(x) ((x) & 0x1f) /* KEY_CTL(A) == ^A == \1 */
-#define KEY_TAB '\t'
-#define KEY_RETURN '\r'
-#define KEY_ESC 27
-
struct ref {
char id[SIZEOF_REV]; /* Commit SHA1 ID */
struct ref {
char id[SIZEOF_REV]; /* Commit SHA1 ID */
static bool prompt_menu(const char *prompt, const struct menu_item *items, int *selected);
static bool prompt_menu(const char *prompt, const struct menu_item *items, int *selected);
-/*
- * Allocation helpers ... Entering macro hell to never be seen again.
- */
-
-#define DEFINE_ALLOCATOR(name, type, chunk_size) \
-static type * \
-name(type **mem, size_t size, size_t increase) \
-{ \
- size_t num_chunks = (size + chunk_size - 1) / chunk_size; \
- size_t num_chunks_new = (size + increase + chunk_size - 1) / chunk_size;\
- type *tmp = *mem; \
- \
- if (mem == NULL || num_chunks != num_chunks_new) { \
- tmp = realloc(tmp, num_chunks_new * chunk_size * sizeof(type)); \
- if (tmp) \
- *mem = tmp; \
- } \
- \
- return tmp; \
-}
-
-/*
- * String helpers
- */
-
-static inline void
-string_ncopy_do(char *dst, size_t dstlen, const char *src, size_t srclen)
-{
- if (srclen > dstlen - 1)
- srclen = dstlen - 1;
-
- strncpy(dst, src, srclen);
- dst[srclen] = 0;
-}
-
-/* Shorthands for safely copying into a fixed buffer. */
-
-#define string_copy(dst, src) \
- string_ncopy_do(dst, sizeof(dst), src, sizeof(src))
-
-#define string_ncopy(dst, src, srclen) \
- string_ncopy_do(dst, sizeof(dst), src, srclen)
-
-#define string_copy_rev(dst, src) \
- string_ncopy_do(dst, SIZEOF_REV, src, SIZEOF_REV - 1)
-
-#define string_add(dst, from, src) \
- string_ncopy_do(dst + (from), sizeof(dst) - (from), src, sizeof(src))
-
-static size_t
-string_expand(char *dst, size_t dstlen, const char *src, int tabsize)
-{
- size_t size, pos;
-
- for (size = pos = 0; size < dstlen - 1 && src[pos]; pos++) {
- if (src[pos] == '\t') {
- size_t expanded = tabsize - (size % tabsize);
-
- if (expanded + size >= dstlen - 1)
- expanded = dstlen - size - 1;
- memcpy(dst + size, " ", expanded);
- size += expanded;
- } else {
- dst[size++] = src[pos];
- }
- }
-
- dst[size] = 0;
- return pos;
-}
-
-static char *
-chomp_string(char *name)
-{
- int namelen;
-
- while (isspace(*name))
- name++;
-
- namelen = strlen(name) - 1;
- while (namelen > 0 && isspace(name[namelen]))
- name[namelen--] = 0;
-
- return name;
-}
-
-static bool
-string_nformat(char *buf, size_t bufsize, size_t *bufpos, const char *fmt, ...)
-{
- va_list args;
- size_t pos = bufpos ? *bufpos : 0;
-
- va_start(args, fmt);
- pos += vsnprintf(buf + pos, bufsize - pos, fmt, args);
- va_end(args);
-
- if (bufpos)
- *bufpos = pos;
-
- return pos >= bufsize ? FALSE : TRUE;
-}
-
-#define string_format(buf, fmt, args...) \
- string_nformat(buf, sizeof(buf), NULL, fmt, args)
-
-#define string_format_from(buf, from, fmt, args...) \
- string_nformat(buf, sizeof(buf), from, fmt, args)
-
-static int
-string_enum_compare(const char *str1, const char *str2, int len)
-{
- size_t i;
-
-#define string_enum_sep(x) ((x) == '-' || (x) == '_' || (x) == '.')
-
- /* Diff-Header == DIFF_HEADER */
- for (i = 0; i < len; i++) {
- if (toupper(str1[i]) == toupper(str2[i]))
- continue;
-
- if (string_enum_sep(str1[i]) &&
- string_enum_sep(str2[i]))
- continue;
-
- return str1[i] - str2[i];
- }
-
- return 0;
-}
-
-#define enum_equals(entry, str, len) \
- ((entry).namelen == (len) && !string_enum_compare((entry).name, str, len))
-
-struct enum_map {
- const char *name;
- int namelen;
- int value;
-};
-
-#define ENUM_MAP(name, value) { name, STRING_SIZE(name), value }
-
-static char *
-enum_map_name(const char *name, size_t namelen)
-{
- static char buf[SIZEOF_STR];
- int bufpos;
-
- for (bufpos = 0; bufpos <= namelen; bufpos++) {
- buf[bufpos] = tolower(name[bufpos]);
- if (buf[bufpos] == '_')
- buf[bufpos] = '-';
- }
-
- buf[bufpos] = 0;
- return buf;
-}
-
-#define enum_name(entry) enum_map_name((entry).name, (entry).namelen)
-
-static bool
-map_enum_do(const struct enum_map *map, size_t map_size, int *value, const char *name)
-{
- size_t namelen = strlen(name);
- int i;
-
- for (i = 0; i < map_size; i++)
- if (enum_equals(map[i], name, namelen)) {
- *value = map[i].value;
- return TRUE;
- }
-
- return FALSE;
-}
-
-#define map_enum(attr, map, name) \
- map_enum_do(map, ARRAY_SIZE(map), attr, name)
-
-#define prefixcmp(str1, str2) \
- strncmp(str1, str2, STRING_SIZE(str2))
-
-static inline int
-suffixcmp(const char *str, int slen, const char *suffix)
-{
- size_t len = slen >= 0 ? slen : strlen(str);
- size_t suffixlen = strlen(suffix);
-
- return suffixlen < len ? strcmp(str + len - suffixlen, suffix) : -1;
-}
-
-
-/*
- * Unicode / UTF-8 handling
- *
- * NOTE: Much of the following code for dealing with Unicode is derived from
- * ELinks' UTF-8 code developed by Scrool <scroolik@gmail.com>. Origin file is
- * src/intl/charset.c from the UTF-8 branch commit elinks-0.11.0-g31f2c28.
- */
-
-static inline int
-unicode_width(unsigned long c, int tab_size)
-{
- if (c >= 0x1100 &&
- (c <= 0x115f /* Hangul Jamo */
- || c == 0x2329
- || c == 0x232a
- || (c >= 0x2e80 && c <= 0xa4cf && c != 0x303f)
- /* CJK ... Yi */
- || (c >= 0xac00 && c <= 0xd7a3) /* Hangul Syllables */
- || (c >= 0xf900 && c <= 0xfaff) /* CJK Compatibility Ideographs */
- || (c >= 0xfe30 && c <= 0xfe6f) /* CJK Compatibility Forms */
- || (c >= 0xff00 && c <= 0xff60) /* Fullwidth Forms */
- || (c >= 0xffe0 && c <= 0xffe6)
- || (c >= 0x20000 && c <= 0x2fffd)
- || (c >= 0x30000 && c <= 0x3fffd)))
- return 2;
-
- if (c == '\t')
- return tab_size;
-
- return 1;
-}
-
-/* Number of bytes used for encoding a UTF-8 character indexed by first byte.
- * Illegal bytes are set one. */
-static const unsigned char utf8_bytes[256] = {
- 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,
- 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,
- 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,
- 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,
- 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,
- 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,
- 2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,
- 3,3,3,3,3,3,3,3, 3,3,3,3,3,3,3,3, 4,4,4,4,4,4,4,4, 5,5,5,5,6,6,1,1,
-};
-
-static inline unsigned char
-utf8_char_length(const char *string, const char *end)
-{
- int c = *(unsigned char *) string;
-
- return utf8_bytes[c];
-}
-
-/* Decode UTF-8 multi-byte representation into a Unicode character. */
-static inline unsigned long
-utf8_to_unicode(const char *string, size_t length)
-{
- unsigned long unicode;
-
- switch (length) {
- case 1:
- unicode = string[0];
- break;
- case 2:
- unicode = (string[0] & 0x1f) << 6;
- unicode += (string[1] & 0x3f);
- break;
- case 3:
- unicode = (string[0] & 0x0f) << 12;
- unicode += ((string[1] & 0x3f) << 6);
- unicode += (string[2] & 0x3f);
- break;
- case 4:
- unicode = (string[0] & 0x0f) << 18;
- unicode += ((string[1] & 0x3f) << 12);
- unicode += ((string[2] & 0x3f) << 6);
- unicode += (string[3] & 0x3f);
- break;
- case 5:
- unicode = (string[0] & 0x0f) << 24;
- unicode += ((string[1] & 0x3f) << 18);
- unicode += ((string[2] & 0x3f) << 12);
- unicode += ((string[3] & 0x3f) << 6);
- unicode += (string[4] & 0x3f);
- break;
- case 6:
- unicode = (string[0] & 0x01) << 30;
- unicode += ((string[1] & 0x3f) << 24);
- unicode += ((string[2] & 0x3f) << 18);
- unicode += ((string[3] & 0x3f) << 12);
- unicode += ((string[4] & 0x3f) << 6);
- unicode += (string[5] & 0x3f);
- break;
- default:
- return 0;
- }
-
- /* Invalid characters could return the special 0xfffd value but NUL
- * should be just as good. */
- return unicode > 0xffff ? 0 : unicode;
-}
-
-/* Calculates how much of string can be shown within the given maximum width
- * and sets trimmed parameter to non-zero value if all of string could not be
- * shown. If the reserve flag is TRUE, it will reserve at least one
- * trailing character, which can be useful when drawing a delimiter.
- *
- * Returns the number of bytes to output from string to satisfy max_width. */
-static size_t
-utf8_length(const char **start, size_t skip, int *width, size_t max_width, int *trimmed, bool reserve, int tab_size)
-{
- const char *string = *start;
- const char *end = strchr(string, '\0');
- unsigned char last_bytes = 0;
- size_t last_ucwidth = 0;
-
- *width = 0;
- *trimmed = 0;
-
- while (string < end) {
- unsigned char bytes = utf8_char_length(string, end);
- size_t ucwidth;
- unsigned long unicode;
-
- if (string + bytes > end)
- break;
-
- /* Change representation to figure out whether
- * it is a single- or double-width character. */
-
- unicode = utf8_to_unicode(string, bytes);
- /* FIXME: Graceful handling of invalid Unicode character. */
- if (!unicode)
- break;
-
- ucwidth = unicode_width(unicode, tab_size);
- if (skip > 0) {
- skip -= ucwidth <= skip ? ucwidth : skip;
- *start += bytes;
- }
- *width += ucwidth;
- if (*width > max_width) {
- *trimmed = 1;
- *width -= ucwidth;
- if (reserve && *width == max_width) {
- string -= last_bytes;
- *width -= last_ucwidth;
- }
- break;
- }
-
- string += bytes;
- last_bytes = ucwidth ? bytes : 0;
- last_ucwidth = ucwidth;
- }
-
- return string - *start;
-}
-
-
#define DATE_INFO \
DATE_(NO), \
DATE_(DEFAULT), \
#define DATE_INFO \
DATE_(NO), \
DATE_(DEFAULT), \