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.
21 static const char *status_messages
[] = {
23 #define STATUS_CODE_MESSAGE(name, msg) msg
24 STATUS_CODE_INFO(STATUS_CODE_MESSAGE
)
28 get_status_message(enum status_code code
)
32 return status_messages
[code
];
36 warn(const char *msg
, ...)
41 fputs("tig warning: ", stderr
);
42 vfprintf(stderr
, msg
, args
);
47 die_fn die_callback
= NULL
;
49 die(const char *err
, ...)
57 fputs("tig: ", stderr
);
58 vfprintf(stderr
, err
, args
);
66 * Git data formatters and parsers.
70 timecmp(const struct time
*t1
, const struct time
*t2
)
72 return t1
->sec
- t2
->sec
;
76 mkdate(const struct time
*time
, enum date date
)
78 static char buf
[DATE_WIDTH
+ 1];
79 static const struct enum_map_entry reldate
[] = {
80 { "second", 1, 60 * 2 },
81 { "minute", 60, 60 * 60 * 2 },
82 { "hour", 60 * 60, 60 * 60 * 24 * 2 },
83 { "day", 60 * 60 * 24, 60 * 60 * 24 * 7 * 2 },
84 { "week", 60 * 60 * 24 * 7, 60 * 60 * 24 * 7 * 5 },
85 { "month", 60 * 60 * 24 * 30, 60 * 60 * 24 * 365 },
86 { "year", 60 * 60 * 24 * 365, 0 },
90 if (!date
|| !time
|| !time
->sec
)
93 if (date
== DATE_RELATIVE
) {
95 time_t date
= time
->sec
+ time
->tz
;
99 gettimeofday(&now
, NULL
);
100 seconds
= now
.tv_sec
< date
? date
- now
.tv_sec
: now
.tv_sec
- date
;
101 for (i
= 0; i
< ARRAY_SIZE(reldate
); i
++) {
102 if (seconds
>= reldate
[i
].value
&& reldate
[i
].value
)
105 seconds
/= reldate
[i
].namelen
;
106 if (!string_format(buf
, "%ld %s%s %s",
107 seconds
, reldate
[i
].name
,
108 seconds
> 1 ? "s" : "",
109 now
.tv_sec
>= date
? "ago" : "ahead"))
115 if (date
== DATE_LOCAL
) {
116 time_t date
= time
->sec
+ time
->tz
;
117 localtime_r(&date
, &tm
);
120 gmtime_r(&time
->sec
, &tm
);
122 return strftime(buf
, sizeof(buf
), DATE_FORMAT
, &tm
) ? buf
: NULL
;
126 mkfilesize(unsigned long size
, enum file_size format
)
128 static char buf
[64 + 1];
129 static const char relsize
[] = {
130 'B', 'K', 'M', 'G', 'T', 'P'
136 if (format
== FILE_SIZE_UNITS
) {
137 const char *fmt
= "%.0f%c";
141 for (i
= 0; i
< ARRAY_SIZE(relsize
); i
++) {
142 if (rsize
> 1024.0 && i
+ 1 < ARRAY_SIZE(relsize
)) {
151 return string_format(buf
, fmt
, rsize
, relsize
[i
])
156 return string_format(buf
, "%ld", size
) ? buf
: NULL
;
159 const struct ident unknown_ident
= { "Unknown", "unknown@localhost" };
162 ident_compare(const struct ident
*i1
, const struct ident
*i2
)
165 return (!!i1
) - (!!i2
);
166 if (!i1
->name
|| !i2
->name
)
167 return (!!i1
->name
) - (!!i2
->name
);
168 return strcmp(i1
->name
, i2
->name
);
172 get_author_initials(const char *author
)
174 static char initials
[256];
176 const char *end
= strchr(author
, '\0');
178 #define is_initial_sep(c) (isspace(c) || ispunct(c) || (c) == '@' || (c) == '-')
180 memset(initials
, 0, sizeof(initials
));
181 while (author
< end
) {
185 while (author
< end
&& is_initial_sep(*author
))
188 bytes
= utf8_char_length(author
, end
);
189 if (bytes
>= sizeof(initials
) - 1 - pos
)
192 initials
[pos
++] = *author
++;
196 while (author
< end
&& !is_initial_sep(*author
)) {
197 bytes
= utf8_char_length(author
, end
);
198 if (bytes
>= sizeof(initials
) - 1 - i
) {
199 while (author
< end
&& !is_initial_sep(*author
))
204 initials
[i
++] = *author
++;
215 get_email_user(const char *email
)
217 static char user
[SIZEOF_STR
+ 1];
218 const char *end
= strchr(email
, '@');
219 int length
= end
? end
- email
: strlen(email
);
221 string_format(user
, "%.*s%c", length
, email
, 0);
226 mkauthor(const struct ident
*ident
, int cols
, enum author author
)
228 bool trim
= author_trim(cols
);
229 bool abbreviate
= author
== AUTHOR_ABBREVIATED
|| !trim
;
231 if (author
== AUTHOR_NO
|| !ident
)
233 if (author
== AUTHOR_EMAIL
&& ident
->email
)
235 if (author
== AUTHOR_EMAIL_USER
&& ident
->email
)
236 return get_email_user(ident
->email
);
237 if (abbreviate
&& ident
->name
)
238 return get_author_initials(ident
->name
);
247 else if (S_ISLNK(mode
))
249 else if (S_ISGITLINK(mode
))
251 else if (S_ISREG(mode
) && mode
& S_IXUSR
)
253 else if (S_ISREG(mode
))
259 /* vim: set ts=8 sw=8 noexpandtab: */