Do not show deleted branch when reloading the branch view
[tig.git] / tig.h
blob019d9ab283addc7441fd6b368dacc87f78bc7d69
1 /* Copyright (c) 2006-2012 Jonas Fonseca <fonseca@diku.dk>
3 * This program is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU General Public License as
5 * published by the Free Software Foundation; either version 2 of
6 * the License, or (at your option) any later version.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
14 #ifndef TIG_H
15 #define TIG_H
17 #ifdef HAVE_CONFIG_H
18 #include "config.h"
19 #endif
21 #ifndef TIG_VERSION
22 #define TIG_VERSION "unknown-version"
23 #endif
25 #ifndef DEBUG
26 #define NDEBUG
27 #endif
29 /* necessary on Snow Leopard to use WINDOW struct */
30 #ifdef NCURSES_OPAQUE
31 #undef NCURSES_OPAQUE
32 #endif
33 #define NCURSES_OPAQUE 0
36 #include <assert.h>
37 #include <errno.h>
38 #include <ctype.h>
39 #include <signal.h>
40 #include <stdarg.h>
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include <sys/types.h>
45 #include <sys/wait.h>
46 #include <sys/stat.h>
47 #include <sys/select.h>
48 #include <unistd.h>
49 #include <sys/time.h>
50 #include <time.h>
51 #include <fcntl.h>
53 #include <regex.h>
55 #include <locale.h>
56 #include <langinfo.h>
57 #include <iconv.h>
59 /* ncurses(3): Must be defined to have extended wide-character functions. */
60 #define _XOPEN_SOURCE_EXTENDED
62 #if defined HAVE_NCURSESW_CURSES_H
63 # include <ncursesw/curses.h>
64 #elif defined HAVE_NCURSESW_H
65 # include <ncursesw.h>
66 #elif defined HAVE_NCURSES_CURSES_H
67 # include <ncurses/curses.h>
68 #elif defined HAVE_NCURSES_H
69 # include <ncurses.h>
70 #elif defined HAVE_CURSES_H
71 # include <curses.h>
72 #else
73 # warning SysV or X/Open-compatible Curses installation is required.
74 # warning Will assume Curses is found in default include and library path.
75 # warning To fix any build issues please use autotools to configure Curses.
76 # warning See INSTALL file for instructions.
77 # include <curses.h>
78 #endif
80 #if __GNUC__ >= 3
81 #define __NORETURN __attribute__((__noreturn__))
82 #define PRINTF_LIKE(fmt, args) __attribute__((format (printf, fmt, args)))
83 #else
84 #define __NORETURN
85 #define PRINTF_LIKE(fmt, args)
86 #endif
88 #define ABS(x) ((x) >= 0 ? (x) : -(x))
89 #define MIN(x, y) ((x) < (y) ? (x) : (y))
90 #define MAX(x, y) ((x) > (y) ? (x) : (y))
92 #define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
93 #define STRING_SIZE(x) (sizeof(x) - 1)
95 #define SIZEOF_STR 1024 /* Default string size. */
96 #define SIZEOF_REF 256 /* Size of symbolic or SHA1 ID. */
97 #define SIZEOF_REV 41 /* Holds a SHA-1 and an ending NUL. */
98 #define SIZEOF_ARG 32 /* Default argument array size. */
100 /* This color name can be used to refer to the default term colors. */
101 #define COLOR_DEFAULT (-1)
103 #define ENCODING_UTF8 "UTF-8"
104 #define ENCODING_SEP ": encoding: "
105 #define ENCODING_ARG "--encoding=" ENCODING_UTF8
107 #define ICONV_NONE ((iconv_t) -1)
108 #ifndef ICONV_CONST
109 #define ICONV_CONST /* nothing */
110 #endif
111 #define ICONV_TRANSLIT "//TRANSLIT"
113 /* The format and size of the date column in the main view. */
114 #define DATE_FORMAT "%Y-%m-%d %H:%M"
115 #define DATE_WIDTH STRING_SIZE("2006-04-29 14:21")
116 #define DATE_SHORT_WIDTH STRING_SIZE("2006-04-29")
118 #define ID_WIDTH 7
119 #define AUTHOR_WIDTH 18
120 #define FILENAME_WIDTH 18
122 #define MIN_VIEW_HEIGHT 4
123 #define MIN_VIEW_WIDTH 4
125 #define NULL_ID "0000000000000000000000000000000000000000"
127 #define S_ISGITLINK(mode) (((mode) & S_IFMT) == 0160000)
129 /* Some ASCII-shorthands fitted into the ncurses namespace. */
130 #define KEY_CTL(x) ((x) & 0x1f) /* KEY_CTL(A) == ^A == \1 */
131 #define KEY_TAB '\t'
132 #define KEY_RETURN '\r'
133 #define KEY_ESC 27
136 * Allocation helpers ... Entering macro hell to never be seen again.
139 #define DEFINE_ALLOCATOR(name, type, chunk_size) \
140 static type * \
141 name(type **mem, size_t size, size_t increase) \
143 size_t num_chunks = (size + chunk_size - 1) / chunk_size; \
144 size_t num_chunks_new = (size + increase + chunk_size - 1) / chunk_size;\
145 type *tmp = *mem; \
147 if (mem == NULL || num_chunks != num_chunks_new) { \
148 size_t newsize = num_chunks_new * chunk_size * sizeof(type); \
150 tmp = realloc(tmp, newsize); \
151 if (tmp) { \
152 *mem = tmp; \
153 if (num_chunks_new > num_chunks) { \
154 size_t offset = num_chunks * chunk_size; \
155 size_t oldsize = offset * sizeof(type); \
157 memset(tmp + offset, 0, newsize - oldsize); \
162 return tmp; \
166 * Strings.
169 #define prefixcmp(str1, str2) \
170 strncmp(str1, str2, STRING_SIZE(str2))
172 static inline bool
173 string_isnumber(const char *str)
175 int pos;
177 for (pos = 0; str[pos]; pos++) {
178 if (!isdigit(str[pos]))
179 return FALSE;
182 return pos > 0;
185 static inline bool
186 iscommit(char *str)
188 int pos;
190 for (pos = 0; str[pos]; pos++) {
191 if (!isxdigit(str[pos]))
192 return FALSE;
195 return 7 <= pos && pos < SIZEOF_REV;
198 static inline int
199 ascii_toupper(int c)
201 if (c >= 'a' && c <= 'z')
202 c &= ~0x20;
203 return c;
206 static inline int
207 ascii_tolower(int c)
209 if (c >= 'A' && c <= 'Z')
210 c |= 0x20;
211 return c;
214 static inline int
215 suffixcmp(const char *str, int slen, const char *suffix)
217 size_t len = slen >= 0 ? slen : strlen(str);
218 size_t suffixlen = strlen(suffix);
220 return suffixlen < len ? strcmp(str + len - suffixlen, suffix) : -1;
223 static inline void
224 string_ncopy_do(char *dst, size_t dstlen, const char *src, size_t srclen)
226 if (srclen > dstlen - 1)
227 srclen = dstlen - 1;
229 strncpy(dst, src, srclen);
230 dst[srclen] = 0;
233 /* Shorthands for safely copying into a fixed buffer. */
235 #define FORMAT_BUFFER(buf, bufsize, fmt, retval, allow_truncate) \
236 do { \
237 va_list args; \
238 va_start(args, fmt); \
239 retval = vsnprintf(buf, bufsize, fmt, args); \
240 va_end(args); \
241 if (retval >= (bufsize) && allow_truncate) { \
242 (buf)[(bufsize) - 1] = 0; \
243 (buf)[(bufsize) - 2] = '.'; \
244 (buf)[(bufsize) - 3] = '.'; \
245 (buf)[(bufsize) - 4] = '.'; \
246 retval = (bufsize) - 1; \
247 } else if (retval < 0 || retval >= (bufsize)) { \
248 retval = -1; \
250 } while (0)
252 #define string_copy(dst, src) \
253 string_ncopy_do(dst, sizeof(dst), src, sizeof(src))
255 #define string_ncopy(dst, src, srclen) \
256 string_ncopy_do(dst, sizeof(dst), src, srclen)
258 static inline void
259 string_copy_rev(char *dst, const char *src)
261 size_t srclen;
263 for (srclen = 0; srclen < SIZEOF_REV; srclen++)
264 if (isspace(src[srclen]))
265 break;
267 string_ncopy_do(dst, SIZEOF_REV, src, srclen);
270 #define string_rev_is_null(rev) !strncmp(rev, NULL_ID, STRING_SIZE(NULL_ID))
272 #define string_add(dst, from, src) \
273 string_ncopy_do(dst + (from), sizeof(dst) - (from), src, sizeof(src))
275 static inline size_t
276 string_expanded_length(const char *src, size_t srclen, size_t tabsize, size_t max_size)
278 size_t size, pos;
280 for (size = pos = 0; pos < srclen && size < max_size; pos++) {
281 if (src[pos] == '\t') {
282 size_t expanded = tabsize - (size % tabsize);
284 size += expanded;
285 } else {
286 size++;
290 return pos;
293 static inline size_t
294 string_expand(char *dst, size_t dstlen, const char *src, int tabsize)
296 size_t size, pos;
298 for (size = pos = 0; size < dstlen - 1 && src[pos]; pos++) {
299 if (src[pos] == '\t') {
300 size_t expanded = tabsize - (size % tabsize);
302 if (expanded + size >= dstlen - 1)
303 expanded = dstlen - size - 1;
304 memcpy(dst + size, " ", expanded);
305 size += expanded;
306 } else {
307 dst[size++] = src[pos];
311 dst[size] = 0;
312 return pos;
315 static inline char *
316 chomp_string(char *name)
318 int namelen;
320 while (isspace(*name))
321 name++;
323 namelen = strlen(name) - 1;
324 while (namelen > 0 && isspace(name[namelen]))
325 name[namelen--] = 0;
327 return name;
330 static inline bool PRINTF_LIKE(4, 5)
331 string_nformat(char *buf, size_t bufsize, size_t *bufpos, const char *fmt, ...)
333 size_t pos = bufpos ? *bufpos : 0;
334 int retval;
336 FORMAT_BUFFER(buf + pos, bufsize - pos, fmt, retval, FALSE);
337 if (bufpos && retval > 0)
338 *bufpos = pos + retval;
340 return pos >= bufsize ? FALSE : TRUE;
343 #define string_format(buf, fmt, args...) \
344 string_nformat(buf, sizeof(buf), NULL, fmt, args)
346 #define string_format_from(buf, from, fmt, args...) \
347 string_nformat(buf, sizeof(buf), from, fmt, args)
349 static inline int
350 strcmp_null(const char *s1, const char *s2)
352 if (!s1 || !s2) {
353 return (!!s1) - (!!s2);
356 return strcmp(s1, s2);
360 * Enumerations
363 struct enum_map {
364 const char *name;
365 int namelen;
366 int value;
369 #define ENUM_MAP(name, value) { name, STRING_SIZE(name), value }
371 #define ENUM_SYM_MACRO(prefix, name) prefix##_##name
372 #define ENUM_MAP_MACRO(prefix, name) ENUM_MAP(#name, ENUM_SYM_MACRO(prefix, name))
374 #define DEFINE_ENUM(name, info) \
375 enum name { info(ENUM_SYM_MACRO) }; \
376 static const struct enum_map name##_map[] = { info(ENUM_MAP_MACRO) }
378 static inline int
379 string_enum_compare(const char *str1, const char *str2, int len)
381 size_t i;
383 #define string_enum_sep(x) ((x) == '-' || (x) == '_' || (x) == '.')
385 /* Diff-Header == DIFF_HEADER */
386 for (i = 0; i < len; i++) {
387 if (ascii_toupper(str1[i]) == ascii_toupper(str2[i]))
388 continue;
390 if (string_enum_sep(str1[i]) &&
391 string_enum_sep(str2[i]))
392 continue;
394 return str1[i] - str2[i];
397 return 0;
400 #define enum_equals(entry, str, len) \
401 ((entry).namelen == (len) && !string_enum_compare((entry).name, str, len))
403 static inline char *
404 enum_map_name(const char *name, size_t namelen)
406 static char buf[SIZEOF_STR];
407 int bufpos;
409 for (bufpos = 0; bufpos <= namelen; bufpos++) {
410 buf[bufpos] = ascii_tolower(name[bufpos]);
411 if (buf[bufpos] == '_')
412 buf[bufpos] = '-';
415 buf[bufpos] = 0;
416 return buf;
419 #define enum_name(entry) enum_map_name((entry).name, (entry).namelen)
421 static inline bool
422 map_enum_do(const struct enum_map *map, size_t map_size, int *value, const char *name)
424 size_t namelen = strlen(name);
425 int i;
427 for (i = 0; i < map_size; i++)
428 if (enum_equals(map[i], name, namelen)) {
429 *value = map[i].value;
430 return TRUE;
433 return FALSE;
436 #define map_enum(attr, map, name) \
437 map_enum_do(map, ARRAY_SIZE(map), attr, name)
440 * Unicode / UTF-8 handling
442 * NOTE: Much of the following code for dealing with Unicode is derived from
443 * ELinks' UTF-8 code developed by Scrool <scroolik@gmail.com>. Origin file is
444 * src/intl/charset.c from the UTF-8 branch commit elinks-0.11.0-g31f2c28.
447 static inline int
448 unicode_width(unsigned long c, int tab_size)
450 if (c >= 0x1100 &&
451 (c <= 0x115f /* Hangul Jamo */
452 || c == 0x2329
453 || c == 0x232a
454 || (c >= 0x2e80 && c <= 0xa4cf && c != 0x303f)
455 /* CJK ... Yi */
456 || (c >= 0xac00 && c <= 0xd7a3) /* Hangul Syllables */
457 || (c >= 0xf900 && c <= 0xfaff) /* CJK Compatibility Ideographs */
458 || (c >= 0xfe30 && c <= 0xfe6f) /* CJK Compatibility Forms */
459 || (c >= 0xff00 && c <= 0xff60) /* Fullwidth Forms */
460 || (c >= 0xffe0 && c <= 0xffe6)
461 || (c >= 0x20000 && c <= 0x2fffd)
462 || (c >= 0x30000 && c <= 0x3fffd)))
463 return 2;
465 if (c == '\t')
466 return tab_size;
468 return 1;
471 /* Number of bytes used for encoding a UTF-8 character indexed by first byte.
472 * Illegal bytes are set one. */
473 static const unsigned char utf8_bytes[256] = {
474 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,
475 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,
476 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,
477 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,
478 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,
479 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,
480 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,
481 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,
484 static inline unsigned char
485 utf8_char_length(const char *string, const char *end)
487 int c = *(unsigned char *) string;
489 return utf8_bytes[c];
492 /* Decode UTF-8 multi-byte representation into a Unicode character. */
493 static inline unsigned long
494 utf8_to_unicode(const char *string, size_t length)
496 unsigned long unicode;
498 switch (length) {
499 case 1:
500 unicode = string[0];
501 break;
502 case 2:
503 unicode = (string[0] & 0x1f) << 6;
504 unicode += (string[1] & 0x3f);
505 break;
506 case 3:
507 unicode = (string[0] & 0x0f) << 12;
508 unicode += ((string[1] & 0x3f) << 6);
509 unicode += (string[2] & 0x3f);
510 break;
511 case 4:
512 unicode = (string[0] & 0x0f) << 18;
513 unicode += ((string[1] & 0x3f) << 12);
514 unicode += ((string[2] & 0x3f) << 6);
515 unicode += (string[3] & 0x3f);
516 break;
517 case 5:
518 unicode = (string[0] & 0x0f) << 24;
519 unicode += ((string[1] & 0x3f) << 18);
520 unicode += ((string[2] & 0x3f) << 12);
521 unicode += ((string[3] & 0x3f) << 6);
522 unicode += (string[4] & 0x3f);
523 break;
524 case 6:
525 unicode = (string[0] & 0x01) << 30;
526 unicode += ((string[1] & 0x3f) << 24);
527 unicode += ((string[2] & 0x3f) << 18);
528 unicode += ((string[3] & 0x3f) << 12);
529 unicode += ((string[4] & 0x3f) << 6);
530 unicode += (string[5] & 0x3f);
531 break;
532 default:
533 return 0;
536 /* Invalid characters could return the special 0xfffd value but NUL
537 * should be just as good. */
538 return unicode > 0xffff ? 0 : unicode;
541 /* Calculates how much of string can be shown within the given maximum width
542 * and sets trimmed parameter to non-zero value if all of string could not be
543 * shown. If the reserve flag is TRUE, it will reserve at least one
544 * trailing character, which can be useful when drawing a delimiter.
546 * Returns the number of bytes to output from string to satisfy max_width. */
547 static inline size_t
548 utf8_length(const char **start, size_t skip, int *width, size_t max_width, int *trimmed, bool reserve, int tab_size)
550 const char *string = *start;
551 const char *end = strchr(string, '\0');
552 unsigned char last_bytes = 0;
553 size_t last_ucwidth = 0;
555 *width = 0;
556 *trimmed = 0;
558 while (string < end) {
559 unsigned char bytes = utf8_char_length(string, end);
560 size_t ucwidth;
561 unsigned long unicode;
563 if (string + bytes > end)
564 break;
566 /* Change representation to figure out whether
567 * it is a single- or double-width character. */
569 unicode = utf8_to_unicode(string, bytes);
570 /* FIXME: Graceful handling of invalid Unicode character. */
571 if (!unicode)
572 break;
574 ucwidth = unicode_width(unicode, tab_size);
575 if (skip > 0) {
576 skip -= ucwidth <= skip ? ucwidth : skip;
577 *start += bytes;
579 *width += ucwidth;
580 if (*width > max_width) {
581 *trimmed = 1;
582 *width -= ucwidth;
583 if (reserve && *width == max_width) {
584 string -= last_bytes;
585 *width -= last_ucwidth;
587 break;
590 string += bytes;
591 last_bytes = ucwidth ? bytes : 0;
592 last_ucwidth = ucwidth;
595 return string - *start;
598 #endif