1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
|
/**************************************************************************/
/* */
/* OCaml */
/* */
/* David Allsopp, OCaml Labs, Cambridge. */
/* */
/* Copyright 2021 David Allsopp Ltd. */
/* */
/* All rights reserved. This file is distributed under the terms of */
/* the GNU Lesser General Public License version 2.1, with the */
/* special exception on linking described in the file LICENSE. */
/* */
/**************************************************************************/
/* Runtime Builder's Swiss Army Knife. This utility performs functions
previously delegated to classic Unix utilities but which ultimately seem to
cause more hassle for maintenance than the initial simplicity suggests.
This tool is a memorial to the many hours and PRs spent chasing down strange
locale issues, stray CR characters and fighting yet another incompatible
implementation of sed or awk. */
/* Borrow the Unicode *_os definitions and T() macro from misc.h */
#define CAML_INTERNALS
#include "caml/misc.h"
#include <stdio.h>
#include <string.h>
#include <ctype.h>
/* Operations
- encode-C-literal. Used for the OCAML_STDLIB_DIR macro in
runtime/build_config.h to ensure the LIBDIR make variable is correctly
represented as a C string literal.
On Unix, `sak encode-C-literal /usr/local/lib` returns `"/usr/local/lib"`
On Windows, `sak encode-C-literal "C:\OCaml🐫\lib"` returns
`L"C:\\OCaml\xd83d\xdc2b\\lib"`
*/
static void usage(void)
{
printf(
"OCaml Build System Swiss Army Knife\n"
"Usage: sak command\n"
"Commands:\n"
" * encode-C-literal path - encodes path as a C string literal\n"
);
}
/* Converts the supplied path (UTF-8 on Unix and UCS-2ish on Windows) to a valid
C string literal. On Windows, this is always a wchar_t* (L"..."). */
static void encode_C_literal(const char_os * path)
{
char_os c;
#ifdef _WIN32
putchar('L');
#endif
putchar('"');
while ((c = *path++) != 0) {
/* Escape \, " and \n */
if (c == '\\') {
printf("\\\\");
} else if (c == '"') {
printf("\\\"");
} else if (c == '\n') {
printf("\\n");
#ifndef _WIN32
/* On Unix, nothing else needs escaping */
} else {
putchar(c);
#else
/* On Windows, allow 7-bit printable characters to be displayed literally
and escape everything else (using the older \x notation for increased
compatibility, rather than the newer \U. */
} else if (c < 0x80 && iswprint(c)) {
putwchar(c);
} else {
printf("\\x%04x", c);
#endif
}
}
putchar('"');
}
int main_os(int argc, char_os **argv)
{
if (argc == 3 && !strcmp_os(argv[1], T("encode-C-literal"))) {
encode_C_literal(argv[2]);
} else {
usage();
return 1;
}
return 0;
}
|