aboutsummaryrefslogtreecommitdiff
path: root/miscutils
diff options
context:
space:
mode:
Diffstat (limited to 'miscutils')
-rw-r--r--miscutils/bbconfig.c1
-rw-r--r--miscutils/bc.c18
-rw-r--r--miscutils/dc.c2
-rw-r--r--miscutils/drop.c220
-rw-r--r--miscutils/iconv.c1771
-rw-r--r--miscutils/inotifyd.c211
-rw-r--r--miscutils/jn.c37
-rw-r--r--miscutils/less.c99
-rw-r--r--miscutils/make.c3382
-rw-r--r--miscutils/man.c31
-rw-r--r--miscutils/time.c51
-rw-r--r--miscutils/ts.c8
12 files changed, 5827 insertions, 4 deletions
diff --git a/miscutils/bbconfig.c b/miscutils/bbconfig.c
index fe02516a8..077e03c5d 100644
--- a/miscutils/bbconfig.c
+++ b/miscutils/bbconfig.c
@@ -35,6 +35,7 @@
35#include "libbb.h" 35#include "libbb.h"
36#include "bbconfigopts.h" 36#include "bbconfigopts.h"
37#if ENABLE_FEATURE_COMPRESS_BBCONFIG 37#if ENABLE_FEATURE_COMPRESS_BBCONFIG
38#define BB_ARCHIVE_PUBLIC
38# include "bb_archive.h" 39# include "bb_archive.h"
39# include "bbconfigopts_bz2.h" 40# include "bbconfigopts_bz2.h"
40#endif 41#endif
diff --git a/miscutils/bc.c b/miscutils/bc.c
index 28bc40c8b..31485ae9c 100644
--- a/miscutils/bc.c
+++ b/miscutils/bc.c
@@ -203,6 +203,9 @@
203 203
204#include "libbb.h" 204#include "libbb.h"
205#include "common_bufsiz.h" 205#include "common_bufsiz.h"
206#if ENABLE_PLATFORM_MINGW32
207# include "BB_VER.h"
208#endif
206 209
207#if !ENABLE_BC && !ENABLE_FEATURE_DC_BIG 210#if !ENABLE_BC && !ENABLE_FEATURE_DC_BIG
208# include "dc.c" 211# include "dc.c"
@@ -7466,6 +7469,17 @@ static unsigned xc_vm_envLen(const char *var)
7466 return len; 7469 return len;
7467} 7470}
7468 7471
7472#if ENABLE_PLATFORM_MINGW32 && ENABLE_FEATURE_BC_INTERACTIVE
7473static BOOL WINAPI ctrl_handler(DWORD dwCtrlType)
7474{
7475 if (dwCtrlType == CTRL_C_EVENT || dwCtrlType == CTRL_BREAK_EVENT) {
7476 bb_got_signal = SIGINT;
7477 return TRUE;
7478 }
7479 return FALSE;
7480}
7481#endif
7482
7469static int xc_vm_init(const char *env_len) 7483static int xc_vm_init(const char *env_len)
7470{ 7484{
7471 G.prog.len = xc_vm_envLen(env_len); 7485 G.prog.len = xc_vm_envLen(env_len);
@@ -7491,7 +7505,11 @@ static int xc_vm_init(const char *env_len)
7491 // from stdin is not interrupted by ^C either, 7505 // from stdin is not interrupted by ^C either,
7492 // it restarts, thus fgetc() does not return on ^C. 7506 // it restarts, thus fgetc() does not return on ^C.
7493 // (This problem manifests only if line editing is disabled) 7507 // (This problem manifests only if line editing is disabled)
7508# if !ENABLE_PLATFORM_MINGW32
7494 signal_SA_RESTART_empty_mask(SIGINT, record_signo); 7509 signal_SA_RESTART_empty_mask(SIGINT, record_signo);
7510# else
7511 SetConsoleCtrlHandler(ctrl_handler, TRUE);
7512# endif
7495 7513
7496 // Without SA_RESTART, this exhibits a bug: 7514 // Without SA_RESTART, this exhibits a bug:
7497 // "while (1) print 1" and try ^C-ing it. 7515 // "while (1) print 1" and try ^C-ing it.
diff --git a/miscutils/dc.c b/miscutils/dc.c
index 42baa67ad..d6369fd15 100644
--- a/miscutils/dc.c
+++ b/miscutils/dc.c
@@ -17,7 +17,7 @@ typedef unsigned long data_t;
17#define DATA_FMT "l" 17#define DATA_FMT "l"
18#else 18#else
19typedef unsigned long long data_t; 19typedef unsigned long long data_t;
20#define DATA_FMT "ll" 20#define DATA_FMT LL_FMT
21#endif 21#endif
22 22
23struct globals { 23struct globals {
diff --git a/miscutils/drop.c b/miscutils/drop.c
new file mode 100644
index 000000000..bef1fa52b
--- /dev/null
+++ b/miscutils/drop.c
@@ -0,0 +1,220 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * drop - run a command without elevated privileges.
4 *
5 * Copyright (c) 2023 Ronald M Yorston
6 *
7 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
8 */
9//config:config DROP
10//config: bool "drop"
11//config: default y
12//config: depends on PLATFORM_MINGW32 && SH_IS_ASH
13//config: help
14//config: Run a command without elevated privileges
15
16//config:config CDROP
17//config: bool "cdrop"
18//config: default y
19//config: depends on PLATFORM_MINGW32
20//config: help
21//config: Run a command without elevated privileges using cmd.exe
22
23//config:config PDROP
24//config: bool "pdrop"
25//config: default y
26//config: depends on PLATFORM_MINGW32
27//config: help
28//config: Run a command without elevated privileges using PowerShell
29
30//applet:IF_DROP(APPLET(drop, BB_DIR_USR_BIN, BB_SUID_DROP))
31//applet:IF_CDROP(APPLET_ODDNAME(cdrop, drop, BB_DIR_USR_BIN, BB_SUID_DROP, cdrop))
32//applet:IF_PDROP(APPLET_ODDNAME(pdrop, drop, BB_DIR_USR_BIN, BB_SUID_DROP, pdrop))
33
34//kbuild:lib-$(CONFIG_DROP) += drop.o
35//kbuild:lib-$(CONFIG_CDROP) += drop.o
36//kbuild:lib-$(CONFIG_PDROP) += drop.o
37
38//usage:#define drop_trivial_usage
39//usage: "[COMMAND [ARG...] | [-s SHELL] -c CMD_STRING [ARG...]]"
40//usage:#define drop_full_usage "\n\n"
41//usage: "Drop elevated privileges and run a command. If no command\n"
42//usage: "is provided run a shell (by default, the BusyBox shell).\n"
43
44//usage:#define cdrop_trivial_usage
45//usage: "[COMMAND [ARG...] | -c CMD_STRING [ARG...]]"
46//usage:#define cdrop_full_usage "\n\n"
47//usage: "Drop elevated privileges and run a command. If no command\n"
48//usage: "is provided run cmd.exe.\n"
49
50//usage:#define pdrop_trivial_usage
51//usage: "[COMMAND [ARG...] | -c CMD_STRING [ARG...]]"
52//usage:#define pdrop_full_usage "\n\n"
53//usage: "Drop elevated privileges and run a command. If no command\n"
54//usage: "is provided run PowerShell.\n"
55
56#include "libbb.h"
57#include <winsafer.h>
58#include <lazyload.h>
59#include "NUM_APPLETS.h"
60
61// Set an environment variable to the name of the unprivileged user,
62// but only if it was previously unset or contained "root".
63static void setenv_name(const char *key)
64{
65 const char *name = get_user_name();
66 const char *oldname = getenv(key);
67
68 if (name && (!oldname || strcmp(oldname, "root") == 0)) {
69 setenv(key, name, 1);
70 }
71}
72
73int drop_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
74int drop_main(int argc UNUSED_PARAM, char **argv)
75{
76 SAFER_LEVEL_HANDLE safer;
77 HANDLE token;
78 STARTUPINFO si;
79 PROCESS_INFORMATION pi;
80 TOKEN_MANDATORY_LABEL TIL;
81 // Medium integrity level S-1-16-8192
82 unsigned char medium[12] = {
83 0x01, 0x01, 0x00, 0x00,
84 0x00, 0x00, 0x00, 0x10,
85 0x00, 0x20, 0x00, 0x00
86 };
87 DWORD code;
88 // This shouldn't be necessary but without it the binary complains
89 // it can't find CreateProcessAsUserA on older versions of Windows.
90 DECLARE_PROC_ADDR(BOOL, CreateProcessAsUserA, HANDLE, LPCSTR, LPSTR,
91 LPSECURITY_ATTRIBUTES, LPSECURITY_ATTRIBUTES, BOOL, DWORD,
92 LPVOID, LPCSTR, LPSTARTUPINFOA, LPPROCESS_INFORMATION);
93
94 if (!INIT_PROC_ADDR(advapi32.dll, CreateProcessAsUserA))
95 bb_simple_error_msg_and_die("not supported");
96
97 /*
98 * Run a shell using a token with reduced privilege. Hints from:
99 *
100 * https://stackoverflow.com/questions/17765568/
101 */
102 if (SaferCreateLevel(SAFER_SCOPEID_USER, SAFER_LEVELID_NORMALUSER,
103 SAFER_LEVEL_OPEN, &safer, NULL) &&
104 SaferComputeTokenFromLevel(safer, NULL, &token, 0, NULL)) {
105
106 // Set medium integrity
107 TIL.Label.Sid = (PSID)medium;
108 TIL.Label.Attributes = SE_GROUP_INTEGRITY;
109 if (SetTokenInformation(token, TokenIntegrityLevel, &TIL,
110 sizeof(TOKEN_MANDATORY_LABEL))) {
111 char *opt_command = NULL;
112 char *opt_shell = NULL;
113 char **a;
114 const char *opt, *arg;
115 char *exe, *cmd, *q;
116
117 if (*applet_name == 'd')
118 getopt32(argv, "c:s:", &opt_command, &opt_shell);
119 else
120 getopt32(argv, "c:", &opt_command);
121 a = argv + optind;
122 opt = "-c";
123
124 if (*a == NULL || opt_command) {
125 switch (*applet_name) {
126#if ENABLE_PDROP
127 case 'p':
128 arg = "powershell.exe";
129 exe = find_first_executable(arg);
130 break;
131#endif
132#if ENABLE_CDROP
133 case 'c':
134 opt = "/c";
135 arg = "cmd.exe";
136 exe = find_first_executable(arg);
137 break;
138#endif
139#if ENABLE_DROP
140 case 'd':
141 if (opt_shell) {
142 arg = bb_basename(opt_shell);
143 if (strcasecmp(arg, "cmd.exe") == 0)
144 opt = "/c";
145 exe = file_is_win32_exe(opt_shell);
146 } else {
147 arg = "sh";
148 exe = xstrdup(bb_busybox_exec_path);
149 }
150 break;
151#endif
152 default:
153 // Never executed, just to silence warnings.
154 arg = argv[0];
155 exe = NULL;
156 break;
157 }
158 } else {
159 arg = *a++;
160
161#if ENABLE_FEATURE_PREFER_APPLETS && NUM_APPLETS > 1
162 if (!has_path(arg) && find_applet_by_name(arg) >= 0) {
163 exe = xstrdup(bb_busybox_exec_path);
164 } else
165#endif
166 if (has_path(arg)) {
167 exe = file_is_win32_exe(arg);
168 } else {
169 exe = find_first_executable(arg);
170 }
171 }
172
173 if (exe == NULL) {
174 xfunc_error_retval = 127;
175 bb_error_msg_and_die("can't find '%s'", arg);
176 }
177
178 slash_to_bs(exe);
179 cmd = quote_arg(arg);
180 if (opt_command) {
181 cmd = xappendword(cmd, opt);
182 q = quote_arg(opt_command);
183 cmd = xappendword(cmd, q);
184 free(q);
185 }
186
187 // Build the command line
188 while (*a) {
189 q = quote_arg(*a++);
190 cmd = xappendword(cmd, q);
191 free(q);
192 }
193
194 ZeroMemory(&si, sizeof(STARTUPINFO));
195 si.cb = sizeof(STARTUPINFO);
196 si.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
197 si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
198 si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
199 si.dwFlags = STARTF_USESTDHANDLES;
200
201 setenv_name("USER");
202 setenv_name("LOGNAME");
203
204 if (!CreateProcessAsUserA(token, exe, cmd, NULL, NULL, TRUE,
205 0, NULL, NULL, &si, &pi)) {
206 xfunc_error_retval = 126;
207 bb_error_msg_and_die("can't execute '%s'", exe);
208 }
209
210 kill_child_ctrl_handler(pi.dwProcessId);
211 SetConsoleCtrlHandler(kill_child_ctrl_handler, TRUE);
212 WaitForSingleObject(pi.hProcess, INFINITE);
213 if (GetExitCodeProcess(pi.hProcess, &code)) {
214 return exit_code_to_posix(code);
215 }
216 }
217 }
218
219 return EXIT_FAILURE;
220}
diff --git a/miscutils/iconv.c b/miscutils/iconv.c
new file mode 100644
index 000000000..bedbb718d
--- /dev/null
+++ b/miscutils/iconv.c
@@ -0,0 +1,1771 @@
1/*
2 * iconv implementation using Win32 API to convert.
3 *
4 * This file is placed in the public domain.
5 */
6
7/*
8 * This code was obtained from:
9 *
10 * https://github.com/win-iconv/win-iconv
11 *
12 * Modified for busybox-w32 by Ronald M Yorston. These modifications
13 * are also dedicated to the public domain.
14 */
15
16//config:config ICONV
17//config: bool "iconv (11.4 kb)"
18//config: default y
19//config: depends on PLATFORM_MINGW32
20//config: help
21//config: 'iconv' converts text between character encodings.
22
23//applet:IF_ICONV(APPLET(iconv, BB_DIR_USR_BIN, BB_SUID_DROP))
24
25//kbuild:lib-$(CONFIG_ICONV) += iconv.o
26
27//usage:#define iconv_trivial_usage
28//usage: "[-lc] [-o outfile] [-f from-enc] [-t to-enc] [FILE]..."
29//usage:#define iconv_full_usage "\n\n"
30//usage: "Convert text between character encodings\n"
31//usage: "\n -l List all known character encodings"
32//usage: "\n -c Silently discard characters that cannot be converted"
33//usage: "\n -o Use outfile for output"
34//usage: "\n -f Use from-enc for input characters"
35//usage: "\n -t Use to-enc for output characters"
36
37#include "libbb.h"
38
39/* WORKAROUND: */
40#define GetProcAddressA GetProcAddress
41
42#define MB_CHAR_MAX 16
43
44#define UNICODE_MODE_BOM_DONE 1
45#define UNICODE_MODE_SWAPPED 2
46
47#define FLAG_USE_BOM 1
48#define FLAG_TRANSLIT 2 /* //TRANSLIT */
49#define FLAG_IGNORE 4 /* //IGNORE */
50
51typedef unsigned char uchar;
52typedef unsigned short ushort;
53typedef unsigned int uint;
54
55typedef void* iconv_t;
56
57static iconv_t iconv_open(const char *tocode, const char *fromcode);
58static int iconv_close(iconv_t cd);
59static size_t iconv(iconv_t cd, const char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft);
60
61typedef struct compat_t compat_t;
62typedef struct csconv_t csconv_t;
63typedef struct rec_iconv_t rec_iconv_t;
64
65typedef int (*f_mbtowc)(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize);
66typedef int (*f_wctomb)(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize);
67typedef int (*f_mblen)(csconv_t *cv, const uchar *buf, int bufsize);
68typedef int (*f_flush)(csconv_t *cv, uchar *buf, int bufsize);
69
70#define COMPAT_IN 1
71#define COMPAT_OUT 2
72
73/* unicode mapping for compatibility with other conversion table. */
74struct compat_t {
75 uint in;
76 uint out;
77 uint flag;
78};
79
80struct csconv_t {
81 int codepage;
82 int flags;
83 f_mbtowc mbtowc;
84 f_wctomb wctomb;
85 f_mblen mblen;
86 f_flush flush;
87 DWORD mode;
88 compat_t *compat;
89};
90
91struct rec_iconv_t {
92 iconv_t cd;
93 csconv_t from;
94 csconv_t to;
95};
96
97static int load_mlang(void);
98static int make_csconv(const char *name, csconv_t *cv);
99static int name_to_codepage(const char *name);
100static uint utf16_to_ucs4(const ushort *wbuf);
101static void ucs4_to_utf16(uint wc, ushort *wbuf, int *wbufsize);
102static int mbtowc_flags(int codepage);
103static int must_use_null_useddefaultchar(int codepage);
104static int seterror(int err);
105
106static int sbcs_mblen(csconv_t *cv, const uchar *buf, int bufsize);
107static int dbcs_mblen(csconv_t *cv, const uchar *buf, int bufsize);
108static int mbcs_mblen(csconv_t *cv, const uchar *buf, int bufsize);
109static int utf8_mblen(csconv_t *cv, const uchar *buf, int bufsize);
110static int eucjp_mblen(csconv_t *cv, const uchar *buf, int bufsize);
111
112static int kernel_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize);
113static int kernel_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize);
114static int mlang_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize);
115static int mlang_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize);
116static int utf16_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize);
117static int utf16_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize);
118static int utf32_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize);
119static int utf32_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize);
120static int iso2022jp_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize);
121static int iso2022jp_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize);
122static int iso2022jp_flush(csconv_t *cv, uchar *buf, int bufsize);
123
124#define CP_ALIAS_LIST \
125 CP_ALIAS(65001, "CP65001") \
126 CP_ALIAS(65001, "UTF8") \
127 CP_ALIAS(65001, "UTF-8") \
128\
129 CP_ALIAS(1200, "CP1200") \
130 CP_ALIAS(1200, "UTF16LE") \
131 CP_ALIAS(1200, "UTF-16LE") \
132 CP_ALIAS(1200, "UCS2LE") \
133 CP_ALIAS(1200, "UCS-2LE") \
134 CP_ALIAS(1200, "UCS-2-INTERNAL") \
135\
136 CP_ALIAS(1201, "CP1201") \
137 CP_ALIAS(1201, "UTF16BE") \
138 CP_ALIAS(1201, "UTF-16BE") \
139 CP_ALIAS(1201, "UCS2BE") \
140 CP_ALIAS(1201, "UCS-2BE") \
141 CP_ALIAS(1201, "unicodeFFFE") \
142\
143 CP_ALIAS(12000, "CP12000") \
144 CP_ALIAS(12000, "UTF32LE") \
145 CP_ALIAS(12000, "UTF-32LE") \
146 CP_ALIAS(12000, "UCS4LE") \
147 CP_ALIAS(12000, "UCS-4LE") \
148\
149 CP_ALIAS(12001, "CP12001") \
150 CP_ALIAS(12001, "UTF32BE") \
151 CP_ALIAS(12001, "UTF-32BE") \
152 CP_ALIAS(12001, "UCS4BE") \
153 CP_ALIAS(12001, "UCS-4BE") \
154\
155 /* Default is little endian, because the platform is */ \
156 CP_ALIAS(1200, "UTF16") \
157 CP_ALIAS(1200, "UTF-16") \
158 CP_ALIAS(1200, "UCS2") \
159 CP_ALIAS(1200, "UCS-2") \
160 CP_ALIAS(12000, "UTF32") \
161 CP_ALIAS(12000, "UTF-32") \
162 CP_ALIAS(12000, "UCS4") \
163 CP_ALIAS(12000, "UCS-4") \
164\
165 /* copy from libiconv `iconv -l` */ \
166 /* !IsValidCodePage(367) */ \
167 CP_ALIAS(20127, "ANSI_X3.4-1968") \
168 CP_ALIAS(20127, "ANSI_X3.4-1986") \
169 CP_ALIAS(20127, "ASCII") \
170 CP_ALIAS(20127, "CP367") \
171 CP_ALIAS(20127, "IBM367") \
172 CP_ALIAS(20127, "ISO-IR-6") \
173 CP_ALIAS(20127, "ISO646-US") \
174 CP_ALIAS(20127, "ISO_646.IRV:1991") \
175 CP_ALIAS(20127, "US") \
176 CP_ALIAS(20127, "US-ASCII") \
177 CP_ALIAS(20127, "CSASCII") \
178\
179 /* !IsValidCodePage(819) */ \
180 CP_ALIAS(1252, "CP819") \
181 CP_ALIAS(1252, "IBM819") \
182 CP_ALIAS(28591, "ISO-8859-1") \
183 CP_ALIAS(28591, "ISO-IR-100") \
184 CP_ALIAS(28591, "ISO8859-1") \
185 CP_ALIAS(28591, "ISO_8859-1") \
186 CP_ALIAS(28591, "ISO_8859-1:1987") \
187 CP_ALIAS(28591, "L1") \
188 CP_ALIAS(28591, "LATIN1") \
189 CP_ALIAS(28591, "CSISOLATIN1") \
190\
191 CP_ALIAS(1250, "CP1250") \
192 CP_ALIAS(1250, "MS-EE") \
193 CP_ALIAS(1250, "WINDOWS-1250") \
194\
195 CP_ALIAS(1251, "CP1251") \
196 CP_ALIAS(1251, "MS-CYRL") \
197 CP_ALIAS(1251, "WINDOWS-1251") \
198\
199 CP_ALIAS(1252, "CP1252") \
200 CP_ALIAS(1252, "MS-ANSI") \
201 CP_ALIAS(1252, "WINDOWS-1252") \
202\
203 CP_ALIAS(1253, "CP1253") \
204 CP_ALIAS(1253, "MS-GREEK") \
205 CP_ALIAS(1253, "WINDOWS-1253") \
206\
207 CP_ALIAS(1254, "CP1254") \
208 CP_ALIAS(1254, "MS-TURK") \
209 CP_ALIAS(1254, "WINDOWS-1254") \
210\
211 CP_ALIAS(1255, "CP1255") \
212 CP_ALIAS(1255, "MS-HEBR") \
213 CP_ALIAS(1255, "WINDOWS-1255") \
214\
215 CP_ALIAS(1256, "CP1256") \
216 CP_ALIAS(1256, "MS-ARAB") \
217 CP_ALIAS(1256, "WINDOWS-1256") \
218\
219 CP_ALIAS(1257, "CP1257") \
220 CP_ALIAS(1257, "WINBALTRIM") \
221 CP_ALIAS(1257, "WINDOWS-1257") \
222\
223 CP_ALIAS(1258, "CP1258") \
224 CP_ALIAS(1258, "WINDOWS-1258") \
225\
226 CP_ALIAS(850, "850") \
227 CP_ALIAS(850, "CP850") \
228 CP_ALIAS(850, "IBM850") \
229 CP_ALIAS(850, "CSPC850MULTILINGUAL") \
230\
231 /* !IsValidCodePage(862) */ \
232 CP_ALIAS(862, "862") \
233 CP_ALIAS(862, "CP862") \
234 CP_ALIAS(862, "IBM862") \
235 CP_ALIAS(862, "CSPC862LATINHEBREW") \
236\
237 CP_ALIAS(866, "866") \
238 CP_ALIAS(866, "CP866") \
239 CP_ALIAS(866, "IBM866") \
240 CP_ALIAS(866, "CSIBM866") \
241\
242 /* !IsValidCodePage(154) */ \
243 CP_ALIAS(154, "CP154") \
244 CP_ALIAS(154, "CYRILLIC-ASIAN") \
245 CP_ALIAS(154, "PT154") \
246 CP_ALIAS(154, "PTCP154") \
247 CP_ALIAS(154, "CSPTCP154") \
248\
249 /* !IsValidCodePage(1133) */ \
250 CP_ALIAS(1133, "CP1133") \
251 CP_ALIAS(1133, "IBM-CP1133") \
252\
253 CP_ALIAS(874, "CP874") \
254 CP_ALIAS(874, "WINDOWS-874") \
255\
256 /* !IsValidCodePage(51932) */ \
257 CP_ALIAS(51932, "CP51932") \
258 CP_ALIAS(51932, "MS51932") \
259 CP_ALIAS(51932, "WINDOWS-51932") \
260 CP_ALIAS(51932, "EUC-JP") \
261\
262 CP_ALIAS(932, "CP932") \
263 CP_ALIAS(932, "MS932") \
264 CP_ALIAS(932, "SHIFFT_JIS") \
265 CP_ALIAS(932, "SHIFFT_JIS-MS") \
266 CP_ALIAS(932, "SJIS") \
267 CP_ALIAS(932, "SJIS-MS") \
268 CP_ALIAS(932, "SJIS-OPEN") \
269 CP_ALIAS(932, "SJIS-WIN") \
270 CP_ALIAS(932, "WINDOWS-31J") \
271 CP_ALIAS(932, "WINDOWS-932") \
272 CP_ALIAS(932, "CSWINDOWS31J") \
273\
274 CP_ALIAS(50221, "CP50221") \
275 CP_ALIAS(50221, "ISO-2022-JP") \
276 CP_ALIAS(50221, "ISO-2022-JP-MS") \
277 CP_ALIAS(50221, "ISO2022-JP") \
278 CP_ALIAS(50221, "ISO2022-JP-MS") \
279 CP_ALIAS(50221, "MS50221") \
280 CP_ALIAS(50221, "WINDOWS-50221") \
281\
282 CP_ALIAS(936, "CP936") \
283 CP_ALIAS(936, "GBK") \
284 CP_ALIAS(936, "MS936") \
285 CP_ALIAS(936, "WINDOWS-936") \
286\
287 CP_ALIAS(950, "CP950") \
288 CP_ALIAS(950, "BIG5") \
289 CP_ALIAS(950, "BIG5HKSCS") \
290 CP_ALIAS(950, "BIG5-HKSCS") \
291\
292 CP_ALIAS(949, "CP949") \
293 CP_ALIAS(949, "UHC") \
294 CP_ALIAS(949, "EUC-KR") \
295\
296 CP_ALIAS(1361, "CP1361") \
297 CP_ALIAS(1361, "JOHAB") \
298\
299 CP_ALIAS(437, "437") \
300 CP_ALIAS(437, "CP437") \
301 CP_ALIAS(437, "IBM437") \
302 CP_ALIAS(437, "CSPC8CODEPAGE437") \
303\
304 CP_ALIAS(737, "CP737") \
305\
306 CP_ALIAS(775, "CP775") \
307 CP_ALIAS(775, "IBM775") \
308 CP_ALIAS(775, "CSPC775BALTIC") \
309\
310 CP_ALIAS(852, "852") \
311 CP_ALIAS(852, "CP852") \
312 CP_ALIAS(852, "IBM852") \
313 CP_ALIAS(852, "CSPCP852") \
314\
315 /* !IsValidCodePage(853) */ \
316 CP_ALIAS(853, "CP853") \
317\
318 CP_ALIAS(855, "855") \
319 CP_ALIAS(855, "CP855") \
320 CP_ALIAS(855, "IBM855") \
321 CP_ALIAS(855, "CSIBM855") \
322\
323 CP_ALIAS(857, "857") \
324 CP_ALIAS(857, "CP857") \
325 CP_ALIAS(857, "IBM857") \
326 CP_ALIAS(857, "CSIBM857") \
327\
328 /* !IsValidCodePage(858) */ \
329 CP_ALIAS(858, "CP858") \
330\
331 CP_ALIAS(860, "860") \
332 CP_ALIAS(860, "CP860") \
333 CP_ALIAS(860, "IBM860") \
334 CP_ALIAS(860, "CSIBM860") \
335\
336 CP_ALIAS(861, "861") \
337 CP_ALIAS(861, "CP-IS") \
338 CP_ALIAS(861, "CP861") \
339 CP_ALIAS(861, "IBM861") \
340 CP_ALIAS(861, "CSIBM861") \
341\
342 CP_ALIAS(863, "863") \
343 CP_ALIAS(863, "CP863") \
344 CP_ALIAS(863, "IBM863") \
345 CP_ALIAS(863, "CSIBM863") \
346\
347 CP_ALIAS(864, "CP864") \
348 CP_ALIAS(864, "IBM864") \
349 CP_ALIAS(864, "CSIBM864") \
350\
351 CP_ALIAS(865, "865") \
352 CP_ALIAS(865, "CP865") \
353 CP_ALIAS(865, "IBM865") \
354 CP_ALIAS(865, "CSIBM865") \
355\
356 CP_ALIAS(869, "869") \
357 CP_ALIAS(869, "CP-GR") \
358 CP_ALIAS(869, "CP869") \
359 CP_ALIAS(869, "IBM869") \
360 CP_ALIAS(869, "CSIBM869") \
361\
362 /* !IsValidCodePage(1152) */ \
363 CP_ALIAS(1125, "CP1125") \
364\
365 /* \
366 * Code Page Identifiers \
367 * http://msdn2.microsoft.com/en-us/library/ms776446.aspx \
368 */ \
369 CP_ALIAS(37, "IBM037") /* IBM EBCDIC US-Canada */ \
370 CP_ALIAS(437, "IBM437") /* OEM United States */ \
371 CP_ALIAS(500, "IBM500") /* IBM EBCDIC International */ \
372 CP_ALIAS(708, "ASMO-708") /* Arabic (ASMO 708) */ \
373 /* 709 Arabic (ASMO-449+, BCON V4) */ \
374 /* 710 Arabic - Transparent Arabic */ \
375 CP_ALIAS(720, "DOS-720") /* Arabic (Transparent ASMO); Arabic (DOS) */ \
376 CP_ALIAS(737, "ibm737") /* OEM Greek (formerly 437G); Greek (DOS) */ \
377 CP_ALIAS(775, "ibm775") /* OEM Baltic; Baltic (DOS) */ \
378 CP_ALIAS(850, "ibm850") /* OEM Multilingual Latin 1; Western European (DOS) */ \
379 CP_ALIAS(852, "ibm852") /* OEM Latin 2; Central European (DOS) */ \
380 CP_ALIAS(855, "IBM855") /* OEM Cyrillic (primarily Russian) */ \
381 CP_ALIAS(857, "ibm857") /* OEM Turkish; Turkish (DOS) */ \
382 CP_ALIAS(858, "IBM00858") /* OEM Multilingual Latin 1 + Euro symbol */ \
383 CP_ALIAS(860, "IBM860") /* OEM Portuguese; Portuguese (DOS) */ \
384 CP_ALIAS(861, "ibm861") /* OEM Icelandic; Icelandic (DOS) */ \
385 CP_ALIAS(862, "DOS-862") /* OEM Hebrew; Hebrew (DOS) */ \
386 CP_ALIAS(863, "IBM863") /* OEM French Canadian; French Canadian (DOS) */ \
387 CP_ALIAS(864, "IBM864") /* OEM Arabic; Arabic (864) */ \
388 CP_ALIAS(865, "IBM865") /* OEM Nordic; Nordic (DOS) */ \
389 CP_ALIAS(866, "cp866") /* OEM Russian; Cyrillic (DOS) */ \
390 CP_ALIAS(869, "ibm869") /* OEM Modern Greek; Greek, Modern (DOS) */ \
391 CP_ALIAS(870, "IBM870") /* IBM EBCDIC Multilingual/ROECE (Latin 2); IBM EBCDIC Multilingual Latin 2 */ \
392 CP_ALIAS(874, "windows-874") /* ANSI/OEM Thai (same as 28605, ISO 8859-15); Thai (Windows) */ \
393 CP_ALIAS(875, "cp875") /* IBM EBCDIC Greek Modern */ \
394 CP_ALIAS(932, "shift_jis") /* ANSI/OEM Japanese; Japanese (Shift-JIS) */ \
395 CP_ALIAS(932, "shift-jis") /* alternative name for it */ \
396 CP_ALIAS(936, "gb2312") /* ANSI/OEM Simplified Chinese (PRC, Singapore); Chinese Simplified (GB2312) */ \
397 CP_ALIAS(949, "ks_c_5601-1987") /* ANSI/OEM Korean (Unified Hangul Code) */ \
398 CP_ALIAS(950, "big5") /* ANSI/OEM Traditional Chinese (Taiwan; Hong Kong SAR, PRC); Chinese Traditional (Big5) */ \
399 CP_ALIAS(950, "big5hkscs") /* ANSI/OEM Traditional Chinese (Hong Kong SAR); Chinese Traditional (Big5-HKSCS) */ \
400 CP_ALIAS(950, "big5-hkscs") /* alternative name for it */ \
401 CP_ALIAS(1026, "IBM1026") /* IBM EBCDIC Turkish (Latin 5) */ \
402 CP_ALIAS(1047, "IBM01047") /* IBM EBCDIC Latin 1/Open System */ \
403 CP_ALIAS(1140, "IBM01140") /* IBM EBCDIC US-Canada (037 + Euro symbol); IBM EBCDIC (US-Canada-Euro) */ \
404 CP_ALIAS(1141, "IBM01141") /* IBM EBCDIC Germany (20273 + Euro symbol); IBM EBCDIC (Germany-Euro) */ \
405 CP_ALIAS(1142, "IBM01142") /* IBM EBCDIC Denmark-Norway (20277 + Euro symbol); IBM EBCDIC (Denmark-Norway-Euro) */ \
406 CP_ALIAS(1143, "IBM01143") /* IBM EBCDIC Finland-Sweden (20278 + Euro symbol); IBM EBCDIC (Finland-Sweden-Euro) */ \
407 CP_ALIAS(1144, "IBM01144") /* IBM EBCDIC Italy (20280 + Euro symbol); IBM EBCDIC (Italy-Euro) */ \
408 CP_ALIAS(1145, "IBM01145") /* IBM EBCDIC Latin America-Spain (20284 + Euro symbol); IBM EBCDIC (Spain-Euro) */ \
409 CP_ALIAS(1146, "IBM01146") /* IBM EBCDIC United Kingdom (20285 + Euro symbol); IBM EBCDIC (UK-Euro) */ \
410 CP_ALIAS(1147, "IBM01147") /* IBM EBCDIC France (20297 + Euro symbol); IBM EBCDIC (France-Euro) */ \
411 CP_ALIAS(1148, "IBM01148") /* IBM EBCDIC International (500 + Euro symbol); IBM EBCDIC (International-Euro) */ \
412 CP_ALIAS(1149, "IBM01149") /* IBM EBCDIC Icelandic (20871 + Euro symbol); IBM EBCDIC (Icelandic-Euro) */ \
413 CP_ALIAS(1250, "windows-1250") /* ANSI Central European; Central European (Windows) */ \
414 CP_ALIAS(1251, "windows-1251") /* ANSI Cyrillic; Cyrillic (Windows) */ \
415 CP_ALIAS(1252, "windows-1252") /* ANSI Latin 1; Western European (Windows) */ \
416 CP_ALIAS(1253, "windows-1253") /* ANSI Greek; Greek (Windows) */ \
417 CP_ALIAS(1254, "windows-1254") /* ANSI Turkish; Turkish (Windows) */ \
418 CP_ALIAS(1255, "windows-1255") /* ANSI Hebrew; Hebrew (Windows) */ \
419 CP_ALIAS(1256, "windows-1256") /* ANSI Arabic; Arabic (Windows) */ \
420 CP_ALIAS(1257, "windows-1257") /* ANSI Baltic; Baltic (Windows) */ \
421 CP_ALIAS(1258, "windows-1258") /* ANSI/OEM Vietnamese; Vietnamese (Windows) */ \
422 CP_ALIAS(1361, "Johab") /* Korean (Johab) */ \
423 CP_ALIAS(10000, "macintosh") /* MAC Roman; Western European (Mac) */ \
424 CP_ALIAS(10001, "x-mac-japanese") /* Japanese (Mac) */ \
425 CP_ALIAS(10002, "x-mac-chinesetrad") /* MAC Traditional Chinese (Big5); Chinese Traditional (Mac) */ \
426 CP_ALIAS(10003, "x-mac-korean") /* Korean (Mac) */ \
427 CP_ALIAS(10004, "x-mac-arabic") /* Arabic (Mac) */ \
428 CP_ALIAS(10005, "x-mac-hebrew") /* Hebrew (Mac) */ \
429 CP_ALIAS(10006, "x-mac-greek") /* Greek (Mac) */ \
430 CP_ALIAS(10007, "x-mac-cyrillic") /* Cyrillic (Mac) */ \
431 CP_ALIAS(10008, "x-mac-chinesesimp") /* MAC Simplified Chinese (GB 2312); Chinese Simplified (Mac) */ \
432 CP_ALIAS(10010, "x-mac-romanian") /* Romanian (Mac) */ \
433 CP_ALIAS(10017, "x-mac-ukrainian") /* Ukrainian (Mac) */ \
434 CP_ALIAS(10021, "x-mac-thai") /* Thai (Mac) */ \
435 CP_ALIAS(10029, "x-mac-ce") /* MAC Latin 2; Central European (Mac) */ \
436 CP_ALIAS(10079, "x-mac-icelandic") /* Icelandic (Mac) */ \
437 CP_ALIAS(10081, "x-mac-turkish") /* Turkish (Mac) */ \
438 CP_ALIAS(10082, "x-mac-croatian") /* Croatian (Mac) */ \
439 CP_ALIAS(20000, "x-Chinese_CNS") /* CNS Taiwan; Chinese Traditional (CNS) */ \
440 CP_ALIAS(20001, "x-cp20001") /* TCA Taiwan */ \
441 CP_ALIAS(20002, "x_Chinese-Eten") /* Eten Taiwan; Chinese Traditional (Eten) */ \
442 CP_ALIAS(20003, "x-cp20003") /* IBM5550 Taiwan */ \
443 CP_ALIAS(20004, "x-cp20004") /* TeleText Taiwan */ \
444 CP_ALIAS(20005, "x-cp20005") /* Wang Taiwan */ \
445 CP_ALIAS(20105, "x-IA5") /* IA5 (IRV International Alphabet No. 5, 7-bit); Western European (IA5) */ \
446 CP_ALIAS(20106, "x-IA5-German") /* IA5 German (7-bit) */ \
447 CP_ALIAS(20107, "x-IA5-Swedish") /* IA5 Swedish (7-bit) */ \
448 CP_ALIAS(20108, "x-IA5-Norwegian") /* IA5 Norwegian (7-bit) */ \
449 CP_ALIAS(20127, "us-ascii") /* US-ASCII (7-bit) */ \
450 CP_ALIAS(20261, "x-cp20261") /* T.61 */ \
451 CP_ALIAS(20269, "x-cp20269") /* ISO 6937 Non-Spacing Accent */ \
452 CP_ALIAS(20273, "IBM273") /* IBM EBCDIC Germany */ \
453 CP_ALIAS(20277, "IBM277") /* IBM EBCDIC Denmark-Norway */ \
454 CP_ALIAS(20278, "IBM278") /* IBM EBCDIC Finland-Sweden */ \
455 CP_ALIAS(20280, "IBM280") /* IBM EBCDIC Italy */ \
456 CP_ALIAS(20284, "IBM284") /* IBM EBCDIC Latin America-Spain */ \
457 CP_ALIAS(20285, "IBM285") /* IBM EBCDIC United Kingdom */ \
458 CP_ALIAS(20290, "IBM290") /* IBM EBCDIC Japanese Katakana Extended */ \
459 CP_ALIAS(20297, "IBM297") /* IBM EBCDIC France */ \
460 CP_ALIAS(20420, "IBM420") /* IBM EBCDIC Arabic */ \
461 CP_ALIAS(20423, "IBM423") /* IBM EBCDIC Greek */ \
462 CP_ALIAS(20424, "IBM424") /* IBM EBCDIC Hebrew */ \
463 CP_ALIAS(20833, "x-EBCDIC-KoreanExtended") /* IBM EBCDIC Korean Extended */ \
464 CP_ALIAS(20838, "IBM-Thai") /* IBM EBCDIC Thai */ \
465 CP_ALIAS(20866, "koi8-r") /* Russian (KOI8-R); Cyrillic (KOI8-R) */ \
466 CP_ALIAS(20871, "IBM871") /* IBM EBCDIC Icelandic */ \
467 CP_ALIAS(20880, "IBM880") /* IBM EBCDIC Cyrillic Russian */ \
468 CP_ALIAS(20905, "IBM905") /* IBM EBCDIC Turkish */ \
469 CP_ALIAS(20924, "IBM00924") /* IBM EBCDIC Latin 1/Open System (1047 + Euro symbol) */ \
470 CP_ALIAS(20932, "EUC-JP") /* Japanese (JIS 0208-1990 and 0121-1990) */ \
471 CP_ALIAS(20936, "x-cp20936") /* Simplified Chinese (GB2312); Chinese Simplified (GB2312-80) */ \
472 CP_ALIAS(20949, "x-cp20949") /* Korean Wansung */ \
473 CP_ALIAS(21025, "cp1025") /* IBM EBCDIC Cyrillic Serbian-Bulgarian */ \
474 /* 21027 (deprecated) */ \
475 CP_ALIAS(21866, "koi8-u") /* Ukrainian (KOI8-U); Cyrillic (KOI8-U) */ \
476 CP_ALIAS(28591, "iso-8859-1") /* ISO 8859-1 Latin 1; Western European (ISO) */ \
477 CP_ALIAS(28591, "iso8859-1") /* ISO 8859-1 Latin 1; Western European (ISO) */ \
478 CP_ALIAS(28591, "iso_8859-1") \
479 CP_ALIAS(28591, "iso_8859_1") \
480 CP_ALIAS(28592, "iso-8859-2") /* ISO 8859-2 Central European; Central European (ISO) */ \
481 CP_ALIAS(28592, "iso8859-2") /* ISO 8859-2 Central European; Central European (ISO) */ \
482 CP_ALIAS(28592, "iso_8859-2") \
483 CP_ALIAS(28592, "iso_8859_2") \
484 CP_ALIAS(28593, "iso-8859-3") /* ISO 8859-3 Latin 3 */ \
485 CP_ALIAS(28593, "iso8859-3") /* ISO 8859-3 Latin 3 */ \
486 CP_ALIAS(28593, "iso_8859-3") \
487 CP_ALIAS(28593, "iso_8859_3") \
488 CP_ALIAS(28594, "iso-8859-4") /* ISO 8859-4 Baltic */ \
489 CP_ALIAS(28594, "iso8859-4") /* ISO 8859-4 Baltic */ \
490 CP_ALIAS(28594, "iso_8859-4") \
491 CP_ALIAS(28594, "iso_8859_4") \
492 CP_ALIAS(28595, "iso-8859-5") /* ISO 8859-5 Cyrillic */ \
493 CP_ALIAS(28595, "iso8859-5") /* ISO 8859-5 Cyrillic */ \
494 CP_ALIAS(28595, "iso_8859-5") \
495 CP_ALIAS(28595, "iso_8859_5") \
496 CP_ALIAS(28596, "iso-8859-6") /* ISO 8859-6 Arabic */ \
497 CP_ALIAS(28596, "iso8859-6") /* ISO 8859-6 Arabic */ \
498 CP_ALIAS(28596, "iso_8859-6") \
499 CP_ALIAS(28596, "iso_8859_6") \
500 CP_ALIAS(28597, "iso-8859-7") /* ISO 8859-7 Greek */ \
501 CP_ALIAS(28597, "iso8859-7") /* ISO 8859-7 Greek */ \
502 CP_ALIAS(28597, "iso_8859-7") \
503 CP_ALIAS(28597, "iso_8859_7") \
504 CP_ALIAS(28598, "iso-8859-8") /* ISO 8859-8 Hebrew; Hebrew (ISO-Visual) */ \
505 CP_ALIAS(28598, "iso8859-8") /* ISO 8859-8 Hebrew; Hebrew (ISO-Visual) */ \
506 CP_ALIAS(28598, "iso_8859-8") \
507 CP_ALIAS(28598, "iso_8859_8") \
508 CP_ALIAS(28599, "iso-8859-9") /* ISO 8859-9 Turkish */ \
509 CP_ALIAS(28599, "iso8859-9") /* ISO 8859-9 Turkish */ \
510 CP_ALIAS(28599, "iso_8859-9") \
511 CP_ALIAS(28599, "iso_8859_9") \
512 CP_ALIAS(28603, "iso-8859-13") /* ISO 8859-13 Estonian */ \
513 CP_ALIAS(28603, "iso8859-13") /* ISO 8859-13 Estonian */ \
514 CP_ALIAS(28603, "iso_8859-13") \
515 CP_ALIAS(28603, "iso_8859_13") \
516 CP_ALIAS(28605, "iso-8859-15") /* ISO 8859-15 Latin 9 */ \
517 CP_ALIAS(28605, "iso8859-15") /* ISO 8859-15 Latin 9 */ \
518 CP_ALIAS(28605, "iso_8859-15") \
519 CP_ALIAS(28605, "iso_8859_15") \
520 CP_ALIAS(29001, "x-Europa") /* Europa 3 */ \
521 CP_ALIAS(38598, "iso-8859-8-i") /* ISO 8859-8 Hebrew; Hebrew (ISO-Logical) */ \
522 CP_ALIAS(38598, "iso8859-8-i") /* ISO 8859-8 Hebrew; Hebrew (ISO-Logical) */ \
523 CP_ALIAS(38598, "iso_8859-8-i") \
524 CP_ALIAS(38598, "iso_8859_8-i") \
525 CP_ALIAS(50220, "iso-2022-jp") /* ISO 2022 Japanese with no halfwidth Katakana; Japanese (JIS) */ \
526 CP_ALIAS(50221, "csISO2022JP") /* ISO 2022 Japanese with halfwidth Katakana; Japanese (JIS-Allow 1 byte Kana) */ \
527 CP_ALIAS(50222, "iso-2022-jp") /* ISO 2022 Japanese JIS X 0201-1989; Japanese (JIS-Allow 1 byte Kana - SO/SI) */ \
528 CP_ALIAS(50225, "iso-2022-kr") /* ISO 2022 Korean */ \
529 CP_ALIAS(50225, "iso2022-kr") /* ISO 2022 Korean */ \
530 CP_ALIAS(50227, "x-cp50227") /* ISO 2022 Simplified Chinese; Chinese Simplified (ISO 2022) */ \
531 /* 50229 ISO 2022 Traditional Chinese */ \
532 /* 50930 EBCDIC Japanese (Katakana) Extended */ \
533 /* 50931 EBCDIC US-Canada and Japanese */ \
534 /* 50933 EBCDIC Korean Extended and Korean */ \
535 /* 50935 EBCDIC Simplified Chinese Extended and Simplified Chinese */ \
536 /* 50936 EBCDIC Simplified Chinese */ \
537 /* 50937 EBCDIC US-Canada and Traditional Chinese */ \
538 /* 50939 EBCDIC Japanese (Latin) Extended and Japanese */ \
539 CP_ALIAS(51932, "euc-jp") /* EUC Japanese */ \
540 CP_ALIAS(51936, "EUC-CN") /* EUC Simplified Chinese; Chinese Simplified (EUC) */ \
541 CP_ALIAS(51949, "euc-kr") /* EUC Korean */ \
542 /* 51950 EUC Traditional Chinese */ \
543 CP_ALIAS(52936, "hz-gb-2312") /* HZ-GB2312 Simplified Chinese; Chinese Simplified (HZ) */ \
544 CP_ALIAS(54936, "GB18030") /* Windows XP and later: GB18030 Simplified Chinese (4 byte); Chinese Simplified (GB18030) */ \
545 CP_ALIAS(57002, "x-iscii-de") /* ISCII Devanagari */ \
546 CP_ALIAS(57003, "x-iscii-be") /* ISCII Bengali */ \
547 CP_ALIAS(57004, "x-iscii-ta") /* ISCII Tamil */ \
548 CP_ALIAS(57005, "x-iscii-te") /* ISCII Telugu */ \
549 CP_ALIAS(57006, "x-iscii-as") /* ISCII Assamese */ \
550 CP_ALIAS(57007, "x-iscii-or") /* ISCII Oriya */ \
551 CP_ALIAS(57008, "x-iscii-ka") /* ISCII Kannada */ \
552 CP_ALIAS(57009, "x-iscii-ma") /* ISCII Malayalam */ \
553 CP_ALIAS(57010, "x-iscii-gu") /* ISCII Gujarati */ \
554 CP_ALIAS(57011, "x-iscii-pa") /* ISCII Punjabi */
555
556#define CP_ALIAS(codepage, alias) codepage,
557static const int cp_codepage[] = {
558 CP_ALIAS_LIST
559};
560#undef CP_ALIAS
561
562#define CP_ALIAS(codepage, alias) alias"\0"
563static const char cp_alias[] ALIGN1 =
564 CP_ALIAS_LIST;
565#undef CP_ALIAS
566
567/*
568 * SJIS SHIFTJIS table CP932 table
569 * ---- --------------------------- --------------------------------
570 * 5C U+00A5 YEN SIGN U+005C REVERSE SOLIDUS
571 * 7E U+203E OVERLINE U+007E TILDE
572 * 815C U+2014 EM DASH U+2015 HORIZONTAL BAR
573 * 815F U+005C REVERSE SOLIDUS U+FF3C FULLWIDTH REVERSE SOLIDUS
574 * 8160 U+301C WAVE DASH U+FF5E FULLWIDTH TILDE
575 * 8161 U+2016 DOUBLE VERTICAL LINE U+2225 PARALLEL TO
576 * 817C U+2212 MINUS SIGN U+FF0D FULLWIDTH HYPHEN-MINUS
577 * 8191 U+00A2 CENT SIGN U+FFE0 FULLWIDTH CENT SIGN
578 * 8192 U+00A3 POUND SIGN U+FFE1 FULLWIDTH POUND SIGN
579 * 81CA U+00AC NOT SIGN U+FFE2 FULLWIDTH NOT SIGN
580 *
581 * EUC-JP and ISO-2022-JP should be compatible with CP932.
582 *
583 * Kernel and MLang have different Unicode mapping table. Make sure
584 * which API is used.
585 */
586static compat_t cp932_compat[] = {
587 {0x00A5, 0x005C, COMPAT_OUT},
588 {0x203E, 0x007E, COMPAT_OUT},
589 {0x2014, 0x2015, COMPAT_OUT},
590 {0x301C, 0xFF5E, COMPAT_OUT},
591 {0x2016, 0x2225, COMPAT_OUT},
592 {0x2212, 0xFF0D, COMPAT_OUT},
593 {0x00A2, 0xFFE0, COMPAT_OUT},
594 {0x00A3, 0xFFE1, COMPAT_OUT},
595 {0x00AC, 0xFFE2, COMPAT_OUT},
596 {0, 0, 0}
597};
598
599static compat_t cp20932_compat[] = {
600 {0x00A5, 0x005C, COMPAT_OUT},
601 {0x203E, 0x007E, COMPAT_OUT},
602 {0x2014, 0x2015, COMPAT_OUT},
603 {0xFF5E, 0x301C, COMPAT_OUT|COMPAT_IN},
604 {0x2225, 0x2016, COMPAT_OUT|COMPAT_IN},
605 {0xFF0D, 0x2212, COMPAT_OUT|COMPAT_IN},
606 {0xFFE0, 0x00A2, COMPAT_OUT|COMPAT_IN},
607 {0xFFE1, 0x00A3, COMPAT_OUT|COMPAT_IN},
608 {0xFFE2, 0x00AC, COMPAT_OUT|COMPAT_IN},
609 {0, 0, 0}
610};
611
612static compat_t *cp51932_compat = cp932_compat;
613
614/* cp20932_compat for kernel. cp932_compat for mlang. */
615static compat_t *cp5022x_compat = cp932_compat;
616
617typedef HRESULT (WINAPI *CONVERTINETMULTIBYTETOUNICODE)(
618 LPDWORD lpdwMode,
619 DWORD dwSrcEncoding,
620 LPCSTR lpSrcStr,
621 LPINT lpnMultiCharCount,
622 LPWSTR lpDstStr,
623 LPINT lpnWideCharCount
624);
625
626typedef HRESULT (WINAPI *CONVERTINETUNICODETOMULTIBYTE)(
627 LPDWORD lpdwMode,
628 DWORD dwEncoding,
629 LPCWSTR lpSrcStr,
630 LPINT lpnWideCharCount,
631 LPSTR lpDstStr,
632 LPINT lpnMultiCharCount
633);
634
635static CONVERTINETMULTIBYTETOUNICODE ConvertINetMultiByteToUnicode;
636static CONVERTINETUNICODETOMULTIBYTE ConvertINetUnicodeToMultiByte;
637
638static int
639load_mlang(void)
640{
641 HMODULE h;
642 if (ConvertINetMultiByteToUnicode != NULL)
643 return TRUE;
644 h = LoadLibrary(TEXT("mlang.dll"));
645 if (!h)
646 return FALSE;
647 ConvertINetMultiByteToUnicode = (CONVERTINETMULTIBYTETOUNICODE)GetProcAddressA(h, "ConvertINetMultiByteToUnicode");
648 ConvertINetUnicodeToMultiByte = (CONVERTINETUNICODETOMULTIBYTE)GetProcAddressA(h, "ConvertINetUnicodeToMultiByte");
649 return TRUE;
650}
651
652static iconv_t
653iconv_open(const char *tocode, const char *fromcode)
654{
655 rec_iconv_t *cd;
656
657 cd = (rec_iconv_t *)xzalloc(sizeof(rec_iconv_t));
658
659 /* reset the errno to prevent reporting wrong error code.
660 * 0 for unsorted error. */
661 errno = 0;
662 if (make_csconv(fromcode, &cd->from) && make_csconv(tocode, &cd->to)) {
663 cd->cd = (iconv_t)cd;
664 return (iconv_t)cd;
665 }
666
667 free(cd);
668 return (iconv_t)(-1);
669}
670
671static int
672iconv_close(iconv_t _cd)
673{
674 free(_cd);
675 return 0;
676}
677
678static size_t
679iconv(iconv_t _cd, const char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft)
680{
681 rec_iconv_t *cd = (rec_iconv_t *)_cd;
682 ushort wbuf[MB_CHAR_MAX]; /* enough room for one character */
683 int insize;
684 int outsize;
685 int wsize;
686 DWORD frommode;
687 DWORD tomode;
688 uint wc;
689 compat_t *cp;
690 int i;
691
692 if (inbuf == NULL || *inbuf == NULL)
693 {
694 if (outbuf != NULL && *outbuf != NULL && cd->to.flush != NULL)
695 {
696 tomode = cd->to.mode;
697 outsize = cd->to.flush(&cd->to, (uchar *)*outbuf, *outbytesleft);
698 if (outsize == -1)
699 {
700 if ((cd->to.flags & FLAG_IGNORE) && errno != E2BIG)
701 {
702 outsize = 0;
703 }
704 else
705 {
706 cd->to.mode = tomode;
707 return (size_t)(-1);
708 }
709 }
710 *outbuf += outsize;
711 *outbytesleft -= outsize;
712 }
713 cd->from.mode = 0;
714 cd->to.mode = 0;
715 return 0;
716 }
717
718 while (*inbytesleft != 0)
719 {
720 frommode = cd->from.mode;
721 tomode = cd->to.mode;
722 wsize = MB_CHAR_MAX;
723
724 insize = cd->from.mbtowc(&cd->from, (const uchar *)*inbuf, *inbytesleft, wbuf, &wsize);
725 if (insize == -1)
726 {
727 if (cd->to.flags & FLAG_IGNORE)
728 {
729 cd->from.mode = frommode;
730 insize = 1;
731 wsize = 0;
732 }
733 else
734 {
735 cd->from.mode = frommode;
736 return (size_t)(-1);
737 }
738 }
739
740 if (wsize == 0)
741 {
742 *inbuf += insize;
743 *inbytesleft -= insize;
744 continue;
745 }
746
747 if (cd->from.compat != NULL)
748 {
749 wc = utf16_to_ucs4(wbuf);
750 cp = cd->from.compat;
751 for (i = 0; cp[i].in != 0; ++i)
752 {
753 if ((cp[i].flag & COMPAT_IN) && cp[i].out == wc)
754 {
755 ucs4_to_utf16(cp[i].in, wbuf, &wsize);
756 break;
757 }
758 }
759 }
760
761 if (cd->to.compat != NULL)
762 {
763 wc = utf16_to_ucs4(wbuf);
764 cp = cd->to.compat;
765 for (i = 0; cp[i].in != 0; ++i)
766 {
767 if ((cp[i].flag & COMPAT_OUT) && cp[i].in == wc)
768 {
769 ucs4_to_utf16(cp[i].out, wbuf, &wsize);
770 break;
771 }
772 }
773 }
774
775 outsize = cd->to.wctomb(&cd->to, wbuf, wsize, (uchar *)*outbuf, *outbytesleft);
776 if (outsize == -1)
777 {
778 if ((cd->to.flags & FLAG_IGNORE) && errno != E2BIG)
779 {
780 cd->to.mode = tomode;
781 outsize = 0;
782 }
783 else
784 {
785 cd->from.mode = frommode;
786 cd->to.mode = tomode;
787 return (size_t)(-1);
788 }
789 }
790
791 *inbuf += insize;
792 *outbuf += outsize;
793 *inbytesleft -= insize;
794 *outbytesleft -= outsize;
795 }
796
797 return 0;
798}
799
800static int
801make_csconv(const char *_name, csconv_t *cv)
802{
803 CPINFO cpinfo;
804 int use_compat = TRUE;
805 int flag = 0;
806 char *name;
807 char *p, *s;
808
809 name = xstrdup(_name);
810
811 /* check for option "enc_name//opt1//opt2" */
812 while ((p = strrstr(name, "//")) != NULL)
813 {
814 for (s = p + 2; *s; ++s)
815 *s = tolower(*s);
816 switch (index_in_strings("nocompat\0translit\0ignore\0", p + 2)) {
817 case 0:
818 use_compat = FALSE;
819 break;
820 case 1:
821 flag |= FLAG_TRANSLIT;
822 break;
823 case 2:
824 flag |= FLAG_IGNORE;
825 break;
826 }
827 *p = 0;
828 }
829
830 cv->mode = 0;
831 cv->flags = flag;
832 cv->mblen = NULL;
833 cv->flush = NULL;
834 cv->compat = NULL;
835 cv->codepage = name_to_codepage(name);
836 if (cv->codepage == 1200 || cv->codepage == 1201)
837 {
838 cv->mbtowc = utf16_mbtowc;
839 cv->wctomb = utf16_wctomb;
840 if (_stricmp(name, "UTF-16") == 0 || _stricmp(name, "UTF16") == 0 ||
841 _stricmp(name, "UCS-2") == 0 || _stricmp(name, "UCS2") == 0 ||
842 _stricmp(name,"UCS-2-INTERNAL") == 0)
843 cv->flags |= FLAG_USE_BOM;
844 }
845 else if (cv->codepage == 12000 || cv->codepage == 12001)
846 {
847 cv->mbtowc = utf32_mbtowc;
848 cv->wctomb = utf32_wctomb;
849 if (_stricmp(name, "UTF-32") == 0 || _stricmp(name, "UTF32") == 0 ||
850 _stricmp(name, "UCS-4") == 0 || _stricmp(name, "UCS4") == 0)
851 cv->flags |= FLAG_USE_BOM;
852 }
853 else if (cv->codepage == 65001)
854 {
855 cv->mbtowc = kernel_mbtowc;
856 cv->wctomb = kernel_wctomb;
857 cv->mblen = utf8_mblen;
858 }
859 else if ((cv->codepage == 50220 || cv->codepage == 50221 || cv->codepage == 50222) && load_mlang())
860 {
861 cv->mbtowc = iso2022jp_mbtowc;
862 cv->wctomb = iso2022jp_wctomb;
863 cv->flush = iso2022jp_flush;
864 }
865 else if (cv->codepage == 51932 && load_mlang())
866 {
867 cv->mbtowc = mlang_mbtowc;
868 cv->wctomb = mlang_wctomb;
869 cv->mblen = eucjp_mblen;
870 }
871 else if (IsValidCodePage(cv->codepage)
872 && GetCPInfo(cv->codepage, &cpinfo) != 0)
873 {
874 cv->mbtowc = kernel_mbtowc;
875 cv->wctomb = kernel_wctomb;
876 if (cpinfo.MaxCharSize == 1)
877 cv->mblen = sbcs_mblen;
878 else if (cpinfo.MaxCharSize == 2)
879 cv->mblen = dbcs_mblen;
880 else
881 cv->mblen = mbcs_mblen;
882 }
883 else
884 {
885 /* not supported */
886 free(name);
887 errno = EINVAL;
888 return FALSE;
889 }
890
891 if (use_compat)
892 {
893 switch (cv->codepage)
894 {
895 case 932: cv->compat = cp932_compat; break;
896 case 20932: cv->compat = cp20932_compat; break;
897 case 51932: cv->compat = cp51932_compat; break;
898 case 50220: case 50221: case 50222: cv->compat = cp5022x_compat; break;
899 }
900 }
901
902 free(name);
903
904 return TRUE;
905}
906
907static int
908name_to_codepage(const char *name)
909{
910 int i;
911 const char *alias;
912
913 if (*name == '\0' || strcmp(name, "char") == 0)
914 return GetACP();
915 else if (strcmp(name, "wchar_t") == 0)
916 return 1200;
917 else if (_strnicmp(name, "cp", 2) == 0)
918 return atoi(name + 2); /* CP123 */
919 else if ('0' <= name[0] && name[0] <= '9')
920 return atoi(name); /* 123 */
921 else if (_strnicmp(name, "xx", 2) == 0)
922 return atoi(name + 2); /* XX123 for debug */
923
924 i = 0;
925 alias = cp_alias;
926 while (*alias) {
927 if (_stricmp(alias, name) == 0) {
928 return cp_codepage[i];
929 }
930 alias += strlen(alias) + 1;
931 ++i;
932 }
933 return -1;
934}
935
936/*
937 * http://www.faqs.org/rfcs/rfc2781.html
938 */
939static uint
940utf16_to_ucs4(const ushort *wbuf)
941{
942 uint wc = wbuf[0];
943 if (0xD800 <= wbuf[0] && wbuf[0] <= 0xDBFF)
944 wc = ((wbuf[0] & 0x3FF) << 10) + (wbuf[1] & 0x3FF) + 0x10000;
945 return wc;
946}
947
948static void
949ucs4_to_utf16(uint wc, ushort *wbuf, int *wbufsize)
950{
951 if (wc < 0x10000)
952 {
953 wbuf[0] = wc;
954 *wbufsize = 1;
955 }
956 else
957 {
958 wc -= 0x10000;
959 wbuf[0] = 0xD800 | ((wc >> 10) & 0x3FF);
960 wbuf[1] = 0xDC00 | (wc & 0x3FF);
961 *wbufsize = 2;
962 }
963}
964
965/*
966 * Check if codepage is one of those for which the dwFlags parameter
967 * to MultiByteToWideChar() must be zero. Return zero or
968 * MB_ERR_INVALID_CHARS. The docs in Platform SDK for Windows
969 * Server 2003 R2 claims that also codepage 65001 is one of these, but
970 * that doesn't seem to be the case. The MSDN docs for MSVS2008 leave
971 * out 65001 (UTF-8), and that indeed seems to be the case on XP, it
972 * works fine to pass MB_ERR_INVALID_CHARS in dwFlags when converting
973 * from UTF-8.
974 */
975static int
976mbtowc_flags(int codepage)
977{
978 return (codepage == 50220 || codepage == 50221 ||
979 codepage == 50222 || codepage == 50225 ||
980 codepage == 50227 || codepage == 50229 ||
981 codepage == 52936 || codepage == 54936 ||
982 (codepage >= 57002 && codepage <= 57011) ||
983 codepage == 65000 || codepage == 42) ? 0 : MB_ERR_INVALID_CHARS;
984}
985
986/*
987 * Check if codepage is one those for which the lpUsedDefaultChar
988 * parameter to WideCharToMultiByte() must be NULL. The docs in
989 * Platform SDK for Windows Server 2003 R2 claims that this is the
990 * list below, while the MSDN docs for MSVS2008 claim that it is only
991 * for 65000 (UTF-7) and 65001 (UTF-8). This time the earlier Platform
992 * SDK seems to be correct, at least for XP.
993 */
994static int
995must_use_null_useddefaultchar(int codepage)
996{
997 return (codepage == 65000 || codepage == 65001 ||
998 codepage == 50220 || codepage == 50221 ||
999 codepage == 50222 || codepage == 50225 ||
1000 codepage == 50227 || codepage == 50229 ||
1001 codepage == 52936 || codepage == 54936 ||
1002 (codepage >= 57002 && codepage <= 57011) ||
1003 codepage == 42);
1004}
1005
1006static int
1007seterror(int err)
1008{
1009 errno = err;
1010 return -1;
1011}
1012
1013static int
1014sbcs_mblen(csconv_t *cv UNUSED_PARAM, const uchar *buf UNUSED_PARAM,
1015 int bufsize UNUSED_PARAM)
1016{
1017 return 1;
1018}
1019
1020static int
1021dbcs_mblen(csconv_t *cv, const uchar *buf, int bufsize)
1022{
1023 int len = IsDBCSLeadByteEx(cv->codepage, buf[0]) ? 2 : 1;
1024 if (bufsize < len)
1025 return seterror(EINVAL);
1026 return len;
1027}
1028
1029static int
1030mbcs_mblen(csconv_t *cv, const uchar *buf, int bufsize)
1031{
1032 int len = 0;
1033
1034 if (cv->codepage == 54936) {
1035 if (buf[0] <= 0x7F)
1036 len = 1;
1037 else if (buf[0] >= 0x81 && buf[0] <= 0xFE &&
1038 bufsize >= 2 &&
1039 ((buf[1] >= 0x40 && buf[1] <= 0x7E) ||
1040 (buf[1] >= 0x80 && buf[1] <= 0xFE)))
1041 len = 2;
1042 else if (buf[0] >= 0x81 && buf[0] <= 0xFE &&
1043 bufsize >= 4 &&
1044 buf[1] >= 0x30 && buf[1] <= 0x39)
1045 len = 4;
1046 else
1047 return seterror(EINVAL);
1048 return len;
1049 }
1050 else
1051 return seterror(EINVAL);
1052}
1053
1054static int
1055utf8_mblen(csconv_t *cv UNUSED_PARAM, const uchar *buf, int bufsize)
1056{
1057 int len = 0;
1058
1059 if (buf[0] < 0x80) len = 1;
1060 else if ((buf[0] & 0xE0) == 0xC0) len = 2;
1061 else if ((buf[0] & 0xF0) == 0xE0) len = 3;
1062 else if ((buf[0] & 0xF8) == 0xF0) len = 4;
1063 else if ((buf[0] & 0xFC) == 0xF8) len = 5;
1064 else if ((buf[0] & 0xFE) == 0xFC) len = 6;
1065
1066 if (len == 0)
1067 return seterror(EILSEQ);
1068 else if (bufsize < len)
1069 return seterror(EINVAL);
1070 return len;
1071}
1072
1073static int
1074eucjp_mblen(csconv_t *cv UNUSED_PARAM, const uchar *buf, int bufsize)
1075{
1076 if (buf[0] < 0x80) /* ASCII */
1077 return 1;
1078 else if (buf[0] == 0x8E) /* JIS X 0201 */
1079 {
1080 if (bufsize < 2)
1081 return seterror(EINVAL);
1082 else if (!(0xA1 <= buf[1] && buf[1] <= 0xDF))
1083 return seterror(EILSEQ);
1084 return 2;
1085 }
1086 else if (buf[0] == 0x8F) /* JIS X 0212 */
1087 {
1088 if (bufsize < 3)
1089 return seterror(EINVAL);
1090 else if (!(0xA1 <= buf[1] && buf[1] <= 0xFE)
1091 || !(0xA1 <= buf[2] && buf[2] <= 0xFE))
1092 return seterror(EILSEQ);
1093 return 3;
1094 }
1095 else /* JIS X 0208 */
1096 {
1097 if (bufsize < 2)
1098 return seterror(EINVAL);
1099 else if (!(0xA1 <= buf[0] && buf[0] <= 0xFE)
1100 || !(0xA1 <= buf[1] && buf[1] <= 0xFE))
1101 return seterror(EILSEQ);
1102 return 2;
1103 }
1104}
1105
1106static int
1107kernel_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize)
1108{
1109 int len;
1110
1111 len = cv->mblen(cv, buf, bufsize);
1112 if (len == -1)
1113 return -1;
1114 /* If converting from ASCII, reject 8bit
1115 * chars. MultiByteToWideChar() doesn't. Note that for ASCII we
1116 * know that the mblen function is sbcs_mblen() so len is 1.
1117 */
1118 if (cv->codepage == 20127 && buf[0] >= 0x80)
1119 return seterror(EILSEQ);
1120 *wbufsize = MultiByteToWideChar(cv->codepage, mbtowc_flags (cv->codepage),
1121 (const char *)buf, len, (wchar_t *)wbuf, *wbufsize);
1122 if (*wbufsize == 0)
1123 return seterror(EILSEQ);
1124 return len;
1125}
1126
1127static int
1128kernel_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize)
1129{
1130 BOOL usedDefaultChar = 0;
1131 BOOL *p = NULL;
1132 int flags = 0;
1133 int len;
1134
1135 if (bufsize == 0)
1136 return seterror(E2BIG);
1137 if (!must_use_null_useddefaultchar(cv->codepage))
1138 {
1139 p = &usedDefaultChar;
1140#ifdef WC_NO_BEST_FIT_CHARS
1141 if (!(cv->flags & FLAG_TRANSLIT))
1142 flags |= WC_NO_BEST_FIT_CHARS;
1143#endif
1144 }
1145 len = WideCharToMultiByte(cv->codepage, flags,
1146 (const wchar_t *)wbuf, wbufsize, (char *)buf, bufsize, NULL, p);
1147 if (len == 0)
1148 {
1149 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
1150 return seterror(E2BIG);
1151 return seterror(EILSEQ);
1152 }
1153 else if (usedDefaultChar && !(cv->flags & FLAG_TRANSLIT))
1154 return seterror(EILSEQ);
1155 else if (cv->mblen(cv, buf, len) != len) /* validate result */
1156 return seterror(EILSEQ);
1157 return len;
1158}
1159
1160/*
1161 * It seems that the mode (cv->mode) is fixnum.
1162 * For example, when converting iso-2022-jp(cp50221) to unicode:
1163 * in ascii sequence: mode=0xC42C0000
1164 * in jisx0208 sequence: mode=0xC42C0001
1165 * "C42C" is same for each convert session.
1166 * It should be: ((codepage-1)<<16)|state
1167 */
1168static int
1169mlang_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize)
1170{
1171 int len;
1172 int insize;
1173 HRESULT hr;
1174
1175 len = cv->mblen(cv, buf, bufsize);
1176 if (len == -1)
1177 return -1;
1178 insize = len;
1179 hr = ConvertINetMultiByteToUnicode(&cv->mode, cv->codepage,
1180 (const char *)buf, &insize, (wchar_t *)wbuf, wbufsize);
1181 if (hr != S_OK || insize != len)
1182 return seterror(EILSEQ);
1183 return len;
1184}
1185
1186static int
1187mlang_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize)
1188{
1189 char tmpbuf[MB_CHAR_MAX]; /* enough room for one character */
1190 int tmpsize = MB_CHAR_MAX;
1191 int insize = wbufsize;
1192 HRESULT hr;
1193
1194 hr = ConvertINetUnicodeToMultiByte(&cv->mode, cv->codepage,
1195 (const wchar_t *)wbuf, &wbufsize, tmpbuf, &tmpsize);
1196 if (hr != S_OK || insize != wbufsize)
1197 return seterror(EILSEQ);
1198 else if (bufsize < tmpsize)
1199 return seterror(E2BIG);
1200 else if (cv->mblen(cv, (uchar *)tmpbuf, tmpsize) != tmpsize)
1201 return seterror(EILSEQ);
1202 memcpy(buf, tmpbuf, tmpsize);
1203 return tmpsize;
1204}
1205
1206static int
1207utf16_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize)
1208{
1209 int codepage = cv->codepage;
1210
1211 /* swap endian: 1200 <-> 1201 */
1212 if (cv->mode & UNICODE_MODE_SWAPPED)
1213 codepage ^= 1;
1214
1215 if (bufsize < 2)
1216 return seterror(EINVAL);
1217 if (codepage == 1200) /* little endian */
1218 wbuf[0] = (buf[1] << 8) | buf[0];
1219 else if (codepage == 1201) /* big endian */
1220 wbuf[0] = (buf[0] << 8) | buf[1];
1221
1222 if ((cv->flags & FLAG_USE_BOM) && !(cv->mode & UNICODE_MODE_BOM_DONE))
1223 {
1224 cv->mode |= UNICODE_MODE_BOM_DONE;
1225 if (wbuf[0] == 0xFFFE)
1226 {
1227 cv->mode |= UNICODE_MODE_SWAPPED;
1228 *wbufsize = 0;
1229 return 2;
1230 }
1231 else if (wbuf[0] == 0xFEFF)
1232 {
1233 *wbufsize = 0;
1234 return 2;
1235 }
1236 }
1237
1238 if (0xDC00 <= wbuf[0] && wbuf[0] <= 0xDFFF)
1239 return seterror(EILSEQ);
1240 if (0xD800 <= wbuf[0] && wbuf[0] <= 0xDBFF)
1241 {
1242 if (bufsize < 4)
1243 return seterror(EINVAL);
1244 if (codepage == 1200) /* little endian */
1245 wbuf[1] = (buf[3] << 8) | buf[2];
1246 else if (codepage == 1201) /* big endian */
1247 wbuf[1] = (buf[2] << 8) | buf[3];
1248 if (!(0xDC00 <= wbuf[1] && wbuf[1] <= 0xDFFF))
1249 return seterror(EILSEQ);
1250 *wbufsize = 2;
1251 return 4;
1252 }
1253 *wbufsize = 1;
1254 return 2;
1255}
1256
1257static int
1258utf16_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize)
1259{
1260 if ((cv->flags & FLAG_USE_BOM) && !(cv->mode & UNICODE_MODE_BOM_DONE))
1261 {
1262 int r;
1263
1264 cv->mode |= UNICODE_MODE_BOM_DONE;
1265 if (bufsize < 2)
1266 return seterror(E2BIG);
1267 if (cv->codepage == 1200) /* little endian */
1268 memcpy(buf, "\xFF\xFE", 2);
1269 else if (cv->codepage == 1201) /* big endian */
1270 memcpy(buf, "\xFE\xFF", 2);
1271
1272 r = utf16_wctomb(cv, wbuf, wbufsize, buf + 2, bufsize - 2);
1273 if (r == -1)
1274 return -1;
1275 return r + 2;
1276 }
1277
1278 if (bufsize < 2)
1279 return seterror(E2BIG);
1280 if (cv->codepage == 1200) /* little endian */
1281 {
1282 buf[0] = (wbuf[0] & 0x00FF);
1283 buf[1] = (wbuf[0] & 0xFF00) >> 8;
1284 }
1285 else if (cv->codepage == 1201) /* big endian */
1286 {
1287 buf[0] = (wbuf[0] & 0xFF00) >> 8;
1288 buf[1] = (wbuf[0] & 0x00FF);
1289 }
1290 if (0xD800 <= wbuf[0] && wbuf[0] <= 0xDBFF)
1291 {
1292 if (bufsize < 4)
1293 return seterror(E2BIG);
1294 if (cv->codepage == 1200) /* little endian */
1295 {
1296 buf[2] = (wbuf[1] & 0x00FF);
1297 buf[3] = (wbuf[1] & 0xFF00) >> 8;
1298 }
1299 else if (cv->codepage == 1201) /* big endian */
1300 {
1301 buf[2] = (wbuf[1] & 0xFF00) >> 8;
1302 buf[3] = (wbuf[1] & 0x00FF);
1303 }
1304 return 4;
1305 }
1306 return 2;
1307}
1308
1309static int
1310utf32_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize)
1311{
1312 int codepage = cv->codepage;
1313 uint wc = 0xD800;
1314
1315 /* swap endian: 12000 <-> 12001 */
1316 if (cv->mode & UNICODE_MODE_SWAPPED)
1317 codepage ^= 1;
1318
1319 if (bufsize < 4)
1320 return seterror(EINVAL);
1321 if (codepage == 12000) /* little endian */
1322 wc = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
1323 else if (codepage == 12001) /* big endian */
1324 wc = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
1325
1326 if ((cv->flags & FLAG_USE_BOM) && !(cv->mode & UNICODE_MODE_BOM_DONE))
1327 {
1328 cv->mode |= UNICODE_MODE_BOM_DONE;
1329 if (wc == 0xFFFE0000)
1330 {
1331 cv->mode |= UNICODE_MODE_SWAPPED;
1332 *wbufsize = 0;
1333 return 4;
1334 }
1335 else if (wc == 0x0000FEFF)
1336 {
1337 *wbufsize = 0;
1338 return 4;
1339 }
1340 }
1341
1342 if ((0xD800 <= wc && wc <= 0xDFFF) || 0x10FFFF < wc)
1343 return seterror(EILSEQ);
1344 ucs4_to_utf16(wc, wbuf, wbufsize);
1345 return 4;
1346}
1347
1348static int
1349utf32_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize)
1350{
1351 uint wc;
1352
1353 if ((cv->flags & FLAG_USE_BOM) && !(cv->mode & UNICODE_MODE_BOM_DONE))
1354 {
1355 int r;
1356
1357 cv->mode |= UNICODE_MODE_BOM_DONE;
1358 if (bufsize < 4)
1359 return seterror(E2BIG);
1360 if (cv->codepage == 12000) /* little endian */
1361 memcpy(buf, "\xFF\xFE\x00\x00", 4);
1362 else if (cv->codepage == 12001) /* big endian */
1363 memcpy(buf, "\x00\x00\xFE\xFF", 4);
1364
1365 r = utf32_wctomb(cv, wbuf, wbufsize, buf + 4, bufsize - 4);
1366 if (r == -1)
1367 return -1;
1368 return r + 4;
1369 }
1370
1371 if (bufsize < 4)
1372 return seterror(E2BIG);
1373 wc = utf16_to_ucs4(wbuf);
1374 if (cv->codepage == 12000) /* little endian */
1375 {
1376 buf[0] = wc & 0x000000FF;
1377 buf[1] = (wc & 0x0000FF00) >> 8;
1378 buf[2] = (wc & 0x00FF0000) >> 16;
1379 buf[3] = (wc & 0xFF000000) >> 24;
1380 }
1381 else if (cv->codepage == 12001) /* big endian */
1382 {
1383 buf[0] = (wc & 0xFF000000) >> 24;
1384 buf[1] = (wc & 0x00FF0000) >> 16;
1385 buf[2] = (wc & 0x0000FF00) >> 8;
1386 buf[3] = wc & 0x000000FF;
1387 }
1388 return 4;
1389}
1390
1391/*
1392 * 50220: ISO 2022 Japanese with no halfwidth Katakana; Japanese (JIS)
1393 * 50221: ISO 2022 Japanese with halfwidth Katakana; Japanese (JIS-Allow
1394 * 1 byte Kana)
1395 * 50222: ISO 2022 Japanese JIS X 0201-1989; Japanese (JIS-Allow 1 byte
1396 * Kana - SO/SI)
1397 *
1398 * MultiByteToWideChar() and WideCharToMultiByte() behave differently
1399 * depending on Windows version. On XP, WideCharToMultiByte() doesn't
1400 * terminate result sequence with ascii escape. But Vista does.
1401 * Use MLang instead.
1402 */
1403
1404#define ISO2022_MODE(cs, shift) (((cs) << 8) | (shift))
1405#define ISO2022_MODE_CS(mode) (((mode) >> 8) & 0xFF)
1406#define ISO2022_MODE_SHIFT(mode) ((mode) & 0xFF)
1407
1408#define ISO2022_SI 0
1409#define ISO2022_SO 1
1410
1411/* shift in */
1412static const char iso2022_SI_seq[] = "\x0F";
1413/* shift out */
1414static const char iso2022_SO_seq[] = "\x0E";
1415
1416typedef struct iso2022_esc_t iso2022_esc_t;
1417struct iso2022_esc_t {
1418 const char *esc;
1419 int esc_len;
1420 int len;
1421 int cs;
1422};
1423
1424#define ISO2022JP_CS_ASCII 0
1425#define ISO2022JP_CS_JISX0201_ROMAN 1
1426#define ISO2022JP_CS_JISX0201_KANA 2
1427#define ISO2022JP_CS_JISX0208_1978 3
1428#define ISO2022JP_CS_JISX0208_1983 4
1429#define ISO2022JP_CS_JISX0212 5
1430
1431static iso2022_esc_t iso2022jp_esc[] = {
1432 {"\x1B\x28\x42", 3, 1, ISO2022JP_CS_ASCII},
1433 {"\x1B\x28\x4A", 3, 1, ISO2022JP_CS_JISX0201_ROMAN},
1434 {"\x1B\x28\x49", 3, 1, ISO2022JP_CS_JISX0201_KANA},
1435 {"\x1B\x24\x40", 3, 2, ISO2022JP_CS_JISX0208_1983}, /* unify 1978 with 1983 */
1436 {"\x1B\x24\x42", 3, 2, ISO2022JP_CS_JISX0208_1983},
1437 {"\x1B\x24\x28\x44", 4, 2, ISO2022JP_CS_JISX0212},
1438 {NULL, 0, 0, 0}
1439};
1440
1441static int
1442iso2022jp_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize)
1443{
1444 iso2022_esc_t *iesc = iso2022jp_esc;
1445 char tmp[MB_CHAR_MAX];
1446 int insize;
1447 HRESULT hr;
1448 DWORD dummy = 0;
1449 int len;
1450 int esc_len;
1451 int cs;
1452 int shift;
1453 int i;
1454
1455 if (buf[0] == 0x1B)
1456 {
1457 for (i = 0; iesc[i].esc != NULL; ++i)
1458 {
1459 esc_len = iesc[i].esc_len;
1460 if (bufsize < esc_len)
1461 {
1462 if (strncmp((char *)buf, iesc[i].esc, bufsize) == 0)
1463 return seterror(EINVAL);
1464 }
1465 else
1466 {
1467 if (strncmp((char *)buf, iesc[i].esc, esc_len) == 0)
1468 {
1469 cv->mode = ISO2022_MODE(iesc[i].cs, ISO2022_SI);
1470 *wbufsize = 0;
1471 return esc_len;
1472 }
1473 }
1474 }
1475 /* not supported escape sequence */
1476 return seterror(EILSEQ);
1477 }
1478 else if (buf[0] == iso2022_SO_seq[0])
1479 {
1480 cv->mode = ISO2022_MODE(ISO2022_MODE_CS(cv->mode), ISO2022_SO);
1481 *wbufsize = 0;
1482 return 1;
1483 }
1484 else if (buf[0] == iso2022_SI_seq[0])
1485 {
1486 cv->mode = ISO2022_MODE(ISO2022_MODE_CS(cv->mode), ISO2022_SI);
1487 *wbufsize = 0;
1488 return 1;
1489 }
1490
1491 cs = ISO2022_MODE_CS(cv->mode);
1492 shift = ISO2022_MODE_SHIFT(cv->mode);
1493
1494 /* reset the mode for informal sequence */
1495 if (buf[0] < 0x20)
1496 {
1497 cs = ISO2022JP_CS_ASCII;
1498 shift = ISO2022_SI;
1499 }
1500
1501 len = iesc[cs].len;
1502 if (bufsize < len)
1503 return seterror(EINVAL);
1504 for (i = 0; i < len; ++i)
1505 if (!(buf[i] < 0x80))
1506 return seterror(EILSEQ);
1507 esc_len = iesc[cs].esc_len;
1508 memcpy(tmp, iesc[cs].esc, esc_len);
1509 if (shift == ISO2022_SO)
1510 {
1511 memcpy(tmp + esc_len, iso2022_SO_seq, 1);
1512 esc_len += 1;
1513 }
1514 memcpy(tmp + esc_len, buf, len);
1515
1516 if ((cv->codepage == 50220 || cv->codepage == 50221
1517 || cv->codepage == 50222) && shift == ISO2022_SO)
1518 {
1519 /* XXX: shift-out cannot be used for mbtowc (both kernel and
1520 * mlang) */
1521 esc_len = iesc[ISO2022JP_CS_JISX0201_KANA].esc_len;
1522 memcpy(tmp, iesc[ISO2022JP_CS_JISX0201_KANA].esc, esc_len);
1523 memcpy(tmp + esc_len, buf, len);
1524 }
1525
1526 insize = len + esc_len;
1527 hr = ConvertINetMultiByteToUnicode(&dummy, cv->codepage,
1528 (const char *)tmp, &insize, (wchar_t *)wbuf, wbufsize);
1529 if (hr != S_OK || insize != len + esc_len)
1530 return seterror(EILSEQ);
1531
1532 /* Check for conversion error. Assuming defaultChar is 0x3F. */
1533 /* ascii should be converted from ascii */
1534 if (wbuf[0] == buf[0]
1535 && cv->mode != ISO2022_MODE(ISO2022JP_CS_ASCII, ISO2022_SI))
1536 return seterror(EILSEQ);
1537
1538 /* reset the mode for informal sequence */
1539 if (cv->mode != ISO2022_MODE(cs, shift))
1540 cv->mode = ISO2022_MODE(cs, shift);
1541
1542 return len;
1543}
1544
1545static int
1546iso2022jp_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize)
1547{
1548 iso2022_esc_t *iesc = iso2022jp_esc;
1549 char tmp[MB_CHAR_MAX];
1550 int tmpsize = MB_CHAR_MAX;
1551 int insize = wbufsize;
1552 HRESULT hr;
1553 DWORD dummy = 0;
1554 int len;
1555 int esc_len;
1556 int cs;
1557 int shift;
1558 int i;
1559
1560 /*
1561 * MultiByte = [escape sequence] + character + [escape sequence]
1562 *
1563 * Whether trailing escape sequence is added depends on which API is
1564 * used (kernel or MLang, and its version).
1565 */
1566 hr = ConvertINetUnicodeToMultiByte(&dummy, cv->codepage,
1567 (const wchar_t *)wbuf, &wbufsize, tmp, &tmpsize);
1568 if (hr != S_OK || insize != wbufsize)
1569 return seterror(EILSEQ);
1570 else if (bufsize < tmpsize)
1571 return seterror(E2BIG);
1572
1573 if (tmpsize == 1)
1574 {
1575 cs = ISO2022JP_CS_ASCII;
1576 esc_len = 0;
1577 }
1578 else
1579 {
1580 for (i = 1; iesc[i].esc != NULL; ++i)
1581 {
1582 esc_len = iesc[i].esc_len;
1583 if (strncmp(tmp, iesc[i].esc, esc_len) == 0)
1584 {
1585 cs = iesc[i].cs;
1586 break;
1587 }
1588 }
1589 if (iesc[i].esc == NULL)
1590 /* not supported escape sequence */
1591 return seterror(EILSEQ);
1592 }
1593
1594 shift = ISO2022_SI;
1595 if (tmp[esc_len] == iso2022_SO_seq[0])
1596 {
1597 shift = ISO2022_SO;
1598 esc_len += 1;
1599 }
1600
1601 len = iesc[cs].len;
1602
1603 /* Check for converting error. Assuming defaultChar is 0x3F. */
1604 /* ascii should be converted from ascii */
1605 if (cs == ISO2022JP_CS_ASCII && !(wbuf[0] < 0x80))
1606 return seterror(EILSEQ);
1607 else if (tmpsize < esc_len + len)
1608 return seterror(EILSEQ);
1609
1610 if (cv->mode == ISO2022_MODE(cs, shift))
1611 {
1612 /* remove escape sequence */
1613 if (esc_len != 0)
1614 memmove(tmp, tmp + esc_len, len);
1615 esc_len = 0;
1616 }
1617 else
1618 {
1619 if (cs == ISO2022JP_CS_ASCII)
1620 {
1621 esc_len = iesc[ISO2022JP_CS_ASCII].esc_len;
1622 memmove(tmp + esc_len, tmp, len);
1623 memcpy(tmp, iesc[ISO2022JP_CS_ASCII].esc, esc_len);
1624 }
1625 if (ISO2022_MODE_SHIFT(cv->mode) == ISO2022_SO)
1626 {
1627 /* shift-in before changing to other mode */
1628 memmove(tmp + 1, tmp, len + esc_len);
1629 memcpy(tmp, iso2022_SI_seq, 1);
1630 esc_len += 1;
1631 }
1632 }
1633
1634 if (bufsize < len + esc_len)
1635 return seterror(E2BIG);
1636 memcpy(buf, tmp, len + esc_len);
1637 cv->mode = ISO2022_MODE(cs, shift);
1638 return len + esc_len;
1639}
1640
1641static int
1642iso2022jp_flush(csconv_t *cv, uchar *buf, int bufsize)
1643{
1644 iso2022_esc_t *iesc = iso2022jp_esc;
1645 int esc_len;
1646
1647 if (cv->mode != ISO2022_MODE(ISO2022JP_CS_ASCII, ISO2022_SI))
1648 {
1649 esc_len = 0;
1650 if (ISO2022_MODE_SHIFT(cv->mode) != ISO2022_SI)
1651 esc_len += 1;
1652 if (ISO2022_MODE_CS(cv->mode) != ISO2022JP_CS_ASCII)
1653 esc_len += iesc[ISO2022JP_CS_ASCII].esc_len;
1654 if (bufsize < esc_len)
1655 return seterror(E2BIG);
1656
1657 esc_len = 0;
1658 if (ISO2022_MODE_SHIFT(cv->mode) != ISO2022_SI)
1659 {
1660 memcpy(buf, iso2022_SI_seq, 1);
1661 esc_len += 1;
1662 }
1663 if (ISO2022_MODE_CS(cv->mode) != ISO2022JP_CS_ASCII)
1664 {
1665 memcpy(buf + esc_len, iesc[ISO2022JP_CS_ASCII].esc,
1666 iesc[ISO2022JP_CS_ASCII].esc_len);
1667 esc_len += iesc[ISO2022JP_CS_ASCII].esc_len;
1668 }
1669 return esc_len;
1670 }
1671 return 0;
1672}
1673
1674static void process_file(iconv_t cd, FILE *in, FILE *out)
1675{
1676 char inbuf[BUFSIZ];
1677 char outbuf[BUFSIZ];
1678 const char *pin;
1679 char *pout;
1680 size_t inbytesleft;
1681 size_t outbytesleft;
1682 size_t rest = 0;
1683 size_t r;
1684
1685 while ((inbytesleft=fread(inbuf+rest, 1, sizeof(inbuf)-rest, in)) != 0
1686 || rest != 0) {
1687 inbytesleft += rest;
1688 pin = inbuf;
1689 pout = outbuf;
1690 outbytesleft = sizeof(outbuf);
1691 r = iconv(cd, &pin, &inbytesleft, &pout, &outbytesleft);
1692 fwrite(outbuf, 1, sizeof(outbuf) - outbytesleft, out);
1693 if (r == (size_t)(-1) && errno != E2BIG &&
1694 (errno != EINVAL || feof(in)))
1695 bb_perror_msg_and_die("conversion error");
1696 memmove(inbuf, pin, inbytesleft);
1697 rest = inbytesleft;
1698 if (rest == 0 && feof(in))
1699 break;
1700 }
1701 pout = outbuf;
1702 outbytesleft = sizeof(outbuf);
1703 r = iconv(cd, NULL, NULL, &pout, &outbytesleft);
1704 fwrite(outbuf, 1, sizeof(outbuf) - outbytesleft, out);
1705 if (r == (size_t)(-1))
1706 bb_perror_msg_and_die("conversion error");
1707}
1708
1709enum {
1710 OPT_f = (1 << 0),
1711 OPT_t = (1 << 1),
1712 OPT_l = (1 << 2),
1713 OPT_c = (1 << 3),
1714 OPT_o = (1 << 4),
1715};
1716
1717int iconv_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
1718int iconv_main(int argc, char **argv)
1719{
1720 const char *fromcode = "", *tocode = "", *outfile;
1721 char *tmpname = NULL;
1722 int i, opt;
1723 iconv_t cd;
1724 FILE *in;
1725 FILE *out = stdout;
1726
1727 opt = getopt32(argv, "f:t:lco:", &fromcode, &tocode, &outfile);
1728
1729 if (opt & OPT_l) {
1730 const char *alias = cp_alias;
1731 while (*alias) {
1732 printf("%s\n", alias);
1733 alias += strlen(alias) + 1;
1734 }
1735 return 0;
1736 }
1737
1738 if (opt & OPT_o) {
1739 tmpname = xasprintf("%sXXXXXX", outfile);
1740 mktemp(tmpname);
1741 out = xfopen(tmpname, "wb");
1742 }
1743
1744 if (opt & OPT_c)
1745 tocode = xasprintf("%s//IGNORE", tocode);
1746
1747 cd = iconv_open(tocode, fromcode);
1748 if (cd == (iconv_t)(-1))
1749 bb_perror_msg_and_die("iconv_open error");
1750
1751 if (optind == argc)
1752 argv[argc++] = (char *)"-";
1753
1754 for (i=optind; i<argc; ++i) {
1755 if (argv[i][0] == '-' && argv[i][1] == '\0')
1756 in = stdin;
1757 else
1758 in = xfopen(argv[optind], "rb");
1759 process_file(cd, in, out);
1760 fclose(in);
1761 }
1762
1763 if (tmpname) {
1764 fclose(out);
1765 xrename(tmpname, outfile);
1766 }
1767
1768 if (ENABLE_FEATURE_CLEAN_UP)
1769 iconv_close(cd);
1770 return 0;
1771}
diff --git a/miscutils/inotifyd.c b/miscutils/inotifyd.c
index 8bff86ae5..fdd04c292 100644
--- a/miscutils/inotifyd.c
+++ b/miscutils/inotifyd.c
@@ -45,8 +45,11 @@
45//usage: "\nPROG ACTUAL_EVENTS FILEn [SUBFILE] is run." 45//usage: "\nPROG ACTUAL_EVENTS FILEn [SUBFILE] is run."
46//usage: "\nIf PROG is -, events are sent to stdout." 46//usage: "\nIf PROG is -, events are sent to stdout."
47//usage: "\nEvents:" 47//usage: "\nEvents:"
48//usage: IF_NOT_PLATFORM_MINGW32(
48//usage: "\n a File is accessed" 49//usage: "\n a File is accessed"
50//usage: )
49//usage: "\n c File is modified" 51//usage: "\n c File is modified"
52//usage: IF_NOT_PLATFORM_MINGW32(
50//usage: "\n e Metadata changed" 53//usage: "\n e Metadata changed"
51//usage: "\n w Writable file is closed" 54//usage: "\n w Writable file is closed"
52//usage: "\n 0 Unwritable file is closed" 55//usage: "\n 0 Unwritable file is closed"
@@ -55,8 +58,11 @@
55//usage: "\n M File is moved" 58//usage: "\n M File is moved"
56//usage: "\n u Backing fs is unmounted" 59//usage: "\n u Backing fs is unmounted"
57//usage: "\n o Event queue overflowed" 60//usage: "\n o Event queue overflowed"
61//usage: )
58//usage: "\n x File can't be watched anymore" 62//usage: "\n x File can't be watched anymore"
63//usage: IF_NOT_PLATFORM_MINGW32(
59//usage: "\nIf watching a directory:" 64//usage: "\nIf watching a directory:"
65//usage: )
60//usage: "\n y Subfile is moved into dir" 66//usage: "\n y Subfile is moved into dir"
61//usage: "\n m Subfile is moved out of dir" 67//usage: "\n m Subfile is moved out of dir"
62//usage: "\n n Subfile is created" 68//usage: "\n n Subfile is created"
@@ -69,6 +75,7 @@
69#include "common_bufsiz.h" 75#include "common_bufsiz.h"
70#include <sys/inotify.h> 76#include <sys/inotify.h>
71 77
78#if !ENABLE_PLATFORM_MINGW32
72static const char mask_names[] ALIGN1 = 79static const char mask_names[] ALIGN1 =
73 "a" // 0x00000001 File was accessed 80 "a" // 0x00000001 File was accessed
74 "c" // 0x00000002 File was modified 81 "c" // 0x00000002 File was modified
@@ -222,3 +229,207 @@ int inotifyd_main(int argc, char **argv)
222 done: 229 done:
223 return bb_got_signal; 230 return bb_got_signal;
224} 231}
232#else /* ENABLE_PLATFORM_MINGW32 */
233/*
234 * Order is important: the indices match the values taken by the
235 * Action member of the FILE_NOTIFY_INFORMATION structure, including
236 * the undocumented zero value when the directory itself is deleted.
237 */
238static const char mask_names[] ALIGN1 =
239 "x" // File is no longer watched (usually deleted)
240 "n" // Subfile was created
241 "d" // Subfile was deleted
242 "c" // File was modified
243 "m" // File was moved from X
244 "y" // File was moved to Y
245;
246
247enum {
248 MASK_BITS = sizeof(mask_names) - 1
249};
250
251static const unsigned mask_values[] = {
252 0x000, // File is no longer watched (usually deleted)
253 0x003, // Subfile was created
254 0x003, // Subfile was deleted
255 0x1fc, // File was modified (everything except create/delete/move)
256 0x003, // File was moved from X
257 0x003, // File was moved to Y
258};
259
260struct watch {
261 HANDLE hdir;
262 HANDLE hevent;
263 DWORD mask; // notification filter
264 DWORD bits; // events to report
265 OVERLAPPED overlap;
266 const char *dirname;
267 char buf[2048];
268};
269
270static void run_agent(const char *agent, FILE_NOTIFY_INFORMATION *info,
271 struct watch *w)
272{
273 int len;
274 char filename[MAX_PATH];
275 char event[2];
276 const char *args[5];
277
278 memset(filename, 0, sizeof(filename));
279 len = WideCharToMultiByte(CP_ACP, 0, info->FileName,
280 info->FileNameLength/2, filename, sizeof(filename),
281 NULL, NULL);
282
283 if (info->Action >= 0 && info->Action < 6 &&
284 ((1 << info->Action) & w->bits)) {
285 event[0] = mask_names[info->Action];
286 event[1] = '\0';
287
288 if (LONE_CHAR(agent, '-')) {
289 /* "inotifyd - FILE": built-in echo */
290 printf(len ? "%s\t%s\t%s\n" : "%s\t%s\n",
291 event, w->dirname, filename);
292 fflush(stdout);
293 }
294 else {
295 args[0] = agent;
296 args[1] = event;
297 args[2] = w->dirname;
298 args[3] = len ? filename : NULL;
299 args[4] = NULL;
300 spawn_and_wait((char **)args);
301 }
302 }
303}
304
305static BOOL start_watch(struct watch *w)
306{
307 DWORD nret;
308
309 memset(w->buf, 0, sizeof(w->buf));
310 memset(&w->overlap, 0, sizeof(OVERLAPPED));
311 w->overlap.hEvent = w->hevent;
312 ResetEvent(w->hevent);
313
314 return ReadDirectoryChangesW(w->hdir, w->buf, sizeof(w->buf),
315 FALSE, w->mask, &nret, &w->overlap, NULL);
316}
317
318int inotifyd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
319int inotifyd_main(int argc, char **argv)
320{
321 int n;
322 unsigned mask, bits;
323 const char *agent;
324 HANDLE *hevent;
325 struct watch *watch;
326
327 // sanity check: agent and at least one watch must be given
328 if (!argv[1] || !argv[2])
329 bb_show_usage();
330
331 argv++;
332 agent = *argv;
333 argc -= 2; // number of files we watch
334
335 watch = (struct watch *)xzalloc(argc * sizeof(struct watch));
336 hevent = (HANDLE *)xzalloc(argc * sizeof(HANDLE));
337
338 // setup watches
339 for (n = 0; *++argv; ++n) {
340 char *masks;
341
342 masks = strrchr(*argv, ':');
343 // don't confuse a drive prefix with a mask
344 if (masks && masks != (*argv)+1)
345 *masks = '\0';
346
347 mask = 0x01ff; // assuming we want all notifications
348 bits = 0x3f; // assuming we want to report everything
349 // if mask is specified ->
350 if (masks && *masks == '\0') {
351 // convert names to notification filter and report bitmask
352 mask = bits = 0;
353 while (*++masks) {
354 const char *found;
355 found = memchr(mask_names, *masks, MASK_BITS);
356 if (found) {
357 mask |= mask_values[(found - mask_names)];
358 bits |= (1 << (found - mask_names));
359 }
360 }
361 }
362
363 if (mask == 0)
364 bb_error_msg_and_die("%s: invalid mask\n", *argv);
365
366 if (!is_directory(*argv, FALSE))
367 bb_error_msg_and_die("%s: not a directory", *argv);
368
369 watch[n].hdir = CreateFile(*argv, GENERIC_READ|FILE_LIST_DIRECTORY,
370 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
371 NULL, OPEN_EXISTING,
372 FILE_FLAG_BACKUP_SEMANTICS|FILE_FLAG_OVERLAPPED, NULL);
373 if (watch[n].hdir == INVALID_HANDLE_VALUE)
374 break;
375
376 watch[n].dirname = *argv;
377 watch[n].mask = mask;
378 watch[n].bits = bits;
379 watch[n].hevent = hevent[n] = CreateEvent(NULL, TRUE, FALSE, NULL);
380
381 if (!start_watch(watch+n))
382 break;
383 }
384
385 if (*argv != NULL) {
386 errno = err_win_to_posix();
387 bb_perror_msg_and_die("add watch (%s) failed", *argv);
388 }
389
390 while (1) {
391 DWORD status;
392
393 status = WaitForMultipleObjects(n, hevent, FALSE, INFINITE);
394 if (WAIT_OBJECT_0 <= status && status < WAIT_OBJECT_0 + n) {
395 FILE_NOTIFY_INFORMATION *info;
396 int index = status - WAIT_OBJECT_0;
397 int offset = 0;
398 struct watch *w = watch + index;
399 int got_zero = 0;
400
401 do {
402 info = (FILE_NOTIFY_INFORMATION *)(w->buf + offset);
403 got_zero += (info->Action == 0);
404 run_agent(agent, info, w);
405 offset += info->NextEntryOffset;
406 } while (info->NextEntryOffset);
407
408 if (!start_watch(w)) {
409 // directory was deleted?
410 int i, count;
411
412 if (!got_zero) {
413 // we haven't seen an 'x' event, fake one
414 memset(info, 0, sizeof(FILE_NOTIFY_INFORMATION));
415 run_agent(agent, info, w);
416 }
417
418 // mark watch as dead, terminate if all are dead
419 w->mask = 0;
420 for (count = i = 0; i<n; ++i)
421 if (watch[i].mask)
422 ++count;
423 if (count == 0)
424 break;
425 }
426 }
427 else {
428 errno = err_win_to_posix();
429 bb_perror_msg_and_die("watch failed");
430 }
431 }
432
433 return EXIT_SUCCESS;
434}
435#endif
diff --git a/miscutils/jn.c b/miscutils/jn.c
new file mode 100644
index 000000000..db6a3e6d9
--- /dev/null
+++ b/miscutils/jn.c
@@ -0,0 +1,37 @@
1/*
2 * directory junction creation for busybox
3 *
4 * Copyright (C) 2017 Denys Vlasenko <vda.linux@googlemail.com>
5 * Copyright (C) 2022 Ron Yorston <rmy@pobox.com>
6 *
7 * Licensed under GPLv2, see file LICENSE in this source tree.
8 */
9//config:config JN
10//config: bool "jn (3.2 kb)"
11//config: default y
12//config: depends on PLATFORM_MINGW32
13//config: help
14//config: Creates a directory junction.
15
16//applet:IF_JN(APPLET_NOEXEC(jn, jn, BB_DIR_USR_BIN, BB_SUID_DROP, jn))
17
18//kbuild:lib-$(CONFIG_JN) += jn.o
19
20//usage:#define jn_trivial_usage
21//usage: "DIR JUNC"
22//usage:#define jn_full_usage "\n\n"
23//usage: "Create directory junction JUNC to DIR"
24
25#include "libbb.h"
26
27int jn_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
28int jn_main(int argc UNUSED_PARAM, char **argv)
29{
30 getopt32(argv, "^" "" "\0" "=2");
31 argv += optind;
32 if (create_junction(argv[0], argv[1]) != 0) {
33 bb_perror_msg_and_die("can't create junction '%s' to '%s'",
34 argv[1], argv[0]);
35 }
36 return EXIT_SUCCESS;
37}
diff --git a/miscutils/less.c b/miscutils/less.c
index 8a0525cb7..467c76e2a 100644
--- a/miscutils/less.c
+++ b/miscutils/less.c
@@ -145,6 +145,10 @@
145 145
146#include <sched.h> /* sched_yield() */ 146#include <sched.h> /* sched_yield() */
147 147
148#if ENABLE_PLATFORM_MINGW32
149#include <conio.h>
150#endif
151
148#include "libbb.h" 152#include "libbb.h"
149#include "common_bufsiz.h" 153#include "common_bufsiz.h"
150#if ENABLE_FEATURE_LESS_REGEXP 154#if ENABLE_FEATURE_LESS_REGEXP
@@ -330,7 +334,11 @@ static void restore_tty(void)
330 set_tty_cooked(); 334 set_tty_cooked();
331 if (!(G.kbd_fd_orig_flags & O_NONBLOCK)) 335 if (!(G.kbd_fd_orig_flags & O_NONBLOCK))
332 ndelay_off(kbd_fd); 336 ndelay_off(kbd_fd);
337#if !ENABLE_PLATFORM_MINGW32
333 clear_line(); 338 clear_line();
339#else
340 printf(ESC"[?1049l");
341#endif
334} 342}
335 343
336static NOINLINE void less_exit(void) 344static NOINLINE void less_exit(void)
@@ -578,6 +586,11 @@ static void read_lines(void)
578 last_line_pos = 0; 586 last_line_pos = 0;
579 break; 587 break;
580 } 588 }
589#if ENABLE_PLATFORM_MINGW32
590 if (c == '\r') {
591 continue;
592 }
593#endif
581 /* NUL is substituted by '\n'! */ 594 /* NUL is substituted by '\n'! */
582 if (c == '\0') c = '\n'; 595 if (c == '\0') c = '\n';
583 *p++ = c; 596 *p++ = c;
@@ -674,7 +687,12 @@ static void update_num_lines(void)
674 /* only do this for regular files */ 687 /* only do this for regular files */
675 if (num_lines == REOPEN_AND_COUNT || num_lines == REOPEN_STDIN) { 688 if (num_lines == REOPEN_AND_COUNT || num_lines == REOPEN_STDIN) {
676 count = 0; 689 count = 0;
690#if !ENABLE_PLATFORM_MINGW32
677 fd = open("/proc/self/fd/0", O_RDONLY); 691 fd = open("/proc/self/fd/0", O_RDONLY);
692#else
693 /* don't even try to access /proc on WIN32 */
694 fd = -1;
695#endif
678 if (fd < 0 && num_lines == REOPEN_AND_COUNT) { 696 if (fd < 0 && num_lines == REOPEN_AND_COUNT) {
679 /* "filename" is valid only if REOPEN_AND_COUNT */ 697 /* "filename" is valid only if REOPEN_AND_COUNT */
680 fd = open(filename, O_RDONLY); 698 fd = open(filename, O_RDONLY);
@@ -857,7 +875,12 @@ static void print_found(const char *line)
857 match_status = 1; 875 match_status = 1;
858 } 876 }
859 877
878#if !ENABLE_PLATFORM_MINGW32
860 printf("%s%s\n", growline ? growline : "", str); 879 printf("%s%s\n", growline ? growline : "", str);
880#else
881 /* skip newline, we use explicit positioning on WIN32 */
882 printf("%s%s", growline ? growline : "", str);
883#endif
861 free(growline); 884 free(growline);
862} 885}
863#else 886#else
@@ -893,7 +916,12 @@ static void print_ascii(const char *str)
893 *p = '\0'; 916 *p = '\0';
894 print_hilite(buf); 917 print_hilite(buf);
895 } 918 }
919#if !ENABLE_PLATFORM_MINGW32
896 puts(str); 920 puts(str);
921#else
922 /* skip newline, we use explicit positioning on WIN32 */
923 printf("%s", str);
924#endif
897} 925}
898 926
899/* Print the buffer */ 927/* Print the buffer */
@@ -903,6 +931,10 @@ static void buffer_print(void)
903 931
904 move_cursor(0, 0); 932 move_cursor(0, 0);
905 for (i = 0; i <= max_displayed_line; i++) { 933 for (i = 0; i <= max_displayed_line; i++) {
934#if ENABLE_PLATFORM_MINGW32
935 /* make sure we're on the right line */
936 move_cursor(i+1, 0);
937#endif
906 printf(CLEAR_2_EOL); 938 printf(CLEAR_2_EOL);
907 if (option_mask32 & FLAG_N) 939 if (option_mask32 & FLAG_N)
908 print_lineno(buffer[i]); 940 print_lineno(buffer[i]);
@@ -1090,10 +1122,17 @@ static void reinitialize(void)
1090 if (G.winsize_err) 1122 if (G.winsize_err)
1091 printf(ESC"[999;999H" ESC"[6n"); 1123 printf(ESC"[999;999H" ESC"[6n");
1092#endif 1124#endif
1125#if ENABLE_PLATFORM_MINGW32
1126 printf(ESC"[?1049h");
1127#endif
1093 buffer_fill_and_print(); 1128 buffer_fill_and_print();
1094} 1129}
1095 1130
1131#if ENABLE_PLATFORM_MINGW32
1132static int64_t unix_getch_nowait(void)
1133#else
1096static int64_t getch_nowait(void) 1134static int64_t getch_nowait(void)
1135#endif
1097{ 1136{
1098 int rd; 1137 int rd;
1099 int64_t key64; 1138 int64_t key64;
@@ -1155,6 +1194,50 @@ static int64_t getch_nowait(void)
1155 return key64; 1194 return key64;
1156} 1195}
1157 1196
1197#if ENABLE_PLATFORM_MINGW32
1198static int64_t getch_nowait(void)
1199{
1200 int64_t c;
1201
1202 if (terminal_mode(FALSE) & VT_INPUT)
1203 return unix_getch_nowait();
1204
1205retry:
1206 c = _getch();
1207 if (c == 0 || c == 0xe0) {
1208 switch (_getch()) {
1209 case 0x48:
1210 c = KEYCODE_UP;
1211 break;
1212 case 0x50:
1213 c = KEYCODE_DOWN;
1214 break;
1215 case 0x49:
1216 c = KEYCODE_PAGEUP;
1217 break;
1218 case 0x51:
1219 c = KEYCODE_PAGEDOWN;
1220 break;
1221 case 0x47:
1222 c = KEYCODE_HOME;
1223 break;
1224 case 0x4f:
1225 c = KEYCODE_END;
1226 break;
1227 default:
1228 goto retry;
1229 }
1230 }
1231
1232 /* Position cursor if line input is done */
1233 if (less_gets_pos >= 0)
1234 move_cursor(max_displayed_line + 2, less_gets_pos + 1);
1235 fflush_all();
1236
1237 return c;
1238}
1239#endif
1240
1158/* Grab a character from input without requiring the return key. 1241/* Grab a character from input without requiring the return key.
1159 * May return KEYCODE_xxx values. 1242 * May return KEYCODE_xxx values.
1160 * Note that this function works best with raw input. */ 1243 * Note that this function works best with raw input. */
@@ -1794,11 +1877,13 @@ static void keypress_process(int keypress)
1794 number_process(keypress); 1877 number_process(keypress);
1795} 1878}
1796 1879
1880#if !ENABLE_PLATFORM_MINGW32
1797static void sig_catcher(int sig) 1881static void sig_catcher(int sig)
1798{ 1882{
1799 restore_tty(); 1883 restore_tty();
1800 kill_myself_with_sig(sig); /* does not return */ 1884 kill_myself_with_sig(sig); /* does not return */
1801} 1885}
1886#endif
1802 1887
1803#if ENABLE_FEATURE_LESS_WINCH 1888#if ENABLE_FEATURE_LESS_WINCH
1804static void sigwinch_handler(int sig UNUSED_PARAM) 1889static void sigwinch_handler(int sig UNUSED_PARAM)
@@ -1810,7 +1895,11 @@ static void sigwinch_handler(int sig UNUSED_PARAM)
1810int less_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 1895int less_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
1811int less_main(int argc, char **argv) 1896int less_main(int argc, char **argv)
1812{ 1897{
1898#if !ENABLE_PLATFORM_MINGW32
1813 char *tty_name; 1899 char *tty_name;
1900#else
1901 HANDLE h;
1902#endif
1814 int tty_fd; 1903 int tty_fd;
1815 1904
1816 INIT_G(); 1905 INIT_G();
@@ -1869,6 +1958,7 @@ int less_main(int argc, char **argv)
1869 if (option_mask32 & FLAG_TILDE) 1958 if (option_mask32 & FLAG_TILDE)
1870 empty_line_marker = ""; 1959 empty_line_marker = "";
1871 1960
1961#if !ENABLE_PLATFORM_MINGW32
1872 /* Some versions of less can survive w/o controlling tty, 1962 /* Some versions of less can survive w/o controlling tty,
1873 * try to do the same. This also allows to specify an alternative 1963 * try to do the same. This also allows to specify an alternative
1874 * tty via "less 1<>TTY". 1964 * tty via "less 1<>TTY".
@@ -1894,6 +1984,15 @@ int less_main(int argc, char **argv)
1894 } 1984 }
1895 G.kbd_fd_orig_flags = ndelay_on(tty_fd); 1985 G.kbd_fd_orig_flags = ndelay_on(tty_fd);
1896 kbd_fd = tty_fd; /* save in a global */ 1986 kbd_fd = tty_fd; /* save in a global */
1987#else
1988 h = CreateFileA("CONIN$", GENERIC_READ | GENERIC_WRITE,
1989 FILE_SHARE_READ, NULL, OPEN_EXISTING,
1990 FILE_ATTRIBUTE_NORMAL, NULL);
1991 if (h == INVALID_HANDLE_VALUE)
1992 bb_simple_error_msg_and_die("unable to open console");
1993
1994 kbd_fd = tty_fd = _open_osfhandle((intptr_t)h, O_BINARY);
1995#endif
1897 1996
1898 get_termios_and_make_raw(tty_fd, &term_less, &term_orig, TERMIOS_RAW_CRNL_INPUT); 1997 get_termios_and_make_raw(tty_fd, &term_less, &term_orig, TERMIOS_RAW_CRNL_INPUT);
1899 1998
diff --git a/miscutils/make.c b/miscutils/make.c
new file mode 100644
index 000000000..7316408bf
--- /dev/null
+++ b/miscutils/make.c
@@ -0,0 +1,3382 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * make implementation for BusyBox
4 *
5 * Based on public domain POSIX make: https://frippery.org/make
6 */
7//config:config MAKE
8//config: bool "make (18 kb)"
9//config: default n
10//config: help
11//config: The make command can be used to maintain files that depend on
12//config: other files. Normally it's used to build programs from source
13//config: code but it can be used in other situations too.
14//config:
15//config:config PDPMAKE
16//config: bool "pdpmake (18 kb)"
17//config: default n
18//config: help
19//config: Alias for "make"
20//config:
21//config:config FEATURE_MAKE_POSIX
22//config: bool "Runtime enforcement of POSIX"
23//config: default n
24//config: depends on MAKE || PDPMAKE
25//config: help
26//config: Allow strict enforcement of POSIX compliance at runtime by:
27//config: - .POSIX special target in makefile
28//config: - '--posix' command line option
29//config: - PDPMAKE_POSIXLY_CORRECT environment variable
30//config: Enable this if you want to check whether your makefiles are
31//config: POSIX compliant. This adds about 1.7 kb.
32//config:
33//config:choice
34//config: prompt "Default POSIX level to enforce"
35//config: depends on FEATURE_MAKE_POSIX
36//config: default FEATURE_MAKE_POSIX_2017
37//config:
38//config:config FEATURE_MAKE_POSIX_2017
39//config: bool "2017"
40//config:
41//config:config FEATURE_MAKE_POSIX_2024
42//config: bool "2024"
43//config:
44//config:endchoice
45
46//applet:IF_MAKE(APPLET(make, BB_DIR_USR_BIN, BB_SUID_DROP))
47//applet:IF_PDPMAKE(APPLET_ODDNAME(pdpmake, make, BB_DIR_USR_BIN, BB_SUID_DROP, make))
48
49//kbuild:lib-$(CONFIG_MAKE) += make.o
50//kbuild:lib-$(CONFIG_PDPMAKE) += make.o
51
52//usage:#define make_trivial_usage
53//usage: IF_FEATURE_MAKE_POSIX(
54//usage: "[--posix] [-C DIR] [-f FILE] [-j NUM] [-x PRAG] [-eiknpqrsSt] [MACRO[:[:[:]]]=VAL]... [TARGET]..."
55//usage: )
56//usage: IF_NOT_FEATURE_MAKE_POSIX(
57//usage: "[-C DIR] [-f FILE] [-j NUM] [-eiknpqrsSt] [MACRO[:[:[:]]]=VAL]... [TARGET]..."
58//usage: )
59//usage:#define make_full_usage "\n\n"
60//usage: "Maintain files based on their dependencies\n"
61//usage: IF_FEATURE_MAKE_POSIX(
62//usage: "\n --posix Enforce POSIX mode"
63//usage: )
64//usage: "\n -C DIR Change to DIR"
65//usage: "\n -f FILE Makefile"
66//usage: "\n -j NUM Jobs to run in parallel (not implemented)"
67//usage: IF_FEATURE_MAKE_POSIX(
68//usage: "\n -x PRAG Make POSIX mode less strict"
69//usage: )
70//usage: "\n -e Environment variables override macros in makefiles"
71//usage: "\n -i Ignore exit status"
72//usage: "\n -k Continue on error"
73//usage: "\n -n Dry run"
74//usage: "\n -p Print macros and targets"
75//usage: "\n -q Query target; exit status 1 if not up to date"
76//usage: "\n -r Don't use built-in rules"
77//usage: "\n -s Make silently"
78//usage: "\n -S Stop on error"
79//usage: "\n -t Touch files instead of making them"
80//usage: IF_FEATURE_MAKE_POSIX(
81//usage: "\n\nThis build supports: non-POSIX extensions, POSIX 2024, POSIX 2017"
82//usage: )
83//usage: IF_FEATURE_MAKE_POSIX_2017(
84//usage: "\nIn strict POSIX mode the 2017 standard is enforced by default"
85//usage: )
86//usage: IF_FEATURE_MAKE_POSIX_2024(
87//usage: "\nIn strict POSIX mode the 2024 standard is enforced by default"
88//usage: )
89
90#include "libbb.h"
91#include "bb_archive.h"
92#include "common_bufsiz.h"
93#include <glob.h>
94
95// Supported POSIX levels
96#define STD_POSIX_2017 0
97#define STD_POSIX_2024 1
98
99#define POSIX_2017 (posix && posix_level == STD_POSIX_2017)
100
101#if ENABLE_FEATURE_MAKE_POSIX_2017
102# define DEFAULT_POSIX_LEVEL STD_POSIX_2017
103#else
104# define DEFAULT_POSIX_LEVEL STD_POSIX_2024
105#endif
106
107#define OPTSTR1 "eij:+knqrsSt"
108#if ENABLE_FEATURE_MAKE_POSIX
109#define OPTSTR2 "pf:*C:*x:*"
110#else
111#define OPTSTR2 "pf:*C:*"
112#endif
113
114enum {
115 OPTBIT_e = 0,
116 OPTBIT_i,
117 OPTBIT_j,
118 OPTBIT_k,
119 OPTBIT_n,
120 OPTBIT_q,
121 OPTBIT_r,
122 OPTBIT_s,
123 OPTBIT_S,
124 OPTBIT_t,
125 OPTBIT_p,
126 OPTBIT_f,
127 OPTBIT_C,
128 IF_FEATURE_MAKE_POSIX(OPTBIT_x,)
129 OPTBIT_precious,
130 OPTBIT_phony,
131 OPTBIT_include,
132 OPTBIT_make,
133
134 OPT_e = (1 << OPTBIT_e),
135 OPT_i = (1 << OPTBIT_i),
136 OPT_j = (1 << OPTBIT_j),
137 OPT_k = (1 << OPTBIT_k),
138 OPT_n = (1 << OPTBIT_n),
139 OPT_q = (1 << OPTBIT_q),
140 OPT_r = (1 << OPTBIT_r),
141 OPT_s = (1 << OPTBIT_s),
142 OPT_S = (1 << OPTBIT_S),
143 OPT_t = (1 << OPTBIT_t),
144 // These options aren't allowed in MAKEFLAGS
145 OPT_p = (1 << OPTBIT_p),
146 OPT_f = (1 << OPTBIT_f),
147 OPT_C = (1 << OPTBIT_C),
148 OPT_x = IF_FEATURE_MAKE_POSIX((1 << OPTBIT_x)) + 0,
149 // The following aren't command line options and must be last
150 OPT_precious = (1 << OPTBIT_precious),
151 OPT_phony = (1 << OPTBIT_phony),
152 OPT_include = (1 << OPTBIT_include),
153 OPT_make = (1 << OPTBIT_make),
154};
155
156// Options in OPTSTR1 that aren't included in MAKEFLAGS
157#define OPT_MASK (~OPT_S)
158
159#define useenv (opts & OPT_e)
160#define ignore (opts & OPT_i)
161#define errcont (opts & OPT_k)
162#define dryrun (opts & OPT_n)
163#define print (opts & OPT_p)
164#define quest (opts & OPT_q)
165#define norules (opts & OPT_r)
166#define silent (opts & OPT_s)
167#define dotouch (opts & OPT_t)
168#define precious (opts & OPT_precious)
169#define doinclude (opts & OPT_include)
170#define domake (opts & OPT_make)
171
172// A name. This represents a file, either to be made, or pre-existing.
173struct name {
174 struct name *n_next; // Next in the list of names
175 char *n_name; // Called
176 struct rule *n_rule; // Rules to build this (prerequisites/commands)
177 struct timespec n_tim; // Modification time of this name
178 uint16_t n_flag; // Info about the name
179};
180
181#define N_DOING 0x01 // Name in process of being built
182#define N_DONE 0x02 // Name looked at
183#define N_TARGET 0x04 // Name is a target
184#define N_PRECIOUS 0x08 // Target is precious
185#define N_DOUBLE 0x10 // Double-colon target
186#define N_SILENT 0x20 // Build target silently
187#define N_IGNORE 0x40 // Ignore build errors
188#define N_SPECIAL 0x80 // Special target
189#define N_MARK 0x100 // Mark for deduplication
190#define N_PHONY 0x200 // Name is a phony target
191#define N_INFERENCE 0x400 // Inference rule
192
193// List of rules to build a target
194struct rule {
195 struct rule *r_next; // Next rule
196 struct depend *r_dep; // Prerequisites for this rule
197 struct cmd *r_cmd; // Commands for this rule
198};
199
200// NOTE: the layout of the following two structures must be compatible.
201// Also, their first two members must be compatible with llist_t.
202
203// List of prerequisites for a rule
204struct depend {
205 struct depend *d_next; // Next prerequisite
206 struct name *d_name; // Name of prerequisite
207 int d_refcnt; // Reference count
208};
209
210// List of commands for a rule
211struct cmd {
212 struct cmd *c_next; // Next command line
213 char *c_cmd; // Text of command line
214 int c_refcnt; // Reference count
215 const char *c_makefile; // Makefile in which command was defined
216 int c_dispno; // Line number within makefile
217};
218
219// Macro storage
220struct macro {
221 struct macro *m_next; // Next variable
222 char *m_name; // Its name
223 char *m_val; // Its value
224 bool m_immediate; // Immediate-expansion macro set using ::=
225 bool m_flag; // Infinite loop check
226 uint8_t m_level; // Level at which macro was created
227};
228
229// Flags passed to setmacro()
230#define M_IMMEDIATE 0x08 // immediate-expansion macro is being defined
231#define M_VALID 0x10 // assert macro name is valid
232#define M_ENVIRON 0x20 // macro imported from environment
233
234// Constants for PRAGMA. Order must match strings in set_pragma().
235enum {
236 BIT_MACRO_NAME = 0,
237 BIT_TARGET_NAME,
238 BIT_COMMAND_COMMENT,
239 BIT_EMPTY_SUFFIX,
240#if ENABLE_PLATFORM_MINGW32
241 BIT_WINDOWS,
242#endif
243 BIT_POSIX_2017,
244 BIT_POSIX_2024,
245 BIT_POSIX_202X,
246
247 P_MACRO_NAME = (1 << BIT_MACRO_NAME),
248 P_TARGET_NAME = (1 << BIT_TARGET_NAME),
249 P_COMMAND_COMMENT = (1 << BIT_COMMAND_COMMENT),
250 P_EMPTY_SUFFIX = (1 << BIT_EMPTY_SUFFIX),
251#if ENABLE_PLATFORM_MINGW32
252 P_WINDOWS = (1 << BIT_WINDOWS),
253#endif
254};
255
256// Status of make()
257#define MAKE_FAILURE 0x01
258#define MAKE_DIDSOMETHING 0x02
259
260#define HTABSIZE 39
261
262struct globals {
263 uint32_t opts;
264 const char *makefile;
265 llist_t *makefiles;
266 llist_t *dirs;
267 struct name *namehead[HTABSIZE];
268 struct macro *macrohead[HTABSIZE];
269 struct name *firstname;
270 struct name *target;
271 time_t ar_mtime;
272 int lineno; // Physical line number in file
273 int dispno; // Line number for display purposes
274 const char *rulepos;
275 int rule_idx;
276#define IF_MAX 10
277 uint8_t clevel;
278 uint8_t cstate[IF_MAX + 1];
279 int numjobs;
280#if ENABLE_FEATURE_MAKE_POSIX
281 bool posix;
282 bool seen_first;
283 llist_t *pragmas;
284 unsigned char pragma;
285 unsigned char posix_level;
286#endif
287} FIX_ALIASING;
288
289#define G (*(struct globals*)bb_common_bufsiz1)
290#define INIT_G() do { \
291 setup_common_bufsiz(); \
292} while (0)
293
294#define opts (G.opts)
295#define makefile (G.makefile)
296#define makefiles (G.makefiles)
297#define dirs (G.dirs)
298#define namehead (G.namehead)
299#define macrohead (G.macrohead)
300#define firstname (G.firstname)
301#define target (G.target)
302#define ar_mtime (G.ar_mtime)
303#define lineno (G.lineno)
304#define dispno (G.dispno)
305#define rulepos (G.rulepos)
306#define rule_idx (G.rule_idx)
307#define clevel (G.clevel)
308#define cstate (G.cstate)
309#define numjobs (G.numjobs)
310#if ENABLE_FEATURE_MAKE_POSIX
311#define posix (G.posix)
312#define seen_first (G.seen_first)
313#define pragmas (G.pragmas)
314#define pragma (G.pragma)
315#define posix_level (G.posix_level)
316#else
317#define posix 0
318#define pragma 0
319#define posix_level DEFAULT_POSIX_LEVEL
320#endif
321
322static int make(struct name *np, int level);
323
324// Return TRUE if c is allowed in a POSIX 2017 macro or target name
325#define ispname(c) (isalpha(c) || isdigit(c) || c == '.' || c == '_')
326// Return TRUE if c is in the POSIX 'portable filename character set'
327#define isfname(c) (ispname(c) || c == '-')
328
329/*
330 * Utility functions.
331 */
332
333/*
334 * Print message, with makefile and line number if possible.
335 */
336static void
337vwarning(FILE *stream, const char *msg, va_list list)
338{
339 fprintf(stream, "%s: ", applet_name);
340 if (makefile)
341 fprintf(stream, "(%s:%d): ", makefile, dispno);
342 vfprintf(stream, msg, list);
343 fputc('\n', stream);
344}
345
346/*
347 * Diagnostic handler. Print message to standard error.
348 */
349static void
350diagnostic(const char *msg, ...)
351{
352 va_list list;
353
354 va_start(list, msg);
355 vwarning(stderr, msg, list);
356 va_end(list);
357}
358
359/*
360 * Error handler. Print message and exit.
361 */
362static void error(const char *msg, ...) NORETURN;
363static void
364error(const char *msg, ...)
365{
366 va_list list;
367
368 va_start(list, msg);
369 vwarning(stderr, msg, list);
370 va_end(list);
371 exit(2);
372}
373
374static void error_unexpected(const char *s) NORETURN;
375static void
376error_unexpected(const char *s)
377{
378 error("unexpected %s", s);
379}
380
381static void error_in_inference_rule(const char *s) NORETURN;
382static void
383error_in_inference_rule(const char *s)
384{
385 error("%s in inference rule", s);
386}
387
388static void
389error_not_allowed(const char *s, const char *t)
390{
391 error("%s not allowed for %s", s, t);
392}
393
394static void
395warning(const char *msg, ...)
396{
397 va_list list;
398
399 va_start(list, msg);
400 vwarning(stdout, msg, list);
401 va_end(list);
402}
403
404static char *
405auto_concat(const char *s1, const char *s2)
406{
407 return auto_string(xasprintf("%s%s", s1, s2));
408}
409
410#if !ENABLE_PLATFORM_MINGW32
411/*
412 * Append a word to a space-separated string of words. The first
413 * call should use a NULL pointer for str, subsequent calls should
414 * pass an allocated string which will be freed.
415 */
416static char *
417xappendword(const char *str, const char *word)
418{
419 char *newstr = str ? xasprintf("%s %s", str, word) : xstrdup(word);
420 free((void *)str);
421 return newstr;
422}
423#endif
424
425static unsigned int
426getbucket(const char *name)
427{
428 unsigned int hashval = 0;
429 const unsigned char *p = (unsigned char *)name;
430
431 while (*p)
432 hashval ^= (hashval << 5) + (hashval >> 2) + *p++;
433 return hashval % HTABSIZE;
434}
435
436/*
437 * Add a prerequisite to the end of the supplied list.
438 */
439static void
440newdep(struct depend **dphead, struct name *np)
441{
442 while (*dphead)
443 dphead = &(*dphead)->d_next;
444 *dphead = xzalloc(sizeof(struct depend));
445 /*(*dphead)->d_next = NULL; - xzalloc did it */
446 (*dphead)->d_name = np;
447 /*(*dphead)->d_refcnt = 0; */
448}
449
450static void
451freedeps(struct depend *dp)
452{
453 if (dp && --dp->d_refcnt <= 0)
454 llist_free((llist_t *)dp, NULL);
455}
456
457/*
458 * Add a command to the end of the supplied list of commands.
459 */
460static void
461newcmd(struct cmd **cphead, char *str)
462{
463 while (isspace(*str))
464 str++;
465
466 while (*cphead)
467 cphead = &(*cphead)->c_next;
468 *cphead = xzalloc(sizeof(struct cmd));
469 /*(*cphead)->c_next = NULL; - xzalloc did it */
470 (*cphead)->c_cmd = xstrdup(str);
471 /*(*cphead)->c_refcnt = 0; */
472 if (makefile)
473 (*cphead)->c_makefile = xstrdup(makefile);
474 (*cphead)->c_dispno = dispno;
475}
476
477static void
478freecmds(struct cmd *cp)
479{
480 struct cmd *nextcp;
481
482 if (cp && --cp->c_refcnt <= 0) {
483 for (; cp; cp = nextcp) {
484 nextcp = cp->c_next;
485 free(cp->c_cmd);
486 free((void *)cp->c_makefile);
487 free(cp);
488 }
489 }
490}
491
492static struct name *
493findname(const char *name)
494{
495 struct name *np = namehead[getbucket(name)];
496 return (struct name *)llist_find_str((llist_t *)np, name);
497}
498
499static int
500check_name(const char *name)
501{
502 const char *s;
503
504#if ENABLE_PLATFORM_MINGW32
505 if (!posix || (pragma & P_WINDOWS)) {
506 if (isalpha(name[0]) && name[1] == ':' && name[2] == '/') {
507 name += 3;
508 }
509 }
510#endif
511 if (!posix) {
512 for (s = name; *s; ++s) {
513 if (*s == '=')
514 return FALSE;
515 }
516 return TRUE;
517 }
518
519 for (s = name; *s; ++s) {
520 if ((pragma & P_TARGET_NAME) || !POSIX_2017 ?
521 !(isfname(*s) || *s == '/') : !ispname(*s))
522 return FALSE;
523 }
524 return TRUE;
525}
526
527static char *splitlib(const char *name, char **member);
528
529static int
530is_valid_target(const char *name)
531{
532 char *archive, *member = NULL;
533 int ret;
534
535 /* Names of the form 'lib(member)' are referred to as 'expressions'
536 * in POSIX and are subjected to special treatment. The 'lib'
537 * and 'member' elements must each be a valid target name. */
538 archive = splitlib(name, &member);
539 ret = check_name(archive) && (member == NULL || check_name(member));
540 free(archive);
541
542 return ret;
543}
544
545#if ENABLE_FEATURE_MAKE_POSIX
546static int
547potentially_valid_target(const char *name)
548{
549 int ret = FALSE;
550
551 if (!(pragma & P_TARGET_NAME)) {
552 pragma |= P_TARGET_NAME;
553 ret = is_valid_target(name);
554 pragma &= ~P_TARGET_NAME;
555 }
556 return ret;
557}
558#endif
559
560/*
561 * Intern a name. Return a pointer to the name struct
562 */
563static struct name *
564newname(const char *name)
565{
566 struct name *np = findname(name);
567
568 if (np == NULL) {
569 unsigned int bucket;
570
571 if (!is_valid_target(name))
572#if ENABLE_FEATURE_MAKE_POSIX
573 error("invalid target name '%s'%s", name,
574 potentially_valid_target(name) ?
575 ": allow with pragma target_name" : "");
576#else
577 error("invalid target name '%s'", name);
578#endif
579
580 bucket = getbucket(name);
581 np = xzalloc(sizeof(struct name));
582 np->n_next = namehead[bucket];
583 namehead[bucket] = np;
584 np->n_name = xstrdup(name);
585 /*np->n_rule = NULL; - xzalloc did it */
586 /*np->n_tim = (struct timespec){0, 0}; */
587 /*np->n_flag = 0; */
588 }
589 return np;
590}
591
592/*
593 * Return the commands on the first rule that has them or NULL.
594 */
595static struct cmd *
596getcmd(struct name *np)
597{
598 struct rule *rp;
599
600 if (np == NULL)
601 return NULL;
602
603 for (rp = np->n_rule; rp; rp = rp->r_next)
604 if (rp->r_cmd)
605 return rp->r_cmd;
606 return NULL;
607}
608
609#if ENABLE_FEATURE_CLEAN_UP
610static void
611freenames(void)
612{
613 int i;
614 struct name *np, *nextnp;
615
616 for (i = 0; i < HTABSIZE; i++) {
617 for (np = namehead[i]; np; np = nextnp) {
618 nextnp = np->n_next;
619 free(np->n_name);
620 freerules(np->n_rule);
621 free(np);
622 }
623 }
624}
625#endif
626
627static void
628freerules(struct rule *rp)
629{
630 struct rule *nextrp;
631
632 for (; rp; rp = nextrp) {
633 nextrp = rp->r_next;
634 freedeps(rp->r_dep);
635 freecmds(rp->r_cmd);
636 free(rp);
637 }
638}
639
640static void *
641inc_ref(void *vp)
642{
643 if (vp) {
644 struct depend *dp = vp;
645 if (dp->d_refcnt == INT_MAX)
646 bb_die_memory_exhausted();
647 dp->d_refcnt++;
648 }
649 return vp;
650}
651
652#if ENABLE_FEATURE_MAKE_POSIX
653// Order must match constants above.
654// POSIX levels must be last and in increasing order
655static const char *p_name =
656 "macro_name\0"
657 "target_name\0"
658 "command_comment\0"
659 "empty_suffix\0"
660#if ENABLE_PLATFORM_MINGW32
661 "windows\0"
662#endif
663 "posix_2017\0"
664 "posix_2024\0"
665 "posix_202x\0";
666
667static void
668set_pragma(const char *name)
669{
670 int idx = index_in_strings(p_name, name);
671
672 if (idx != -1) {
673 if (idx >= BIT_POSIX_2017) {
674 // POSIX level is stored in a separate variable.
675 // No bits in 'pragma' are used.
676 if (posix_level == DEFAULT_POSIX_LEVEL) {
677 posix_level = idx - BIT_POSIX_2017;
678 if (posix_level > STD_POSIX_2024)
679 posix_level = STD_POSIX_2024;
680 } else if (posix_level != idx - BIT_POSIX_2017)
681 warning("unable to change POSIX level");
682 } else {
683 pragma |= 1 << idx;
684 }
685 return;
686 }
687 warning("invalid pragma '%s'", name);
688}
689
690static void
691pragmas_to_env(void)
692{
693 int i;
694 char *val = NULL;
695
696 for (i = 0; i < BIT_POSIX_2017; ++i) {
697 if ((pragma & (1 << i)))
698 val = xappendword(val, nth_string(p_name, i));
699 }
700
701 if (posix_level != DEFAULT_POSIX_LEVEL)
702 val = xappendword(val,
703 nth_string(p_name, BIT_POSIX_2017 + posix_level));
704
705 if (val) {
706 setenv("PDPMAKE_PRAGMAS", val, 1);
707 free(val);
708 }
709}
710#endif
711
712/*
713 * Add a new rule to a target. This checks to see if commands already
714 * exist for the target. If flag is TRUE the target can have multiple
715 * rules with commands (double-colon rules).
716 *
717 * i) If the name is a special target and there are no prerequisites
718 * or commands to be added remove all prerequisites and commands.
719 * This is necessary when clearing a built-in inference rule.
720 * ii) If name is a special target and has commands, replace them.
721 * This is for redefining commands for an inference rule.
722 */
723static void
724addrule(struct name *np, struct depend *dp, struct cmd *cp, int flag)
725{
726 struct rule *rp;
727 struct rule **rpp;
728
729 // Can't mix single-colon and double-colon rules
730 if (!posix && (np->n_flag & N_TARGET)) {
731 if (!(np->n_flag & N_DOUBLE) != !flag) // like xor
732 error("inconsistent rules for target %s", np->n_name);
733 }
734
735 // Clear out prerequisites and commands
736 if ((np->n_flag & N_SPECIAL) && !dp && !cp) {
737 if (strcmp(np->n_name, ".PHONY") == 0)
738 return;
739 freerules(np->n_rule);
740 np->n_rule = NULL;
741 return;
742 }
743
744 if (cp && !(np->n_flag & N_DOUBLE) && getcmd(np)) {
745 // Handle the inference rule redefinition case
746 // .DEFAULT rule can also be redefined (as an extension).
747 if ((np->n_flag & N_INFERENCE)
748 && !(posix && (np->n_flag & N_SPECIAL))
749 ) {
750 freerules(np->n_rule);
751 np->n_rule = NULL;
752 } else {
753 error("commands defined twice for target %s", np->n_name);
754 }
755 }
756
757 rpp = &np->n_rule;
758 while (*rpp)
759 rpp = &(*rpp)->r_next;
760
761 *rpp = rp = xzalloc(sizeof(struct rule));
762 /*rp->r_next = NULL; - xzalloc did it */
763 rp->r_dep = inc_ref(dp);
764 rp->r_cmd = inc_ref(cp);
765
766 np->n_flag |= N_TARGET;
767 if (flag)
768 np->n_flag |= N_DOUBLE;
769#if ENABLE_FEATURE_MAKE_POSIX
770 if (strcmp(np->n_name, ".PRAGMA") == 0) {
771 for (; dp; dp = dp->d_next) {
772 set_pragma(dp->d_name->n_name);
773 }
774 pragmas_to_env();
775 }
776#endif
777}
778
779/*
780 * Macro control for make
781 */
782static struct macro *
783getmp(const char *name)
784{
785 struct macro *mp = macrohead[getbucket(name)];
786 return (struct macro *)llist_find_str((llist_t *)mp, name);
787}
788
789static int
790is_valid_macro(const char *name)
791{
792 const char *s;
793 for (s = name; *s; ++s) {
794 // In POSIX mode only a limited set of characters are guaranteed
795 // to be allowed in macro names.
796 if (posix) {
797 // Find the appropriate character set
798 if ((pragma & P_MACRO_NAME) || !POSIX_2017 ?
799 !isfname(*s) : !ispname(*s))
800 return FALSE;
801 }
802 // As an extension allow anything that can get through the
803 // input parser, apart from the following.
804 if (*s == '=' || isblank(*s) || iscntrl(*s))
805 return FALSE;
806 }
807 return TRUE;
808}
809
810#if ENABLE_FEATURE_MAKE_POSIX
811static int
812potentially_valid_macro(const char *name)
813{
814 int ret = FALSE;
815
816 if (!(pragma & P_MACRO_NAME)) {
817 pragma |= P_MACRO_NAME;
818 ret = is_valid_macro(name);
819 pragma &= ~P_MACRO_NAME;
820 }
821 return ret;
822}
823#endif
824
825static void
826setmacro(const char *name, const char *val, int level)
827{
828 struct macro *mp;
829 bool valid = level & M_VALID;
830 bool from_env = level & M_ENVIRON;
831 bool immediate = level & M_IMMEDIATE;
832
833 level &= ~(M_IMMEDIATE | M_VALID | M_ENVIRON);
834 mp = getmp(name);
835 if (mp) {
836 // Don't replace existing macro from a lower level
837 if (level > mp->m_level)
838 return;
839
840 // Replace existing macro
841 free(mp->m_val);
842 } else {
843 // If not defined, allocate space for new
844 unsigned int bucket;
845
846 if (!valid && !is_valid_macro(name)) {
847 // Silently drop invalid names from the environment
848 if (from_env)
849 return;
850#if ENABLE_FEATURE_MAKE_POSIX
851 error("invalid macro name '%s'%s", name,
852 potentially_valid_macro(name) ?
853 ": allow with pragma macro_name" : "");
854#else
855 error("invalid macro name '%s'", name);
856#endif
857 }
858
859 bucket = getbucket(name);
860 mp = xzalloc(sizeof(struct macro));
861 mp->m_next = macrohead[bucket];
862 macrohead[bucket] = mp;
863 /* mp->m_flag = FALSE; - xzalloc did it */
864 mp->m_name = xstrdup(name);
865 }
866 mp->m_immediate = immediate;
867 mp->m_level = level;
868 mp->m_val = xstrdup(val ? val : "");
869}
870
871#if ENABLE_FEATURE_CLEAN_UP
872static void
873freemacros(void)
874{
875 int i;
876 struct macro *mp, *nextmp;
877
878 for (i = 0; i < HTABSIZE; i++) {
879 for (mp = macrohead[i]; mp; mp = nextmp) {
880 nextmp = mp->m_next;
881 free(mp->m_name);
882 free(mp->m_val);
883 free(mp);
884 }
885 }
886}
887#endif
888
889/*
890 * Get modification time of file or archive member
891 */
892static void FAST_FUNC
893record_mtime(const file_header_t *file_header)
894{
895 ar_mtime = file_header->mtime;
896}
897
898static time_t
899artime(const char *archive, const char *member)
900{
901 archive_handle_t *archive_handle;
902
903 ar_mtime = 0;
904 archive_handle = init_handle();
905 archive_handle->src_fd = open(archive, O_RDONLY);
906 if (archive_handle->src_fd != -1) {
907 archive_handle->action_header = record_mtime;
908 archive_handle->filter = filter_accept_list;
909 llist_add_to_end(&archive_handle->accept, (void *)member);
910 unpack_ar_archive(archive_handle);
911 close(archive_handle->src_fd);
912 }
913
914#if ENABLE_FEATURE_AR_LONG_FILENAMES
915 free(archive_handle->ar__long_names);
916#endif
917 llist_free(archive_handle->accept, NULL);
918 free(archive_handle->file_header);
919 free(archive_handle);
920
921 return ar_mtime;
922}
923
924/*
925 * If the name is of the form 'libname(member.o)' split it into its
926 * name and member parts and set the member pointer to point to the
927 * latter. Otherwise just take a copy of the name and don't alter
928 * the member pointer.
929 *
930 * In either case the return value is an allocated string which must
931 * be freed by the caller.
932 */
933static char *
934splitlib(const char *name, char **member)
935{
936 char *s, *t;
937 size_t len;
938
939 t = xstrdup(name);
940 s = strchr(t, '(');
941 if (s) {
942 // We have 'libname(member.o)'
943 *s++ = '\0';
944 len = strlen(s);
945 if (len <= 1 || s[len - 1] != ')' || *t == '\0')
946 error("invalid name '%s'", name);
947 s[len - 1] = '\0';
948 *member = s;
949 }
950 return t;
951}
952
953/*
954 * Get the modification time of a file. Set it to 0 if the file
955 * doesn't exist.
956 */
957static void
958modtime(struct name *np)
959{
960 char *name, *member = NULL;
961 struct stat info;
962
963 name = splitlib(np->n_name, &member);
964 if (member) {
965 // Looks like library(member)
966 np->n_tim.tv_sec = artime(name, member);
967 np->n_tim.tv_nsec = 0;
968 } else if (stat(name, &info) < 0) {
969 if (errno != ENOENT)
970 bb_perror_msg("can't open %s", name);
971 np->n_tim.tv_sec = 0;
972 np->n_tim.tv_nsec = 0;
973 } else {
974 np->n_tim.tv_sec = info.st_mtim.tv_sec;
975 np->n_tim.tv_nsec = info.st_mtim.tv_nsec;
976 }
977 free(name);
978}
979
980/*
981 * Control of the implicit suffix rules
982 */
983
984/*
985 * Return a pointer to the suffix of a name (which may be the
986 * terminating NUL if there's no suffix).
987 */
988static char *
989suffix(const char *name)
990{
991 char *p = strrchr(name, '.');
992 return p ? p : (char *)name + strlen(name);
993}
994
995/*
996 * Dynamic dependency. This routine applies the suffix rules
997 * to try and find a source and a set of rules for a missing
998 * target. NULL is returned on failure. On success the name of
999 * the implicit prerequisite is returned and the details are
1000 * placed in the imprule structure provided by the caller.
1001 */
1002static struct name *
1003dyndep(struct name *np, struct rule *imprule)
1004{
1005 char *suff, *newsuff;
1006 char *base, *name, *member;
1007 struct name *xp; // Suffixes
1008 struct name *sp; // Suffix rule
1009 struct name *pp = NULL; // Implicit prerequisite
1010 struct rule *rp;
1011 struct depend *dp;
1012 bool chain = FALSE;
1013
1014 member = NULL;
1015 name = splitlib(np->n_name, &member);
1016
1017 suff = xstrdup(suffix(name));
1018 base = member ? member : name;
1019 *suffix(base) = '\0';
1020
1021 xp = newname(".SUFFIXES");
1022 retry:
1023 for (rp = xp->n_rule; rp; rp = rp->r_next) {
1024 for (dp = rp->r_dep; dp; dp = dp->d_next) {
1025 // Generate new suffix rule to try
1026 newsuff = dp->d_name->n_name;
1027 sp = findname(auto_concat(newsuff, suff));
1028 if (sp && sp->n_rule) {
1029 struct name *ip;
1030 int got_ip;
1031
1032 // Has rule already been used in this chain?
1033 if ((sp->n_flag & N_MARK))
1034 continue;
1035
1036 // Generate a name for an implicit prerequisite
1037 ip = newname(auto_concat(base, newsuff));
1038 if ((ip->n_flag & N_DOING))
1039 continue;
1040
1041 if (!ip->n_tim.tv_sec)
1042 modtime(ip);
1043
1044 if (!chain) {
1045 got_ip = ip->n_tim.tv_sec || (ip->n_flag & N_TARGET);
1046 } else {
1047 sp->n_flag |= N_MARK;
1048 got_ip = dyndep(ip, NULL) != NULL;
1049 sp->n_flag &= ~N_MARK;
1050 }
1051
1052 if (got_ip) {
1053 // Prerequisite exists or we know how to make it
1054 if (imprule) {
1055 dp = NULL;
1056 newdep(&dp, ip);
1057 imprule->r_dep = dp;
1058 imprule->r_cmd = sp->n_rule->r_cmd;
1059 }
1060 pp = ip;
1061 goto finish;
1062 }
1063 }
1064 }
1065 }
1066 // If we didn't find an existing file or an explicit rule try
1067 // again, this time looking for a chained inference rule.
1068 if (!posix && !chain) {
1069 chain = TRUE;
1070 goto retry;
1071 }
1072 finish:
1073 free(suff);
1074 free(name);
1075 return pp;
1076}
1077
1078#define RULES \
1079 ".c.o:\n" \
1080 " $(CC) $(CFLAGS) -c $<\n" \
1081 ".y.o:\n" \
1082 " $(YACC) $(YFLAGS) $<\n" \
1083 " $(CC) $(CFLAGS) -c y.tab.c\n" \
1084 " rm -f y.tab.c\n" \
1085 " mv y.tab.o $@\n" \
1086 ".y.c:\n" \
1087 " $(YACC) $(YFLAGS) $<\n" \
1088 " mv y.tab.c $@\n" \
1089 ".l.o:\n" \
1090 " $(LEX) $(LFLAGS) $<\n" \
1091 " $(CC) $(CFLAGS) -c lex.yy.c\n" \
1092 " rm -f lex.yy.c\n" \
1093 " mv lex.yy.o $@\n" \
1094 ".l.c:\n" \
1095 " $(LEX) $(LFLAGS) $<\n" \
1096 " mv lex.yy.c $@\n" \
1097 ".c.a:\n" \
1098 " $(CC) -c $(CFLAGS) $<\n" \
1099 " $(AR) $(ARFLAGS) $@ $*.o\n" \
1100 " rm -f $*.o\n" \
1101 ".c:\n" \
1102 " $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $<\n" \
1103 ".sh:\n" \
1104 " cp $< $@\n" \
1105 " chmod a+x $@\n"
1106
1107#define RULES_2017 \
1108 ".SUFFIXES:.o .c .y .l .a .sh .f\n" \
1109 ".f.o:\n" \
1110 " $(FC) $(FFLAGS) -c $<\n" \
1111 ".f.a:\n" \
1112 " $(FC) -c $(FFLAGS) $<\n" \
1113 " $(AR) $(ARFLAGS) $@ $*.o\n" \
1114 " rm -f $*.o\n" \
1115 ".f:\n" \
1116 " $(FC) $(FFLAGS) $(LDFLAGS) -o $@ $<\n"
1117
1118#define RULES_2024 \
1119 ".SUFFIXES:.o .c .y .l .a .sh\n"
1120
1121#define MACROS \
1122 "CFLAGS=-O1\n" \
1123 "YACC=yacc\n" \
1124 "YFLAGS=\n" \
1125 "LEX=lex\n" \
1126 "LFLAGS=\n" \
1127 "AR=ar\n" \
1128 "ARFLAGS=-rv\n" \
1129 "LDFLAGS=\n"
1130
1131#define MACROS_2017 \
1132 "CC=c99\n" \
1133 "FC=fort77\n" \
1134 "FFLAGS=-O1\n" \
1135
1136#define MACROS_2024 \
1137 "CC=c17\n"
1138
1139#define MACROS_EXT \
1140 "CC=cc\n"
1141
1142/*
1143 * Read the built-in rules using a fake fgets-like interface.
1144 */
1145static char *
1146getrules(char *s, int size)
1147{
1148 char *r = s;
1149
1150 if (rulepos == NULL || *rulepos == '\0') {
1151 if (rule_idx == 0) {
1152 rulepos = MACROS;
1153 rule_idx++;
1154 } else if (rule_idx == 1) {
1155 if (POSIX_2017)
1156 rulepos = MACROS_2017;
1157 else if (posix)
1158 rulepos = MACROS_2024;
1159 else
1160 rulepos = MACROS_EXT;
1161 rule_idx++;
1162 } else if (!norules) {
1163 if (rule_idx == 2) {
1164 rulepos = POSIX_2017 ? RULES_2017 : RULES_2024;
1165 rule_idx++;
1166 } else if (rule_idx == 3) {
1167 rulepos = RULES;
1168 rule_idx++;
1169 }
1170 }
1171 }
1172
1173 if (*rulepos == '\0')
1174 return NULL;
1175
1176 while (--size) {
1177 if ((*r++ = *rulepos++) == '\n')
1178 break;
1179 }
1180 *r = '\0';
1181 return s;
1182}
1183
1184/*
1185 * Parse a makefile
1186 */
1187
1188/*
1189 * Return a pointer to the next blank-delimited word or NULL if
1190 * there are none left.
1191 */
1192static char *
1193gettok(char **ptr)
1194{
1195 char *p;
1196
1197 while (isblank(**ptr)) // Skip blanks
1198 (*ptr)++;
1199
1200 if (**ptr == '\0') // Nothing after blanks
1201 return NULL;
1202
1203 p = *ptr; // Word starts here
1204
1205 while (**ptr != '\0' && !isblank(**ptr))
1206 (*ptr)++; // Find end of word
1207
1208 // Terminate token and move on unless already at end of string
1209 if (**ptr != '\0')
1210 *(*ptr)++ = '\0';
1211
1212 return(p);
1213}
1214
1215/*
1216 * Skip over (possibly adjacent or nested) macro expansions.
1217 */
1218static char *
1219skip_macro(const char *s)
1220{
1221 while (*s && s[0] == '$') {
1222 if (s[1] == '(' || s[1] == '{') {
1223 char end = *++s == '(' ? ')' : '}';
1224 while (*s && *s != end)
1225 s = skip_macro(s + 1);
1226 if (*s == end)
1227 ++s;
1228 } else if (s[1] != '\0') {
1229 s += 2;
1230 } else {
1231 break;
1232 }
1233 }
1234 return (char *)s;
1235}
1236
1237/*
1238 * Process each whitespace-separated word in the input string:
1239 *
1240 * - replace paths with their directory or filename part
1241 * - replace prefixes and suffixes
1242 *
1243 * Returns an allocated string or NULL if the input is unmodified.
1244 */
1245static char *
1246modify_words(const char *val, int modifier, size_t lenf, size_t lenr,
1247 const char *find_pref, const char *repl_pref,
1248 const char *find_suff, const char *repl_suff)
1249{
1250 char *s, *copy, *word, *sep, *buf = NULL;
1251 size_t find_pref_len = 0, find_suff_len = 0;
1252
1253 if (!modifier && lenf == 0 && lenr == 0)
1254 return buf;
1255
1256 if (find_pref) {
1257 // get length of find prefix, e.g: src/
1258 find_pref_len = strlen(find_pref);
1259 // get length of find suffix, e.g: .c
1260 find_suff_len = lenf - find_pref_len - 1;
1261 }
1262
1263 s = copy = xstrdup(val);
1264 while ((word = gettok(&s)) != NULL) {
1265 if (modifier) {
1266 sep = strrchr(word, '/');
1267 if (modifier == 'D') {
1268 if (!sep) {
1269 word[0] = '.'; // no '/', return "."
1270 sep = word + 1;
1271 } else if (sep == word) {
1272 // '/' at start of word, return "/"
1273 sep = word + 1;
1274 }
1275 // else terminate at separator
1276 *sep = '\0';
1277 } else if (/* modifier == 'F' && */ sep) {
1278 word = sep + 1;
1279 }
1280 }
1281 if (find_pref != NULL || lenf != 0 || lenr != 0) {
1282 size_t lenw = strlen(word);
1283 // This code implements pattern macro expansions:
1284 // https://austingroupbugs.net/view.php?id=519
1285 //
1286 // find: <prefix>%<suffix>
1287 // example: src/%.c
1288 //
1289 // For a pattern of the form:
1290 // $(string1:[op]%[os]=[np][%][ns])
1291 // lenf is the length of [op]%[os]. So lenf >= 1.
1292 if (find_pref != NULL && lenw + 1 >= lenf) {
1293 // If prefix and suffix of word match find_pref and
1294 // find_suff, then do substitution.
1295 if (strncmp(word, find_pref, find_pref_len) == 0 &&
1296 strcmp(word + lenw - find_suff_len, find_suff) == 0) {
1297 // replace: <prefix>[%<suffix>]
1298 // example: build/%.o or build/all.o (notice no %)
1299 // If repl_suff is NULL, replace whole word with repl_pref.
1300 if (!repl_suff) {
1301 word = xstrdup(repl_pref);
1302 } else {
1303 word[lenw - find_suff_len] = '\0';
1304 word = xasprintf("%s%s%s", repl_pref,
1305 word + find_pref_len, repl_suff);
1306 }
1307 word = auto_string(word);
1308 }
1309 } else if (lenw >= lenf &&
1310 strcmp(word + lenw - lenf, find_suff) == 0) {
1311 word[lenw - lenf] = '\0';
1312 word = auto_concat(word, repl_suff);
1313 }
1314 }
1315 buf = xappendword(buf, word);
1316 }
1317 free(copy);
1318 return buf;
1319}
1320
1321/*
1322 * Return a pointer to the next instance of a given character. Macro
1323 * expansions are skipped so the ':' and '=' in $(VAR:.s1=.s2) aren't
1324 * detected as separators in macro definitions. Some other situations
1325 * also require skipping the internals of a macro expansion.
1326 */
1327static char *
1328find_char(const char *str, int c)
1329{
1330 const char *s;
1331
1332 for (s = skip_macro(str); *s; s = skip_macro(s + 1)) {
1333 if (*s == c)
1334 return (char *)s;
1335 }
1336 return NULL;
1337}
1338
1339#if ENABLE_PLATFORM_MINGW32
1340/*
1341 * Check for a target rule by searching for a colon that isn't
1342 * part of a Windows path. Return a pointer to the colon or NULL.
1343 */
1344static char *
1345find_colon(char *p)
1346{
1347 char *q;
1348
1349 for (q = p; (q = strchr(q, ':')); ++q) {
1350 if (posix && !(pragma & P_WINDOWS))
1351 break;
1352 if (q == p || !isalpha(q[-1]) || q[1] != '/')
1353 break;
1354 }
1355 return q;
1356}
1357#else
1358# define find_colon(s) strchr(s, ':')
1359#endif
1360
1361/*
1362 * Recursively expand any macros in str to an allocated string.
1363 */
1364static char *
1365expand_macros(const char *str, int except_dollar)
1366{
1367 char *exp, *newexp, *s, *t, *p, *q, *name;
1368 char *find, *replace, *modified;
1369 char *expval, *expfind, *find_suff, *repl_suff;
1370 char *find_pref = NULL, *repl_pref = NULL;
1371 size_t lenf, lenr;
1372 char modifier;
1373 struct macro *mp;
1374
1375 exp = xstrdup(str);
1376 for (t = exp; *t; t++) {
1377 if (*t == '$') {
1378 if (t[1] == '\0') {
1379 break;
1380 }
1381 if (t[1] == '$' && except_dollar) {
1382 t++;
1383 continue;
1384 }
1385 // Need to expand a macro. Find its extent (s to t inclusive)
1386 // and take a copy of its content.
1387 s = t;
1388 t++;
1389 if (*t == '{' || *t == '(') {
1390 t = find_char(t, *t == '{' ? '}' : ')');
1391 if (t == NULL)
1392 error("unterminated variable '%s'", s);
1393 name = xstrndup(s + 2, t - s - 2);
1394 } else {
1395 name = xzalloc(2);
1396 name[0] = *t;
1397 /*name[1] = '\0'; - xzalloc did it */
1398 }
1399
1400 // Only do suffix replacement or pattern macro expansion
1401 // if both ':' and '=' are found, plus a '%' for the latter.
1402 // Suffix replacement is indicated by
1403 // find_pref == NULL && (lenf != 0 || lenr != 0);
1404 // pattern macro expansion by find_pref != NULL.
1405 expfind = NULL;
1406 find_suff = repl_suff = NULL;
1407 lenf = lenr = 0;
1408 if ((find = find_char(name, ':'))) {
1409 *find++ = '\0';
1410 expfind = expand_macros(find, FALSE);
1411 if ((replace = find_char(expfind, '='))) {
1412 *replace++ = '\0';
1413 lenf = strlen(expfind);
1414 if (!POSIX_2017 && (find_suff = strchr(expfind, '%'))) {
1415 find_pref = expfind;
1416 repl_pref = replace;
1417 *find_suff++ = '\0';
1418 if ((repl_suff = strchr(replace, '%')))
1419 *repl_suff++ = '\0';
1420 } else {
1421 if (posix && !(pragma & P_EMPTY_SUFFIX) && lenf == 0)
1422 error("empty suffix%s",
1423 !ENABLE_FEATURE_MAKE_POSIX ? "" :
1424 ": allow with pragma empty_suffix");
1425 find_suff = expfind;
1426 repl_suff = replace;
1427 lenr = strlen(repl_suff);
1428 }
1429 }
1430 }
1431
1432 p = q = name;
1433 // If not in POSIX mode expand macros in the name.
1434 if (!POSIX_2017) {
1435 char *expname = expand_macros(name, FALSE);
1436 free(name);
1437 name = expname;
1438 } else {
1439 // Skip over nested expansions in name
1440 do {
1441 *q++ = *p;
1442 } while ((p = skip_macro(p + 1)) && *p);
1443 }
1444
1445 // The internal macros support 'D' and 'F' modifiers
1446 modifier = '\0';
1447 switch (name[0]) {
1448 case '^':
1449 case '+':
1450 if (POSIX_2017)
1451 break;
1452 // fall through
1453 case '@': case '%': case '?': case '<': case '*':
1454 if ((name[1] == 'D' || name[1] == 'F') && name[2] == '\0') {
1455 modifier = name[1];
1456 name[1] = '\0';
1457 }
1458 break;
1459 }
1460
1461 modified = NULL;
1462 if ((mp = getmp(name))) {
1463 // Recursive expansion
1464 if (mp->m_flag)
1465 error("recursive macro %s", name);
1466 // Note if we've expanded $(MAKE)
1467 if (strcmp(name, "MAKE") == 0)
1468 opts |= OPT_make;
1469 mp->m_flag = TRUE;
1470 expval = expand_macros(mp->m_val, FALSE);
1471 mp->m_flag = FALSE;
1472 modified = modify_words(expval, modifier, lenf, lenr,
1473 find_pref, repl_pref, find_suff, repl_suff);
1474 if (modified)
1475 free(expval);
1476 else
1477 modified = expval;
1478 }
1479 free(name);
1480 free(expfind);
1481
1482 if (modified && *modified) {
1483 // The text to be replaced by the macro expansion is
1484 // from s to t inclusive.
1485 *s = '\0';
1486 newexp = xasprintf("%s%s%s", exp, modified, t + 1);
1487 t = newexp + (s - exp) + strlen(modified) - 1;
1488 free(exp);
1489 exp = newexp;
1490 } else {
1491 // Macro wasn't expanded or expanded to nothing.
1492 // Close the space occupied by the macro reference.
1493 q = t + 1;
1494 t = s - 1;
1495 while ((*s++ = *q++))
1496 continue;
1497 }
1498 free(modified);
1499 }
1500 }
1501 return exp;
1502}
1503
1504/*
1505 * Process a non-command line
1506 */
1507static void
1508process_line(char *s)
1509{
1510 char *t;
1511
1512 // Strip comment
1513 // don't treat '#' in macro expansion as a comment
1514 // nor '#' outside macro expansion preceded by backslash
1515 if (!posix) {
1516 char *u = s;
1517 while ((t = find_char(u, '#')) && t > u && t[-1] == '\\') {
1518 for (u = t; *u; ++u) {
1519 u[-1] = u[0];
1520 }
1521 *u = '\0';
1522 u = t;
1523 }
1524 } else
1525 t = strchr(s, '#');
1526 if (t)
1527 *t = '\0';
1528
1529 // Replace escaped newline and any leading white space on the
1530 // following line with a single space. Stop processing at a
1531 // non-escaped newline.
1532 for (t = s; *s && *s != '\n'; ) {
1533 if (s[0] == '\\' && s[1] == '\n') {
1534 s += 2;
1535 while (isspace(*s))
1536 ++s;
1537 *t++ = ' ';
1538 } else {
1539 *t++ = *s++;
1540 }
1541 }
1542 *t = '\0';
1543}
1544
1545enum {
1546 INITIAL = 0,
1547 SKIP_LINE = 1 << 0,
1548 EXPECT_ELSE = 1 << 1,
1549 GOT_MATCH = 1 << 2
1550};
1551
1552#define IFDEF 0
1553#define IFNDEF 1
1554#define IFEQ 2
1555#define IFNEQ 3
1556#define ELSE 0
1557#define ENDIF 1
1558
1559/*
1560 * Extract strings following ifeq/ifneq and compare them.
1561 * Return -1 on error.
1562 */
1563static int
1564compare_strings(char *arg1)
1565{
1566 char *arg2, *end, term, *t1, *t2;
1567 int ret;
1568
1569 // Get first string terminator.
1570 if (arg1[0] == '(')
1571 term = ',';
1572 else if (arg1[0] == '"' || arg1[0] == '\'')
1573 term = arg1[0];
1574 else
1575 return -1;
1576
1577 arg2 = find_char(++arg1, term);
1578 if (arg2 == NULL)
1579 return -1;
1580 *arg2++ = '\0';
1581
1582 // Get second string terminator.
1583 if (term == ',') {
1584 term = ')';
1585 } else {
1586 // Skip spaces between quoted strings.
1587 while (isspace(arg2[0]))
1588 arg2++;
1589 if (arg2[0] == '"' || arg2[0] == '\'')
1590 term = arg2[0];
1591 else
1592 return -1;
1593 ++arg2;
1594 }
1595
1596 end = find_char(arg2, term);
1597 if (end == NULL)
1598 return -1;
1599 *end++ = '\0';
1600
1601 if (gettok(&end) != NULL) {
1602 warning("unexpected text");
1603 }
1604
1605 t1 = expand_macros(arg1, FALSE);
1606 t2 = expand_macros(arg2, FALSE);
1607
1608 ret = strcmp(t1, t2) == 0;
1609 free(t1);
1610 free(t2);
1611 return ret;
1612}
1613
1614/*
1615 * Process conditional directives and return TRUE if the current line
1616 * should be skipped.
1617 */
1618static int
1619skip_line(const char *str1)
1620{
1621 char *copy, *q, *token;
1622 bool new_level = TRUE;
1623 // Default is to return skip flag for current level
1624 int ret = cstate[clevel] & SKIP_LINE;
1625 int key;
1626
1627 q = copy = xstrdup(str1);
1628 process_line(copy);
1629 if ((token = gettok(&q)) != NULL) {
1630 switch (index_in_strings("else\0endif\0", token)) {
1631 case ENDIF:
1632 if (gettok(&q) != NULL)
1633 error_unexpected("text");
1634 if (clevel == 0)
1635 error_unexpected(token);
1636 --clevel;
1637 ret = TRUE;
1638 goto end;
1639 case ELSE:
1640 if (!(cstate[clevel] & EXPECT_ELSE))
1641 error_unexpected(token);
1642
1643 // If an earlier condition matched we'll now skip lines.
1644 // If not we don't, though an 'else if' may override this.
1645 if ((cstate[clevel] & GOT_MATCH))
1646 cstate[clevel] |= SKIP_LINE;
1647 else
1648 cstate[clevel] &= ~SKIP_LINE;
1649
1650 token = gettok(&q);
1651 if (token == NULL) {
1652 // Simple else with no conditional directive
1653 cstate[clevel] &= ~EXPECT_ELSE;
1654 ret = TRUE;
1655 goto end;
1656 } else {
1657 // A conditional directive is now required ('else if').
1658 new_level = FALSE;
1659 }
1660 }
1661
1662 key = index_in_strings("ifdef\0ifndef\0ifeq\0ifneq\0", token);
1663 if (key != -1) {
1664 int match;
1665
1666 if (key == IFDEF || key == IFNDEF) {
1667 // ifdef/ifndef: find out if macro is defined.
1668 char *name = gettok(&q);
1669 if (name != NULL && gettok(&q) == NULL) {
1670 char *t = expand_macros(name, FALSE);
1671 struct macro *mp = getmp(t);
1672 match = mp != NULL && mp->m_val[0] != '\0';
1673 free(t);
1674 } else {
1675 match = -1;
1676 }
1677 } else {
1678 // ifeq/ifneq: compare strings.
1679 match = compare_strings(q);
1680 }
1681
1682 if (match >= 0) {
1683 if (new_level) {
1684 // Start a new level.
1685 if (clevel == IF_MAX)
1686 error("nesting too deep");
1687 ++clevel;
1688 cstate[clevel] = EXPECT_ELSE | SKIP_LINE;
1689 // If we were skipping lines at the previous level
1690 // we need to continue doing that unconditionally
1691 // at the new level.
1692 if ((cstate[clevel - 1] & SKIP_LINE))
1693 cstate[clevel] |= GOT_MATCH;
1694 }
1695
1696 if (!(cstate[clevel] & GOT_MATCH)) {
1697 if (key == IFNDEF || key == IFNEQ)
1698 match = !match;
1699 if (match) {
1700 cstate[clevel] &= ~SKIP_LINE;
1701 cstate[clevel] |= GOT_MATCH;
1702 }
1703 }
1704 } else {
1705 error("invalid condition");
1706 }
1707 ret = TRUE;
1708 } else if (!new_level) {
1709 error("missing conditional");
1710 }
1711 }
1712 end:
1713 free(copy);
1714 return ret;
1715}
1716
1717/*
1718 * If fd is NULL read the built-in rules. Otherwise read from the
1719 * specified file descriptor.
1720 */
1721static char *
1722make_fgets(char *s, int size, FILE *fd)
1723{
1724 return fd ? fgets(s, size, fd) : getrules(s, size);
1725}
1726
1727/*
1728 * Read a newline-terminated line into an allocated string.
1729 * Backslash-escaped newlines don't terminate the line.
1730 * Ignore comment lines. Return NULL on EOF.
1731 */
1732static char *
1733readline(FILE *fd, int want_command)
1734{
1735 char *p, *str = NULL;
1736 int pos = 0;
1737 int len = 0;
1738
1739 for (;;) {
1740 // We need room for at least one character and a NUL terminator
1741 if (len - pos > 1 &&
1742 make_fgets(str + pos, len - pos, fd) == NULL) {
1743 if (pos)
1744 return str;
1745 free(str);
1746 return NULL; // EOF
1747 }
1748
1749 if (len - pos < 2 || (p = strchr(str + pos, '\n')) == NULL) {
1750 // Need more room
1751 if (len)
1752 pos = len - 1;
1753 len += 256;
1754 str = xrealloc(str, len);
1755 continue;
1756 }
1757 lineno++;
1758
1759#if ENABLE_PLATFORM_MINGW32
1760 // Remove CR before LF
1761 if (p != str && p[-1] == '\r') {
1762 p[-1] = '\n';
1763 *p-- = '\0';
1764 }
1765#endif
1766 // Keep going if newline has been escaped
1767 if (p != str && p[-1] == '\\') {
1768 pos = p - str + 1;
1769 continue;
1770 }
1771 dispno = lineno;
1772
1773 // Check for lines that are conditionally skipped.
1774 if (posix || !skip_line(str)) {
1775 if (want_command && *str == '\t')
1776 return str;
1777
1778 // Check for comment lines
1779 p = str;
1780 while (isblank(*p))
1781 p++;
1782
1783 if (*p != '\n' && (posix ? *str != '#' : *p != '#'))
1784 return str;
1785 }
1786
1787 pos = 0;
1788 }
1789}
1790
1791/*
1792 * Return TRUE if the argument is a known suffix.
1793 */
1794static int
1795is_suffix(const char *s)
1796{
1797 struct name *np;
1798 struct rule *rp;
1799 struct depend *dp;
1800
1801 np = newname(".SUFFIXES");
1802 for (rp = np->n_rule; rp; rp = rp->r_next) {
1803 for (dp = rp->r_dep; dp; dp = dp->d_next) {
1804 if (strcmp(s, dp->d_name->n_name) == 0) {
1805 return TRUE;
1806 }
1807 }
1808 }
1809 return FALSE;
1810}
1811
1812enum {
1813 T_NORMAL = 0,
1814 T_SPECIAL = (1 << 0),
1815 T_INFERENCE = (1 << 1), // Inference rule
1816 T_NOPREREQ = (1 << 2), // If set must not have prerequisites
1817 T_COMMAND = (1 << 3), // If set must have commands, if unset must not
1818};
1819
1820/*
1821 * Determine if the argument is a special target and return a set
1822 * of flags indicating its properties.
1823 */
1824static int
1825target_type(char *s)
1826{
1827 char *sfx;
1828 int ret;
1829 static const char *s_name =
1830 ".DEFAULT\0"
1831 ".POSIX\0"
1832 ".IGNORE\0"
1833 ".PRECIOUS\0"
1834 ".SILENT\0"
1835 ".SUFFIXES\0"
1836 ".PHONY\0"
1837 ".NOTPARALLEL\0"
1838 ".WAIT\0"
1839#if ENABLE_FEATURE_MAKE_POSIX
1840 ".PRAGMA\0"
1841#endif
1842 ;
1843
1844 static const uint8_t s_type[] = {
1845 T_SPECIAL | T_NOPREREQ | T_COMMAND,
1846 T_SPECIAL | T_NOPREREQ,
1847 T_SPECIAL,
1848 T_SPECIAL,
1849 T_SPECIAL,
1850 T_SPECIAL,
1851 T_SPECIAL,
1852 T_SPECIAL | T_NOPREREQ,
1853 T_SPECIAL | T_NOPREREQ,
1854 T_SPECIAL,
1855 };
1856
1857 if (*s != '.')
1858 return T_NORMAL;
1859
1860 // Check for one of the known special targets
1861 ret = index_in_strings(s_name, s);
1862 if (ret >= 0)
1863 return s_type[ret];
1864
1865 // Check for an inference rule
1866 ret = T_NORMAL;
1867 sfx = suffix(s);
1868 if (is_suffix(sfx)) {
1869 if (s == sfx) { // Single suffix rule
1870 ret = T_INFERENCE | T_NOPREREQ | T_COMMAND;
1871 } else {
1872 // Suffix is valid, check that prefix is too
1873 *sfx = '\0';
1874 if (is_suffix(s))
1875 ret = T_INFERENCE | T_NOPREREQ | T_COMMAND;
1876 *sfx = '.';
1877 }
1878 }
1879 return ret;
1880}
1881
1882static int
1883ends_with_bracket(const char *s)
1884{
1885 return last_char_is(s, ')') != NULL;
1886}
1887
1888/*
1889 * Process a command line
1890 */
1891static char *
1892process_command(char *s)
1893{
1894 char *t, *u;
1895 int len;
1896 char *outside;
1897
1898 if (!(pragma & P_COMMAND_COMMENT) && posix) {
1899 // POSIX strips comments from command lines
1900 t = strchr(s, '#');
1901 if (t) {
1902 *t = '\0';
1903 warning("comment in command removed: keep with pragma command_comment");
1904 }
1905 }
1906
1907 len = strlen(s) + 1;
1908 outside = xzalloc(len);
1909 for (t = skip_macro(s); *t; t = skip_macro(t + 1)) {
1910 outside[t - s] = 1;
1911 }
1912
1913 // Process escaped newlines. Stop at first non-escaped newline.
1914 for (t = u = s; *u && *u != '\n'; ) {
1915 if (u[0] == '\\' && u[1] == '\n') {
1916 if (POSIX_2017 || outside[u - s]) {
1917 // Outside macro: remove tab following escaped newline.
1918 *t++ = *u++;
1919 *t++ = *u++;
1920 u += (*u == '\t');
1921 } else {
1922 // Inside macro: replace escaped newline and any leading
1923 // whitespace on the following line with a single space.
1924 u += 2;
1925 while (isspace(*u))
1926 ++u;
1927 *t++ = ' ';
1928 }
1929 } else {
1930 *t++ = *u++;
1931 }
1932 }
1933 *t = '\0';
1934 free(outside);
1935 return s;
1936}
1937
1938static char *
1939run_command(const char *cmd)
1940{
1941 FILE *fd;
1942 char *s, *val = NULL;
1943 char buf[256];
1944 size_t len = 0, nread;
1945
1946 if ((fd = popen(cmd, "r")) == NULL)
1947 return val;
1948
1949 for (;;) {
1950 nread = fread(buf, 1, sizeof(buf), fd);
1951 if (nread == 0)
1952 break;
1953
1954 val = xrealloc(val, len + nread + 1);
1955 memcpy(val + len, buf, nread);
1956 len += nread;
1957 val[len] = '\0';
1958 }
1959 pclose(fd);
1960
1961 if (val == NULL)
1962 return NULL;
1963
1964 // Strip leading whitespace in POSIX 2024 mode
1965 if (posix) {
1966 s = val;
1967 while (isspace(*s)) {
1968 ++s;
1969 --len;
1970 }
1971
1972 if (len == 0) {
1973 free(val);
1974 return NULL;
1975 }
1976 memmove(val, s, len + 1);
1977 }
1978
1979#if ENABLE_PLATFORM_MINGW32
1980 len = remove_cr(val, len + 1) - 1;
1981 if (len == 0) {
1982 free(val);
1983 return NULL;
1984 }
1985#endif
1986
1987 // Remove one newline from the end (BSD compatibility)
1988 if (val[len - 1] == '\n')
1989 val[len - 1] = '\0';
1990 // Other newlines are changed to spaces
1991 for (s = val; *s; ++s) {
1992 if (*s == '\n')
1993 *s = ' ';
1994 }
1995 return val;
1996}
1997
1998/*
1999 * Check for an unescaped wildcard character
2000 */
2001static int wildchar(const char *p)
2002{
2003 while (*p) {
2004 switch (*p) {
2005 case '?':
2006 case '*':
2007 case '[':
2008 return 1;
2009 case '\\':
2010 if (p[1] != '\0')
2011 ++p;
2012 break;
2013 }
2014 ++p;
2015 }
2016 return 0;
2017}
2018
2019/*
2020 * Expand any wildcards in a pattern. Return TRUE if a match is
2021 * found, in which case the caller should call globfree() on the
2022 * glob_t structure.
2023 */
2024static int
2025wildcard(char *p, glob_t *gd)
2026{
2027 int ret;
2028 char *s;
2029
2030 // Don't call glob() if there are no wildcards.
2031 if (!wildchar(p)) {
2032 nomatch:
2033 // Remove backslashes from the name.
2034 for (s = p; *p; ++p) {
2035 if (*p == '\\' && p[1] != '\0')
2036 continue;
2037 *s++ = *p;
2038 }
2039 *s = '\0';
2040 return 0;
2041 }
2042
2043 memset(gd, 0, sizeof(*gd));
2044 ret = glob(p, GLOB_NOSORT, NULL, gd);
2045 if (ret == GLOB_NOMATCH) {
2046 globfree(gd);
2047 goto nomatch;
2048 } else if (ret != 0) {
2049 error("glob error for '%s'", p);
2050 }
2051 return 1;
2052}
2053
2054#if ENABLE_FEATURE_MAKE_POSIX
2055static void
2056pragmas_from_env(void)
2057{
2058 char *p, *q, *var;
2059 const char *env = getenv("PDPMAKE_PRAGMAS");
2060
2061 if (env == NULL)
2062 return;
2063
2064 q = var = xstrdup(env);
2065 while ((p = gettok(&q)) != NULL)
2066 set_pragma(p);
2067 free(var);
2068}
2069#endif
2070
2071/*
2072 * Parse input from the makefile and construct a tree structure of it.
2073 */
2074static void
2075input(FILE *fd, int ilevel)
2076{
2077 char *p, *q, *s, *a, *str, *expanded, *copy;
2078 char *str1, *str2;
2079 struct name *np;
2080 struct depend *dp;
2081 struct cmd *cp;
2082 int startno, count;
2083 bool semicolon_cmd, seen_inference;
2084 uint8_t old_clevel = clevel;
2085 bool dbl;
2086 char *lib = NULL;
2087 glob_t gd;
2088 int nfile, i;
2089 char **files;
2090 bool minus;
2091
2092 lineno = 0;
2093 str1 = readline(fd, FALSE);
2094 while (str1) {
2095 str2 = NULL;
2096
2097 // Newlines and comments are handled differently in command lines
2098 // and other types of line. Take a copy of the current line before
2099 // processing it as a non-command line in case it contains a
2100 // rule with a command line. That is, a line of the form:
2101 //
2102 // target: prereq; command
2103 //
2104 copy = xstrdup(str1);
2105 process_line(str1);
2106 str = str1;
2107
2108 // Check for an include line
2109 if (!posix)
2110 while (isblank(*str))
2111 ++str;
2112 minus = !POSIX_2017 && *str == '-';
2113 p = str + minus;
2114 if (strncmp(p, "include", 7) == 0 && isblank(p[7])) {
2115 const char *old_makefile = makefile;
2116 int old_lineno = lineno;
2117
2118 if (ilevel > 16)
2119 error("too many includes");
2120
2121 count = 0;
2122 q = expanded = expand_macros(p + 7, FALSE);
2123 while ((p = gettok(&q)) != NULL) {
2124 FILE *ifd;
2125
2126 ++count;
2127 if (!POSIX_2017) {
2128 // Try to create include file or bring it up-to-date
2129 opts |= OPT_include;
2130 make(newname(p), 1);
2131 opts &= ~OPT_include;
2132 }
2133 if ((ifd = fopen(p, "r")) == NULL) {
2134 if (!minus)
2135 error("can't open include file '%s'", p);
2136 } else {
2137 makefile = p;
2138 input(ifd, ilevel + 1);
2139 fclose(ifd);
2140 makefile = old_makefile;
2141 lineno = old_lineno;
2142 }
2143 if (POSIX_2017)
2144 break;
2145 }
2146 if (POSIX_2017) {
2147 // In POSIX 2017 zero or more than one include file is
2148 // unspecified behaviour.
2149 if (p == NULL || gettok(&q)) {
2150 error("one include file per line");
2151 }
2152 } else if (count == 0) {
2153 // In POSIX 2024 no include file is unspecified behaviour.
2154 if (posix)
2155 error("no include file");
2156 }
2157 goto end_loop;
2158 }
2159
2160 // Check for a macro definition
2161 str = str1;
2162 // POSIX 2024 seems to allow a tab as the first character of
2163 // a macro definition, though most implementations don't.
2164 if (POSIX_2017 && *str == '\t')
2165 error("command not allowed here");
2166 if (find_char(str, '=') != NULL) {
2167 int level = (useenv || fd == NULL) ? 4 : 3;
2168 // Use a copy of the line: we might need the original
2169 // if this turns out to be a target rule.
2170 char *copy2 = xstrdup(str);
2171 char *newq = NULL;
2172 char eq = '\0';
2173 q = find_char(copy2, '='); // q can't be NULL
2174
2175 if (q - 1 > copy2) {
2176 switch (q[-1]) {
2177 case ':':
2178 // '::=' and ':::=' are from POSIX 2024.
2179 if (!POSIX_2017 && q - 2 > copy2 && q[-2] == ':') {
2180 if (q - 3 > copy2 && q[-3] == ':') {
2181 eq = 'B'; // BSD-style ':='
2182 q[-3] = '\0';
2183 } else {
2184 eq = ':'; // GNU-style ':='
2185 q[-2] = '\0';
2186 }
2187 break;
2188 }
2189 // ':=' is a non-POSIX extension.
2190 if (posix)
2191 break;
2192 goto set_eq;
2193 case '+':
2194 case '?':
2195 case '!':
2196 // '+=', '?=' and '!=' are from POSIX 2024.
2197 if (POSIX_2017)
2198 break;
2199 set_eq:
2200 eq = q[-1];
2201 q[-1] = '\0';
2202 break;
2203 }
2204 }
2205 *q++ = '\0'; // Separate name and value
2206 while (isblank(*q))
2207 q++;
2208 if ((p = strrchr(q, '\n')) != NULL)
2209 *p = '\0';
2210
2211 // Expand left-hand side of assignment
2212 p = expanded = expand_macros(copy2, FALSE);
2213 if ((a = gettok(&p)) == NULL)
2214 error("invalid macro assignment");
2215
2216 // If the expanded LHS contains ':' and ';' it can't be a
2217 // macro assignment but it might be a target rule.
2218 if ((s = strchr(a, ':')) != NULL && strchr(s, ';') != NULL) {
2219 free(expanded);
2220 free(copy2);
2221 goto try_target;
2222 }
2223
2224 if (gettok(&p))
2225 error("invalid macro assignment");
2226
2227 if (eq == ':') {
2228 // GNU-style ':='. Expand right-hand side of assignment.
2229 // Macro is of type immediate-expansion.
2230 q = newq = expand_macros(q, FALSE);
2231 level |= M_IMMEDIATE;
2232 }
2233 else if (eq == 'B') {
2234 // BSD-style ':='. Expand right-hand side of assignment,
2235 // though not '$$'. Macro is of type delayed-expansion.
2236 q = newq = expand_macros(q, TRUE);
2237 } else if (eq == '?' && getmp(a) != NULL) {
2238 // Skip assignment if macro is already set
2239 goto end_loop;
2240 } else if (eq == '+') {
2241 // Append to current value
2242 struct macro *mp = getmp(a);
2243 char *rhs;
2244 newq = mp && mp->m_val[0] ? xstrdup(mp->m_val) : NULL;
2245 if (mp && mp->m_immediate) {
2246 // Expand right-hand side of assignment (GNU make
2247 // compatibility)
2248 rhs = expand_macros(q, FALSE);
2249 level |= M_IMMEDIATE;
2250 } else {
2251 rhs = q;
2252 }
2253 newq = xappendword(newq, rhs);
2254 if (rhs != q)
2255 free(rhs);
2256 q = newq;
2257 } else if (eq == '!') {
2258 char *cmd = expand_macros(q, FALSE);
2259 q = newq = run_command(cmd);
2260 free(cmd);
2261 }
2262 setmacro(a, q, level);
2263 free(newq);
2264 free(copy2);
2265 goto end_loop;
2266 }
2267
2268 // If we get here it must be a target rule
2269 try_target:
2270 if (*str == '\t') // Command without target
2271 error("command not allowed here");
2272 p = expanded = expand_macros(str, FALSE);
2273
2274 // Look for colon separator
2275 q = find_colon(p);
2276 if (q == NULL)
2277 error("expected separator");
2278
2279 *q++ = '\0'; // Separate targets and prerequisites
2280
2281 // Double colon
2282 dbl = !posix && *q == ':';
2283 if (dbl)
2284 q++;
2285
2286 // Look for semicolon separator
2287 cp = NULL;
2288 s = strchr(q, ';');
2289 if (s) {
2290 // Retrieve command from expanded copy of line
2291 char *copy3 = expand_macros(copy, FALSE);
2292 if ((p = find_colon(copy3)) && (p = strchr(p, ';')))
2293 newcmd(&cp, process_command(p + 1));
2294 free(copy3);
2295 *s = '\0';
2296 }
2297 semicolon_cmd = cp != NULL && cp->c_cmd[0] != '\0';
2298
2299 // Create list of prerequisites
2300 dp = NULL;
2301 while (((p = gettok(&q)) != NULL)) {
2302 char *newp = NULL;
2303
2304 if (!posix) {
2305 // Allow prerequisites of form library(member1 member2).
2306 // Leading and trailing spaces in the brackets are skipped.
2307 if (!lib) {
2308 s = strchr(p, '(');
2309 if (s && !ends_with_bracket(s) && strchr(q, ')')) {
2310 // Looks like an unterminated archive member
2311 // with a terminator later on the line.
2312 lib = p;
2313 if (s[1] != '\0') {
2314 p = newp = auto_concat(lib, ")");
2315 s[1] = '\0';
2316 } else {
2317 continue;
2318 }
2319 }
2320 } else if (ends_with_bracket(p)) {
2321 if (*p != ')')
2322 p = newp = auto_concat(lib, p);
2323 lib = NULL;
2324 if (newp == NULL)
2325 continue;
2326 } else {
2327 p = newp = auto_string(xasprintf("%s%s)", lib, p));
2328 }
2329 }
2330
2331 // If not in POSIX mode expand wildcards in the name.
2332 nfile = 1;
2333 files = &p;
2334 if (!posix && wildcard(p, &gd)) {
2335 nfile = gd.gl_pathc;
2336 files = gd.gl_pathv;
2337 }
2338 for (i = 0; i < nfile; ++i) {
2339 if (!POSIX_2017 && strcmp(files[i], ".WAIT") == 0)
2340 continue;
2341 np = newname(files[i]);
2342 newdep(&dp, np);
2343 }
2344 if (files != &p)
2345 globfree(&gd);
2346 free(newp);
2347 }
2348 lib = NULL;
2349
2350 // Create list of commands
2351 startno = dispno;
2352 while ((str2 = readline(fd, TRUE)) && *str2 == '\t') {
2353 newcmd(&cp, process_command(str2));
2354 free(str2);
2355 }
2356 dispno = startno;
2357
2358 // Create target names and attach rule to them
2359 q = expanded;
2360 count = 0;
2361 seen_inference = FALSE;
2362 while ((p = gettok(&q)) != NULL) {
2363 // If not in POSIX mode expand wildcards in the name.
2364 nfile = 1;
2365 files = &p;
2366 if (!posix && wildcard(p, &gd)) {
2367 nfile = gd.gl_pathc;
2368 files = gd.gl_pathv;
2369 }
2370 for (i = 0; i < nfile; ++i) {
2371 int ttype = target_type(files[i]);
2372
2373 np = newname(files[i]);
2374 if (ttype != T_NORMAL) {
2375 // Enforce prerequisites/commands in POSIX mode
2376 if (posix) {
2377 if ((ttype & T_NOPREREQ) && dp)
2378 error_not_allowed("prerequisites", p);
2379 if ((ttype & T_INFERENCE)) {
2380 if (semicolon_cmd)
2381 error_in_inference_rule("'; command'");
2382 seen_inference = TRUE;
2383 }
2384 if ((ttype & T_COMMAND) && !cp &&
2385 !((ttype & T_INFERENCE) && !semicolon_cmd))
2386 error("commands required for %s", p);
2387 if (!(ttype & T_COMMAND) && cp)
2388 error_not_allowed("commands", p);
2389 }
2390
2391 if ((ttype & T_INFERENCE)) {
2392 np->n_flag |= N_INFERENCE;
2393 } else if (strcmp(p, ".DEFAULT") == 0) {
2394 // .DEFAULT rule is a special case
2395 np->n_flag |= N_SPECIAL | N_INFERENCE;
2396 } else {
2397 np->n_flag |= N_SPECIAL;
2398 }
2399 } else if (!firstname) {
2400 firstname = np;
2401 }
2402 addrule(np, dp, cp, dbl);
2403 count++;
2404 }
2405 if (files != &p)
2406 globfree(&gd);
2407 }
2408 if (posix && seen_inference && count != 1)
2409 error_in_inference_rule("multiple targets");
2410
2411 // Prerequisites and commands will be unused if there were
2412 // no targets. Avoid leaking memory.
2413 if (count == 0) {
2414 freedeps(dp);
2415 freecmds(cp);
2416 }
2417
2418 end_loop:
2419 free(str1);
2420 dispno = lineno;
2421 str1 = str2 ? str2 : readline(fd, FALSE);
2422 free(copy);
2423 free(expanded);
2424#if ENABLE_FEATURE_MAKE_POSIX
2425 if (!seen_first && fd) {
2426 if (findname(".POSIX")) {
2427 // The first non-comment line from a real makefile
2428 // defined the .POSIX special target.
2429 setenv("PDPMAKE_POSIXLY_CORRECT", "", 1);
2430 posix = TRUE;
2431 }
2432 seen_first = TRUE;
2433 }
2434#endif
2435 }
2436 // Conditionals aren't allowed to span files
2437 if (clevel != old_clevel)
2438 error("invalid conditional");
2439}
2440
2441static void
2442remove_target(void)
2443{
2444 if (!dryrun && !print && !precious &&
2445 target && !(target->n_flag & (N_PRECIOUS | N_PHONY)) &&
2446 unlink(target->n_name) == 0) {
2447 diagnostic("'%s' removed", target->n_name);
2448 }
2449}
2450
2451/*
2452 * Update the modification time of a file to now.
2453 */
2454static void
2455touch(struct name *np)
2456{
2457 if (dryrun || !silent)
2458 printf("touch %s\n", np->n_name);
2459
2460 if (!dryrun) {
2461 const struct timespec timebuf[2] = {{0, UTIME_NOW}, {0, UTIME_NOW}};
2462
2463 if (utimensat(AT_FDCWD, np->n_name, timebuf, 0) < 0) {
2464 if (errno == ENOENT) {
2465 int fd = open(np->n_name, O_RDWR | O_CREAT, 0666);
2466 if (fd >= 0) {
2467 close(fd);
2468 return;
2469 }
2470 }
2471 warning("touch %s failed", np->n_name);
2472 }
2473 }
2474}
2475
2476/*
2477 * Do commands to make a target
2478 */
2479static int
2480docmds(struct name *np, struct cmd *cp)
2481{
2482 int estat = 0;
2483 char *q, *command;
2484
2485 for (; cp; cp = cp->c_next) {
2486 uint32_t ssilent, signore, sdomake;
2487
2488 // Location of command in makefile (for use in error messages)
2489 makefile = cp->c_makefile;
2490 dispno = cp->c_dispno;
2491 opts &= ~OPT_make; // We want to know if $(MAKE) is expanded
2492 q = command = expand_macros(cp->c_cmd, FALSE);
2493 ssilent = silent || (np->n_flag & N_SILENT) || dotouch;
2494 signore = ignore || (np->n_flag & N_IGNORE);
2495 sdomake = (!dryrun || doinclude || domake) && !dotouch;
2496 for (;;) {
2497 if (*q == '@') // Specific silent
2498 ssilent = TRUE + 1;
2499 else if (*q == '-') // Specific ignore
2500 signore = TRUE;
2501 else if (*q == '+') // Specific domake
2502 sdomake = TRUE + 1;
2503 else
2504 break;
2505 do {
2506 q++;
2507 } while (isblank(*q));
2508 }
2509
2510 if (sdomake > TRUE) {
2511 // '+' must not override '@' or .SILENT
2512 if (ssilent != TRUE + 1 && !(np->n_flag & N_SILENT))
2513 ssilent = FALSE;
2514 } else if (!sdomake)
2515 ssilent = dotouch;
2516
2517 if (!ssilent && *q != '\0') { // Ignore empty commands
2518 puts(q);
2519 fflush_all();
2520 }
2521
2522 if (quest && sdomake != TRUE + 1) {
2523 // MAKE_FAILURE means rebuild is needed
2524 estat |= MAKE_FAILURE | MAKE_DIDSOMETHING;
2525 continue;
2526 }
2527
2528 if (sdomake && *q != '\0') { // Ignore empty commands
2529 // Get the shell to execute it
2530 int status;
2531 char *cmd = !signore && posix ? auto_concat("set -e;", q) : q;
2532
2533 target = np;
2534 status = system(cmd);
2535 // If this command was being run to create an include file
2536 // or bring it up-to-date errors should be ignored and a
2537 // failure status returned.
2538 if (status == -1 && !doinclude) {
2539 error("couldn't execute '%s'", q);
2540 } else if (status != 0 && !signore) {
2541 if (!posix && WIFSIGNALED(status))
2542 remove_target();
2543 if (doinclude) {
2544 warning("failed to build '%s'", np->n_name);
2545 } else {
2546 const char *err_type = NULL;
2547 int err_value = 1;
2548
2549 if (WIFEXITED(status)) {
2550 err_type = "exit";
2551 err_value = WEXITSTATUS(status);
2552 } else if (WIFSIGNALED(status)) {
2553 err_type = "signal";
2554 err_value = WTERMSIG(status);
2555 }
2556
2557 if (!quest || err_value == 127) {
2558 if (err_type)
2559 diagnostic("failed to build '%s' %s %d",
2560 np->n_name, err_type, err_value);
2561 else
2562 diagnostic("failed to build '%s'", np->n_name);
2563 }
2564
2565 if (errcont) {
2566 estat |= MAKE_FAILURE;
2567 free(command);
2568 break;
2569 }
2570 exit(2);
2571 }
2572 }
2573 }
2574 if (sdomake || dryrun)
2575 estat = MAKE_DIDSOMETHING;
2576 free(command);
2577 }
2578
2579 if (dotouch && !(np->n_flag & N_PHONY) && !(estat & MAKE_DIDSOMETHING)) {
2580 touch(np);
2581 estat = MAKE_DIDSOMETHING;
2582 }
2583
2584 makefile = NULL;
2585 return estat;
2586}
2587
2588static int
2589make1(struct name *np, struct cmd *cp, char *oodate, char *allsrc,
2590 char *dedup, struct name *implicit)
2591{
2592 char *name, *member = NULL, *base = NULL, *prereq = NULL;
2593
2594 name = splitlib(np->n_name, &member);
2595 setmacro("?", oodate, 0 | M_VALID);
2596 if (!POSIX_2017) {
2597 setmacro("+", allsrc, 0 | M_VALID);
2598 setmacro("^", dedup, 0 | M_VALID);
2599 }
2600 setmacro("%", member, 0 | M_VALID);
2601 setmacro("@", name, 0 | M_VALID);
2602 if (implicit || !posix) {
2603 char *s;
2604
2605 // As an extension, if we're not dealing with an implicit
2606 // rule set $< to the first out-of-date prerequisite.
2607 if (implicit == NULL) {
2608 if (oodate) {
2609 s = strchr(oodate, ' ');
2610 if (s)
2611 *s = '\0';
2612 prereq = oodate;
2613 }
2614 } else
2615 prereq = implicit->n_name;
2616
2617 base = member ? member : name;
2618 s = suffix(base);
2619 // As an extension, if we're not dealing with an implicit
2620 // rule and the target ends with a known suffix, remove it
2621 // and set $* to the stem, else to an empty string.
2622 if (implicit == NULL && !is_suffix(s))
2623 base = NULL;
2624 else
2625 *s = '\0';
2626 }
2627 setmacro("<", prereq, 0 | M_VALID);
2628 setmacro("*", base, 0 | M_VALID);
2629 free(name);
2630
2631 return docmds(np, cp);
2632}
2633
2634/*
2635 * Determine if the modification time of a target, t, is less than
2636 * that of a prerequisite, p. If the tv_nsec member of either is
2637 * exactly 0 we assume (possibly incorrectly) that the time resolution
2638 * is 1 second and only compare tv_sec values.
2639 */
2640static int
2641timespec_le(const struct timespec *t, const struct timespec *p)
2642{
2643 if (t->tv_nsec == 0 || p->tv_nsec == 0)
2644 return t->tv_sec <= p->tv_sec;
2645 else if (t->tv_sec < p->tv_sec)
2646 return TRUE;
2647 else if (t->tv_sec == p->tv_sec)
2648 return t->tv_nsec <= p->tv_nsec;
2649 return FALSE;
2650}
2651
2652/*
2653 * Return the greater of two struct timespecs
2654 */
2655static const struct timespec *
2656timespec_max(const struct timespec *t, const struct timespec *p)
2657{
2658 return timespec_le(t, p) ? p : t;
2659}
2660
2661/*
2662 * Recursive routine to make a target.
2663 */
2664static int
2665make(struct name *np, int level)
2666{
2667 struct depend *dp;
2668 struct rule *rp;
2669 struct name *impdep = NULL; // implicit prerequisite
2670 struct rule imprule;
2671 struct cmd *sc_cmd = NULL; // commands for single-colon rule
2672 char *oodate = NULL;
2673 char *allsrc = NULL;
2674 char *dedup = NULL;
2675 struct timespec dtim = {1, 0};
2676 int estat = 0;
2677
2678 if (np->n_flag & N_DONE)
2679 return 0;
2680 if (np->n_flag & N_DOING)
2681 error("circular dependency for %s", np->n_name);
2682 np->n_flag |= N_DOING;
2683
2684 if (!np->n_tim.tv_sec)
2685 modtime(np); // Get modtime of this file
2686
2687 if (!(np->n_flag & N_DOUBLE)) {
2688 // Find the commands needed for a single-colon rule, using
2689 // an inference rule or .DEFAULT rule if necessary (but,
2690 // as an extension, not for phony targets)
2691 sc_cmd = getcmd(np);
2692 if (!sc_cmd && (posix || !(np->n_flag & N_PHONY))) {
2693 impdep = dyndep(np, &imprule);
2694 if (impdep) {
2695 sc_cmd = imprule.r_cmd;
2696 addrule(np, imprule.r_dep, NULL, FALSE);
2697 }
2698 }
2699
2700 // As a last resort check for a default rule
2701 if (!(np->n_flag & N_TARGET) && np->n_tim.tv_sec == 0) {
2702 if (posix || !(np->n_flag & N_PHONY))
2703 sc_cmd = getcmd(findname(".DEFAULT"));
2704 if (!sc_cmd) {
2705 if (doinclude)
2706 return 1;
2707 error("don't know how to make %s", np->n_name);
2708 }
2709 impdep = np;
2710 }
2711 }
2712 else {
2713 // If any double-colon rule has no commands we need
2714 // an inference rule (but, as an extension, not for phony targets)
2715 for (rp = np->n_rule; rp; rp = rp->r_next) {
2716 if (!rp->r_cmd) {
2717 if (posix || !(np->n_flag & N_PHONY))
2718 impdep = dyndep(np, &imprule);
2719 if (!impdep) {
2720 if (doinclude)
2721 return 1;
2722 error("don't know how to make %s", np->n_name);
2723 }
2724 break;
2725 }
2726 }
2727 }
2728
2729 // Reset flag to detect duplicate prerequisites
2730 if (!(np->n_flag & N_DOUBLE)) {
2731 for (rp = np->n_rule; rp; rp = rp->r_next) {
2732 for (dp = rp->r_dep; dp; dp = dp->d_next) {
2733 dp->d_name->n_flag &= ~N_MARK;
2734 }
2735 }
2736 }
2737
2738 for (rp = np->n_rule; rp; rp = rp->r_next) {
2739 struct name *locdep = NULL;
2740
2741 // Each double-colon rule is handled separately.
2742 if ((np->n_flag & N_DOUBLE)) {
2743 // If the rule has no commands use the inference rule.
2744 if (!rp->r_cmd) {
2745 locdep = impdep;
2746 imprule.r_dep->d_next = rp->r_dep;
2747 rp->r_dep = imprule.r_dep;
2748 rp->r_cmd = imprule.r_cmd;
2749 }
2750 // A rule with no prerequisities is executed unconditionally.
2751 if (!rp->r_dep)
2752 dtim = np->n_tim;
2753 // Reset flag to detect duplicate prerequisites
2754 for (dp = rp->r_dep; dp; dp = dp->d_next) {
2755 dp->d_name->n_flag &= ~N_MARK;
2756 }
2757 }
2758 for (dp = rp->r_dep; dp; dp = dp->d_next) {
2759 // Make prerequisite
2760 estat |= make(dp->d_name, level + 1);
2761
2762 // Make strings of out-of-date prerequisites (for $?),
2763 // all prerequisites (for $+) and deduplicated prerequisites
2764 // (for $^).
2765 if (timespec_le(&np->n_tim, &dp->d_name->n_tim)) {
2766 if (posix || !(dp->d_name->n_flag & N_MARK))
2767 oodate = xappendword(oodate, dp->d_name->n_name);
2768 }
2769 allsrc = xappendword(allsrc, dp->d_name->n_name);
2770 if (!(dp->d_name->n_flag & N_MARK))
2771 dedup = xappendword(dedup, dp->d_name->n_name);
2772 dp->d_name->n_flag |= N_MARK;
2773 dtim = *timespec_max(&dtim, &dp->d_name->n_tim);
2774 }
2775 if ((np->n_flag & N_DOUBLE)) {
2776 if (((np->n_flag & N_PHONY) || timespec_le(&np->n_tim, &dtim))) {
2777 if (!(estat & MAKE_FAILURE)) {
2778 estat |= make1(np, rp->r_cmd, oodate, allsrc,
2779 dedup, locdep);
2780 dtim = (struct timespec){1, 0};
2781 }
2782 free(oodate);
2783 oodate = NULL;
2784 }
2785 free(allsrc);
2786 free(dedup);
2787 allsrc = dedup = NULL;
2788 if (locdep) {
2789 rp->r_dep = rp->r_dep->d_next;
2790 rp->r_cmd = NULL;
2791 }
2792 }
2793 }
2794 if ((np->n_flag & N_DOUBLE) && impdep)
2795 free(imprule.r_dep);
2796
2797 np->n_flag |= N_DONE;
2798 np->n_flag &= ~N_DOING;
2799
2800 if (!(np->n_flag & N_DOUBLE) &&
2801 ((np->n_flag & N_PHONY) || (timespec_le(&np->n_tim, &dtim)))) {
2802 if (!(estat & MAKE_FAILURE)) {
2803 if (sc_cmd)
2804 estat |= make1(np, sc_cmd, oodate, allsrc, dedup, impdep);
2805 else if (!doinclude && level == 0 && !(estat & MAKE_DIDSOMETHING))
2806 warning("nothing to be done for %s", np->n_name);
2807 } else if (!doinclude && !quest) {
2808 diagnostic("'%s' not built due to errors", np->n_name);
2809 }
2810 free(oodate);
2811 }
2812
2813 if (estat & MAKE_DIDSOMETHING) {
2814 modtime(np);
2815 if (!np->n_tim.tv_sec)
2816 clock_gettime(CLOCK_REALTIME, &np->n_tim);
2817 } else if (!quest && level == 0 && !timespec_le(&np->n_tim, &dtim))
2818 printf("%s: '%s' is up to date\n", applet_name, np->n_name);
2819
2820 free(allsrc);
2821 free(dedup);
2822 return estat;
2823}
2824
2825/*
2826 * Check structures for make.
2827 */
2828
2829static void
2830print_name(struct name *np)
2831{
2832 if (np == firstname)
2833 printf("# default target\n");
2834 printf("%s:", np->n_name);
2835 if ((np->n_flag & N_DOUBLE))
2836 putchar(':');
2837}
2838
2839static void
2840print_prerequisites(struct rule *rp)
2841{
2842 struct depend *dp;
2843
2844 for (dp = rp->r_dep; dp; dp = dp->d_next)
2845 printf(" %s", dp->d_name->n_name);
2846}
2847
2848static void
2849print_commands(struct rule *rp)
2850{
2851 struct cmd *cp;
2852
2853 for (cp = rp->r_cmd; cp; cp = cp->c_next)
2854 printf("\t%s\n", cp->c_cmd);
2855}
2856
2857static void
2858print_details(void)
2859{
2860 int i;
2861 struct macro *mp;
2862 struct name *np;
2863 struct rule *rp;
2864
2865 for (i = 0; i < HTABSIZE; i++)
2866 for (mp = macrohead[i]; mp; mp = mp->m_next)
2867 printf("%s = %s\n", mp->m_name, mp->m_val);
2868 putchar('\n');
2869
2870 for (i = 0; i < HTABSIZE; i++) {
2871 for (np = namehead[i]; np; np = np->n_next) {
2872 if (!(np->n_flag & N_DOUBLE)) {
2873 print_name(np);
2874 for (rp = np->n_rule; rp; rp = rp->r_next) {
2875 print_prerequisites(rp);
2876 }
2877 putchar('\n');
2878
2879 for (rp = np->n_rule; rp; rp = rp->r_next) {
2880 print_commands(rp);
2881 }
2882 putchar('\n');
2883 } else {
2884 for (rp = np->n_rule; rp; rp = rp->r_next) {
2885 print_name(np);
2886 print_prerequisites(rp);
2887 putchar('\n');
2888
2889 print_commands(rp);
2890 putchar('\n');
2891 }
2892 }
2893 }
2894 }
2895}
2896
2897/*
2898 * Process options from an argv array. If from_env is non-zero we're
2899 * handling options from MAKEFLAGS so skip '-C', '-f', '-p' and '-x'.
2900 */
2901static uint32_t
2902process_options(char **argv, int from_env)
2903{
2904 uint32_t flags;
2905
2906 flags = getopt32(argv, "^" OPTSTR1 OPTSTR2 "\0k-S:S-k",
2907 &numjobs, &makefiles, &dirs
2908 IF_FEATURE_MAKE_POSIX(, &pragmas));
2909 if (from_env && (flags & (OPT_C | OPT_f | OPT_p | OPT_x)))
2910 error("invalid MAKEFLAGS");
2911 if (posix && (flags & OPT_C))
2912 error("-C not allowed");
2913
2914 return flags;
2915}
2916
2917/*
2918 * Split the contents of MAKEFLAGS into an argv array. If the return
2919 * value (call it fargv) isn't NULL the caller should free fargv[1] and
2920 * fargv.
2921 */
2922static char **
2923expand_makeflags(void)
2924{
2925 const char *m, *makeflags = getenv("MAKEFLAGS");
2926 char *p, *argstr;
2927 int argc;
2928 char **argv;
2929
2930 if (makeflags == NULL)
2931 return NULL;
2932
2933 while (isblank(*makeflags))
2934 makeflags++;
2935
2936 if (*makeflags == '\0')
2937 return NULL;
2938
2939 p = argstr = xzalloc(strlen(makeflags) + 2);
2940
2941 // If MAKEFLAGS doesn't start with a hyphen, doesn't look like
2942 // a macro definition and only contains valid option characters,
2943 // add a hyphen.
2944 argc = 3;
2945 if (makeflags[0] != '-' && strchr(makeflags, '=') == NULL) {
2946 if (strspn(makeflags, OPTSTR1) != strlen(makeflags))
2947 error("invalid MAKEFLAGS");
2948 *p++ = '-';
2949 } else {
2950 // MAKEFLAGS may need to be split, estimate size of argv array.
2951 for (m = makeflags; *m; ++m) {
2952 if (isblank(*m))
2953 argc++;
2954 }
2955 }
2956
2957 argv = xzalloc(argc * sizeof(char *));
2958 argc = 0;
2959 argv[argc++] = (char *)applet_name;
2960 argv[argc++] = argstr;
2961
2962 // Copy MAKEFLAGS into argstr, splitting at non-escaped blanks.
2963 m = makeflags;
2964 do {
2965 if (*m == '\\' && m[1] != '\0')
2966 m++; // Skip backslash, copy next character unconditionally.
2967 else if (isblank(*m)) {
2968 // Terminate current argument and start a new one.
2969 /* *p = '\0'; - xzalloc did it */
2970 argv[argc++] = ++p;
2971 do {
2972 m++;
2973 } while (isblank(*m));
2974 continue;
2975 }
2976 *p++ = *m++;
2977 } while (*m != '\0');
2978 /* *p = '\0'; - xzalloc did it */
2979 /* argv[argc] = NULL; - and this */
2980
2981 return argv;
2982}
2983
2984// These macros require special treatment
2985#define SPECIAL_MACROS "MAKEFLAGS\0SHELL\0CURDIR\0"
2986#define MAKEFLAGS 0
2987#define SHELL 1
2988#define CURDIR 2
2989
2990/*
2991 * Instantiate all macros in an argv-style array of pointers. Stop
2992 * processing at the first string that doesn't contain an equal sign.
2993 * As an extension, target arguments on the command line (level 1)
2994 * are skipped and will be processed later.
2995 */
2996static char **
2997process_macros(char **argv, int level)
2998{
2999 char *equal;
3000
3001 for (; *argv; argv++) {
3002 char *colon = NULL;
3003 int idx, immediate = 0;
3004 int except_dollar = FALSE;
3005
3006 if (!(equal = strchr(*argv, '='))) {
3007 // Skip targets on the command line
3008 if (!posix && level == 1)
3009 continue;
3010 else
3011 // Stop at first target
3012 break;
3013 }
3014
3015 if (equal - 1 > *argv && equal[-1] == ':') {
3016 if (equal - 2 > *argv && equal[-2] == ':') {
3017 if (POSIX_2017)
3018 error("invalid macro assignment");
3019 if (equal - 3 > *argv && equal[-3] == ':') {
3020 // BSD-style ':='. Expand RHS, but not '$$',
3021 // resulting macro is delayed expansion.
3022 colon = equal - 3;
3023 except_dollar = TRUE;
3024 } else {
3025 // GNU-style ':='. Expand RHS, including '$$',
3026 // resulting macro is immediate expansion.
3027 colon = equal - 2;
3028 immediate = M_IMMEDIATE;
3029 }
3030 *colon = '\0';
3031 } else {
3032 if (posix)
3033 error("invalid macro assignment");
3034 colon = equal - 1;
3035 immediate = M_IMMEDIATE;
3036 *colon = '\0';
3037 }
3038 } else
3039 *equal = '\0';
3040
3041 /* We want to process _most_ macro assignments.
3042 * There are exceptions for particular values from the
3043 * environment. */
3044 idx = index_in_strings(SPECIAL_MACROS, *argv);
3045 if (!((level & M_ENVIRON) &&
3046 (idx == MAKEFLAGS || idx == SHELL ||
3047 (idx == CURDIR && !useenv && !POSIX_2017)))) {
3048 if (colon) {
3049 char *exp = expand_macros(equal + 1, except_dollar);
3050 setmacro(*argv, exp, level | immediate);
3051 free(exp);
3052 } else
3053 setmacro(*argv, equal + 1, level);
3054 }
3055
3056 if (colon)
3057 *colon = ':';
3058 else
3059 *equal = '=';
3060 }
3061 return argv;
3062}
3063
3064/*
3065 * Update the MAKEFLAGS macro and environment variable to include any
3066 * command line options that don't have their default value (apart from
3067 * -f, -p and -S). Also add any macros defined on the command line or
3068 * by the MAKEFLAGS environment variable (apart from MAKEFLAGS itself).
3069 * Add macros that were defined on the command line to the environment.
3070 */
3071static void
3072update_makeflags(void)
3073{
3074 int i;
3075 char optbuf[] = "-?";
3076 char *makeflags = NULL;
3077 char *macro, *s;
3078 const char *t;
3079 struct macro *mp;
3080
3081 t = OPTSTR1;
3082 for (i = 0; *t; t++) {
3083 if (*t == ':' || *t == '+')
3084 continue;
3085 if ((opts & OPT_MASK & (1 << i))) {
3086 optbuf[1] = *t;
3087 makeflags = xappendword(makeflags, optbuf);
3088 if (*t == 'j') {
3089 s = auto_string(xasprintf("%d", numjobs));
3090 makeflags = xappendword(makeflags, s);
3091 }
3092 }
3093 i++;
3094 }
3095
3096 for (i = 0; i < HTABSIZE; ++i) {
3097 for (mp = macrohead[i]; mp; mp = mp->m_next) {
3098 if (mp->m_level == 1 || mp->m_level == 2) {
3099 int idx = index_in_strings(SPECIAL_MACROS, mp->m_name);
3100 if (idx == MAKEFLAGS)
3101 continue;
3102 macro = xzalloc(strlen(mp->m_name) + 2 * strlen(mp->m_val) + 1);
3103 s = stpcpy(macro, mp->m_name);
3104 *s++ = '=';
3105 for (t = mp->m_val; *t; t++) {
3106 if (*t == '\\' || isblank(*t))
3107 *s++ = '\\';
3108 *s++ = *t;
3109 }
3110 /* *s = '\0'; - xzalloc did it */
3111
3112 makeflags = xappendword(makeflags, macro);
3113 free(macro);
3114
3115 // Add command line macro definitions to the environment
3116 if (mp->m_level == 1 && idx != SHELL)
3117 setenv(mp->m_name, mp->m_val, 1);
3118 }
3119 }
3120 }
3121
3122 if (makeflags) {
3123 setmacro("MAKEFLAGS", makeflags, 0);
3124 setenv("MAKEFLAGS", makeflags, 1);
3125 free(makeflags);
3126 }
3127}
3128
3129#if !ENABLE_PLATFORM_MINGW32
3130static void
3131make_handler(int sig)
3132{
3133 signal(sig, SIG_DFL);
3134 remove_target();
3135 kill(getpid(), sig);
3136}
3137
3138static void
3139init_signal(int sig)
3140{
3141 struct sigaction sa, new_action;
3142
3143 sigemptyset(&new_action.sa_mask);
3144 new_action.sa_flags = 0;
3145 new_action.sa_handler = make_handler;
3146
3147 sigaction(sig, NULL, &sa);
3148 if (sa.sa_handler != SIG_IGN)
3149 sigaction_set(sig, &new_action);
3150}
3151#endif
3152
3153/*
3154 * If the global option flag associated with a special target hasn't
3155 * been set mark all prerequisites of the target with a flag. If the
3156 * target had no prerequisites set the global option flag.
3157 */
3158static void
3159mark_special(const char *special, uint32_t oflag, uint16_t nflag)
3160{
3161 struct name *np;
3162 struct rule *rp;
3163 struct depend *dp;
3164 int marked = FALSE;
3165
3166 if (!(opts & oflag) && (np = findname(special))) {
3167 for (rp = np->n_rule; rp; rp = rp->r_next) {
3168 for (dp = rp->r_dep; dp; dp = dp->d_next) {
3169 dp->d_name->n_flag |= nflag;
3170 marked = TRUE;
3171 }
3172 }
3173
3174 if (!marked)
3175 opts |= oflag;
3176 }
3177}
3178
3179int make_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
3180int make_main(int argc UNUSED_PARAM, char **argv)
3181{
3182 const char *path, *newpath = NULL;
3183 char **fargv, **fargv0;
3184 const char *dir, *file;
3185#if ENABLE_FEATURE_MAKE_POSIX
3186 const char *prag;
3187#endif
3188 int estat;
3189 bool found_target;
3190 FILE *ifd;
3191
3192 INIT_G();
3193
3194#if ENABLE_FEATURE_MAKE_POSIX
3195 if (argv[1] && strcmp(argv[1], "--posix") == 0) {
3196 argv[1] = argv[0];
3197 ++argv;
3198 --argc;
3199 setenv("PDPMAKE_POSIXLY_CORRECT", "", 1);
3200 posix = TRUE;
3201 } else {
3202 posix = getenv("PDPMAKE_POSIXLY_CORRECT") != NULL;
3203 }
3204 posix_level = DEFAULT_POSIX_LEVEL;
3205 pragmas_from_env();
3206#endif
3207
3208 if (!POSIX_2017) {
3209 path = argv[0];
3210#if ENABLE_PLATFORM_MINGW32
3211 if (has_path(argv[0])) {
3212 // Add extension if necessary, else realpath() will fail
3213 char *p = alloc_ext_space(argv[0]);
3214 add_win32_extension(p);
3215 path = newpath = xmalloc_realpath(p);
3216 free(p);
3217 if (!path) {
3218 if (unix_path(argv[0]))
3219 path = argv[0];
3220 else
3221 bb_perror_msg("can't resolve path for %s", argv[0]);
3222 }
3223 }
3224#else
3225 if (argv[0][0] != '/' && strchr(argv[0], '/')) {
3226 // Make relative path absolute
3227 path = newpath = realpath(argv[0], NULL);
3228 if (!path) {
3229 bb_perror_msg("can't resolve path for %s", argv[0]);
3230 }
3231 }
3232#endif
3233 } else {
3234 path = "make";
3235 }
3236
3237 // Process options from MAKEFLAGS
3238 fargv = fargv0 = expand_makeflags();
3239 if (fargv0) {
3240 opts = process_options(fargv, TRUE);
3241 fargv = fargv0 + optind;
3242 // Reset getopt(3) so we can call it again
3243 GETOPT_RESET();
3244 }
3245
3246 // Process options from the command line
3247 opts |= process_options(argv, FALSE);
3248 argv += optind;
3249
3250 while ((dir = llist_pop(&dirs))) {
3251 if (chdir(dir) == -1) {
3252 bb_perror_msg("can't chdir to %s", dir);
3253 }
3254 }
3255
3256#if ENABLE_FEATURE_MAKE_POSIX
3257 while ((prag = llist_pop(&pragmas)))
3258 set_pragma(prag);
3259 pragmas_to_env();
3260#endif
3261
3262#if !ENABLE_PLATFORM_MINGW32
3263 init_signal(SIGHUP);
3264 init_signal(SIGTERM);
3265#endif
3266
3267 setmacro("$", "$", 0 | M_VALID);
3268
3269 // Process macro definitions from the command line
3270 if (!posix)
3271 process_macros(argv, 1);
3272 else
3273 // In POSIX mode macros must appear before targets.
3274 // argv should now point to targets only.
3275 argv = process_macros(argv, 1);
3276
3277 // Process macro definitions from MAKEFLAGS
3278 if (fargv) {
3279 process_macros(fargv, 2);
3280 free(fargv0[1]);
3281 free(fargv0);
3282 }
3283
3284 // Process macro definitions from the environment
3285 process_macros(environ, 3 | M_ENVIRON);
3286
3287 // Update MAKEFLAGS and environment
3288 update_makeflags();
3289
3290 // Read built-in rules
3291 input(NULL, 0);
3292
3293 setmacro("SHELL", DEFAULT_SHELL, 4);
3294 setmacro("MAKE", path, 4);
3295 if (!POSIX_2017) {
3296 char *cwd = xrealloc_getcwd_or_warn(NULL);
3297
3298 if (cwd) {
3299 if (!useenv) {
3300 // Export cwd to environment, if necessary
3301 char *envcwd = getenv("CURDIR");
3302 if (envcwd && strcmp(cwd, envcwd) != 0)
3303 setenv("CURDIR", cwd, 1);
3304 }
3305 setmacro("CURDIR", cwd, 4);
3306 }
3307 free(cwd);
3308 }
3309 free((void *)newpath);
3310
3311 if (!makefiles) { // Look for a default Makefile
3312 if (!posix && (ifd = fopen("PDPmakefile", "r")) != NULL)
3313 makefile = "PDPmakefile";
3314 else if ((ifd = fopen("PDPmakefile" + 3, "r")) != NULL)
3315 makefile = "PDPmakefile" + 3;
3316#if !ENABLE_PLATFORM_MINGW32
3317 else if ((ifd = fopen("Makefile", "r")) != NULL)
3318 makefile = "Makefile";
3319#endif
3320 else
3321 error("no makefile found");
3322 goto read_makefile;
3323 }
3324
3325 while ((file = llist_pop(&makefiles))) {
3326 if (strcmp(file, "-") == 0) { // Can use stdin as makefile
3327 ifd = stdin;
3328 makefile = "stdin";
3329 } else {
3330 ifd = xfopen_for_read(file);
3331 makefile = file;
3332 }
3333 read_makefile:
3334 input(ifd, 0);
3335 fclose(ifd);
3336 makefile = NULL;
3337 }
3338
3339 if (print)
3340 print_details();
3341
3342 mark_special(".SILENT", OPT_s, N_SILENT);
3343 mark_special(".IGNORE", OPT_i, N_IGNORE);
3344 mark_special(".PRECIOUS", OPT_precious, N_PRECIOUS);
3345 if (!POSIX_2017)
3346 mark_special(".PHONY", OPT_phony, N_PHONY);
3347
3348 if (posix) {
3349 // In POSIX mode only targets should now be in argv.
3350 found_target = FALSE;
3351 for (char **a = argv; *a; a++) {
3352 if (!strchr(*a, '='))
3353 found_target = TRUE;
3354 else if (found_target)
3355 error("macro assignments must precede targets");
3356 }
3357 }
3358
3359 estat = 0;
3360 found_target = FALSE;
3361 for (; *argv; argv++) {
3362 // Skip macro assignments.
3363 if (strchr(*argv, '='))
3364 continue;
3365 found_target = TRUE;
3366 estat |= make(newname(*argv), 0);
3367 }
3368 if (!found_target) {
3369 if (!firstname)
3370 error("no targets defined");
3371 estat = make(firstname, 0);
3372 }
3373
3374#if ENABLE_FEATURE_CLEAN_UP
3375 freenames();
3376 freemacros();
3377 llist_free(makefiles, NULL);
3378 llist_free(dirs, NULL);
3379#endif
3380
3381 return estat & MAKE_FAILURE;
3382}
diff --git a/miscutils/man.c b/miscutils/man.c
index deaf9e5ab..3954455b4 100644
--- a/miscutils/man.c
+++ b/miscutils/man.c
@@ -199,8 +199,7 @@ static char **add_MANPATH(char **man_path_list, int *count_mp, char *path)
199 if (path) while (*path) { 199 if (path) while (*path) {
200 char *next_path; 200 char *next_path;
201 char **path_element; 201 char **path_element;
202 202 next_path = strchr(path, PATH_SEP);
203 next_path = strchr(path, ':');
204 if (next_path) { 203 if (next_path) {
205 if (next_path == path) /* "::"? */ 204 if (next_path == path) /* "::"? */
206 goto next; 205 goto next;
@@ -223,7 +222,7 @@ static char **add_MANPATH(char **man_path_list, int *count_mp, char *path)
223 if (!next_path) 222 if (!next_path)
224 break; 223 break;
225 /* "path" may be a result of getenv(), be nice and don't mangle it */ 224 /* "path" may be a result of getenv(), be nice and don't mangle it */
226 *next_path = ':'; 225 *next_path = PATH_SEP;
227 next: 226 next:
228 path = next_path + 1; 227 path = next_path + 1;
229 } 228 }
@@ -260,11 +259,24 @@ int man_main(int argc UNUSED_PARAM, char **argv)
260 int count_mp; 259 int count_mp;
261 int opt, not_found; 260 int opt, not_found;
262 char *token[2]; 261 char *token[2];
262#if ENABLE_PLATFORM_MINGW32
263 char **ptr;
264 char *relpath;
265 const char *mpl[] = { "/usr/man", "/usr/share/man", NULL, NULL };
266#endif
263 267
264 INIT_G(); 268 INIT_G();
265 269
266 opt = getopt32(argv, "^+" "aw" "\0" "-1"/*at least one arg*/); 270 opt = getopt32(argv, "^+" "aw" "\0" "-1"/*at least one arg*/);
267 argv += optind; 271 argv += optind;
272#if ENABLE_PLATFORM_MINGW32
273 /* add system drive prefix to filenames, if necessary */
274 for (ptr = argv; *ptr; ++ptr) {
275 if (strchr(*ptr, '/') || strchr(*ptr, '\\'))
276 *ptr = xabsolute_path(*ptr);
277 }
278 chdir_system_drive();
279#endif
268 280
269 conf_sec_list = xstrdup("0p:1:1p:2:3:3p:4:5:6:7:8:9"); 281 conf_sec_list = xstrdup("0p:1:1p:2:3:3p:4:5:6:7:8:9");
270 282
@@ -302,11 +314,24 @@ int man_main(int argc UNUSED_PARAM, char **argv)
302 } 314 }
303 config_close(parser); 315 config_close(parser);
304 316
317#if ENABLE_PLATFORM_MINGW32
318 /* allow man pages to be stored relative to the executable */
319 relpath = exe_relative_path("man");
320
321 if (!man_path_list) {
322 mpl[2] = relpath;
323 man_path_list = (char**)mpl;
324 }
325 else {
326 man_path_list = add_MANPATH(man_path_list, &count_mp, relpath);
327 }
328#else
305 if (!man_path_list) { 329 if (!man_path_list) {
306 static const char *const mpl[] ALIGN_PTR = { "/usr/man", "/usr/share/man", NULL }; 330 static const char *const mpl[] ALIGN_PTR = { "/usr/man", "/usr/share/man", NULL };
307 man_path_list = (char**)mpl; 331 man_path_list = (char**)mpl;
308 /*count_mp = 2; - not used below anyway */ 332 /*count_mp = 2; - not used below anyway */
309 } 333 }
334#endif
310 335
311 { 336 {
312 /* environment overrides setting from man.config */ 337 /* environment overrides setting from man.config */
diff --git a/miscutils/time.c b/miscutils/time.c
index 77d35a832..9a1039be9 100644
--- a/miscutils/time.c
+++ b/miscutils/time.c
@@ -22,10 +22,17 @@
22//kbuild:lib-$(CONFIG_TIME) += time.o 22//kbuild:lib-$(CONFIG_TIME) += time.o
23 23
24//usage:#define time_trivial_usage 24//usage:#define time_trivial_usage
25//usage: IF_NOT_PLATFORM_MINGW32(
25//usage: "[-vpa] [-o FILE] PROG ARGS" 26//usage: "[-vpa] [-o FILE] PROG ARGS"
27//usage: )
28//usage: IF_PLATFORM_MINGW32(
29//usage: "[-pa] [-f FMT] [-o FILE] PROG ARGS"
30//usage: )
26//usage:#define time_full_usage "\n\n" 31//usage:#define time_full_usage "\n\n"
27//usage: "Run PROG, display resource usage when it exits\n" 32//usage: "Run PROG, display resource usage when it exits\n"
33//usage: IF_NOT_PLATFORM_MINGW32(
28//usage: "\n -v Verbose" 34//usage: "\n -v Verbose"
35//usage: )
29//usage: "\n -p POSIX output format" 36//usage: "\n -p POSIX output format"
30//usage: "\n -f FMT Custom format" 37//usage: "\n -f FMT Custom format"
31//usage: "\n -o FILE Write result to FILE" 38//usage: "\n -o FILE Write result to FILE"
@@ -57,6 +64,7 @@ static const char default_format[] ALIGN1 = "real\t%E\nuser\t%u\nsys\t%T";
57/* The output format for the -p option .*/ 64/* The output format for the -p option .*/
58static const char posix_format[] ALIGN1 = "real %e\nuser %U\nsys %S"; 65static const char posix_format[] ALIGN1 = "real %e\nuser %U\nsys %S";
59 66
67#if !ENABLE_PLATFORM_MINGW32
60/* Format string for printing all statistics verbosely. 68/* Format string for printing all statistics verbosely.
61 Keep this output to 24 lines so users on terminals can see it all.*/ 69 Keep this output to 24 lines so users on terminals can see it all.*/
62static const char long_format[] ALIGN1 = 70static const char long_format[] ALIGN1 =
@@ -83,6 +91,7 @@ static const char long_format[] ALIGN1 =
83 "\tSignals delivered: %k\n" 91 "\tSignals delivered: %k\n"
84 "\tPage size (bytes): %Z\n" 92 "\tPage size (bytes): %Z\n"
85 "\tExit status: %x"; 93 "\tExit status: %x";
94#endif
86 95
87/* Wait for and fill in data on child process PID. 96/* Wait for and fill in data on child process PID.
88 Return 0 on error, 1 if ok. */ 97 Return 0 on error, 1 if ok. */
@@ -93,7 +102,11 @@ static void resuse_end(pid_t pid, resource_t *resp)
93 102
94 /* Ignore signals, but don't ignore the children. When wait3 103 /* Ignore signals, but don't ignore the children. When wait3
95 * returns the child process, set the time the command finished. */ 104 * returns the child process, set the time the command finished. */
105#if !ENABLE_PLATFORM_MINGW32
96 while ((caught = wait3(&resp->waitstatus, 0, &resp->ru)) != pid) { 106 while ((caught = wait3(&resp->waitstatus, 0, &resp->ru)) != pid) {
107#else
108 while ((caught=mingw_wait3(pid, &resp->waitstatus, 0, &resp->ru)) != pid) {
109#endif
97 if (caught == -1 && errno != EINTR) { 110 if (caught == -1 && errno != EINTR) {
98 bb_simple_perror_msg("wait"); 111 bb_simple_perror_msg("wait");
99 return; 112 return;
@@ -189,9 +202,11 @@ static unsigned long ptok(const unsigned pagesize, const unsigned long pages)
189 202
190static void summarize(const char *fmt, char **command, resource_t *resp) 203static void summarize(const char *fmt, char **command, resource_t *resp)
191{ 204{
205#if !ENABLE_PLATFORM_MINGW32
192 unsigned vv_ms; /* Elapsed virtual (CPU) milliseconds */ 206 unsigned vv_ms; /* Elapsed virtual (CPU) milliseconds */
193 unsigned cpu_ticks; /* Same, in "CPU ticks" */ 207 unsigned cpu_ticks; /* Same, in "CPU ticks" */
194 unsigned pagesize = bb_getpagesize(); 208 unsigned pagesize = bb_getpagesize();
209#endif
195 210
196 /* Impossible: we do not use WUNTRACED flag in wait()... 211 /* Impossible: we do not use WUNTRACED flag in wait()...
197 if (WIFSTOPPED(resp->waitstatus)) 212 if (WIFSTOPPED(resp->waitstatus))
@@ -205,6 +220,7 @@ static void summarize(const char *fmt, char **command, resource_t *resp)
205 printf("Command exited with non-zero status %u\n", 220 printf("Command exited with non-zero status %u\n",
206 WEXITSTATUS(resp->waitstatus)); 221 WEXITSTATUS(resp->waitstatus));
207 222
223#if !ENABLE_PLATFORM_MINGW32
208 vv_ms = (resp->ru.ru_utime.tv_sec + resp->ru.ru_stime.tv_sec) * 1000 224 vv_ms = (resp->ru.ru_utime.tv_sec + resp->ru.ru_stime.tv_sec) * 1000
209 + (resp->ru.ru_utime.tv_usec + resp->ru.ru_stime.tv_usec) / 1000; 225 + (resp->ru.ru_utime.tv_usec + resp->ru.ru_stime.tv_usec) / 1000;
210 226
@@ -215,6 +231,7 @@ static void summarize(const char *fmt, char **command, resource_t *resp)
215 cpu_ticks = vv_ms * (unsigned long long)TICKS_PER_SEC / 1000; 231 cpu_ticks = vv_ms * (unsigned long long)TICKS_PER_SEC / 1000;
216#endif 232#endif
217 if (!cpu_ticks) cpu_ticks = 1; /* we divide by it, must be nonzero */ 233 if (!cpu_ticks) cpu_ticks = 1; /* we divide by it, must be nonzero */
234#endif
218 235
219 while (*fmt) { 236 while (*fmt) {
220 /* Handle leading literal part */ 237 /* Handle leading literal part */
@@ -242,6 +259,7 @@ static void summarize(const char *fmt, char **command, resource_t *resp)
242 case 'C': /* The command that got timed. */ 259 case 'C': /* The command that got timed. */
243 printargv(command); 260 printargv(command);
244 break; 261 break;
262#if !ENABLE_PLATFORM_MINGW32
245 case 'D': /* Average unshared data size. */ 263 case 'D': /* Average unshared data size. */
246 /* (linux kernel sets ru_idrss/isrss/ixrss to 0, 264 /* (linux kernel sets ru_idrss/isrss/ixrss to 0,
247 * docs say the value is in kbytes, so ptok() is wrong) */ 265 * docs say the value is in kbytes, so ptok() is wrong) */
@@ -251,6 +269,7 @@ static void summarize(const char *fmt, char **command, resource_t *resp)
251 ) / cpu_ticks 269 ) / cpu_ticks
252 ); 270 );
253 break; 271 break;
272#endif
254 case 'E': { /* Elapsed real (wall clock) time. */ 273 case 'E': { /* Elapsed real (wall clock) time. */
255 unsigned seconds = resp->elapsed_ms / 1000; 274 unsigned seconds = resp->elapsed_ms / 1000;
256 if (seconds >= 3600) /* One hour -> h:m:s. */ 275 if (seconds >= 3600) /* One hour -> h:m:s. */
@@ -265,6 +284,7 @@ static void summarize(const char *fmt, char **command, resource_t *resp)
265 (unsigned)(resp->elapsed_ms / 10) % 100); 284 (unsigned)(resp->elapsed_ms / 10) % 100);
266 break; 285 break;
267 } 286 }
287#if !ENABLE_PLATFORM_MINGW32
268 case 'F': /* Major page faults. */ 288 case 'F': /* Major page faults. */
269 printf("%lu", resp->ru.ru_majflt); 289 printf("%lu", resp->ru.ru_majflt);
270 break; 290 break;
@@ -297,6 +317,7 @@ static void summarize(const char *fmt, char **command, resource_t *resp)
297 case 'R': /* Minor page faults (reclaims). */ 317 case 'R': /* Minor page faults (reclaims). */
298 printf("%lu", resp->ru.ru_minflt); 318 printf("%lu", resp->ru.ru_minflt);
299 break; 319 break;
320#endif
300 case 'S': /* System time. */ 321 case 'S': /* System time. */
301 printf("%u.%02u", 322 printf("%u.%02u",
302 (unsigned)resp->ru.ru_stime.tv_sec, 323 (unsigned)resp->ru.ru_stime.tv_sec,
@@ -331,6 +352,7 @@ static void summarize(const char *fmt, char **command, resource_t *resp)
331 (unsigned)(resp->ru.ru_utime.tv_sec % 60), 352 (unsigned)(resp->ru.ru_utime.tv_sec % 60),
332 (unsigned)(resp->ru.ru_utime.tv_usec / 10000)); 353 (unsigned)(resp->ru.ru_utime.tv_usec / 10000));
333 break; 354 break;
355#if !ENABLE_PLATFORM_MINGW32
334 case 'W': /* Times swapped out. */ 356 case 'W': /* Times swapped out. */
335 printf("%lu", resp->ru.ru_nswap); 357 printf("%lu", resp->ru.ru_nswap);
336 break; 358 break;
@@ -343,11 +365,13 @@ static void summarize(const char *fmt, char **command, resource_t *resp)
343 case 'c': /* Involuntary context switches. */ 365 case 'c': /* Involuntary context switches. */
344 printf("%lu", resp->ru.ru_nivcsw); 366 printf("%lu", resp->ru.ru_nivcsw);
345 break; 367 break;
368#endif
346 case 'e': /* Elapsed real time in seconds. */ 369 case 'e': /* Elapsed real time in seconds. */
347 printf("%u.%02u", 370 printf("%u.%02u",
348 (unsigned)resp->elapsed_ms / 1000, 371 (unsigned)resp->elapsed_ms / 1000,
349 (unsigned)(resp->elapsed_ms / 10) % 100); 372 (unsigned)(resp->elapsed_ms / 10) % 100);
350 break; 373 break;
374#if !ENABLE_PLATFORM_MINGW32
351 case 'k': /* Signals delivered. */ 375 case 'k': /* Signals delivered. */
352 printf("%lu", resp->ru.ru_nsignals); 376 printf("%lu", resp->ru.ru_nsignals);
353 break; 377 break;
@@ -366,6 +390,7 @@ static void summarize(const char *fmt, char **command, resource_t *resp)
366 case 'w': /* Voluntary context switches. */ 390 case 'w': /* Voluntary context switches. */
367 printf("%lu", resp->ru.ru_nvcsw); 391 printf("%lu", resp->ru.ru_nvcsw);
368 break; 392 break;
393#endif
369 case 'x': /* Exit status. */ 394 case 'x': /* Exit status. */
370 printf("%u", WEXITSTATUS(resp->waitstatus)); 395 printf("%u", WEXITSTATUS(resp->waitstatus));
371 break; 396 break;
@@ -409,6 +434,7 @@ static void summarize(const char *fmt, char **command, resource_t *resp)
409static void run_command(char *const *cmd, resource_t *resp) 434static void run_command(char *const *cmd, resource_t *resp)
410{ 435{
411 pid_t pid; 436 pid_t pid;
437#if !ENABLE_PLATFORM_MINGW32
412 void (*interrupt_signal)(int); 438 void (*interrupt_signal)(int);
413 void (*quit_signal)(int); 439 void (*quit_signal)(int);
414 440
@@ -429,6 +455,13 @@ static void run_command(char *const *cmd, resource_t *resp)
429 /* Re-enable signals. */ 455 /* Re-enable signals. */
430 signal(SIGINT, interrupt_signal); 456 signal(SIGINT, interrupt_signal);
431 signal(SIGQUIT, quit_signal); 457 signal(SIGQUIT, quit_signal);
458#else
459 resp->elapsed_ms = monotonic_ms();
460 if ((pid=spawn((char **)cmd)) == -1)
461 bb_perror_msg_and_die("can't execute %s", cmd[0]);
462
463 resuse_end(pid, resp);
464#endif
432} 465}
433 466
434int time_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 467int time_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
@@ -442,20 +475,35 @@ int time_main(int argc UNUSED_PARAM, char **argv)
442 int opt; 475 int opt;
443 int ex; 476 int ex;
444 enum { 477 enum {
478#if !ENABLE_PLATFORM_MINGW32
445 OPT_v = (1 << 0), 479 OPT_v = (1 << 0),
446 OPT_p = (1 << 1), 480 OPT_p = (1 << 1),
447 OPT_a = (1 << 2), 481 OPT_a = (1 << 2),
448 OPT_o = (1 << 3), 482 OPT_o = (1 << 3),
449 OPT_f = (1 << 4), 483 OPT_f = (1 << 4),
484#else
485 OPT_p = (1 << 0),
486 OPT_a = (1 << 1),
487 OPT_o = (1 << 2),
488 OPT_f = (1 << 3),
489#endif
450 }; 490 };
451 491
452 /* "+": stop on first non-option */ 492 /* "+": stop on first non-option */
493#if !ENABLE_PLATFORM_MINGW32
453 opt = getopt32(argv, "^+" "vpao:f:" "\0" "-1"/*at least one arg*/, 494 opt = getopt32(argv, "^+" "vpao:f:" "\0" "-1"/*at least one arg*/,
454 &output_filename, &output_format 495 &output_filename, &output_format
455 ); 496 );
497#else
498 opt = getopt32(argv, "^+" "pao:f:" "\0" "-1"/*at least one arg*/,
499 &output_filename, &output_format
500 );
501#endif
456 argv += optind; 502 argv += optind;
503#if !ENABLE_PLATFORM_MINGW32
457 if (opt & OPT_v) 504 if (opt & OPT_v)
458 output_format = long_format; 505 output_format = long_format;
506#endif
459 if (opt & OPT_p) 507 if (opt & OPT_p)
460 output_format = posix_format; 508 output_format = posix_format;
461 output_fd = STDERR_FILENO; 509 output_fd = STDERR_FILENO;
@@ -476,6 +524,9 @@ int time_main(int argc UNUSED_PARAM, char **argv)
476 524
477 /* Cheat. printf's are shorter :) */ 525 /* Cheat. printf's are shorter :) */
478 xdup2(output_fd, STDOUT_FILENO); 526 xdup2(output_fd, STDOUT_FILENO);
527#if ENABLE_PLATFORM_MINGW32
528 setvbuf(stdout, NULL, _IOFBF, 256);
529#endif
479 summarize(output_format, argv, &res); 530 summarize(output_format, argv, &res);
480 531
481 ex = WEXITSTATUS(res.waitstatus); 532 ex = WEXITSTATUS(res.waitstatus);
diff --git a/miscutils/ts.c b/miscutils/ts.c
index c5c1879df..fb669b858 100644
--- a/miscutils/ts.c
+++ b/miscutils/ts.c
@@ -25,6 +25,9 @@ int ts_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
25int ts_main(int argc UNUSED_PARAM, char **argv) 25int ts_main(int argc UNUSED_PARAM, char **argv)
26{ 26{
27 struct timeval base; 27 struct timeval base;
28#if ENABLE_PLATFORM_MINGW32
29 time_t t;
30#endif
28 unsigned opt; 31 unsigned opt;
29 char *frac; 32 char *frac;
30 char *fmt_dt2str; 33 char *fmt_dt2str;
@@ -73,7 +76,12 @@ int ts_main(int argc UNUSED_PARAM, char **argv)
73 if (opt & 1) /* -i */ 76 if (opt & 1) /* -i */
74 base = ts1; 77 base = ts1;
75 } 78 }
79#if ENABLE_PLATFORM_MINGW32
80 t = ts.tv_sec;
81 localtime_r(&t, &tm_time);
82#else
76 localtime_r(&ts.tv_sec, &tm_time); 83 localtime_r(&ts.tv_sec, &tm_time);
84#endif
77 strftime(date_buf, COMMON_BUFSIZE, fmt_dt2str, &tm_time); 85 strftime(date_buf, COMMON_BUFSIZE, fmt_dt2str, &tm_time);
78 if (!frac) { 86 if (!frac) {
79 printf("%s %s", date_buf, line); 87 printf("%s %s", date_buf, line);