Show the title of the last commit in the branch view
[tig.git] / tig.h
blob6394ee85259b5fd1d1d461efb837c264b8fa5778
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 #ifdef HAVE_NCURSESW_H
63 #include <ncursesw/ncurses.h>
64 #else
65 #include <ncurses.h>
66 #endif
68 #if __GNUC__ >= 3
69 #define __NORETURN __attribute__((__noreturn__))
70 #else
71 #define __NORETURN
72 #endif
74 #define ABS(x) ((x) >= 0 ? (x) : -(x))
75 #define MIN(x, y) ((x) < (y) ? (x) : (y))
76 #define MAX(x, y) ((x) > (y) ? (x) : (y))
78 #define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
79 #define STRING_SIZE(x) (sizeof(x) - 1)
81 #define SIZEOF_STR 1024 /* Default string size. */
82 #define SIZEOF_REF 256 /* Size of symbolic or SHA1 ID. */
83 #define SIZEOF_REV 41 /* Holds a SHA-1 and an ending NUL. */
84 #define SIZEOF_ARG 32 /* Default argument array size. */
86 /* This color name can be used to refer to the default term colors. */
87 #define COLOR_DEFAULT (-1)
89 #define ENCODING_UTF8 "UTF-8"
90 #define ENCODING_SEP ": encoding: "
91 #define ENCODING_ARG "--encoding=" ENCODING_UTF8
93 #define ICONV_NONE ((iconv_t) -1)
94 #ifndef ICONV_CONST
95 #define ICONV_CONST /* nothing */
96 #endif
97 #define ICONV_TRANSLIT "//TRANSLIT"
99 /* The format and size of the date column in the main view. */
100 #define DATE_FORMAT "%Y-%m-%d %H:%M"
101 #define DATE_COLS STRING_SIZE("2006-04-29 14:21 ")
102 #define DATE_SHORT_COLS STRING_SIZE("2006-04-29 ")
104 #define ID_COLS 8
105 #define AUTHOR_COLS 19
106 #define FILENAME_COLS 19
108 #define MIN_VIEW_HEIGHT 4
110 #define NULL_ID "0000000000000000000000000000000000000000"
112 #define S_ISGITLINK(mode) (((mode) & S_IFMT) == 0160000)
114 /* Some ASCII-shorthands fitted into the ncurses namespace. */
115 #define KEY_CTL(x) ((x) & 0x1f) /* KEY_CTL(A) == ^A == \1 */
116 #define KEY_TAB '\t'
117 #define KEY_RETURN '\r'
118 #define KEY_ESC 27
121 * Allocation helpers ... Entering macro hell to never be seen again.
124 #define DEFINE_ALLOCATOR(name, type, chunk_size) \
125 static type * \
126 name(type **mem, size_t size, size_t increase) \
128 size_t num_chunks = (size + chunk_size - 1) / chunk_size; \
129 size_t num_chunks_new = (size + increase + chunk_size - 1) / chunk_size;\
130 type *tmp = *mem; \
132 if (mem == NULL || num_chunks != num_chunks_new) { \
133 size_t newsize = num_chunks_new * chunk_size * sizeof(type); \
135 tmp = realloc(tmp, newsize); \
136 if (tmp) { \
137 *mem = tmp; \
138 if (num_chunks_new > num_chunks) { \
139 size_t offset = num_chunks * chunk_size; \
140 size_t oldsize = offset * sizeof(type); \
142 memset(tmp + offset, 0, newsize - oldsize); \
147 return tmp; \
151 * Strings.
154 #define prefixcmp(str1, str2) \
155 strncmp(str1, str2, STRING_SIZE(str2))
157 static inline bool
158 string_isnumber(const char *str)
160 int pos;
162 for (pos = 0; str[pos]; pos++) {
163 if (!isdigit(str[pos]))
164 return FALSE;
167 return pos > 0;
170 static inline bool
171 iscommit(char *str)
173 int pos;
175 for (pos = 0; str[pos]; pos++) {
176 if (!isxdigit(str[pos]))
177 return FALSE;
180 return 7 <= pos && pos < SIZEOF_REV;
183 static inline int
184 ascii_toupper(int c)
186 if (c >= 'a' && c <= 'z')
187 c &= ~0x20;
188 return c;
191 static inline int
192 ascii_tolower(int c)
194 if (c >= 'A' && c <= 'Z')
195 c |= 0x20;
196 return c;
199 static inline int
200 suffixcmp(const char *str, int slen, const char *suffix)
202 size_t len = slen >= 0 ? slen : strlen(str);
203 size_t suffixlen = strlen(suffix);
205 return suffixlen < len ? strcmp(str + len - suffixlen, suffix) : -1;
208 static inline void
209 string_ncopy_do(char *dst, size_t dstlen, const char *src, size_t srclen)
211 if (srclen > dstlen - 1)
212 srclen = dstlen - 1;
214 strncpy(dst, src, srclen);
215 dst[srclen] = 0;
218 /* Shorthands for safely copying into a fixed buffer. */
220 #define FORMAT_BUFFER(buf, bufsize, fmt, retval, allow_truncate) \
221 do { \
222 va_list args; \
223 va_start(args, fmt); \
224 retval = vsnprintf(buf, bufsize, fmt, args); \
225 va_end(args); \
226 if (retval >= (bufsize) && allow_truncate) { \
227 (buf)[(bufsize) - 1] = 0; \
228 (buf)[(bufsize) - 2] = '.'; \
229 (buf)[(bufsize) - 3] = '.'; \
230 (buf)[(bufsize) - 4] = '.'; \
231 retval = (bufsize) - 1; \
232 } else if (retval < 0 || retval >= (bufsize)) { \
233 retval = -1; \
235 } while (0)
237 #define string_copy(dst, src) \
238 string_ncopy_do(dst, sizeof(dst), src, sizeof(src))
240 #define string_ncopy(dst, src, srclen) \
241 string_ncopy_do(dst, sizeof(dst), src, srclen)
243 static inline void
244 string_copy_rev(char *dst, const char *src)
246 size_t srclen;
248 for (srclen = 0; srclen < SIZEOF_REV; srclen++)
249 if (isspace(src[srclen]))
250 break;
252 string_ncopy_do(dst, SIZEOF_REV, src, srclen);
255 #define string_rev_is_null(rev) !strncmp(rev, NULL_ID, STRING_SIZE(NULL_ID))
257 #define string_add(dst, from, src) \
258 string_ncopy_do(dst + (from), sizeof(dst) - (from), src, sizeof(src))
260 static inline size_t
261 string_expand(char *dst, size_t dstlen, const char *src, int tabsize)
263 size_t size, pos;
265 for (size = pos = 0; size < dstlen - 1 && src[pos]; pos++) {
266 if (src[pos] == '\t') {
267 size_t expanded = tabsize - (size % tabsize);
269 if (expanded + size >= dstlen - 1)
270 expanded = dstlen - size - 1;
271 memcpy(dst + size, " ", expanded);
272 size += expanded;
273 } else {
274 dst[size++] = src[pos];
278 dst[size] = 0;
279 return pos;
282 static inline char *
283 chomp_string(char *name)
285 int namelen;
287 while (isspace(*name))
288 name++;
290 namelen = strlen(name) - 1;
291 while (namelen > 0 && isspace(name[namelen]))
292 name[namelen--] = 0;
294 return name;
297 static inline bool
298 string_nformat(char *buf, size_t bufsize, size_t *bufpos, const char *fmt, ...)
300 size_t pos = bufpos ? *bufpos : 0;
301 int retval;
303 FORMAT_BUFFER(buf + pos, bufsize - pos, fmt, retval, FALSE);
304 if (bufpos && retval > 0)
305 *bufpos = pos + retval;
307 return pos >= bufsize ? FALSE : TRUE;
310 #define string_format(buf, fmt, args...) \
311 string_nformat(buf, sizeof(buf), NULL, fmt, args)
313 #define string_format_from(buf, from, fmt, args...) \
314 string_nformat(buf, sizeof(buf), from, fmt, args)
316 static inline int
317 strcmp_null(const char *s1, const char *s2)
319 if (!s1 || !s2) {
320 return (!!s1) - (!!s2);
323 return strcmp(s1, s2);
327 * Enumerations
330 struct enum_map {
331 const char *name;
332 int namelen;
333 int value;
336 #define ENUM_MAP(name, value) { name, STRING_SIZE(name), value }
338 #define ENUM_SYM_MACRO(prefix, name) prefix##_##name
339 #define ENUM_MAP_MACRO(prefix, name) ENUM_MAP(#name, ENUM_SYM_MACRO(prefix, name))
341 #define DEFINE_ENUM(name, info) \
342 enum name { info(ENUM_SYM_MACRO) }; \
343 static const struct enum_map name##_map[] = { info(ENUM_MAP_MACRO) }
345 static inline int
346 string_enum_compare(const char *str1, const char *str2, int len)
348 size_t i;
350 #define string_enum_sep(x) ((x) == '-' || (x) == '_' || (x) == '.')
352 /* Diff-Header == DIFF_HEADER */
353 for (i = 0; i < len; i++) {
354 if (ascii_toupper(str1[i]) == ascii_toupper(str2[i]))
355 continue;
357 if (string_enum_sep(str1[i]) &&
358 string_enum_sep(str2[i]))
359 continue;
361 return str1[i] - str2[i];
364 return 0;
367 #define enum_equals(entry, str, len) \
368 ((entry).namelen == (len) && !string_enum_compare((entry).name, str, len))
370 static inline char *
371 enum_map_name(const char *name, size_t namelen)
373 static char buf[SIZEOF_STR];
374 int bufpos;
376 for (bufpos = 0; bufpos <= namelen; bufpos++) {
377 buf[bufpos] = ascii_tolower(name[bufpos]);
378 if (buf[bufpos] == '_')
379 buf[bufpos] = '-';
382 buf[bufpos] = 0;
383 return buf;
386 #define enum_name(entry) enum_map_name((entry).name, (entry).namelen)
388 static inline bool
389 map_enum_do(const struct enum_map *map, size_t map_size, int *value, const char *name)
391 size_t namelen = strlen(name);
392 int i;
394 for (i = 0; i < map_size; i++)
395 if (enum_equals(map[i], name, namelen)) {
396 *value = map[i].value;
397 return TRUE;
400 return FALSE;
403 #define map_enum(attr, map, name) \
404 map_enum_do(map, ARRAY_SIZE(map), attr, name)
407 * Unicode / UTF-8 handling
409 * NOTE: Much of the following code for dealing with Unicode is derived from
410 * ELinks' UTF-8 code developed by Scrool <scroolik@gmail.com>. Origin file is
411 * src/intl/charset.c from the UTF-8 branch commit elinks-0.11.0-g31f2c28.
414 static inline int
415 unicode_width(unsigned long c, int tab_size)
417 if (c >= 0x1100 &&
418 (c <= 0x115f /* Hangul Jamo */
419 || c == 0x2329
420 || c == 0x232a
421 || (c >= 0x2e80 && c <= 0xa4cf && c != 0x303f)
422 /* CJK ... Yi */
423 || (c >= 0xac00 && c <= 0xd7a3) /* Hangul Syllables */
424 || (c >= 0xf900 && c <= 0xfaff) /* CJK Compatibility Ideographs */
425 || (c >= 0xfe30 && c <= 0xfe6f) /* CJK Compatibility Forms */
426 || (c >= 0xff00 && c <= 0xff60) /* Fullwidth Forms */
427 || (c >= 0xffe0 && c <= 0xffe6)
428 || (c >= 0x20000 && c <= 0x2fffd)
429 || (c >= 0x30000 && c <= 0x3fffd)))
430 return 2;
432 if (c == '\t')
433 return tab_size;
435 return 1;
438 /* Number of bytes used for encoding a UTF-8 character indexed by first byte.
439 * Illegal bytes are set one. */
440 static const unsigned char utf8_bytes[256] = {
441 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,
442 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,
443 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,
444 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,
445 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,
446 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,
447 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,
448 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,
451 static inline unsigned char
452 utf8_char_length(const char *string, const char *end)
454 int c = *(unsigned char *) string;
456 return utf8_bytes[c];
459 /* Decode UTF-8 multi-byte representation into a Unicode character. */
460 static inline unsigned long
461 utf8_to_unicode(const char *string, size_t length)
463 unsigned long unicode;
465 switch (length) {
466 case 1:
467 unicode = string[0];
468 break;
469 case 2:
470 unicode = (string[0] & 0x1f) << 6;
471 unicode += (string[1] & 0x3f);
472 break;
473 case 3:
474 unicode = (string[0] & 0x0f) << 12;
475 unicode += ((string[1] & 0x3f) << 6);
476 unicode += (string[2] & 0x3f);
477 break;
478 case 4:
479 unicode = (string[0] & 0x0f) << 18;
480 unicode += ((string[1] & 0x3f) << 12);
481 unicode += ((string[2] & 0x3f) << 6);
482 unicode += (string[3] & 0x3f);
483 break;
484 case 5:
485 unicode = (string[0] & 0x0f) << 24;
486 unicode += ((string[1] & 0x3f) << 18);
487 unicode += ((string[2] & 0x3f) << 12);
488 unicode += ((string[3] & 0x3f) << 6);
489 unicode += (string[4] & 0x3f);
490 break;
491 case 6:
492 unicode = (string[0] & 0x01) << 30;
493 unicode += ((string[1] & 0x3f) << 24);
494 unicode += ((string[2] & 0x3f) << 18);
495 unicode += ((string[3] & 0x3f) << 12);
496 unicode += ((string[4] & 0x3f) << 6);
497 unicode += (string[5] & 0x3f);
498 break;
499 default:
500 return 0;
503 /* Invalid characters could return the special 0xfffd value but NUL
504 * should be just as good. */
505 return unicode > 0xffff ? 0 : unicode;
508 /* Calculates how much of string can be shown within the given maximum width
509 * and sets trimmed parameter to non-zero value if all of string could not be
510 * shown. If the reserve flag is TRUE, it will reserve at least one
511 * trailing character, which can be useful when drawing a delimiter.
513 * Returns the number of bytes to output from string to satisfy max_width. */
514 static inline size_t
515 utf8_length(const char **start, size_t skip, int *width, size_t max_width, int *trimmed, bool reserve, int tab_size)
517 const char *string = *start;
518 const char *end = strchr(string, '\0');
519 unsigned char last_bytes = 0;
520 size_t last_ucwidth = 0;
522 *width = 0;
523 *trimmed = 0;
525 while (string < end) {
526 unsigned char bytes = utf8_char_length(string, end);
527 size_t ucwidth;
528 unsigned long unicode;
530 if (string + bytes > end)
531 break;
533 /* Change representation to figure out whether
534 * it is a single- or double-width character. */
536 unicode = utf8_to_unicode(string, bytes);
537 /* FIXME: Graceful handling of invalid Unicode character. */
538 if (!unicode)
539 break;
541 ucwidth = unicode_width(unicode, tab_size);
542 if (skip > 0) {
543 skip -= ucwidth <= skip ? ucwidth : skip;
544 *start += bytes;
546 *width += ucwidth;
547 if (*width > max_width) {
548 *trimmed = 1;
549 *width -= ucwidth;
550 if (reserve && *width == max_width) {
551 string -= last_bytes;
552 *width -= last_ucwidth;
554 break;
557 string += bytes;
558 last_bytes = ucwidth ? bytes : 0;
559 last_ucwidth = ucwidth;
562 return string - *start;
565 #endif