Remove the dont_free line struct flag in favor of custom help_done
[tig.git] / tig.h
blob615ac1d1c901c9e5e57f3baede0bb37e9ea57a72
1 /* Copyright (c) 2006-2013 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 #include "compat/compat.h"
23 #ifndef TIG_VERSION
24 #define TIG_VERSION "unknown-version"
25 #endif
27 #ifndef DEBUG
28 #define NDEBUG
29 #endif
31 /* necessary on Snow Leopard to use WINDOW struct */
32 #ifdef NCURSES_OPAQUE
33 #undef NCURSES_OPAQUE
34 #endif
35 #define NCURSES_OPAQUE 0
38 #include <assert.h>
39 #include <errno.h>
40 #include <ctype.h>
41 #include <signal.h>
42 #include <stdarg.h>
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <string.h>
46 #include <sys/types.h>
47 #include <sys/wait.h>
48 #include <sys/stat.h>
49 #include <sys/select.h>
50 #include <unistd.h>
51 #include <sys/time.h>
52 #include <time.h>
53 #include <fcntl.h>
55 #include <regex.h>
57 #include <locale.h>
58 #include <langinfo.h>
59 #include <iconv.h>
61 /* ncurses(3): Must be defined to have extended wide-character functions. */
62 #define _XOPEN_SOURCE_EXTENDED
64 #if defined HAVE_NCURSESW_CURSES_H
65 # include <ncursesw/curses.h>
66 #elif defined HAVE_NCURSESW_H
67 # include <ncursesw.h>
68 #elif defined HAVE_NCURSES_CURSES_H
69 # include <ncurses/curses.h>
70 #elif defined HAVE_NCURSES_H
71 # include <ncurses.h>
72 #elif defined HAVE_CURSES_H
73 # include <curses.h>
74 #else
75 #ifdef WARN_MISSING_CURSES_CONFIGURATION
76 # warning SysV or X/Open-compatible Curses installation is required.
77 # warning Will assume Curses is found in default include and library path.
78 # warning To fix any build issues please use autotools to configure Curses.
79 # warning See INSTALL file for instructions.
80 #endif
81 # include <curses.h>
82 #endif
84 #if __GNUC__ >= 3
85 #define TIG_NORETURN __attribute__((__noreturn__))
86 #define PRINTF_LIKE(fmt, args) __attribute__((format (printf, fmt, args)))
87 #else
88 #define TIG_NORETURN
89 #define PRINTF_LIKE(fmt, args)
90 #endif
92 #define ABS(x) ((x) >= 0 ? (x) : -(x))
93 #define MIN(x, y) ((x) < (y) ? (x) : (y))
94 #define MAX(x, y) ((x) > (y) ? (x) : (y))
96 #define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
97 #define STRING_SIZE(x) (sizeof(x) - 1)
99 #define SIZEOF_STR 1024 /* Default string size. */
100 #define SIZEOF_REF 256 /* Size of symbolic or SHA1 ID. */
101 #define SIZEOF_REV 41 /* Holds a SHA-1 and an ending NUL. */
102 #define SIZEOF_ARG 32 /* Default argument array size. */
104 /* This color name can be used to refer to the default term colors. */
105 #define COLOR_DEFAULT (-1)
107 #define ENCODING_UTF8 "UTF-8"
108 #define ENCODING_SEP ": encoding: "
109 #define ENCODING_ARG "--encoding=" ENCODING_UTF8
111 #define ICONV_NONE ((iconv_t) -1)
112 #ifndef ICONV_CONST
113 #define ICONV_CONST /* nothing */
114 #endif
115 #define ICONV_TRANSLIT "//TRANSLIT//IGNORE"
117 /* The format and size of the date column in the main view. */
118 #define DATE_FORMAT "%Y-%m-%d %H:%M"
119 #define DATE_WIDTH STRING_SIZE("2006-04-29 14:21")
120 #define DATE_SHORT_WIDTH STRING_SIZE("2006-04-29")
122 #define ID_WIDTH 7
123 #define AUTHOR_WIDTH 18
124 #define FILENAME_WIDTH 18
126 #define MIN_VIEW_HEIGHT 4
127 #define MIN_VIEW_WIDTH 4
129 #define NULL_ID "0000000000000000000000000000000000000000"
131 #define S_ISGITLINK(mode) (((mode) & S_IFMT) == 0160000)
133 /* Some ASCII-shorthands fitted into the ncurses namespace. */
134 #define KEY_CTL(x) ((x) & 0x1f) /* KEY_CTL(A) == ^A == \1 */
135 #define KEY_TAB '\t'
136 #define KEY_RETURN '\r'
137 #define KEY_ESC 27
140 * Allocation helpers ... Entering macro hell to never be seen again.
143 #define DEFINE_ALLOCATOR(name, type, chunk_size) \
144 static type * \
145 name(type **mem, size_t size, size_t increase) \
147 size_t num_chunks = (size + chunk_size - 1) / chunk_size; \
148 size_t num_chunks_new = (size + increase + chunk_size - 1) / chunk_size;\
149 type *tmp = *mem; \
151 if (mem == NULL || num_chunks != num_chunks_new) { \
152 size_t newsize = num_chunks_new * chunk_size * sizeof(type); \
154 tmp = realloc(tmp, newsize); \
155 if (tmp) { \
156 *mem = tmp; \
157 if (num_chunks_new > num_chunks) { \
158 size_t offset = num_chunks * chunk_size; \
159 size_t oldsize = offset * sizeof(type); \
161 memset(tmp + offset, 0, newsize - oldsize); \
166 return tmp; \
170 * Strings.
173 #define prefixcmp(str1, str2) \
174 strncmp(str1, str2, STRING_SIZE(str2))
176 static inline bool
177 string_isnumber(const char *str)
179 int pos;
181 for (pos = 0; str[pos]; pos++) {
182 if (!isdigit(str[pos]))
183 return FALSE;
186 return pos > 0;
189 static inline bool
190 iscommit(char *str)
192 int pos;
194 for (pos = 0; str[pos]; pos++) {
195 if (!isxdigit(str[pos]))
196 return FALSE;
199 return 7 <= pos && pos < SIZEOF_REV;
202 static inline int
203 ascii_toupper(int c)
205 if (c >= 'a' && c <= 'z')
206 c &= ~0x20;
207 return c;
210 static inline int
211 ascii_tolower(int c)
213 if (c >= 'A' && c <= 'Z')
214 c |= 0x20;
215 return c;
218 static inline int
219 suffixcmp(const char *str, int slen, const char *suffix)
221 size_t len = slen >= 0 ? slen : strlen(str);
222 size_t suffixlen = strlen(suffix);
224 return suffixlen < len ? strcmp(str + len - suffixlen, suffix) : -1;
227 static inline void
228 string_ncopy_do(char *dst, size_t dstlen, const char *src, size_t srclen)
230 if (srclen > dstlen - 1)
231 srclen = dstlen - 1;
233 strncpy(dst, src, srclen);
234 dst[srclen] = 0;
237 /* Shorthands for safely copying into a fixed buffer. */
239 #define FORMAT_BUFFER(buf, bufsize, fmt, retval, allow_truncate) \
240 do { \
241 va_list args; \
242 va_start(args, fmt); \
243 retval = vsnprintf(buf, bufsize, fmt, args); \
244 va_end(args); \
245 if (retval >= (bufsize) && allow_truncate) { \
246 (buf)[(bufsize) - 1] = 0; \
247 (buf)[(bufsize) - 2] = '.'; \
248 (buf)[(bufsize) - 3] = '.'; \
249 (buf)[(bufsize) - 4] = '.'; \
250 retval = (bufsize) - 1; \
251 } else if (retval < 0 || retval >= (bufsize)) { \
252 retval = -1; \
254 } while (0)
256 #define string_copy(dst, src) \
257 string_ncopy_do(dst, sizeof(dst), src, sizeof(src))
259 #define string_ncopy(dst, src, srclen) \
260 string_ncopy_do(dst, sizeof(dst), src, srclen)
262 static inline void
263 string_copy_rev(char *dst, const char *src)
265 size_t srclen;
267 if (!*src)
268 return;
270 for (srclen = 0; srclen < SIZEOF_REV; srclen++)
271 if (isspace(src[srclen]))
272 break;
274 string_ncopy_do(dst, SIZEOF_REV, src, srclen);
277 static inline void
278 string_copy_rev_from_commit_line(char *dst, const char *src)
280 string_copy_rev(dst, src + STRING_SIZE("commit "));
283 #define string_rev_is_null(rev) !strncmp(rev, NULL_ID, STRING_SIZE(NULL_ID))
285 #define string_add(dst, from, src) \
286 string_ncopy_do(dst + (from), sizeof(dst) - (from), src, sizeof(src))
288 static inline size_t
289 string_expanded_length(const char *src, size_t srclen, size_t tabsize, size_t max_size)
291 size_t size, pos;
293 for (size = pos = 0; pos < srclen && size < max_size; pos++) {
294 if (src[pos] == '\t') {
295 size_t expanded = tabsize - (size % tabsize);
297 size += expanded;
298 } else {
299 size++;
303 return pos;
306 static inline size_t
307 string_expand(char *dst, size_t dstlen, const char *src, int tabsize)
309 size_t size, pos;
311 for (size = pos = 0; size < dstlen - 1 && src[pos]; pos++) {
312 if (src[pos] == '\t') {
313 size_t expanded = tabsize - (size % tabsize);
315 if (expanded + size >= dstlen - 1)
316 expanded = dstlen - size - 1;
317 memcpy(dst + size, " ", expanded);
318 size += expanded;
319 } else {
320 dst[size++] = src[pos];
324 dst[size] = 0;
325 return pos;
328 static inline char *
329 chomp_string(char *name)
331 int namelen;
333 while (isspace(*name))
334 name++;
336 namelen = strlen(name) - 1;
337 while (namelen > 0 && isspace(name[namelen]))
338 name[namelen--] = 0;
340 return name;
343 static inline bool PRINTF_LIKE(4, 5)
344 string_nformat(char *buf, size_t bufsize, size_t *bufpos, const char *fmt, ...)
346 size_t pos = bufpos ? *bufpos : 0;
347 int retval;
349 FORMAT_BUFFER(buf + pos, bufsize - pos, fmt, retval, FALSE);
350 if (bufpos && retval > 0)
351 *bufpos = pos + retval;
353 return pos >= bufsize ? FALSE : TRUE;
356 #define string_format(buf, fmt, args...) \
357 string_nformat(buf, sizeof(buf), NULL, fmt, args)
359 #define string_format_size(buf, size, fmt, args...) \
360 string_nformat(buf, size, NULL, fmt, args)
362 #define string_format_from(buf, from, fmt, args...) \
363 string_nformat(buf, sizeof(buf), from, fmt, args)
365 static inline int
366 strcmp_null(const char *s1, const char *s2)
368 if (!s1 || !s2) {
369 return (!!s1) - (!!s2);
372 return strcmp(s1, s2);
376 * Enumerations
379 struct enum_map {
380 const char *name;
381 int namelen;
382 int value;
385 #define ENUM_MAP(name, value) { name, STRING_SIZE(name), value }
387 #define ENUM_SYM_MACRO(prefix, name) prefix##_##name
388 #define ENUM_MAP_MACRO(prefix, name) ENUM_MAP(#name, ENUM_SYM_MACRO(prefix, name))
390 #define DEFINE_ENUM(name, info) \
391 enum name { info(ENUM_SYM_MACRO) }; \
392 static const struct enum_map name##_map[] = { info(ENUM_MAP_MACRO) }
394 static inline int
395 string_enum_compare(const char *str1, const char *str2, int len)
397 size_t i;
399 #define string_enum_sep(x) ((x) == '-' || (x) == '_' || (x) == '.')
401 /* Diff-Header == DIFF_HEADER */
402 for (i = 0; i < len; i++) {
403 if (ascii_toupper(str1[i]) == ascii_toupper(str2[i]))
404 continue;
406 if (string_enum_sep(str1[i]) &&
407 string_enum_sep(str2[i]))
408 continue;
410 return str1[i] - str2[i];
413 return 0;
416 #define enum_equals(entry, str, len) \
417 ((entry).namelen == (len) && !string_enum_compare((entry).name, str, len))
419 static inline char *
420 enum_map_name(const char *name, size_t namelen)
422 static char buf[SIZEOF_STR];
423 int bufpos;
425 for (bufpos = 0; bufpos <= namelen; bufpos++) {
426 buf[bufpos] = ascii_tolower(name[bufpos]);
427 if (buf[bufpos] == '_')
428 buf[bufpos] = '-';
431 buf[bufpos] = 0;
432 return buf;
435 #define enum_name(entry) enum_map_name((entry).name, (entry).namelen)
437 static inline bool
438 map_enum_do(const struct enum_map *map, size_t map_size, int *value, const char *name)
440 size_t namelen = strlen(name);
441 int i;
443 for (i = 0; i < map_size; i++)
444 if (enum_equals(map[i], name, namelen)) {
445 *value = map[i].value;
446 return TRUE;
449 return FALSE;
452 #define map_enum(attr, map, name) \
453 map_enum_do(map, ARRAY_SIZE(map), attr, name)
456 * Unicode / UTF-8 handling
458 * NOTE: Much of the following code for dealing with Unicode is derived from
459 * ELinks' UTF-8 code developed by Scrool <scroolik@gmail.com>. Origin file is
460 * src/intl/charset.c from the UTF-8 branch commit elinks-0.11.0-g31f2c28.
463 static inline int
464 unicode_width(unsigned long c, int tab_size)
466 if (c >= 0x1100 &&
467 (c <= 0x115f /* Hangul Jamo */
468 || c == 0x2329
469 || c == 0x232a
470 || (c >= 0x2e80 && c <= 0xa4cf && c != 0x303f)
471 /* CJK ... Yi */
472 || (c >= 0xac00 && c <= 0xd7a3) /* Hangul Syllables */
473 || (c >= 0xf900 && c <= 0xfaff) /* CJK Compatibility Ideographs */
474 || (c >= 0xfe30 && c <= 0xfe6f) /* CJK Compatibility Forms */
475 || (c >= 0xff00 && c <= 0xff60) /* Fullwidth Forms */
476 || (c >= 0xffe0 && c <= 0xffe6)
477 || (c >= 0x20000 && c <= 0x2fffd)
478 || (c >= 0x30000 && c <= 0x3fffd)))
479 return 2;
481 if ((c >= 0x0300 && c <= 0x036f) /* combining diacretical marks */
482 || (c >= 0x1dc0 && c <= 0x1dff) /* combining diacretical marks supplement */
483 || (c >= 0x20d0 && c <= 0x20ff) /* combining diacretical marks for symbols */
484 || (c >= 0xfe20 && c <= 0xfe2f)) /* combining half marks */
485 return 0;
487 if (c == '\t')
488 return tab_size;
490 return 1;
493 /* Number of bytes used for encoding a UTF-8 character indexed by first byte.
494 * Illegal bytes are set one. */
495 static const unsigned char utf8_bytes[256] = {
496 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,
497 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,
498 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,
499 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,
500 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,
501 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,
502 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,
503 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,
506 static inline unsigned char
507 utf8_char_length(const char *string, const char *end)
509 int c = *(unsigned char *) string;
511 return utf8_bytes[c];
514 /* Decode UTF-8 multi-byte representation into a Unicode character. */
515 static inline unsigned long
516 utf8_to_unicode(const char *string, size_t length)
518 unsigned long unicode;
520 switch (length) {
521 case 1:
522 unicode = string[0];
523 break;
524 case 2:
525 unicode = (string[0] & 0x1f) << 6;
526 unicode += (string[1] & 0x3f);
527 break;
528 case 3:
529 unicode = (string[0] & 0x0f) << 12;
530 unicode += ((string[1] & 0x3f) << 6);
531 unicode += (string[2] & 0x3f);
532 break;
533 case 4:
534 unicode = (string[0] & 0x0f) << 18;
535 unicode += ((string[1] & 0x3f) << 12);
536 unicode += ((string[2] & 0x3f) << 6);
537 unicode += (string[3] & 0x3f);
538 break;
539 case 5:
540 unicode = (string[0] & 0x0f) << 24;
541 unicode += ((string[1] & 0x3f) << 18);
542 unicode += ((string[2] & 0x3f) << 12);
543 unicode += ((string[3] & 0x3f) << 6);
544 unicode += (string[4] & 0x3f);
545 break;
546 case 6:
547 unicode = (string[0] & 0x01) << 30;
548 unicode += ((string[1] & 0x3f) << 24);
549 unicode += ((string[2] & 0x3f) << 18);
550 unicode += ((string[3] & 0x3f) << 12);
551 unicode += ((string[4] & 0x3f) << 6);
552 unicode += (string[5] & 0x3f);
553 break;
554 default:
555 return 0;
558 /* Invalid characters could return the special 0xfffd value but NUL
559 * should be just as good. */
560 return unicode > 0xffff ? 0 : unicode;
563 /* Calculates how much of string can be shown within the given maximum width
564 * and sets trimmed parameter to non-zero value if all of string could not be
565 * shown. If the reserve flag is TRUE, it will reserve at least one
566 * trailing character, which can be useful when drawing a delimiter.
568 * Returns the number of bytes to output from string to satisfy max_width. */
569 static inline size_t
570 utf8_length(const char **start, size_t skip, int *width, size_t max_width, int *trimmed, bool reserve, int tab_size)
572 const char *string = *start;
573 const char *end = strchr(string, '\0');
574 unsigned char last_bytes = 0;
575 size_t last_ucwidth = 0;
577 *width = 0;
578 *trimmed = 0;
580 while (string < end) {
581 unsigned char bytes = utf8_char_length(string, end);
582 size_t ucwidth;
583 unsigned long unicode;
585 if (string + bytes > end)
586 break;
588 /* Change representation to figure out whether
589 * it is a single- or double-width character. */
591 unicode = utf8_to_unicode(string, bytes);
592 /* FIXME: Graceful handling of invalid Unicode character. */
593 if (!unicode)
594 break;
596 ucwidth = unicode_width(unicode, tab_size);
597 if (skip > 0) {
598 skip -= ucwidth <= skip ? ucwidth : skip;
599 *start += bytes;
601 *width += ucwidth;
602 if (*width > max_width) {
603 *trimmed = 1;
604 *width -= ucwidth;
605 if (reserve && *width == max_width) {
606 string -= last_bytes;
607 *width -= last_ucwidth;
609 break;
612 string += bytes;
613 last_bytes = ucwidth ? bytes : 0;
614 last_ucwidth = ucwidth;
617 return string - *start;
620 #endif
622 /* vim: set ts=8 sw=8 noexpandtab: */