]> git.draconx.ca Git - liblbx.git/blob - src/tools.c
Trivial manual fixes.
[liblbx.git] / src / tools.c
1 /*
2  * 2ooM: The Master of Orion II Reverse Engineering Project
3  * Helper functions for liblbx command-line applications.
4  * Copyright © 2013 Nick Bowler
5  *
6  * This program is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include <config.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <errno.h>
25 #include <stdarg.h>
26 #include <limits.h>
27 #include <inttypes.h>
28 #include <assert.h>
29
30 #include "tools.h"
31
32 static const char *progname, *argv0;
33
34 void tool_init(const char *name, int argc, char **argv)
35 {
36         progname = name;
37         argv0 = argv[0] ? argv[0] : progname;
38 }
39
40 void tool_version(void)
41 {
42         assert(argv0 != NULL);
43         printf("%s (%s) %s\n", progname, PACKAGE_NAME, PACKAGE_VERSION);
44         printf("Copyright (C) 2013 Nick Bowler.\n");
45         puts("License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.");
46         puts("This is free software: you are free to change and redistribute it.");
47         puts("There is NO WARRANTY, to the extent permitted by law.");
48 }
49
50 const char *tool_invocation(void)
51 {
52         assert(argv0 != NULL);
53         return argv0;
54 }
55
56 /* Saturating addition. */
57 static size_t add_size(size_t a, size_t b)
58 {
59         if (a >= (size_t)-1 - b)
60                 return (size_t)-1;
61         return a + b;
62 }
63
64 static int vfmsg_internal(FILE *f, int err, const char *fmt, va_list ap)
65 {
66         size_t invokelen, fmtlen, errlen, totlen;
67         char *newfmt, *errmsg;
68         int rc;
69
70         invokelen = strlen(tool_invocation());
71         fmtlen = fmt ? strlen(fmt) : 0;
72         errlen = err > 0 ? strlen(errmsg = strerror(err)) : 0;
73
74         totlen = add_size(invokelen, sizeof "\n");
75         if (fmtlen > 0) {
76                 totlen = add_size(totlen, strlen(": "));
77                 totlen = add_size(totlen, fmtlen);
78         }
79         if (errlen > 0) {
80                 totlen = add_size(totlen, strlen(": "));
81                 totlen = add_size(totlen, errlen);
82         }
83
84         if (totlen == (size_t)-1 || totlen > INT_MAX)
85                 return -1;
86
87         newfmt = malloc(totlen);
88         if (!newfmt)
89                 return -1;
90
91         if (errlen && fmtlen)
92                 rc = sprintf(newfmt, "%s: %s: %s\n", argv0, fmt, errmsg);
93         else if (errlen)
94                 rc = sprintf(newfmt, "%s: %s\n", argv0, errmsg);
95         else if (fmtlen)
96                 rc = sprintf(newfmt, "%s: %s\n", argv0, fmt);
97         else
98                 rc = sprintf(newfmt, "%s\n", argv0);
99
100         assert(rc < totlen);
101         if (rc < 0)
102                 goto out;
103
104         rc = vfprintf(f, newfmt, ap);
105 out:
106         free(newfmt);
107         return rc;
108 }
109
110 int tool_vmsg(const char *fmt, va_list ap)
111 {
112         return vfmsg_internal(stdout, -1, fmt, ap);
113 }
114
115 int tool_verr(int err, const char *fmt, va_list ap)
116 {
117         return vfmsg_internal(stderr, err == 0 ? errno : err, fmt, ap);
118 }
119
120 int tool_msg(const char *fmt, ...)
121 {
122         va_list ap;
123         int rc;
124
125         va_start(ap, fmt);
126         rc = tool_vmsg(fmt, ap);
127         va_end(ap);
128
129         return rc;
130 }
131
132 int tool_err(int err, const char *fmt, ...)
133 {
134         va_list ap;
135         int rc;
136
137         va_start(ap, fmt);
138         rc = tool_verr(err, fmt, ap);
139         va_end(ap);
140
141         return rc;
142 }