mirror of
				https://github.com/jart/cosmopolitan.git
				synced 2025-10-27 03:16:44 +00:00 
			
		
		
		
	Remove some dead code
This commit is contained in:
		
							parent
							
								
									168d1c157e
								
							
						
					
					
						commit
						73c0faa1b5
					
				
					 66 changed files with 324 additions and 7705 deletions
				
			
		|  | @ -3,8 +3,7 @@ | |||
| #if !(__ASSEMBLER__ + __LINKER__ + 0) | ||||
| COSMOPOLITAN_C_START_ | ||||
| 
 | ||||
| extern bool __assert_disable; | ||||
| void __assert_fail(const char *, const char *, int) _Hide relegated; | ||||
| void __assert_fail(const char *, const char *, int) relegated; | ||||
| 
 | ||||
| #ifdef NDEBUG | ||||
| #define assert(x) ((void)0) | ||||
|  | @ -16,6 +15,8 @@ void __assert_fail(const char *, const char *, int) _Hide relegated; | |||
| #define static_assert _Static_assert | ||||
| #endif | ||||
| 
 | ||||
| #ifdef COSMO | ||||
| extern bool __assert_disable; | ||||
| #ifndef NDEBUG | ||||
| #define _unassert(x) __assert_macro(x, #x) | ||||
| #define _npassert(x) __assert_macro(x, #x) | ||||
|  | @ -42,7 +43,8 @@ void __assert_fail(const char *, const char *, int) _Hide relegated; | |||
|     }                                \ | ||||
|     (void)0;                         \ | ||||
|   }) | ||||
| #endif | ||||
| #endif /* NDEBUG */ | ||||
| #endif /* COSMO */ | ||||
| 
 | ||||
| COSMOPOLITAN_C_END_ | ||||
| #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ | ||||
|  |  | |||
|  | @ -1,7 +1,7 @@ | |||
| /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
 | ||||
| │vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8                                :vi│ | ||||
| ╞══════════════════════════════════════════════════════════════════════════════╡ | ||||
| │ Copyright 2022 Justine Alexandra Roberts Tunney                              │ | ||||
| │ Copyright 2023 Justine Alexandra Roberts Tunney                              │ | ||||
| │                                                                              │ | ||||
| │ Permission to use, copy, modify, and/or distribute this software for         │ | ||||
| │ any purpose with or without fee is hereby granted, provided that the         │ | ||||
|  | @ -16,18 +16,19 @@ | |||
| │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR             │ | ||||
| │ PERFORMANCE OF THIS SOFTWARE.                                                │ | ||||
| ╚─────────────────────────────────────────────────────────────────────────────*/ | ||||
| #include "libc/assert.h" | ||||
| #include "libc/calls/calls.h" | ||||
| #include "libc/elf/struct/ehdr.h" | ||||
| #include "libc/fmt/itoa.h" | ||||
| #include "libc/runtime/runtime.h" | ||||
| #include "libc/sysv/consts/auxv.h" | ||||
| 
 | ||||
| noasan int main(int argc, char *argv[]) { | ||||
|   int i = 0; | ||||
|   Elf64_Ehdr *ehdr; | ||||
|   ehdr = (Elf64_Ehdr *)getauxval(AT_SYSINFO_EHDR); | ||||
|   if (isatty(1)) exit(1); | ||||
|   for (;;) { | ||||
|     write(1, ((char *)ehdr) + i++, 1); | ||||
| /**
 | ||||
|  * Handles assert() failure. | ||||
|  */ | ||||
| void __assert_fail(const char *expr, const char *file, int line) { | ||||
|   char ibuf[12]; | ||||
|   if (!__assert_disable) { | ||||
|     FormatInt32(ibuf, line); | ||||
|     tinyprint(2, file, ":", ibuf, ": assert(", expr, ") failed\n", NULL); | ||||
|     abort(); | ||||
|   } | ||||
|   return 0; | ||||
| } | ||||
|  | @ -62,7 +62,7 @@ COSMOPOLITAN_C_START_ | |||
| 
 | ||||
| typedef int sig_atomic_t; | ||||
| 
 | ||||
| bool32 isatty(int) nosideeffect; | ||||
| bool32 isatty(int); | ||||
| char *get_current_dir_name(void) dontdiscard; | ||||
| char *getcwd(char *, size_t); | ||||
| char *realpath(const char *, char *); | ||||
|  |  | |||
|  | @ -24,11 +24,8 @@ | |||
| /**
 | ||||
|  * Writes error messages to standard error. | ||||
|  */ | ||||
| void perror(const char *message) { | ||||
|   int err; | ||||
|   const char *estr; | ||||
|   estr = _strerdoc(errno); | ||||
|   if (!message) message = ""; | ||||
|   if (!estr) estr = "Unknown error"; | ||||
|   tinyprint(2, message, *message ? ": " : "", estr, "\n", NULL); | ||||
| void perror(const char *thing) { | ||||
|   const char *reason; | ||||
|   if (!(reason = _strerdoc(errno))) reason = "Unknown error"; | ||||
|   tinyprint(2, thing ? thing : "", thing ? ": " : "", reason, "\n", NULL); | ||||
| } | ||||
|  | @ -17,7 +17,7 @@ | |||
| │ PERFORMANCE OF THIS SOFTWARE.                                                │ | ||||
| ╚─────────────────────────────────────────────────────────────────────────────*/ | ||||
| 
 | ||||
| // stub version of abort() for low-dependency apps
 | ||||
| // stub version of abort() to keep the build a dag
 | ||||
| __attribute__((__noreturn__, __weak__)) void abort(void) { | ||||
|   __builtin_trap(); | ||||
| } | ||||
|  |  | |||
|  | @ -1,7 +1,7 @@ | |||
| /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
 | ||||
| │vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8                                :vi│ | ||||
| ╞══════════════════════════════════════════════════════════════════════════════╡ | ||||
| │ Copyright 2021 Justine Alexandra Roberts Tunney                              │ | ||||
| │ Copyright 2023 Justine Alexandra Roberts Tunney                              │ | ||||
| │                                                                              │ | ||||
| │ Permission to use, copy, modify, and/or distribute this software for         │ | ||||
| │ any purpose with or without fee is hereby granted, provided that the         │ | ||||
|  | @ -16,19 +16,9 @@ | |||
| │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR             │ | ||||
| │ PERFORMANCE OF THIS SOFTWARE.                                                │ | ||||
| ╚─────────────────────────────────────────────────────────────────────────────*/ | ||||
| #include "libc/fmt/conv.h" | ||||
| #include "libc/math.h" | ||||
| #include "libc/stdio/stdio.h" | ||||
| 
 | ||||
| int main(int argc, char *argv[]) { | ||||
|   int i, x, y; | ||||
|   for (i = 1; i < argc; ++i) { | ||||
|     x = atoi(argv[i]); | ||||
|     y = round( | ||||
|         (1.923 * cbrt(x * log(2)) * cbrt(log(x * log(2)) * log(x * log(2))) - | ||||
|          4.69) / | ||||
|         log(2)); | ||||
|     printf("%4d %4d\n", x, y); | ||||
|   } | ||||
|   return 0; | ||||
| // stub version of assert() to keep the build a dag
 | ||||
| __attribute__((__weak__)) void __assert_fail(const char *expr, const char *file, | ||||
|                                              int line) { | ||||
|   __builtin_trap(); | ||||
| } | ||||
|  | @ -1,33 +0,0 @@ | |||
| /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
 | ||||
| │vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8                                :vi│ | ||||
| ╞══════════════════════════════════════════════════════════════════════════════╡ | ||||
| │ Copyright 2020 Justine Alexandra Roberts Tunney                              │ | ||||
| │                                                                              │ | ||||
| │ Permission to use, copy, modify, and/or distribute this software for         │ | ||||
| │ any purpose with or without fee is hereby granted, provided that the         │ | ||||
| │ above copyright notice and this permission notice appear in all copies.      │ | ||||
| │                                                                              │ | ||||
| │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL                │ | ||||
| │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED                │ | ||||
| │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE             │ | ||||
| │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL         │ | ||||
| │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR        │ | ||||
| │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER               │ | ||||
| │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR             │ | ||||
| │ PERFORMANCE OF THIS SOFTWARE.                                                │ | ||||
| ╚─────────────────────────────────────────────────────────────────────────────*/ | ||||
| #include "libc/assert.h" | ||||
| #include "libc/atomic.h" | ||||
| #include "libc/intrin/atomic.h" | ||||
| #include "libc/intrin/kprintf.h" | ||||
| #include "libc/runtime/runtime.h" | ||||
| 
 | ||||
| privileged void __assert_fail(const char *expr, const char *file, int line) { | ||||
|   static atomic_bool once; | ||||
|   if (!__assert_disable) { | ||||
|     if (!atomic_exchange(&once, true)) { | ||||
|       kprintf("%s:%d: assert(%s) failed (tid %P) %m\n", file, line, expr); | ||||
|     } | ||||
|     __builtin_trap(); | ||||
|   } | ||||
| } | ||||
|  | @ -1,4 +1,4 @@ | |||
| #ifndef COSMOPOLITAN_LIBC_ISYSTEM_ALLOCA_H_ | ||||
| #define COSMOPOLITAN_LIBC_ISYSTEM_ALLOCA_H_ | ||||
| #ifndef _ALLOCA_H | ||||
| #define _ALLOCA_H | ||||
| #include "libc/mem/alloca.h" | ||||
| #endif /* COSMOPOLITAN_LIBC_ISYSTEM_ALLOCA_H_ */ | ||||
| #endif /* _ALLOCA_H */ | ||||
|  |  | |||
|  | @ -1,4 +1,4 @@ | |||
| #ifndef COSMOPOLITAN_LIBC_ISYSTEM_AR_H_ | ||||
| #define COSMOPOLITAN_LIBC_ISYSTEM_AR_H_ | ||||
| #ifndef _AR_H | ||||
| #define _AR_H | ||||
| #include "libc/ar.h" | ||||
| #endif /* COSMOPOLITAN_LIBC_ISYSTEM_AR_H_ */ | ||||
| #endif /* _AR_H */ | ||||
|  |  | |||
|  | @ -1,5 +1,5 @@ | |||
| #ifndef COSMOPOLITAN_LIBC_ISYSTEM_COSMO_H_ | ||||
| #define COSMOPOLITAN_LIBC_ISYSTEM_COSMO_H_ | ||||
| #ifndef _COSMO_H | ||||
| #define _COSMO_H | ||||
| 
 | ||||
| #ifdef COSMO | ||||
| #define COSMO_ALREADY_DEFINED | ||||
|  | @ -65,4 +65,4 @@ | |||
| #undef COSMO | ||||
| #endif | ||||
| 
 | ||||
| #endif /* COSMOPOLITAN_LIBC_ISYSTEM_COSMO_H_ */ | ||||
| #endif /* _COSMO_H */ | ||||
|  |  | |||
|  | @ -1,8 +1,6 @@ | |||
| #ifndef COSMOPOLITAN_LIBC_MEM_ALLOCA_H_ | ||||
| #define COSMOPOLITAN_LIBC_MEM_ALLOCA_H_ | ||||
| #if !(__ASSEMBLER__ + __LINKER__ + 0) | ||||
| 
 | ||||
| #define alloca(size) __builtin_alloca(size) | ||||
| 
 | ||||
| #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ | ||||
| #endif /* COSMOPOLITAN_LIBC_MEM_ALLOCA_H_ */ | ||||
|  |  | |||
|  | @ -153,7 +153,7 @@ textstartup void cosmo(long *sp, struct Syslib *m1) { | |||
|   __envp = envp; | ||||
|   __auxv = auxv; | ||||
|   environ = envp; | ||||
|   if (argc) program_invocation_name = argv[0]; | ||||
|   program_invocation_name = argv[0]; | ||||
| 
 | ||||
|   // initialize program
 | ||||
|   _init(); | ||||
|  |  | |||
|  | @ -60,8 +60,8 @@ | |||
|               ? __ckd_##op##ll((__ckd_dword *)(res), (x), (y))           \ | ||||
|               : __ckd_trap())) | ||||
| 
 | ||||
| __funline wontreturn int __ckd_trap(void) { | ||||
|   *(volatile int *)0 = 0; | ||||
| __funline int __ckd_trap(void) { | ||||
|   return *(volatile int *)0 = 0; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  |  | |||
|  | @ -240,9 +240,10 @@ static int __fmt_ntoa_format(int out(const char *, void *, size_t), void *arg, | |||
|   return 0; | ||||
| } | ||||
| 
 | ||||
| static int ntoa2(int out(const char *, void *, size_t), void *arg, | ||||
|                  uint128_t value, bool neg, unsigned log2base, unsigned prec, | ||||
|                  unsigned width, unsigned flags, const char *alphabet) { | ||||
| static int __fmt_ntoa2(int out(const char *, void *, size_t), void *arg, | ||||
|                        uint128_t value, bool neg, unsigned log2base, | ||||
|                        unsigned prec, unsigned width, unsigned flags, | ||||
|                        const char *alphabet) { | ||||
|   uint128_t remainder; | ||||
|   unsigned len, count, digit; | ||||
|   char buf[BUFFER_SIZE]; | ||||
|  | @ -314,7 +315,7 @@ static int __fmt_ntoa(int out(const char *, void *, size_t), void *arg, | |||
|     } | ||||
|   } | ||||
| 
 | ||||
|   return ntoa2(out, arg, value, neg, log2base, prec, width, flags, lang); | ||||
|   return __fmt_ntoa2(out, arg, value, neg, log2base, prec, width, flags, lang); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  |  | |||
							
								
								
									
										124
									
								
								third_party/getopt/getopt.c
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										124
									
								
								third_party/getopt/getopt.c
									
										
									
									
										vendored
									
									
								
							|  | @ -41,56 +41,27 @@ getopt (BSD-3)\\n\ | |||
| Copyright 1987, 1993, 1994 The Regents of the University of California\""); | ||||
| asm(".include \"libc/disclaimer.inc\""); | ||||
| 
 | ||||
| #define BADCH  (int)'?' | ||||
| #define BADARG (int)':' | ||||
| #define BADCH  '?' | ||||
| #define BADARG ':' | ||||
| 
 | ||||
| /**
 | ||||
|  * If error message should be printed. | ||||
|  * @see getopt() | ||||
|  */ | ||||
| int opterr; | ||||
| int opterr;    // If error message should be printed.
 | ||||
| int optind;    // Index into parent argv vector.
 | ||||
| int optopt;    // Character checked for validity.
 | ||||
| int optreset;  // Reset getopt.
 | ||||
| char *optarg;  // Argument associated with option.
 | ||||
| 
 | ||||
| /**
 | ||||
|  * Index into parent argv vector. | ||||
|  * @see getopt() | ||||
|  */ | ||||
| int optind; | ||||
| static struct { | ||||
|   char once; | ||||
|   char emsg[1]; | ||||
|   char *place; | ||||
| } optglob; | ||||
| 
 | ||||
| /**
 | ||||
|  * Character checked for validity. | ||||
|  * @see getopt() | ||||
|  */ | ||||
| int optopt; | ||||
| 
 | ||||
| /**
 | ||||
|  * Reset getopt. | ||||
|  * @see getopt() | ||||
|  */ | ||||
| int optreset; | ||||
| 
 | ||||
| /**
 | ||||
|  * Argument associated with option. | ||||
|  * @see getopt() | ||||
|  */ | ||||
| char *optarg; | ||||
| 
 | ||||
| char *getopt_place; | ||||
| static char kGetoptEmsg[1]; | ||||
| 
 | ||||
| static void getopt_print_badch(const char *s) { | ||||
|   char b1[512]; | ||||
|   char b2[8] = " -- "; | ||||
|   b1[0] = 0; | ||||
|   if (program_invocation_name) { | ||||
|     strlcat(b1, program_invocation_name, sizeof(b1)); | ||||
|     strlcat(b1, ": ", sizeof(b1)); | ||||
|   } | ||||
|   strlcat(b1, s, sizeof(b1)); | ||||
|   b2[4] = optopt; | ||||
|   b2[5] = '\n'; | ||||
|   b2[6] = 0; | ||||
|   strlcat(b1, b2, sizeof(b1)); | ||||
|   write(2, b1, strlen(b1)); | ||||
| static void getopt_print(const char *s) { | ||||
|   const char *prog; | ||||
|   char b[8] = " -- ?\n"; | ||||
|   prog = program_invocation_short_name; | ||||
|   b[4] = optopt; | ||||
|   tinyprint(2, prog ? prog : "", prog ? ": " : "", s, b, NULL); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  | @ -116,69 +87,74 @@ static void getopt_print_badch(const char *s) { | |||
|  */ | ||||
| int getopt(int nargc, char *const nargv[], const char *ostr) { | ||||
|   char *oli; /* option letter list index */ | ||||
|   static bool once; | ||||
|   if (!once) { | ||||
|   if (!optglob.once) { | ||||
|     opterr = 1; | ||||
|     optind = 1; | ||||
|     getopt_place = kGetoptEmsg; | ||||
|     once = true; | ||||
|     optglob.place = optglob.emsg; | ||||
|     optglob.once = 1; | ||||
|   } | ||||
|   /*
 | ||||
|    * Some programs like cvs expect optind = 0 to trigger | ||||
|    * a reset of getopt. | ||||
|    */ | ||||
|   if (optind == 0) optind = 1; | ||||
|   if (optreset || *getopt_place == 0) { /* update scanning pointer */ | ||||
|   if (!optind) optind = 1; | ||||
|   if (optreset || !*optglob.place) { /* update scanning pointer */ | ||||
|     optreset = 0; | ||||
|     getopt_place = nargv[optind]; | ||||
|     if (optind >= nargc || *getopt_place++ != '-') { | ||||
|     optglob.place = nargv[optind]; | ||||
|     if (optind >= nargc || *optglob.place++ != '-') { | ||||
|       /* Argument is absent or is not an option */ | ||||
|       getopt_place = kGetoptEmsg; | ||||
|       optglob.place = optglob.emsg; | ||||
|       return -1; | ||||
|     } | ||||
|     optopt = *getopt_place++; | ||||
|     if (optopt == '-' && *getopt_place == 0) { | ||||
|     optopt = *optglob.place++; | ||||
|     if (optopt == '-' && !*optglob.place) { | ||||
|       /* "--" => end of options */ | ||||
|       ++optind; | ||||
|       getopt_place = kGetoptEmsg; | ||||
|       optglob.place = optglob.emsg; | ||||
|       return -1; | ||||
|     } | ||||
|     if (optopt == 0) { | ||||
|     if (!optopt) { | ||||
|       /* Solitary '-', treat as a '-' option
 | ||||
|          if the program (eg su) is looking for it. */ | ||||
|       getopt_place = kGetoptEmsg; | ||||
|       if (strchr(ostr, '-') == NULL) return -1; | ||||
|       optglob.place = optglob.emsg; | ||||
|       if (!strchr(ostr, '-')) return -1; | ||||
|       optopt = '-'; | ||||
|     } | ||||
|   } else { | ||||
|     optopt = *getopt_place++; | ||||
|     optopt = *optglob.place++; | ||||
|   } | ||||
|   /* See if option letter is one the caller wanted... */ | ||||
|   if (optopt == ':' || (oli = strchr(ostr, optopt)) == NULL) { | ||||
|     if (*getopt_place == 0) ++optind; | ||||
|     if (opterr && *ostr != ':') getopt_print_badch("illegal option"); | ||||
|   if (optopt == ':' || !(oli = strchr(ostr, optopt))) { | ||||
|     if (!*optglob.place) ++optind; | ||||
|     if (opterr && *ostr != ':') { | ||||
|       getopt_print("illegal option"); | ||||
|     } | ||||
|     return BADCH; | ||||
|   } | ||||
|   /* Does this option need an argument? */ | ||||
|   if (oli[1] != ':') { | ||||
|     /* don't need argument */ | ||||
|     optarg = NULL; | ||||
|     if (*getopt_place == 0) ++optind; | ||||
|     optarg = 0; | ||||
|     if (!*optglob.place) ++optind; | ||||
|   } else { | ||||
|     /* Option-argument is either the rest of this argument or the
 | ||||
|        entire next argument. */ | ||||
|     if (*getopt_place) { | ||||
|       optarg = getopt_place; | ||||
|     if (*optglob.place) { | ||||
|       optarg = optglob.place; | ||||
|     } else if (nargc > ++optind) { | ||||
|       optarg = nargv[optind]; | ||||
|     } else { | ||||
|       /* option-argument absent */ | ||||
|       getopt_place = kGetoptEmsg; | ||||
|       if (*ostr == ':') return BADARG; | ||||
|       if (opterr) getopt_print_badch("option requires an argument"); | ||||
|       optglob.place = optglob.emsg; | ||||
|       if (*ostr == ':') { | ||||
|         return BADARG; | ||||
|       } | ||||
|       if (opterr) { | ||||
|         getopt_print("option requires an argument"); | ||||
|       } | ||||
|       return BADCH; | ||||
|     } | ||||
|     getopt_place = kGetoptEmsg; | ||||
|     optglob.place = optglob.emsg; | ||||
|     ++optind; | ||||
|   } | ||||
|   return optopt; /* return option letter */ | ||||
|  |  | |||
							
								
								
									
										10
									
								
								third_party/musl/crypt.internal.h
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										10
									
								
								third_party/musl/crypt.internal.h
									
										
									
									
										vendored
									
									
								
							|  | @ -4,11 +4,11 @@ | |||
| #if !(__ASSEMBLER__ + __LINKER__ + 0) | ||||
| COSMOPOLITAN_C_START_ | ||||
| 
 | ||||
| _Hide char *__crypt_des(const char *, const char *, char *); | ||||
| _Hide char *__crypt_md5(const char *, const char *, char *); | ||||
| _Hide char *__crypt_blowfish(const char *, const char *, char *); | ||||
| _Hide char *__crypt_sha256(const char *, const char *, char *); | ||||
| _Hide char *__crypt_sha512(const char *, const char *, char *); | ||||
| char *__crypt_des(const char *, const char *, char *); | ||||
| char *__crypt_md5(const char *, const char *, char *); | ||||
| char *__crypt_blowfish(const char *, const char *, char *); | ||||
| char *__crypt_sha256(const char *, const char *, char *); | ||||
| char *__crypt_sha512(const char *, const char *, char *); | ||||
| 
 | ||||
| COSMOPOLITAN_C_END_ | ||||
| #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ | ||||
|  |  | |||
							
								
								
									
										5
									
								
								third_party/nsync/panic.c
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										5
									
								
								third_party/nsync/panic.c
									
										
									
									
										vendored
									
									
								
							|  | @ -23,9 +23,6 @@ | |||
| 
 | ||||
| /* Aborts after printing the nul-terminated string s[]. */ | ||||
| void nsync_panic_ (const char *s) { | ||||
| 	char b[256], *p = b; | ||||
| 	p = stpcpy (p, "panic: "); | ||||
| 	p = stpcpy (p, s); | ||||
| 	write (2, b, p - b); | ||||
| 	tinyprint (2, "nsync panic: ", s, NULL); | ||||
| 	notpossible; | ||||
| } | ||||
|  |  | |||
|  | @ -6,7 +6,6 @@ PKGS += TOOL_BUILD | |||
| TOOL_BUILD_FILES := $(wildcard tool/build/*) | ||||
| TOOL_BUILD_SRCS = $(filter %.c,$(TOOL_BUILD_FILES)) | ||||
| TOOL_BUILD_HDRS = $(filter %.h,$(TOOL_BUILD_FILES)) | ||||
| TOOL_BUILD_CTESTS = $(filter %.ctest,$(TOOL_BUILD_FILES)) | ||||
| 
 | ||||
| TOOL_BUILD_BINS =					\
 | ||||
| 	$(TOOL_BUILD_COMS)				\
 | ||||
|  | @ -21,8 +20,6 @@ TOOL_BUILD_BINS =					\ | |||
| 	o/$(MODE)/tool/build/printf			\
 | ||||
| 	o/$(MODE)/tool/build/dd | ||||
| 
 | ||||
| TOOL_BUILD_CALCULATOR = o/$(MODE)/tool/build/calculator.com | ||||
| 
 | ||||
| TOOL_BUILD_OBJS =					\
 | ||||
| 	$(TOOL_BUILD_SRCS:%.c=o/$(MODE)/%.o) | ||||
| 
 | ||||
|  | @ -31,8 +28,7 @@ TOOL_BUILD_COMS =					\ | |||
| 
 | ||||
| TOOL_BUILD_CHECKS =					\
 | ||||
| 	$(TOOL_BUILD).pkg				\
 | ||||
| 	$(TOOL_BUILD_HDRS:%=o/$(MODE)/%.ok)		\
 | ||||
| 	$(TOOL_BUILD_CTESTS:%=o/$(MODE)/%.ok) | ||||
| 	$(TOOL_BUILD_HDRS:%=o/$(MODE)/%.ok) | ||||
| 
 | ||||
| TOOL_BUILD_DIRECTDEPS =					\
 | ||||
| 	DSP_CORE					\
 | ||||
|  | @ -80,12 +76,6 @@ o/$(MODE)/tool/build/build.pkg:				\ | |||
| 		$(TOOL_BUILD_OBJS)			\
 | ||||
| 		$(foreach x,$(TOOL_BUILD_DIRECTDEPS),$($(x)_A).pkg) | ||||
| 
 | ||||
| o/$(MODE)/%.ctest.ok:					\ | ||||
| 		%.ctest					\
 | ||||
| 		$(TOOL_BUILD_CALCULATOR)		\
 | ||||
| 		$(VM) | ||||
| 	@$(COMPILE) -AMKWIDES -wtT$@ $(VM) $(TOOL_BUILD_CALCULATOR) $< | ||||
| 
 | ||||
| o/$(MODE)/tool/build/%.com.dbg:				\ | ||||
| 		$(TOOL_BUILD_DEPS)			\
 | ||||
| 		o/$(MODE)/tool/build/build.pkg		\
 | ||||
|  |  | |||
|  | @ -1,760 +0,0 @@ | |||
| #if 0 | ||||
| /*─────────────────────────────────────────────────────────────────╗
 | ||||
| │ To the extent possible under law, Justine Tunney has waived      │ | ||||
| │ all copyright and related or neighboring rights to this file,    │ | ||||
| │ as it is written in the following disclaimers:                   │ | ||||
| │   • http://unlicense.org/                                        │
 | ||||
| │   • http://creativecommons.org/publicdomain/zero/1.0/            │
 | ||||
| ╚─────────────────────────────────────────────────────────────────*/ | ||||
| #endif | ||||
| #include "dsp/tty/tty.h" | ||||
| #include "libc/assert.h" | ||||
| #include "libc/calls/calls.h" | ||||
| #include "libc/errno.h" | ||||
| #include "libc/fmt/conv.h" | ||||
| #include "libc/fmt/fmt.h" | ||||
| #include "libc/fmt/itoa.h" | ||||
| #include "libc/intrin/bits.h" | ||||
| #include "libc/intrin/morton.h" | ||||
| #include "libc/intrin/popcnt.h" | ||||
| #include "libc/limits.h" | ||||
| #include "libc/log/color.internal.h" | ||||
| #include "libc/log/internal.h" | ||||
| #include "libc/log/log.h" | ||||
| #include "libc/macros.internal.h" | ||||
| #include "libc/math.h" | ||||
| #include "libc/mem/arraylist2.internal.h" | ||||
| #include "libc/mem/mem.h" | ||||
| #include "libc/runtime/runtime.h" | ||||
| #include "libc/stdio/rand.h" | ||||
| #include "libc/stdio/stdio.h" | ||||
| #include "libc/str/str.h" | ||||
| #include "libc/sysv/consts/ex.h" | ||||
| #include "libc/sysv/consts/exit.h" | ||||
| #include "libc/sysv/consts/sig.h" | ||||
| #include "libc/tinymath/emodl.h" | ||||
| #include "libc/x/xsigaction.h" | ||||
| #include "third_party/gdtoa/gdtoa.h" | ||||
| #include "third_party/getopt/getopt.internal.h" | ||||
| 
 | ||||
| #define INT     int128_t | ||||
| #define FLOAT   long double | ||||
| #define EPSILON 1e-16l | ||||
| 
 | ||||
| #define BANNER \ | ||||
|   "\
 | ||||
| Reverse Polish Notation Calculator\n\ | ||||
| Copyright 2020 Justine Alexandra Roberts Tunney\n\ | ||||
| This is fast portable lightweight software. You have the freedom to build\n\ | ||||
| software just like it painlessly. See http://github.com/jart/cosmopolitan\n\ | ||||
| " | ||||
| 
 | ||||
| #define USAGE1 \ | ||||
|   "SYNOPSIS\n\
 | ||||
| \n\ | ||||
|   Reverse Polish Notation Calculator\n\ | ||||
| \n\ | ||||
| USAGE\n\ | ||||
| \n" | ||||
| 
 | ||||
| #define USAGE2 \ | ||||
|   " [FLAGS] [FILE...]\n\
 | ||||
| \n\ | ||||
| FLAGS\n\ | ||||
| \n\ | ||||
|   -h\n\ | ||||
|   -?               shows this information\n\ | ||||
|   -i               force interactive mode\n\ | ||||
| \n\ | ||||
| KEYBOARD SHORTCUTS\n\ | ||||
| \n\ | ||||
|   CTRL-D           Closes standard input\n\ | ||||
|   CTRL-C           Sends SIGINT to program\n\ | ||||
|   CTRL-U           Redraw line\n\ | ||||
|   CTRL-L           Redraw display\n\ | ||||
| \n\ | ||||
| FUNCTIONS\n\ | ||||
| \n" | ||||
| 
 | ||||
| #define USAGE3 \ | ||||
|   "\n\
 | ||||
| EXAMPLES\n\ | ||||
| \n\ | ||||
|   calculator.com\n\ | ||||
|   40 2 +\n\ | ||||
|   42\n\ | ||||
| \n\ | ||||
|   echo '2 2 + . cr' | calculator.com\n\ | ||||
|   4\n\ | ||||
| \n\ | ||||
|   calculator.com <<EOF\n\ | ||||
|   true assert\n\ | ||||
|   -1 ~ 0 = assert\n\ | ||||
|   3 2 / 1.5 = assert\n\ | ||||
|   81 3 // 27 = assert\n\ | ||||
|   2 8 ** 256 = assert\n\ | ||||
|   pi cos -1 = assert\n\ | ||||
|   pi sqrt pi sqrt * pi - abs epsilon < assert\n\ | ||||
|   nan isnormal ! assert\n\ | ||||
|   0b1010101 0b0110101 ^ 0b1100000 = assert\n\ | ||||
|   0b1010101 popcnt 4 = assert\n\ | ||||
|   EOF\n\ | ||||
| \n\ | ||||
| CONTACT\n\ | ||||
| \n\ | ||||
|   Justine Tunney <jtunney@gmail.com>\n\ | ||||
|   https://github.com/jart/cosmooplitan\n\ | ||||
| \n\ | ||||
| " | ||||
| 
 | ||||
| #define CTRL(C)      ((C) ^ 0100) | ||||
| #define Fatal(...)   Log(kFatal, __VA_ARGS__) | ||||
| #define Warning(...) Log(kWarning, __VA_ARGS__) | ||||
| 
 | ||||
| enum Severity { | ||||
|   kFatal, | ||||
|   kWarning, | ||||
| }; | ||||
| 
 | ||||
| enum Exception { | ||||
|   kUnderflow = 1, | ||||
|   kDivideError, | ||||
| }; | ||||
| 
 | ||||
| struct Bytes { | ||||
|   size_t i, n; | ||||
|   char *p; | ||||
| }; | ||||
| 
 | ||||
| struct History { | ||||
|   size_t i, n; | ||||
|   struct Bytes *p; | ||||
| }; | ||||
| 
 | ||||
| struct Value { | ||||
|   enum Type { | ||||
|     kInt, | ||||
|     kFloat, | ||||
|   } t; | ||||
|   union { | ||||
|     INT i; | ||||
|     FLOAT f; | ||||
|   }; | ||||
| }; | ||||
| 
 | ||||
| struct Function { | ||||
|   const char sym[16]; | ||||
|   void (*fun)(void); | ||||
|   const char *doc; | ||||
| }; | ||||
| 
 | ||||
| jmp_buf thrower; | ||||
| const char *file; | ||||
| struct Bytes token; | ||||
| struct History history; | ||||
| struct Value stack[128]; | ||||
| int sp, comment, line, column, interactive; | ||||
| 
 | ||||
| uint32_t gray(uint32_t x) { | ||||
|   return x ^ (x >> 1); | ||||
| } | ||||
| 
 | ||||
| uint32_t ungray(uint32_t x) { | ||||
|   x ^= x >> 16; | ||||
|   x ^= x >> 8; | ||||
|   x ^= x >> 4; | ||||
|   x ^= x >> 2; | ||||
|   x ^= x >> 1; | ||||
|   return x; | ||||
| } | ||||
| 
 | ||||
| INT Popcnt(INT x) { | ||||
|   uint128_t word = x; | ||||
|   return popcnt(word >> 64) + popcnt(word); | ||||
| } | ||||
| 
 | ||||
| char *Repr(struct Value x) { | ||||
|   static char buf[64]; | ||||
|   if (x.t == kFloat) { | ||||
|     g_xfmt_p(buf, &x.f, 16, sizeof(buf), 0); | ||||
|   } else { | ||||
|     sprintf(buf, "%jjd", x.i); | ||||
|   } | ||||
|   return buf; | ||||
| } | ||||
| 
 | ||||
| char *ReprStack(void) { | ||||
|   int i, j, l; | ||||
|   char *s, *p; | ||||
|   static char buf[80]; | ||||
|   p = memset(buf, 0, sizeof(buf)); | ||||
|   for (i = 0; i < sp; ++i) { | ||||
|     s = Repr(stack[i]); | ||||
|     l = strlen(s); | ||||
|     if (p + l + 2 > buf + sizeof(buf)) break; | ||||
|     p = mempcpy(p, s, l); | ||||
|     *p++ = ' '; | ||||
|   } | ||||
|   return buf; | ||||
| } | ||||
| 
 | ||||
| void ShowStack(void) { | ||||
|   if (interactive) { | ||||
|     printf("\r\e[K"); | ||||
|     fputs(ReprStack(), stdout); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| void Cr(FILE *f) { | ||||
|   fputs(interactive || IsWindows() ? "\r\n" : "\n", f); | ||||
| } | ||||
| 
 | ||||
| void Log(enum Severity l, const char *fmt, ...) { | ||||
|   va_list va; | ||||
|   const char *severity[] = {"FATAL", "WARNING"}; | ||||
|   if (interactive) fflush(/* key triggering throw not echo'd yet */ stdout); | ||||
|   fprintf(stderr, "%s:%d:%d:%s: ", file, line + 1, column, severity[l & 1]); | ||||
|   va_start(va, fmt); | ||||
|   vfprintf(stderr, fmt, va); | ||||
|   va_end(va); | ||||
|   Cr(stderr); | ||||
|   if (l == kFatal) exit(EXIT_FAILURE); | ||||
|   if (interactive) ShowStack(); | ||||
| } | ||||
| 
 | ||||
| void __on_arithmetic_overflow(void) { | ||||
|   Warning("arithmetic overflow"); | ||||
| } | ||||
| 
 | ||||
| void OnDivideError(void) { | ||||
|   longjmp(thrower, kDivideError); | ||||
| } | ||||
| 
 | ||||
| struct Value Push(struct Value x) { | ||||
|   if (sp >= ARRAYLEN(stack)) Fatal("stack overflow"); | ||||
|   return (stack[sp++] = x); | ||||
| } | ||||
| 
 | ||||
| struct Value Pop(void) { | ||||
|   if (sp) { | ||||
|     return stack[--sp]; | ||||
|   } else { | ||||
|     longjmp(thrower, kUnderflow); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| INT Popi(void) { | ||||
|   struct Value x = Pop(); | ||||
|   return x.t == kInt ? x.i : x.f; | ||||
| } | ||||
| 
 | ||||
| void Pushi(INT i) { | ||||
|   struct Value x; | ||||
|   x.t = kInt; | ||||
|   x.i = i; | ||||
|   Push(x); | ||||
| } | ||||
| 
 | ||||
| FLOAT Popf(void) { | ||||
|   struct Value x = Pop(); | ||||
|   return x.t == kInt ? x.i : x.f; | ||||
| } | ||||
| 
 | ||||
| void Pushf(FLOAT f) { | ||||
|   struct Value x; | ||||
|   x.t = kFloat; | ||||
|   x.f = f; | ||||
|   Push(x); | ||||
| } | ||||
| 
 | ||||
| void OpDrop(void) { | ||||
|   Pop(); | ||||
| } | ||||
| 
 | ||||
| void OpDup(void) { | ||||
|   Push(Push(Pop())); | ||||
| } | ||||
| 
 | ||||
| void OpExit(void) { | ||||
|   exit(Popi()); | ||||
| } | ||||
| 
 | ||||
| void OpSrand(void) { | ||||
|   srand(Popi()); | ||||
| } | ||||
| 
 | ||||
| void OpEmit(void) { | ||||
|   fputwc(Popi(), stdout); | ||||
| } | ||||
| 
 | ||||
| void OpCr(void) { | ||||
|   Cr(stdout); | ||||
| } | ||||
| 
 | ||||
| void OpPrint(void) { | ||||
|   printf("%s ", Repr(Pop())); | ||||
| } | ||||
| 
 | ||||
| void OpComment(void) { | ||||
|   comment = true; | ||||
| } | ||||
| 
 | ||||
| void Glue0f(FLOAT fn(void)) { | ||||
|   Pushf(fn()); | ||||
| } | ||||
| 
 | ||||
| void Glue0i(INT fn(void)) { | ||||
|   Pushi(fn()); | ||||
| } | ||||
| 
 | ||||
| void Glue1f(FLOAT fn(FLOAT)) { | ||||
|   Pushf(fn(Popf())); | ||||
| } | ||||
| 
 | ||||
| void Glue1i(INT fn(INT)) { | ||||
|   Pushi(fn(Popi())); | ||||
| } | ||||
| 
 | ||||
| void OpSwap(void) { | ||||
|   struct Value a, b; | ||||
|   b = Pop(); | ||||
|   a = Pop(); | ||||
|   Push(b); | ||||
|   Push(a); | ||||
| } | ||||
| 
 | ||||
| void OpOver(void) { | ||||
|   struct Value a, b; | ||||
|   b = Pop(); | ||||
|   a = Pop(); | ||||
|   Push(a); | ||||
|   Push(b); | ||||
|   Push(a); | ||||
| } | ||||
| 
 | ||||
| void OpKey(void) { | ||||
|   wint_t c; | ||||
|   ttyraw(kTtyCursor | kTtySigs | kTtyLfToCrLf); | ||||
|   c = fgetwc(stdin); | ||||
|   ttyraw(-1); | ||||
|   if (c != -1) Pushi(c); | ||||
| } | ||||
| 
 | ||||
| void OpAssert(void) { | ||||
|   if (!Popi()) Fatal("assert failed"); | ||||
| } | ||||
| 
 | ||||
| void OpExpect(void) { | ||||
|   if (!Popi()) Warning("expect failed"); | ||||
| } | ||||
| 
 | ||||
| void OpMeminfo(void) { | ||||
|   OpCr(); | ||||
|   OpCr(); | ||||
|   fflush(stdout); | ||||
|   _meminfo(fileno(stdout)); | ||||
| } | ||||
| 
 | ||||
| void Glue2f(FLOAT fn(FLOAT, FLOAT)) { | ||||
|   FLOAT x, y; | ||||
|   y = Popf(); | ||||
|   x = Popf(); | ||||
|   Pushf(fn(x, y)); | ||||
| } | ||||
| 
 | ||||
| void Glue2i(INT fn(INT, INT)) { | ||||
|   INT x, y; | ||||
|   y = Popi(); | ||||
|   x = Popi(); | ||||
|   Pushi(fn(x, y)); | ||||
| } | ||||
| 
 | ||||
| void Glue1g(FLOAT fnf(FLOAT), INT fni(INT)) { | ||||
|   struct Value x; | ||||
|   x = Pop(); | ||||
|   switch (x.t) { | ||||
|     case kInt: | ||||
|       Pushi(fni(x.i)); | ||||
|       break; | ||||
|     case kFloat: | ||||
|       Pushf(fnf(x.f)); | ||||
|       break; | ||||
|     default: | ||||
|       Warning("type mismatch"); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| void Glue2g(FLOAT fnf(FLOAT, FLOAT), INT fni(INT, INT)) { | ||||
|   struct Value x, y; | ||||
|   y = Pop(); | ||||
|   x = Pop(); | ||||
|   if (x.t == kInt && y.t == kInt) { | ||||
|     Pushi(fni(x.i, y.i)); | ||||
|   } else if (x.t == kFloat && y.t == kFloat) { | ||||
|     Pushf(fnf(x.f, y.f)); | ||||
|   } else if (x.t == kInt && y.t == kFloat) { | ||||
|     Pushf(fnf(x.i, y.f)); | ||||
|   } else if (x.t == kFloat && y.t == kInt) { | ||||
|     Pushf(fnf(x.f, y.i)); | ||||
|   } else { | ||||
|     Warning("type mismatch"); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| #define LB                  { | ||||
| #define RB                  } | ||||
| #define SEMI                ; | ||||
| #define FNTYPEi             INT | ||||
| #define FNTYPEf             FLOAT | ||||
| #define FORM(F)             LB F SEMI RB | ||||
| #define FNPL0(T)            void | ||||
| #define FNPL1(T)            FNTYPE##T x | ||||
| #define FNPL2(T)            FNTYPE##T x, FNTYPE##T y | ||||
| #define FNDEF(A, T, S, C)   FNTYPE##T Fn##S##T(FNPL##A(T)) FORM(return C) | ||||
| #define FNDEFf(A, S, C)     FNDEF(A, f, S, C) | ||||
| #define FNDEFi(A, S, C)     FNDEF(A, i, S, C) | ||||
| #define FNDEFg(A, S, C)     FNDEF(A, f, S, C) FNDEF(A, i, S, C) | ||||
| #define OPDEF(A, T, S, C)   void Op##S(void) FORM(Glue##A##T(Fn##S##T)) | ||||
| #define OPDEFf(A, S, C)     OPDEF(A, f, S, C) | ||||
| #define OPDEFi(A, S, C)     OPDEF(A, i, S, C) | ||||
| #define OPDEFg(A, S, C)     void Op##S(void) FORM(Glue##A##g(Fn##S##f, Fn##S##i)) | ||||
| #define M(A, T, N, S, C, D) FNDEF##T(A, S, C) OPDEF##T(A, S, C) | ||||
| #include "tool/build/calculator.inc" | ||||
| #undef M | ||||
| 
 | ||||
| const struct Function kFunctions[] = { | ||||
|     {".", OpPrint, "pops prints value repr"}, | ||||
|     {"#", OpComment, "line comment"}, | ||||
| #define M(A, T, N, S, C, D) {N, Op##S, D}, | ||||
| #include "tool/build/calculator.inc" | ||||
| #undef M | ||||
|     {"dup", OpDup, "pushes copy of last item on stack"}, | ||||
|     {"drop", OpDrop, "pops and discards"}, | ||||
|     {"swap", OpSwap, "swaps last two items on stack"}, | ||||
|     {"over", OpOver, "pushes second item on stack"}, | ||||
|     {"cr", OpCr, "prints newline"}, | ||||
|     {"key", OpKey, "reads and pushes unicode character from keyboard"}, | ||||
|     {"emit", OpEmit, "pops and writes unicode character to output"}, | ||||
|     {"assert", OpAssert, "crashes if top of stack isn't nonzero"}, | ||||
|     {"expect", OpExpect, "prints warning if top of stack isn't nonzero"}, | ||||
|     {"meminfo", OpMeminfo, "prints memory mappings"}, | ||||
|     {"exit", OpExit, "exits program with status"}, | ||||
| }; | ||||
| 
 | ||||
| bool CallFunction(const char *sym) { | ||||
|   int i; | ||||
|   char s[16]; | ||||
|   strncpy(s, sym, sizeof(s)); | ||||
|   for (i = 0; i < ARRAYLEN(kFunctions); ++i) { | ||||
|     if (memcmp(kFunctions[i].sym, s, sizeof(s)) == 0) { | ||||
|       kFunctions[i].fun(); | ||||
|       return true; | ||||
|     } | ||||
|   } | ||||
|   return false; | ||||
| } | ||||
| 
 | ||||
| volatile const char *literal_; | ||||
| bool ConsumeLiteral(const char *literal) { | ||||
|   bool r; | ||||
|   char *e; | ||||
|   struct Value x; | ||||
|   literal_ = literal; | ||||
|   errno = 0; | ||||
|   x.t = kInt; | ||||
|   x.i = strtoi128(literal, &e, 0); | ||||
|   if (*e) { | ||||
|     x.t = kFloat; | ||||
|     x.f = strtod(literal, &e); | ||||
|     r = !(!e || *e); | ||||
|   } else if (errno == ERANGE) { | ||||
|     r = false; | ||||
|   } else { | ||||
|     r = true; | ||||
|   } | ||||
|   Push(x); | ||||
|   return r; | ||||
| } | ||||
| 
 | ||||
| void ConsumeToken(void) { | ||||
|   enum Exception ex; | ||||
|   if (!token.i) return; | ||||
|   token.p[token.i] = 0; | ||||
|   token.i = 0; | ||||
|   if (history.i) history.p[history.i - 1].i = 0; | ||||
|   if (comment) return; | ||||
|   if (_startswith(token.p, "#!")) return; | ||||
|   switch (setjmp(thrower)) { | ||||
|     default: | ||||
|       if (CallFunction(token.p)) return; | ||||
|       if (ConsumeLiteral(token.p)) return; | ||||
|       Warning("bad token: %`'s", token.p); | ||||
|       break; | ||||
|     case kUnderflow: | ||||
|       Warning("stack underflow"); | ||||
|       break; | ||||
|     case kDivideError: | ||||
|       Warning("divide error"); | ||||
|       break; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| void CleanupRepl(void) { | ||||
|   if (sp && interactive) { | ||||
|     Cr(stdout); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| void AppendByte(struct Bytes *a, char b) { | ||||
|   APPEND(&a->p, &a->i, &a->n, &b); | ||||
| } | ||||
| 
 | ||||
| void AppendHistory(void) { | ||||
|   struct Bytes line; | ||||
|   if (interactive) { | ||||
|     bzero(&line, sizeof(line)); | ||||
|     APPEND(&history.p, &history.i, &history.n, &line); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| void AppendLine(char b) { | ||||
|   if (interactive) { | ||||
|     if (!history.i) AppendHistory(); | ||||
|     AppendByte(&history.p[history.i - 1], b); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| void Echo(int c) { | ||||
|   if (interactive) { | ||||
|     fputc(c, stdout); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| void Backspace(int c) { | ||||
|   struct Bytes *line; | ||||
|   if (interactive) { | ||||
|     if (history.i) { | ||||
|       line = &history.p[history.i - 1]; | ||||
|       if (line->i && token.i) { | ||||
|         do { | ||||
|           line->i--; | ||||
|           token.i--; | ||||
|         } while (line->i && token.i && (line->p[line->i] & 0x80)); | ||||
|         fputs("\e[D \e[D", stdout); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| void NewLine(void) { | ||||
|   line++; | ||||
|   column = 0; | ||||
|   comment = false; | ||||
|   if (interactive) { | ||||
|     Cr(stdout); | ||||
|     AppendHistory(); | ||||
|     ShowStack(); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| void KillLine(void) { | ||||
|   if (interactive) { | ||||
|     if (history.i) { | ||||
|       history.p[history.i - 1].i--; | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| void ClearLine(void) { | ||||
|   if (interactive) { | ||||
|     if (token.i) sp = 0; | ||||
|     ShowStack(); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| void RedrawDisplay(void) { | ||||
|   int i; | ||||
|   struct Bytes *line; | ||||
|   if (interactive) { | ||||
|     printf("\e[H\e[2J%s", BANNER); | ||||
|     ShowStack(); | ||||
|     if (history.i) { | ||||
|       line = &history.p[history.i - 1]; | ||||
|       for (i = 0; i < line->i; ++i) { | ||||
|         fputc(line->p[i], stdout); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| void GotoStartOfLine(void) { | ||||
|   if (interactive) { | ||||
|     printf("\r"); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| void GotoEndOfLine(void) { | ||||
| } | ||||
| 
 | ||||
| void GotoPrevLine(void) { | ||||
| } | ||||
| 
 | ||||
| void GotoNextLine(void) { | ||||
| } | ||||
| 
 | ||||
| void GotoPrevChar(void) { | ||||
| } | ||||
| 
 | ||||
| void GotoNextChar(void) { | ||||
| } | ||||
| 
 | ||||
| void Calculator(FILE *f) { | ||||
|   int c; | ||||
|   while (!feof(f)) { | ||||
|     switch ((c = getc(f))) { | ||||
|       case -1: | ||||
|       case CTRL('D'): | ||||
|         goto Done; | ||||
|       case CTRL('@'): | ||||
|         break; | ||||
|       case ' ': | ||||
|         column++; | ||||
|         Echo(c); | ||||
|         AppendLine(c); | ||||
|         ConsumeToken(); | ||||
|         break; | ||||
|       case '\t': | ||||
|         column = ROUNDUP(column, 8); | ||||
|         Echo(c); | ||||
|         AppendLine(c); | ||||
|         ConsumeToken(); | ||||
|         break; | ||||
|       case '\r': | ||||
|       case '\n': | ||||
|         ConsumeToken(); | ||||
|         NewLine(); | ||||
|         break; | ||||
|       case CTRL('A'): | ||||
|         GotoStartOfLine(); | ||||
|         break; | ||||
|       case CTRL('E'): | ||||
|         GotoEndOfLine(); | ||||
|         break; | ||||
|       case CTRL('P'): | ||||
|         GotoPrevLine(); | ||||
|         break; | ||||
|       case CTRL('N'): | ||||
|         GotoNextLine(); | ||||
|         break; | ||||
|       case CTRL('B'): | ||||
|         GotoPrevChar(); | ||||
|         break; | ||||
|       case CTRL('F'): | ||||
|         GotoNextChar(); | ||||
|         break; | ||||
|       case CTRL('L'): | ||||
|         RedrawDisplay(); | ||||
|         break; | ||||
|       case CTRL('U'): | ||||
|         ClearLine(); | ||||
|         break; | ||||
|       case CTRL('K'): | ||||
|         KillLine(); | ||||
|         break; | ||||
|       case CTRL('?'): | ||||
|       case CTRL('H'): | ||||
|         Backspace(c); | ||||
|         break; | ||||
|       default: | ||||
|         column++; | ||||
|         /* fallthrough */ | ||||
|       case 0x80 ... 0xff: | ||||
|         Echo(c); | ||||
|         AppendLine(c); | ||||
|         AppendByte(&token, c); | ||||
|         break; | ||||
|     } | ||||
|     fflush(/* needed b/c this is event loop */ stdout); | ||||
|   } | ||||
| Done: | ||||
|   CleanupRepl(); | ||||
| } | ||||
| 
 | ||||
| int Calculate(const char *path) { | ||||
|   FILE *f; | ||||
|   file = path; | ||||
|   line = column = 0; | ||||
|   if (!(f = fopen(file, "r"))) Fatal("file not found: %s", file); | ||||
|   Calculator(f); | ||||
|   return fclose(f); | ||||
| } | ||||
| 
 | ||||
| void CleanupTerminal(void) { | ||||
|   ttyraw(-1); | ||||
| } | ||||
| 
 | ||||
| void StartInteractive(void) { | ||||
|   if (!interactive && !__nocolor && isatty(fileno(stdin)) && | ||||
|       isatty(fileno(stdout)) && !__nocolor) { | ||||
|     interactive = true; | ||||
|   } | ||||
|   errno = 0; | ||||
|   if (interactive) { | ||||
|     fputs(BANNER, stdout); | ||||
|     fflush(/* needed b/c entering tty mode */ stdout); | ||||
|     ttyraw(kTtyCursor | kTtySigs); | ||||
|     atexit(CleanupTerminal); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| void PrintUsage(int rc, FILE *f) { | ||||
|   char c; | ||||
|   int i, j; | ||||
|   fprintf(f, "%s  %s%s", USAGE1, program_invocation_name, USAGE2); | ||||
|   for (i = 0; i < ARRAYLEN(kFunctions); ++i) { | ||||
|     fputs("  ", f); | ||||
|     for (j = 0; j < ARRAYLEN(kFunctions[i].sym); ++j) { | ||||
|       c = kFunctions[i].sym[j]; | ||||
|       fputc(c ? c : ' ', f); | ||||
|     } | ||||
|     fprintf(f, " %s\n", kFunctions[i].doc); | ||||
|   } | ||||
|   fputs(USAGE3, f); | ||||
|   exit(rc); | ||||
| } | ||||
| 
 | ||||
| void GetOpts(int argc, char *argv[]) { | ||||
|   int opt; | ||||
|   while ((opt = getopt(argc, argv, "?hi")) != -1) { | ||||
|     switch (opt) { | ||||
|       case 'i': | ||||
|         interactive = true; | ||||
|         break; | ||||
|       case 'h': | ||||
|       case '?': | ||||
|         PrintUsage(EXIT_SUCCESS, stdout); | ||||
|       default: | ||||
|         PrintUsage(EX_USAGE, stderr); | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| int main(int argc, char *argv[]) { | ||||
|   int i, rc; | ||||
|   ShowCrashReports(); | ||||
|   GetOpts(argc, argv); | ||||
|   xsigaction(SIGFPE, OnDivideError, 0, 0, 0); | ||||
|   if (optind == argc) { | ||||
|     file = "/dev/stdin"; | ||||
|     StartInteractive(); | ||||
|     Calculator(stdin); | ||||
|     return fclose(stdin); | ||||
|   } else { | ||||
|     for (i = optind; i < argc; ++i) { | ||||
|       if (Calculate(argv[i]) == -1) { | ||||
|         return -1; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|   return 0; | ||||
| } | ||||
|  | @ -1,91 +0,0 @@ | |||
| # INTEGER | ||||
| 2 3 + 5 = assert | ||||
| 3 2 + 5 = assert | ||||
| 5 2 - 3 = assert | ||||
| 2 5 - -3 = assert | ||||
| 81 3 / 27 = assert | ||||
| 81 3 // 27 = assert | ||||
| 2 8 ** 256 = assert | ||||
| 17 10 % 7 = assert | ||||
| 17 10 fmod 7 = assert | ||||
| 
 | ||||
| # FLOATING POINT | ||||
| .1 .2 + .3 - abs epsilon < assert | ||||
| pi sqrt pi sqrt * pi - abs epsilon < assert | ||||
| 3 2 / 1.5 = assert | ||||
| pi pi = assert | ||||
| pi cos -1 = assert | ||||
| pi 2 / sin 1 = assert | ||||
| 81 3 / 27 = assert | ||||
| inf isinf assert | ||||
| inf isnormal ! assert | ||||
| nan isnormal ! assert | ||||
| 1 0 / isnormal ! assert | ||||
| 0 signbit ! assert | ||||
| -.5 round -1 = assert | ||||
| -.5 floor -1 = assert | ||||
| -.5 rint dup 0 = assert signbit assert | ||||
| -.5 nearbyint dup 0 = assert signbit assert | ||||
| -.5 ceil dup 0 = assert signbit assert | ||||
| -.5 trunc dup 0 = assert signbit assert | ||||
| 0 0 / dup isnan assert signbit assert   # is this right? | ||||
| 1 0 / dup isinf assert signbit ! assert # is this right? | ||||
|  nan  nan != assert                     # is this right? | ||||
| # -nan -nan != assert                   # is this right? | ||||
|  inf  inf  = assert                     # is this right? | ||||
| -inf -inf  = assert                     # is this right? | ||||
| 
 | ||||
| # BIT ARITHMETIC | ||||
| -1 ~ 0 = assert | ||||
| 0 0x7fffffffffffffffffffffffffffffff - -0x7fffffffffffffffffffffffffffffff = assert | ||||
| 0b1010101 popcnt 4 = assert | ||||
| 0b1010101 0b0110101 ^ 0b1100000 = assert | ||||
| 0b1010101 0b0110101 | 0b1110101 = assert | ||||
| 0b1010101 0b0110101 & 0b0010101 = assert | ||||
| 0b1010101 1 >> 0b000101010 = assert | ||||
| 0b1010101 2 >> 0b000010101 = assert | ||||
| 0b1010101 1 << 0b010101010 = assert | ||||
| 0b1010101 2 << 0b101010100 = assert | ||||
| 
 | ||||
| # BOOLEAN | ||||
| true assert | ||||
| false ! assert | ||||
| true ! ! assert | ||||
| true true && assert | ||||
| true false && ! assert | ||||
| false true && ! assert | ||||
| true false && ! assert | ||||
| false true && ! assert | ||||
| true true || assert | ||||
| false true || assert | ||||
| true false || assert | ||||
| false false || ! assert | ||||
| 4 5 < assert | ||||
| 5 4 < ! assert | ||||
| -5 4 < assert | ||||
| 5 5 < ! assert | ||||
| 5 5 <= assert | ||||
| 5 4 > assert | ||||
| 4 5 > ! assert | ||||
| 4 -5 > assert | ||||
| 5 5 > ! assert | ||||
| 5 5 >= assert | ||||
| 
 | ||||
| # MISC | ||||
| 1 abs 1 = assert | ||||
| -1 abs 1 = assert | ||||
| -1 1 max 1 = assert | ||||
| 1 -1 max 1 = assert | ||||
| 1 2 max 2 = assert | ||||
| -1 1 min -1 = assert | ||||
| 1 -1 min -1 = assert | ||||
| 1 2 min 1 = assert | ||||
| rand64 rand64 rand64 rand64 != != && assert | ||||
| 
 | ||||
| # HEX SIGN | ||||
|  -0x80000000 -2147483648 = assert | ||||
|   0x80000000  2147483648 = assert | ||||
|   0x80000001  2147483649 = assert | ||||
|   0xffffffff  4294967295 = assert | ||||
|  0x100000000  4294967296 = assert | ||||
| -0x100000000 -4294967296 = assert | ||||
|  | @ -1,100 +0,0 @@ | |||
| M(2, g, "+", Add, x + y, "add") | ||||
| M(2, g, "-", Sub, x - y, "sub") | ||||
| M(2, g, "*", Mul, x *y, "multiply") | ||||
| M(2, f, "/", Div, x / y, "division") | ||||
| M(2, i, "%", Rem, x % y, "integer remainder") | ||||
| M(2, i, "//", Idiv, x / y, "integer division") | ||||
| M(2, g, "**", Expo, powl(x, y), "exponentiation") | ||||
| 
 | ||||
| M(1, i, "~", Not, ~x, "bitwise not") | ||||
| M(2, i, "^", Xor, x ^ y, "bitwise xor") | ||||
| M(2, i, "|", Or, x | y, "bitwise or") | ||||
| M(2, i, "&", And, x &y, "bitwise and") | ||||
| M(2, i, ">>", Shr, x >> y, "shift right") | ||||
| M(2, i, "<<", Shl, x << y, "shift left") | ||||
| 
 | ||||
| M(1, i, "!", LogicalNot, !x, "logical not") | ||||
| M(2, i, "||", LogicalOr, x || y, "logical or") | ||||
| M(2, i, "&&", LogicalAnd, x &&y, "logical and") | ||||
| 
 | ||||
| M(2, g, "=", Equal1, x == y, "equal to") | ||||
| M(2, g, "!=", Notequal, x != y, "not equal to") | ||||
| M(2, g, "<", LessThan, x < y, "less than") | ||||
| M(2, g, ">", GreaterThan, x > y, "greater than") | ||||
| M(2, g, "<=", LessThanEqual, x <= y, "less than or equal to") | ||||
| M(2, g, ">=", GreaterThanEqual, x >= y, "greater than or equal to") | ||||
| 
 | ||||
| M(1, i, "gray", Gray, gray(x), "gray coding") | ||||
| M(1, i, "ungray", Ungray, ungray(x), "inverse gray coding") | ||||
| M(1, i, "popcnt", Popcnt, Popcnt(x), "count bits") | ||||
| 
 | ||||
| M(1, g, "abs", Abs, fabsl(x), "absolute value") | ||||
| M(2, g, "min", Min, fminl(x, y), "pops two values and pushes minimum") | ||||
| M(2, g, "max", Max, fmaxl(x, y), "pops two values and pushes maximum") | ||||
| 
 | ||||
| M(2, g, "fmod", Fmod, fmodl(x, y), "trunc remainder") | ||||
| M(2, g, "emod", Emod, emodl(x, y), "euclidean remainder") | ||||
| M(2, g, "remainder", Remainder, remainderl(x, y), "rint remainder") | ||||
| M(2, g, "hypot", Hypot, hypotl(x, y), "euclidean distance") | ||||
| 
 | ||||
| M(0, i, "false", False, 0, "0") | ||||
| M(0, i, "true", True, 1, "1") | ||||
| M(0, i, "intmin", IntMin, INT128_MIN, "native integer minimum") | ||||
| M(0, i, "intmax", IntMax, INT128_MAX, "native integer maximum") | ||||
| M(0, f, "e", Euler, M_E, "𝑒") | ||||
| M(0, f, "pi", Fldpi, M_PI, "π") | ||||
| M(0, f, "epsilon", Epsilon, EPSILON, "ɛ") | ||||
| M(0, f, "inf", Inf, INFINITY, "∞") | ||||
| M(0, f, "nan", Nan, NAN, "NAN") | ||||
| M(0, f, "-0", Negzero, -0., "wut") | ||||
| M(0, f, "l2t", Fldl2t, M_LOG2_10, "log₂10") | ||||
| M(0, f, "lg2", Fldlg2, M_LOG10_2, "log₁₀2") | ||||
| M(0, f, "ln2", Fldln2, M_LN2, "logₑ2") | ||||
| M(0, f, "l2e", Fldl2e, M_LOG2E, "logₑ10") | ||||
| M(2, f, "nextafter", Nextafter, nextafterl(x, y), "next ulp") | ||||
| M(1, f, "significand", Significand, significandl(x), "mantissa") | ||||
| 
 | ||||
| M(1, f, "sqrt", Sqrt, sqrtl(x), "√𝑥") | ||||
| M(1, f, "exp", Exp, expl(x), "𝑒ˣ") | ||||
| M(1, g, "expm1", Expm1, expm1l(x), "𝑒ˣ-1") | ||||
| M(1, g, "exp2", Exp2, exp2l(x), "2ˣ") | ||||
| M(1, g, "exp10", Exp10, exp10l(x), "10ˣ") | ||||
| M(2, g, "ldexp", Ldexp, ldexpl(x, y), "𝑥×2ʸ") | ||||
| 
 | ||||
| M(1, f, "log", Log, logl(x), "logₑ𝑥") | ||||
| M(1, g, "log2", Log2, log2l(x), "log₂𝑥") | ||||
| M(1, g, "log10", Log10, log10l(x), "log₁₀𝑥") | ||||
| M(1, g, "ilogb", Ilogb, ilogbl(x), "exponent") | ||||
| 
 | ||||
| M(1, g, "sin", Sin, sinl(x), "sine") | ||||
| M(1, g, "cos", Cos, cosl(x), "cosine") | ||||
| M(1, g, "tan", Tan, tanl(x), "tangent") | ||||
| M(1, g, "asin", Asin, asinl(x), "arcsine") | ||||
| M(1, g, "acos", Acos, acosl(x), "arccosine") | ||||
| M(1, g, "atan", Atan, atanl(x), "arctangent") | ||||
| M(2, g, "atan2", Atan2, atan2l(x, y), "arctangent of 𝑥/𝑦") | ||||
| 
 | ||||
| M(1, g, "sinh", Sinh, sinhl(x), "hyperbolic sine") | ||||
| M(1, g, "cosh", Cosh, coshl(x), "hyperbolic cosine") | ||||
| M(1, g, "tanh", Tanh, tanhl(x), "hyperbolic tangent") | ||||
| M(1, g, "asinh", Asinh, asinhl(x), "hyperbolic arcsine") | ||||
| M(1, g, "acosh", Acosh, acoshl(x), "hyperbolic arccosine") | ||||
| M(1, g, "atanh", Atanh, atanhl(x), "hyperbolic arctangent") | ||||
| 
 | ||||
| M(1, g, "round", Round, roundl(x), "round away from zero") | ||||
| M(1, g, "trunc", Trunc, truncl(x), "round towards zero") | ||||
| M(1, g, "rint", Rint, rintl(x), "round to even") | ||||
| M(1, g, "nearbyint", Nearbyint, nearbyintl(x), "round to nearest integer") | ||||
| M(1, g, "ceil", Ceil, ceill(x), "smallest integral not less than 𝑥") | ||||
| M(1, g, "floor", Floor, floorl(x), "largest integral not greater than 𝑥") | ||||
| 
 | ||||
| M(1, f, "isnan", Isnan, isnan(x), "returns true if 𝑥=NAN") | ||||
| M(1, f, "isinf", Isinf, isinf(x), "returns true if 𝑥=INFINITY") | ||||
| M(1, f, "signbit", Signbit, signbit(x), "clears all bits but sign bit") | ||||
| M(1, f, "isfinite", Isfinite, isfinite(x), "returns true if 𝑥≠INFINITY") | ||||
| M(1, f, "isnormal", Isnormal, isnormal(x), "returns true if not denormal") | ||||
| M(1, f, "fpclassify", Fpclassify, fpclassify(x), | ||||
|   "nan=0,inf=1,zero=2,subnorm=3,normal=4") | ||||
| 
 | ||||
| M(0, i, "rand", Rand, rand(), "deterministic random number") | ||||
| M(0, i, "rand64", _Rand64, _rand64(), "64-bit random number") | ||||
|  | @ -21,6 +21,7 @@ | |||
| #include "libc/fmt/conv.h" | ||||
| #include "libc/fmt/magnumstrs.internal.h" | ||||
| #include "libc/runtime/runtime.h" | ||||
| #include "libc/stdio/stdio.h" | ||||
| #include "libc/str/str.h" | ||||
| #include "third_party/getopt/getopt.internal.h" | ||||
| 
 | ||||
|  | @ -33,42 +34,21 @@ SYNOPSIS\n\ | |||
| \n\ | ||||
| FLAGS\n\ | ||||
| \n\ | ||||
|   -?\n\ | ||||
|   -h      help\n\ | ||||
| \n" | ||||
| 
 | ||||
| const char *prog; | ||||
| 
 | ||||
| nullterminated() static void Print(int fd, const char *s, ...) { | ||||
|   va_list va; | ||||
|   char buf[2048]; | ||||
|   va_start(va, s); | ||||
|   buf[0] = 0; | ||||
|   do { | ||||
|     strlcat(buf, s, sizeof(buf)); | ||||
|   } while ((s = va_arg(va, const char *))); | ||||
|   write(fd, buf, strlen(buf)); | ||||
|   va_end(va); | ||||
| } | ||||
| 
 | ||||
| static wontreturn void SysExit(const char *path, const char *func) { | ||||
|   const char *errstr; | ||||
|   if (!(errstr = _strerdoc(errno))) errstr = "EUNKNOWN"; | ||||
|   Print(2, path, ": ", func, " failed with ", errstr, "\n", NULL); | ||||
|   exit(1); | ||||
| } | ||||
| 
 | ||||
| static wontreturn void PrintUsage(int fd, int rc) { | ||||
|   Print(fd, "USAGE\n\n  ", program_invocation_name, USAGE, NULL); | ||||
|   tinyprint(fd, "USAGE\n\n  ", prog, USAGE, NULL); | ||||
|   exit(rc); | ||||
| } | ||||
| 
 | ||||
| static void GetOpts(int argc, char *argv[]) { | ||||
|   int opt; | ||||
|   while ((opt = getopt(argc, argv, "?h")) != -1) { | ||||
|   while ((opt = getopt(argc, argv, "h")) != -1) { | ||||
|     switch (opt) { | ||||
|       case 'h': | ||||
|       case '?': | ||||
|         PrintUsage(1, 0); | ||||
|       default: | ||||
|         PrintUsage(2, 1); | ||||
|  | @ -79,18 +59,22 @@ static void GetOpts(int argc, char *argv[]) { | |||
| int main(int argc, char *argv[]) { | ||||
|   int i, mode; | ||||
|   char buf[PATH_MAX], *endptr; | ||||
|   prog = argv[0]; | ||||
|   if (!prog) prog = "chmod"; | ||||
|   GetOpts(argc, argv); | ||||
|   if (argc - optind < 2) { | ||||
|     PrintUsage(2, 1); | ||||
|     tinyprint(2, prog, ": missing operand\n", NULL); | ||||
|     exit(1); | ||||
|   } | ||||
|   mode = strtol(argv[optind], &endptr, 8) & 07777; | ||||
|   if (*endptr) { | ||||
|     Print(2, "chmod: invalid mode octal\n", NULL); | ||||
|     tinyprint(2, prog, ": invalid mode octal\n", NULL); | ||||
|     exit(1); | ||||
|   } | ||||
|   for (i = optind + 1; i < argc; ++i) { | ||||
|     if (chmod(argv[i], mode) == -1) { | ||||
|       SysExit(argv[i], "chmod"); | ||||
|       perror(argv[i]); | ||||
|       exit(1); | ||||
|     } | ||||
|   } | ||||
|   return 0; | ||||
|  |  | |||
|  | @ -24,6 +24,7 @@ | |||
| #include "libc/fmt/fmt.h" | ||||
| #include "libc/fmt/libgen.h" | ||||
| #include "libc/fmt/magnumstrs.internal.h" | ||||
| #include "libc/intrin/kprintf.h" | ||||
| #include "libc/mem/gc.h" | ||||
| #include "libc/runtime/runtime.h" | ||||
| #include "libc/stdio/stdio.h" | ||||
|  | @ -91,16 +92,14 @@ bool IsSymlink(const char *path) { | |||
|   return res; | ||||
| } | ||||
| 
 | ||||
| wontreturn void PrintUsage(int rc, FILE *f) { | ||||
|   fputs("usage: ", f); | ||||
|   fputs(prog, f); | ||||
|   fputs(USAGE, f); | ||||
| wontreturn void PrintUsage(int rc, int fd) { | ||||
|   tinyprint(fd, "USAGE\n\n  ", prog, USAGE, NULL); | ||||
|   exit(rc); | ||||
| } | ||||
| 
 | ||||
| void GetOpts(int argc, char *argv[]) { | ||||
|   int opt; | ||||
|   while ((opt = getopt(argc, argv, "?hfnaprR")) != -1) { | ||||
|   while ((opt = getopt(argc, argv, "hfnaprR")) != -1) { | ||||
|     switch (opt) { | ||||
|       case 'f': | ||||
|         force = true; | ||||
|  | @ -118,10 +117,9 @@ void GetOpts(int argc, char *argv[]) { | |||
|         flags |= COPYFILE_PRESERVE_TIMESTAMPS; | ||||
|         break; | ||||
|       case 'h': | ||||
|       case '?': | ||||
|         PrintUsage(EXIT_SUCCESS, stdout); | ||||
|         PrintUsage(0, 1); | ||||
|       default: | ||||
|         PrintUsage(EX_USAGE, stderr); | ||||
|         PrintUsage(1, 2); | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | @ -146,8 +144,7 @@ int Visit(const char *fpath, const struct stat *sb, int tflag, | |||
|       Cp(srcfile, dstfile); | ||||
|       return 0; | ||||
|     default: | ||||
|       fputs(fpath, stderr); | ||||
|       fputs(": can't handle file type\n", stderr); | ||||
|       tinyprint(2, fpath, ": bad file type\n", NULL); | ||||
|       exit(1); | ||||
|   } | ||||
| } | ||||
|  | @ -157,7 +154,7 @@ char *Join(const char *a, const char *b) { | |||
|   n = strlen(a); | ||||
|   m = strlen(b); | ||||
|   if (n + 1 + m + 1 > sizeof(dstfile)) { | ||||
|     fputs("error: cp: path too long\n", stderr); | ||||
|     tinyprint(2, prog, ": path too long\n", NULL); | ||||
|     exit(1); | ||||
|   } | ||||
|   stpcpy(stpcpy(stpcpy(dstfile, a), "/"), b); | ||||
|  | @ -191,8 +188,7 @@ void Cp(char *src, char *dst) { | |||
|   basename(dst); | ||||
|   if (IsDirectory(src)) { | ||||
|     if (!recursive) { | ||||
|       fputs(prog, stderr); | ||||
|       fputs(": won't copy directory without -r flag.\n", stderr); | ||||
|       tinyprint(2, prog, ": won't copy directory without -r flag\n", NULL); | ||||
|       exit(1); | ||||
|     } | ||||
|     strcpy(dstdir, dst); | ||||
|  | @ -208,10 +204,7 @@ void Cp(char *src, char *dst) { | |||
|       strcpy(srcdir, ""); | ||||
|     } | ||||
|     if (nftw(src, Visit, 20, 0) == -1) { | ||||
|       fputs(prog, stderr); | ||||
|       fputs(": nftw failed: ", stderr); | ||||
|       fputs(_strerdoc(errno), stderr); | ||||
|       fputs("\n", stderr); | ||||
|       perror(src); | ||||
|       exit(1); | ||||
|     } | ||||
|     return; | ||||
|  | @ -219,37 +212,49 @@ void Cp(char *src, char *dst) { | |||
|   if (IsDirectory(dst)) { | ||||
|     dst = Join(dst, basename(src)); | ||||
|   } | ||||
|   if (!force && access(dst, W_OK) == -1 && errno != ENOENT) goto OnFail; | ||||
|   strcpy(mkbuf, dst); | ||||
|   if (makedirs(dirname(mkbuf), 0755) == -1) goto OnFail; | ||||
|   if (IsSymlink(src)) { | ||||
|     if ((rc = readlink(src, linkbuf, sizeof(linkbuf) - 1)) == -1) goto OnFail; | ||||
|     linkbuf[rc] = 0; | ||||
|     if (symlink(linkbuf, dst) == -1) goto OnFail; | ||||
|   } else { | ||||
|     if (!MovePreservingDestinationInode(src, dst)) goto OnFail; | ||||
|   } | ||||
|   return; | ||||
| OnFail: | ||||
|   s = _strerdoc(errno); | ||||
|   fputs(prog, stderr); | ||||
|   fputs(": ", stderr); | ||||
|   fputs(src, stderr); | ||||
|   fputs(" ", stderr); | ||||
|   fputs(dst, stderr); | ||||
|   fputs(": ", stderr); | ||||
|   fputs(s, stderr); | ||||
|   fputs("\n", stderr); | ||||
|   if (!force && access(dst, W_OK) == -1 && errno != ENOENT) { | ||||
|     perror(dst); | ||||
|     exit(1); | ||||
|   } | ||||
|   strcpy(mkbuf, dst); | ||||
|   if (makedirs((s = dirname(mkbuf)), 0755) == -1) { | ||||
|     perror(s); | ||||
|     exit(1); | ||||
|   } | ||||
|   if (IsSymlink(src)) { | ||||
|     if ((rc = readlink(src, linkbuf, sizeof(linkbuf) - 1)) == -1) { | ||||
|       perror(src); | ||||
|       exit(1); | ||||
|     } | ||||
|     linkbuf[rc] = 0; | ||||
|     if (symlink(linkbuf, dst) == -1) { | ||||
|       perror(dst); | ||||
|       exit(1); | ||||
|     } | ||||
|   } else { | ||||
|     if (!MovePreservingDestinationInode(src, dst)) { | ||||
|       perror(src); | ||||
|       exit(1); | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| int main(int argc, char *argv[]) { | ||||
|   int i; | ||||
|   prog = argc > 0 ? argv[0] : "cp.com"; | ||||
| 
 | ||||
|   prog = argv[0]; | ||||
|   if (!prog) prog = "cp"; | ||||
| 
 | ||||
|   GetOpts(argc, argv); | ||||
|   if (argc - optind < 2) PrintUsage(EX_USAGE, stderr); | ||||
| 
 | ||||
|   if (argc - optind < 2) { | ||||
|     tinyprint(2, prog, ": missing operand\n", NULL); | ||||
|     exit(1); | ||||
|   } | ||||
| 
 | ||||
|   for (i = optind; i < argc - 1; ++i) { | ||||
|     Cp(argv[i], argv[argc - 1]); | ||||
|   } | ||||
| 
 | ||||
|   return 0; | ||||
| } | ||||
|  |  | |||
|  | @ -73,32 +73,20 @@ static const char *epath; | |||
| static Elf64_Xword symcount; | ||||
| static const Elf64_Ehdr *elf; | ||||
| 
 | ||||
| nullterminated() static void Print(int fd, const char *s, ...) { | ||||
|   va_list va; | ||||
|   char buf[2048]; | ||||
|   va_start(va, s); | ||||
|   buf[0] = 0; | ||||
|   do { | ||||
|     strlcat(buf, s, sizeof(buf)); | ||||
|   } while ((s = va_arg(va, const char *))); | ||||
|   write(fd, buf, strlen(buf)); | ||||
|   va_end(va); | ||||
| } | ||||
| 
 | ||||
| static wontreturn void Die(const char *reason) { | ||||
|   Print(2, epath, ": ", reason, "\n", NULL); | ||||
|   tinyprint(2, epath, ": ", reason, "\n", NULL); | ||||
|   exit(1); | ||||
| } | ||||
| 
 | ||||
| static wontreturn void SysExit(const char *func) { | ||||
|   const char *errstr; | ||||
|   if (!(errstr = _strerdoc(errno))) errstr = "EUNKNOWN"; | ||||
|   Print(2, epath, ": ", func, " failed with ", errstr, "\n", NULL); | ||||
|   tinyprint(2, epath, ": ", func, " failed with ", errstr, "\n", NULL); | ||||
|   exit(1); | ||||
| } | ||||
| 
 | ||||
| static wontreturn void PrintUsage(int fd, int exitcode) { | ||||
|   Print(fd, "\n\
 | ||||
|   tinyprint(fd, "\n\
 | ||||
| NAME\n\ | ||||
| \n\ | ||||
|   Cosmopolitan Object Fixer\n\ | ||||
|  | @ -143,7 +131,7 @@ static void GetOpts(int argc, char *argv[]) { | |||
|     } | ||||
|   } | ||||
|   if (optind == argc) { | ||||
|     Print(2, | ||||
|     tinyprint(2, | ||||
|               "error: no elf object files specified\n" | ||||
|               "run ", | ||||
|               program_invocation_name, " -h for usage\n", NULL); | ||||
|  | @ -184,7 +172,7 @@ static void CheckPrivilegedCrossReferences(void) { | |||
|       if (~shdr->sh_flags & SHF_EXECINSTR) continue;  // data reference
 | ||||
|       if ((secname = GetElfString(elf, esize, secstrs, shdr->sh_name)) && | ||||
|           strcmp(".privileged", secname)) { | ||||
|         Print(2, epath, | ||||
|         tinyprint(2, epath, | ||||
|                   ": code in .privileged section " | ||||
|                   "references symbol '", | ||||
|                   GetElfString(elf, esize, symstrs, syms[x].st_name), | ||||
|  |  | |||
|  | @ -289,7 +289,8 @@ void Decompress(const char *inpath) { | |||
| 
 | ||||
| int main(int argc, char *argv[]) { | ||||
|   int i; | ||||
|   prog = argc > 0 ? argv[0] : "cp.com"; | ||||
|   prog = argv[0]; | ||||
|   if (!prog) prog = "gzip"; | ||||
|   GetOpts(argc, argv); | ||||
|   if (opt_decompress) { | ||||
|     if (optind == argc) { | ||||
|  |  | |||
|  | @ -52,7 +52,7 @@ void PrintUsage(int rc, FILE *f) { | |||
| void GetOpts(int argc, char *argv[]) { | ||||
|   int opt; | ||||
|   bits_ = 64; | ||||
|   while ((opt = getopt(argc, argv, "?hbs")) != -1) { | ||||
|   while ((opt = getopt(argc, argv, "hbs")) != -1) { | ||||
|     switch (opt) { | ||||
|       case 's': | ||||
|         succinct_ = true; | ||||
|  | @ -60,7 +60,6 @@ void GetOpts(int argc, char *argv[]) { | |||
|       case 'b': | ||||
|         bits_ = atoi(optarg); | ||||
|         break; | ||||
|       case '?': | ||||
|       case 'h': | ||||
|         PrintUsage(EXIT_SUCCESS, stdout); | ||||
|       default: | ||||
|  |  | |||
|  | @ -8,14 +8,9 @@ | |||
| ╚─────────────────────────────────────────────────────────────────*/ | ||||
| #endif | ||||
| #include "libc/calls/calls.h" | ||||
| #include "libc/errno.h" | ||||
| #include "libc/fmt/conv.h" | ||||
| #include "libc/fmt/magnumstrs.internal.h" | ||||
| #include "libc/runtime/runtime.h" | ||||
| #include "libc/stdio/stdio.h" | ||||
| #include "libc/str/str.h" | ||||
| #include "libc/sysv/consts/ex.h" | ||||
| #include "libc/x/x.h" | ||||
| #include "third_party/getopt/getopt.internal.h" | ||||
| 
 | ||||
| #define USAGE \ | ||||
|  | @ -30,19 +25,19 @@ FLAGS\n\ | |||
| 
 | ||||
| const char *prog; | ||||
| 
 | ||||
| wontreturn void PrintUsage(int rc, FILE *f) { | ||||
|   fputs("Usage: ", f); | ||||
|   fputs(prog, f); | ||||
|   fputs(USAGE, f); | ||||
| wontreturn void PrintUsage(int rc, int fd) { | ||||
|   tinyprint(fd, "USAGE\n\n  ", prog, USAGE, NULL); | ||||
|   exit(rc); | ||||
| } | ||||
| 
 | ||||
| int main(int argc, char *argv[]) { | ||||
|   int i, mode = 0755; | ||||
|   int (*mkdirp)(const char *, unsigned) = mkdir; | ||||
|   prog = argc > 0 ? argv[0] : "mkdir.com"; | ||||
| 
 | ||||
|   while ((i = getopt(argc, argv, "?hpm:")) != -1) { | ||||
|   prog = argv[0]; | ||||
|   if (!prog) prog = "mkdir"; | ||||
| 
 | ||||
|   while ((i = getopt(argc, argv, "hpm:")) != -1) { | ||||
|     switch (i) { | ||||
|       case 'p': | ||||
|         mkdirp = makedirs; | ||||
|  | @ -50,31 +45,21 @@ int main(int argc, char *argv[]) { | |||
|       case 'm': | ||||
|         mode = strtol(optarg, 0, 8); | ||||
|         break; | ||||
|       case '?': | ||||
|       case 'h': | ||||
|         PrintUsage(0, stdout); | ||||
|         PrintUsage(0, 1); | ||||
|       default: | ||||
|         PrintUsage(EX_USAGE, stderr); | ||||
|         PrintUsage(1, 2); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   if (optind == argc) { | ||||
|     fputs(prog, stderr); | ||||
|     fputs(": missing argument\n", stderr); | ||||
|     fputs("Try '", stderr); | ||||
|     fputs(prog, stderr); | ||||
|     fputs(" -h' for more information.\n", stderr); | ||||
|     tinyprint(2, prog, ": missing operand\n", NULL); | ||||
|     exit(1); | ||||
|   } | ||||
| 
 | ||||
|   for (i = optind; i < argc; ++i) { | ||||
|     if (mkdirp(argv[i], mode) == -1) { | ||||
|       fputs(prog, stderr); | ||||
|       fputs(": cannot create directory '", stderr); | ||||
|       fputs(argv[i], stderr); | ||||
|       fputs("' ", stderr); | ||||
|       fputs(_strerdoc(errno), stderr); | ||||
|       fputc('\n', stderr); | ||||
|       perror(argv[i]); | ||||
|       exit(1); | ||||
|     } | ||||
|   } | ||||
|  |  | |||
|  | @ -62,27 +62,15 @@ char linkbuf[PATH_MAX]; | |||
| 
 | ||||
| void Mv(char *, char *); | ||||
| 
 | ||||
| nullterminated() void Print(int fd, const char *s, ...) { | ||||
|   va_list va; | ||||
|   char buf[2048]; | ||||
|   va_start(va, s); | ||||
|   buf[0] = 0; | ||||
|   do { | ||||
|     strlcat(buf, s, sizeof(buf)); | ||||
|   } while ((s = va_arg(va, const char *))); | ||||
|   write(fd, buf, strlen(buf)); | ||||
|   va_end(va); | ||||
| } | ||||
| 
 | ||||
| wontreturn void Die(const char *path, const char *reason) { | ||||
|   Print(2, path, ": ", reason, "\n", NULL); | ||||
|   tinyprint(2, path, ": ", reason, "\n", NULL); | ||||
|   exit(1); | ||||
| } | ||||
| 
 | ||||
| wontreturn void SysExit(const char *path, const char *func) { | ||||
| wontreturn void SysDie(const char *path, const char *func) { | ||||
|   const char *errstr; | ||||
|   if (!(errstr = _strerdoc(errno))) errstr = "EUNKNOWN"; | ||||
|   Print(2, path, ": ", func, "() failed with ", errstr, "\n", NULL); | ||||
|   tinyprint(2, path, ": ", func, ": ", errstr, "\n", NULL); | ||||
|   exit(1); | ||||
| } | ||||
| 
 | ||||
|  | @ -108,7 +96,7 @@ bool IsSymlink(const char *path) { | |||
| } | ||||
| 
 | ||||
| wontreturn void PrintUsage(int rc, int fd) { | ||||
|   Print(fd, "usage: ", prog, USAGE, NULL); | ||||
|   tinyprint(fd, "usage: ", prog, USAGE, NULL); | ||||
|   exit(rc); | ||||
| } | ||||
| 
 | ||||
|  | @ -161,7 +149,7 @@ char *Join(const char *a, const char *b) { | |||
|   n = strlen(a); | ||||
|   m = strlen(b); | ||||
|   if (n + 1 + m + 1 > sizeof(dstfile)) { | ||||
|     Print(2, "error: mv: path too long\n", NULL); | ||||
|     tinyprint(2, "error: mv: path too long\n", NULL); | ||||
|     exit(1); | ||||
|   } | ||||
|   stpcpy(stpcpy(stpcpy(dstfile, a), "/"), b); | ||||
|  | @ -192,7 +180,7 @@ void Mv(char *src, char *dst) { | |||
|       strcpy(srcdir, ""); | ||||
|     } | ||||
|     if (nftw(src, Visit, 20, 0) == -1) { | ||||
|       SysExit(src, "nftw"); | ||||
|       SysDie(src, "nftw"); | ||||
|     } | ||||
|     return; | ||||
|   } | ||||
|  | @ -200,30 +188,31 @@ void Mv(char *src, char *dst) { | |||
|     dst = Join(dst, basename(src)); | ||||
|   } | ||||
|   if (!force && access(dst, W_OK) == -1 && errno != ENOENT) { | ||||
|     SysExit(dst, "access"); | ||||
|     SysDie(dst, "access"); | ||||
|   } | ||||
|   strcpy(mkbuf, dst); | ||||
|   if (makedirs((d = dirname(mkbuf)), 0755) == -1) { | ||||
|     SysExit(d, "makedirs"); | ||||
|     SysDie(d, "makedirs"); | ||||
|   } | ||||
|   if (IsSymlink(src)) { | ||||
|     if ((rc = readlink(src, linkbuf, sizeof(linkbuf) - 1)) == -1) { | ||||
|       SysExit(src, "readlink"); | ||||
|       SysDie(src, "readlink"); | ||||
|     } | ||||
|     linkbuf[rc] = 0; | ||||
|     if (symlink(linkbuf, dst)) { | ||||
|       SysExit(dst, "symlink"); | ||||
|       SysDie(dst, "symlink"); | ||||
|     } | ||||
|   } else { | ||||
|     if (rename(src, dst)) { | ||||
|       SysExit(src, "rename"); | ||||
|       SysDie(src, "rename"); | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| int main(int argc, char *argv[]) { | ||||
|   int i; | ||||
|   prog = argc > 0 ? argv[0] : "mv.com"; | ||||
|   prog = argv[0]; | ||||
|   if (!prog) prog = "mv"; | ||||
|   GetOpts(argc, argv); | ||||
|   if (argc - optind < 2) PrintUsage(1, 2); | ||||
|   for (i = optind; i < argc - 1; ++i) { | ||||
|  |  | |||
|  | @ -1,79 +0,0 @@ | |||
| /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
 | ||||
| │vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8                                :vi│ | ||||
| ╞══════════════════════════════════════════════════════════════════════════════╡ | ||||
| │ Copyright 2022 Justine Alexandra Roberts Tunney                              │ | ||||
| │                                                                              │ | ||||
| │ Permission to use, copy, modify, and/or distribute this software for         │ | ||||
| │ any purpose with or without fee is hereby granted, provided that the         │ | ||||
| │ above copyright notice and this permission notice appear in all copies.      │ | ||||
| │                                                                              │ | ||||
| │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL                │ | ||||
| │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED                │ | ||||
| │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE             │ | ||||
| │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL         │ | ||||
| │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR        │ | ||||
| │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER               │ | ||||
| │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR             │ | ||||
| │ PERFORMANCE OF THIS SOFTWARE.                                                │ | ||||
| ╚─────────────────────────────────────────────────────────────────────────────*/ | ||||
| #include "libc/calls/calls.h" | ||||
| #include "libc/errno.h" | ||||
| #include "libc/fmt/itoa.h" | ||||
| #include "libc/fmt/magnumstrs.internal.h" | ||||
| #include "libc/runtime/runtime.h" | ||||
| #include "libc/str/str.h" | ||||
| #include "libc/sysv/consts/ex.h" | ||||
| #include "libc/sysv/consts/o.h" | ||||
| #include "third_party/getopt/getopt.internal.h" | ||||
| 
 | ||||
| char buf[512]; | ||||
| 
 | ||||
| static void Write(const char *s, ...) { | ||||
|   va_list va; | ||||
|   va_start(va, s); | ||||
|   do { | ||||
|     write(2, s, strlen(s)); | ||||
|   } while ((s = va_arg(va, const char *))); | ||||
|   va_end(va); | ||||
| } | ||||
| 
 | ||||
| wontreturn void SysExit(int rc, const char *call, const char *thing) { | ||||
|   int err; | ||||
|   char ibuf[12]; | ||||
|   const char *estr; | ||||
|   err = errno; | ||||
|   FormatInt32(ibuf, err); | ||||
|   estr = _strerdoc(err); | ||||
|   if (!estr) estr = "EUNKNOWN"; | ||||
|   Write(thing, ": ", call, "() failed: ", estr, " (", ibuf, ")\n", 0); | ||||
|   exit(rc); | ||||
| } | ||||
| 
 | ||||
| int main(int argc, char *argv[]) { | ||||
|   int i, opt; | ||||
|   const char *outpath = "/dev/stdout"; | ||||
|   while ((opt = getopt(argc, argv, "o:")) != -1) { | ||||
|     switch (opt) { | ||||
|       case 'o': | ||||
|         outpath = optarg; | ||||
|         break; | ||||
|       default: | ||||
|         return 1; | ||||
|     } | ||||
|   } | ||||
|   int out = open(outpath, O_WRONLY | O_CREAT | O_TRUNC, 0644); | ||||
|   if (out == -1) SysExit(2, "open", outpath); | ||||
|   for (i = optind; i < argc; ++i) { | ||||
|     int in = open(argv[i], O_RDONLY); | ||||
|     if (in == -1) SysExit(3, "open", argv[i]); | ||||
|     for (;;) { | ||||
|       ssize_t rc = read(in, buf, 512); | ||||
|       if (rc == -1) SysExit(3, "read", argv[i]); | ||||
|       if (!rc) break; | ||||
|       ssize_t rc2 = write(out, buf, rc); | ||||
|       if (rc2 != rc) SysExit(4, "write", outpath); | ||||
|     } | ||||
|     if (close(in) == -1) SysExit(5, "close", argv[i]); | ||||
|   } | ||||
|   if (close(out) == -1) SysExit(6, "close", outpath); | ||||
| } | ||||
|  | @ -153,27 +153,15 @@ struct Relas { | |||
|   } * p; | ||||
| } prtu; | ||||
| 
 | ||||
| nullterminated() static void Print(int fd, const char *s, ...) { | ||||
|   va_list va; | ||||
|   char buf[2048]; | ||||
|   va_start(va, s); | ||||
|   buf[0] = 0; | ||||
|   do { | ||||
|     strlcat(buf, s, sizeof(buf)); | ||||
|   } while ((s = va_arg(va, const char *))); | ||||
|   write(fd, buf, strlen(buf)); | ||||
|   va_end(va); | ||||
| } | ||||
| 
 | ||||
| static wontreturn void Die(const char *path, const char *reason) { | ||||
|   Print(2, path, ": ", reason, "\n", NULL); | ||||
|   tinyprint(2, path, ": ", reason, "\n", NULL); | ||||
|   exit(1); | ||||
| } | ||||
| 
 | ||||
| static wontreturn void SysExit(const char *path, const char *func) { | ||||
|   const char *errstr; | ||||
|   if (!(errstr = _strerrno(errno))) errstr = "EUNKNOWN"; | ||||
|   Print(2, path, ": ", func, " failed with ", errstr, "\n", NULL); | ||||
|   tinyprint(2, path, ": ", func, " failed with ", errstr, "\n", NULL); | ||||
|   exit(1); | ||||
| } | ||||
| 
 | ||||
|  | @ -321,7 +309,7 @@ static void WritePackage(struct Package *pkg) { | |||
| } | ||||
| 
 | ||||
| static wontreturn void PrintUsage(int fd, int exitcode) { | ||||
|   Print(fd, "\n\
 | ||||
|   tinyprint(fd, "\n\
 | ||||
| NAME\n\ | ||||
| \n\ | ||||
|   Cosmopolitan Monorepo Packager\n\ | ||||
|  | @ -370,11 +358,12 @@ static void GetOpts(struct Package *pkg, struct Packages *deps, int argc, | |||
|     } | ||||
|   } | ||||
|   if (pkg->path == -1) { | ||||
|     Print(2, "error: no packages passed to package.com\n", NULL); | ||||
|     tinyprint(2, "error: no packages passed to package.com\n", NULL); | ||||
|     exit(1); | ||||
|   } | ||||
|   if (optind == argc) { | ||||
|     Print(2, | ||||
|     tinyprint( | ||||
|         2, | ||||
|         "no objects passed to package.com; is your foo.mk $(FOO_OBJS) glob " | ||||
|         "broken?\n", | ||||
|         NULL); | ||||
|  | @ -495,7 +484,7 @@ static void LoadPriviligedRefsToUndefs(struct Package *pkg, | |||
|       if (obj->syms[x].st_shndx) continue;  // symbol is defined
 | ||||
|       if (ELF64_ST_BIND(obj->syms[x].st_info) != STB_WEAK && | ||||
|           ELF64_ST_BIND(obj->syms[x].st_info) != STB_GLOBAL) { | ||||
|         Print(2, "warning: undefined symbol not global\n", NULL); | ||||
|         tinyprint(2, "warning: undefined symbol not global\n", NULL); | ||||
|         continue; | ||||
|       } | ||||
|       if (!(s = GetElfString(obj->elf, obj->size, obj->strs, | ||||
|  | @ -602,13 +591,13 @@ static void CheckStrictDeps(struct Package *pkg, struct Packages *deps) { | |||
|     undef = &pkg->undefs.p[i]; | ||||
|     if (undef->bind_ == STB_WEAK) continue; | ||||
|     if (!FindSymbol(pkg->strings.p + undef->name, pkg, deps, NULL, NULL)) { | ||||
|       Print(2, pkg->strings.p + pkg->path, ": undefined symbol '", | ||||
|       tinyprint(2, pkg->strings.p + pkg->path, ": undefined symbol '", | ||||
|                 pkg->strings.p + undef->name, "' (", | ||||
|                 pkg->strings.p + pkg->objects.p[undef->object].path, | ||||
|                 ") not defined by direct dependencies:\n", NULL); | ||||
|       for (j = 0; j < deps->i; ++j) { | ||||
|         dep = deps->p[j]; | ||||
|         Print(2, "\t", dep->strings.p + dep->path, "\n", NULL); | ||||
|         tinyprint(2, "\t", dep->strings.p + dep->path, "\n", NULL); | ||||
|       } | ||||
|       exit(1); | ||||
|     } | ||||
|  | @ -626,10 +615,11 @@ static void CheckYourPrivilege(struct Package *pkg, struct Packages *deps) { | |||
|     name = prtu.p[i].symbol_name; | ||||
|     if (FindSymbol(name, pkg, deps, &dep, &sym) && | ||||
|         dep->sections.p[sym->section].kind == kText) { | ||||
|       Print(2, prtu.p[i].object_path, | ||||
|       tinyprint(2, prtu.p[i].object_path, | ||||
|                 ": privileged code referenced unprivileged symbol '", name, | ||||
|                 "' in section '", | ||||
|             dep->strings.p + dep->sections.p[sym->section].name, "'\n", NULL); | ||||
|                 dep->strings.p + dep->sections.p[sym->section].name, "'\n", | ||||
|                 NULL); | ||||
|       ++f; | ||||
|     } | ||||
|   } | ||||
|  |  | |||
|  | @ -119,9 +119,7 @@ int main(int argc, char *argv[]) { | |||
|       printf(U(argv[1]), argv[2], argv[3], argv[4], argv[5], argv[6], argv[7]); | ||||
|       return 0; | ||||
|     default: | ||||
|       if (argc > 0) { | ||||
|       fprintf(stderr, "%s: %s format [arguments]\n", argv[0], argv[0]); | ||||
|       } | ||||
|       return 1; | ||||
|   } | ||||
| } | ||||
|  |  | |||
|  | @ -1,990 +0,0 @@ | |||
| /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
 | ||||
| │vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8                                :vi│ | ||||
| ╞══════════════════════════════════════════════════════════════════════════════╡ | ||||
| │ Copyright 2021 Justine Alexandra Roberts Tunney                              │ | ||||
| │                                                                              │ | ||||
| │ Permission to use, copy, modify, and/or distribute this software for         │ | ||||
| │ any purpose with or without fee is hereby granted, provided that the         │ | ||||
| │ above copyright notice and this permission notice appear in all copies.      │ | ||||
| │                                                                              │ | ||||
| │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL                │ | ||||
| │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED                │ | ||||
| │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE             │ | ||||
| │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL         │ | ||||
| │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR        │ | ||||
| │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER               │ | ||||
| │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR             │ | ||||
| │ PERFORMANCE OF THIS SOFTWARE.                                                │ | ||||
| ╚─────────────────────────────────────────────────────────────────────────────*/ | ||||
| #include "libc/calls/calls.h" | ||||
| #include "libc/calls/struct/sigaction.h" | ||||
| #include "libc/calls/struct/sigset.h" | ||||
| #include "libc/errno.h" | ||||
| #include "libc/fmt/conv.h" | ||||
| #include "libc/intrin/bits.h" | ||||
| #include "libc/log/check.h" | ||||
| #include "libc/log/log.h" | ||||
| #include "libc/mem/gc.internal.h" | ||||
| #include "libc/mem/mem.h" | ||||
| #include "libc/runtime/runtime.h" | ||||
| #include "libc/stdio/stdio.h" | ||||
| #include "libc/str/str.h" | ||||
| #include "libc/sysv/consts/ex.h" | ||||
| #include "libc/sysv/consts/exit.h" | ||||
| #include "libc/sysv/consts/nr.h" | ||||
| #include "libc/sysv/consts/o.h" | ||||
| #include "libc/sysv/consts/sa.h" | ||||
| #include "libc/sysv/consts/sig.h" | ||||
| #include "libc/x/xasprintf.h" | ||||
| #include "libc/x/xgetline.h" | ||||
| #include "third_party/dlmalloc/dlmalloc.h" | ||||
| #include "third_party/getopt/getopt.internal.h" | ||||
| 
 | ||||
| /**
 | ||||
|  * @fileoverview Pythonic System Call Trace | ||||
|  * | ||||
|  * This program invokes `strace` as a subprocess and turns its output | ||||
|  * into Python data structures. It is useful because strace output is | ||||
|  * this weird plaintext format that's so famously difficult to parse. | ||||
|  * | ||||
|  * For example, you can run this command: | ||||
|  * | ||||
|  *     pstrace -o trace.pylog echo hello world | ||||
|  * | ||||
|  * After which you may parse the output with Python: | ||||
|  * | ||||
|  *     for line in open('trace.pylog'): | ||||
|  *       pid,time,elap,kind,x = eval(line) | ||||
|  *       if kind == 1: | ||||
|  *         name,ret,args = x | ||||
|  *         print "%s%r -> %d" % (name, args, ret) | ||||
|  * | ||||
|  * This program traces the subset of system calls governing processes | ||||
|  * and files. To do that we must track file descriptor lifetimes too. | ||||
|  * We also track system calls that are problematic for build configs, | ||||
|  * such as sockets, since compiling code shouldn't need the Internet. | ||||
|  * | ||||
|  * @note this tool is linux only | ||||
|  * @note freebsd: truss PROC ARGS | ||||
|  * @note appleos: sudo dtruss PROC ARGS | ||||
|  * @note openbsd: ktrace PROC ARGS && kdump -f ktrace.out | ||||
|  * @note windows: https://github.com/rogerorr/NtTrace
 | ||||
|  */ | ||||
| 
 | ||||
| #define DEBUG        "%ld: %s", lineno, line | ||||
| #define READ128BE(S) ((uint128_t)READ64BE(S) << 64 | READ64BE((S) + 8)) | ||||
| #define APPEND(L)                             \ | ||||
|   do {                                        \ | ||||
|     if (++L.n > L.c) {                        \ | ||||
|       L.c = MAX(11, L.c);                     \ | ||||
|       L.c += L.c >> 1;                        \ | ||||
|       L.p = realloc(L.p, L.c * sizeof(*L.p)); \ | ||||
|     }                                         \ | ||||
|     bzero(L.p + L.n - 1, sizeof(*L.p));       \ | ||||
|   } while (0) | ||||
| 
 | ||||
| struct Trace { | ||||
|   struct Slices { | ||||
|     long n, c; | ||||
|     struct Slice { | ||||
|       int n, c; | ||||
|       char *p; | ||||
|     } * p; | ||||
|   } slices; | ||||
|   struct HashTable { | ||||
|     long i, n; | ||||
|     struct HashEntry { | ||||
|       long h; | ||||
|       long i; | ||||
|     } * p; | ||||
|   } sliceindex; | ||||
|   struct Strlists { | ||||
|     long n, c; | ||||
|     struct Strlist { | ||||
|       long n, c; | ||||
|       long *p;  // slices.p[p[i]]
 | ||||
|     } * p; | ||||
|   } strlists; | ||||
|   struct Events { | ||||
|     long n, c; | ||||
|     struct Event { | ||||
|       enum EventKind { | ||||
|         EK_NONE, | ||||
|         EK_CALL, | ||||
|         EK_EXIT,    // ret is kernel code
 | ||||
|         EK_SIGNAL,  // ret is signal code
 | ||||
|         EK_KILLED,  // ret is signal code
 | ||||
|       } kind; | ||||
|       unsigned char arity; | ||||
|       unsigned char syscall_; | ||||
|       bool is_interrupted; | ||||
|       int us; | ||||
|       int elap; | ||||
|       int pid; | ||||
|       long sec; | ||||
|       long ret; | ||||
|       long lineno; | ||||
|       struct Arg { | ||||
|         enum ArgKind { | ||||
|           AK_LONG,     // x
 | ||||
|           AK_STR,      // slices.p[x]
 | ||||
|           AK_STRLIST,  // strlists.p[x]
 | ||||
|           AK_INTPAIR,  // (x&0xffffffff, x>>32)
 | ||||
|         } kind; | ||||
|         long name; | ||||
|         long x; | ||||
|       } arg[6]; | ||||
|     } * p; | ||||
|   } events; | ||||
| }; | ||||
| 
 | ||||
| static const struct Syscall { | ||||
|   char name[16]; | ||||
| } kSyscalls[] = { | ||||
|     {"accept"},          //
 | ||||
|     {"accept4"},         //
 | ||||
|     {"access"},          //
 | ||||
|     {"bind"},            //
 | ||||
|     {"chdir"},           //
 | ||||
|     {"chmod"},           //
 | ||||
|     {"chown"},           //
 | ||||
|     {"chroot"},          //
 | ||||
|     {"clone"},           //
 | ||||
|     {"close"},           //
 | ||||
|     {"connect"},         //
 | ||||
|     {"creat"},           //
 | ||||
|     {"dup"},             //
 | ||||
|     {"dup2"},            //
 | ||||
|     {"dup3"},            //
 | ||||
|     {"epoll_create"},    //
 | ||||
|     {"epoll_create1"},   //
 | ||||
|     {"eventfd"},         //
 | ||||
|     {"eventfd2"},        //
 | ||||
|     {"execve"},          //
 | ||||
|     {"execveat"},        //
 | ||||
|     {"faccessat"},       //
 | ||||
|     {"fchmodat"},        //
 | ||||
|     {"fchownat"},        //
 | ||||
|     {"fdatasync"},       //
 | ||||
|     {"fcntl"},           //
 | ||||
|     {"flock"},           //
 | ||||
|     {"fork"},            //
 | ||||
|     {"fsync"},           //
 | ||||
|     {"lchown"},          //
 | ||||
|     {"link"},            //
 | ||||
|     {"linkat"},          //
 | ||||
|     {"listen"},          //
 | ||||
|     {"memfd_create"},    //
 | ||||
|     {"mkdir"},           //
 | ||||
|     {"mkdirat"},         //
 | ||||
|     {"mknod"},           //
 | ||||
|     {"mknodat"},         //
 | ||||
|     {"open"},            //
 | ||||
|     {"openat"},          //
 | ||||
|     {"pipe"},            //
 | ||||
|     {"pipe2"},           //
 | ||||
|     {"readlink"},        //
 | ||||
|     {"readlinkat"},      //
 | ||||
|     {"rename"},          //
 | ||||
|     {"renameat"},        //
 | ||||
|     {"renameat2"},       //
 | ||||
|     {"rmdir"},           //
 | ||||
|     {"signalfd"},        //
 | ||||
|     {"signalfd4"},       //
 | ||||
|     {"socket"},          //
 | ||||
|     {"socketpair"},      //
 | ||||
|     {"statfs"},          //
 | ||||
|     {"symlink"},         //
 | ||||
|     {"symlinkat"},       //
 | ||||
|     {"sync"},            //
 | ||||
|     {"syncfs"},          //
 | ||||
|     {"timerfd_create"},  //
 | ||||
|     {"truncate"},        //
 | ||||
|     {"unlink"},          //
 | ||||
|     {"unlinkat"},        //
 | ||||
|     {"utimensat"},       //
 | ||||
|     {"vfork"},           //
 | ||||
| }; | ||||
| 
 | ||||
| static const struct Signal { | ||||
|   char name[8]; | ||||
|   unsigned char number; | ||||
| } kSignals[] = { | ||||
|     {"SIGABRT", 6},    //
 | ||||
|     {"SIGALRM", 14},   //
 | ||||
|     {"SIGBUS", 7},     //
 | ||||
|     {"SIGCHLD", 17},   //
 | ||||
|     {"SIGCONT", 18},   //
 | ||||
|     {"SIGFPE", 8},     //
 | ||||
|     {"SIGHUP", 1},     //
 | ||||
|     {"SIGILL", 4},     //
 | ||||
|     {"SIGINT", 2},     //
 | ||||
|     {"SIGIO", 29},     //
 | ||||
|     {"SIGIOT", 6},     //
 | ||||
|     {"SIGKILL", 9},    //
 | ||||
|     {"SIGPIPE", 13},   //
 | ||||
|     {"SIGPOLL", 29},   //
 | ||||
|     {"SIGPROF", 27},   //
 | ||||
|     {"SIGPWR", 30},    //
 | ||||
|     {"SIGQUIT", 3},    //
 | ||||
|     {"SIGSEGV", 11},   //
 | ||||
|     {"SIGSTOP", 19},   //
 | ||||
|     {"SIGSYS", 31},    //
 | ||||
|     {"SIGTERM", 15},   //
 | ||||
|     {"SIGTRAP", 5},    //
 | ||||
|     {"SIGTSTP", 20},   //
 | ||||
|     {"SIGTTIN", 21},   //
 | ||||
|     {"SIGTTOU", 22},   //
 | ||||
|     {"SIGURG", 23},    //
 | ||||
|     {"SIGUSR1", 10},   //
 | ||||
|     {"SIGUSR2", 12},   //
 | ||||
|     {"SIGWINCH", 28},  //
 | ||||
|     {"SIGXCPU", 24},   //
 | ||||
|     {"SIGXFSZ", 25},   //
 | ||||
| }; | ||||
| 
 | ||||
| static const struct Errno { | ||||
|   char name[16]; | ||||
|   unsigned char number; | ||||
| } kErrnos[] = { | ||||
|     {"E2BIG", 7},              //
 | ||||
|     {"EACCES", 13},            //
 | ||||
|     {"EADDRINUSE", 98},        //
 | ||||
|     {"EADDRNOTAVAIL", 99},     //
 | ||||
|     {"EADV", 68},              //
 | ||||
|     {"EAFNOSUPPORT", 97},      //
 | ||||
|     {"EAGAIN", 11},            //
 | ||||
|     {"EALREADY", 114},         //
 | ||||
|     {"EBADE", 52},             //
 | ||||
|     {"EBADF", 9},              //
 | ||||
|     {"EBADFD", 77},            //
 | ||||
|     {"EBADMSG", 74},           //
 | ||||
|     {"EBADR", 53},             //
 | ||||
|     {"EBADRQC", 56},           //
 | ||||
|     {"EBADSLT", 57},           //
 | ||||
|     {"EBFONT", 59},            //
 | ||||
|     {"EBUSY", 16},             //
 | ||||
|     {"ECANCELED", 125},        //
 | ||||
|     {"ECHILD", 10},            //
 | ||||
|     {"ECHRNG", 44},            //
 | ||||
|     {"ECOMM", 70},             //
 | ||||
|     {"ECONNABORTED", 103},     //
 | ||||
|     {"ECONNREFUSED", 111},     //
 | ||||
|     {"ECONNRESET", 104},       //
 | ||||
|     {"EDEADLK", 35},           //
 | ||||
|     {"EDESTADDRREQ", 89},      //
 | ||||
|     {"EDOM", 33},              //
 | ||||
|     {"EDOTDOT", 73},           //
 | ||||
|     {"EDQUOT", 122},           //
 | ||||
|     {"EEXIST", 17},            //
 | ||||
|     {"EFAULT", 14},            //
 | ||||
|     {"EFBIG", 27},             //
 | ||||
|     {"EHOSTDOWN", 112},        //
 | ||||
|     {"EHOSTUNREACH", 113},     //
 | ||||
|     {"EHWPOISON", 133},        //
 | ||||
|     {"EIDRM", 43},             //
 | ||||
|     {"EILSEQ", 84},            //
 | ||||
|     {"EINPROGRESS", 115},      //
 | ||||
|     {"EINTR", 4},              //
 | ||||
|     {"EINVAL", 22},            //
 | ||||
|     {"EIO", 5},                //
 | ||||
|     {"EISCONN", 106},          //
 | ||||
|     {"EISDIR", 21},            //
 | ||||
|     {"EISNAM", 120},           //
 | ||||
|     {"EKEYEXPIRED", 127},      //
 | ||||
|     {"EKEYREJECTED", 129},     //
 | ||||
|     {"EKEYREVOKED", 128},      //
 | ||||
|     {"EL2HLT", 51},            //
 | ||||
|     {"EL2NSYNC", 45},          //
 | ||||
|     {"EL3HLT", 46},            //
 | ||||
|     {"EL3RST", 47},            //
 | ||||
|     {"ELIBACC", 79},           //
 | ||||
|     {"ELIBBAD", 80},           //
 | ||||
|     {"ELIBEXEC", 83},          //
 | ||||
|     {"ELIBMAX", 82},           //
 | ||||
|     {"ELIBSCN", 81},           //
 | ||||
|     {"ELNRNG", 48},            //
 | ||||
|     {"ELOOP", 40},             //
 | ||||
|     {"EMEDIUMTYPE", 124},      //
 | ||||
|     {"EMFILE", 24},            //
 | ||||
|     {"EMLINK", 31},            //
 | ||||
|     {"EMSGSIZE", 90},          //
 | ||||
|     {"EMULTIHOP", 72},         //
 | ||||
|     {"ENAMETOOLONG", 36},      //
 | ||||
|     {"ENAVAIL", 119},          //
 | ||||
|     {"ENETDOWN", 100},         //
 | ||||
|     {"ENETRESET", 102},        //
 | ||||
|     {"ENETUNREACH", 101},      //
 | ||||
|     {"ENFILE", 23},            //
 | ||||
|     {"ENOANO", 55},            //
 | ||||
|     {"ENOBUFS", 105},          //
 | ||||
|     {"ENOCSI", 50},            //
 | ||||
|     {"ENODATA", 61},           //
 | ||||
|     {"ENODEV", 19},            //
 | ||||
|     {"ENOENT", 2},             //
 | ||||
|     {"ENOEXEC", 8},            //
 | ||||
|     {"ENOKEY", 126},           //
 | ||||
|     {"ENOLCK", 37},            //
 | ||||
|     {"ENOLINK", 67},           //
 | ||||
|     {"ENOMEDIUM", 123},        //
 | ||||
|     {"ENOMEM", 12},            //
 | ||||
|     {"ENOMSG", 42},            //
 | ||||
|     {"ENONET", 64},            //
 | ||||
|     {"ENOPKG", 65},            //
 | ||||
|     {"ENOPROTOOPT", 92},       //
 | ||||
|     {"ENOSPC", 28},            //
 | ||||
|     {"ENOSR", 63},             //
 | ||||
|     {"ENOSTR", 60},            //
 | ||||
|     {"ENOSYS", 38},            //
 | ||||
|     {"ENOTBLK", 15},           //
 | ||||
|     {"ENOTCONN", 107},         //
 | ||||
|     {"ENOTDIR", 20},           //
 | ||||
|     {"ENOTEMPTY", 39},         //
 | ||||
|     {"ENOTNAM", 118},          //
 | ||||
|     {"ENOTRECOVERABLE", 131},  //
 | ||||
|     {"ENOTSOCK", 88},          //
 | ||||
|     {"ENOTSUP", 95},           //
 | ||||
|     {"ENOTTY", 25},            //
 | ||||
|     {"ENOTUNIQ", 76},          //
 | ||||
|     {"ENXIO", 6},              //
 | ||||
|     {"EOPNOTSUPP", 95},        //
 | ||||
|     {"EOVERFLOW", 75},         //
 | ||||
|     {"EOWNERDEAD", 130},       //
 | ||||
|     {"EPERM", 1},              //
 | ||||
|     {"EPFNOSUPPORT", 96},      //
 | ||||
|     {"EPIPE", 32},             //
 | ||||
|     {"EPROTO", 71},            //
 | ||||
|     {"EPROTONOSUPPORT", 93},   //
 | ||||
|     {"EPROTOTYPE", 91},        //
 | ||||
|     {"ERANGE", 34},            //
 | ||||
|     {"EREMCHG", 78},           //
 | ||||
|     {"EREMOTE", 66},           //
 | ||||
|     {"EREMOTEIO", 121},        //
 | ||||
|     {"ERESTART", 85},          //
 | ||||
|     {"ERFKILL", 132},          //
 | ||||
|     {"EROFS", 30},             //
 | ||||
|     {"ESHUTDOWN", 108},        //
 | ||||
|     {"ESOCKTNOSUPPORT", 94},   //
 | ||||
|     {"ESPIPE", 29},            //
 | ||||
|     {"ESRCH", 3},              //
 | ||||
|     {"ESRMNT", 69},            //
 | ||||
|     {"ESTALE", 116},           //
 | ||||
|     {"ESTRPIPE", 86},          //
 | ||||
|     {"ETIME", 62},             //
 | ||||
|     {"ETIMEDOUT", 110},        //
 | ||||
|     {"ETOOMANYREFS", 109},     //
 | ||||
|     {"ETXTBSY", 26},           //
 | ||||
|     {"EUCLEAN", 117},          //
 | ||||
|     {"EUNATCH", 49},           //
 | ||||
|     {"EUSERS", 87},            //
 | ||||
|     {"EWOULDBLOCK", 11},       //
 | ||||
|     {"EXDEV", 18},             //
 | ||||
|     {"EXFULL", 54},            //
 | ||||
| }; | ||||
| 
 | ||||
| static char **strace_args; | ||||
| static size_t strace_args_len; | ||||
| static volatile bool interrupted; | ||||
| 
 | ||||
| static long Hash(const void *p, size_t n) { | ||||
|   unsigned h, i; | ||||
|   for (h = i = 0; i < n; i++) { | ||||
|     h += ((unsigned char *)p)[i]; | ||||
|     h *= 0x9e3779b1; | ||||
|   } | ||||
|   return MAX(1, h); | ||||
| } | ||||
| 
 | ||||
| static uint64_t MakeKey64(const char *p, size_t n) { | ||||
|   char k[8] = {0}; | ||||
|   memcpy(k, p, n); | ||||
|   return READ64BE(k); | ||||
| } | ||||
| 
 | ||||
| static uint128_t MakeKey128(const char *p, size_t n) { | ||||
|   char k[16] = {0}; | ||||
|   memcpy(k, p, n); | ||||
|   return READ128BE(k); | ||||
| } | ||||
| 
 | ||||
| static int GetSyscall(const char *name, size_t namelen) { | ||||
|   int m, l, r; | ||||
|   uint128_t x, y; | ||||
|   char *endofname; | ||||
|   if (namelen && namelen <= 16) { | ||||
|     x = MakeKey128(name, namelen); | ||||
|     l = 0; | ||||
|     r = ARRAYLEN(kSyscalls) - 1; | ||||
|     while (l <= r) { | ||||
|       m = (l + r) >> 1; | ||||
|       y = READ128BE(kSyscalls[m].name); | ||||
|       if (x < y) { | ||||
|         r = m - 1; | ||||
|       } else if (x > y) { | ||||
|         l = m + 1; | ||||
|       } else { | ||||
|         return m; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|   return -1; | ||||
| } | ||||
| 
 | ||||
| static int GetErrno(const char *name, size_t namelen) { | ||||
|   int m, l, r; | ||||
|   uint128_t x, y; | ||||
|   char *endofname; | ||||
|   if (namelen && namelen <= 16) { | ||||
|     x = MakeKey128(name, namelen); | ||||
|     l = 0; | ||||
|     r = ARRAYLEN(kErrnos) - 1; | ||||
|     while (l <= r) { | ||||
|       m = (l + r) >> 1; | ||||
|       y = READ128BE(kErrnos[m].name); | ||||
|       if (x < y) { | ||||
|         r = m - 1; | ||||
|       } else if (x > y) { | ||||
|         l = m + 1; | ||||
|       } else { | ||||
|         return kErrnos[m].number; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|   return -1; | ||||
| } | ||||
| 
 | ||||
| static int GetSignal(const char *name, size_t namelen) { | ||||
|   int m, l, r; | ||||
|   uint64_t x, y; | ||||
|   char *endofname; | ||||
|   if (namelen && namelen <= 8) { | ||||
|     x = MakeKey64(name, namelen); | ||||
|     l = 0; | ||||
|     r = ARRAYLEN(kSignals) - 1; | ||||
|     while (l <= r) { | ||||
|       m = (l + r) >> 1; | ||||
|       y = READ64BE(kSignals[m].name); | ||||
|       if (x < y) { | ||||
|         r = m - 1; | ||||
|       } else if (x > y) { | ||||
|         l = m + 1; | ||||
|       } else { | ||||
|         return kSignals[m].number; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|   return -1; | ||||
| } | ||||
| 
 | ||||
| static struct Trace *NewTrace(void) { | ||||
|   return calloc(1, sizeof(struct Trace)); | ||||
| } | ||||
| 
 | ||||
| static void FreeTrace(struct Trace *t) { | ||||
|   long i; | ||||
|   if (t) { | ||||
|     for (i = 0; i < t->slices.n; ++i) { | ||||
|       free(t->slices.p[i].p); | ||||
|     } | ||||
|     free(t->slices.p); | ||||
|     free(t->sliceindex.p); | ||||
|     for (i = 0; i < t->strlists.n; ++i) { | ||||
|       free(t->strlists.p[i].p); | ||||
|     } | ||||
|     free(t->strlists.p); | ||||
|     free(t->events.p); | ||||
|     free(t); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| static void AppendStrlists(struct Trace *t) { | ||||
|   APPEND(t->strlists); | ||||
| } | ||||
| 
 | ||||
| static void AppendStrlist(struct Strlist *l) { | ||||
|   APPEND((*l)); | ||||
| } | ||||
| 
 | ||||
| static void AppendEvent(struct Trace *t) { | ||||
|   APPEND(t->events); | ||||
| } | ||||
| 
 | ||||
| static void AppendSlices(struct Trace *t) { | ||||
|   APPEND(t->slices); | ||||
| } | ||||
| 
 | ||||
| static void AppendSlice(struct Slice *s, int c) { | ||||
|   APPEND((*s)); | ||||
|   s->p[s->n - 1] = c; | ||||
| } | ||||
| 
 | ||||
| static long Intern(struct Trace *t, char *data, long size) { | ||||
|   struct HashEntry *p; | ||||
|   long i, j, k, n, m, h, n2; | ||||
|   h = Hash(data, size); | ||||
|   n = t->sliceindex.n; | ||||
|   i = 0; | ||||
|   if (n) { | ||||
|     k = 0; | ||||
|     do { | ||||
|       i = (h + k + ((k + 1) >> 1)) & (n - 1); | ||||
|       if (t->sliceindex.p[i].h == h && | ||||
|           t->slices.p[t->sliceindex.p[i].i].n == size && | ||||
|           !memcmp(t->slices.p[t->sliceindex.p[i].i].p, data, size)) { | ||||
|         free(data); | ||||
|         return t->sliceindex.p[i].i; | ||||
|       } | ||||
|       ++k; | ||||
|     } while (t->sliceindex.p[i].h); | ||||
|   } | ||||
|   if (++t->sliceindex.i >= (n >> 1)) { | ||||
|     m = n ? n << 1 : 16; | ||||
|     p = calloc(m, sizeof(struct HashEntry)); | ||||
|     for (j = 0; j < n; ++j) { | ||||
|       if (t->sliceindex.p[j].h) { | ||||
|         k = 0; | ||||
|         do { | ||||
|           i = (t->sliceindex.p[j].h + k + ((k + 1) >> 1)) & (m - 1); | ||||
|           ++k; | ||||
|         } while (p[i].h); | ||||
|         p[i].h = t->sliceindex.p[j].h; | ||||
|         p[i].i = t->sliceindex.p[j].i; | ||||
|       } | ||||
|     } | ||||
|     k = 0; | ||||
|     do { | ||||
|       i = (h + k + ((k + 1) >> 1)) & (m - 1); | ||||
|       ++k; | ||||
|     } while (p[i].h); | ||||
|     free(t->sliceindex.p); | ||||
|     t->sliceindex.p = p; | ||||
|     t->sliceindex.n = m; | ||||
|   } | ||||
|   AppendSlices(t); | ||||
|   t->slices.p[t->slices.n - 1].p = data; | ||||
|   t->slices.p[t->slices.n - 1].n = size; | ||||
|   t->sliceindex.p[i].i = t->slices.n - 1; | ||||
|   t->sliceindex.p[i].h = h; | ||||
|   return t->slices.n - 1; | ||||
| } | ||||
| 
 | ||||
| static long ReadCharLiteral(struct Slice *buf, long c, char *p, long *i) { | ||||
|   if (c != '\\') return c; | ||||
|   switch ((c = p[(*i)++])) { | ||||
|     case 'a': | ||||
|       return '\a'; | ||||
|     case 'b': | ||||
|       return '\b'; | ||||
|     case 't': | ||||
|       return '\t'; | ||||
|     case 'n': | ||||
|       return '\n'; | ||||
|     case 'v': | ||||
|       return '\v'; | ||||
|     case 'f': | ||||
|       return '\f'; | ||||
|     case 'r': | ||||
|       return '\r'; | ||||
|     case 'e': | ||||
|       return 033; | ||||
|     case 'x': | ||||
|       if (isxdigit(p[*i])) { | ||||
|         c = hextoint(p[(*i)++]); | ||||
|         if (isxdigit(p[*i])) { | ||||
|           c = c * 16 + hextoint(p[(*i)++]); | ||||
|         } | ||||
|       } | ||||
|       return c; | ||||
|     case '0': | ||||
|     case '1': | ||||
|     case '2': | ||||
|     case '3': | ||||
|     case '4': | ||||
|     case '5': | ||||
|     case '6': | ||||
|     case '7': | ||||
|       c -= '0'; | ||||
|       if ('0' <= p[*i] && p[*i] <= '7') { | ||||
|         c = c * 8 + (p[(*i)++] - '0'); | ||||
|         if ('0' <= p[*i] && p[*i] <= '7') { | ||||
|           c = c * 8 + (p[(*i)++] - '0'); | ||||
|         } | ||||
|       } | ||||
|       return c; | ||||
|     default: | ||||
|       return c; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| static long GetDuration(long sec1, long us1, long sec2, long us2) { | ||||
|   long elap; | ||||
|   if ((elap = (sec2 - sec1) * 1000000)) { | ||||
|     return elap + 1000000 - us1 + us2; | ||||
|   } else { | ||||
|     return elap + us2 - us1; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| static void Parse(struct Trace *t, const char *line, long lineno) { | ||||
|   char *p, *q; | ||||
|   struct Slice b; | ||||
|   long c, i, j, k, arg, pid, event, sec, us; | ||||
|   p = line; | ||||
|   pid = strtol(p, &p, 10); | ||||
|   while (*p == ' ') ++p; | ||||
|   sec = strtol(p, &p, 10); | ||||
|   CHECK_EQ('.', *p++, DEBUG); | ||||
|   us = strtol(p, &p, 10); | ||||
|   CHECK_EQ(' ', *p++, DEBUG); | ||||
|   if (_startswith(p, "<... ")) { | ||||
|     CHECK_NOTNULL((p = strchr(p, '>'))); | ||||
|     ++p; | ||||
|     for (event = t->events.n; event--;) { | ||||
|       if (t->events.p[event].pid == pid) { | ||||
|         CHECK(t->events.p[event].is_interrupted, DEBUG); | ||||
|         t->events.p[event].is_interrupted = false; | ||||
|         t->events.p[event].elap = | ||||
|             GetDuration(t->events.p[event].sec, t->events.p[event].us, sec, us); | ||||
|         break; | ||||
|       } | ||||
|     } | ||||
|     CHECK_GE(event, 0); | ||||
|   } else { | ||||
|     AppendEvent(t); | ||||
|     event = t->events.n - 1; | ||||
|     t->events.p[event].pid = pid; | ||||
|     t->events.p[event].sec = sec; | ||||
|     t->events.p[event].us = us; | ||||
|     t->events.p[event].lineno = lineno; | ||||
|     if (_startswith(p, "+++ exited with ")) { | ||||
|       p += strlen("+++ exited with "); | ||||
|       t->events.p[event].kind = EK_EXIT; | ||||
|       t->events.p[event].ret = atoi(p); | ||||
|       return; | ||||
|     } else if (_startswith(p, "+++ killed by ")) { | ||||
|       p += strlen("+++ killed by "); | ||||
|       CHECK((q = strchr(p, ' ')), DEBUG); | ||||
|       t->events.p[event].kind = EK_KILLED; | ||||
|       t->events.p[event].ret = GetSignal(p, q - p); | ||||
|       return; | ||||
|     } else if (_startswith(p, "--- ")) { | ||||
|       p += 4; | ||||
|       CHECK(isalpha(*p), DEBUG); | ||||
|       CHECK((q = strchr(p, ' ')), DEBUG); | ||||
|       t->events.p[event].kind = EK_SIGNAL; | ||||
|       t->events.p[event].ret = GetSignal(p, q - p); | ||||
|       return; | ||||
|     } else if (isalpha(*p) && (q = strchr(p, '('))) { | ||||
|       t->events.p[event].kind = EK_CALL; | ||||
|       CHECK_NE(-1, (t->events.p[event].syscall_ = GetSyscall(p, q - p)), DEBUG); | ||||
|       p = q + 1; | ||||
|     } | ||||
|   } | ||||
|   for (;;) { | ||||
|     if (*p == ',') ++p; | ||||
|     while (*p == ' ') ++p; | ||||
|     CHECK(*p, DEBUG); | ||||
|     if (_startswith(p, "<unfinished ...>")) { | ||||
|       t->events.p[event].is_interrupted = true; | ||||
|       break; | ||||
|     } else if (*p == ')') { | ||||
|       ++p; | ||||
|       while (isspace(*p)) ++p; | ||||
|       CHECK_EQ('=', *p++, DEBUG); | ||||
|       while (isspace(*p)) ++p; | ||||
|       CHECK(isdigit(*p) || *p == '-', DEBUG); | ||||
|       t->events.p[event].ret = strtol(p, &p, 0); | ||||
|       if (t->events.p[event].ret == -1) { | ||||
|         while (isspace(*p)) ++p; | ||||
|         CHECK((q = strchr(p, ' ')), DEBUG); | ||||
|         if ((t->events.p[event].ret = GetErrno(p, q - p)) != -1) { | ||||
|           t->events.p[event].ret = -t->events.p[event].ret; | ||||
|         } | ||||
|       } | ||||
|       break; | ||||
|     } | ||||
|     CHECK_LT((arg = t->events.p[event].arity++), 6); | ||||
|     if (isalpha(*p) && !_startswith(p, "NULL")) { | ||||
|       bzero(&b, sizeof(b)); | ||||
|       for (; isalpha(*p) || *p == '_'; ++p) { | ||||
|         AppendSlice(&b, *p); | ||||
|       } | ||||
|       t->events.p[event].arg[arg].name = Intern(t, b.p, b.n); | ||||
|       CHECK_EQ('=', *p++, DEBUG); | ||||
|     } else { | ||||
|       t->events.p[event].arg[arg].name = -1; | ||||
|     } | ||||
|     if (_startswith(p, "NULL")) { | ||||
|       p += 4; | ||||
|       t->events.p[event].arg[arg].kind = AK_LONG; | ||||
|       t->events.p[event].arg[arg].x = 0; | ||||
|     } else if (*p == '-' || isdigit(*p)) { | ||||
|       t->events.p[event].arg[arg].kind = AK_LONG; | ||||
|       for (;;) { | ||||
|         t->events.p[event].arg[arg].x |= strtol(p, &p, 0); | ||||
|         if (*p == '|') { | ||||
|           ++p; | ||||
|         } else { | ||||
|           break; | ||||
|         } | ||||
|       } | ||||
|     } else if (*p == '{') { | ||||
|       CHECK_NOTNULL((p = strchr(p, '}')), DEBUG); | ||||
|       ++p; | ||||
|     } else if (*p == '"') { | ||||
|       bzero(&b, sizeof(b)); | ||||
|       for (j = 0; (c = p[++j]);) { | ||||
|         if (c == '"') { | ||||
|           p += j + 1; | ||||
|           break; | ||||
|         } | ||||
|         c = ReadCharLiteral(&b, c, p, &j); | ||||
|         AppendSlice(&b, c); | ||||
|       } | ||||
|       t->events.p[event].arg[arg].kind = AK_STR; | ||||
|       t->events.p[event].arg[arg].x = Intern(t, b.p, b.n); | ||||
|     } else if (*p == '[') { | ||||
|       ++p; | ||||
|       if (isdigit(*p)) { | ||||
|         t->events.p[event].arg[arg].kind = AK_INTPAIR; | ||||
|         t->events.p[event].arg[arg].x = strtol(p, &p, 0) & 0xffffffff; | ||||
|         CHECK_EQ(',', *p++, DEBUG); | ||||
|         CHECK_EQ(' ', *p++, DEBUG); | ||||
|         t->events.p[event].arg[arg].x |= strtol(p, &p, 0) << 32; | ||||
|         CHECK_EQ(']', *p++, DEBUG); | ||||
|       } else { | ||||
|         AppendStrlists(t); | ||||
|         for (j = 0;; ++j) { | ||||
|           if (*p == ']') { | ||||
|             ++p; | ||||
|             break; | ||||
|           } | ||||
|           if (*p == ',') ++p; | ||||
|           if (*p == ' ') ++p; | ||||
|           CHECK_EQ('"', *p, DEBUG); | ||||
|           bzero(&b, sizeof(b)); | ||||
|           for (k = 0; (c = p[++k]);) { | ||||
|             if (c == '"') { | ||||
|               p += k + 1; | ||||
|               break; | ||||
|             } | ||||
|             c = ReadCharLiteral(&b, c, p, &k); | ||||
|             AppendSlice(&b, c); | ||||
|           } | ||||
|           AppendStrlist(&t->strlists.p[t->strlists.n - 1]); | ||||
|           t->strlists.p[t->strlists.n - 1] | ||||
|               .p[t->strlists.p[t->strlists.n - 1].n - 1] = Intern(t, b.p, b.n); | ||||
|         } | ||||
|         t->events.p[event].arg[arg].kind = AK_STRLIST; | ||||
|         t->events.p[event].arg[arg].x = t->strlists.n - 1; | ||||
|       } | ||||
|     } else { | ||||
|       CHECK(false, DEBUG); | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| static void PrintArg(FILE *f, struct Trace *t, long ev, long arg) { | ||||
|   long i, x; | ||||
|   x = t->events.p[ev].arg[arg].name; | ||||
|   if (x != -1) { | ||||
|     fprintf(f, "b%`'.*s:", t->slices.p[x].n, t->slices.p[x].p); | ||||
|   } | ||||
|   x = t->events.p[ev].arg[arg].x; | ||||
|   switch (t->events.p[ev].arg[arg].kind) { | ||||
|     case AK_LONG: | ||||
|       fprintf(f, "%ld", x); | ||||
|       break; | ||||
|     case AK_STR: | ||||
|       fprintf(f, "b%`'.*s", t->slices.p[x].n, t->slices.p[x].p); | ||||
|       break; | ||||
|     case AK_INTPAIR: | ||||
|       fprintf(f, "(%d,%d)", x >> 32, x); | ||||
|       break; | ||||
|     case AK_STRLIST: | ||||
|       fprintf(f, "("); | ||||
|       for (i = 0; i < t->strlists.p[x].n; ++i) { | ||||
|         fprintf(f, "b%`'.*s,", t->slices.p[t->strlists.p[x].p[i]].n, | ||||
|                 t->slices.p[t->strlists.p[x].p[i]].p); | ||||
|       } | ||||
|       fprintf(f, ")"); | ||||
|       break; | ||||
|     default: | ||||
|       abort(); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| static void PrintEvent(FILE *f, struct Trace *t, long ev) { | ||||
|   long arg; | ||||
|   fprintf(f, "(%d,%ld,%d,%d,", t->events.p[ev].pid, | ||||
|           t->events.p[ev].sec * 1000000 + t->events.p[ev].us, | ||||
|           t->events.p[ev].elap, t->events.p[ev].kind); | ||||
|   switch (t->events.p[ev].kind) { | ||||
|     case EK_EXIT: | ||||
|     case EK_SIGNAL: | ||||
|     case EK_KILLED: | ||||
|       fprintf(f, "%d", t->events.p[ev].ret); | ||||
|       break; | ||||
|     case EK_CALL: | ||||
|       CHECK_LT(t->events.p[ev].syscall_, ARRAYLEN(kSyscalls)); | ||||
|       fprintf(f, "(b%`'s,%ld,", kSyscalls[t->events.p[ev].syscall_].name, | ||||
|               t->events.p[ev].ret); | ||||
|       fprintf(f, "%c", | ||||
|               t->events.p[ev].arity && t->events.p[ev].arg[0].name != -1 ? '{' | ||||
|                                                                          : '('); | ||||
|       for (arg = 0; arg < t->events.p[ev].arity; ++arg) { | ||||
|         PrintArg(f, t, ev, arg); | ||||
|         fprintf(f, ","); | ||||
|       } | ||||
|       fprintf(f, "%c)", | ||||
|               t->events.p[ev].arity && t->events.p[ev].arg[0].name != -1 ? '}' | ||||
|                                                                          : ')'); | ||||
|       break; | ||||
|     default: | ||||
|       break; | ||||
|   } | ||||
|   fprintf(f, ")"); | ||||
| } | ||||
| 
 | ||||
| static void AppendArg(char *arg) { | ||||
|   strace_args = realloc(strace_args, ++strace_args_len * sizeof(*strace_args)); | ||||
|   strace_args[strace_args_len - 1] = arg; | ||||
| } | ||||
| 
 | ||||
| static wontreturn void PrintUsage(FILE *f, int rc) { | ||||
|   fprintf(f, "Usage: %s [-o OUT] PROG [ARGS...]\n", program_invocation_name); | ||||
|   exit(rc); | ||||
| } | ||||
| 
 | ||||
| int main(int argc, char *argv[]) { | ||||
|   int i; | ||||
|   int ws; | ||||
|   int opt; | ||||
|   int pid; | ||||
|   long ev; | ||||
|   FILE *fin; | ||||
|   FILE *fout; | ||||
|   char *line; | ||||
|   long lineno; | ||||
|   char *strace; | ||||
|   int pipefds[2]; | ||||
|   struct Trace *t; | ||||
|   sigset_t block, mask; | ||||
|   struct sigaction ignore, saveint, savequit; | ||||
| 
 | ||||
|   /*
 | ||||
|    * parse prefix arguments | ||||
|    */ | ||||
|   fout = stderr; | ||||
|   while ((opt = getopt(argc, argv, "?ho:")) != -1) { | ||||
|     switch (opt) { | ||||
|       case 'o': | ||||
|         fout = fopen(optarg, "w"); | ||||
|         break; | ||||
|       case 'h': | ||||
|       case '?': | ||||
|         PrintUsage(stdout, EXIT_SUCCESS); | ||||
|       default: | ||||
|         PrintUsage(stderr, EX_USAGE); | ||||
|     } | ||||
|   } | ||||
|   if (optind == argc) { | ||||
|     PrintUsage(stderr, EX_USAGE); | ||||
|   } | ||||
| 
 | ||||
|   /*
 | ||||
|    * resolve full paths of dependencies | ||||
|    */ | ||||
|   if ((strace = commandvenv("STRACE", "strace"))) { | ||||
|     strace = strdup(strace); | ||||
|   } else { | ||||
|     fprintf(stderr, "error: please install strace\n"); | ||||
|     exit(1); | ||||
|   } | ||||
| 
 | ||||
|   /*
 | ||||
|    * create strace argument list | ||||
|    */ | ||||
|   AppendArg("strace"); | ||||
|   AppendArg("-q");         // don't log attach/detach noise
 | ||||
|   AppendArg("-v");         // don't abbreviate arrays
 | ||||
|   AppendArg("-f");         // follow subprocesses
 | ||||
|   AppendArg("-ttt");       // print unixseconds.micros
 | ||||
|   AppendArg("-X");         // print numbers instead of symbols
 | ||||
|   AppendArg("raw");        //   e.g. 2 vs. O_RDWR
 | ||||
|   AppendArg("-s");         // don't abbreviate data
 | ||||
|   AppendArg("805306368");  //   strace won't let us go higher
 | ||||
|   AppendArg("-e");         // system calls that matter
 | ||||
|   AppendArg( | ||||
|       "open,close,access,pipe,dup,dup2,socket,connect,accept,bind,listen," | ||||
|       "socketpair,fork,vfork,execve,clone,flock,fsync,fdatasync,truncate,chdir," | ||||
|       "rename,mkdir,rmdir,creat,link,unlink,symlink,readlink,chmod,chown,fcntl," | ||||
|       "lchown,mknod,mknodat,statfs,chroot,sync,epoll_create,openat,mkdirat," | ||||
|       "fchownat,unlinkat,renameat,linkat,symlinkat,readlinkat,fchmodat,fchdir," | ||||
|       "faccessat,utimensat,accept4,dup3,pipe2,epoll_create1,signalfd,signalfd4," | ||||
|       "eventfd,eventfd2,timerfd_create,syncfs,renameat2,memfd_create,execveat"); | ||||
|   CHECK_NE(-1, pipe(pipefds)); | ||||
|   AppendArg("-o"); | ||||
|   AppendArg(xasprintf("/dev/fd/%d", pipefds[1])); | ||||
|   for (i = optind; i < argc; ++i) { | ||||
|     AppendArg(argv[i]); | ||||
|   } | ||||
|   AppendArg(NULL); | ||||
| 
 | ||||
|   /*
 | ||||
|    * spawn strace | ||||
|    */ | ||||
|   ignore.sa_flags = 0; | ||||
|   ignore.sa_handler = SIG_IGN; | ||||
|   sigemptyset(&ignore.sa_mask); | ||||
|   sigaction(SIGINT, &ignore, &saveint); | ||||
|   sigaction(SIGQUIT, &ignore, &savequit); | ||||
|   sigfillset(&block); | ||||
|   sigprocmask(SIG_BLOCK, &block, &mask); | ||||
|   CHECK_NE(-1, (pid = vfork())); | ||||
|   if (!pid) { | ||||
|     close(pipefds[0]); | ||||
|     sigaction(SIGINT, &saveint, NULL); | ||||
|     sigaction(SIGQUIT, &savequit, NULL); | ||||
|     sigprocmask(SIG_SETMASK, &mask, NULL); | ||||
|     execv(strace, strace_args); | ||||
|     _exit(127); | ||||
|   } | ||||
|   close(pipefds[1]); | ||||
|   sigaddset(&mask, SIGCHLD); | ||||
|   sigprocmask(SIG_SETMASK, &mask, NULL); | ||||
| 
 | ||||
|   /*
 | ||||
|    * read output of strace until eof | ||||
|    */ | ||||
|   fin = fdopen(pipefds[0], "r"); | ||||
|   t = NewTrace(); | ||||
|   for (ev = 0, lineno = 1; !interrupted && (line = xgetline(fin)); ++lineno) { | ||||
|     _chomp(line); | ||||
|     Parse(t, line, lineno); | ||||
|     free(line); | ||||
|     for (; ev < t->events.n && !t->events.p[ev].is_interrupted; ++ev) { | ||||
|       PrintEvent(fout, t, ev); | ||||
|       fprintf(fout, "\n"); | ||||
|     } | ||||
|   } | ||||
|   FreeTrace(t); | ||||
|   CHECK_NE(-1, fclose(fout)); | ||||
| 
 | ||||
|   /*
 | ||||
|    * wait for strace to exit | ||||
|    */ | ||||
|   while (waitpid(pid, &ws, 0) == -1) { | ||||
|     CHECK_EQ(EINTR, errno); | ||||
|   } | ||||
|   CHECK_NE(-1, fclose(fin)); | ||||
| 
 | ||||
|   /*
 | ||||
|    * propagate exit | ||||
|    */ | ||||
|   if (WIFEXITED(ws)) { | ||||
|     return WEXITSTATUS(ws); | ||||
|   } else { | ||||
|     return 128 + WTERMSIG(ws); | ||||
|   } | ||||
| } | ||||
|  | @ -17,21 +17,27 @@ | |||
| │ PERFORMANCE OF THIS SOFTWARE.                                                │ | ||||
| ╚─────────────────────────────────────────────────────────────────────────────*/ | ||||
| #include "libc/calls/calls.h" | ||||
| #include "libc/runtime/runtime.h" | ||||
| #include "libc/stdio/stdio.h" | ||||
| #include "libc/str/str.h" | ||||
| 
 | ||||
| /**
 | ||||
|  * @fileoverview Tool for printing current directory. | ||||
|  */ | ||||
| 
 | ||||
| char path[PATH_MAX]; | ||||
| 
 | ||||
| int main(int argc, char *argv[]) { | ||||
|   char *p; | ||||
|   if ((p = getcwd(path, sizeof(path)))) { | ||||
|     fputs(p, stdout); | ||||
|     fputc('\n', stdout); | ||||
|   char path[PATH_MAX + 2]; | ||||
| 
 | ||||
|   if (!getcwd(path, PATH_MAX)) { | ||||
|     perror(argv[0]); | ||||
|     exit(1); | ||||
|   } | ||||
| 
 | ||||
|   strcat(path, "\n"); | ||||
|   if (write(1, path, strlen(path)) == -1) { | ||||
|     perror("write"); | ||||
|     exit(1); | ||||
|   } | ||||
| 
 | ||||
|   return 0; | ||||
|   } else { | ||||
|     return 1; | ||||
|   } | ||||
| } | ||||
|  |  | |||
|  | @ -1,134 +0,0 @@ | |||
| /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
 | ||||
| │vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8                                :vi│ | ||||
| ╞══════════════════════════════════════════════════════════════════════════════╡ | ||||
| │ Copyright 2020 Justine Alexandra Roberts Tunney                              │ | ||||
| │                                                                              │ | ||||
| │ Permission to use, copy, modify, and/or distribute this software for         │ | ||||
| │ any purpose with or without fee is hereby granted, provided that the         │ | ||||
| │ above copyright notice and this permission notice appear in all copies.      │ | ||||
| │                                                                              │ | ||||
| │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL                │ | ||||
| │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED                │ | ||||
| │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE             │ | ||||
| │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL         │ | ||||
| │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR        │ | ||||
| │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER               │ | ||||
| │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR             │ | ||||
| │ PERFORMANCE OF THIS SOFTWARE.                                                │ | ||||
| ╚─────────────────────────────────────────────────────────────────────────────*/ | ||||
| #include "libc/assert.h" | ||||
| #include "libc/calls/calls.h" | ||||
| #include "libc/calls/struct/dirent.h" | ||||
| #include "libc/calls/struct/stat.h" | ||||
| #include "libc/fmt/fmt.h" | ||||
| #include "libc/intrin/safemacros.internal.h" | ||||
| #include "libc/log/check.h" | ||||
| #include "libc/mem/alg.h" | ||||
| #include "libc/mem/gc.internal.h" | ||||
| #include "libc/stdio/stdio.h" | ||||
| #include "libc/str/str.h" | ||||
| #include "libc/sysv/consts/dt.h" | ||||
| #include "libc/sysv/consts/map.h" | ||||
| #include "libc/sysv/consts/o.h" | ||||
| #include "libc/sysv/consts/prot.h" | ||||
| #include "libc/x/x.h" | ||||
| 
 | ||||
| /**
 | ||||
|  * @fileoverview Pretty fast substring refactor tool. | ||||
|  */ | ||||
| 
 | ||||
| static const char kBefore[] = "\
 | ||||
| │ Copyright 2020 Justine Alexandra Roberts Tunney                              │\n\ | ||||
| │                                                                              │\n\ | ||||
| │ This program is free software; you can redistribute it and/or modify         │\n\ | ||||
| │ it under the terms of the GNU General Public License as published by         │\n\ | ||||
| │ the Free Software Foundation; version 2 of the License.                      │\n\ | ||||
| │                                                                              │\n\ | ||||
| │ This program is distributed in the hope that it will be useful, but          │\n\ | ||||
| │ WITHOUT ANY WARRANTY; without even the implied warranty of                   │\n\ | ||||
| │ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU             │\n\ | ||||
| │ General Public License for more details.                                     │\n\ | ||||
| │                                                                              │\n\ | ||||
| │ You should have received a copy of the GNU General Public License            │\n\ | ||||
| │ along with this program; if not, write to the Free Software                  │\n\ | ||||
| │ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA                │\n\ | ||||
| │ 02110-1301 USA                                                               │\n\ | ||||
| "; | ||||
| const char kAfter[] = "\
 | ||||
| │ Copyright 2020 Justine Alexandra Roberts Tunney                              │\n\ | ||||
| │                                                                              │\n\ | ||||
| │ Permission to use, copy, modify, and/or distribute this software for         │\n\ | ||||
| │ any purpose with or without fee is hereby granted, provided that the         │\n\ | ||||
| │ above copyright notice and this permission notice appear in all copies.      │\n\ | ||||
| │                                                                              │\n\ | ||||
| │ THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL                │\n\
 | ||||
| │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED                │\n\ | ||||
| │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE             │\n\ | ||||
| │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL         │\n\ | ||||
| │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR        │\n\ | ||||
| │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER               │\n\ | ||||
| │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR             │\n\ | ||||
| │ PERFORMANCE OF THIS SOFTWARE.                                                │\n\ | ||||
| "; | ||||
| 
 | ||||
| #if 0 | ||||
| static const char kBefore[] = "\
 | ||||
| /*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8     -*-│";
 | ||||
| const char kAfter[] = "\
 | ||||
| /*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8     -*-│";
 | ||||
| #endif | ||||
| 
 | ||||
| void RefactorFile(const char *path) { | ||||
|   int fd; | ||||
|   struct stat st; | ||||
|   size_t len, partlen, len1, len2; | ||||
|   char *mem, *spot = NULL, *part1, *part2; | ||||
|   CHECK_NE(-1, (fd = open(path, O_RDONLY))); | ||||
|   CHECK_NE(-1, fstat(fd, &st)); | ||||
|   len2 = 0; | ||||
|   if ((len = st.st_size)) { | ||||
|     CHECK_NE(MAP_FAILED, | ||||
|              (mem = mmap(NULL, len, PROT_READ, MAP_PRIVATE, fd, 0))); | ||||
|     partlen = sizeof(kBefore) - 1; | ||||
|     if ((spot = memmem(mem, len, kBefore, partlen))) { | ||||
|       part1 = gc(xmalloc((len1 = spot - mem))); | ||||
|       part2 = gc(xmalloc((len2 = len - partlen - (spot - mem)))); | ||||
|       memcpy(part1, mem, len1); | ||||
|       memcpy(part2, spot + partlen, len2); | ||||
|     } | ||||
|     CHECK_NE(-1, munmap(mem, len)); | ||||
|   } | ||||
|   CHECK_NE(-1, close(fd)); | ||||
|   if (spot) { | ||||
|     fprintf(stderr, "found! %s\n", path); | ||||
|     CHECK_NE(-1, (fd = open(path, O_RDWR | O_TRUNC))); | ||||
|     CHECK_EQ(len1, write(fd, part1, len1)); | ||||
|     CHECK_EQ(sizeof(kAfter) - 1, write(fd, kAfter, sizeof(kAfter) - 1)); | ||||
|     CHECK_EQ(len2, write(fd, part2, len2)); | ||||
|     CHECK_NE(-1, close(fd)); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| void RefactorDir(const char *dpath) { | ||||
|   DIR *dir; | ||||
|   struct dirent *ent; | ||||
|   char *path = gc(xmalloc(4096)); | ||||
|   CHECK_NOTNULL(dir = opendir(firstnonnull(dpath, "."))); | ||||
|   while ((ent = readdir(dir))) { | ||||
|     if (_startswith(ent->d_name, ".")) continue; | ||||
|     if (strcmp(ent->d_name, "o") == 0) continue; | ||||
|     snprintf(path, 4096, "%s%s%s", dpath ? dpath : "", dpath ? "/" : "", | ||||
|              ent->d_name); | ||||
|     if (isdirectory(path)) { | ||||
|       RefactorDir(path); | ||||
|     } else if (isregularfile(path)) { | ||||
|       RefactorFile(path); | ||||
|     } | ||||
|   } | ||||
|   CHECK_NE(-1, closedir(dir)); | ||||
| } | ||||
| 
 | ||||
| int main(int argc, char *argv[]) { | ||||
|   RefactorDir(NULL); | ||||
|   return 0; | ||||
| } | ||||
							
								
								
									
										251
									
								
								tool/build/rle.c
									
										
									
									
									
								
							
							
						
						
									
										251
									
								
								tool/build/rle.c
									
										
									
									
									
								
							|  | @ -1,251 +0,0 @@ | |||
| /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
 | ||||
| │vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8                                :vi│ | ||||
| ╞══════════════════════════════════════════════════════════════════════════════╡ | ||||
| │ Copyright 2020 Justine Alexandra Roberts Tunney                              │ | ||||
| │                                                                              │ | ||||
| │ Permission to use, copy, modify, and/or distribute this software for         │ | ||||
| │ any purpose with or without fee is hereby granted, provided that the         │ | ||||
| │ above copyright notice and this permission notice appear in all copies.      │ | ||||
| │                                                                              │ | ||||
| │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL                │ | ||||
| │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED                │ | ||||
| │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE             │ | ||||
| │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL         │ | ||||
| │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR        │ | ||||
| │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER               │ | ||||
| │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR             │ | ||||
| │ PERFORMANCE OF THIS SOFTWARE.                                                │ | ||||
| ╚─────────────────────────────────────────────────────────────────────────────*/ | ||||
| #include "libc/calls/calls.h" | ||||
| #include "libc/dce.h" | ||||
| #include "libc/errno.h" | ||||
| #include "libc/fmt/fmt.h" | ||||
| #include "libc/log/check.h" | ||||
| #include "libc/macros.internal.h" | ||||
| #include "libc/runtime/runtime.h" | ||||
| #include "libc/stdio/stdio.h" | ||||
| #include "libc/str/str.h" | ||||
| #include "libc/sysv/consts/ex.h" | ||||
| #include "libc/sysv/consts/exit.h" | ||||
| #include "libc/sysv/errfuns.h" | ||||
| #include "third_party/getopt/getopt.internal.h" | ||||
| 
 | ||||
| #define USAGE1 \ | ||||
|   "NAME\n\
 | ||||
| \n\ | ||||
|   rle - Run Length Encoder\n\ | ||||
| \n\ | ||||
| SYNOPSIS\n\ | ||||
| \n\ | ||||
|   " | ||||
| 
 | ||||
| #define USAGE2 \ | ||||
|   " [FLAGS] [FILE...]\n\
 | ||||
| \n\ | ||||
| DESCRIPTION\n\ | ||||
| \n\ | ||||
|   This is a primitive compression algorithm. Its advantage is that\n\ | ||||
|   the concomitant rldecode() library is seventeen bytes, and works\n\ | ||||
|   on IA-16, IA-32, and NexGen32e without needing to be recompiled.\n\ | ||||
| \n\ | ||||
|   This CLI is consistent with gzip, bzip2, lzma, etc.\n\ | ||||
| \n\ | ||||
| FLAGS\n\ | ||||
| \n\ | ||||
|   -1 .. -9   ignored\n\ | ||||
|   -a         ignored\n\ | ||||
|   -c         send to stdout\n\ | ||||
|   -d         decompress\n\ | ||||
|   -f         ignored\n\ | ||||
|   -t         test integrity\n\ | ||||
|   -S SUFFIX  overrides .rle extension\n\ | ||||
|   -h         shows this information\n" | ||||
| 
 | ||||
| FILE *fin_, *fout_; | ||||
| bool decompress_, test_; | ||||
| const char *suffix_, *hint_; | ||||
| 
 | ||||
| void StartErrorMessage(void) { | ||||
|   fputs("error: ", stderr); | ||||
|   fputs(hint_, stderr); | ||||
|   fputs(": ", stderr); | ||||
| } | ||||
| 
 | ||||
| void PrintIoErrorMessage(void) { | ||||
|   int err; | ||||
|   err = errno; | ||||
|   StartErrorMessage(); | ||||
|   fputs(strerror(err), stderr); | ||||
|   fputc('\n', stderr); | ||||
| } | ||||
| 
 | ||||
| void PrintUsage(int rc, FILE *f) { | ||||
|   fputs(USAGE1, f); | ||||
|   fputs(program_invocation_name, f); | ||||
|   fputs(USAGE2, f); | ||||
|   exit(rc); | ||||
| } | ||||
| 
 | ||||
| void GetOpts(int argc, char *argv[]) { | ||||
|   int opt; | ||||
|   fin_ = stdin; | ||||
|   suffix_ = ".rle"; | ||||
|   while ((opt = getopt(argc, argv, "123456789S:acdfho:t")) != -1) { | ||||
|     switch (opt) { | ||||
|       case '1': | ||||
|       case '2': | ||||
|       case '3': | ||||
|       case '4': | ||||
|       case '5': | ||||
|       case '6': | ||||
|       case '7': | ||||
|       case '8': | ||||
|       case '9': | ||||
|       case 'a': | ||||
|       case 'f': | ||||
|         break; | ||||
|       case 'c': | ||||
|         fout_ = stdout; | ||||
|         break; | ||||
|       case 'd': | ||||
|         decompress_ = true; | ||||
|         break; | ||||
|       case 't': | ||||
|         test_ = true; | ||||
|         break; | ||||
|       case 'o': | ||||
|         fclose(fout_); | ||||
|         if (!(fout_ = fopen((hint_ = optarg), "w"))) { | ||||
|           PrintIoErrorMessage(); | ||||
|           exit(1); | ||||
|         } | ||||
|         break; | ||||
|       case 'S': | ||||
|         suffix_ = optarg; | ||||
|         break; | ||||
|       case 'h': | ||||
|       case '?': | ||||
|         PrintUsage(EXIT_SUCCESS, stdout); | ||||
|       default: | ||||
|         PrintUsage(EX_USAGE, stderr); | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| int RunLengthEncode1(void) { | ||||
|   int byte1, byte2, runlength; | ||||
|   byte2 = -1; | ||||
|   runlength = 0; | ||||
|   if ((byte1 = fgetc(fin_)) == -1) return -1; | ||||
|   do { | ||||
|     while (++runlength < 255) { | ||||
|       if ((byte2 = fgetc(fin_)) != byte1) break; | ||||
|     } | ||||
|     if (fputc(runlength, fout_) == -1 || fputc(byte1, fout_) == -1) { | ||||
|       return -1; | ||||
|     } | ||||
|     runlength = 0; | ||||
|   } while ((byte1 = byte2) != -1); | ||||
|   return feof(fin_) ? 0 : -1; | ||||
| } | ||||
| 
 | ||||
| int RunLengthEncode2(void) { | ||||
|   return fputc(0, fout_) | fputc(0, fout_); | ||||
| } | ||||
| 
 | ||||
| int EmitRun(unsigned char count, unsigned char byte) { | ||||
|   do { | ||||
|     if (fputc(byte, fout_) == -1) return -1; | ||||
|   } while (--count); | ||||
|   return 0; | ||||
| } | ||||
| 
 | ||||
| int RunLengthDecode(void) { | ||||
|   int byte1, byte2; | ||||
|   if ((byte1 = fgetc(fin_)) == -1) return einval(); | ||||
|   if ((byte2 = fgetc(fin_)) == -1) return einval(); | ||||
|   while (byte1) { | ||||
|     if (!test_ && EmitRun(byte1, byte2) == -1) return -1; | ||||
|     if ((byte1 = fgetc(fin_)) == -1) break; | ||||
|     if ((byte2 = fgetc(fin_)) == -1) return einval(); | ||||
|   } | ||||
|   if (byte1 != 0 || byte2 != 0) return einval(); | ||||
|   fgetc(fin_); | ||||
|   return feof(fin_) ? 0 : -1; | ||||
| } | ||||
| 
 | ||||
| int RunLengthCode(void) { | ||||
|   if (test_ || decompress_) { | ||||
|     return RunLengthDecode(); | ||||
|   } else { | ||||
|     return RunLengthEncode1(); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| int Run(char **paths, size_t count) { | ||||
|   int rc; | ||||
|   char *p; | ||||
|   size_t i, suffixlen; | ||||
|   const char pathbuf[PATH_MAX]; | ||||
|   if (!count) { | ||||
|     hint_ = "/dev/stdin"; | ||||
|     if (!fout_) fout_ = stdout; | ||||
|     rc = RunLengthCode(); | ||||
|     rc |= fclose(fin_); | ||||
|     fin_ = 0; | ||||
|   } else { | ||||
|     rc = fclose(fin_); | ||||
|     fin_ = 0; | ||||
|     for (i = 0; i < count && rc != -1; ++i) { | ||||
|       rc = -1; | ||||
|       if ((fin_ = fopen((hint_ = paths[i]), "r"))) { | ||||
|         if (test_ || fout_) { | ||||
|           rc = RunLengthCode(); | ||||
|         } else { | ||||
|           suffixlen = strlen(suffix_); | ||||
|           if (!IsTrustworthy() && | ||||
|               strlen(paths[i]) + suffixlen >= ARRAYLEN(pathbuf)) { | ||||
|             return eoverflow(); | ||||
|           } | ||||
|           p = stpcpy(pathbuf, paths[i]); | ||||
|           if (!decompress_) { | ||||
|             strcpy(p, suffix_); | ||||
|           } else if (p - pathbuf > suffixlen && | ||||
|                      memcmp(p - suffixlen, suffix_, suffixlen) == 0) { | ||||
|             p[-suffixlen] = '\0'; | ||||
|           } else { | ||||
|             return enotsup(); | ||||
|           } | ||||
|           if ((fout_ = fopen((hint_ = pathbuf), "w"))) { | ||||
|             rc = RunLengthCode(); | ||||
|             if (rc != -1 && !decompress_) { | ||||
|               rc = RunLengthEncode2(); | ||||
|             } | ||||
|             if ((rc |= fclose(fout_)) != -1) { | ||||
|               unlink(paths[i]); | ||||
|             } | ||||
|             fout_ = 0; | ||||
|           } | ||||
|         } | ||||
|         rc |= fclose(fin_); | ||||
|         fin_ = 0; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|   if (rc != -1 && fout_) { | ||||
|     rc = RunLengthEncode2(); | ||||
|     rc |= fclose(fout_); | ||||
|     fout_ = 0; | ||||
|   } | ||||
|   return rc; | ||||
| } | ||||
| 
 | ||||
| int main(int argc, char *argv[]) { | ||||
|   GetOpts(argc, argv); | ||||
|   if (Run(argv + optind, argc - optind) != -1) { | ||||
|     return EXIT_SUCCESS; | ||||
|   } else { | ||||
|     PrintIoErrorMessage(); | ||||
|     return EXIT_FAILURE; | ||||
|   } | ||||
| } | ||||
|  | @ -22,8 +22,6 @@ | |||
| #include "libc/runtime/runtime.h" | ||||
| #include "libc/stdio/stdio.h" | ||||
| #include "libc/str/str.h" | ||||
| #include "libc/sysv/consts/ex.h" | ||||
| #include "libc/sysv/consts/exit.h" | ||||
| #include "libc/sysv/consts/ok.h" | ||||
| #include "third_party/getopt/getopt.internal.h" | ||||
| 
 | ||||
|  | @ -36,63 +34,53 @@ SYNOPSIS\n\ | |||
| \n\ | ||||
| FLAGS\n\ | ||||
| \n\ | ||||
|   -?\n\ | ||||
|   -h      help\n\ | ||||
|   -f      force\n\ | ||||
| \n" | ||||
| 
 | ||||
| bool force; | ||||
| const char *prog; | ||||
| static bool force; | ||||
| static const char *prog; | ||||
| 
 | ||||
| wontreturn void PrintUsage(int rc, FILE *f) { | ||||
|   fputs("usage: ", f); | ||||
|   fputs(prog, f); | ||||
|   fputs(USAGE, f); | ||||
| static wontreturn void PrintUsage(int rc, int fd) { | ||||
|   tinyprint(fd, "USAGE\n\n  ", prog, USAGE, NULL); | ||||
|   exit(rc); | ||||
| } | ||||
| 
 | ||||
| void GetOpts(int argc, char *argv[]) { | ||||
| static void GetOpts(int argc, char *argv[]) { | ||||
|   int opt; | ||||
|   while ((opt = getopt(argc, argv, "?hf")) != -1) { | ||||
|   while ((opt = getopt(argc, argv, "hf")) != -1) { | ||||
|     switch (opt) { | ||||
|       case 'f': | ||||
|         force = true; | ||||
|         break; | ||||
|       case 'h': | ||||
|       case '?': | ||||
|         PrintUsage(EXIT_SUCCESS, stdout); | ||||
|         PrintUsage(0, 1); | ||||
|       default: | ||||
|         PrintUsage(EX_USAGE, stderr); | ||||
|         PrintUsage(1, 2); | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| void Remove(const char *path) { | ||||
|   const char *s; | ||||
|   if (!force && access(path, W_OK) == -1) goto OnFail; | ||||
|   if (unlink(path) == -1) goto OnFail; | ||||
|   return; | ||||
| OnFail: | ||||
|   if (force && errno == ENOENT) return; | ||||
|   s = _strerdoc(errno); | ||||
|   fputs(prog, stderr); | ||||
|   fputs(": cannot remove '", stderr); | ||||
|   fputs(path, stderr); | ||||
|   fputs("': ", stderr); | ||||
|   fputs(s, stderr); | ||||
|   fputs("\n", stderr); | ||||
| static void Remove(const char *path) { | ||||
|   if (!force && access(path, W_OK) == -1) { | ||||
|     perror(path); | ||||
|     exit(1); | ||||
|   } | ||||
|   if (unlink(path) == -1) { | ||||
|     if (force && errno == ENOENT) return; | ||||
|     perror(path); | ||||
|     exit(1); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| int main(int argc, char *argv[]) { | ||||
|   int i; | ||||
|   prog = argc > 0 ? argv[0] : "rm.com"; | ||||
| 
 | ||||
|   prog = argv[0]; | ||||
|   if (!prog) prog = "rm"; | ||||
| 
 | ||||
|   if (argc < 2) { | ||||
|     fputs(prog, stderr); | ||||
|     fputs(": missing operand\n" | ||||
|           "Try 'rm -h' for more information.\n", | ||||
|           stderr); | ||||
|     tinyprint(2, prog, ": missing operand\n", NULL); | ||||
|     exit(1); | ||||
|   } | ||||
| 
 | ||||
|  |  | |||
|  | @ -28,17 +28,15 @@ | |||
| #include "third_party/getopt/getopt.internal.h" | ||||
| #include "third_party/mbedtls/sha256.h" | ||||
| 
 | ||||
| #define PROG "sha256sum" | ||||
| #define USAGE \ | ||||
|   "\
 | ||||
| Usage: " PROG " [-?hbctw] [PATH...]\n\ | ||||
|   "[-?hbctw] [PATH...]\n\
 | ||||
|   -h          help\n\ | ||||
|   -c          check mode\n\ | ||||
|   -b          binary mode\n\ | ||||
|   -t          textual mode\n\ | ||||
|   -w          warning mode\n\ | ||||
| \n\ | ||||
| cosmopolitan " PROG " v1.0\n\ | ||||
| cosmopolitan sha256sum v1.1\n\ | ||||
| copyright 2022 justine alexandra roberts tunney\n\ | ||||
| notice licenses are embedded in the binary\n\ | ||||
| https://twitter.com/justinetunney\n\ | ||||
|  | @ -56,11 +54,17 @@ static bool g_warn; | |||
| static char g_mode; | ||||
| static bool g_check; | ||||
| static int g_mismatches; | ||||
| static const char *prog; | ||||
| 
 | ||||
| static wontreturn void PrintUsage(int rc, int fd) { | ||||
|   tinyprint(fd, "Usage: ", prog, USAGE, NULL); | ||||
|   exit(rc); | ||||
| } | ||||
| 
 | ||||
| static void GetOpts(int argc, char *argv[]) { | ||||
|   int opt; | ||||
|   g_mode = ' '; | ||||
|   while ((opt = getopt(argc, argv, "?hbctw")) != -1) { | ||||
|   while ((opt = getopt(argc, argv, "hbctw")) != -1) { | ||||
|     switch (opt) { | ||||
|       case 'w': | ||||
|         g_warn = true; | ||||
|  | @ -75,28 +79,13 @@ static void GetOpts(int argc, char *argv[]) { | |||
|         g_mode = '*'; | ||||
|         break; | ||||
|       case 'h': | ||||
|       case '?': | ||||
|         write(1, USAGE, sizeof(USAGE) - 1); | ||||
|         exit(0); | ||||
|         PrintUsage(0, 1); | ||||
|       default: | ||||
|         write(2, USAGE, sizeof(USAGE) - 1); | ||||
|         exit(64); | ||||
|         PrintUsage(1, 2); | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| static ssize_t Write(int fd, const char *s, ...) { | ||||
|   va_list va; | ||||
|   char buf[512]; | ||||
|   buf[0] = 0; | ||||
|   va_start(va, s); | ||||
|   do { | ||||
|     strlcat(buf, s, sizeof(buf)); | ||||
|   } while ((s = va_arg(va, const char *))); | ||||
|   va_end(va); | ||||
|   return write(fd, buf, strlen(buf)); | ||||
| } | ||||
| 
 | ||||
| static bool IsModeCharacter(char c) { | ||||
|   switch (c) { | ||||
|     case ' ': | ||||
|  | @ -117,7 +106,7 @@ static bool IsSupportedPath(const char *path) { | |||
|       case '\r': | ||||
|       case '\n': | ||||
|       case '\\': | ||||
|         Write(2, PROG, ": ", path, ": unsupported path\n", NULL); | ||||
|         tinyprint(2, prog, ": ", path, ": unsupported path\n", NULL); | ||||
|         return false; | ||||
|       default: | ||||
|         break; | ||||
|  | @ -135,7 +124,7 @@ static bool GetDigest(const char *path, FILE *f, unsigned char digest[32]) { | |||
|     _unassert(!mbedtls_sha256_update_ret(&ctx, buf, got)); | ||||
|   } | ||||
|   if (ferror(f)) { | ||||
|     Write(2, PROG, ": ", path, ": ", _strerdoc(errno), "\n", NULL); | ||||
|     tinyprint(2, prog, ": ", path, ": ", strerror(errno), "\n", NULL); | ||||
|     return false; | ||||
|   } | ||||
|   _unassert(!mbedtls_sha256_finish_ret(&ctx, digest)); | ||||
|  | @ -150,7 +139,7 @@ static bool ProduceDigest(const char *path, FILE *f) { | |||
|   if (!IsSupportedPath(path)) return false; | ||||
|   if (!GetDigest(path, f, digest)) return false; | ||||
|   hexpcpy(hexdigest, digest, 32); | ||||
|   Write(1, hexdigest, " ", mode, path, "\n", NULL); | ||||
|   tinyprint(1, hexdigest, " ", mode, path, "\n", NULL); | ||||
|   return true; | ||||
| } | ||||
| 
 | ||||
|  | @ -182,13 +171,13 @@ static bool CheckDigests(const char *path, FILE *f) { | |||
|           ++g_mismatches; | ||||
|           k = false; | ||||
|         } | ||||
|         Write(1, path2, ": ", status, "\n", NULL); | ||||
|         tinyprint(1, path2, ": ", status, "\n", NULL); | ||||
|       } else { | ||||
|         k = false; | ||||
|       } | ||||
|       fclose(f2); | ||||
|     } else { | ||||
|       Write(2, PROG, ": ", path2, ": ", _strerdoc(errno), "\n", NULL); | ||||
|       tinyprint(2, prog, ": ", path2, ": ", strerror(errno), "\n", NULL); | ||||
|       k = false; | ||||
|     } | ||||
|     continue; | ||||
|  | @ -196,12 +185,12 @@ static bool CheckDigests(const char *path, FILE *f) { | |||
|     if (g_warn) { | ||||
|       char linestr[12]; | ||||
|       FormatInt32(linestr, line + 1); | ||||
|       Write(2, PROG, ": ", path, ":", linestr, ": ", | ||||
|       tinyprint(2, prog, ": ", path, ":", linestr, ": ", | ||||
|                 "improperly formatted checksum line", "\n", NULL); | ||||
|     } | ||||
|   } | ||||
|   if (ferror(f)) { | ||||
|     Write(2, PROG, ": ", path, ": ", _strerdoc(errno), "\n", NULL); | ||||
|     tinyprint(2, prog, ": ", path, ": ", strerror(errno), "\n", NULL); | ||||
|     k = false; | ||||
|   } | ||||
|   return k; | ||||
|  | @ -219,6 +208,8 @@ int main(int argc, char *argv[]) { | |||
|   int i; | ||||
|   FILE *f; | ||||
|   bool k = true; | ||||
|   prog = argv[0]; | ||||
|   if (!prog) prog = "sha256sum"; | ||||
|   GetOpts(argc, argv); | ||||
|   if (optind == argc) { | ||||
|     f = stdin; | ||||
|  | @ -229,7 +220,7 @@ int main(int argc, char *argv[]) { | |||
|         k &= Process(argv[i], f); | ||||
|         fclose(f); | ||||
|       } else { | ||||
|         Write(2, PROG, ": ", argv[i], ": ", _strerdoc(errno), "\n", NULL); | ||||
|         tinyprint(2, prog, ": ", argv[i], ": ", strerror(errno), "\n", NULL); | ||||
|         k = false; | ||||
|       } | ||||
|     } | ||||
|  | @ -237,8 +228,8 @@ int main(int argc, char *argv[]) { | |||
|   if (g_mismatches) { | ||||
|     char ibuf[12]; | ||||
|     FormatInt32(ibuf, g_mismatches); | ||||
|     Write(2, PROG, ": WARNING: ", ibuf, " computed checksum did NOT match\n", | ||||
|           NULL); | ||||
|     tinyprint(2, prog, ": WARNING: ", ibuf, | ||||
|               " computed checksum did NOT match\n", NULL); | ||||
|   } | ||||
|   return !k; | ||||
| } | ||||
|  |  | |||
|  | @ -17,31 +17,31 @@ | |||
| │ PERFORMANCE OF THIS SOFTWARE.                                                │ | ||||
| ╚─────────────────────────────────────────────────────────────────────────────*/ | ||||
| #include "libc/calls/calls.h" | ||||
| #include "libc/errno.h" | ||||
| #include "libc/fmt/magnumstrs.internal.h" | ||||
| #include "libc/runtime/runtime.h" | ||||
| #include "libc/stdio/stdio.h" | ||||
| #include "libc/str/str.h" | ||||
| 
 | ||||
| /**
 | ||||
|  * @fileoverview Command for updating timestamps on files. | ||||
|  * @fileoverview file timestamp update command | ||||
|  */ | ||||
| 
 | ||||
| int main(int argc, char *argv[]) { | ||||
|   int i; | ||||
|   const char *s, *prog; | ||||
|   prog = argc > 0 ? argv[0] : "touch.com"; | ||||
|   const char *prog; | ||||
| 
 | ||||
|   prog = argv[0]; | ||||
|   if (!prog) prog = "touch"; | ||||
| 
 | ||||
|   if (argc < 2) { | ||||
|     tinyprint(2, prog, ": missing operand\n", NULL); | ||||
|     exit(1); | ||||
|   } | ||||
| 
 | ||||
|   for (i = 1; i < argc; ++i) { | ||||
|     if (touch(argv[i], 0666) == -1) { | ||||
|       s = _strerdoc(errno); | ||||
|       fputs(prog, stderr); | ||||
|       fputs(": cannot touch '", stderr); | ||||
|       fputs(argv[i], stderr); | ||||
|       fputs("': ", stderr); | ||||
|       fputs(s, stderr); | ||||
|       fputs("\n", stderr); | ||||
|       perror(argv[i]); | ||||
|       exit(1); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   return 0; | ||||
| } | ||||
|  |  | |||
|  | @ -74,7 +74,8 @@ int Visit(const char *fpath, const struct stat *sb, int tflag, | |||
| 
 | ||||
| int main(int argc, char *argv[]) { | ||||
|   if (!IsLinux()) return 0; | ||||
|   prog = argc > 0 ? argv[0] : "unbundle.com"; | ||||
|   prog = argv[0]; | ||||
|   if (!prog) prog = "unbundle"; | ||||
|   if (IsDirectory("o/third_party/gcc")) return 0; | ||||
|   makedirs("o/third_party", 0755); | ||||
|   FormatInt32(stpcpy(tmpdir, "o/third_party/gcc."), getpid()); | ||||
|  |  | |||
|  | @ -1,330 +0,0 @@ | |||
| /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
 | ||||
| │vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8                                :vi│ | ||||
| ╞══════════════════════════════════════════════════════════════════════════════╡ | ||||
| │ Copyright 2022 Justine Alexandra Roberts Tunney                              │ | ||||
| │                                                                              │ | ||||
| │ Permission to use, copy, modify, and/or distribute this software for         │ | ||||
| │ any purpose with or without fee is hereby granted, provided that the         │ | ||||
| │ above copyright notice and this permission notice appear in all copies.      │ | ||||
| │                                                                              │ | ||||
| │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL                │ | ||||
| │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED                │ | ||||
| │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE             │ | ||||
| │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL         │ | ||||
| │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR        │ | ||||
| │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER               │ | ||||
| │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR             │ | ||||
| │ PERFORMANCE OF THIS SOFTWARE.                                                │ | ||||
| ╚─────────────────────────────────────────────────────────────────────────────*/ | ||||
| #include "libc/assert.h" | ||||
| #include "libc/calls/calls.h" | ||||
| #include "libc/fmt/conv.h" | ||||
| #include "libc/log/check.h" | ||||
| #include "libc/math.h" | ||||
| #include "libc/mem/gc.h" | ||||
| #include "libc/mem/mem.h" | ||||
| #include "libc/runtime/runtime.h" | ||||
| #include "libc/stdio/stdio.h" | ||||
| #include "libc/str/str.h" | ||||
| #include "libc/str/tab.internal.h" | ||||
| #include "libc/x/xasprintf.h" | ||||
| 
 | ||||
| /**
 | ||||
|  * @fileoverview Tool for generating rldecode'd character sets, e.g. | ||||
|  * | ||||
|  *     # generate http token table | ||||
|  *     o//tool/build/xlat.com -TiC ' ()<>@,;:\"/[]?={}' -i
 | ||||
|  */ | ||||
| 
 | ||||
| int dig; | ||||
| int xlat[256]; | ||||
| bool identity; | ||||
| const char *symbol; | ||||
| 
 | ||||
| static int Bing(int c) { | ||||
|   if (!c) return L'∅'; | ||||
|   if (c == ' ') return L'␠'; | ||||
|   if (c == '$') return L'§'; | ||||
|   if (c == '\\') return L'⭝'; | ||||
|   return kCp437[c & 255]; | ||||
| } | ||||
| 
 | ||||
| static void Fill(int f(int)) { | ||||
|   int i; | ||||
|   for (i = 0; i < 256; ++i) { | ||||
|     if (f(i)) { | ||||
|       xlat[i] = identity ? i : 1; | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| static void Invert(void) { | ||||
|   int i; | ||||
|   for (i = 0; i < 256; ++i) { | ||||
|     xlat[i] = !xlat[i]; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| static void Negate(void) { | ||||
|   int i; | ||||
|   for (i = 0; i < 256; ++i) { | ||||
|     xlat[i] = ~xlat[i] & 255; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| static void Negative(void) { | ||||
|   int i; | ||||
|   for (i = 0; i < 256; ++i) { | ||||
|     xlat[i] = -xlat[i] & 255; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| static bool ArgNeedsShellQuotes(const char *s) { | ||||
|   if (*s) { | ||||
|     for (;;) { | ||||
|       switch (*s++ & 255) { | ||||
|         case 0: | ||||
|           return false; | ||||
|         case '-': | ||||
|         case '.': | ||||
|         case '/': | ||||
|         case '_': | ||||
|         case '=': | ||||
|         case ':': | ||||
|         case '0' ... '9': | ||||
|         case 'A' ... 'Z': | ||||
|         case 'a' ... 'z': | ||||
|           break; | ||||
|         default: | ||||
|           return true; | ||||
|       } | ||||
|     } | ||||
|   } else { | ||||
|     return true; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| static char *AddShellQuotes(const char *s) { | ||||
|   char *p, *q; | ||||
|   size_t i, j, n; | ||||
|   n = strlen(s); | ||||
|   p = malloc(1 + n * 5 + 1 + 1); | ||||
|   j = 0; | ||||
|   p[j++] = '\''; | ||||
|   for (i = 0; i < n; ++i) { | ||||
|     if (s[i] != '\'') { | ||||
|       p[j++] = s[i]; | ||||
|     } else { | ||||
|       p[j + 0] = '\''; | ||||
|       p[j + 1] = '"'; | ||||
|       p[j + 2] = '\''; | ||||
|       p[j + 3] = '"'; | ||||
|       p[j + 4] = '\''; | ||||
|       j += 5; | ||||
|     } | ||||
|   } | ||||
|   p[j++] = '\''; | ||||
|   p[j] = 0; | ||||
|   if ((q = realloc(p, j + 1))) p = q; | ||||
|   return p; | ||||
| } | ||||
| 
 | ||||
| static const char *GetArg(char *argv[], int i, int *k) { | ||||
|   if (argv[*k][i + 1]) { | ||||
|     return argv[*k] + i + 1; | ||||
|   } else { | ||||
|     return argv[++*k]; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| int main(int argc, char *argv[]) { | ||||
|   const char *arg; | ||||
|   int i, j, k, opt; | ||||
|   dig = 1; | ||||
|   symbol = "kXlatTab"; | ||||
| 
 | ||||
|   for (k = 1; k < argc; ++k) { | ||||
|     if (argv[k][0] != '-') { | ||||
|       for (i = 0; argv[k][i]; ++i) { | ||||
|         /* xlat[argv[k][i] & 255] = identity ? i : dig; */ | ||||
|         xlat[argv[k][i] & 255] = identity ? (argv[k][i] & 255) : dig; | ||||
|       } | ||||
|     } else { | ||||
|       i = 0; | ||||
|     moar: | ||||
|       ++i; | ||||
|       if ((opt = argv[k][i])) { | ||||
|         switch (opt) { | ||||
|           case 's': | ||||
|             symbol = GetArg(argv, i, &k); | ||||
|             break; | ||||
|           case 'x': | ||||
|             dig = atoi(GetArg(argv, i, &k)) & 255; | ||||
|             break; | ||||
|           case 'i': | ||||
|             Invert(); | ||||
|             goto moar; | ||||
|           case 'I': | ||||
|             identity = !identity; | ||||
|             goto moar; | ||||
|           case 'n': | ||||
|             Negative(); | ||||
|             goto moar; | ||||
|           case 'N': | ||||
|             Negate(); | ||||
|             goto moar; | ||||
|           case 'T': | ||||
|             Fill(isascii); | ||||
|             goto moar; | ||||
|           case 'C': | ||||
|             Fill(iscntrl); | ||||
|             goto moar; | ||||
|           case 'A': | ||||
|             Fill(isalpha); | ||||
|             goto moar; | ||||
|           case 'B': | ||||
|             Fill(isblank); | ||||
|             goto moar; | ||||
|           case 'G': | ||||
|             Fill(isgraph); | ||||
|             goto moar; | ||||
|           case 'P': | ||||
|             Fill(ispunct); | ||||
|             goto moar; | ||||
|           case 'D': | ||||
|             Fill(isdigit); | ||||
|             goto moar; | ||||
|           case 'U': | ||||
|             Fill(isupper); | ||||
|             goto moar; | ||||
|           case 'L': | ||||
|             Fill(islower); | ||||
|             goto moar; | ||||
|           default: | ||||
|             fprintf(stderr, "error: unrecognized option: %c\n", opt); | ||||
|             return 1; | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   ////////////////////////////////////////////////////////////
 | ||||
|   printf("#include \"libc/macros.internal.h\"\n"); | ||||
|   printf("\n"); | ||||
| 
 | ||||
|   printf("//\tgenerated by:\n"); | ||||
|   printf("//\t"); | ||||
|   for (i = 0; i < argc; ++i) { | ||||
|     if (i) printf(" "); | ||||
|     printf("%s", !ArgNeedsShellQuotes(argv[i]) ? argv[i] | ||||
|                                                : _gc(AddShellQuotes(argv[i]))); | ||||
|   } | ||||
|   printf("\n"); | ||||
| 
 | ||||
|   ////////////////////////////////////////////////////////////
 | ||||
|   printf("//\n"); | ||||
|   printf("//\t    present            absent\n"); | ||||
|   printf("//\t    ────────────────   ────────────────\n"); | ||||
|   for (i = 0; i < 16; ++i) { | ||||
|     char16_t absent[16]; | ||||
|     char16_t present[16]; | ||||
|     for (j = 0; j < 16; ++j) { | ||||
|       if (xlat[i * 16 + j]) { | ||||
|         absent[j] = L' '; | ||||
|         present[j] = Bing(i * 16 + j); | ||||
|       } else { | ||||
|         absent[j] = Bing(i * 16 + j); | ||||
|         present[j] = L' '; | ||||
|       } | ||||
|     } | ||||
|     printf("//\t    %.16hs   %.16hs   0x%02x\n", present, absent, i * 16); | ||||
|   } | ||||
| 
 | ||||
|   ////////////////////////////////////////////////////////////
 | ||||
|   printf("//\n"); | ||||
|   printf("//\tconst char %s[256] = {\n//\t", symbol); | ||||
|   for (i = 0; i < 16; ++i) { | ||||
|     printf("  "); | ||||
|     for (j = 0; j < 16; ++j) { | ||||
|       printf("%2d,", (char)xlat[i * 16 + j]); | ||||
|     } | ||||
|     printf(" // 0x%02x\n//\t", i * 16); | ||||
|   } | ||||
|   printf("};\n"); | ||||
|   printf("\n"); | ||||
| 
 | ||||
|   ////////////////////////////////////////////////////////////
 | ||||
|   printf("\t.initbss 300,_init_%s\n", symbol); | ||||
|   printf("%s:\n", symbol); | ||||
|   printf("\t.zero\t256\n"); | ||||
|   printf("\t.endobj\t%s,globl\n", symbol); | ||||
|   printf("\t.previous\n"); | ||||
|   printf("\n"); | ||||
| 
 | ||||
|   ////////////////////////////////////////////////////////////
 | ||||
|   printf("\t.initro 300,_init_%s\n", symbol); | ||||
|   printf("%s.rom:\n", symbol); | ||||
| 
 | ||||
|   int thebloat = 0; | ||||
|   int thetally = 0; | ||||
|   int thecount = 0; | ||||
|   int runstart = 0; | ||||
|   int runchar = -1; | ||||
|   int runcount = 0; | ||||
|   for (i = 0;; ++i) { | ||||
|     if (i < 256 && xlat[i] == runchar) { | ||||
|       ++runcount; | ||||
|     } else { | ||||
|       if (runcount) { | ||||
|         printf("\t.byte\t%-24s# %02x-%02x %hc-%hc\n", | ||||
|                _gc(xasprintf("%3d,%d", runcount, runchar)), runstart, | ||||
|                runstart + runcount - 1, Bing(runstart), | ||||
|                Bing(runstart + runcount - 1)); | ||||
|         thetally += 2; | ||||
|         thecount += runcount; | ||||
|       } | ||||
|       if (i < 256) { | ||||
|         runcount = 1; | ||||
|         runchar = xlat[i]; | ||||
|         runstart = i; | ||||
|       } | ||||
|     } | ||||
|     if (i == 256) { | ||||
|       break; | ||||
|     } | ||||
|   } | ||||
|   CHECK_EQ(256, thecount); | ||||
|   printf("\t.byte\t%-24s# terminator\n", "0,0"); | ||||
|   thetally += 2; | ||||
|   thebloat = thetally; | ||||
|   for (i = 0; (thetally + i) % 8; i += 2) { | ||||
|     printf("\t.byte\t%-24s# padding\n", "0,0"); | ||||
|     thebloat += 2; | ||||
|   } | ||||
| 
 | ||||
|   printf("\t.endobj\t%s.rom,globl\n", symbol); | ||||
|   printf("\n"); | ||||
| 
 | ||||
|   ////////////////////////////////////////////////////////////
 | ||||
|   printf("\t.init.start 300,_init_%s\n", symbol); | ||||
|   printf("\tcall\trldecode\n"); | ||||
|   thebloat += 5; | ||||
|   int padding = 8 - thetally % 8; | ||||
|   if (padding < 8) { | ||||
|     if (padding >= 4) { | ||||
|       thebloat += 1; | ||||
|       printf("\tlodsl\n"); | ||||
|       padding -= 4; | ||||
|     } | ||||
|     if (padding >= 2) { | ||||
|       thebloat += 2; | ||||
|       printf("\tlodsw\n"); | ||||
|     } | ||||
|   } | ||||
|   printf("\t.init.end 300,_init_%s\n", symbol); | ||||
| 
 | ||||
|   ////////////////////////////////////////////////////////////
 | ||||
|   printf("\n"); | ||||
|   printf("//\t%d bytes total (%d%% original size)\n", thebloat, | ||||
|          (int)round((double)thebloat / 256 * 100)); | ||||
| } | ||||
|  | @ -38,32 +38,20 @@ static const char *inpath; | |||
| static const char *outpath; | ||||
| static unsigned char *inmap; | ||||
| 
 | ||||
| nullterminated() static void Print(int fd, const char *s, ...) { | ||||
|   va_list va; | ||||
|   char buf[2048]; | ||||
|   va_start(va, s); | ||||
|   buf[0] = 0; | ||||
|   do { | ||||
|     strlcat(buf, s, sizeof(buf)); | ||||
|   } while ((s = va_arg(va, const char *))); | ||||
|   write(fd, buf, strlen(buf)); | ||||
|   va_end(va); | ||||
| } | ||||
| 
 | ||||
| static wontreturn void Die(const char *path, const char *reason) { | ||||
|   Print(2, path, ": ", reason, "\n", NULL); | ||||
|   tinyprint(2, path, ": ", reason, "\n", NULL); | ||||
|   exit(1); | ||||
| } | ||||
| 
 | ||||
| static wontreturn void SysExit(const char *path, const char *func) { | ||||
| static wontreturn void SysDie(const char *path, const char *func) { | ||||
|   const char *errstr; | ||||
|   if (!(errstr = _strerdoc(errno))) errstr = "EUNKNOWN"; | ||||
|   Print(2, path, ": ", func, " failed with ", errstr, "\n", NULL); | ||||
|   tinyprint(2, path, ": ", func, " failed with ", errstr, "\n", NULL); | ||||
|   exit(1); | ||||
| } | ||||
| 
 | ||||
| static wontreturn void PrintUsage(int fd, int exitcode) { | ||||
|   Print(fd, "\
 | ||||
|   tinyprint(fd, "\
 | ||||
| NAME\n\ | ||||
| \n\ | ||||
|   Cosmopolitan Zip Copier\n\ | ||||
|  | @ -173,10 +161,10 @@ static void CopyZip(void) { | |||
| 
 | ||||
|   // write output
 | ||||
|   if ((outfd = open(outpath, O_WRONLY | O_CREAT, 0644)) == -1) { | ||||
|     SysExit(outpath, "open"); | ||||
|     SysDie(outpath, "open"); | ||||
|   } | ||||
|   if ((outsize = lseek(outfd, 0, SEEK_END)) == -1) { | ||||
|     SysExit(outpath, "lseek"); | ||||
|     SysDie(outpath, "lseek"); | ||||
|   } | ||||
|   ldest = outsize; | ||||
|   cdest = outsize + ltotal; | ||||
|  | @ -186,23 +174,23 @@ static void CopyZip(void) { | |||
|     // write local file
 | ||||
|     length = ZIP_LFILE_SIZE(lfile); | ||||
|     if (pwrite(outfd, lfile, length, ldest) != length) { | ||||
|       SysExit(outpath, "lfile pwrite"); | ||||
|       SysDie(outpath, "lfile pwrite"); | ||||
|     } | ||||
|     ldest += length; | ||||
|     // write directory entry
 | ||||
|     length = ZIP_CFILE_HDRSIZE(cfile); | ||||
|     if (pwrite(outfd, cfile, length, cdest) != length) { | ||||
|       SysExit(outpath, "lfile pwrite"); | ||||
|       SysDie(outpath, "lfile pwrite"); | ||||
|     } | ||||
|     cdest += length; | ||||
|   } | ||||
|   WRITE32LE(eocd + kZipCdirOffsetOffset, outsize + ltotal); | ||||
|   length = ZIP_CDIR_HDRSIZE(eocd); | ||||
|   if (pwrite(outfd, eocd, length, cdest) != length) { | ||||
|     SysExit(outpath, "eocd pwrite"); | ||||
|     SysDie(outpath, "eocd pwrite"); | ||||
|   } | ||||
|   if (close(outfd)) { | ||||
|     SysExit(outpath, "close"); | ||||
|     SysDie(outpath, "close"); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
|  | @ -213,23 +201,23 @@ int main(int argc, char *argv[]) { | |||
|   } | ||||
|   GetOpts(argc, argv); | ||||
|   if ((infd = open(inpath, O_RDONLY)) == -1) { | ||||
|     SysExit(inpath, "open"); | ||||
|     SysDie(inpath, "open"); | ||||
|   } | ||||
|   if ((insize = lseek(infd, 0, SEEK_END)) == -1) { | ||||
|     SysExit(inpath, "lseek"); | ||||
|     SysDie(inpath, "lseek"); | ||||
|   } | ||||
|   if (!insize) { | ||||
|     Die(inpath, "file is empty"); | ||||
|   } | ||||
|   if ((inmap = mmap(0, insize, PROT_READ | PROT_WRITE, MAP_PRIVATE, infd, 0)) == | ||||
|       MAP_FAILED) { | ||||
|     SysExit(inpath, "mmap"); | ||||
|     SysDie(inpath, "mmap"); | ||||
|   } | ||||
|   CopyZip(); | ||||
|   if (munmap(inmap, insize)) { | ||||
|     SysExit(inpath, "munmap"); | ||||
|     SysDie(inpath, "munmap"); | ||||
|   } | ||||
|   if (close(infd)) { | ||||
|     SysExit(inpath, "close"); | ||||
|     SysDie(inpath, "close"); | ||||
|   } | ||||
| } | ||||
|  |  | |||
|  | @ -21,7 +21,6 @@ | |||
| #include "libc/elf/def.h" | ||||
| #include "libc/fmt/conv.h" | ||||
| #include "libc/fmt/libgen.h" | ||||
| #include "libc/intrin/kprintf.h" | ||||
| #include "libc/limits.h" | ||||
| #include "libc/log/check.h" | ||||
| #include "libc/log/log.h" | ||||
|  | @ -52,15 +51,16 @@ int strip_components_; | |||
| const char *path_prefix_; | ||||
| struct timespec timestamp; | ||||
| 
 | ||||
| wontreturn void PrintUsage(int rc) { | ||||
|   kprintf("\n\
 | ||||
| wontreturn void PrintUsage(int fd, int rc) { | ||||
|   tinyprint(fd, "\n\
 | ||||
| NAME\n\ | ||||
| \n\ | ||||
|   Cosmpolitan Zip File Compiler\n\ | ||||
| \n\ | ||||
| SYNOPSIS\n\ | ||||
| \n\ | ||||
|   %s [FLAGS] FILE...\n\ | ||||
|   ", | ||||
|             program_invocation_name, " [FLAGS] FILE...\n\
 | ||||
| \n\ | ||||
| DESCRIPTION\n\ | ||||
| \n\ | ||||
|  | @ -80,7 +80,7 @@ FLAGS\n\ | |||
|   -y SYMBOL       generate yoink for symbol (default __zip_eocd)\n\ | ||||
| \n\ | ||||
| ", | ||||
|           program_invocation_name); | ||||
|             NULL); | ||||
|   exit(rc); | ||||
| } | ||||
| 
 | ||||
|  | @ -117,17 +117,18 @@ void GetOpts(int *argc, char ***argv) { | |||
|         break; | ||||
|       case '?': | ||||
|       case 'h': | ||||
|         PrintUsage(EXIT_SUCCESS); | ||||
|         PrintUsage(1, EXIT_SUCCESS); | ||||
|       default: | ||||
|         PrintUsage(EX_USAGE); | ||||
|         PrintUsage(2, EX_USAGE); | ||||
|     } | ||||
|   } | ||||
|   *argc -= optind; | ||||
|   *argv += optind; | ||||
|   if (!outpath_) { | ||||
|     kprintf("error: no output path specified\n" | ||||
|             "run %s -h for usage\n", | ||||
|             program_invocation_name); | ||||
|     tinyprint(2, | ||||
|               "error: no output path specified\n" | ||||
|               "run ", | ||||
|               program_invocation_name, " -h for usage\n", NULL); | ||||
|     exit(1); | ||||
|   } | ||||
| } | ||||
|  |  | |||
|  | @ -1,101 +0,0 @@ | |||
| #include "libc/nt/struct/peb.h" | ||||
| #include "libc/stdio/stdio.h" | ||||
| 
 | ||||
| int main() { | ||||
|   printf("InheritedAddressSpace = 0x%x\n", | ||||
|          offsetof(struct NtPeb, InheritedAddressSpace)); | ||||
|   printf("ReadImageFileExecOptions = 0x%x\n", | ||||
|          offsetof(struct NtPeb, ReadImageFileExecOptions)); | ||||
|   printf("BeingDebugged = 0x%x\n", offsetof(struct NtPeb, BeingDebugged)); | ||||
|   printf("Mutant = 0x%x\n", offsetof(struct NtPeb, Mutant)); | ||||
|   printf("ImageBaseAddress = 0x%x\n", offsetof(struct NtPeb, ImageBaseAddress)); | ||||
|   printf("Ldr = 0x%x\n", offsetof(struct NtPeb, Ldr)); | ||||
|   printf("ProcessParameters = 0x%x\n", | ||||
|          offsetof(struct NtPeb, ProcessParameters)); | ||||
|   printf("SubSystemData = 0x%x\n", offsetof(struct NtPeb, SubSystemData)); | ||||
|   printf("ProcessHeap = 0x%x\n", offsetof(struct NtPeb, ProcessHeap)); | ||||
|   printf("FastPebLock = 0x%x\n", offsetof(struct NtPeb, FastPebLock)); | ||||
|   printf("KernelCallbackTable = 0x%x\n", | ||||
|          offsetof(struct NtPeb, KernelCallbackTable)); | ||||
|   printf("UserSharedInfoPtr = 0x%x\n", | ||||
|          offsetof(struct NtPeb, UserSharedInfoPtr)); | ||||
|   printf("SystemReserved = 0x%x\n", offsetof(struct NtPeb, SystemReserved)); | ||||
|   printf("__wut6 = 0x%x\n", offsetof(struct NtPeb, __wut6)); | ||||
|   printf("__wut7 = 0x%x\n", offsetof(struct NtPeb, __wut7)); | ||||
|   printf("TlsExpansionCounter = 0x%x\n", | ||||
|          offsetof(struct NtPeb, TlsExpansionCounter)); | ||||
|   printf("TlsBitmap = 0x%x\n", offsetof(struct NtPeb, TlsBitmap)); | ||||
|   printf("TlsBitmapBits = 0x%x\n", offsetof(struct NtPeb, TlsBitmapBits)); | ||||
|   printf("ReadOnlySharedMemoryBase = 0x%x\n", | ||||
|          offsetof(struct NtPeb, ReadOnlySharedMemoryBase)); | ||||
|   printf("ReadOnlyStaticServerData = 0x%x\n", | ||||
|          offsetof(struct NtPeb, ReadOnlyStaticServerData)); | ||||
|   printf("AnsiCodePageData = 0x%x\n", offsetof(struct NtPeb, AnsiCodePageData)); | ||||
|   printf("OemCodePageData = 0x%x\n", offsetof(struct NtPeb, OemCodePageData)); | ||||
|   printf("UnicodeCaseTableData = 0x%x\n", | ||||
|          offsetof(struct NtPeb, UnicodeCaseTableData)); | ||||
|   printf("NumberOfProcessors = 0x%x\n", | ||||
|          offsetof(struct NtPeb, NumberOfProcessors)); | ||||
|   printf("NtGlobalFlag = 0x%x\n", offsetof(struct NtPeb, NtGlobalFlag)); | ||||
|   printf("CriticalSectionTimeout = 0x%x\n", | ||||
|          offsetof(struct NtPeb, CriticalSectionTimeout)); | ||||
|   printf("HeapSegmentReserve = 0x%x\n", | ||||
|          offsetof(struct NtPeb, HeapSegmentReserve)); | ||||
|   printf("HeapSegmentCommit = 0x%x\n", | ||||
|          offsetof(struct NtPeb, HeapSegmentCommit)); | ||||
|   printf("HeapDeCommitTotalFreeThreshold = 0x%x\n", | ||||
|          offsetof(struct NtPeb, HeapDeCommitTotalFreeThreshold)); | ||||
|   printf("HeapDeCommitFreeBlockThreshold = 0x%x\n", | ||||
|          offsetof(struct NtPeb, HeapDeCommitFreeBlockThreshold)); | ||||
|   printf("NumberOfHeaps = 0x%x\n", offsetof(struct NtPeb, NumberOfHeaps)); | ||||
|   printf("MaximumNumberOfHeaps = 0x%x\n", | ||||
|          offsetof(struct NtPeb, MaximumNumberOfHeaps)); | ||||
|   printf("ProcessHeaps = 0x%x\n", offsetof(struct NtPeb, ProcessHeaps)); | ||||
|   printf("GdiSharedHandleTable = 0x%x\n", | ||||
|          offsetof(struct NtPeb, GdiSharedHandleTable)); | ||||
|   printf("ProcessStarterHelper = 0x%x\n", | ||||
|          offsetof(struct NtPeb, ProcessStarterHelper)); | ||||
|   printf("GdiDCAttributeList = 0x%x\n", | ||||
|          offsetof(struct NtPeb, GdiDCAttributeList)); | ||||
|   printf("LoaderLock = 0x%x\n", offsetof(struct NtPeb, LoaderLock)); | ||||
|   printf("OSMajorVersion = 0x%x\n", offsetof(struct NtPeb, OSMajorVersion)); | ||||
|   printf("OSMinorVersion = 0x%x\n", offsetof(struct NtPeb, OSMinorVersion)); | ||||
|   printf("OSVersion = 0x%x\n", offsetof(struct NtPeb, OSVersion)); | ||||
|   printf("OSBuildNumber = 0x%x\n", offsetof(struct NtPeb, OSBuildNumber)); | ||||
|   printf("OSCSDVersion = 0x%x\n", offsetof(struct NtPeb, OSCSDVersion)); | ||||
|   printf("OSPlatformId = 0x%x\n", offsetof(struct NtPeb, OSPlatformId)); | ||||
|   printf("ImageSubsystem = 0x%x\n", offsetof(struct NtPeb, ImageSubsystem)); | ||||
|   printf("ImageSubsystemMajorVersion = 0x%x\n", | ||||
|          offsetof(struct NtPeb, ImageSubsystemMajorVersion)); | ||||
|   printf("ImageSubsystemMinorVersion = 0x%x\n", | ||||
|          offsetof(struct NtPeb, ImageSubsystemMinorVersion)); | ||||
|   printf("ImageProcessAffinityMask = 0x%x\n", | ||||
|          offsetof(struct NtPeb, ImageProcessAffinityMask)); | ||||
|   printf("ActiveProcessAffinityMask = 0x%x\n", | ||||
|          offsetof(struct NtPeb, ActiveProcessAffinityMask)); | ||||
|   printf("GdiHandleBuffer = 0x%x\n", offsetof(struct NtPeb, GdiHandleBuffer)); | ||||
|   printf("PostProcessInitRoutine = 0x%x\n", | ||||
|          offsetof(struct NtPeb, PostProcessInitRoutine)); | ||||
|   printf("TlsExpansionBitmap = 0x%x\n", | ||||
|          offsetof(struct NtPeb, TlsExpansionBitmap)); | ||||
|   printf("TlsExpansionBitmapBits = 0x%x\n", | ||||
|          offsetof(struct NtPeb, TlsExpansionBitmapBits)); | ||||
|   printf("SessionId = 0x%x\n", offsetof(struct NtPeb, SessionId)); | ||||
|   printf("AppCompatFlags = 0x%x\n", offsetof(struct NtPeb, AppCompatFlags)); | ||||
|   printf("AppCompatFlagsUser = 0x%x\n", | ||||
|          offsetof(struct NtPeb, AppCompatFlagsUser)); | ||||
|   printf("pShimData = 0x%x\n", offsetof(struct NtPeb, pShimData)); | ||||
|   printf("AppCompatInfo = 0x%x\n", offsetof(struct NtPeb, AppCompatInfo)); | ||||
|   printf("CSDVersion = 0x%x\n", offsetof(struct NtPeb, CSDVersion)); | ||||
|   printf("ActivationContextData = 0x%x\n", | ||||
|          offsetof(struct NtPeb, ActivationContextData)); | ||||
|   printf("ProcessAssemblyStorageMap = 0x%x\n", | ||||
|          offsetof(struct NtPeb, ProcessAssemblyStorageMap)); | ||||
|   printf("SystemDefaultActivationContextData = 0x%x\n", | ||||
|          offsetof(struct NtPeb, SystemDefaultActivationContextData)); | ||||
|   printf("SystemAssemblyStorageMap = 0x%x\n", | ||||
|          offsetof(struct NtPeb, SystemAssemblyStorageMap)); | ||||
|   printf("MinimumStackCommit = 0x%x\n", | ||||
|          offsetof(struct NtPeb, MinimumStackCommit)); | ||||
|   return 0; | ||||
| } | ||||
|  | @ -1,202 +0,0 @@ | |||
| /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
 | ||||
| │vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8                                :vi│ | ||||
| ╞══════════════════════════════════════════════════════════════════════════════╡ | ||||
| │ Copyright 2021 Justine Alexandra Roberts Tunney                              │ | ||||
| │                                                                              │ | ||||
| │ Permission to use, copy, modify, and/or distribute this software for         │ | ||||
| │ any purpose with or without fee is hereby granted, provided that the         │ | ||||
| │ above copyright notice and this permission notice appear in all copies.      │ | ||||
| │                                                                              │ | ||||
| │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL                │ | ||||
| │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED                │ | ||||
| │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE             │ | ||||
| │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL         │ | ||||
| │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR        │ | ||||
| │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER               │ | ||||
| │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR             │ | ||||
| │ PERFORMANCE OF THIS SOFTWARE.                                                │ | ||||
| ╚──────────────────────────────────────────────────────────────────────────────┘ | ||||
| 
 | ||||
|   THIS PROGRAM TURNS TEXT LIKE THIS | ||||
| 
 | ||||
|    +------------------------------------------------------------------------+ | ||||
|    | Button     | Name        | Go to                          | From 1.2.3 | | ||||
|    |            |             |                                | go to      | | ||||
|    |------------+-------------+--------------------------------+------------| | ||||
|    |   [ < ]    |    Back     | previous section in reading    | 1.2.2      | | ||||
|    |            |             | order                          |            | | ||||
|    |------------+-------------+--------------------------------+------------| | ||||
|    |   [ > ]    |   Forward   | next section in reading order  | 1.2.4      | | ||||
|    |------------+-------------+--------------------------------+------------| | ||||
|    |   [ << ]   |  FastBack   | previous or up-and-previous    | 1.1        | | ||||
|    |            |             | section                        |            | | ||||
|    |------------+-------------+--------------------------------+------------| | ||||
|    |   [ Up ]   |     Up      | up section                     | 1.2        | | ||||
|    |------------+-------------+--------------------------------+------------| | ||||
|    |   [ >> ]   | FastForward | next or up-and-next section    | 1.3        | | ||||
|    |------------+-------------+--------------------------------+------------| | ||||
|    |   [Top]    |     Top     | cover (top) of document        |            | | ||||
|    |------------+-------------+--------------------------------+------------| | ||||
|    | [Contents] |  Contents   | table of contents              |            | | ||||
|    |------------+-------------+--------------------------------+------------| | ||||
|    |  [Index]   |    Index    | concept index                  |            | | ||||
|    |------------+-------------+--------------------------------+------------| | ||||
|    |   [ ? ]    |    About    | this page                      |            | | ||||
|    +------------------------------------------------------------------------+ | ||||
| 
 | ||||
|   INTO THIS | ||||
| 
 | ||||
|    ┌────────────┬─────────────┬────────────────────────────────┬────────────┐ | ||||
|    │ Button     │ Name        │ Go to                          │ From 1.2.3 │ | ||||
|    │            │             │                                │ go to      │ | ||||
|    ├────────────┼─────────────┼────────────────────────────────┼────────────┤ | ||||
|    │   [ < ]    │    Back     │ previous section in reading    │ 1.2.2      │ | ||||
|    │            │             │ order                          │            │ | ||||
|    ├────────────┼─────────────┼────────────────────────────────┼────────────┤ | ||||
|    │   [ > ]    │   Forward   │ next section in reading order  │ 1.2.4      │ | ||||
|    ├────────────┼─────────────┼────────────────────────────────┼────────────┤ | ||||
|    │   [ << ]   │  FastBack   │ previous or up─and─previous    │ 1.1        │ | ||||
|    │            │             │ section                        │            │ | ||||
|    ├────────────┼─────────────┼────────────────────────────────┼────────────┤ | ||||
|    │   [ Up ]   │     Up      │ up section                     │ 1.2        │ | ||||
|    ├────────────┼─────────────┼────────────────────────────────┼────────────┤ | ||||
|    │   [ >> ]   │ FastForward │ next or up─and─next section    │ 1.3        │ | ||||
|    ├────────────┼─────────────┼────────────────────────────────┼────────────┤ | ||||
|    │   [Top]    │     Top     │ cover (top) of document        │            │ | ||||
|    ├────────────┼─────────────┼────────────────────────────────┼────────────┤ | ||||
|    │ [Contents] │  Contents   │ table of contents              │            │ | ||||
|    ├────────────┼─────────────┼────────────────────────────────┼────────────┤ | ||||
|    │  [Index]   │    Index    │ concept index                  │            │ | ||||
|    ├────────────┼─────────────┼────────────────────────────────┼────────────┤ | ||||
|    │   [ ? ]    │    About    │ this page                      │            │ | ||||
|    └────────────┴─────────────┴────────────────────────────────┴────────────┘ */ | ||||
| #include "libc/macros.internal.h" | ||||
| #include "libc/mem/gc.h" | ||||
| #include "libc/mem/mem.h" | ||||
| #include "libc/runtime/runtime.h" | ||||
| #include "libc/stdio/stdio.h" | ||||
| #include "libc/str/str.h" | ||||
| #include "libc/str/strwidth.h" | ||||
| #include "libc/x/x.h" | ||||
| #include "libc/x/xasprintf.h" | ||||
| #include "libc/x/xgetline.h" | ||||
| 
 | ||||
| #define IsSpace(C)  ((C) == ' ') | ||||
| #define IsPipe(C)   ((C) == '|' || (C) == u'│') | ||||
| #define IsPlus(C)   ((C) == '+' || (C) == u'┼') | ||||
| #define IsHyphen(C) ((C) == '-' || (C) == u'─') | ||||
| #define IsTick(C)   ((C) == '`' || (C) == u'└') | ||||
| #define IsPipe(C)   ((C) == '|' || (C) == u'│') | ||||
| #define IsEquals(C) ((C) == '=' || (C) == u'═') | ||||
| 
 | ||||
| int n; | ||||
| int yn; | ||||
| int xn; | ||||
| 
 | ||||
| FILE *f; | ||||
| bool *V; | ||||
| char **T; | ||||
| char16_t **L; | ||||
| 
 | ||||
| static void DoIt(int y, int x) { | ||||
|   if (V[y * (xn + 1) + x]) return; | ||||
|   V[y * (xn + 1) + x] = 1; | ||||
|   if (IsPipe(L[y - 1][x]) && IsHyphen(L[y][x - 1]) && IsPlus(L[y][x]) && | ||||
|       IsHyphen(L[y][x + 1]) && IsPipe(L[y + 1][x])) { | ||||
|     L[y][x] = u'┼'; | ||||
|   } else if (IsPipe(L[y - 1][x]) && IsEquals(L[y][x - 1]) && IsPlus(L[y][x]) && | ||||
|              IsEquals(L[y][x + 1]) && IsPipe(L[y + 1][x])) { | ||||
|     L[y][x] = u'╪'; | ||||
|   } else if (IsSpace(L[y - 1][x]) && IsHyphen(L[y][x - 1]) && | ||||
|              IsHyphen(L[y][x]) && IsHyphen(L[y][x + 1]) && | ||||
|              IsPipe(L[y + 1][x])) { | ||||
|     L[y][x] = u'┬'; | ||||
|   } else if (IsPipe(L[y - 1][x]) && IsHyphen(L[y][x - 1]) && | ||||
|              IsHyphen(L[y][x]) && IsHyphen(L[y][x + 1]) && | ||||
|              IsSpace(L[y + 1][x])) { | ||||
|     L[y][x] = u'┴'; | ||||
|   } else if (IsPipe(L[y - 1][x]) && IsSpace(L[y][x - 1]) && IsPipe(L[y][x]) && | ||||
|              IsHyphen(L[y][x + 1]) && IsPipe(L[y + 1][x])) { | ||||
|     L[y][x] = u'├'; | ||||
|   } else if (IsPipe(L[y - 1][x]) && IsHyphen(L[y][x - 1]) && IsPipe(L[y][x]) && | ||||
|              IsSpace(L[y][x + 1]) && IsPipe(L[y + 1][x])) { | ||||
|     L[y][x] = u'┤'; | ||||
|   } else if (IsSpace(L[y - 1][x]) && IsSpace(L[y][x - 1]) && IsPlus(L[y][x]) && | ||||
|              IsHyphen(L[y][x + 1]) && IsPipe(L[y + 1][x])) { | ||||
|     L[y][x] = u'┌'; | ||||
|   } else if (IsPipe(L[y - 1][x]) && IsHyphen(L[y][x - 1]) && IsPlus(L[y][x]) && | ||||
|              IsSpace(L[y][x + 1]) && IsSpace(L[y + 1][x])) { | ||||
|     L[y][x] = u'┘'; | ||||
|   } else if (IsSpace(L[y - 1][x]) && IsHyphen(L[y][x - 1]) && IsPlus(L[y][x]) && | ||||
|              IsSpace(L[y][x + 1]) && IsPipe(L[y + 1][x])) { | ||||
|     L[y][x] = u'┐'; | ||||
|   } else if (IsPipe(L[y - 1][x]) && IsSpace(L[y][x - 1]) && IsPlus(L[y][x]) && | ||||
|              IsHyphen(L[y][x + 1]) && IsSpace(L[y + 1][x])) { | ||||
|     L[y][x] = u'└'; | ||||
|   } else if (IsTick(L[y][x]) && IsPipe(L[y - 1][x]) && IsHyphen(L[y][x + 1]) && | ||||
|              IsSpace(L[y + 1][x]) && IsSpace(L[y][x - 1])) { | ||||
|     L[y][x] = u'└'; | ||||
|   } else if (IsHyphen(L[y][x])) { | ||||
|     L[y][x] = u'─'; | ||||
|   } else if (IsPipe(L[y][x])) { | ||||
|     L[y][x] = u'│'; | ||||
|   } else if (IsEquals(L[y][x])) { | ||||
|     L[y][x] = u'═'; | ||||
|   } else { | ||||
|     return; | ||||
|   } | ||||
|   DoIt(y - 1, x + 0); | ||||
|   DoIt(y + 1, x + 0); | ||||
|   DoIt(y + 0, x - 1); | ||||
|   DoIt(y + 0, x + 1); | ||||
| } | ||||
| 
 | ||||
| int main(int argc, char *argv[]) { | ||||
|   char *s; | ||||
|   int y, x; | ||||
|   ShowCrashReports(); | ||||
|   f = stdin; | ||||
|   while ((s = _chomp(xgetline(f)))) { | ||||
|     n = strwidth(s, 0); | ||||
|     xn = MAX(xn, n); | ||||
|     T = xrealloc(T, ++yn * sizeof(*T)); | ||||
|     T[yn - 1] = s; | ||||
|   } | ||||
|   xn += 1000; | ||||
|   L = xmalloc((yn + 2) * sizeof(*L)); | ||||
|   L[0] = utf8to16(_gc(xasprintf(" %*s ", xn, " ")), -1, 0); | ||||
|   for (y = 0; y < yn; ++y) { | ||||
|     s = xasprintf(" %s%*s ", T[y], xn - n, " "); | ||||
|     L[y + 1] = utf8to16(s, -1, 0); | ||||
|     free(T[y]); | ||||
|     free(s); | ||||
|   } | ||||
|   L[yn + 2 - 1] = utf8to16(_gc(xasprintf(" %*s ", xn, " ")), -1, 0); | ||||
|   free(T); | ||||
|   V = xcalloc((yn + 1) * (xn + 1), 1); | ||||
|   for (y = 1; y <= yn; ++y) { | ||||
|     for (x = 1; x <= xn; ++x) { | ||||
|       if (IsPipe(L[y - 1][x]) && IsHyphen(L[y][x - 1]) && IsPlus(L[y][x]) && | ||||
|           IsHyphen(L[y][x + 1]) && IsPipe(L[y + 1][x])) { | ||||
|         DoIt(y, x); | ||||
|       } | ||||
|       if (IsTick(L[y][x]) && IsPipe(L[y - 1][x]) && IsHyphen(L[y][x + 1]) && | ||||
|           IsSpace(L[y + 1][x]) && IsSpace(L[y][x - 1])) { | ||||
|         DoIt(y, x); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|   for (y = 1; y + 1 < yn; ++y) { | ||||
|     s = utf16to8(L[y], -1, 0); | ||||
|     n = strlen(s); | ||||
|     while (n && s[n - 1] == ' ') s[n - 1] = 0, --n; | ||||
|     puts(s + 1); | ||||
|     free(s); | ||||
|   } | ||||
|   for (y = 0; y < yn; ++y) { | ||||
|     free(L[y]); | ||||
|   } | ||||
|   free(L); | ||||
|   free(V); | ||||
|   return 0; | ||||
| } | ||||
|  | @ -1,284 +0,0 @@ | |||
| /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
 | ||||
| │vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8                                :vi│ | ||||
| ╞══════════════════════════════════════════════════════════════════════════════╡ | ||||
| │ Copyright 2021 Justine Alexandra Roberts Tunney                              │ | ||||
| │                                                                              │ | ||||
| │ Permission to use, copy, modify, and/or distribute this software for         │ | ||||
| │ any purpose with or without fee is hereby granted, provided that the         │ | ||||
| │ above copyright notice and this permission notice appear in all copies.      │ | ||||
| │                                                                              │ | ||||
| │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL                │ | ||||
| │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED                │ | ||||
| │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE             │ | ||||
| │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL         │ | ||||
| │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR        │ | ||||
| │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER               │ | ||||
| │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR             │ | ||||
| │ PERFORMANCE OF THIS SOFTWARE.                                                │ | ||||
| ╚─────────────────────────────────────────────────────────────────────────────*/ | ||||
| #include "libc/calls/calls.h" | ||||
| #include "libc/calls/struct/stat.h" | ||||
| #include "libc/fmt/conv.h" | ||||
| #include "libc/intrin/safemacros.internal.h" | ||||
| #include "libc/log/check.h" | ||||
| #include "libc/log/log.h" | ||||
| #include "libc/mem/gc.h" | ||||
| #include "libc/mem/mem.h" | ||||
| #include "libc/runtime/runtime.h" | ||||
| #include "libc/sysv/consts/map.h" | ||||
| #include "libc/sysv/consts/o.h" | ||||
| #include "libc/sysv/consts/prot.h" | ||||
| #include "libc/x/xasprintf.h" | ||||
| #include "libc/x/xiso8601.h" | ||||
| #include "libc/zip.internal.h" | ||||
| #include "tool/decode/lib/asmcodegen.h" | ||||
| #include "tool/decode/lib/disassemblehex.h" | ||||
| #include "tool/decode/lib/zipnames.h" | ||||
| 
 | ||||
| char *FormatDosDate(uint16_t dosdate) { | ||||
|   return xasprintf("%04u-%02u-%02u", ((dosdate >> 9) & 0b1111111) + 1980, | ||||
|                    (dosdate >> 5) & 0b1111, dosdate & 0b11111); | ||||
| } | ||||
| 
 | ||||
| char *FormatDosTime(uint16_t dostime) { | ||||
|   return xasprintf("%02u:%02u:%02u", (dostime >> 11) & 0b11111, | ||||
|                    (dostime >> 5) & 0b111111, (dostime << 1) & 0b111110); | ||||
| } | ||||
| 
 | ||||
| void ShowGeneralFlag(uint16_t generalflag) { | ||||
|   puts("\
 | ||||
| /	              ┌─utf8\n\ | ||||
| /	              │    ┌─strong encryption\n\ | ||||
| /	              │    │┌─compressed patch data\n\ | ||||
| /	              │    ││ ┌─crc and size go after file content\n\ | ||||
| /	              │    ││ │┌─{normal,max,fast,superfast}\n\ | ||||
| /	              │    ││ ││ ┌─encrypted\n\ | ||||
| /	          rrrr│uuuu││r│├┐│"); | ||||
|   show(".short", format(b1, "0b%016b", generalflag), "generalflag"); | ||||
| } | ||||
| 
 | ||||
| void ShowCompressionMethod(uint16_t compressmethod) { | ||||
|   show(".short", | ||||
|        firstnonnull(findnamebyid(kZipCompressionNames, compressmethod), | ||||
|                     format(b1, "%hu", compressmethod)), | ||||
|        "compressionmethod"); | ||||
| } | ||||
| 
 | ||||
| void ShowTimestamp(uint16_t time, uint16_t date) { | ||||
|   show(".short", format(b1, "%#04hx", time), | ||||
|        _gc(xasprintf("%s (%s)", "lastmodifiedtime", _gc(FormatDosTime(time))))); | ||||
|   show(".short", format(b1, "%#04hx", date), | ||||
|        _gc(xasprintf("%s (%s)", "lastmodifieddate", _gc(FormatDosDate(date))))); | ||||
| } | ||||
| 
 | ||||
| void ShowNtfs(uint8_t *ntfs, size_t n) { | ||||
|   struct timespec mtime, atime, ctime; | ||||
|   mtime = WindowsTimeToTimeSpec(READ64LE(ntfs + 8)); | ||||
|   atime = WindowsTimeToTimeSpec(READ64LE(ntfs + 16)); | ||||
|   ctime = WindowsTimeToTimeSpec(READ64LE(ntfs + 24)); | ||||
|   show(".long", _gc(xasprintf("%d", READ32LE(ntfs))), "ntfs reserved"); | ||||
|   show(".short", _gc(xasprintf("0x%04x", READ16LE(ntfs + 4))), | ||||
|        "ntfs attribute tag value #1"); | ||||
|   show(".short", _gc(xasprintf("%hu", READ16LE(ntfs + 6))), | ||||
|        "ntfs attribute tag size"); | ||||
|   show(".quad", _gc(xasprintf("%lu", READ64LE(ntfs + 8))), | ||||
|        _gc(xasprintf("%s (%s)", "ntfs last modified time", | ||||
|                      _gc(xiso8601(&mtime))))); | ||||
|   show(".quad", _gc(xasprintf("%lu", READ64LE(ntfs + 16))), | ||||
|        _gc(xasprintf("%s (%s)", "ntfs last access time", | ||||
|                      _gc(xiso8601(&atime))))); | ||||
|   show(".quad", _gc(xasprintf("%lu", READ64LE(ntfs + 24))), | ||||
|        _gc(xasprintf("%s (%s)", "ntfs creation time", _gc(xiso8601(&ctime))))); | ||||
| } | ||||
| 
 | ||||
| void ShowExtendedTimestamp(uint8_t *p, size_t n, bool islocal) { | ||||
|   int flag; | ||||
|   if (n) { | ||||
|     --n; | ||||
|     flag = *p++; | ||||
|     show(".byte", _gc(xasprintf("0b%03hhb", flag)), "fields present in local"); | ||||
|     if ((flag & 1) && n >= 4) { | ||||
|       show(".long", _gc(xasprintf("%u", READ32LE(p))), | ||||
|            _gc(xasprintf("%s (%s)", "last modified", | ||||
|                          _gc(xiso8601(&(struct timespec){READ32LE(p)}))))); | ||||
|       p += 4; | ||||
|       n -= 4; | ||||
|     } | ||||
|     flag >>= 1; | ||||
|     if (islocal) { | ||||
|       if ((flag & 1) && n >= 4) { | ||||
|         show(".long", _gc(xasprintf("%u", READ32LE(p))), | ||||
|              _gc(xasprintf("%s (%s)", "access time", | ||||
|                            _gc(xiso8601(&(struct timespec){READ32LE(p)}))))); | ||||
|         p += 4; | ||||
|         n -= 4; | ||||
|       } | ||||
|       flag >>= 1; | ||||
|       if ((flag & 1) && n >= 4) { | ||||
|         show(".long", _gc(xasprintf("%u", READ32LE(p))), | ||||
|              _gc(xasprintf("%s (%s)", "creation time", | ||||
|                            _gc(xiso8601(&(struct timespec){READ32LE(p)}))))); | ||||
|         p += 4; | ||||
|         n -= 4; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| void ShowZip64(uint8_t *p, size_t n, bool islocal) { | ||||
|   if (n >= 8) { | ||||
|     show(".quad", _gc(xasprintf("%lu", READ64LE(p))), | ||||
|          _gc(xasprintf("uncompressed size (%,ld)", READ64LE(p)))); | ||||
|   } | ||||
|   if (n >= 16) { | ||||
|     show(".quad", _gc(xasprintf("%lu", READ64LE(p + 8))), | ||||
|          _gc(xasprintf("compressed size (%,ld)", READ64LE(p + 8)))); | ||||
|   } | ||||
|   if (n >= 24) { | ||||
|     show(".quad", _gc(xasprintf("%lu", READ64LE(p + 16))), | ||||
|          _gc(xasprintf("lfile hdr offset (%,ld)", READ64LE(p + 16)))); | ||||
|   } | ||||
|   if (n >= 28) { | ||||
|     show(".long", _gc(xasprintf("%u", READ32LE(p + 24))), "disk number"); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| void ShowInfoZipNewUnixExtra(uint8_t *p, size_t n, bool islocal) { | ||||
|   if (p[0] == 1 && p[1] == 4 && p[6] == 4) { | ||||
|     show(".byte", "1", "version"); | ||||
|     show(".byte", "4", "uid length"); | ||||
|     show(".long", _gc(xasprintf("%u", READ32LE(p + 2))), "uid"); | ||||
|     show(".byte", "4", "gid length"); | ||||
|     show(".long", _gc(xasprintf("%u", READ32LE(p + 7))), "gid"); | ||||
|   } else { | ||||
|     disassemblehex(p, n, stdout); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| void ShowExtra(uint8_t *extra, bool islocal) { | ||||
|   switch (ZIP_EXTRA_HEADERID(extra)) { | ||||
|     case kZipExtraNtfs: | ||||
|       ShowNtfs(ZIP_EXTRA_CONTENT(extra), ZIP_EXTRA_CONTENTSIZE(extra)); | ||||
|       break; | ||||
|     case kZipExtraExtendedTimestamp: | ||||
|       ShowExtendedTimestamp(ZIP_EXTRA_CONTENT(extra), | ||||
|                             ZIP_EXTRA_CONTENTSIZE(extra), islocal); | ||||
|       break; | ||||
|     case kZipExtraZip64: | ||||
|       ShowZip64(ZIP_EXTRA_CONTENT(extra), ZIP_EXTRA_CONTENTSIZE(extra), | ||||
|                 islocal); | ||||
|       break; | ||||
|     case kZipExtraInfoZipNewUnixExtra: | ||||
|       ShowInfoZipNewUnixExtra(ZIP_EXTRA_CONTENT(extra), | ||||
|                               ZIP_EXTRA_CONTENTSIZE(extra), islocal); | ||||
|       break; | ||||
|     default: | ||||
|       disassemblehex(ZIP_EXTRA_CONTENT(extra), ZIP_EXTRA_CONTENTSIZE(extra), | ||||
|                      stdout); | ||||
|       break; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| void ShowExtras(uint8_t *extras, uint16_t extrassize, bool islocal) { | ||||
|   int i; | ||||
|   bool first; | ||||
|   uint8_t *p, *pe; | ||||
|   if (extrassize) { | ||||
|     first = true; | ||||
|     for (p = extras, pe = extras + extrassize, i = 0; p < pe; | ||||
|          p += ZIP_EXTRA_SIZE(p), ++i) { | ||||
|       show(".short", | ||||
|            firstnonnull(findnamebyid(kZipExtraNames, ZIP_EXTRA_HEADERID(p)), | ||||
|                         _gc(xasprintf("0x%04hx", ZIP_EXTRA_HEADERID(p)))), | ||||
|            _gc(xasprintf("%s[%d].%s", "extras", i, "headerid"))); | ||||
|       show(".short", _gc(xasprintf("%df-%df", (i + 2) * 10, (i + 1) * 10)), | ||||
|            _gc(xasprintf("%s[%d].%s (%hd %s)", "extras", i, "contentsize", | ||||
|                          ZIP_EXTRA_CONTENTSIZE(p), "bytes"))); | ||||
|       if (first) { | ||||
|         first = false; | ||||
|         printf("%d:", (i + 1) * 10); | ||||
|       } | ||||
|       ShowExtra(p, islocal); | ||||
|       printf("%d:", (i + 2) * 10); | ||||
|     } | ||||
|   } | ||||
|   putchar('\n'); | ||||
| } | ||||
| 
 | ||||
| void ShowLocalFileHeader(uint8_t *lf, uint16_t idx) { | ||||
|   printf("\n/\t%s #%hu (%zu %s)\n", "local file", idx + 1, | ||||
|          ZIP_LFILE_HDRSIZE(lf), "bytes"); | ||||
|   show(".ascii", format(b1, "%`'.*s", 4, lf), "magic"); | ||||
|   show(".byte", | ||||
|        firstnonnull(findnamebyid(kZipEraNames, ZIP_LFILE_VERSIONNEED(lf)), | ||||
|                     _gc(xasprintf("%d", ZIP_LFILE_VERSIONNEED(lf)))), | ||||
|        "pkzip version need"); | ||||
|   show(".byte", | ||||
|        firstnonnull(findnamebyid(kZipOsNames, ZIP_LFILE_OSNEED(lf)), | ||||
|                     _gc(xasprintf("%d", ZIP_LFILE_OSNEED(lf)))), | ||||
|        "os need"); | ||||
|   ShowGeneralFlag(ZIP_LFILE_GENERALFLAG(lf)); | ||||
|   ShowCompressionMethod(ZIP_LFILE_COMPRESSIONMETHOD(lf)); | ||||
|   ShowTimestamp(ZIP_LFILE_LASTMODIFIEDTIME(lf), ZIP_LFILE_LASTMODIFIEDDATE(lf)); | ||||
|   show( | ||||
|       ".long", | ||||
|       format(b1, "%#x", ZIP_LFILE_CRC32(lf)), _gc(xasprintf("%s (%#x)", "crc32z", GetZipLfileCompressedSize(lf) /* crc32_z(0, ZIP_LFILE_CONTENT(lf), GetZipLfileCompressedSize(lf)) */))); | ||||
|   if (ZIP_LFILE_COMPRESSEDSIZE(lf) == 0xFFFFFFFF) { | ||||
|     show(".long", "0xFFFFFFFF", "compressedsize (zip64)"); | ||||
|   } else { | ||||
|     show(".long", "3f-2f", | ||||
|          format(b1, "%s (%u %s)", "compressedsize", | ||||
|                 ZIP_LFILE_COMPRESSEDSIZE(lf), "bytes")); | ||||
|   } | ||||
|   show(".long", | ||||
|        ZIP_LFILE_UNCOMPRESSEDSIZE(lf) == 0xFFFFFFFF | ||||
|            ? "0xFFFFFFFF" | ||||
|            : format(b1, "%u", ZIP_LFILE_UNCOMPRESSEDSIZE(lf)), | ||||
|        "uncompressedsize"); | ||||
|   show(".short", "1f-0f", | ||||
|        format(b1, "%s (%hu %s)", "namesize", ZIP_LFILE_NAMESIZE(lf), "bytes")); | ||||
|   show( | ||||
|       ".short", "2f-1f", | ||||
|       format(b1, "%s (%hu %s)", "extrasize", ZIP_LFILE_EXTRASIZE(lf), "bytes")); | ||||
|   printf("0:"); | ||||
|   show(".ascii", | ||||
|        format(b1, "%`'s", | ||||
|               _gc(strndup(ZIP_LFILE_NAME(lf), ZIP_LFILE_NAMESIZE(lf)))), | ||||
|        "name"); | ||||
|   printf("1:"); | ||||
|   ShowExtras(ZIP_LFILE_EXTRA(lf), ZIP_LFILE_EXTRASIZE(lf), true); | ||||
|   printf("2:"); | ||||
|   disassemblehex(ZIP_LFILE_CONTENT(lf), ZIP_LFILE_COMPRESSEDSIZE(lf), stdout); | ||||
|   printf("3:\n"); | ||||
| } | ||||
| 
 | ||||
| void DisassembleZip(const char *path, uint8_t *p, size_t n) { | ||||
|   size_t i, records; | ||||
|   uint8_t *eocd, *cdir, *cf, *lf; | ||||
|   CHECK_NOTNULL((eocd = GetZipEocd(p, n, 0))); | ||||
|   records = GetZipCdirRecords(eocd); | ||||
|   cdir = p + GetZipCdirOffset(eocd); | ||||
|   for (i = 0, cf = cdir; i < records; ++i, cf += ZIP_CFILE_HDRSIZE(cf)) { | ||||
|     CHECK_EQ(kZipCfileHdrMagic, ZIP_CFILE_MAGIC(cf)); | ||||
|     lf = p + GetZipCfileOffset(cf); | ||||
|     CHECK_EQ(kZipLfileHdrMagic, ZIP_LFILE_MAGIC(lf)); | ||||
|     ShowLocalFileHeader(lf, i); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| int main(int argc, char *argv[]) { | ||||
|   int fd; | ||||
|   uint8_t *map; | ||||
|   struct stat st; | ||||
|   ShowCrashReports(); | ||||
|   CHECK_EQ(2, argc); | ||||
|   CHECK_NE(-1, (fd = open(argv[1], O_RDONLY))); | ||||
|   CHECK_NE(-1, fstat(fd, &st)); | ||||
|   CHECK_GE(st.st_size, kZipCdirHdrMinSize); | ||||
|   CHECK_NE(MAP_FAILED, | ||||
|            (map = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0))); | ||||
|   DisassembleZip(argv[1], map, st.st_size); | ||||
|   CHECK_NE(-1, munmap(map, st.st_size)); | ||||
|   CHECK_NE(-1, close(fd)); | ||||
|   return 0; | ||||
| } | ||||
|  | @ -1,4 +1,3 @@ | |||
| (require 'ctest-mode) | ||||
| (require 'ld-script) | ||||
| (require 'optinfo-mode) | ||||
| (require 'protobuf-mode) | ||||
|  |  | |||
|  | @ -1,115 +0,0 @@ | |||
| (defconst ctest-operators | ||||
|   '("+" | ||||
|     "-" | ||||
|     "*" | ||||
|     "/" | ||||
|     "%" | ||||
|     "//" | ||||
|     "**" | ||||
|     "~" | ||||
|     "^" | ||||
|     "|" | ||||
|     "&" | ||||
|     ">>" | ||||
|     "<<" | ||||
|     "!" | ||||
|     "||" | ||||
|     "&&" | ||||
|     "=" | ||||
|     "!=" | ||||
|     "<" | ||||
|     ">" | ||||
|     "<=" | ||||
|     ">=")) | ||||
| 
 | ||||
| (defconst ctest-consts | ||||
|   '("false" | ||||
|     "true" | ||||
|     "e" | ||||
|     "pi" | ||||
|     "epsilon" | ||||
|     "inf" | ||||
|     "nan" | ||||
|     "l2t" | ||||
|     "lg2" | ||||
|     "ln2" | ||||
|     "l2e")) | ||||
| 
 | ||||
| (defconst ctest-builtins | ||||
|   '("emit" | ||||
|     "exit" | ||||
|     "meminfo" | ||||
|     "isnan" | ||||
|     "isinf" | ||||
|     "signbit" | ||||
|     "isfinite" | ||||
|     "isnormal" | ||||
|     "fpclassify")) | ||||
| 
 | ||||
| (defconst ctest-functions | ||||
|   '("emit" | ||||
|     "cr" | ||||
|     "key" | ||||
|     "dup" | ||||
|     "swap" | ||||
|     "over" | ||||
|     "drop" | ||||
|     "expect" | ||||
|     "assert" | ||||
|     "abs" | ||||
|     "min" | ||||
|     "max")) | ||||
| 
 | ||||
| (defconst ctest-functions-libm | ||||
|   '("mod" | ||||
|     "rem" | ||||
|     "gray" | ||||
|     "ungray" | ||||
|     "popcnt" | ||||
|     "sqrt" | ||||
|     "exp" | ||||
|     "exp2" | ||||
|     "exp10" | ||||
|     "ldexp" | ||||
|     "log" | ||||
|     "log2" | ||||
|     "log10" | ||||
|     "sin" | ||||
|     "cos" | ||||
|     "tan" | ||||
|     "asin" | ||||
|     "acos" | ||||
|     "atan" | ||||
|     "atan2" | ||||
|     "round" | ||||
|     "trunc" | ||||
|     "rint" | ||||
|     "nearbyint" | ||||
|     "ceil" | ||||
|     "floor" | ||||
|     "rand" | ||||
|     "rand64")) | ||||
| 
 | ||||
| (defun ctest--make-regex (words) | ||||
|   (concat "\\_<" (regexp-opt words) "\\_>")) | ||||
| 
 | ||||
| (defconst ctest-highlights | ||||
|   `(("\\(#.*\\)$" 1 font-lock-comment-face) | ||||
|     ("\\b0\\([xX]\\)[[:xdigit:]]+\\([ulUL]*\\)\\b" | ||||
|      (1 font-lock-constant-face) | ||||
|      (2 font-lock-constant-face)) | ||||
|     ("\\b0\\([bB]\\)[01]+\\([ulUL]*\\)\\b" | ||||
|      (1 font-lock-constant-face) | ||||
|      (2 font-lock-constant-face)) | ||||
|     (,(concat "\\_<" (regexp-opt ctest-consts) "\\_>") . | ||||
|      font-lock-constant-face) | ||||
|     (,(concat "\\_<" (regexp-opt ctest-builtins) "\\_>") . | ||||
|      font-lock-builtin-face))) | ||||
| 
 | ||||
| (define-derived-mode ctest-mode fundamental-mode "CALCULATOR.COM" | ||||
|   "Major mode for editing CALCULATOR.COM smoke tests." | ||||
|   (setq font-lock-defaults '(ctest-highlights))) | ||||
| 
 | ||||
| (add-to-list 'auto-mode-alist '("\\.ctest$" . ctest-mode)) | ||||
| 
 | ||||
| (provide 'ctest-mode) | ||||
|  | @ -1,315 +0,0 @@ | |||
| /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
 | ||||
| │vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8                                :vi│ | ||||
| ╞══════════════════════════════════════════════════════════════════════════════╡ | ||||
| │ Copyright 2020 Justine Alexandra Roberts Tunney                              │ | ||||
| │                                                                              │ | ||||
| │ Permission to use, copy, modify, and/or distribute this software for         │ | ||||
| │ any purpose with or without fee is hereby granted, provided that the         │ | ||||
| │ above copyright notice and this permission notice appear in all copies.      │ | ||||
| │                                                                              │ | ||||
| │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL                │ | ||||
| │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED                │ | ||||
| │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE             │ | ||||
| │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL         │ | ||||
| │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR        │ | ||||
| │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER               │ | ||||
| │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR             │ | ||||
| │ PERFORMANCE OF THIS SOFTWARE.                                                │ | ||||
| ╚─────────────────────────────────────────────────────────────────────────────*/ | ||||
| #include "libc/fmt/conv.h" | ||||
| #include "libc/fmt/fmt.h" | ||||
| #include "libc/intrin/safemacros.internal.h" | ||||
| #include "libc/limits.h" | ||||
| #include "libc/log/check.h" | ||||
| #include "libc/log/log.h" | ||||
| #include "libc/macros.internal.h" | ||||
| #include "libc/math.h" | ||||
| #include "libc/mem/gc.internal.h" | ||||
| #include "libc/mem/mem.h" | ||||
| #include "libc/runtime/runtime.h" | ||||
| #include "libc/stdio/lcg.internal.h" | ||||
| #include "libc/stdio/rand.h" | ||||
| #include "libc/stdio/stdio.h" | ||||
| #include "libc/str/str.h" | ||||
| #include "libc/sysv/consts/ex.h" | ||||
| #include "libc/sysv/consts/exit.h" | ||||
| #include "libc/x/x.h" | ||||
| #include "third_party/gdtoa/gdtoa.h" | ||||
| #include "third_party/getopt/getopt.internal.h" | ||||
| #include "tool/viz/lib/formatstringtable.h" | ||||
| 
 | ||||
| typedef double (*round_f)(double); | ||||
| typedef unsigned long (*rand_f)(void); | ||||
| 
 | ||||
| struct Range { | ||||
|   long double a; | ||||
|   long double b; | ||||
| }; | ||||
| 
 | ||||
| short xn_ = 8; | ||||
| short yn_ = 8; | ||||
| double digs_ = 6; | ||||
| rand_f rand_; | ||||
| round_f rounder_; | ||||
| const char *path_ = "-"; | ||||
| const char *name_ = "M"; | ||||
| const char *type_ = "float"; | ||||
| struct Range r1_ = {LONG_MIN, LONG_MAX}; | ||||
| struct Range r2_ = {0, 1}; | ||||
| StringTableFormatter *formatter_ = FormatStringTableAsCode; | ||||
| 
 | ||||
| static wontreturn void PrintUsage(int rc, FILE *f) { | ||||
|   fprintf(f, "Usage: %s%s", program_invocation_name, "\
 | ||||
|  [FLAGS] [FILE]\n\ | ||||
| \n\ | ||||
| Flags:\n\ | ||||
|   -u         unsigned\n\ | ||||
|   -c         char\n\ | ||||
|   -s         short\n\ | ||||
|   -i         int\n\ | ||||
|   -l         long\n\ | ||||
|   -d         double\n\ | ||||
|   -b         bytes [-uc]\n\ | ||||
|   -g         non-deterministic rng\n\ | ||||
|   -S         output assembly\n\ | ||||
|   -W         output whitespace\n\ | ||||
|   -o PATH    output path\n\ | ||||
|   -x FLEX\n\ | ||||
|   -w FLEX    width\n\ | ||||
|   -y FLEX\n\ | ||||
|   -h FLEX    height\n\ | ||||
|   -N NAME    name\n\ | ||||
|   -T NAME    type name\n\ | ||||
|   -A FLEX    min value\n\ | ||||
|   -B FLEX    max value\n\ | ||||
|   -R FUNC    round function for indexing\n\ | ||||
|   -D FLEX    decimal digits to printout\n\ | ||||
|   -v         increases verbosity\n\ | ||||
|   -?         shows this information\n\ | ||||
| \n"); | ||||
|   exit(rc); | ||||
| } | ||||
| 
 | ||||
| static bool StringEquals(const char *a, const char *b) { | ||||
|   return strcasecmp(a, b) == 0; | ||||
| } | ||||
| 
 | ||||
| static wontreturn void ShowInvalidArg(const char *name, const char *s, | ||||
|                                       const char *type) { | ||||
|   fprintf(stderr, "error: invalid %s %s: %s\n", type, name, s); | ||||
|   exit(EXIT_FAILURE); | ||||
| } | ||||
| 
 | ||||
| static double ParseFlexidecimalOrDie(const char *name, const char *s, | ||||
|                                      double min, double max) { | ||||
|   double x; | ||||
|   s = firstnonnull(s, "NULL"); | ||||
|   if (strchr(s, '.') || strchr(s, 'e')) { | ||||
|     x = strtod(s, NULL); | ||||
|   } else { | ||||
|     x = strtol(s, NULL, 0); | ||||
|   } | ||||
|   if (min <= x && x <= max) { | ||||
|     return x; | ||||
|   } else { | ||||
|     ShowInvalidArg(name, s, "flexidecimal"); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| static round_f ParseRoundingFunctionOrDie(const char *s) { | ||||
|   if (isempty(s) || StringEquals(s, "none") || StringEquals(s, "null")) { | ||||
|     return NULL; | ||||
|   } else if (StringEquals(s, "round")) { | ||||
|     return round; | ||||
|   } else if (StringEquals(s, "rint")) { | ||||
|     return rint; | ||||
|   } else if (StringEquals(s, "nearbyint")) { | ||||
|     return nearbyint; | ||||
|   } else if (StringEquals(s, "trunc")) { | ||||
|     return trunc; | ||||
|   } else if (StringEquals(s, "floor")) { | ||||
|     return floor; | ||||
|   } else if (StringEquals(s, "ceil")) { | ||||
|     return ceil; | ||||
|   } else { | ||||
|     ShowInvalidArg("round", s, "func"); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| static void ConfigureIntegralRange(const char *type, long min, long max) { | ||||
|   type_ = type; | ||||
|   r1_.a = min; | ||||
|   r1_.b = max; | ||||
|   r2_.a = min; | ||||
|   r2_.b = max; | ||||
|   if (!rounder_) rounder_ = round; | ||||
| } | ||||
| 
 | ||||
| void GetOpts(int argc, char *argv[]) { | ||||
|   int opt; | ||||
|   bool want_unsigned, want_char, want_short, want_int, want_long, want_double; | ||||
|   want_unsigned = false; | ||||
|   want_char = false; | ||||
|   want_short = false; | ||||
|   want_int = false; | ||||
|   want_long = false; | ||||
|   want_double = false; | ||||
|   if (argc == 2 && | ||||
|       (StringEquals(argv[1], "--help") || StringEquals(argv[1], "-help"))) { | ||||
|     PrintUsage(EXIT_SUCCESS, stdout); | ||||
|   } | ||||
|   while ((opt = getopt(argc, argv, "?vubcsildgSWo:x:w:y:h:N:A:B:C:E:T:R:D:")) != | ||||
|          -1) { | ||||
|     switch (opt) { | ||||
|       case 'b': | ||||
|         want_unsigned = true; | ||||
|         want_char = true; | ||||
|         break; | ||||
|       case 'u': | ||||
|         want_unsigned = true; | ||||
|         break; | ||||
|       case 'c': | ||||
|         want_char = true; | ||||
|         break; | ||||
|       case 's': | ||||
|         want_short = true; | ||||
|         break; | ||||
|       case 'i': | ||||
|         want_int = true; | ||||
|         break; | ||||
|       case 'l': | ||||
|         want_long = true; | ||||
|         break; | ||||
|       case 'd': | ||||
|         want_double = true; | ||||
|         break; | ||||
|       case 'g': | ||||
|         rand_ = _rand64; | ||||
|         break; | ||||
|       case 'N': | ||||
|         name_ = optarg; | ||||
|         break; | ||||
|       case 'o': | ||||
|         path_ = optarg; | ||||
|         break; | ||||
|       case 'S': | ||||
|         formatter_ = FormatStringTableAsAssembly; | ||||
|         break; | ||||
|       case 'W': | ||||
|         formatter_ = FormatStringTableBasic; | ||||
|         break; | ||||
|       case 't': | ||||
|         type_ = optarg; | ||||
|         break; | ||||
|       case 'x': | ||||
|       case 'w': | ||||
|         xn_ = ParseFlexidecimalOrDie("width", optarg, 1, SHRT_MAX); | ||||
|         break; | ||||
|       case 'y': | ||||
|       case 'h': | ||||
|         yn_ = ParseFlexidecimalOrDie("height", optarg, 1, SHRT_MAX); | ||||
|         break; | ||||
|       case 'D': | ||||
|         digs_ = ParseFlexidecimalOrDie("digs", optarg, 0, 15.95); | ||||
|         break; | ||||
|       case 'r': | ||||
|         rounder_ = ParseRoundingFunctionOrDie(optarg); | ||||
|         break; | ||||
|       case 'A': | ||||
|         r1_.a = ParseFlexidecimalOrDie("r1_.a", optarg, INT_MIN, INT_MAX); | ||||
|         break; | ||||
|       case 'B': | ||||
|         r1_.b = ParseFlexidecimalOrDie("r1_.b", optarg, INT_MIN, INT_MAX); | ||||
|         break; | ||||
|       case 'C': | ||||
|         r2_.a = ParseFlexidecimalOrDie("r2_.a", optarg, INT_MIN, INT_MAX); | ||||
|         break; | ||||
|       case 'E': | ||||
|         r2_.b = ParseFlexidecimalOrDie("r2_.b", optarg, INT_MIN, INT_MAX); | ||||
|         break; | ||||
|       case '?': | ||||
|         PrintUsage(EXIT_SUCCESS, stdout); | ||||
|       default: | ||||
|         PrintUsage(EX_USAGE, stderr); | ||||
|     } | ||||
|   } | ||||
|   if (want_unsigned && want_char) { | ||||
|     ConfigureIntegralRange("unsigned char", 0, 255); | ||||
|   } else if (want_char) { | ||||
|     ConfigureIntegralRange("signed char", -128, 127); | ||||
|   } else if (want_unsigned && want_short) { | ||||
|     ConfigureIntegralRange("unsigned short", USHRT_MIN, USHRT_MAX); | ||||
|   } else if (want_short) { | ||||
|     ConfigureIntegralRange("short", SHRT_MIN, SHRT_MAX); | ||||
|   } else if (want_unsigned && want_int) { | ||||
|     ConfigureIntegralRange("unsigned", UINT_MIN, UINT_MAX); | ||||
|   } else if (want_int) { | ||||
|     ConfigureIntegralRange("int", INT_MIN, INT_MAX); | ||||
|   } else if (want_unsigned && want_long) { | ||||
|     ConfigureIntegralRange("unsigned long", ULONG_MIN, ULONG_MAX); | ||||
|   } else if (want_long) { | ||||
|     ConfigureIntegralRange("long", LONG_MIN, LONG_MAX); | ||||
|   } else if (want_double) { | ||||
|     type_ = "double"; | ||||
|     r1_.a = LONG_MIN; | ||||
|     r1_.b = LONG_MAX; | ||||
|     digs_ = 19; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| static void *SetRandom(long n, long p[n]) { | ||||
|   long i; | ||||
|   uint64_t r; | ||||
|   if (rand_) { | ||||
|     for (r = 1, i = 0; i < n; ++i) { | ||||
|       p[i] = rand_(); | ||||
|     } | ||||
|   } else { | ||||
|     for (r = 1, i = 0; i < n; ++i) { | ||||
|       p[i] = KnuthLinearCongruentialGenerator(&r) >> 32 | | ||||
|              KnuthLinearCongruentialGenerator(&r) >> 32 << 32; | ||||
|     } | ||||
|   } | ||||
|   return p; | ||||
| } | ||||
| 
 | ||||
| static long double ConvertRange(long double x, long double a, long double b, | ||||
|                                 long double c, long double d) { | ||||
|   return (d - c) / (b - a) * (x - a) + c; | ||||
| } | ||||
| 
 | ||||
| static double Compand(long x, double a, double b, double c, double d) { | ||||
|   return ConvertRange(ConvertRange(x, LONG_MIN, LONG_MAX, a, b), a, b, c, d); | ||||
| } | ||||
| 
 | ||||
| static void GenerateMatrixImpl(long I[yn_][xn_], double M[yn_][xn_], FILE *f) { | ||||
|   long y, x; | ||||
|   for (y = 0; y < yn_; ++y) { | ||||
|     for (x = 0; x < xn_; ++x) { | ||||
|       M[y][x] = Compand(I[y][x], r1_.a, r1_.b, r2_.a, r2_.b); | ||||
|     } | ||||
|     if (rounder_) { | ||||
|       for (x = 0; x < xn_; ++x) { | ||||
|         M[y][x] = rounder_(M[y][x]); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|   FormatMatrixDouble(yn_, xn_, M, fputs, f, formatter_, type_, name_, NULL, | ||||
|                      digs_, round); | ||||
| } | ||||
| 
 | ||||
| void GenerateMatrix(FILE *f) { | ||||
|   GenerateMatrixImpl(SetRandom(yn_ * xn_, gc(calloc(yn_ * xn_, sizeof(long)))), | ||||
|                      gc(calloc(yn_ * xn_, sizeof(double))), f); | ||||
| } | ||||
| 
 | ||||
| int main(int argc, char *argv[]) { | ||||
|   int i; | ||||
|   FILE *f; | ||||
|   ShowCrashReports(); | ||||
|   GetOpts(argc, argv); | ||||
|   CHECK_NOTNULL((f = fopen(path_, "w"))); | ||||
|   if (optind < argc) FATALF("TODO(jart): support input files"); | ||||
|   GenerateMatrix(f); | ||||
|   return fclose(f); | ||||
| } | ||||
|  | @ -1,116 +0,0 @@ | |||
| /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
 | ||||
| │vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8                                :vi│ | ||||
| ╞══════════════════════════════════════════════════════════════════════════════╡ | ||||
| │ Copyright 2020 Justine Alexandra Roberts Tunney                              │ | ||||
| │                                                                              │ | ||||
| │ Permission to use, copy, modify, and/or distribute this software for         │ | ||||
| │ any purpose with or without fee is hereby granted, provided that the         │ | ||||
| │ above copyright notice and this permission notice appear in all copies.      │ | ||||
| │                                                                              │ | ||||
| │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL                │ | ||||
| │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED                │ | ||||
| │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE             │ | ||||
| │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL         │ | ||||
| │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR        │ | ||||
| │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER               │ | ||||
| │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR             │ | ||||
| │ PERFORMANCE OF THIS SOFTWARE.                                                │ | ||||
| ╚─────────────────────────────────────────────────────────────────────────────*/ | ||||
| #include "libc/log/check.h" | ||||
| #include "libc/runtime/runtime.h" | ||||
| #include "libc/stdio/stdio.h" | ||||
| #include "libc/sysv/consts/ex.h" | ||||
| #include "libc/sysv/consts/exit.h" | ||||
| #include "third_party/getopt/getopt.internal.h" | ||||
| 
 | ||||
| static FILE *fi_, *fo_; | ||||
| static char *inpath_, *outpath_; | ||||
| 
 | ||||
| wontreturn void usage(int rc, FILE *f) { | ||||
|   fprintf(f, "%s%s%s\n", "Usage: ", program_invocation_name, | ||||
|           " [-o FILE] [FILE...]\n"); | ||||
|   exit(rc); | ||||
| } | ||||
| 
 | ||||
| void getopts(int *argc, char *argv[]) { | ||||
|   int opt; | ||||
|   outpath_ = "-"; | ||||
|   while ((opt = getopt(*argc, argv, "?ho:")) != -1) { | ||||
|     switch (opt) { | ||||
|       case 'o': | ||||
|         outpath_ = optarg; | ||||
|         break; | ||||
|       case '?': | ||||
|       case 'h': | ||||
|         usage(EXIT_SUCCESS, stdout); | ||||
|       default: | ||||
|         usage(EX_USAGE, stderr); | ||||
|     } | ||||
|   } | ||||
|   if (optind == *argc) { | ||||
|     argv[(*argc)++] = "-"; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| void processfile(void) { | ||||
|   wint_t wc; | ||||
|   while ((wc = fgetwc(fi_)) != -1) { | ||||
|     switch (wc) { | ||||
|       case L'█': | ||||
|         wc = L' '; | ||||
|         break; | ||||
|       case L'▓': | ||||
|         wc = L'░'; | ||||
|         break; | ||||
|       case L'▒': | ||||
|         wc = L'▒'; | ||||
|         break; | ||||
|       case L'░': | ||||
|         wc = L'▓'; | ||||
|         break; | ||||
|         /* █ */ | ||||
|       case L'▐': | ||||
|         wc = L'▌'; | ||||
|         break; | ||||
|       case L'▌': | ||||
|         wc = L'▐'; | ||||
|         break; | ||||
|       case L'▀': | ||||
|         wc = L'▄'; | ||||
|         break; | ||||
|       case L'▄': | ||||
|         wc = L'▀'; | ||||
|         break; | ||||
|       case L'☺': | ||||
|         wc = L'☻'; | ||||
|         break; | ||||
|       case L'☻': | ||||
|         wc = L'☺'; | ||||
|         break; | ||||
|       case L'○': | ||||
|         wc = L'◙'; | ||||
|         break; | ||||
|       case L'◙': | ||||
|         wc = L'○'; | ||||
|         break; | ||||
|       default: | ||||
|         break; | ||||
|     } | ||||
|     fputwc(wc, fo_); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| int main(int argc, char *argv[]) { | ||||
|   size_t i; | ||||
|   getopts(&argc, argv); | ||||
|   CHECK_NOTNULL((fo_ = fopen(outpath_, "w"))); | ||||
|   for (i = optind; i < argc; ++i) { | ||||
|     CHECK_NOTNULL((fi_ = fopen((inpath_ = argv[i]), "r"))); | ||||
|     processfile(); | ||||
|     CHECK_NE(-1, fclose(fi_)); | ||||
|     fi_ = 0; | ||||
|   } | ||||
|   CHECK_NE(-1, fclose(fo_)); | ||||
|   fo_ = 0; | ||||
|   return 0; | ||||
| } | ||||
|  | @ -1,642 +0,0 @@ | |||
| /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
 | ||||
| │vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8                                :vi│ | ||||
| ╞══════════════════════════════════════════════════════════════════════════════╡ | ||||
| │ Copyright 2020 Justine Alexandra Roberts Tunney                              │ | ||||
| │                                                                              │ | ||||
| │ Permission to use, copy, modify, and/or distribute this software for         │ | ||||
| │ any purpose with or without fee is hereby granted, provided that the         │ | ||||
| │ above copyright notice and this permission notice appear in all copies.      │ | ||||
| │                                                                              │ | ||||
| │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL                │ | ||||
| │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED                │ | ||||
| │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE             │ | ||||
| │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL         │ | ||||
| │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR        │ | ||||
| │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER               │ | ||||
| │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR             │ | ||||
| │ PERFORMANCE OF THIS SOFTWARE.                                                │ | ||||
| ╚─────────────────────────────────────────────────────────────────────────────*/ | ||||
| #include "dsp/core/c1331.h" | ||||
| #include "dsp/core/c161.h" | ||||
| #include "dsp/core/core.h" | ||||
| #include "dsp/scale/scale.h" | ||||
| #include "libc/assert.h" | ||||
| #include "libc/calls/calls.h" | ||||
| #include "libc/calls/struct/stat.h" | ||||
| #include "libc/fmt/conv.h" | ||||
| #include "libc/limits.h" | ||||
| #include "libc/log/check.h" | ||||
| #include "libc/log/log.h" | ||||
| #include "libc/macros.internal.h" | ||||
| #include "libc/math.h" | ||||
| #include "libc/mem/gc.internal.h" | ||||
| #include "libc/mem/mem.h" | ||||
| #include "libc/runtime/runtime.h" | ||||
| #include "libc/stdio/rand.h" | ||||
| #include "libc/stdio/stdio.h" | ||||
| #include "libc/str/str.h" | ||||
| #include "libc/sysv/consts/madv.h" | ||||
| #include "libc/sysv/consts/map.h" | ||||
| #include "libc/sysv/consts/o.h" | ||||
| #include "libc/sysv/consts/prot.h" | ||||
| #include "libc/testlib/testlib.h" | ||||
| #include "libc/x/x.h" | ||||
| #include "third_party/getopt/getopt.internal.h" | ||||
| #include "third_party/stb/stb_image.h" | ||||
| #include "tool/viz/lib/bilinearscale.h" | ||||
| #include "tool/viz/lib/graphic.h" | ||||
| 
 | ||||
| #define LONG          long | ||||
| #define CHAR          char | ||||
| #define CLAMP(X)      MIN(255, MAX(0, X)) | ||||
| #define C13(A, B)     (((A) + 3 * (B) + 2) >> 2) | ||||
| #define LERP(X, Y, P) ((X) + (((P) * ((Y) - (X))) >> 8)) | ||||
| 
 | ||||
| static double r_; | ||||
| 
 | ||||
| static unsigned char ChessBoard(unsigned y, unsigned x, unsigned char a, | ||||
|                                 unsigned char b) { | ||||
|   return !((y ^ x) & (1u << 2)) ? a : b; | ||||
| } | ||||
| 
 | ||||
| static unsigned char AlphaBackground(unsigned y, unsigned x) { | ||||
|   return ChessBoard(y, x, 255, 200); | ||||
| } | ||||
| 
 | ||||
| static unsigned char OutOfBoundsBackground(unsigned y, unsigned x) { | ||||
|   return ChessBoard(y, x, 40, 80); | ||||
| } | ||||
| 
 | ||||
| static unsigned char Opacify(CHAR w, const unsigned char P[1u << w][1u << w], | ||||
|                              const unsigned char A[1u << w][1u << w], LONG yn, | ||||
|                              LONG xn, long y, long x) { | ||||
|   if ((0 <= y && y < yn) && (0 <= x && x < xn)) { | ||||
|     return LERP(AlphaBackground(y, x), P[y][x], A[y][x]); | ||||
|   } else { | ||||
|     return OutOfBoundsBackground(y, x); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| static void PrintImage(CHAR w, unsigned char R[1u << w][1u << w], | ||||
|                        unsigned char G[1u << w][1u << w], | ||||
|                        unsigned char B[1u << w][1u << w], | ||||
|                        unsigned char A[1u << w][1u << w], LONG yn, LONG xn) { | ||||
|   bool didhalfy; | ||||
|   long y, x; | ||||
|   didhalfy = false; | ||||
|   for (y = 0; y < yn; y += 2) { | ||||
|     if (y) printf("\e[0m\n"); | ||||
|     for (x = 0; x < xn; ++x) { | ||||
|       printf("\e[48;2;%d;%d;%d;38;2;%d;%d;%dm▄", | ||||
|              Opacify(w, R, A, yn, xn, y + 0, x), | ||||
|              Opacify(w, G, A, yn, xn, y + 0, x), | ||||
|              Opacify(w, B, A, yn, xn, y + 0, x), | ||||
|              Opacify(w, R, A, yn, xn, y + 1, x), | ||||
|              Opacify(w, G, A, yn, xn, y + 1, x), | ||||
|              Opacify(w, B, A, yn, xn, y + 1, x)); | ||||
|     } | ||||
|     if (y == 0) { | ||||
|       printf("\e[0m‾0"); | ||||
|     } else if (yn / 2 <= y && y <= yn / 2 + 1 && !didhalfy) { | ||||
|       printf("\e[0m‾%s%s", "yn/2", y % 2 ? "+1" : ""); | ||||
|       didhalfy = true; | ||||
|     } else if (y + 1 == yn / 2 && !didhalfy) { | ||||
|       printf("\e[0m⎯yn/2"); | ||||
|       didhalfy = true; | ||||
|     } else if (y + 1 == yn) { | ||||
|       printf("\e[0m⎯yn"); | ||||
|     } else if (y + 2 == yn) { | ||||
|       printf("\e[0m_yn"); | ||||
|     } else if (!(y % 10)) { | ||||
|       printf("\e[0m‾%,u", y); | ||||
|     } | ||||
|   } | ||||
|   printf("\e[0m\n"); | ||||
| } | ||||
| 
 | ||||
| static void DeblinterlaceRgba(CHAR w, unsigned char R[1u << w][1u << w], | ||||
|                               unsigned char G[1u << w][1u << w], | ||||
|                               unsigned char B[1u << w][1u << w], | ||||
|                               unsigned char A[1u << w][1u << w], LONG yn, | ||||
|                               LONG xn, const unsigned char src[yn][xn][4]) { | ||||
|   long y, x; | ||||
|   for (y = 0; y < yn; ++y) { | ||||
|     for (x = 0; x < xn; ++x) { | ||||
|       R[y][x] = src[y][x][0]; | ||||
|       G[y][x] = src[y][x][1]; | ||||
|       B[y][x] = src[y][x][2]; | ||||
|       A[y][x] = src[y][x][3]; | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| static void SharpenX(CHAR w, unsigned char dst[1u << w][1u << w], | ||||
|                      const unsigned char src[1u << w][1u << w], char yw, | ||||
|                      char xw) { | ||||
|   int y, x; | ||||
|   for (y = 0; y < (1u << yw); ++y) { | ||||
|     for (x = 0; x < (1u << xw); ++x) { | ||||
|       dst[y][x] = C161(src[y][MAX(0, x - 1)], src[y][x], | ||||
|                        src[y][MIN((1u << xw) - 1, x + 1)]); | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| static void SharpenY(CHAR w, unsigned char dst[1u << w][1u << w], | ||||
|                      const unsigned char src[1u << w][1u << w], char yw, | ||||
|                      char xw) { | ||||
|   int y, x; | ||||
|   for (y = 0; y < (1u << yw); ++y) { | ||||
|     for (x = 0; x < (1u << xw); ++x) { | ||||
|       dst[y][x] = C161(src[MAX(0, y - 1)][x], src[y][x], | ||||
|                        src[MIN((1u << yw) - 1, y + 1)][x]); | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| static void UpscaleX(CHAR w, unsigned char img[1u << w][1u << w], char yw, | ||||
|                      char xw) { | ||||
|   long y, x; | ||||
|   for (y = (1u << yw); y--;) { | ||||
|     for (x = (1u << xw); --x;) { | ||||
|       img[y][x] = | ||||
|           C13(img[y][MIN(((1u << xw) >> 1) - 1, (x >> 1) - 1 + (x & 1) * 2)], | ||||
|               img[y][x >> 1]); | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| static void UpscaleY(CHAR w, unsigned char img[1u << w][1u << w], char yw, | ||||
|                      char xw) { | ||||
|   long y, x; | ||||
|   for (y = (1u << yw); --y;) { | ||||
|     for (x = (1u << xw); x--;) { | ||||
|       img[y][x] = | ||||
|           C13(img[MIN(((1u << yw) >> 1) - 1, (y >> 1) - 1 + (y & 1) * 2)][x], | ||||
|               img[y >> 1][x]); | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| static void Upscale(CHAR w, unsigned char img[1u << w][1u << w], | ||||
|                     unsigned char tmp[1u << w][1u << w], char yw, char xw) { | ||||
|   UpscaleY(w, img, yw, xw - 1); | ||||
|   SharpenY(w, tmp, img, yw, xw - 1); | ||||
|   UpscaleX(w, tmp, yw, xw); | ||||
|   SharpenX(w, img, tmp, yw, xw); | ||||
| } | ||||
| 
 | ||||
| #if 0 | ||||
| static void *MagikarpY(CHAR w, unsigned char p[1u << w][1u << w], char yw, | ||||
|                        char xw) { | ||||
|   long y, x, yn, xn, ym; | ||||
|   unsigned char(*t)[(1u << w) + 2][1u << w]; | ||||
|   t = memalign(64, ((1u << w) + 2) * (1u << w)); | ||||
|   bzero(t, ((1u << w) + 2) * (1u << w)); | ||||
|   yn = 1u << yw; | ||||
|   xn = 1u << xw; | ||||
|   ym = yn >> 1; | ||||
|   for (y = 0; y < ym; ++y) { | ||||
|     for (x = 0; x < xn; ++x) { | ||||
|       (*t)[y + 1][x] = | ||||
|           C1331(y ? p[(y << 1) - 1][x] : 0, p[y << 1][x], p[(y << 1) + 1][x], | ||||
|                 p[MIN(yn - 1, (y << 1) + 2)][x]); | ||||
|     } | ||||
|   } | ||||
|   for (y = 0; y < ym; ++y) { | ||||
|     for (x = 0; x < xn; ++x) { | ||||
|       p[y][x] = | ||||
|           C161((*t)[y + 1 - 1][x], (*t)[y + 1 + 0][x], (*t)[y + 1 + 1][x]); | ||||
|     } | ||||
|   } | ||||
|   free(t); | ||||
|   return p; | ||||
| } | ||||
| static void *MagikarpX(CHAR w, unsigned char p[1u << w][1u << w], char yw, | ||||
|                        char xw) { | ||||
|   int y, x; | ||||
|   LONG yn, xn, xm; | ||||
|   yn = 1u << yw; | ||||
|   xn = 1u << xw; | ||||
|   xm = xn >> 1; | ||||
|   for (x = 0; x < xm; ++x) { | ||||
|     for (y = 0; y < yn; ++y) { | ||||
|       p[y][(xn - xm - 1) + (xm - x - 1)] = | ||||
|           C1331(p[y][MAX(00 + 0, xn - (x << 1) - 1 + (xn & 1) - 1)], | ||||
|                 p[y][MIN(xn - 1, xn - (x << 1) - 1 + (xn & 1) + 0)], | ||||
|                 p[y][MIN(xn - 1, xn - (x << 1) - 1 + (xn & 1) + 1)], | ||||
|                 p[y][MIN(xn - 1, xn - (x << 1) - 1 + (xn & 1) + 2)]); | ||||
|     } | ||||
|   } | ||||
|   for (x = 0; x < xm; ++x) { | ||||
|     for (y = 0; y < yn; ++y) { | ||||
|       p[y][x] = C161(p[y][MAX(xn - 1 - xm, xn - xm - 1 + x - 1)], | ||||
|                      p[y][MIN(xn - 1 - 00, xn - xm - 1 + x + 0)], | ||||
|                      p[y][MIN(xn - 1 - 00, xn - xm - 1 + x + 1)]); | ||||
|     } | ||||
|   } | ||||
|   return p; | ||||
| } | ||||
| static void ProcessImageVerbatim(LONG yn, LONG xn, | ||||
|                                  unsigned char img[yn][xn][4]) { | ||||
|   CHAR w; | ||||
|   void *R, *G, *B, *A; | ||||
|   w = _roundup2log(MAX(yn, xn)); | ||||
|   R = xvalloc((1u << w) * (1u << w)); | ||||
|   G = xvalloc((1u << w) * (1u << w)); | ||||
|   B = xvalloc((1u << w) * (1u << w)); | ||||
|   A = xvalloc((1u << w) * (1u << w)); | ||||
|   DeblinterlaceRgba(w, R, G, B, A, yn, xn, img); | ||||
|   PrintImage(w, R, G, B, A, yn, xn); | ||||
|   free(R); | ||||
|   free(G); | ||||
|   free(B); | ||||
|   free(A); | ||||
| } | ||||
| static void ProcessImageDouble(LONG yn, LONG xn, unsigned char img[yn][xn][4]) { | ||||
|   CHAR w; | ||||
|   void *t, *R, *G, *B, *A; | ||||
|   w = _roundup2log(MAX(yn, xn)) + 1; | ||||
|   t = xvalloc((1u << w) * (1u << w)); | ||||
|   R = xvalloc((1u << w) * (1u << w)); | ||||
|   G = xvalloc((1u << w) * (1u << w)); | ||||
|   B = xvalloc((1u << w) * (1u << w)); | ||||
|   A = xvalloc((1u << w) * (1u << w)); | ||||
|   DeblinterlaceRgba(w, R, G, B, A, yn, xn, img); | ||||
|   Upscale(w, R, t, w, w); | ||||
|   Upscale(w, G, t, w, w); | ||||
|   Upscale(w, B, t, w, w); | ||||
|   Upscale(w, A, t, w, w); | ||||
|   free(t); | ||||
|   PrintImage(w, R, G, B, A, yn * 2, xn * 2); | ||||
|   free(R); | ||||
|   free(G); | ||||
|   free(B); | ||||
|   free(A); | ||||
| } | ||||
| static void ProcessImageHalf(LONG yn, LONG xn, unsigned char img[yn][xn][4]) { | ||||
|   CHAR w; | ||||
|   void *R, *G, *B, *A; | ||||
|   w = _roundup2log(MAX(yn, xn)); | ||||
|   R = xvalloc((1u << w) * (1u << w)); | ||||
|   G = xvalloc((1u << w) * (1u << w)); | ||||
|   B = xvalloc((1u << w) * (1u << w)); | ||||
|   A = xvalloc((1u << w) * (1u << w)); | ||||
|   DeblinterlaceRgba(w, R, G, B, A, yn, xn, img); | ||||
|   MagikarpY(w, R, w, w); | ||||
|   MagikarpY(w, G, w, w); | ||||
|   MagikarpY(w, B, w, w); | ||||
|   MagikarpY(w, A, w, w); | ||||
|   MagikarpX(w, R, w - 1, w); | ||||
|   MagikarpX(w, G, w - 1, w); | ||||
|   MagikarpX(w, B, w - 1, w); | ||||
|   MagikarpX(w, A, w - 1, w); | ||||
|   PrintImage(w, R, G, B, A, yn >> 1, xn >> 1); | ||||
|   free(R); | ||||
|   free(G); | ||||
|   free(B); | ||||
|   free(A); | ||||
| } | ||||
| static void ProcessImageHalfY(LONG yn, LONG xn, unsigned char img[yn][xn][4]) { | ||||
|   CHAR w; | ||||
|   void *R, *G, *B, *A; | ||||
|   w = _roundup2log(MAX(yn, xn)); | ||||
|   R = xvalloc((1u << w) * (1u << w)); | ||||
|   G = xvalloc((1u << w) * (1u << w)); | ||||
|   B = xvalloc((1u << w) * (1u << w)); | ||||
|   A = xvalloc((1u << w) * (1u << w)); | ||||
|   DeblinterlaceRgba(w, R, G, B, A, yn, xn, img); | ||||
|   MagikarpY(w, R, w, w); | ||||
|   MagikarpY(w, G, w, w); | ||||
|   MagikarpY(w, B, w, w); | ||||
|   MagikarpY(w, A, w, w); | ||||
|   PrintImage(w, R, G, B, A, yn >> 1, xn); | ||||
|   free(R); | ||||
|   free(G); | ||||
|   free(B); | ||||
|   free(A); | ||||
| } | ||||
| static void ProcessImageHalfLanczos(LONG yn, LONG xn, | ||||
|                                     unsigned char img[yn][xn][4]) { | ||||
|   CHAR w; | ||||
|   void *t, *R, *G, *B, *A; | ||||
|   t = xvalloc((yn >> 1) * (xn >> 1) * 4); | ||||
|   lanczos1b(yn >> 1, xn >> 1, t, yn, xn, &img[0][0][0]); | ||||
|   w = _roundup2log(MAX(yn >> 1, xn >> 1)); | ||||
|   R = xvalloc((1u << w) * (1u << w)); | ||||
|   G = xvalloc((1u << w) * (1u << w)); | ||||
|   B = xvalloc((1u << w) * (1u << w)); | ||||
|   A = xvalloc((1u << w) * (1u << w)); | ||||
|   DeblinterlaceRgba(w, R, G, B, A, yn >> 1, xn >> 1, img); | ||||
|   free(t); | ||||
|   PrintImage(w, R, G, B, A, yn >> 1, xn >> 1); | ||||
|   free(R); | ||||
|   free(G); | ||||
|   free(B); | ||||
|   free(A); | ||||
| } | ||||
| static void ProcessImageWash(LONG yn, LONG xn, unsigned char img[yn][xn][4]) { | ||||
|   long w; | ||||
|   void *R, *G, *B, *A, *t; | ||||
|   w = _roundup2log(MAX(yn, xn)) + 1; | ||||
|   t = xvalloc((1u << w) * (1u << w)); | ||||
|   R = xvalloc((1u << w) * (1u << w)); | ||||
|   G = xvalloc((1u << w) * (1u << w)); | ||||
|   B = xvalloc((1u << w) * (1u << w)); | ||||
|   A = xvalloc((1u << w) * (1u << w)); | ||||
|   DeblinterlaceRgba(w, R, G, B, A, yn, xn, img); | ||||
|   Upscale(w, R, t, w, w); | ||||
|   Upscale(w, G, t, w, w); | ||||
|   Upscale(w, B, t, w, w); | ||||
|   Upscale(w, A, t, w, w); | ||||
|   MagikarpY(w, R, w, w); | ||||
|   MagikarpY(w, G, w, w); | ||||
|   MagikarpY(w, B, w, w); | ||||
|   MagikarpY(w, A, w, w); | ||||
|   MagikarpX(w, R, w - 1, w); | ||||
|   MagikarpX(w, G, w - 1, w); | ||||
|   MagikarpX(w, B, w - 1, w); | ||||
|   MagikarpX(w, A, w - 1, w); | ||||
|   free(t); | ||||
|   PrintImage(w, R, G, B, A, yn, xn); | ||||
|   free(R); | ||||
|   free(G); | ||||
|   free(B); | ||||
|   free(A); | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| #if 0 | ||||
| static void *MagikarpY(size_t ys, size_t xs, unsigned char p[ys][xs], size_t yn, | ||||
|                        size_t xn) { | ||||
|   int y, x, h, b; | ||||
|   b = yn % 2; | ||||
|   h = yn / 2; | ||||
|   if (b && yn < ys) yn++; | ||||
|   for (y = b; y < h + b; ++y) { | ||||
|     for (x = 0; x < xn; ++x) { | ||||
|       p[(yn - h - 1) + (h - y - 1)][x] = | ||||
|           C1331(p[MAX(00 + 0, yn - y * 2 - 1 - 1)][x], | ||||
|                 p[MIN(yn - 1, yn - y * 2 - 1 + 0)][x], | ||||
|                 p[MIN(yn - 1, yn - y * 2 - 1 + 1)][x], | ||||
|                 p[MIN(yn - 1, yn - y * 2 - 1 + 2)][x]); | ||||
|     } | ||||
|   } | ||||
|   for (y = b; y < h + b; ++y) { | ||||
|     for (x = 0; x < xn; ++x) { | ||||
|       p[y][x] = C161(p[MAX(yn - 1 - h, yn - h - 1 + y - 1)][x], | ||||
|                      p[MIN(yn - 1 - 0, yn - h - 1 + y + 0)][x], | ||||
|                      p[MIN(yn - 1 - 0, yn - h - 1 + y + 1)][x]); | ||||
|     } | ||||
|   } | ||||
|   return p; | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| #if 0 | ||||
| static void *MagikarpX(size_t ys, size_t xs, unsigned char p[ys][xs], size_t yn, | ||||
|                        size_t xn) { | ||||
|   int y, x, w, b; | ||||
|   b = xn % 2; | ||||
|   w = xn / 2; | ||||
|   if (b && xn < xs) xn++; | ||||
|   for (x = 0; x < w; ++x) { | ||||
|     for (y = b; y < yn + b; ++y) { | ||||
|       p[y][(xn - w - 1) + (w - x - 1)] = | ||||
|           C1331(p[y][MAX(00 + 0, xn - x * 2 - 1 - 1)], | ||||
|                 p[y][MIN(xn - 1, xn - x * 2 - 1 + 0)], | ||||
|                 p[y][MIN(xn - 1, xn - x * 2 - 1 + 1)], | ||||
|                 p[y][MIN(xn - 1, xn - x * 2 - 1 + 2)]); | ||||
|     } | ||||
|   } | ||||
|   for (x = 0; x < w; ++x) { | ||||
|     for (y = b; y < yn + b; ++y) { | ||||
|       p[y][x] = C161(p[y][MAX(xn - 1 - w, xn - w - 1 + x - 1)], | ||||
|                      p[y][MIN(xn - 1 - 0, xn - w - 1 + x + 0)], | ||||
|                      p[y][MIN(xn - 1 - 0, xn - w - 1 + x + 1)]); | ||||
|     } | ||||
|   } | ||||
|   return p; | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| #if 0 | ||||
| static void ProcessImageMagikarpImpl(CHAR sw, | ||||
|                                      unsigned char src[5][1u << sw][1u << sw], | ||||
|                                      LONG syn, LONG sxn, | ||||
|                                      const unsigned char img[syn][sxn][4], | ||||
|                                      LONG dyn, LONG dxn) { | ||||
|   DeblinterlaceRgba2(sw, src, syn, sxn, img); | ||||
|   MagikarpY(sw, src[0], sw, sw); | ||||
|   MagikarpX(sw, src[0], sw - 1, sw); | ||||
|   MagikarpY(sw, src[1], sw, sw); | ||||
|   MagikarpX(sw, src[1], sw - 1, sw); | ||||
|   MagikarpY(sw, src[2], sw, sw); | ||||
|   MagikarpX(sw, src[2], sw - 1, sw); | ||||
|   BilinearScale(sw, src[4], sw, src[3], dyn, dxn, syn, sxn); | ||||
|   memcpy(src[3], src[4], syn * sxn); | ||||
|   PrintImage2(sw, src, dyn, dxn); | ||||
| } | ||||
| static void ProcessImageMagikarp(LONG syn, LONG sxn, | ||||
|                                  unsigned char img[syn][sxn][4]) { | ||||
|   CHAR sw; | ||||
|   LONG dyn, dxn; | ||||
|   dyn = syn >> 1; | ||||
|   dxn = sxn >> 1; | ||||
|   sw = _roundup2log(MAX(syn, sxn)); | ||||
|   ProcessImageMagikarpImpl(sw, gc(xvalloc((1u << sw) * (1u << sw) * 5)), syn, | ||||
|                            sxn, img, dyn, dxn); | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| /*
 | ||||
| ******************************************************************************** | ||||
| */ | ||||
| 
 | ||||
| static unsigned char Opacify2(unsigned yw, unsigned xw, | ||||
|                               const unsigned char P[yw][xw], | ||||
|                               const unsigned char A[yw][xw], unsigned yn, | ||||
|                               unsigned xn, unsigned y, unsigned x) { | ||||
|   if ((0 <= y && y < yn) && (0 <= x && x < xn)) { | ||||
|     return LERP(AlphaBackground(y, x), P[y][x], A[y][x]); | ||||
|   } else { | ||||
|     return OutOfBoundsBackground(y, x); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| static dontinline void PrintImage2(unsigned yw, unsigned xw, | ||||
|                                    unsigned char img[4][yw][xw], unsigned yn, | ||||
|                                    unsigned xn) { | ||||
|   bool didhalfy; | ||||
|   unsigned y, x; | ||||
|   didhalfy = false; | ||||
|   for (y = 0; y < yn; y += 2) { | ||||
|     if (y) printf("\e[0m\n"); | ||||
|     for (x = 0; x < xn; ++x) { | ||||
|       printf("\e[48;2;%d;%d;%d;38;2;%d;%d;%dm▄", | ||||
|              Opacify2(yw, xw, img[0], img[3], yn, xn, y + 0, x), | ||||
|              Opacify2(yw, xw, img[1], img[3], yn, xn, y + 0, x), | ||||
|              Opacify2(yw, xw, img[2], img[3], yn, xn, y + 0, x), | ||||
|              Opacify2(yw, xw, img[0], img[3], yn, xn, y + 1, x), | ||||
|              Opacify2(yw, xw, img[1], img[3], yn, xn, y + 1, x), | ||||
|              Opacify2(yw, xw, img[2], img[3], yn, xn, y + 1, x)); | ||||
|     } | ||||
|     if (y == 0) { | ||||
|       printf("\e[0m‾0"); | ||||
|     } else if (yn / 2 <= y && y <= yn / 2 + 1 && !didhalfy) { | ||||
|       printf("\e[0m‾%s%s", "yn/2", y % 2 ? "+1" : ""); | ||||
|       didhalfy = true; | ||||
|     } else if (y + 1 == yn / 2 && !didhalfy) { | ||||
|       printf("\e[0m⎯yn/2"); | ||||
|       didhalfy = true; | ||||
|     } else if (y + 1 == yn) { | ||||
|       printf("\e[0m⎯yn"); | ||||
|     } else if (y + 2 == yn) { | ||||
|       printf("\e[0m_yn"); | ||||
|     } else if (!(y % 10)) { | ||||
|       printf("\e[0m‾%,u", y); | ||||
|     } | ||||
|   } | ||||
|   printf("\e[0m\n"); | ||||
| } | ||||
| 
 | ||||
| static dontinline void *DeblinterlaceRgba2(unsigned yn, unsigned xn, | ||||
|                                            unsigned char D[4][yn][xn], | ||||
|                                            const unsigned char S[yn][xn][4]) { | ||||
|   unsigned y, x; | ||||
|   for (y = 0; y < yn; ++y) { | ||||
|     for (x = 0; x < xn; ++x) { | ||||
|       D[0][y][x] = S[y][x][0]; | ||||
|       D[1][y][x] = S[y][x][1]; | ||||
|       D[2][y][x] = S[y][x][2]; | ||||
|       D[3][y][x] = S[y][x][3]; | ||||
|     } | ||||
|   } | ||||
|   return D; | ||||
| } | ||||
| 
 | ||||
| void ProcessImageBilinearImpl(unsigned dyn, unsigned dxn, | ||||
|                               unsigned char dst[4][dyn][dxn], unsigned syn, | ||||
|                               unsigned sxn, unsigned char src[4][syn][sxn], | ||||
|                               unsigned char img[syn][sxn][4]) { | ||||
|   DeblinterlaceRgba2(syn, sxn, src, img); | ||||
|   BilinearScale(4, dyn, dxn, dst, 4, syn, sxn, src, 0, 4, dyn, dxn, syn, sxn, | ||||
|                 r_, r_, 0, 0); | ||||
|   PrintImage2(dyn, dxn, dst, dyn, dxn); | ||||
| } | ||||
| 
 | ||||
| void ProcessImageBilinear(unsigned yn, unsigned xn, | ||||
|                           unsigned char img[yn][xn][4]) { | ||||
|   unsigned dyn, dxn; | ||||
|   dyn = lround(yn / r_); | ||||
|   dxn = lround(xn / r_); | ||||
|   ProcessImageBilinearImpl(dyn, dxn, gc(xmalloc(dyn * dxn * 4)), yn, xn, | ||||
|                            gc(xmalloc(yn * xn * 4)), img); | ||||
| } | ||||
| 
 | ||||
| static void *b2f(long n, float dst[n], const unsigned char src[n]) { | ||||
|   long i; | ||||
|   float f; | ||||
|   for (i = 0; i < n; ++i) { | ||||
|     f = src[i]; | ||||
|     f *= 1 / 255.; | ||||
|     dst[i] = f; | ||||
|   } | ||||
|   return dst; | ||||
| } | ||||
| 
 | ||||
| static void *f2b(long n, unsigned char dst[n], const float src[n]) { | ||||
|   int x; | ||||
|   long i; | ||||
|   for (i = 0; i < n; ++i) { | ||||
|     x = lroundf(src[i] * 255); | ||||
|     dst[i] = MIN(255, MAX(0, x)); | ||||
|   } | ||||
|   return dst; | ||||
| } | ||||
| 
 | ||||
| void ProcessImageGyarados(unsigned yn, unsigned xn, | ||||
|                           unsigned char img[yn][xn][4]) { | ||||
|   unsigned dyn, dxn; | ||||
|   dyn = lround(yn / r_); | ||||
|   dxn = lround(xn / r_); | ||||
|   PrintImage2( | ||||
|       dyn, dxn, | ||||
|       EzGyarados(4, dyn, dxn, gc(xmalloc(dyn * dxn * 4)), 4, yn, xn, | ||||
|                  DeblinterlaceRgba2(yn, xn, gc(xmalloc(yn * xn * 4)), img), 0, | ||||
|                  4, dyn, dxn, yn, xn, r_, r_, 0, 0), | ||||
|       dyn, dxn); | ||||
| } | ||||
| 
 | ||||
| void MagikarpDecimate(int yw, int xw, unsigned char img[4][yw][xw], int yn, | ||||
|                       int xn, int n) { | ||||
|   int c; | ||||
|   if (n <= 1) { | ||||
|     PrintImage2(yw, xw, img, yn, xn); | ||||
|   } else { | ||||
|     for (c = 0; c < 4; ++c) Magikarp2xY(yw, xw, img[c], yn, xn); | ||||
|     for (c = 0; c < 4; ++c) Magikarp2xX(yw, xw, img[c], (yn + 1) / 2, xn); | ||||
|     MagikarpDecimate(yw, xw, img, (yn + 1) / 2, (xn + 1) / 2, (n + 1) / 2); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| void ProcessImageMagikarp(unsigned yn, unsigned xn, | ||||
|                           unsigned char img[yn][xn][4]) { | ||||
|   MagikarpDecimate(yn, xn, | ||||
|                    DeblinterlaceRgba2(yn, xn, gc(xmalloc(yn * xn * 4)), img), | ||||
|                    yn, xn, lround(r_)); | ||||
| } | ||||
| 
 | ||||
| dontinline void WithImageFile(const char *path, | ||||
|                               void fn(unsigned yn, unsigned xn, | ||||
|                                       unsigned char img[yn][xn][4])) { | ||||
|   struct stat st; | ||||
|   int fd, yn, xn; | ||||
|   void *map, *data; | ||||
|   CHECK_NE(-1, (fd = open(path, O_RDONLY)), "%s", path); | ||||
|   CHECK_NE(-1, fstat(fd, &st)); | ||||
|   CHECK_GT(st.st_size, 0); | ||||
|   CHECK_LE(st.st_size, INT_MAX); | ||||
|   fadvise(fd, 0, 0, MADV_WILLNEED | MADV_SEQUENTIAL); | ||||
|   CHECK_NE(MAP_FAILED, | ||||
|            (map = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0))); | ||||
|   CHECK_NOTNULL( | ||||
|       (data = stbi_load_from_memory(map, st.st_size, &xn, &yn, NULL, 4)), "%s", | ||||
|       path); | ||||
|   CHECK_NE(-1, munmap(map, st.st_size)); | ||||
|   CHECK_NE(-1, close(fd)); | ||||
|   fn(yn, xn, data); | ||||
|   free(data); | ||||
| } | ||||
| 
 | ||||
| int main(int argc, char *argv[]) { | ||||
|   int i, opt; | ||||
|   bool bilinear; | ||||
|   void (*scaler)(unsigned yn, unsigned xn, unsigned char[yn][xn][4]) = | ||||
|       ProcessImageMagikarp; | ||||
|   r_ = 2; | ||||
|   while ((opt = getopt(argc, argv, "mlsSybr:")) != -1) { | ||||
|     switch (opt) { | ||||
|       case 'r': | ||||
|         r_ = strtod(optarg, NULL); | ||||
|         break; | ||||
|       case 'm': | ||||
|         scaler = ProcessImageMagikarp; | ||||
|         break; | ||||
|       case 's': | ||||
|       case 'S': | ||||
|         scaler = ProcessImageGyarados; | ||||
|         break; | ||||
|       case 'b': | ||||
|         scaler = ProcessImageBilinear; | ||||
|         break; | ||||
|       default: | ||||
|         break; | ||||
|     } | ||||
|   } | ||||
|   ShowCrashReports(); | ||||
|   for (i = optind; i < argc; ++i) { | ||||
|     WithImageFile(argv[i], scaler); | ||||
|   } | ||||
|   return 0; | ||||
| } | ||||
|  | @ -1,95 +0,0 @@ | |||
| #if 0 | ||||
| /*─────────────────────────────────────────────────────────────────╗
 | ||||
| │ To the extent possible under law, Justine Tunney has waived      │ | ||||
| │ all copyright and related or neighboring rights to this file,    │ | ||||
| │ as it is written in the following disclaimers:                   │ | ||||
| │   • http://unlicense.org/                                        │
 | ||||
| │   • http://creativecommons.org/publicdomain/zero/1.0/            │
 | ||||
| ╚─────────────────────────────────────────────────────────────────*/ | ||||
| #endif | ||||
| #include "libc/calls/internal.h" | ||||
| #include "libc/fmt/conv.h" | ||||
| #include "libc/fmt/itoa.h" | ||||
| #include "libc/intrin/bits.h" | ||||
| #include "libc/macros.internal.h" | ||||
| #include "libc/runtime/memtrack.internal.h" | ||||
| #include "libc/stdio/stdio.h" | ||||
| // clang-format off
 | ||||
| 
 | ||||
| struct WinArgs { | ||||
|   char *argv[4096]; | ||||
|   char *envp[4092]; | ||||
|   intptr_t auxv[2][2]; | ||||
|   char argblock[ARG_MAX / 2]; | ||||
|   char envblock[ARG_MAX / 2]; | ||||
| }; | ||||
| 
 | ||||
| //#define INCREMENT _roundup2pow(kAutomapSize/16)
 | ||||
| #define INCREMENT (64L*1024*1024*1024) | ||||
| 
 | ||||
| uint64_t last; | ||||
| 
 | ||||
| void plan2(uint64_t addr, uint64_t end, const char *name) { | ||||
|   char sz[32]; | ||||
|   sizefmt(sz, end-addr+1, 1024); | ||||
|   printf("%08x-%08x %-6s %s\n", addr>>16, end>>16, sz, name); | ||||
| } | ||||
| 
 | ||||
| void plan(uint64_t addr, uint64_t end, const char *name) { | ||||
|   uint64_t incr, next; | ||||
|   while (addr > last) { | ||||
|     if ((incr = last % INCREMENT)) { | ||||
|       incr = INCREMENT - incr; | ||||
|     } else { | ||||
|       incr = INCREMENT; | ||||
|     } | ||||
|     plan2(last,MIN(last+incr,addr)-1,"free"); | ||||
|     last = MIN(last+incr,addr); | ||||
|   } | ||||
|   while (addr <= end) { | ||||
|     if (end-addr+1 <= INCREMENT) { | ||||
|       plan2(addr,end,name); | ||||
|       last = end + 1; | ||||
|       break; | ||||
|     } | ||||
|     if (!(addr % INCREMENT)) { | ||||
|       plan2(addr, addr + INCREMENT - 1, name); | ||||
|       last = addr + INCREMENT; | ||||
|       addr += INCREMENT; | ||||
|     } else { | ||||
|       next = INCREMENT - addr % INCREMENT + addr; | ||||
|       plan2(addr, next - 1, name); | ||||
|       last = next; | ||||
|       addr = next; | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| int main(int argc, char *argv[]) { | ||||
|   uint64_t x, y; | ||||
| 
 | ||||
|   plan(0x00000000, 0x00200000-1, "null"); | ||||
|   plan(0x00200000, 0x00400000-1, "loader"); | ||||
|   if (!IsWindows() || IsAtLeastWindows10()) { | ||||
|     plan(0x00400000, 0x50000000-1, "image"); | ||||
|     plan(0x50000000, 0x7ffdffff, "arena"); | ||||
|     plan(0x7fff0000, 0x10007fffffff, "asan"); | ||||
|   } else { | ||||
|     plan(0x00400000, 0x01000000-1, "image"); | ||||
|   } | ||||
|   plan(kAutomapStart, kAutomapStart + kAutomapSize - 1, "automap"); | ||||
|   plan(kMemtrackStart, kMemtrackStart + kMemtrackSize - 1, "memtrack"); | ||||
|   plan(kFixedmapStart, kFixedmapStart + kFixedmapSize - 1, "fixedmap"); | ||||
|   if (IsWindows() && !IsAtLeastWindows10()) { | ||||
|     plan(0x50000000, 0x7ffdffff, "arena"); | ||||
|   } | ||||
|   x = GetStaticStackAddr(0); | ||||
|   y = ROUNDUP(sizeof(struct WinArgs), FRAMESIZE); | ||||
|   plan(x - y, x - 1, "winargs"); | ||||
|   plan(x, x + GetStackSize() - 1, "stack"); | ||||
|   if (!IsWindows() || IsAtLeastWindows10()) { | ||||
|     plan(0x7f0000000000, 0x800000000000 - 1, "kernel"); | ||||
|   } | ||||
| 
 | ||||
|   return 0; | ||||
| } | ||||
|  | @ -1,83 +0,0 @@ | |||
| /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
 | ||||
| │vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8                                :vi│ | ||||
| ╞══════════════════════════════════════════════════════════════════════════════╡ | ||||
| │ Copyright 2021 Justine Alexandra Roberts Tunney                              │ | ||||
| │                                                                              │ | ||||
| │ Permission to use, copy, modify, and/or distribute this software for         │ | ||||
| │ any purpose with or without fee is hereby granted, provided that the         │ | ||||
| │ above copyright notice and this permission notice appear in all copies.      │ | ||||
| │                                                                              │ | ||||
| │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL                │ | ||||
| │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED                │ | ||||
| │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE             │ | ||||
| │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL         │ | ||||
| │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR        │ | ||||
| │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER               │ | ||||
| │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR             │ | ||||
| │ PERFORMANCE OF THIS SOFTWARE.                                                │ | ||||
| ╚─────────────────────────────────────────────────────────────────────────────*/ | ||||
| #include "libc/macros.internal.h" | ||||
| #include "libc/mem/mem.h" | ||||
| #include "libc/runtime/runtime.h" | ||||
| #include "libc/stdio/stdio.h" | ||||
| #include "libc/str/str.h" | ||||
| #include "libc/x/xgetline.h" | ||||
| 
 | ||||
| #define DLL "iphlpapi" | ||||
| 
 | ||||
| /**
 | ||||
|  * @fileoverview Tool for adding rnew libraries to libc/nt/master.sh | ||||
|  * | ||||
|  * If provided with a /tmp/syms.txt file containing one symbol name per | ||||
|  * line, this tool will output the correctly tab indented shell code. | ||||
|  */ | ||||
| 
 | ||||
| int main(int argc, char *argv[]) { | ||||
|   FILE *f; | ||||
|   int i, n, t; | ||||
|   char *sym, tabs[64]; | ||||
|   ShowCrashReports(); | ||||
|   f = fopen("/tmp/syms.txt", "r"); | ||||
|   memset(tabs, '\t', 64); | ||||
|   while ((sym = _chomp(xgetline(f)))) { | ||||
|     if (strlen(sym)) { | ||||
|       printf("imp\t"); | ||||
| 
 | ||||
|       /* what we call the symbol */ | ||||
|       i = printf("'%s'", sym); | ||||
|       t = 0; | ||||
|       n = 56; | ||||
|       if (i % 8) ++t, i = ROUNDUP(i, 8); | ||||
|       t += (n - i) / 8; | ||||
|       printf("%.*s", t, tabs); | ||||
| 
 | ||||
|       /* what the kernel dll calls the symbol */ | ||||
|       i = printf("%s", sym); | ||||
|       t = 0; | ||||
|       n = 56; | ||||
|       if (i % 8) ++t, i = ROUNDUP(i, 8); | ||||
|       t += (n - i) / 8; | ||||
|       printf("%.*s", t, tabs); | ||||
| 
 | ||||
|       /* dll short name */ | ||||
|       i = printf("%s", DLL); | ||||
|       t = 0; | ||||
|       n = 16; | ||||
|       if (i % 8) ++t, i = ROUNDUP(i, 8); | ||||
|       t += (n - i) / 8; | ||||
|       printf("%.*s", t, tabs); | ||||
| 
 | ||||
|       /* hint */ | ||||
|       i = printf("0"); | ||||
|       t = 0; | ||||
|       n = 8; | ||||
|       if (i % 8) ++t, i = ROUNDUP(i, 8); | ||||
|       t += (n - i) / 8; | ||||
|       printf("%.*s", t, tabs); | ||||
| 
 | ||||
|       printf("\n"); | ||||
|     } | ||||
|     free(sym); | ||||
|   } | ||||
|   return 0; | ||||
| } | ||||
|  | @ -1,45 +0,0 @@ | |||
| /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
 | ||||
| │vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8                                :vi│ | ||||
| ╞══════════════════════════════════════════════════════════════════════════════╡ | ||||
| │ Copyright 2020 Justine Alexandra Roberts Tunney                              │ | ||||
| │                                                                              │ | ||||
| │ Permission to use, copy, modify, and/or distribute this software for         │ | ||||
| │ any purpose with or without fee is hereby granted, provided that the         │ | ||||
| │ above copyright notice and this permission notice appear in all copies.      │ | ||||
| │                                                                              │ | ||||
| │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL                │ | ||||
| │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED                │ | ||||
| │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE             │ | ||||
| │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL         │ | ||||
| │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR        │ | ||||
| │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER               │ | ||||
| │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR             │ | ||||
| │ PERFORMANCE OF THIS SOFTWARE.                                                │ | ||||
| ╚─────────────────────────────────────────────────────────────────────────────*/ | ||||
| #include "dsp/tty/quant.h" | ||||
| #include "dsp/tty/xtermname.h" | ||||
| #include "libc/fmt/conv.h" | ||||
| #include "libc/runtime/runtime.h" | ||||
| #include "libc/stdio/stdio.h" | ||||
| #include "libc/str/str.h" | ||||
| #include "libc/sysv/consts/ex.h" | ||||
| 
 | ||||
| int main(int argc, char *argv[]) { | ||||
|   int i; | ||||
|   struct TtyRgb tty; | ||||
|   unsigned rgb, r, g, b; | ||||
|   if (argc < 2) { | ||||
|     fprintf(stderr, "Usage: %s RRGGBB...\n", program_invocation_name); | ||||
|     exit(EX_USAGE); | ||||
|   } | ||||
|   for (i = 1; i < argc; ++i) { | ||||
|     rgb = strtol(argv[i], NULL, 16); | ||||
|     b = (rgb & 0x0000ff) >> 000; | ||||
|     g = (rgb & 0x00ff00) >> 010; | ||||
|     r = (rgb & 0xff0000) >> 020; | ||||
|     tty = rgb2tty(r, g, b); | ||||
|     printf("\e[48;5;%dm    \e[0m %d \\e[48;5;%dm %s #%02x%02x%02x\n", tty.xt, | ||||
|            tty.xt, tty.xt, IndexDoubleNulString(kXtermName, tty.xt), r, g, b); | ||||
|   } | ||||
|   return 0; | ||||
| } | ||||
|  | @ -1,135 +0,0 @@ | |||
| /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
 | ||||
| │vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8                                :vi│ | ||||
| ╞══════════════════════════════════════════════════════════════════════════════╡ | ||||
| │ Copyright 2020 Justine Alexandra Roberts Tunney                              │ | ||||
| │                                                                              │ | ||||
| │ Permission to use, copy, modify, and/or distribute this software for         │ | ||||
| │ any purpose with or without fee is hereby granted, provided that the         │ | ||||
| │ above copyright notice and this permission notice appear in all copies.      │ | ||||
| │                                                                              │ | ||||
| │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL                │ | ||||
| │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED                │ | ||||
| │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE             │ | ||||
| │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL         │ | ||||
| │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR        │ | ||||
| │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER               │ | ||||
| │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR             │ | ||||
| │ PERFORMANCE OF THIS SOFTWARE.                                                │ | ||||
| ╚─────────────────────────────────────────────────────────────────────────────*/ | ||||
| #include "dsp/tty/quant.h" | ||||
| #include "libc/calls/calls.h" | ||||
| #include "libc/log/check.h" | ||||
| #include "libc/mem/mem.h" | ||||
| #include "libc/runtime/runtime.h" | ||||
| #include "libc/stdio/stdio.h" | ||||
| #include "libc/str/str.h" | ||||
| #include "libc/sysv/consts/ex.h" | ||||
| #include "libc/sysv/consts/exit.h" | ||||
| #include "libc/sysv/consts/fileno.h" | ||||
| #include "third_party/getopt/getopt.internal.h" | ||||
| 
 | ||||
| #define kUsage \ | ||||
|   "Usage:\n\
 | ||||
| \n\ | ||||
|   %s [-cber] [-o FILE] [ARGS...]\n\ | ||||
| \n\ | ||||
| Flags:\n\ | ||||
| \n\ | ||||
|   -e         enable emphasis\n\ | ||||
|   -b         emit as background color\n\ | ||||
|   -r         print raw codes\n\ | ||||
|   -c         emit cleanup (reset) codes when done\n\ | ||||
|   -o FILE    redirects output [default: /dev/stdout]\n\ | ||||
| \n\ | ||||
| Arguments:\n\ | ||||
| \n\ | ||||
|   - may be passed via ARGS or STDIN (one per line)\n\ | ||||
|   - may be #RRGGBB or RRGGBB\n\ | ||||
|   - may be #RGB or RGB (#123 → #112233)\n\ | ||||
|   - anything else is printed verbatim\n\ | ||||
| \n" | ||||
| 
 | ||||
| static FILE *fout_; | ||||
| static size_t linecap_; | ||||
| static char *outpath_, *line_; | ||||
| static bool rawmode_, background_, emphasis_, cleanup_; | ||||
| 
 | ||||
| wontreturn void usage(int rc, FILE *f) { | ||||
|   fprintf(f, kUsage, program_invocation_name); | ||||
|   exit(rc); | ||||
| } | ||||
| 
 | ||||
| void getopts(int *argc, char *argv[]) { | ||||
|   int opt; | ||||
|   outpath_ = "-"; | ||||
|   while ((opt = getopt(*argc, argv, "?hrecbo:")) != -1) { | ||||
|     switch (opt) { | ||||
|       case 'r': | ||||
|         rawmode_ = true; | ||||
|         break; | ||||
|       case 'b': | ||||
|         background_ = true; | ||||
|         break; | ||||
|       case 'c': | ||||
|         cleanup_ = true; | ||||
|         break; | ||||
|       case 'e': | ||||
|         emphasis_ = true; | ||||
|         break; | ||||
|       case 'o': | ||||
|         outpath_ = optarg; | ||||
|         break; | ||||
|       case '?': | ||||
|       case 'h': | ||||
|         usage(EXIT_SUCCESS, stdout); | ||||
|       default: | ||||
|         usage(EX_USAGE, stderr); | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| void processarg(const char *arg) { | ||||
|   const char *p; | ||||
|   size_t r, g, b; | ||||
|   if (*(p = arg) == '#') p++; | ||||
|   if (strlen(p) == 3 && (isxdigit(p[0]) && isxdigit(p[1]) && isxdigit(p[2]))) { | ||||
|     r = hextoint(p[0]) << 4 | hextoint(p[0]); | ||||
|     g = hextoint(p[1]) << 4 | hextoint(p[1]); | ||||
|     b = hextoint(p[2]) << 4 | hextoint(p[2]); | ||||
|   } else if (strlen(p) == 6 && | ||||
|              (isxdigit(p[0]) && isxdigit(p[1]) && isxdigit(p[2]) && | ||||
|               isxdigit(p[3]) && isxdigit(p[4]) && isxdigit(p[5]))) { | ||||
|     r = hextoint(p[0]) << 4 | hextoint(p[1]); | ||||
|     g = hextoint(p[2]) << 4 | hextoint(p[3]); | ||||
|     b = hextoint(p[4]) << 4 | hextoint(p[5]); | ||||
|   } else { | ||||
|     fputs(arg, fout_); | ||||
|     return; | ||||
|   } | ||||
|   fprintf(fout_, "%s[%s%d;5;%hhum%s", rawmode_ ? "\e" : "\\e", | ||||
|           emphasis_ ? "1;" : "", background_ ? 48 : 38, rgb2tty(r, g, b).xt, | ||||
|           &"\n"[rawmode_]); | ||||
| } | ||||
| 
 | ||||
| int main(int argc, char *argv[]) { | ||||
|   size_t i; | ||||
|   getopts(&argc, argv); | ||||
|   CHECK_NOTNULL((fout_ = fopen(outpath_, "w"))); | ||||
|   if (optind < argc) { | ||||
|     for (i = optind; i < argc; ++i) { | ||||
|       processarg(argv[i]); | ||||
|     } | ||||
|   } else { | ||||
|     while ((getline(&line_, &linecap_, stdin)) != -1) { | ||||
|       processarg(_chomp(line_)); | ||||
|     } | ||||
|     free(line_); | ||||
|     line_ = 0; | ||||
|   } | ||||
|   if (cleanup_) { | ||||
|     fprintf(fout_, "%s[0m\n", rawmode_ ? "\e" : "\\e"); | ||||
|   } | ||||
|   CHECK_NE(-1, fclose(fout_)); | ||||
|   fout_ = 0; | ||||
|   return 0; | ||||
| } | ||||
|  | @ -1,177 +0,0 @@ | |||
| /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
 | ||||
| │vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8                                :vi│ | ||||
| ╞══════════════════════════════════════════════════════════════════════════════╡ | ||||
| │ Copyright 2020 Justine Alexandra Roberts Tunney                              │ | ||||
| │                                                                              │ | ||||
| │ Permission to use, copy, modify, and/or distribute this software for         │ | ||||
| │ any purpose with or without fee is hereby granted, provided that the         │ | ||||
| │ above copyright notice and this permission notice appear in all copies.      │ | ||||
| │                                                                              │ | ||||
| │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL                │ | ||||
| │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED                │ | ||||
| │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE             │ | ||||
| │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL         │ | ||||
| │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR        │ | ||||
| │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER               │ | ||||
| │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR             │ | ||||
| │ PERFORMANCE OF THIS SOFTWARE.                                                │ | ||||
| ╚─────────────────────────────────────────────────────────────────────────────*/ | ||||
| #include "libc/fmt/conv.h" | ||||
| #include "libc/intrin/safemacros.internal.h" | ||||
| #include "libc/limits.h" | ||||
| #include "libc/log/check.h" | ||||
| #include "libc/log/log.h" | ||||
| #include "libc/mem/arraylist.internal.h" | ||||
| #include "libc/mem/mem.h" | ||||
| #include "libc/runtime/runtime.h" | ||||
| #include "libc/stdio/stdio.h" | ||||
| #include "libc/str/str.h" | ||||
| #include "libc/str/strwidth.h" | ||||
| #include "libc/str/unicode.h" | ||||
| #include "libc/sysv/consts/ex.h" | ||||
| #include "libc/sysv/consts/exit.h" | ||||
| #include "third_party/getopt/getopt.internal.h" | ||||
| 
 | ||||
| #define kOneTrueTabWidth 8 | ||||
| 
 | ||||
| struct Pool { | ||||
|   size_t i, n; | ||||
|   char *p; | ||||
| }; | ||||
| 
 | ||||
| struct Lines { | ||||
|   size_t i, n; | ||||
|   struct Line { | ||||
|     uint16_t off; | ||||
|     uint16_t col; | ||||
|     int32_t line; | ||||
|   } * p; | ||||
| }; | ||||
| 
 | ||||
| static bool chunk_; | ||||
| static FILE *fi_, *fo_; | ||||
| static struct Pool pool_; | ||||
| static struct Lines lines_; | ||||
| static size_t mincol_, col_, maxcol_, linecap_; | ||||
| static char *inpath_, *outpath_, *delim_, *line_; | ||||
| 
 | ||||
| wontreturn void usage(int rc, FILE *f) { | ||||
|   fprintf(f, "%s%s%s\n", "Usage: ", program_invocation_name, | ||||
|           " [-c] [-m MINCOL] [-M MAXCOL] [-F DELIM] [-o FILE] [FILE...]\n" | ||||
|           "\n" | ||||
|           "  This program aligns monospace text. It's aware of tabs,\n" | ||||
|           "  color codes, wide characters, combining characters etc.\n"); | ||||
|   exit(rc); | ||||
| } | ||||
| 
 | ||||
| void getopts(int *argc, char *argv[]) { | ||||
|   int opt; | ||||
|   delim_ = "#"; | ||||
|   outpath_ = "-"; | ||||
|   while ((opt = getopt(*argc, argv, "?hco:m:M:F:")) != -1) { | ||||
|     switch (opt) { | ||||
|       case 'm': | ||||
|         mincol_ = strtol(optarg, NULL, 0); | ||||
|         break; | ||||
|       case 'M': | ||||
|         maxcol_ = strtol(optarg, NULL, 0); | ||||
|         break; | ||||
|       case 'c': | ||||
|         chunk_ = true; | ||||
|         break; | ||||
|       case 'o': | ||||
|         outpath_ = optarg; | ||||
|         break; | ||||
|       case 'F': | ||||
|         delim_ = optarg; | ||||
|         break; | ||||
|       case '?': | ||||
|       case 'h': | ||||
|         usage(EXIT_SUCCESS, stdout); | ||||
|       default: | ||||
|         usage(EX_USAGE, stderr); | ||||
|     } | ||||
|   } | ||||
|   if (optind == *argc) { | ||||
|     argv[(*argc)++] = "-"; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| void flush(void) { | ||||
|   size_t i, j; | ||||
|   const char *s; | ||||
|   struct Line l; | ||||
|   col_ = roundup(col_ + 1, kOneTrueTabWidth); | ||||
|   if (maxcol_) col_ = min(col_, maxcol_); | ||||
|   for (i = 0; i < lines_.i; ++i) { | ||||
|     l = lines_.p[i]; | ||||
|     s = &pool_.p[l.line]; | ||||
|     if (l.off < USHRT_MAX) { | ||||
|       fwrite(s, l.off, 1, fo_); | ||||
|       for (j = l.col; j < col_;) { | ||||
|         fputc('\t', fo_); | ||||
|         if (j % kOneTrueTabWidth == 0) { | ||||
|           j += 8; | ||||
|         } else { | ||||
|           j += kOneTrueTabWidth - (j & (kOneTrueTabWidth - 1)); | ||||
|         } | ||||
|       } | ||||
|       fwrite(s + l.off, strlen(s) - l.off, 1, fo_); | ||||
|     } else { | ||||
|       fwrite(s, strlen(s), 1, fo_); | ||||
|     } | ||||
|     fputc('\n', fo_); | ||||
|   } | ||||
|   col_ = mincol_; | ||||
|   pool_.i = 0; | ||||
|   lines_.i = 0; | ||||
| } | ||||
| 
 | ||||
| void processfile(void) { | ||||
|   char *p; | ||||
|   int col, s; | ||||
|   size_t off, len; | ||||
|   while ((getline(&line_, &linecap_, fi_)) != -1) { | ||||
|     _chomp(line_); | ||||
|     len = strlen(line_); | ||||
|     s = concat(&pool_, line_, len + 1); | ||||
|     if (len < USHRT_MAX) { | ||||
|       if ((p = strstr(line_, delim_))) { | ||||
|         off = p - line_; | ||||
|         col = strnwidth(line_, off, 0); | ||||
|         if (col < USHRT_MAX) { | ||||
|           col_ = max(col_, col); | ||||
|           append(&lines_, &((struct Line){.line = s, .off = off, .col = col})); | ||||
|           continue; | ||||
|         } | ||||
|       } else { | ||||
|         if (chunk_) { | ||||
|           flush(); | ||||
|           fputs(line_, fo_); | ||||
|           fputc('\n', fo_); | ||||
|           continue; | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|     append(&lines_, &((struct Line){.line = s, .off = 0xffff, .col = 0xffff})); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| int main(int argc, char *argv[]) { | ||||
|   size_t i; | ||||
|   getopts(&argc, argv); | ||||
|   CHECK_NOTNULL((fo_ = fopen(outpath_, "w"))); | ||||
|   for (i = optind; i < argc; ++i) { | ||||
|     CHECK_NOTNULL((fi_ = fopen((inpath_ = argv[i]), "r"))); | ||||
|     processfile(); | ||||
|     CHECK_NE(-1, fclose(fi_)); | ||||
|     fi_ = 0; | ||||
|   } | ||||
|   flush(); | ||||
|   CHECK_NE(-1, fclose(fo_)); | ||||
|   fo_ = 0; | ||||
|   free(lines_.p); | ||||
|   free(pool_.p); | ||||
|   free(line_); | ||||
|   return 0; | ||||
| } | ||||
							
								
								
									
										156
									
								
								tool/viz/tcp.c
									
										
									
									
									
								
							
							
						
						
									
										156
									
								
								tool/viz/tcp.c
									
										
									
									
									
								
							|  | @ -1,156 +0,0 @@ | |||
| #if 0 | ||||
| /*─────────────────────────────────────────────────────────────────╗
 | ||||
| │ To the extent possible under law, Justine Tunney has waived      │ | ||||
| │ all copyright and related or neighboring rights to this file,    │ | ||||
| │ as it is written in the following disclaimers:                   │ | ||||
| │   • http://unlicense.org/                                        │
 | ||||
| │   • http://creativecommons.org/publicdomain/zero/1.0/            │
 | ||||
| ╚─────────────────────────────────────────────────────────────────*/ | ||||
| #endif | ||||
| #include "libc/intrin/bits.h" | ||||
| #include "libc/stdio/stdio.h" | ||||
| // clang-format off
 | ||||
| 
 | ||||
| static char ip[] = "\
 | ||||
| \x45\x00\x00\x3c\xc8\xbc\x40\x00\x40\x06\x48\xf6\x7f\x0a\x0a\x7a\ | ||||
| \x7f\x0a\x0a\x7c\xe2\x24\x1b\x58\xf6\xe9\xf2\x85\x00\x00\x00\x00\ | ||||
| \xa0\x02\xfa\xf0\x5f\xac\x00\x00\x02\x04\x05\xb4\x04\x02\x08\x0a\ | ||||
| \x4a\x43\x93\x29\x00\x00\x00\x00\x01\x03\x03\x07"; | ||||
| 
 | ||||
| static const char *const kTcpOptionNames[] = { | ||||
|     [0] = "End of Option List", | ||||
|     [1] = "No-Operation", | ||||
|     [2] = "Maximum Segment Size", | ||||
|     [3] = "Window Scale", | ||||
|     [4] = "SACK Permitted", | ||||
|     [5] = "SACK", | ||||
|     [6] = "Echo (obsoleted by option 8)", | ||||
|     [7] = "Echo Reply (obsoleted by option 8)", | ||||
|     [8] = "Timestamps", | ||||
|     [9] = "Partial Order Connection Permitted (obsolete)", | ||||
|     [10] = "Partial Order Service Profile (obsolete)", | ||||
|     [11] = "CC (obsolete)", | ||||
|     [12] = "CC.NEW (obsolete)", | ||||
|     [13] = "CC.ECHO (obsolete)", | ||||
|     [14] = "TCP Alternate Checksum Request (obsolete)", | ||||
|     [15] = "TCP Alternate Checksum Data (obsolete)", | ||||
|     [16] = "Skeeter", | ||||
|     [17] = "Bubba", | ||||
|     [18] = "Trailer Checksum Option", | ||||
|     [19] = "MD5 Signature Option (obsoleted by option 29)", | ||||
|     [20] = "SCPS Capabilities", | ||||
|     [21] = "Selective Negative Acknowledgements", | ||||
|     [22] = "Record Boundaries", | ||||
|     [23] = "Corruption experienced", | ||||
|     [24] = "SNAP", | ||||
|     [25] = "Unassigned (released 2000-12-18)", | ||||
|     [26] = "TCP Compression Filter", | ||||
|     [27] = "Quick-Start Response", | ||||
|     [28] = "User Timeout Option", | ||||
|     [29] = "TCP Authentication Option (TCP-AO)", | ||||
|     [30] = "Multipath TCP (MPTCP)", | ||||
|     [31] = "Reserved (known unauthorized use without proper IANA assignm", | ||||
|     [32] = "Reserved (known unauthorized use without proper IANA assignm", | ||||
|     [33] = "Reserved (known unauthorized use without proper IANA assignm", | ||||
|     [34] = "variable TCP Fast Open Cookie", | ||||
|     [35] = "Reserved", | ||||
|     [69] = "Encryption Negotiation", | ||||
|     [253] = "RFC3692-1", | ||||
|     [254] = "RFC3692-2", | ||||
| }; | ||||
| 
 | ||||
| int main(int argc, char *argv[]) { | ||||
|   int version = (ip[0] & 0b11110000) >> 4; | ||||
|   int ihl = (ip[0] & 0b00001111) >> 0; | ||||
|   int dscp = (ip[1] & 0b11111100) >> 2; | ||||
|   int ecn = (ip[1] & 0b00000011) >> 0; | ||||
|   int lengthtotal = READ16BE(ip + 2); | ||||
|   int identification = READ16BE(ip + 4); | ||||
|   int flags = (ip[6] & 0b11100000) >> 5; | ||||
|   int fragmentoffset = (ip[6] & 0b00011111) << 8 | (ip[7] & 255); | ||||
|   int ttl = ip[8] & 255; | ||||
|   int protocol = ip[9] & 255; | ||||
|   int ipchecksum = (ip[10] & 255) << 8 | (ip[11] & 255); | ||||
|   int srcip = READ32BE(ip + 12); | ||||
|   int dstip = READ32BE(ip + 16); | ||||
| 
 | ||||
|   printf("\n"); | ||||
|   printf("// version        = %u\n", version); | ||||
|   printf("// ihl            = %u\n", ihl * 4); | ||||
|   printf("// dscp           = %u\n", dscp); | ||||
|   printf("// ecn            = %u\n", ecn); | ||||
|   printf("// lengthtotal    = %u\n", lengthtotal); | ||||
|   printf("// identification = %u\n", identification); | ||||
|   printf("// flags          = %u\n", flags); | ||||
|   printf("// fragmentoffset = %u\n", fragmentoffset); | ||||
|   printf("// ttl            = %u\n", ttl); | ||||
|   printf("// protocol       = %u\n", protocol); | ||||
|   printf("// ipchecksum     = %u\n", ipchecksum); | ||||
|   printf("// srcip          = %hhu.%hhu.%hhu.%hhu\n", srcip >> 24, srcip >> 16, srcip >> 8, srcip); | ||||
|   printf("// dstip          = %hhu.%hhu.%hhu.%hhu\n", dstip >> 24, dstip >> 16, dstip >> 8, dstip); | ||||
|   printf("// \n"); | ||||
| 
 | ||||
|   char *tcp = ip + ihl * 4; | ||||
|   int srcport = READ16BE(tcp + 0); | ||||
|   int dstport = READ16BE(tcp + 2); | ||||
|   int sequence = READ32BE(tcp + 4); | ||||
|   int acknumber = READ32BE(tcp + 8); | ||||
|   int dataoffset = (tcp[12] & 0b11110000) >> 4; | ||||
|   bool ns = !!(tcp[12] & 0b00000001); | ||||
|   bool cwr = !!(tcp[13] & 0b10000000); | ||||
|   bool ece = !!(tcp[13] & 0b01000000); | ||||
|   bool urg = !!(tcp[13] & 0b00100000); | ||||
|   bool ack = !!(tcp[13] & 0b00010000); | ||||
|   bool psh = !!(tcp[13] & 0b00001000); | ||||
|   bool rst = !!(tcp[13] & 0b00000100); | ||||
|   bool syn = !!(tcp[13] & 0b00000010); | ||||
|   bool fin = !!(tcp[13] & 0b00000001); | ||||
|   int wsize = READ16BE(tcp + 14); | ||||
|   int tcpchecksum = READ16BE(tcp + 16); | ||||
|   int urgpointer = READ16BE(tcp + 18); | ||||
| 
 | ||||
|   printf("// srcport     = %u\n", srcport); | ||||
|   printf("// dstport     = %u\n", dstport); | ||||
|   printf("// sequence    = %u\n", sequence); | ||||
|   printf("// acknumber   = %u\n", acknumber); | ||||
|   printf("// dataoffset  = %u\n", dataoffset); | ||||
|   printf("// ns          = %u\n", ns); | ||||
|   printf("// cwr         = %u\n", cwr); | ||||
|   printf("// ece         = %u\n", ece); | ||||
|   printf("// urg         = %u\n", urg); | ||||
|   printf("// ack         = %u\n", ack); | ||||
|   printf("// psh         = %u\n", psh); | ||||
|   printf("// rst         = %u\n", rst); | ||||
|   printf("// syn         = %u\n", syn); | ||||
|   printf("// fin         = %u\n", fin); | ||||
|   printf("// wsize       = %u\n", wsize); | ||||
|   printf("// tcpchecksum = %u\n", tcpchecksum); | ||||
|   printf("// urgpointer  = %u\n", urgpointer); | ||||
|   printf("// \n"); | ||||
| 
 | ||||
|   int c, i, j, n; | ||||
|   for (i = 20; i + 1 < dataoffset * 4;) { | ||||
|     printf("// option"); | ||||
|     switch ((c = tcp[i] & 255)) { | ||||
|       case 0: | ||||
|       case 1: | ||||
|         printf(" %u", c); | ||||
|         ++i; | ||||
|         break; | ||||
|       default: | ||||
|         n = tcp[i + 1] & 255; | ||||
|         printf(" %u %u", c, n); | ||||
|         for (j = 2; j < n; ++j) { | ||||
|           printf(" %u", tcp[i + j] & 255); | ||||
|         } | ||||
|         i += n; | ||||
|         break; | ||||
|     } | ||||
|     if (kTcpOptionNames[c]) { | ||||
|       printf(" (%s)", kTcpOptionNames[c]); | ||||
|     } | ||||
|     printf("\n"); | ||||
|   } | ||||
| 
 | ||||
|   return 0; | ||||
| } | ||||
|  | @ -1,91 +0,0 @@ | |||
| /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
 | ||||
| │vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8                                :vi│ | ||||
| ╞══════════════════════════════════════════════════════════════════════════════╡ | ||||
| │ Copyright 2020 Justine Alexandra Roberts Tunney                              │ | ||||
| │                                                                              │ | ||||
| │ Permission to use, copy, modify, and/or distribute this software for         │ | ||||
| │ any purpose with or without fee is hereby granted, provided that the         │ | ||||
| │ above copyright notice and this permission notice appear in all copies.      │ | ||||
| │                                                                              │ | ||||
| │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL                │ | ||||
| │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED                │ | ||||
| │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE             │ | ||||
| │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL         │ | ||||
| │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR        │ | ||||
| │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER               │ | ||||
| │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR             │ | ||||
| │ PERFORMANCE OF THIS SOFTWARE.                                                │ | ||||
| ╚─────────────────────────────────────────────────────────────────────────────*/ | ||||
| #include "libc/str/unicode.h" | ||||
| #include "libc/fmt/fmt.h" | ||||
| #include "libc/mem/gc.h" | ||||
| #include "libc/mem/mem.h" | ||||
| #include "libc/stdio/stdio.h" | ||||
| #include "libc/str/str.h" | ||||
| #include "libc/x/xasprintf.h" | ||||
| 
 | ||||
| int a, b, w, i; | ||||
| char name[512]; | ||||
| 
 | ||||
| void DisplayUnicodeCharacter(void) { | ||||
|   int c, cw; | ||||
|   c = i; | ||||
|   cw = wcwidth(c); | ||||
|   if (cw < 1) { | ||||
|     c = '?'; | ||||
|     cw = 1; | ||||
|   } | ||||
|   if (w) { | ||||
|     if (w + 1 + cw > 80) { | ||||
|       printf("\n"); | ||||
|       w = 0; | ||||
|     } else { | ||||
|       fputc(' ', stdout); | ||||
|       w += 1 + cw; | ||||
|     } | ||||
|   } | ||||
|   if (!w) { | ||||
|     printf("%08x ", i); | ||||
|     w = 9 + cw; | ||||
|   } | ||||
|   fputwc(c, stdout); | ||||
| } | ||||
| 
 | ||||
| void DisplayUnicodeBlock(void) { | ||||
|   if (a == 0x10000) { | ||||
|     printf("\n\n\n\n\n\n\n                                " | ||||
|            "ASTRAL PLANES\n\n\n\n\n"); | ||||
|   } | ||||
|   if (a == 0x0590 /* hebrew */) return; | ||||
|   if (a == 0x0600 /* arabic */) return; | ||||
|   if (a == 0x08a0 /* arabic */) return; | ||||
|   if (a == 0x0750 /* arabic */) return; | ||||
|   if (a == 0x0700 /* syriac */) return; | ||||
|   if (a == 0x10800 /* cypriot */) return; | ||||
|   printf("\n\n%-60s%20s\n" | ||||
|          "──────────────────────────────────────────────" | ||||
|          "──────────────────────────────────\n", | ||||
|          name, _gc(xasprintf("%04x .. %04x", a, b))); | ||||
|   w = 0; | ||||
|   for (i = a; i <= b; ++i) { | ||||
|     DisplayUnicodeCharacter(); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| int main(int argc, char *argv[]) { | ||||
|   FILE *f; | ||||
|   char *line; | ||||
|   size_t linesize; | ||||
|   printf("\n\n\n\n\n                                UNICODE PLANES\n\n\n\n"); | ||||
|   f = fopen("libc/str/blocks.txt", "r"); | ||||
|   line = NULL; | ||||
|   linesize = 0; | ||||
|   while (!feof(f)) { | ||||
|     if (getline(&line, &linesize, f) == -1) break; | ||||
|     if (sscanf(line, "%x..%x; %s", &a, &b, name) != 3) continue; | ||||
|     DisplayUnicodeBlock(); | ||||
|   } | ||||
|   free(line); | ||||
|   fclose(f); | ||||
|   return 0; | ||||
| } | ||||
|  | @ -1,212 +0,0 @@ | |||
| /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
 | ||||
| │vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8                                :vi│ | ||||
| ╞══════════════════════════════════════════════════════════════════════════════╡ | ||||
| │ Copyright 2020 Justine Alexandra Roberts Tunney                              │ | ||||
| │                                                                              │ | ||||
| │ Permission to use, copy, modify, and/or distribute this software for         │ | ||||
| │ any purpose with or without fee is hereby granted, provided that the         │ | ||||
| │ above copyright notice and this permission notice appear in all copies.      │ | ||||
| │                                                                              │ | ||||
| │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL                │ | ||||
| │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED                │ | ||||
| │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE             │ | ||||
| │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL         │ | ||||
| │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR        │ | ||||
| │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER               │ | ||||
| │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR             │ | ||||
| │ PERFORMANCE OF THIS SOFTWARE.                                                │ | ||||
| ╚─────────────────────────────────────────────────────────────────────────────*/ | ||||
| #include "libc/assert.h" | ||||
| #include "libc/calls/calls.h" | ||||
| #include "libc/calls/struct/stat.h" | ||||
| #include "libc/limits.h" | ||||
| #include "libc/log/check.h" | ||||
| #include "libc/macros.internal.h" | ||||
| #include "libc/math.h" | ||||
| #include "libc/mem/mem.h" | ||||
| #include "libc/runtime/runtime.h" | ||||
| #include "libc/stdio/stdio.h" | ||||
| #include "libc/str/str.h" | ||||
| #include "libc/sysv/consts/madv.h" | ||||
| #include "libc/sysv/consts/map.h" | ||||
| #include "libc/sysv/consts/o.h" | ||||
| #include "libc/sysv/consts/prot.h" | ||||
| #include "libc/x/x.h" | ||||
| #include "third_party/stb/stb_image.h" | ||||
| 
 | ||||
| #define C13(A, B)     (((A) + 3 * (B)) / 4) | ||||
| #define S3T(A, B, C)  MAX(0, ((24 * (B)) - (4 * ((A) + (C)))) / 16) | ||||
| #define LERP(A, B, P) ((A) * (1 - (P)) + (B) * (P)) | ||||
| 
 | ||||
| float ByteToFloat(int b) { | ||||
|   return 1 / 255.f * b; | ||||
| } | ||||
| 
 | ||||
| int FloatToByte(float f) { | ||||
|   return MAX(0, MIN(255, roundf(255 * f))); | ||||
| } | ||||
| 
 | ||||
| float ChessBoard(unsigned y, unsigned x, float a, float b) { | ||||
|   return !((y ^ x) & (1u << 2)) ? a : b; | ||||
| } | ||||
| 
 | ||||
| float AlphaBackground(unsigned y, unsigned x) { | ||||
|   return ChessBoard(y, x, 1.f, .7f); | ||||
| } | ||||
| 
 | ||||
| float OutOfBoundsBackground(unsigned y, unsigned x) { | ||||
|   return ChessBoard(y, x, .01f, .02f); | ||||
| } | ||||
| 
 | ||||
| float Opacify(size_t yn, size_t xn, const float P[yn][xn], | ||||
|               const float A[yn][xn], long y, long x) { | ||||
|   if ((0 <= y && y < yn) && (0 <= x && x < xn)) { | ||||
|     return LERP(AlphaBackground(y, x), P[y][x], A[y][x]); | ||||
|   } else { | ||||
|     return OutOfBoundsBackground(y, x); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| void PrintImage(size_t yn, size_t xn, float R[yn][xn], float G[yn][xn], | ||||
|                 float B[yn][xn], float A[yn][xn]) { | ||||
|   unsigned y, x; | ||||
|   for (y = 0; y < yn; y += 2) { | ||||
|     if (y) printf("\e[0m\n"); | ||||
|     for (x = 0; x < xn; ++x) { | ||||
|       printf("\e[48;2;%d;%d;%d;38;2;%d;%d;%dm▄", | ||||
|              FloatToByte(Opacify(yn, xn, R, A, y + 0, x)), | ||||
|              FloatToByte(Opacify(yn, xn, G, A, y + 0, x)), | ||||
|              FloatToByte(Opacify(yn, xn, B, A, y + 0, x)), | ||||
|              FloatToByte(Opacify(yn, xn, R, A, y + 1, x)), | ||||
|              FloatToByte(Opacify(yn, xn, G, A, y + 1, x)), | ||||
|              FloatToByte(Opacify(yn, xn, B, A, y + 1, x))); | ||||
|     } | ||||
|   } | ||||
|   printf("\e[0m\n"); | ||||
| } | ||||
| 
 | ||||
| void DeblinterlaceRgba(size_t dyn, size_t dxn, float R[dyn][dxn], | ||||
|                        float G[dyn][dxn], float B[dyn][dxn], float A[dyn][dxn], | ||||
|                        size_t syn, size_t sxn, | ||||
|                        const unsigned char src[syn][sxn][4]) { | ||||
|   unsigned y, x; | ||||
|   for (y = 0; y < syn; ++y) { | ||||
|     for (x = 0; x < sxn; ++x) { | ||||
|       R[y][x] = ByteToFloat(src[y][x][0]); | ||||
|       G[y][x] = ByteToFloat(src[y][x][1]); | ||||
|       B[y][x] = ByteToFloat(src[y][x][2]); | ||||
|       A[y][x] = ByteToFloat(src[y][x][3]); | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| void SharpenX(size_t yw, size_t xw, float dst[yw][xw], const float src[yw][xw], | ||||
|               size_t yn, size_t xn) { | ||||
|   int y, x; | ||||
|   for (y = 0; y < yn; ++y) { | ||||
|     for (x = 0; x < xn; ++x) { | ||||
|       dst[y][x] = | ||||
|           S3T(src[y][MAX(0, x - 1)], src[y][x], src[y][MIN(xn - 1, x + 1)]); | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| void SharpenY(size_t yw, size_t xw, float dst[yw][xw], const float src[yw][xw], | ||||
|               size_t yn, size_t xn) { | ||||
|   int y, x; | ||||
|   for (y = 0; y < yn; ++y) { | ||||
|     for (x = 0; x < xn; ++x) { | ||||
|       dst[y][x] = | ||||
|           S3T(src[MAX(0, y - 1)][x], src[y][x], src[MIN(yn - 1, y + 1)][x]); | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| void UpscaleX(size_t yw, size_t xw, float img[yw][xw], size_t yn, size_t xn) { | ||||
|   unsigned y, x; | ||||
|   for (y = yn; y--;) { | ||||
|     for (x = xn; --x;) { | ||||
|       img[y][x] = | ||||
|           C13(img[y][MIN(xn / 2 - 1, x / 2 - 1 + x % 2 * 2)], img[y][x / 2]); | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| void UpscaleY(size_t yw, size_t xw, float img[yw][xw], size_t yn, size_t xn) { | ||||
|   unsigned y, x; | ||||
|   for (y = yn; --y;) { | ||||
|     for (x = xn; x--;) { | ||||
|       img[y][x] = | ||||
|           C13(img[MIN(yn / 2 - 1, y / 2 - 1 + y % 2 * 2)][x], img[y / 2][x]); | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| void Upscale(size_t yw, size_t xw, float img[yw][xw], float tmp[yw][xw], | ||||
|              size_t yn, size_t xn) { | ||||
|   UpscaleY(yw, xw, img, yn, xn / 2); | ||||
|   SharpenY(yw, xw, tmp, img, yn, xn / 2); | ||||
|   UpscaleX(yw, xw, tmp, yn, xn); | ||||
|   SharpenX(yw, xw, img, tmp, yn, xn); | ||||
| } | ||||
| 
 | ||||
| void ProcessImageDouble(size_t yn, size_t xn, unsigned char img[yn][xn][4]) { | ||||
|   void *t = xmemalign(32, sizeof(float) * yn * 2 * xn * 2); | ||||
|   void *R = xmemalign(32, sizeof(float) * yn * 2 * xn * 2); | ||||
|   void *G = xmemalign(32, sizeof(float) * yn * 2 * xn * 2); | ||||
|   void *B = xmemalign(32, sizeof(float) * yn * 2 * xn * 2); | ||||
|   void *A = xmemalign(32, sizeof(float) * yn * 2 * xn * 2); | ||||
|   DeblinterlaceRgba(yn * 2, xn * 2, R, G, B, A, yn, xn, img); | ||||
|   Upscale(yn * 2, xn * 2, R, t, yn * 2, xn * 2); | ||||
|   Upscale(yn * 2, xn * 2, G, t, yn * 2, xn * 2); | ||||
|   Upscale(yn * 2, xn * 2, B, t, yn * 2, xn * 2); | ||||
|   Upscale(yn * 2, xn * 2, A, t, yn * 2, xn * 2); | ||||
|   free(t); | ||||
|   PrintImage(yn * 2, xn * 2, R, G, B, A); | ||||
|   free(R); | ||||
|   free(G); | ||||
|   free(B); | ||||
|   free(A); | ||||
| } | ||||
| 
 | ||||
| void ProcessImage(size_t yn, size_t xn, unsigned char img[yn][xn][4]) { | ||||
|   void *R = xmemalign(32, sizeof(float) * yn * xn); | ||||
|   void *G = xmemalign(32, sizeof(float) * yn * xn); | ||||
|   void *B = xmemalign(32, sizeof(float) * yn * xn); | ||||
|   void *A = xmemalign(32, sizeof(float) * yn * xn); | ||||
|   DeblinterlaceRgba(yn, xn, R, G, B, A, yn, xn, img); | ||||
|   PrintImage(yn, xn, R, G, B, A); | ||||
|   free(R); | ||||
|   free(G); | ||||
|   free(B); | ||||
|   free(A); | ||||
| } | ||||
| 
 | ||||
| void WithImageFile(const char *path, void fn(size_t yn, size_t xn, | ||||
|                                              unsigned char img[yn][xn][4])) { | ||||
|   struct stat st; | ||||
|   int fd, yn, xn; | ||||
|   void *map, *data; | ||||
|   CHECK_NE(-1, (fd = open(path, O_RDONLY)), "%s", path); | ||||
|   CHECK_NE(-1, fstat(fd, &st)); | ||||
|   CHECK_GT(st.st_size, 0); | ||||
|   CHECK_LE(st.st_size, INT_MAX); | ||||
|   fadvise(fd, 0, 0, MADV_WILLNEED | MADV_SEQUENTIAL); | ||||
|   CHECK_NE(MAP_FAILED, | ||||
|            (map = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0))); | ||||
|   CHECK_NOTNULL( | ||||
|       (data = stbi_load_from_memory(map, st.st_size, &xn, &yn, NULL, 4)), "%s", | ||||
|       path); | ||||
|   CHECK_NE(-1, munmap(map, st.st_size)); | ||||
|   CHECK_NE(-1, close(fd)); | ||||
|   fn(yn, xn, data); | ||||
|   free(data); | ||||
| } | ||||
| 
 | ||||
| int main(int argc, char *argv[]) { | ||||
|   int i; | ||||
|   for (i = 1; i < argc; ++i) { | ||||
|     WithImageFile(argv[i], ProcessImageDouble); | ||||
|   } | ||||
|   return 0; | ||||
| } | ||||
|  | @ -1,209 +0,0 @@ | |||
| /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
 | ||||
| │vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8                                :vi│ | ||||
| ╞══════════════════════════════════════════════════════════════════════════════╡ | ||||
| │ Copyright 2020 Justine Alexandra Roberts Tunney                              │ | ||||
| │                                                                              │ | ||||
| │ Permission to use, copy, modify, and/or distribute this software for         │ | ||||
| │ any purpose with or without fee is hereby granted, provided that the         │ | ||||
| │ above copyright notice and this permission notice appear in all copies.      │ | ||||
| │                                                                              │ | ||||
| │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL                │ | ||||
| │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED                │ | ||||
| │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE             │ | ||||
| │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL         │ | ||||
| │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR        │ | ||||
| │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER               │ | ||||
| │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR             │ | ||||
| │ PERFORMANCE OF THIS SOFTWARE.                                                │ | ||||
| ╚─────────────────────────────────────────────────────────────────────────────*/ | ||||
| #include "libc/assert.h" | ||||
| #include "libc/calls/calls.h" | ||||
| #include "libc/calls/struct/stat.h" | ||||
| #include "libc/limits.h" | ||||
| #include "libc/log/check.h" | ||||
| #include "libc/macros.internal.h" | ||||
| #include "libc/math.h" | ||||
| #include "libc/mem/mem.h" | ||||
| #include "libc/runtime/runtime.h" | ||||
| #include "libc/stdio/stdio.h" | ||||
| #include "libc/str/str.h" | ||||
| #include "libc/sysv/consts/madv.h" | ||||
| #include "libc/sysv/consts/map.h" | ||||
| #include "libc/sysv/consts/o.h" | ||||
| #include "libc/sysv/consts/prot.h" | ||||
| #include "libc/x/x.h" | ||||
| #include "third_party/stb/stb_image.h" | ||||
| 
 | ||||
| #define CLAMP(X)      MAX(0, MIN(255, X)) | ||||
| #define C13(A, B)     (((A) + 3 * (B) + 2) >> 2) | ||||
| #define S3T(A, B, C)  CLAMP(-((A) >> 2) + ((B) + ((B) >> 1)) + -((C) >> 2)) | ||||
| #define LERP(X, Y, P) ((X) + (((P) * ((Y) - (X))) >> 8)) | ||||
| 
 | ||||
| static unsigned char ChessBoard(unsigned y, unsigned x, unsigned char a, | ||||
|                                 unsigned char b) { | ||||
|   return !((y ^ x) & (1u << 2)) ? a : b; | ||||
| } | ||||
| 
 | ||||
| static unsigned char AlphaBackground(unsigned y, unsigned x) { | ||||
|   return ChessBoard(y, x, 255, 200); | ||||
| } | ||||
| 
 | ||||
| static unsigned char OutOfBoundsBackground(unsigned y, unsigned x) { | ||||
|   return ChessBoard(y, x, 40, 80); | ||||
| } | ||||
| 
 | ||||
| static unsigned char Opacify(size_t yn, size_t xn, | ||||
|                              const unsigned char P[yn][xn], | ||||
|                              const unsigned char A[yn][xn], long y, long x) { | ||||
|   if ((0 <= y && y < yn) && (0 <= x && x < xn)) { | ||||
|     return LERP(AlphaBackground(y, x), P[y][x], A[y][x]); | ||||
|   } else { | ||||
|     return OutOfBoundsBackground(y, x); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| static void PrintImage(size_t yn, size_t xn, unsigned char R[yn][xn], | ||||
|                        unsigned char G[yn][xn], unsigned char B[yn][xn], | ||||
|                        unsigned char A[yn][xn]) { | ||||
|   unsigned y, x; | ||||
|   for (y = 0; y < yn; y += 2) { | ||||
|     if (y) printf("\e[0m\n"); | ||||
|     for (x = 0; x < xn; ++x) { | ||||
|       printf("\e[48;2;%d;%d;%d;38;2;%d;%d;%dm▄", | ||||
|              Opacify(yn, xn, R, A, y + 0, x), Opacify(yn, xn, G, A, y + 0, x), | ||||
|              Opacify(yn, xn, B, A, y + 0, x), Opacify(yn, xn, R, A, y + 1, x), | ||||
|              Opacify(yn, xn, G, A, y + 1, x), Opacify(yn, xn, B, A, y + 1, x)); | ||||
|     } | ||||
|   } | ||||
|   printf("\e[0m\n"); | ||||
| } | ||||
| 
 | ||||
| static void DeblinterlaceRgba(size_t dyn, size_t dxn, unsigned char R[dyn][dxn], | ||||
|                               unsigned char G[dyn][dxn], | ||||
|                               unsigned char B[dyn][dxn], | ||||
|                               unsigned char A[dyn][dxn], size_t syn, size_t sxn, | ||||
|                               const unsigned char src[syn][sxn][4]) { | ||||
|   unsigned y, x; | ||||
|   for (y = 0; y < syn; ++y) { | ||||
|     for (x = 0; x < sxn; ++x) { | ||||
|       R[y][x] = src[y][x][0]; | ||||
|       G[y][x] = src[y][x][1]; | ||||
|       B[y][x] = src[y][x][2]; | ||||
|       A[y][x] = src[y][x][3]; | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| static void SharpenX(size_t yw, size_t xw, unsigned char dst[yw][xw], | ||||
|                      const unsigned char src[yw][xw], size_t yn, size_t xn) { | ||||
|   int y, x; | ||||
|   for (y = 0; y < yn; ++y) { | ||||
|     for (x = 0; x < xn; ++x) { | ||||
|       dst[y][x] = | ||||
|           S3T(src[y][MAX(0, x - 1)], src[y][x], src[y][MIN(xn - 1, x + 1)]); | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| static void SharpenY(size_t yw, size_t xw, unsigned char dst[yw][xw], | ||||
|                      const unsigned char src[yw][xw], size_t yn, size_t xn) { | ||||
|   int y, x; | ||||
|   for (y = 0; y < yn; ++y) { | ||||
|     for (x = 0; x < xn; ++x) { | ||||
|       dst[y][x] = | ||||
|           S3T(src[MAX(0, y - 1)][x], src[y][x], src[MIN(yn - 1, y + 1)][x]); | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| static void UpscaleX(size_t yw, size_t xw, unsigned char img[yw][xw], size_t yn, | ||||
|                      size_t xn) { | ||||
|   unsigned y, x; | ||||
|   for (y = yn; y--;) { | ||||
|     for (x = xn; --x;) { | ||||
|       img[y][x] = | ||||
|           C13(img[y][MIN(xn / 2 - 1, x / 2 - 1 + x % 2 * 2)], img[y][x / 2]); | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| static void UpscaleY(size_t yw, size_t xw, unsigned char img[yw][xw], size_t yn, | ||||
|                      size_t xn) { | ||||
|   unsigned y, x; | ||||
|   for (y = yn; --y;) { | ||||
|     for (x = xn; x--;) { | ||||
|       img[y][x] = | ||||
|           C13(img[MIN(yn / 2 - 1, y / 2 - 1 + y % 2 * 2)][x], img[y / 2][x]); | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| static void Upscale(size_t yw, size_t xw, unsigned char img[yw][xw], | ||||
|                     unsigned char tmp[yw][xw], size_t yn, size_t xn) { | ||||
|   UpscaleY(yw, xw, img, yn, xn / 2); | ||||
|   SharpenY(yw, xw, tmp, img, yn, xn / 2); | ||||
|   UpscaleX(yw, xw, tmp, yn, xn); | ||||
|   SharpenX(yw, xw, img, tmp, yn, xn); | ||||
| } | ||||
| 
 | ||||
| static void ProcessImageDouble(size_t yn, size_t xn, | ||||
|                                unsigned char img[yn][xn][4]) { | ||||
|   void *t = xmemalign(32, sizeof(unsigned char) * yn * 2 * xn * 2); | ||||
|   void *R = xmemalign(32, sizeof(unsigned char) * yn * 2 * xn * 2); | ||||
|   void *G = xmemalign(32, sizeof(unsigned char) * yn * 2 * xn * 2); | ||||
|   void *B = xmemalign(32, sizeof(unsigned char) * yn * 2 * xn * 2); | ||||
|   void *A = xmemalign(32, sizeof(unsigned char) * yn * 2 * xn * 2); | ||||
|   DeblinterlaceRgba(yn * 2, xn * 2, R, G, B, A, yn, xn, img); | ||||
|   Upscale(yn * 2, xn * 2, R, t, yn * 2, xn * 2); | ||||
|   Upscale(yn * 2, xn * 2, G, t, yn * 2, xn * 2); | ||||
|   Upscale(yn * 2, xn * 2, B, t, yn * 2, xn * 2); | ||||
|   Upscale(yn * 2, xn * 2, A, t, yn * 2, xn * 2); | ||||
|   free(t); | ||||
|   PrintImage(yn * 2, xn * 2, R, G, B, A); | ||||
|   free(R); | ||||
|   free(G); | ||||
|   free(B); | ||||
|   free(A); | ||||
| } | ||||
| 
 | ||||
| static void ProcessImage(size_t yn, size_t xn, unsigned char img[yn][xn][4]) { | ||||
|   void *R = xmemalign(32, sizeof(unsigned char) * yn * xn); | ||||
|   void *G = xmemalign(32, sizeof(unsigned char) * yn * xn); | ||||
|   void *B = xmemalign(32, sizeof(unsigned char) * yn * xn); | ||||
|   void *A = xmemalign(32, sizeof(unsigned char) * yn * xn); | ||||
|   DeblinterlaceRgba(yn, xn, R, G, B, A, yn, xn, img); | ||||
|   PrintImage(yn, xn, R, G, B, A); | ||||
|   free(R); | ||||
|   free(G); | ||||
|   free(B); | ||||
|   free(A); | ||||
| } | ||||
| 
 | ||||
| void WithImageFile(const char *path, void fn(size_t yn, size_t xn, | ||||
|                                              unsigned char img[yn][xn][4])) { | ||||
|   struct stat st; | ||||
|   int fd, yn, xn; | ||||
|   void *map, *data; | ||||
|   CHECK_NE(-1, (fd = open(path, O_RDONLY)), "%s", path); | ||||
|   CHECK_NE(-1, fstat(fd, &st)); | ||||
|   CHECK_GT(st.st_size, 0); | ||||
|   CHECK_LE(st.st_size, INT_MAX); | ||||
|   fadvise(fd, 0, 0, MADV_WILLNEED | MADV_SEQUENTIAL); | ||||
|   CHECK_NE(MAP_FAILED, | ||||
|            (map = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0))); | ||||
|   CHECK_NOTNULL( | ||||
|       (data = stbi_load_from_memory(map, st.st_size, &xn, &yn, NULL, 4)), "%s", | ||||
|       path); | ||||
|   CHECK_NE(-1, munmap(map, st.st_size)); | ||||
|   CHECK_NE(-1, close(fd)); | ||||
|   fn(yn, xn, data); | ||||
|   free(data); | ||||
| } | ||||
| 
 | ||||
| int main(int argc, char *argv[]) { | ||||
|   int i; | ||||
|   for (i = 1; i < argc; ++i) { | ||||
|     WithImageFile(argv[i], ProcessImageDouble); | ||||
|   } | ||||
|   return 0; | ||||
| } | ||||
|  | @ -1,85 +0,0 @@ | |||
| /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
 | ||||
| │vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8                                :vi│ | ||||
| ╞══════════════════════════════════════════════════════════════════════════════╡ | ||||
| │ Copyright 2022 Justine Alexandra Roberts Tunney                              │ | ||||
| │                                                                              │ | ||||
| │ Permission to use, copy, modify, and/or distribute this software for         │ | ||||
| │ any purpose with or without fee is hereby granted, provided that the         │ | ||||
| │ above copyright notice and this permission notice appear in all copies.      │ | ||||
| │                                                                              │ | ||||
| │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL                │ | ||||
| │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED                │ | ||||
| │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE             │ | ||||
| │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL         │ | ||||
| │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR        │ | ||||
| │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER               │ | ||||
| │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR             │ | ||||
| │ PERFORMANCE OF THIS SOFTWARE.                                                │ | ||||
| ╚─────────────────────────────────────────────────────────────────────────────*/ | ||||
| #include "libc/calls/struct/sigaction.h" | ||||
| #include "libc/calls/struct/siginfo.h" | ||||
| #include "libc/calls/ucontext.h" | ||||
| #include "libc/runtime/runtime.h" | ||||
| #include "libc/stdio/stdio.h" | ||||
| #include "libc/sysv/consts/auxv.h" | ||||
| #include "libc/sysv/consts/sa.h" | ||||
| #include "libc/sysv/consts/sig.h" | ||||
| #include "third_party/xed/x86.h" | ||||
| #ifdef __x86_64__ | ||||
| 
 | ||||
| #define OUTPATH "vdso.elf" | ||||
| 
 | ||||
| volatile bool finished; | ||||
| 
 | ||||
| void OnSegmentationFault(int sig, siginfo_t *si, void *vctx) { | ||||
|   struct XedDecodedInst xedd; | ||||
|   ucontext_t *ctx = vctx; | ||||
|   xed_decoded_inst_zero_set_mode(&xedd, XED_MACHINE_MODE_LONG_64); | ||||
|   xed_instruction_length_decode(&xedd, (void *)ctx->uc_mcontext.rip, 15); | ||||
|   ctx->uc_mcontext.rip += xedd.length; | ||||
|   finished = true; | ||||
| } | ||||
| 
 | ||||
| int main(int argc, char *argv[]) { | ||||
|   FILE *f; | ||||
|   int byte; | ||||
|   volatile unsigned char *vdso, *p; | ||||
| 
 | ||||
|   vdso = (unsigned char *)getauxval(AT_SYSINFO_EHDR); | ||||
|   if (vdso) { | ||||
|     fprintf(stderr, "vdso found at address %p\n", vdso); | ||||
|   } else { | ||||
|     fprintf(stderr, "error: AT_SYSINFO_EHDR was not in auxiliary values\n"); | ||||
|     return 1; | ||||
|   } | ||||
| 
 | ||||
|   f = fopen(OUTPATH, "wb"); | ||||
|   if (!f) { | ||||
|     fprintf(stderr, "error: fopen(%`'s) failed\n", OUTPATH); | ||||
|     return 1; | ||||
|   } | ||||
| 
 | ||||
|   struct sigaction sa = { | ||||
|       .sa_sigaction = OnSegmentationFault, | ||||
|       .sa_flags = SA_SIGINFO, | ||||
|   }; | ||||
|   sigaction(SIGSEGV, &sa, 0); | ||||
|   sigaction(SIGBUS, &sa, 0); | ||||
| 
 | ||||
|   p = vdso; | ||||
|   for (;;) { | ||||
|     byte = *p++; | ||||
|     if (!finished) { | ||||
|       fputc(byte, f); | ||||
|     } else { | ||||
|       break; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   fclose(f); | ||||
|   fprintf(stderr, "%zu bytes dumped to %s\n", p - vdso, OUTPATH); | ||||
| 
 | ||||
|   return 0; | ||||
| } | ||||
| 
 | ||||
| #endif /* __x86_64__ */ | ||||
|  | @ -1,166 +0,0 @@ | |||
| /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
 | ||||
| │vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8                                :vi│ | ||||
| ╞══════════════════════════════════════════════════════════════════════════════╡ | ||||
| │ Copyright 2022 Justine Alexandra Roberts Tunney                              │ | ||||
| │                                                                              │ | ||||
| │ Permission to use, copy, modify, and/or distribute this software for         │ | ||||
| │ any purpose with or without fee is hereby granted, provided that the         │ | ||||
| │ above copyright notice and this permission notice appear in all copies.      │ | ||||
| │                                                                              │ | ||||
| │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL                │ | ||||
| │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED                │ | ||||
| │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE             │ | ||||
| │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL         │ | ||||
| │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR        │ | ||||
| │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER               │ | ||||
| │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR             │ | ||||
| │ PERFORMANCE OF THIS SOFTWARE.                                                │ | ||||
| ╚─────────────────────────────────────────────────────────────────────────────*/ | ||||
| #include "libc/elf/def.h" | ||||
| #include "libc/elf/scalar.h" | ||||
| #include "libc/elf/struct/ehdr.h" | ||||
| #include "libc/elf/struct/phdr.h" | ||||
| #include "libc/elf/struct/sym.h" | ||||
| #include "libc/elf/struct/verdaux.h" | ||||
| #include "libc/elf/struct/verdef.h" | ||||
| #include "libc/intrin/kprintf.h" | ||||
| #include "libc/intrin/strace.internal.h" | ||||
| #include "libc/runtime/runtime.h" | ||||
| #include "libc/sysv/consts/auxv.h" | ||||
| 
 | ||||
| static inline void PrintDsoSymbolVersions(Elf64_Verdef *vd, int sym, | ||||
|                                           char *strtab) { | ||||
|   Elf64_Verdaux *aux; | ||||
|   for (;; vd = (Elf64_Verdef *)((char *)vd + vd->vd_next)) { | ||||
|     if (!(vd->vd_flags & VER_FLG_BASE) && | ||||
|         (vd->vd_ndx & 0x7fff) == (sym & 0x7fff)) { | ||||
|       aux = (Elf64_Verdaux *)((char *)vd + vd->vd_aux); | ||||
|       kprintf(" %s", strtab + aux->vda_name); | ||||
|     } | ||||
|     if (!vd->vd_next) { | ||||
|       break; | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| int PrintVdsoSymbols(void) { | ||||
|   void *p; | ||||
|   size_t i; | ||||
|   Elf64_Ehdr *ehdr; | ||||
|   Elf64_Phdr *phdr; | ||||
|   char *strtab = 0; | ||||
|   size_t *dyn, base; | ||||
|   unsigned long *ap; | ||||
|   Elf64_Sym *symtab = 0; | ||||
|   uint16_t *versym = 0; | ||||
|   Elf_Symndx *hashtab = 0; | ||||
|   Elf64_Verdef *verdef = 0; | ||||
|   const char *typename, *bindname; | ||||
| 
 | ||||
|   for (ehdr = 0, ap = __auxv; ap[0]; ap += 2) { | ||||
|     if (ap[0] == AT_SYSINFO_EHDR) { | ||||
|       ehdr = (void *)ap[1]; | ||||
|       break; | ||||
|     } | ||||
|   } | ||||
|   if (!ehdr) { | ||||
|     kprintf("error: AT_SYSINFO_EHDR not found\n"); | ||||
|     return 1; | ||||
|   } | ||||
| 
 | ||||
|   phdr = (void *)((char *)ehdr + ehdr->e_phoff); | ||||
|   for (base = -1, dyn = 0, i = 0; i < ehdr->e_phnum; | ||||
|        i++, phdr = (void *)((char *)phdr + ehdr->e_phentsize)) { | ||||
|     switch (phdr->p_type) { | ||||
|       case PT_LOAD: | ||||
|         // modern linux uses the base address zero, but elders
 | ||||
|         // e.g. rhel7 uses the base address 0xffffffffff700000
 | ||||
|         base = (size_t)ehdr + phdr->p_offset - phdr->p_vaddr; | ||||
|         break; | ||||
|       case PT_DYNAMIC: | ||||
|         dyn = (void *)((char *)ehdr + phdr->p_offset); | ||||
|         break; | ||||
|       default: | ||||
|         break; | ||||
|     } | ||||
|   } | ||||
|   if (!dyn || base == -1) { | ||||
|     kprintf("error: missing program headers\n"); | ||||
|     return 2; | ||||
|   } | ||||
| 
 | ||||
|   for (i = 0; dyn[i]; i += 2) { | ||||
|     p = (void *)(base + dyn[i + 1]); | ||||
|     switch (dyn[i]) { | ||||
|       case DT_STRTAB: | ||||
|         strtab = p; | ||||
|         break; | ||||
|       case DT_SYMTAB: | ||||
|         symtab = p; | ||||
|         break; | ||||
|       case DT_HASH: | ||||
|         hashtab = p; | ||||
|         break; | ||||
|       case DT_VERSYM: | ||||
|         versym = p; | ||||
|         break; | ||||
|       case DT_VERDEF: | ||||
|         verdef = p; | ||||
|         break; | ||||
|     } | ||||
|   } | ||||
|   if (!verdef) { | ||||
|     versym = 0; | ||||
|   } | ||||
| 
 | ||||
|   if (!strtab || !symtab || !hashtab) { | ||||
|     kprintf("error: strtab/symtab/hashtab not found\n"); | ||||
|     return 3; | ||||
|   } | ||||
| 
 | ||||
|   for (i = 0; i < hashtab[1]; i++) { | ||||
|     if (!symtab[i].st_shndx) { | ||||
|       continue; | ||||
|     } | ||||
| 
 | ||||
|     switch (ELF64_ST_BIND(symtab[i].st_info)) { | ||||
|       case STB_LOCAL: | ||||
|         bindname = "locl"; | ||||
|         break; | ||||
|       case STB_GLOBAL: | ||||
|         bindname = "glob"; | ||||
|         break; | ||||
|       case STB_WEAK: | ||||
|         bindname = "weak"; | ||||
|         break; | ||||
|       default: | ||||
|         bindname = "????"; | ||||
|         break; | ||||
|     } | ||||
| 
 | ||||
|     switch (ELF64_ST_TYPE(symtab[i].st_info)) { | ||||
|       case STT_FUNC: | ||||
|         typename = "func"; | ||||
|         break; | ||||
|       case STT_OBJECT: | ||||
|         typename = " obj"; | ||||
|         break; | ||||
|       case STT_NOTYPE: | ||||
|         typename = "none"; | ||||
|         break; | ||||
|       default: | ||||
|         typename = "????"; | ||||
|         break; | ||||
|     } | ||||
| 
 | ||||
|     kprintf("%s %s %-40s", bindname, typename, strtab + symtab[i].st_name); | ||||
|     PrintDsoSymbolVersions(verdef, versym[i], strtab); | ||||
|     kprintf("\n"); | ||||
|   } | ||||
| 
 | ||||
|   return 0; | ||||
| } | ||||
| 
 | ||||
| int main(int argc, char *argv[]) { | ||||
|   return PrintVdsoSymbols(); | ||||
| } | ||||
|  | @ -1,97 +0,0 @@ | |||
| /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
 | ||||
| │vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8                                :vi│ | ||||
| ╞══════════════════════════════════════════════════════════════════════════════╡ | ||||
| │ Copyright 2020 Justine Alexandra Roberts Tunney                              │ | ||||
| │                                                                              │ | ||||
| │ Permission to use, copy, modify, and/or distribute this software for         │ | ||||
| │ any purpose with or without fee is hereby granted, provided that the         │ | ||||
| │ above copyright notice and this permission notice appear in all copies.      │ | ||||
| │                                                                              │ | ||||
| │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL                │ | ||||
| │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED                │ | ||||
| │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE             │ | ||||
| │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL         │ | ||||
| │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR        │ | ||||
| │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER               │ | ||||
| │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR             │ | ||||
| │ PERFORMANCE OF THIS SOFTWARE.                                                │ | ||||
| ╚─────────────────────────────────────────────────────────────────────────────*/ | ||||
| #include "libc/assert.h" | ||||
| #include "libc/stdio/stdio.h" | ||||
| 
 | ||||
| #define DIST(X, Y)   ((X) - (Y)) | ||||
| #define SQR(X)       ((X) * (X)) | ||||
| #define SUM(X, Y, Z) ((X) + (Y) + (Z)) | ||||
| 
 | ||||
| static const uint8_t kXtermCube[] = {0, 0137, 0207, 0257, 0327, 0377}; | ||||
| 
 | ||||
| static int uncube(int x) { | ||||
|   return x < 48 ? 0 : x < 115 ? 1 : (x - 35) / 40; | ||||
| } | ||||
| 
 | ||||
| static int rgb2xterm256(int r, int g, int b) { | ||||
|   unsigned av, ir, ig, ib, il, qr, qg, qb, ql; | ||||
|   av = (r + g + b) / 3; | ||||
|   ql = (il = av > 238 ? 23 : (av - 3) / 10) * 10 + 8; | ||||
|   qr = kXtermCube[(ir = uncube(r))]; | ||||
|   qg = kXtermCube[(ig = uncube(g))]; | ||||
|   qb = kXtermCube[(ib = uncube(b))]; | ||||
|   if (SUM(SQR(DIST(qr, r)), SQR(DIST(qg, g)), SQR(DIST(qb, b))) <= | ||||
|       SUM(SQR(DIST(ql, r)), SQR(DIST(ql, g)), SQR(DIST(ql, b)))) { | ||||
|     return ir * 36 + ig * 6 + ib + 020; | ||||
|   } else { | ||||
|     return il + 0350; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| bool IsUglyColorMixture(int rune, int y, int tone, bool toneisfg) { | ||||
|   assert(tone == 16 || (231 <= tone && tone <= 255)); | ||||
|   return false; | ||||
| } | ||||
| 
 | ||||
| int main(int argc, char *argv[]) { | ||||
|   unsigned y, z, x, k, w; | ||||
|   static const char16_t s[2][3] = {{u'▓', u'▒', u'░'}, {u'░', u'▒', u'▓'}}; | ||||
| 
 | ||||
|   printf("\npure\n"); | ||||
|   for (y = 0; y < 6; ++y) { | ||||
|     for (z = 0; z < 6; ++z) { | ||||
|       for (x = 0; x < 6; ++x) { | ||||
|         printf("\033[48;5;%hhum  ", 16 + x + y * 6 + z * 6 * 6); | ||||
|       } | ||||
|       printf("\033[0m "); | ||||
|     } | ||||
|     printf("\n"); | ||||
|   } | ||||
| 
 | ||||
| #define MIX(NAME, COLOR)                                                       \ | ||||
|   do {                                                                         \ | ||||
|     printf("\n%s %d ▓░/▒▒/░▓\n", NAME, COLOR);                                 \ | ||||
|     for (k = 0; k < 3; ++k) {                                                  \ | ||||
|       for (y = 0; y < 6; ++y) {                                                \ | ||||
|         for (z = 0; z < 6; ++z) {                                              \ | ||||
|           for (x = 0; x < 6; ++x) {                                            \ | ||||
|             printf("\033[48;5;%hhu;38;5;%hhum%lc", COLOR,                      \ | ||||
|                    16 + x + y * 6 + z * 6 * 6, s[0][k]);                       \ | ||||
|             printf("\033[48;5;%hhu;38;5;%hhum%lc", 16 + x + y * 6 + z * 6 * 6, \ | ||||
|                    COLOR, s[1][k]);                                            \ | ||||
|           }                                                                    \ | ||||
|           printf("\033[0m ");                                                  \ | ||||
|         }                                                                      \ | ||||
|         printf("\n");                                                          \ | ||||
|       }                                                                        \ | ||||
|     }                                                                          \ | ||||
|   } while (0) | ||||
| 
 | ||||
|   MIX("tint", 231); | ||||
|   MIX("tint", 255); | ||||
|   MIX("tint", 254); | ||||
|   MIX("tone", 240); | ||||
|   MIX("shade", 232); | ||||
| 
 | ||||
|   for (w = 233; w < 254; ++w) { | ||||
|     MIX("gray", w); | ||||
|   } | ||||
| 
 | ||||
|   return 0; | ||||
| } | ||||
|  | @ -1,183 +0,0 @@ | |||
| /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
 | ||||
| │vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8                                :vi│ | ||||
| ╞══════════════════════════════════════════════════════════════════════════════╡ | ||||
| │ Copyright 2020 Justine Alexandra Roberts Tunney                              │ | ||||
| │                                                                              │ | ||||
| │ Permission to use, copy, modify, and/or distribute this software for         │ | ||||
| │ any purpose with or without fee is hereby granted, provided that the         │ | ||||
| │ above copyright notice and this permission notice appear in all copies.      │ | ||||
| │                                                                              │ | ||||
| │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL                │ | ||||
| │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED                │ | ||||
| │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE             │ | ||||
| │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL         │ | ||||
| │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR        │ | ||||
| │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER               │ | ||||
| │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR             │ | ||||
| │ PERFORMANCE OF THIS SOFTWARE.                                                │ | ||||
| ╚─────────────────────────────────────────────────────────────────────────────*/ | ||||
| #include "dsp/tty/quant.h" | ||||
| #include "libc/fmt/fmt.h" | ||||
| #include "libc/intrin/bits.h" | ||||
| #include "libc/intrin/xchg.internal.h" | ||||
| #include "libc/math.h" | ||||
| #include "libc/runtime/runtime.h" | ||||
| #include "libc/stdio/stdio.h" | ||||
| 
 | ||||
| /* #define ROUND(x) x */ | ||||
| /* #define RT       int */ | ||||
| /* #define R1       1 */ | ||||
| /* #define R2       2 */ | ||||
| /* #define R3       3 */ | ||||
| 
 | ||||
| #define RT        float | ||||
| #define MUL(x, y) ((x) * (y)) | ||||
| #define RND(x)    roundf(x) | ||||
| #define R1        0.25f | ||||
| #define R2        0.50f | ||||
| #define R3        0.75f | ||||
| 
 | ||||
| #define rgb_t struct TtyRgb | ||||
| 
 | ||||
| forceinline RT lerp(RT x, RT y, RT d) { | ||||
|   return x * (1.0 - d) + y * d; | ||||
| } | ||||
| forceinline int lerp255(RT x, RT y, RT d) { | ||||
|   return lerp(x / 255.0, y / 255.0, d) * 255.0; | ||||
| } | ||||
| forceinline rgb_t rgblerp(rgb_t x, rgb_t y, RT d) { | ||||
|   return (rgb_t){lerp255(x.r, y.r, d), lerp255(x.g, y.g, d), | ||||
|                  lerp255(x.b, y.b, d)}; | ||||
| } | ||||
| 
 | ||||
| forceinline rgb_t getquant(unsigned xt) { | ||||
|   return g_ansi2rgb_[xt]; | ||||
| } | ||||
| forceinline unsigned dist(int x, int y) { | ||||
|   return x - y; | ||||
| } | ||||
| forceinline unsigned sqr(int x) { | ||||
|   return x * x; | ||||
| } | ||||
| forceinline unsigned rgbdist(rgb_t x, rgb_t y) { | ||||
|   return sqrt(sqr(dist(x.r, y.r)) + sqr(dist(x.g, y.g)) + sqr(dist(x.b, y.b))); | ||||
| } | ||||
| 
 | ||||
| bool b; | ||||
| rgb_t rgb, cc, c1, c2; | ||||
| unsigned i, j, k, m, n, x, y; | ||||
| char buf[128]; | ||||
| 
 | ||||
| /* 0125 025 067-29   # '░' bg=0352 fg=0306 → ░░░ */ | ||||
| /* 0125 025 067-29   # '▓' bg=0306 fg=0352 → ▓▓▓ */ | ||||
| /* 0125 055 067-29   # '░' bg=0352 fg=0314 → ░░░ */ | ||||
| 
 | ||||
| int main(int argc, char *argv[]) { | ||||
|   /* memcpy(g_ansi2rgb_, &kTangoPalette, sizeof(kTangoPalette)); */ | ||||
|   /* i = 21; */ | ||||
|   /* j = 22; */ | ||||
|   /* c1 = getquant(i); */ | ||||
|   /* c2 = getquant(j); */ | ||||
|   /* cc = rgblerp(c1, c2, R1); */ | ||||
|   /* printf("rgblerp((%3d,%3d,%3d), (%3d,%3d,%3d),4) → (%3d,%3d,%3d)\n", c1.r,
 | ||||
|    */ | ||||
|   /*        c1.g, c1.b, c2.r, c2.g, c2.b, cc.r, cc.g, cc.b); */ | ||||
|   /* exit(0); */ | ||||
| 
 | ||||
|   for (m = 16; m < 256; m += 6) { | ||||
|     for (n = 16; n < 256; n += 6) { | ||||
|       printf("------------------------------------------------------------\n"); | ||||
|       i = m; | ||||
|       j = n; | ||||
|       b = false; | ||||
|       while (i < m + 6) { | ||||
|         printf("\n"); | ||||
| 
 | ||||
|         cc = getquant(i); | ||||
|         sprintf(buf, "\e[48;5;%dm   ", i); | ||||
|         printf("0x%02x%02x%02x, %d,%d,0\t/* 0x%02x%02x%02x           " | ||||
|                " + ' ' bg=%3d        → %s         \e[0m */\n", | ||||
|                cc.b, cc.g, cc.r, i, 0, getquant(i).r, getquant(i).g, | ||||
|                getquant(i).b, i, buf); | ||||
| 
 | ||||
| #if 0 | ||||
|         sprintf(buf, "\e[38;5;%dm███", i); | ||||
|         printf("0x%08x 0x%02x%02x%02x\t" | ||||
|                " '█'        fg=%3d → %s\e[0m\n", | ||||
|                cc.b, cc.g, cc.r, strlen(buf), i, buf); | ||||
| #endif | ||||
| 
 | ||||
|         for (x = i; x < i + 1; ++x) { | ||||
|           for (y = j; y < j + 1; ++y) { | ||||
|             for (k = 0; k < 2; ++k) { | ||||
|               if (x > y /*  && */ | ||||
|                   /* rgbdist(getquant(x), getquant(y)) < 49744125 / 16 */ /*  &&
 | ||||
|                   ((32 | ||||
|                   <= x && x <= 232) && (32 <= y && y <= 232)) | ||||
|                   && */ | ||||
|                   /* (cc.r > 0137 && cc.g > 0137 && cc.b > 0137) */) { | ||||
|                 sprintf(buf, "\e[48;5;%d;38;5;%dm░░░", x, y); | ||||
|                 cc = rgblerp(getquant(x), getquant(y), R1); | ||||
|                 printf("0x%02x%02x%02x, %d,%d,1\t/* 0x%02x%02x%02x + " | ||||
|                        "0x%02x%02x%02x" | ||||
|                        " + '░' bg=%3d fg=%3d → " | ||||
|                        "\e[48;5;%dm   \e[48;5;%dm   " | ||||
|                        "%s\e[48;2;%d;%d;%dm   \e[0m */\n", | ||||
|                        cc.b, cc.g, cc.r, x, y, getquant(x).r, getquant(x).g, | ||||
|                        getquant(x).b, getquant(y).r, getquant(y).g, | ||||
|                        getquant(y).b, x, y, x, y, buf, cc.r, cc.g, cc.b); | ||||
| 
 | ||||
|                 sprintf(buf, "\e[48;5;%d;38;5;%dm▒▒▒", x, y); | ||||
|                 cc = rgblerp(getquant(x), getquant(y), R2); | ||||
|                 printf("0x%02x%02x%02x, %d,%d,2\t/* 0x%02x%02x%02x + " | ||||
|                        "0x%02x%02x%02x" | ||||
|                        " + '▒' bg=%3d fg=%3d → " | ||||
|                        "\e[48;5;%dm   \e[48;5;%dm   " | ||||
|                        "%s\e[48;2;%d;%d;%dm   \e[0m */\n", | ||||
|                        cc.b, cc.g, cc.r, x, y, getquant(x).r, getquant(x).g, | ||||
|                        getquant(x).b, getquant(y).r, getquant(y).g, | ||||
|                        getquant(y).b, x, y, x, y, buf, cc.r, cc.g, cc.b); | ||||
| 
 | ||||
|                 sprintf(buf, "\e[48;5;%d;38;5;%dm▓▓▓", x, y); | ||||
|                 cc = rgblerp(getquant(x), getquant(y), R3); | ||||
|                 printf("0x%02x%02x%02x, %d,%d,3\t/* 0x%02x%02x%02x + " | ||||
|                        "0x%02x%02x%02x" | ||||
|                        " + '▓' bg=%3d fg=%3d → " | ||||
|                        "\e[48;5;%dm   \e[48;5;%dm   " | ||||
|                        "%s\e[48;2;%d;%d;%dm   \e[0m */\n", | ||||
|                        cc.b, cc.g, cc.r, x, y, getquant(x).r, getquant(x).g, | ||||
|                        getquant(x).b, getquant(y).r, getquant(y).g, | ||||
|                        getquant(y).b, x, y, x, y, buf, cc.r, cc.g, cc.b); | ||||
|               } | ||||
| 
 | ||||
| #if 0 | ||||
|               sprintf(buf, "\e[48;5;%d;38;5;%dm▓▓▓", x, y); | ||||
|               cc = rgblerp((c1 = getquant(x)), (c2 = getquant(y)), R3); | ||||
|               printf("0%03o%03o%03o\t# '▓' bg=%3d fg=%3d → " | ||||
|                      "%s\e[48;2;%d;%d;%dm   \e[0m\n", | ||||
|                      cc.b, cc.g, cc.r, strlen(buf), x, y, buf, | ||||
|                      lerp255(c1.r, c2.r, R3), lerp255(c1.g, c2.g, R3), | ||||
|                      lerp255(c1.b, c2.b, R3)); | ||||
| #endif | ||||
| 
 | ||||
|               xchg(&x, &y); | ||||
|             } | ||||
|           } | ||||
|         } | ||||
| 
 | ||||
|         ++i; | ||||
|         ++j; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   /* for (i = 0; i < 255; ++i) { */ | ||||
|   /*   for (j = 0; j < 255; ++j) { */ | ||||
|   /*     for (k = 0; k < 255; ++k) { */ | ||||
|   /*       printf("0%03o%03o%03o\n", i, j, k); */ | ||||
|   /*     } */ | ||||
|   /*   } */ | ||||
|   /* } */ | ||||
| 
 | ||||
|   return 0; | ||||
| } | ||||
|  | @ -1,186 +0,0 @@ | |||
| /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
 | ||||
| │vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8                                :vi│ | ||||
| ╞══════════════════════════════════════════════════════════════════════════════╡ | ||||
| │ Copyright 2020 Justine Alexandra Roberts Tunney                              │ | ||||
| │                                                                              │ | ||||
| │ Permission to use, copy, modify, and/or distribute this software for         │ | ||||
| │ any purpose with or without fee is hereby granted, provided that the         │ | ||||
| │ above copyright notice and this permission notice appear in all copies.      │ | ||||
| │                                                                              │ | ||||
| │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL                │ | ||||
| │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED                │ | ||||
| │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE             │ | ||||
| │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL         │ | ||||
| │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR        │ | ||||
| │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER               │ | ||||
| │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR             │ | ||||
| │ PERFORMANCE OF THIS SOFTWARE.                                                │ | ||||
| ╚─────────────────────────────────────────────────────────────────────────────*/ | ||||
| #include "dsp/tty/quant.h" | ||||
| #include "libc/fmt/fmt.h" | ||||
| #include "libc/log/check.h" | ||||
| #include "libc/macros.internal.h" | ||||
| #include "libc/math.h" | ||||
| #include "libc/mem/mem.h" | ||||
| #include "libc/runtime/runtime.h" | ||||
| #include "libc/stdio/stdio.h" | ||||
| #include "libc/str/str.h" | ||||
| #include "libc/sysv/consts/ex.h" | ||||
| #include "libc/sysv/consts/exit.h" | ||||
| #include "third_party/getopt/getopt.internal.h" | ||||
| 
 | ||||
| #define USAGE \ | ||||
|   " [FLAGS] [PATH...]\n\
 | ||||
| \n\ | ||||
| Flags:\n\ | ||||
|   -o PATH    output path\n\ | ||||
|   -h         shows this information\n\ | ||||
| \n" | ||||
| 
 | ||||
| static size_t linecap_; | ||||
| static FILE *in_, *out_; | ||||
| static char *inpath_, *outpath_, *line_; | ||||
| 
 | ||||
| void PrintUsage(int rc, FILE *f) { | ||||
|   fputs("Usage: ", f); | ||||
|   fputs(program_invocation_name, f); | ||||
|   fputs(USAGE, f); | ||||
|   exit(rc); | ||||
| } | ||||
| 
 | ||||
| void GetOpts(int *argc, char *argv[]) { | ||||
|   int opt; | ||||
|   outpath_ = "-"; | ||||
|   while ((opt = getopt(*argc, argv, "?ho:")) != -1) { | ||||
|     switch (opt) { | ||||
|       case 'o': | ||||
|         outpath_ = optarg; | ||||
|         break; | ||||
|       case '?': | ||||
|       case 'h': | ||||
|         PrintUsage(EXIT_SUCCESS, stdout); | ||||
|       default: | ||||
|         PrintUsage(EX_USAGE, stderr); | ||||
|     } | ||||
|   } | ||||
|   if (optind == *argc) { | ||||
|     argv[(*argc)++] = "-"; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| #define U256F1(X) ((float)((X)&0xffu) * 256.0f) | ||||
| #define F1U256(X) MAX(MIN((int)rintl(roundl(256.0f * (X))), 255), 0) | ||||
| 
 | ||||
| forceinline struct TtyRgb getquant(unsigned xt) { | ||||
|   return g_ansi2rgb_[xt]; | ||||
| } | ||||
| 
 | ||||
| forceinline unsigned dist(int x, int y) { | ||||
|   return x - y; | ||||
| } | ||||
| 
 | ||||
| forceinline unsigned sqr(int x) { | ||||
|   return x * x; | ||||
| } | ||||
| 
 | ||||
| static unsigned rgb2hsl(unsigned rgba) { | ||||
|   /* this is broken */ | ||||
|   unsigned h8, s8, l8; | ||||
|   float r, g, b, h, s, d, l, cmax, cmin; | ||||
|   r = U256F1(rgba); | ||||
|   g = U256F1(rgba >> 010); | ||||
|   b = U256F1(rgba >> 020); | ||||
|   cmax = MAX(MAX(r, g), b); | ||||
|   cmin = MIN(MIN(r, g), b); | ||||
|   h = 0.0f; | ||||
|   s = 0.0f; | ||||
|   d = cmax - cmin; | ||||
|   l = (cmax + cmin) / 2.0f; | ||||
|   if (cmax != cmin) { | ||||
|     s = l > 0.5L ? d / (2.0f - cmax - cmin) : d / (cmax + cmin); | ||||
|     if (cmax == r) { | ||||
|       h = (g - b) / d + (g < b ? 6.0f : 0.0f); | ||||
|     } else if (cmax == g) { | ||||
|       h = (b - r) / d + 2.0f; | ||||
|     } else if (cmax == b) { | ||||
|       h = (r - g) / d + 4.0f; | ||||
|     } | ||||
|     h /= 6.0f; | ||||
|   } | ||||
|   h8 = F1U256(h); | ||||
|   s8 = F1U256(s); | ||||
|   l8 = F1U256(l); | ||||
|   return ((rgba >> 030) & 255) << 030 | l8 << 020 | s8 << 010 | h8; | ||||
| } | ||||
| static struct TtyRgb rgb2hsl2(struct TtyRgb rgb) { | ||||
|   unsigned x = | ||||
|       (unsigned)rgb.b << 020 | (unsigned)rgb.g << 010 | (unsigned)rgb.r; | ||||
|   unsigned y = rgb2hsl(x); | ||||
|   return (struct TtyRgb){ | ||||
|       .r = y & 0xff, .g = (y >> 010) & 0xff, .b = (y >> 020) & 0xff}; | ||||
| } | ||||
| static unsigned rgbdist(struct TtyRgb x, struct TtyRgb y) { | ||||
|   x = rgb2hsl2(x); | ||||
|   y = rgb2hsl2(y); | ||||
|   return sqrt(sqr(dist(x.r, y.r)) + sqr(dist(x.g, y.g)) + sqr(dist(x.b, y.b))); | ||||
| } | ||||
| 
 | ||||
| static unsigned xtdist(unsigned x, unsigned y) { | ||||
|   return rgbdist(getquant(x), getquant(y)); | ||||
| } | ||||
| 
 | ||||
| void Show(unsigned color, unsigned bg, unsigned fg, unsigned glyph) { | ||||
|   uint8_t r, g, b; | ||||
|   b = (color >> 020) & 0xff; | ||||
|   g = (color >> 010) & 0xff; | ||||
|   r = color & 0xff; | ||||
|   printf("\tmix\t0x%04x,%3d,%3d,%3d,%3d,%3d,%3d\t# \e[48;2;%d;%d;%dm   \e[0m\n", | ||||
|          rgbdist((struct TtyRgb){r, g, b, 0}, (struct TtyRgb){0, 0, 0, 0}), r, | ||||
|          g, b, bg, fg, glyph, r, g, b); | ||||
| } | ||||
| 
 | ||||
| void ProcessFile(void) { | ||||
|   char *p; | ||||
|   unsigned color1, bg1, fg1, glyph1; | ||||
|   unsigned color, bg, fg, glyph; | ||||
|   color1 = -1u; | ||||
|   bg1 = -1u; | ||||
|   fg1 = -1u; | ||||
|   glyph1 = -1u; | ||||
|   while ((getline(&line_, &linecap_, in_)) != -1) { | ||||
|     p = _chomp(line_); | ||||
|     sscanf(p, "%x, %u,%u,%u", &color, &bg, &fg, &glyph); | ||||
|     if (color != color1) { | ||||
|       if (color1 != -1u) { | ||||
|         Show(color1, bg1, fg1, glyph1); | ||||
|       } | ||||
|       color1 = color; | ||||
|       bg1 = bg; | ||||
|       fg1 = fg; | ||||
|       glyph1 = glyph; | ||||
|     } | ||||
|     if ((fg1 && !fg) || (fg && fg1 && xtdist(fg, bg) < xtdist(fg1, bg1))) { | ||||
|       color1 = color; | ||||
|       bg1 = bg; | ||||
|       fg1 = fg; | ||||
|       glyph1 = glyph; | ||||
|     } | ||||
|   } | ||||
|   Show(color1, bg1, fg1, glyph1); | ||||
| } | ||||
| 
 | ||||
| int main(int argc, char *argv[]) { | ||||
|   size_t i; | ||||
|   GetOpts(&argc, argv); | ||||
|   CHECK_NOTNULL((out_ = fopen(outpath_, "w"))); | ||||
|   for (i = optind; i < argc; ++i) { | ||||
|     CHECK_NOTNULL((in_ = fopen((inpath_ = argv[i]), "r"))); | ||||
|     ProcessFile(); | ||||
|     CHECK_NE(-1, fclose(in_)); | ||||
|     in_ = 0; | ||||
|   } | ||||
|   CHECK_NE(-1, fclose(out_)); | ||||
|   out_ = 0; | ||||
|   free(line_); | ||||
|   return 0; | ||||
| } | ||||
|  | @ -1,77 +0,0 @@ | |||
| /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
 | ||||
| │vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8                                :vi│ | ||||
| ╞══════════════════════════════════════════════════════════════════════════════╡ | ||||
| │ Copyright 2021 Justine Alexandra Roberts Tunney                              │ | ||||
| │                                                                              │ | ||||
| │ Permission to use, copy, modify, and/or distribute this software for         │ | ||||
| │ any purpose with or without fee is hereby granted, provided that the         │ | ||||
| │ above copyright notice and this permission notice appear in all copies.      │ | ||||
| │                                                                              │ | ||||
| │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL                │ | ||||
| │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED                │ | ||||
| │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE             │ | ||||
| │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL         │ | ||||
| │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR        │ | ||||
| │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER               │ | ||||
| │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR             │ | ||||
| │ PERFORMANCE OF THIS SOFTWARE.                                                │ | ||||
| ╚─────────────────────────────────────────────────────────────────────────────*/ | ||||
| #include "libc/math.h" | ||||
| #include "libc/stdio/stdio.h" | ||||
| 
 | ||||
| #define N 8 | ||||
| 
 | ||||
| #define SQR(X) ((X) * (X)) | ||||
| 
 | ||||
| static const uint8_t kXtermCube[6] = {0, 0137, 0207, 0257, 0327, 0377}; | ||||
| 
 | ||||
| static int rgb2xterm256(int r, int g, int b) { | ||||
|   int cerr, gerr, ir, ig, ib, gray, grai, cr, cg, cb, gv; | ||||
|   gray = round(r * .299 + g * .587 + b * .114); | ||||
|   grai = gray > 238 ? 23 : (gray - 3) / 10; | ||||
|   ir = r < 48 ? 0 : r < 115 ? 1 : (r - 35) / 40; | ||||
|   ig = g < 48 ? 0 : g < 115 ? 1 : (g - 35) / 40; | ||||
|   ib = b < 48 ? 0 : b < 115 ? 1 : (b - 35) / 40; | ||||
|   cr = kXtermCube[ir]; | ||||
|   cg = kXtermCube[ig]; | ||||
|   cb = kXtermCube[ib]; | ||||
|   gv = 8 + 10 * grai; | ||||
|   cerr = SQR(cr - r) + SQR(cg - g) + SQR(cb - b); | ||||
|   gerr = SQR(gv - r) + SQR(gv - g) + SQR(gv - b); | ||||
|   if (cerr <= gerr) { | ||||
|     return 16 + 36 * ir + 6 * ig + ib; | ||||
|   } else { | ||||
|     return 232 + grai; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| int main(int argc, char *argv[]) { | ||||
|   double d; | ||||
|   int i, j, x; | ||||
|   int r, g, b; | ||||
|   double G[N][3]; | ||||
|   double rgb[2][3] = { | ||||
|       {1, 0, 0}, | ||||
|       {0, 1, 0}, | ||||
|   }; | ||||
| 
 | ||||
|   for (i = 0; i < N; ++i) { | ||||
|     for (j = 0; j < 3; ++j) { | ||||
|       d = (rgb[1][j] - rgb[0][j]) / (N - 1); | ||||
|       G[i][j] = rgb[0][j] + d * i; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   for (i = 0; i < N; ++i) { | ||||
|     r = round(G[i][0] * 255); | ||||
|     g = round(G[i][1] * 255); | ||||
|     b = round(G[i][2] * 255); | ||||
|     x = rgb2xterm256(r, g, b); | ||||
|     printf("\e[38;5;232;48;5;%dmabcdefg       \e[0m %3d " | ||||
|            "\e[38;5;232;48;2;%d;%d;%dmabcdgefg      \e[0m " | ||||
|            "%3d %3d %3d %f %f %f\n", | ||||
|            x, x, r, g, b, r, g, b, G[i][0], G[i][1], G[i][2]); | ||||
|   } | ||||
| 
 | ||||
|   return 0; | ||||
| } | ||||
|  | @ -1,706 +0,0 @@ | |||
| /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
 | ||||
| │vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8                                :vi│ | ||||
| ╞══════════════════════════════════════════════════════════════════════════════╡ | ||||
| │ Copyright 2020 Justine Alexandra Roberts Tunney                              │ | ||||
| │                                                                              │ | ||||
| │ Permission to use, copy, modify, and/or distribute this software for         │ | ||||
| │ any purpose with or without fee is hereby granted, provided that the         │ | ||||
| │ above copyright notice and this permission notice appear in all copies.      │ | ||||
| │                                                                              │ | ||||
| │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL                │ | ||||
| │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED                │ | ||||
| │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE             │ | ||||
| │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL         │ | ||||
| │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR        │ | ||||
| │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER               │ | ||||
| │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR             │ | ||||
| │ PERFORMANCE OF THIS SOFTWARE.                                                │ | ||||
| ╚─────────────────────────────────────────────────────────────────────────────*/ | ||||
| #include "dsp/tty/xtermname.h" | ||||
| #include "libc/stdio/stdio.h" | ||||
| #include "libc/str/str.h" | ||||
| 
 | ||||
| struct Rgb { | ||||
|   uint8_t r, g, b; | ||||
| }; | ||||
| 
 | ||||
| const struct Rgb kTango[16] = { | ||||
|     {0x00, 0x00, 0x00}, {0x80, 0x00, 0x00}, {0x00, 0x80, 0x00}, | ||||
|     {0x80, 0x80, 0x00}, {0x00, 0x00, 0x80}, {0x80, 0x00, 0x80}, | ||||
|     {0x00, 0x80, 0x80}, {0xc0, 0xc0, 0xc0}, {0x80, 0x80, 0x80}, | ||||
|     {0xff, 0x00, 0x00}, {0x00, 0xff, 0x00}, {0xff, 0xff, 0x00}, | ||||
|     {0x00, 0x00, 0xff}, {0xff, 0x00, 0xff}, {0x00, 0xff, 0xff}, | ||||
|     {0xff, 0xff, 0xff}, | ||||
| }; | ||||
| 
 | ||||
| const struct Rgb kXtermRgb[] = { | ||||
|     /* 0..15: ansi 16-color palette */ | ||||
|     {0x00, 0x00, 0x00}, | ||||
|     {0x80, 0x00, 0x00}, | ||||
|     {0x00, 0x80, 0x00}, | ||||
|     {0x80, 0x80, 0x00}, | ||||
|     {0x00, 0x00, 0x80}, | ||||
|     {0x80, 0x00, 0x80}, | ||||
|     {0x00, 0x80, 0x80}, | ||||
|     {0xc0, 0xc0, 0xc0}, | ||||
|     {0x80, 0x80, 0x80}, | ||||
|     {0xff, 0x00, 0x00}, | ||||
|     {0x00, 0xff, 0x00}, | ||||
|     {0xff, 0xff, 0x00}, | ||||
|     {0x00, 0x00, 0xff}, | ||||
|     {0xff, 0x00, 0xff}, | ||||
|     {0x00, 0xff, 0xff}, | ||||
|     {0xff, 0xff, 0xff}, | ||||
| 
 | ||||
|     /* 16..231: xterm256 color cubes */ | ||||
|     {0x00, 0x00, 0x00}, | ||||
|     {0x00, 0x00, 0x5f}, | ||||
|     {0x00, 0x00, 0x87}, | ||||
|     {0x00, 0x00, 0xaf}, | ||||
|     {0x00, 0x00, 0xd7}, | ||||
|     {0x00, 0x00, 0xff}, | ||||
|     {0x00, 0x5f, 0x00}, | ||||
|     {0x00, 0x5f, 0x5f}, | ||||
|     {0x00, 0x5f, 0x87}, | ||||
|     {0x00, 0x5f, 0xaf}, | ||||
|     {0x00, 0x5f, 0xd7}, | ||||
|     {0x00, 0x5f, 0xff}, | ||||
|     {0x00, 0x87, 0x00}, | ||||
|     {0x00, 0x87, 0x5f}, | ||||
|     {0x00, 0x87, 0x87}, | ||||
|     {0x00, 0x87, 0xaf}, | ||||
|     {0x00, 0x87, 0xd7}, | ||||
|     {0x00, 0x87, 0xff}, | ||||
|     {0x00, 0xaf, 0x00}, | ||||
|     {0x00, 0xaf, 0x5f}, | ||||
|     {0x00, 0xaf, 0x87}, | ||||
|     {0x00, 0xaf, 0xaf}, | ||||
|     {0x00, 0xaf, 0xd7}, | ||||
|     {0x00, 0xaf, 0xff}, | ||||
|     {0x00, 0xd7, 0x00}, | ||||
|     {0x00, 0xd7, 0x5f}, | ||||
|     {0x00, 0xd7, 0x87}, | ||||
|     {0x00, 0xd7, 0xaf}, | ||||
|     {0x00, 0xd7, 0xd7}, | ||||
|     {0x00, 0xd7, 0xff}, | ||||
|     {0x00, 0xff, 0x00}, | ||||
|     {0x00, 0xff, 0x5f}, | ||||
|     {0x00, 0xff, 0x87}, | ||||
|     {0x00, 0xff, 0xaf}, | ||||
|     {0x00, 0xff, 0xd7}, | ||||
|     {0x00, 0xff, 0xff}, | ||||
|     {0x5f, 0x00, 0x00}, | ||||
|     {0x5f, 0x00, 0x5f}, | ||||
|     {0x5f, 0x00, 0x87}, | ||||
|     {0x5f, 0x00, 0xaf}, | ||||
|     {0x5f, 0x00, 0xd7}, | ||||
|     {0x5f, 0x00, 0xff}, | ||||
|     {0x5f, 0x5f, 0x00}, | ||||
|     {0x5f, 0x5f, 0x5f}, | ||||
|     {0x5f, 0x5f, 0x87}, | ||||
|     {0x5f, 0x5f, 0xaf}, | ||||
|     {0x5f, 0x5f, 0xd7}, | ||||
|     {0x5f, 0x5f, 0xff}, | ||||
|     {0x5f, 0x87, 0x00}, | ||||
|     {0x5f, 0x87, 0x5f}, | ||||
|     {0x5f, 0x87, 0x87}, | ||||
|     {0x5f, 0x87, 0xaf}, | ||||
|     {0x5f, 0x87, 0xd7}, | ||||
|     {0x5f, 0x87, 0xff}, | ||||
|     {0x5f, 0xaf, 0x00}, | ||||
|     {0x5f, 0xaf, 0x5f}, | ||||
|     {0x5f, 0xaf, 0x87}, | ||||
|     {0x5f, 0xaf, 0xaf}, | ||||
|     {0x5f, 0xaf, 0xd7}, | ||||
|     {0x5f, 0xaf, 0xff}, | ||||
|     {0x5f, 0xd7, 0x00}, | ||||
|     {0x5f, 0xd7, 0x5f}, | ||||
|     {0x5f, 0xd7, 0x87}, | ||||
|     {0x5f, 0xd7, 0xaf}, | ||||
|     {0x5f, 0xd7, 0xd7}, | ||||
|     {0x5f, 0xd7, 0xff}, | ||||
|     {0x5f, 0xff, 0x00}, | ||||
|     {0x5f, 0xff, 0x5f}, | ||||
|     {0x5f, 0xff, 0x87}, | ||||
|     {0x5f, 0xff, 0xaf}, | ||||
|     {0x5f, 0xff, 0xd7}, | ||||
|     {0x5f, 0xff, 0xff}, | ||||
|     {0x87, 0x00, 0x00}, | ||||
|     {0x87, 0x00, 0x5f}, | ||||
|     {0x87, 0x00, 0x87}, | ||||
|     {0x87, 0x00, 0xaf}, | ||||
|     {0x87, 0x00, 0xd7}, | ||||
|     {0x87, 0x00, 0xff}, | ||||
|     {0x87, 0x5f, 0x00}, | ||||
|     {0x87, 0x5f, 0x5f}, | ||||
|     {0x87, 0x5f, 0x87}, | ||||
|     {0x87, 0x5f, 0xaf}, | ||||
|     {0x87, 0x5f, 0xd7}, | ||||
|     {0x87, 0x5f, 0xff}, | ||||
|     {0x87, 0x87, 0x00}, | ||||
|     {0x87, 0x87, 0x5f}, | ||||
|     {0x87, 0x87, 0x87}, | ||||
|     {0x87, 0x87, 0xaf}, | ||||
|     {0x87, 0x87, 0xd7}, | ||||
|     {0x87, 0x87, 0xff}, | ||||
|     {0x87, 0xaf, 0x00}, | ||||
|     {0x87, 0xaf, 0x5f}, | ||||
|     {0x87, 0xaf, 0x87}, | ||||
|     {0x87, 0xaf, 0xaf}, | ||||
|     {0x87, 0xaf, 0xd7}, | ||||
|     {0x87, 0xaf, 0xff}, | ||||
|     {0x87, 0xd7, 0x00}, | ||||
|     {0x87, 0xd7, 0x5f}, | ||||
|     {0x87, 0xd7, 0x87}, | ||||
|     {0x87, 0xd7, 0xaf}, | ||||
|     {0x87, 0xd7, 0xd7}, | ||||
|     {0x87, 0xd7, 0xff}, | ||||
|     {0x87, 0xff, 0x00}, | ||||
|     {0x87, 0xff, 0x5f}, | ||||
|     {0x87, 0xff, 0x87}, | ||||
|     {0x87, 0xff, 0xaf}, | ||||
|     {0x87, 0xff, 0xd7}, | ||||
|     {0x87, 0xff, 0xff}, | ||||
|     {0xaf, 0x00, 0x00}, | ||||
|     {0xaf, 0x00, 0x5f}, | ||||
|     {0xaf, 0x00, 0x87}, | ||||
|     {0xaf, 0x00, 0xaf}, | ||||
|     {0xaf, 0x00, 0xd7}, | ||||
|     {0xaf, 0x00, 0xff}, | ||||
|     {0xaf, 0x5f, 0x00}, | ||||
|     {0xaf, 0x5f, 0x5f}, | ||||
|     {0xaf, 0x5f, 0x87}, | ||||
|     {0xaf, 0x5f, 0xaf}, | ||||
|     {0xaf, 0x5f, 0xd7}, | ||||
|     {0xaf, 0x5f, 0xff}, | ||||
|     {0xaf, 0x87, 0x00}, | ||||
|     {0xaf, 0x87, 0x5f}, | ||||
|     {0xaf, 0x87, 0x87}, | ||||
|     {0xaf, 0x87, 0xaf}, | ||||
|     {0xaf, 0x87, 0xd7}, | ||||
|     {0xaf, 0x87, 0xff}, | ||||
|     {0xaf, 0xaf, 0x00}, | ||||
|     {0xaf, 0xaf, 0x5f}, | ||||
|     {0xaf, 0xaf, 0x87}, | ||||
|     {0xaf, 0xaf, 0xaf}, | ||||
|     {0xaf, 0xaf, 0xd7}, | ||||
|     {0xaf, 0xaf, 0xff}, | ||||
|     {0xaf, 0xd7, 0x00}, | ||||
|     {0xaf, 0xd7, 0x5f}, | ||||
|     {0xaf, 0xd7, 0x87}, | ||||
|     {0xaf, 0xd7, 0xaf}, | ||||
|     {0xaf, 0xd7, 0xd7}, | ||||
|     {0xaf, 0xd7, 0xff}, | ||||
|     {0xaf, 0xff, 0x00}, | ||||
|     {0xaf, 0xff, 0x5f}, | ||||
|     {0xaf, 0xff, 0x87}, | ||||
|     {0xaf, 0xff, 0xaf}, | ||||
|     {0xaf, 0xff, 0xd7}, | ||||
|     {0xaf, 0xff, 0xff}, | ||||
|     {0xd7, 0x00, 0x00}, | ||||
|     {0xd7, 0x00, 0x5f}, | ||||
|     {0xd7, 0x00, 0x87}, | ||||
|     {0xd7, 0x00, 0xaf}, | ||||
|     {0xd7, 0x00, 0xd7}, | ||||
|     {0xd7, 0x00, 0xff}, | ||||
|     {0xd7, 0x5f, 0x00}, | ||||
|     {0xd7, 0x5f, 0x5f}, | ||||
|     {0xd7, 0x5f, 0x87}, | ||||
|     {0xd7, 0x5f, 0xaf}, | ||||
|     {0xd7, 0x5f, 0xd7}, | ||||
|     {0xd7, 0x5f, 0xff}, | ||||
|     {0xd7, 0x87, 0x00}, | ||||
|     {0xd7, 0x87, 0x5f}, | ||||
|     {0xd7, 0x87, 0x87}, | ||||
|     {0xd7, 0x87, 0xaf}, | ||||
|     {0xd7, 0x87, 0xd7}, | ||||
|     {0xd7, 0x87, 0xff}, | ||||
|     {0xd7, 0xaf, 0x00}, | ||||
|     {0xd7, 0xaf, 0x5f}, | ||||
|     {0xd7, 0xaf, 0x87}, | ||||
|     {0xd7, 0xaf, 0xaf}, | ||||
|     {0xd7, 0xaf, 0xd7}, | ||||
|     {0xd7, 0xaf, 0xff}, | ||||
|     {0xd7, 0xd7, 0x00}, | ||||
|     {0xd7, 0xd7, 0x5f}, | ||||
|     {0xd7, 0xd7, 0x87}, | ||||
|     {0xd7, 0xd7, 0xaf}, | ||||
|     {0xd7, 0xd7, 0xd7}, | ||||
|     {0xd7, 0xd7, 0xff}, | ||||
|     {0xd7, 0xff, 0x00}, | ||||
|     {0xd7, 0xff, 0x5f}, | ||||
|     {0xd7, 0xff, 0x87}, | ||||
|     {0xd7, 0xff, 0xaf}, | ||||
|     {0xd7, 0xff, 0xd7}, | ||||
|     {0xd7, 0xff, 0xff}, | ||||
|     {0xff, 0x00, 0x00}, | ||||
|     {0xff, 0x00, 0x5f}, | ||||
|     {0xff, 0x00, 0x87}, | ||||
|     {0xff, 0x00, 0xaf}, | ||||
|     {0xff, 0x00, 0xd7}, | ||||
|     {0xff, 0x00, 0xff}, | ||||
|     {0xff, 0x5f, 0x00}, | ||||
|     {0xff, 0x5f, 0x5f}, | ||||
|     {0xff, 0x5f, 0x87}, | ||||
|     {0xff, 0x5f, 0xaf}, | ||||
|     {0xff, 0x5f, 0xd7}, | ||||
|     {0xff, 0x5f, 0xff}, | ||||
|     {0xff, 0x87, 0x00}, | ||||
|     {0xff, 0x87, 0x5f}, | ||||
|     {0xff, 0x87, 0x87}, | ||||
|     {0xff, 0x87, 0xaf}, | ||||
|     {0xff, 0x87, 0xd7}, | ||||
|     {0xff, 0x87, 0xff}, | ||||
|     {0xff, 0xaf, 0x00}, | ||||
|     {0xff, 0xaf, 0x5f}, | ||||
|     {0xff, 0xaf, 0x87}, | ||||
|     {0xff, 0xaf, 0xaf}, | ||||
|     {0xff, 0xaf, 0xd7}, | ||||
|     {0xff, 0xaf, 0xff}, | ||||
|     {0xff, 0xd7, 0x00}, | ||||
|     {0xff, 0xd7, 0x5f}, | ||||
|     {0xff, 0xd7, 0x87}, | ||||
|     {0xff, 0xd7, 0xaf}, | ||||
|     {0xff, 0xd7, 0xd7}, | ||||
|     {0xff, 0xd7, 0xff}, | ||||
|     {0xff, 0xff, 0x00}, | ||||
|     {0xff, 0xff, 0x5f}, | ||||
|     {0xff, 0xff, 0x87}, | ||||
|     {0xff, 0xff, 0xaf}, | ||||
|     {0xff, 0xff, 0xd7}, | ||||
|     {0xff, 0xff, 0xff}, | ||||
| 
 | ||||
|     /* 232..255: xterm256 grayscale */ | ||||
|     {0x08, 0x08, 0x08}, /*  8 */ | ||||
|     {0x12, 0x12, 0x12}, /* 10 */ | ||||
|     {0x1c, 0x1c, 0x1c}, /* 10 */ | ||||
|     {0x26, 0x26, 0x26}, /* 10 */ | ||||
|     {0x30, 0x30, 0x30}, /* .. */ | ||||
|     {0x3a, 0x3a, 0x3a}, | ||||
|     {0x44, 0x44, 0x44}, | ||||
|     {0x4e, 0x4e, 0x4e}, | ||||
|     {0x58, 0x58, 0x58}, | ||||
|     {0x62, 0x62, 0x62}, | ||||
|     {0x6c, 0x6c, 0x6c}, | ||||
|     {0x76, 0x76, 0x76}, | ||||
|     {0x80, 0x80, 0x80}, | ||||
|     {0x8a, 0x8a, 0x8a}, | ||||
|     {0x94, 0x94, 0x94}, | ||||
|     {0x9e, 0x9e, 0x9e}, | ||||
|     {0xa8, 0xa8, 0xa8}, | ||||
|     {0xb2, 0xb2, 0xb2}, | ||||
|     {0xbc, 0xbc, 0xbc}, | ||||
|     {0xc6, 0xc6, 0xc6}, | ||||
|     {0xd0, 0xd0, 0xd0}, | ||||
|     {0xda, 0xda, 0xda}, | ||||
|     {0xe4, 0xe4, 0xe4}, | ||||
|     {0xee, 0xee, 0xee}, | ||||
| }; | ||||
| 
 | ||||
| const struct Rgb kXtermRgbAppleFg[] = { | ||||
|     {0, 0, 0},       {192, 55, 41},   {48, 187, 49},   {173, 172, 53}, | ||||
|     {73, 76, 224},   {209, 65, 209},  {60, 187, 199},  {203, 204, 205}, | ||||
|     {154, 155, 156}, {249, 59, 44},   {62, 229, 55},   {234, 234, 62}, | ||||
|     {89, 63, 251},   {247, 67, 245},  {48, 239, 239},  {233, 235, 235}, | ||||
|     {47, 49, 49},    {60, 46, 142},   {67, 51, 180},   {74, 56, 218}, | ||||
|     {82, 62, 248},   {89, 63, 251},   {46, 127, 43},   {46, 127, 127}, | ||||
|     {49, 127, 167},  {60, 127, 207},  {63, 127, 241},  {70, 126, 251}, | ||||
|     {57, 161, 50},   {47, 161, 122},  {50, 161, 161},  {60, 161, 200}, | ||||
|     {53, 161, 237},  {65, 160, 252},  {45, 194, 51},   {58, 194, 118}, | ||||
|     {51, 194, 156},  {59, 194, 194},  {48, 194, 233},  {63, 194, 252}, | ||||
|     {62, 227, 55},   {55, 227, 115},  {48, 227, 151},  {63, 227, 189}, | ||||
|     {52, 227, 227},  {66, 227, 253},  {51, 252, 57},   {53, 252, 111}, | ||||
|     {63, 252, 147},  {58, 252, 184},  {59, 252, 222},  {62, 253, 251}, | ||||
|     {138, 49, 43},   {134, 55, 134},  {134, 58, 174},  {133, 61, 213}, | ||||
|     {134, 67, 244},  {134, 65, 251},  {125, 124, 46},  {124, 125, 125}, | ||||
|     {122, 125, 165}, {123, 126, 205}, {124, 126, 243}, {125, 125, 251}, | ||||
|     {120, 159, 47},  {118, 159, 121}, {118, 159, 160}, {117, 160, 199}, | ||||
|     {118, 160, 238}, {119, 160, 252}, {115, 193, 53},  {113, 193, 117}, | ||||
|     {114, 193, 155}, {111, 193, 193}, {113, 194, 232}, {112, 193, 252}, | ||||
|     {110, 226, 53},  {108, 226, 114}, {110, 226, 151}, {106, 226, 189}, | ||||
|     {105, 227, 227}, {105, 226, 252}, {99, 251, 59},   {103, 251, 111}, | ||||
|     {104, 251, 146}, {97, 252, 184},  {102, 252, 221}, {98, 254, 250}, | ||||
|     {175, 54, 40},   {172, 58, 130},  {170, 61, 170},  {170, 66, 210}, | ||||
|     {169, 67, 245},  {168, 69, 251},  {164, 123, 47},  {162, 123, 124}, | ||||
|     {161, 124, 163}, {161, 124, 203}, {160, 125, 238}, {160, 125, 251}, | ||||
|     {158, 157, 47},  {157, 158, 120}, {157, 158, 159}, {155, 158, 198}, | ||||
|     {155, 159, 236}, {155, 158, 252}, {153, 192, 55},  {152, 192, 117}, | ||||
|     {151, 192, 154}, {151, 192, 193}, {150, 192, 231}, {150, 192, 251}, | ||||
|     {148, 225, 53},  {147, 225, 114}, {146, 225, 150}, {147, 226, 188}, | ||||
|     {145, 226, 226}, {145, 226, 250}, {142, 251, 61},  {141, 251, 111}, | ||||
|     {141, 252, 146}, {142, 253, 183}, {139, 254, 221}, {138, 255, 249}, | ||||
|     {211, 59, 40},   {209, 63, 126},  {207, 63, 166},  {206, 64, 206}, | ||||
|     {205, 69, 243},  {204, 72, 252},  {202, 121, 45},  {201, 122, 122}, | ||||
|     {200, 122, 161}, {199, 123, 200}, {199, 124, 238}, {197, 124, 252}, | ||||
|     {197, 156, 51},  {195, 156, 119}, {195, 157, 157}, {194, 157, 196}, | ||||
|     {193, 157, 234}, {193, 157, 252}, {191, 190, 54},  {190, 190, 116}, | ||||
|     {189, 191, 153}, {190, 191, 191}, {188, 191, 229}, {187, 191, 251}, | ||||
|     {186, 224, 55},  {185, 224, 113}, {184, 224, 150}, {184, 224, 187}, | ||||
|     {184, 225, 225}, {182, 224, 251}, {180, 253, 62},  {180, 253, 111}, | ||||
|     {179, 253, 146}, {179, 253, 183}, {179, 254, 220}, {177, 252, 249}, | ||||
|     {244, 59, 43},   {243, 62, 123},  {241, 65, 162},  {241, 69, 202}, | ||||
|     {240, 70, 238},  {238, 69, 252},  {239, 119, 50},  {238, 120, 120}, | ||||
|     {236, 121, 159}, {235, 121, 198}, {235, 123, 236}, {234, 123, 252}, | ||||
|     {234, 154, 53},  {233, 154, 118}, {232, 155, 156}, {231, 155, 194}, | ||||
|     {231, 156, 233}, {230, 156, 252}, {229, 188, 53},  {228, 189, 115}, | ||||
|     {227, 189, 152}, {227, 189, 190}, {226, 189, 228}, {225, 189, 253}, | ||||
|     {223, 222, 60},  {223, 223, 113}, {222, 223, 149}, {222, 223, 186}, | ||||
|     {222, 223, 224}, {220, 223, 252}, {218, 251, 61},  {217, 251, 109}, | ||||
|     {217, 251, 145}, {217, 251, 182}, {216, 251, 219}, {216, 251, 250}, | ||||
|     {252, 63, 43},   {252, 64, 120},  {252, 64, 159},  {252, 65, 198}, | ||||
|     {252, 67, 236},  {252, 72, 252},  {253, 117, 47},  {253, 118, 118}, | ||||
|     {253, 119, 156}, {253, 120, 194}, {253, 120, 233}, {252, 121, 252}, | ||||
|     {253, 152, 49},  {252, 152, 116}, {252, 153, 153}, {253, 153, 192}, | ||||
|     {252, 154, 229}, {251, 154, 251}, {253, 186, 56},  {251, 187, 114}, | ||||
|     {251, 187, 151}, {252, 187, 188}, {252, 188, 226}, {251, 188, 251}, | ||||
|     {251, 221, 61},  {250, 221, 112}, {250, 221, 148}, {250, 221, 185}, | ||||
|     {251, 222, 222}, {251, 222, 251}, {251, 250, 58},  {250, 250, 109}, | ||||
|     {249, 250, 144}, {247, 251, 181}, {247, 253, 218}, {254, 255, 255}, | ||||
|     {52, 53, 53},    {57, 58, 59},    {66, 67, 67},    {75, 76, 76}, | ||||
|     {84, 85, 85},    {92, 93, 94},    {101, 102, 102}, {109, 111, 111}, | ||||
|     {118, 119, 119}, {126, 127, 128}, {134, 136, 136}, {143, 144, 145}, | ||||
|     {151, 152, 153}, {159, 161, 161}, {167, 169, 169}, {176, 177, 177}, | ||||
|     {184, 185, 186}, {192, 193, 194}, {200, 201, 202}, {208, 209, 210}, | ||||
|     {216, 218, 218}, {224, 226, 226}, {232, 234, 234}, {240, 242, 242}, | ||||
| }; | ||||
| 
 | ||||
| const struct Rgb kXtermRgbAppleBg[] = { | ||||
|     {0, 0, 0},       {151, 4, 12},    {23, 164, 26},   {153, 152, 29}, | ||||
|     {8, 43, 181},    {177, 25, 176},  {26, 166, 177},  {191, 191, 191}, | ||||
|     {132, 132, 132}, {227, 10, 23},   {33, 215, 38},   {229, 228, 49}, | ||||
|     {11, 36, 251},   {227, 35, 227},  {39, 229, 228},  {230, 229, 230}, | ||||
|     {0, 0, 0},       {1, 7, 93},      {3, 14, 133},    {5, 21, 172}, | ||||
|     {7, 28, 211},    {11, 36, 251},   {8, 94, 11},     {10, 95, 95}, | ||||
|     {11, 96, 133},   {13, 97, 173},   {15, 99, 212},   {18, 101, 251}, | ||||
|     {17, 134, 20},   {18, 134, 96},   {18, 135, 134},  {20, 136, 173}, | ||||
|     {21, 137, 212},  {23, 138, 251},  {25, 173, 29},   {26, 174, 98}, | ||||
|     {26, 174, 136},  {27, 175, 174},  {28, 175, 213},  {30, 176, 252}, | ||||
|     {33, 213, 38},   {34, 213, 101},  {34, 214, 137},  {35, 214, 175}, | ||||
|     {36, 215, 214},  {37, 215, 253},  {41, 253, 47},   {42, 253, 104}, | ||||
|     {42, 253, 140},  {43, 253, 177},  {44, 254, 215},  {45, 255, 254}, | ||||
|     {94, 2, 4},      {94, 8, 94},     {94, 15, 133},   {94, 22, 172}, | ||||
|     {95, 29, 211},   {95, 36, 251},   {95, 94, 14},    {95, 95, 95}, | ||||
|     {95, 96, 134},   {95, 97, 173},   {96, 99, 212},   {96, 101, 251}, | ||||
|     {96, 134, 22},   {96, 134, 96},   {96, 135, 135},  {97, 136, 173}, | ||||
|     {97, 137, 212},  {97, 138, 252},  {98, 173, 30},   {98, 174, 98}, | ||||
|     {98, 174, 136},  {98, 175, 174},  {98, 176, 213},  {99, 177, 252}, | ||||
|     {100, 213, 39},  {100, 213, 101}, {100, 214, 138}, {100, 214, 176}, | ||||
|     {101, 215, 214}, {101, 215, 253}, {102, 253, 48},  {103, 253, 104}, | ||||
|     {103, 253, 140}, {103, 253, 177}, {103, 254, 215}, {104, 255, 254}, | ||||
|     {133, 3, 9},     {133, 10, 94},   {134, 16, 133},  {134, 23, 172}, | ||||
|     {134, 30, 212},  {134, 37, 251},  {134, 94, 18},   {134, 95, 96}, | ||||
|     {134, 96, 134},  {134, 97, 173},  {135, 99, 212},  {135, 101, 251}, | ||||
|     {135, 134, 25},  {135, 134, 97},  {135, 135, 135}, {135, 136, 174}, | ||||
|     {135, 137, 213}, {136, 138, 252}, {136, 173, 32},  {136, 174, 99}, | ||||
|     {136, 174, 136}, {136, 175, 175}, {136, 176, 213}, {137, 177, 252}, | ||||
|     {137, 213, 40},  {137, 213, 102}, {138, 214, 138}, {138, 214, 176}, | ||||
|     {138, 215, 214}, {138, 216, 253}, {139, 253, 49},  {139, 253, 105}, | ||||
|     {139, 253, 140}, {139, 254, 178}, {140, 254, 216}, {140, 255, 254}, | ||||
|     {173, 6, 15},    {173, 12, 95},   {173, 18, 134},  {173, 24, 173}, | ||||
|     {173, 31, 212},  {174, 38, 251},  {173, 95, 22},   {174, 95, 96}, | ||||
|     {174, 96, 135},  {174, 98, 173},  {174, 99, 212},  {174, 101, 252}, | ||||
|     {174, 134, 28},  {174, 135, 98},  {174, 135, 136}, {174, 136, 174}, | ||||
|     {174, 137, 213}, {175, 139, 252}, {175, 174, 35},  {175, 174, 100}, | ||||
|     {175, 174, 137}, {175, 175, 175}, {175, 176, 214}, {175, 177, 253}, | ||||
|     {176, 213, 43},  {176, 213, 102}, {176, 214, 139}, {176, 214, 176}, | ||||
|     {176, 215, 215}, {176, 216, 253}, {177, 253, 51},  {177, 253, 105}, | ||||
|     {177, 253, 141}, {177, 254, 178}, {178, 254, 216}, {178, 255, 254}, | ||||
|     {213, 9, 21},    {213, 15, 96},   {213, 20, 135},  {241, 69, 202}, | ||||
|     {213, 32, 212},  {213, 39, 251},  {213, 95, 27},   {213, 96, 97}, | ||||
|     {213, 97, 135},  {213, 98, 174},  {213, 100, 213}, {213, 102, 252}, | ||||
|     {213, 134, 32},  {213, 135, 99},  {213, 135, 136}, {214, 136, 175}, | ||||
|     {214, 137, 213}, {214, 139, 252}, {214, 174, 38},  {214, 174, 101}, | ||||
|     {214, 175, 138}, {214, 175, 176}, {214, 176, 214}, {214, 177, 253}, | ||||
|     {215, 213, 45},  {215, 214, 103}, {215, 214, 139}, {215, 214, 177}, | ||||
|     {215, 215, 215}, {215, 216, 254}, {216, 253, 53},  {216, 253, 106}, | ||||
|     {216, 253, 141}, {216, 254, 178}, {216, 254, 216}, {216, 255, 255}, | ||||
|     {252, 13, 27},   {252, 18, 98},   {252, 22, 135},  {252, 28, 174}, | ||||
|     {252, 34, 213},  {252, 40, 252},  {252, 96, 32},   {252, 96, 99}, | ||||
|     {252, 97, 136},  {253, 99, 175},  {253, 100, 213}, {253, 102, 252}, | ||||
|     {253, 135, 36},  {253, 135, 100}, {253, 136, 137}, {253, 137, 175}, | ||||
|     {253, 138, 214}, {253, 139, 253}, {253, 174, 42},  {253, 174, 102}, | ||||
|     {253, 175, 138}, {253, 175, 176}, {253, 176, 215}, {254, 177, 253}, | ||||
|     {254, 213, 48},  {254, 214, 105}, {254, 214, 140}, {254, 215, 177}, | ||||
|     {254, 215, 216}, {254, 216, 254}, {255, 253, 56},  {255, 253, 108}, | ||||
|     {255, 253, 142}, {255, 254, 179}, {255, 254, 217}, {255, 255, 255}, | ||||
|     {8, 8, 8},       {18, 18, 18},    {28, 28, 28},    {38, 38, 38}, | ||||
|     {48, 48, 48},    {58, 58, 58},    {68, 68, 68},    {78, 78, 78}, | ||||
|     {88, 88, 88},    {98, 98, 98},    {108, 108, 108}, {118, 118, 118}, | ||||
|     {128, 128, 128}, {138, 138, 138}, {148, 148, 148}, {158, 158, 158}, | ||||
|     {168, 168, 168}, {178, 178, 178}, {188, 188, 188}, {198, 198, 198}, | ||||
|     {208, 208, 208}, {218, 218, 218}, {228, 228, 228}, {238, 238, 238}, | ||||
| }; | ||||
| 
 | ||||
| const struct XtermDb { | ||||
|   struct Rgb rgb; | ||||
|   const char *text; | ||||
| } kXtermDb[] = { | ||||
|     {{0x00, 0x00, 0x00}, "0      Black             #000000"}, | ||||
|     {{0x80, 0x00, 0x00}, "1      Maroon            #800000"}, | ||||
|     {{0x00, 0x80, 0x00}, "2      Green             #008000"}, | ||||
|     {{0x80, 0x80, 0x00}, "3      Olive             #808000"}, | ||||
|     {{0x00, 0x00, 0x80}, "4      Navy              #000080"}, | ||||
|     {{0x80, 0x00, 0x80}, "5      Purple            #800080"}, | ||||
|     {{0x00, 0x80, 0x80}, "6      Teal              #008080"}, | ||||
|     {{0xc0, 0xc0, 0xc0}, "7      Silver            #c0c0c0"}, | ||||
|     {{0x80, 0x80, 0x80}, "8      Grey              #808080"}, | ||||
|     {{0xff, 0x00, 0x00}, "9      Red               #ff0000"}, | ||||
|     {{0x00, 0xff, 0x00}, "10     Lime              #00ff00"}, | ||||
|     {{0xff, 0xff, 0x00}, "11     Yellow            #ffff00"}, | ||||
|     {{0x00, 0x00, 0xff}, "12     Blue              #0000ff"}, | ||||
|     {{0xff, 0x00, 0xff}, "13     Fuchsia           #ff00ff"}, | ||||
|     {{0x00, 0xff, 0xff}, "14     Aqua              #00ffff"}, | ||||
|     {{0xff, 0xff, 0xff}, "15     White             #ffffff"}, | ||||
|     {{0x00, 0x00, 0x00}, "16     Grey0             #000000"}, | ||||
|     {{0x00, 0x00, 0x5f}, "17     NavyBlue          #00005f"}, | ||||
|     {{0x00, 0x00, 0x87}, "18     DarkBlue          #000087"}, | ||||
|     {{0x00, 0x00, 0xaf}, "19     Blue3             #0000af"}, | ||||
|     {{0x00, 0x00, 0xd7}, "20     Blue3             #0000d7"}, | ||||
|     {{0x00, 0x00, 0xff}, "21     Blue1             #0000ff"}, | ||||
|     {{0x00, 0x5f, 0x00}, "22     DarkGreen         #005f00"}, | ||||
|     {{0x00, 0x5f, 0x5f}, "23     DeepSkyBlue4      #005f5f"}, | ||||
|     {{0x00, 0x5f, 0x87}, "24     DeepSkyBlue4      #005f87"}, | ||||
|     {{0x00, 0x5f, 0xaf}, "25     DeepSkyBlue4      #005faf"}, | ||||
|     {{0x00, 0x5f, 0xd7}, "26     DodgerBlue3       #005fd7"}, | ||||
|     {{0x00, 0x5f, 0xff}, "27     DodgerBlue2       #005fff"}, | ||||
|     {{0x00, 0x87, 0x00}, "28     Green4            #008700"}, | ||||
|     {{0x00, 0x87, 0x5f}, "29     SpringGreen4      #00875f"}, | ||||
|     {{0x00, 0x87, 0x87}, "30     Turquoise4        #008787"}, | ||||
|     {{0x00, 0x87, 0xaf}, "31     DeepSkyBlue3      #0087af"}, | ||||
|     {{0x00, 0x87, 0xd7}, "32     DeepSkyBlue3      #0087d7"}, | ||||
|     {{0x00, 0x87, 0xff}, "33     DodgerBlue1       #0087ff"}, | ||||
|     {{0x00, 0xaf, 0x00}, "34     Green3            #00af00"}, | ||||
|     {{0x00, 0xaf, 0x5f}, "35     SpringGreen3      #00af5f"}, | ||||
|     {{0x00, 0xaf, 0x87}, "36     DarkCyan          #00af87"}, | ||||
|     {{0x00, 0xaf, 0xaf}, "37     LightSeaGreen     #00afaf"}, | ||||
|     {{0x00, 0xaf, 0xd7}, "38     DeepSkyBlue2      #00afd7"}, | ||||
|     {{0x00, 0xaf, 0xff}, "39     DeepSkyBlue1      #00afff"}, | ||||
|     {{0x00, 0xd7, 0x00}, "40     Green3            #00d700"}, | ||||
|     {{0x00, 0xd7, 0x5f}, "41     SpringGreen3      #00d75f"}, | ||||
|     {{0x00, 0xd7, 0x87}, "42     SpringGreen2      #00d787"}, | ||||
|     {{0x00, 0xd7, 0xaf}, "43     Cyan3             #00d7af"}, | ||||
|     {{0x00, 0xd7, 0xd7}, "44     DarkTurquoise     #00d7d7"}, | ||||
|     {{0x00, 0xd7, 0xff}, "45     Turquoise2        #00d7ff"}, | ||||
|     {{0x00, 0xff, 0x00}, "46     Green1            #00ff00"}, | ||||
|     {{0x00, 0xff, 0x5f}, "47     SpringGreen2      #00ff5f"}, | ||||
|     {{0x00, 0xff, 0x87}, "48     SpringGreen1      #00ff87"}, | ||||
|     {{0x00, 0xff, 0xaf}, "49     MediumSpringGreen #00ffaf"}, | ||||
|     {{0x00, 0xff, 0xd7}, "50     Cyan2             #00ffd7"}, | ||||
|     {{0x00, 0xff, 0xff}, "51     Cyan1             #00ffff"}, | ||||
|     {{0x5f, 0x00, 0x00}, "52     DarkRed           #5f0000"}, | ||||
|     {{0x5f, 0x00, 0x5f}, "53     DeepPink4         #5f005f"}, | ||||
|     {{0x5f, 0x00, 0x87}, "54     Purple4           #5f0087"}, | ||||
|     {{0x5f, 0x00, 0xaf}, "55     Purple4           #5f00af"}, | ||||
|     {{0x5f, 0x00, 0xd7}, "56     Purple3           #5f00d7"}, | ||||
|     {{0x5f, 0x00, 0xff}, "57     BlueViolet        #5f00ff"}, | ||||
|     {{0x5f, 0x5f, 0x00}, "58     Orange4           #5f5f00"}, | ||||
|     {{0x5f, 0x5f, 0x5f}, "59     Grey37            #5f5f5f"}, | ||||
|     {{0x5f, 0x5f, 0x87}, "60     MediumPurple4     #5f5f87"}, | ||||
|     {{0x5f, 0x5f, 0xaf}, "61     SlateBlue3        #5f5faf"}, | ||||
|     {{0x5f, 0x5f, 0xd7}, "62     SlateBlue3        #5f5fd7"}, | ||||
|     {{0x5f, 0x5f, 0xff}, "63     RoyalBlue1        #5f5fff"}, | ||||
|     {{0x5f, 0x87, 0x00}, "64     Chartreuse4       #5f8700"}, | ||||
|     {{0x5f, 0x87, 0x5f}, "65     DarkSeaGreen4     #5f875f"}, | ||||
|     {{0x5f, 0x87, 0x87}, "66     PaleTurquoise4    #5f8787"}, | ||||
|     {{0x5f, 0x87, 0xaf}, "67     SteelBlue         #5f87af"}, | ||||
|     {{0x5f, 0x87, 0xd7}, "68     SteelBlue3        #5f87d7"}, | ||||
|     {{0x5f, 0x87, 0xff}, "69     CornflowerBlue    #5f87ff"}, | ||||
|     {{0x5f, 0xaf, 0x00}, "70     Chartreuse3       #5faf00"}, | ||||
|     {{0x5f, 0xaf, 0x5f}, "71     DarkSeaGreen4     #5faf5f"}, | ||||
|     {{0x5f, 0xaf, 0x87}, "72     CadetBlue         #5faf87"}, | ||||
|     {{0x5f, 0xaf, 0xaf}, "73     CadetBlue         #5fafaf"}, | ||||
|     {{0x5f, 0xaf, 0xd7}, "74     SkyBlue3          #5fafd7"}, | ||||
|     {{0x5f, 0xaf, 0xff}, "75     SteelBlue1        #5fafff"}, | ||||
|     {{0x5f, 0xd7, 0x00}, "76     Chartreuse3       #5fd700"}, | ||||
|     {{0x5f, 0xd7, 0x5f}, "77     PaleGreen3        #5fd75f"}, | ||||
|     {{0x5f, 0xd7, 0x87}, "78     SeaGreen3         #5fd787"}, | ||||
|     {{0x5f, 0xd7, 0xaf}, "79     Aquamarine3       #5fd7af"}, | ||||
|     {{0x5f, 0xd7, 0xd7}, "80     MediumTurquoise   #5fd7d7"}, | ||||
|     {{0x5f, 0xd7, 0xff}, "81     SteelBlue1        #5fd7ff"}, | ||||
|     {{0x5f, 0xff, 0x00}, "82     Chartreuse2       #5fff00"}, | ||||
|     {{0x5f, 0xff, 0x5f}, "83     SeaGreen2         #5fff5f"}, | ||||
|     {{0x5f, 0xff, 0x87}, "84     SeaGreen1         #5fff87"}, | ||||
|     {{0x5f, 0xff, 0xaf}, "85     SeaGreen1         #5fffaf"}, | ||||
|     {{0x5f, 0xff, 0xd7}, "86     Aquamarine1       #5fffd7"}, | ||||
|     {{0x5f, 0xff, 0xff}, "87     DarkSlateGray2    #5fffff"}, | ||||
|     {{0x87, 0x00, 0x00}, "88     DarkRed           #870000"}, | ||||
|     {{0x87, 0x00, 0x5f}, "89     DeepPink4         #87005f"}, | ||||
|     {{0x87, 0x00, 0x87}, "90     DarkMagenta       #870087"}, | ||||
|     {{0x87, 0x00, 0xaf}, "91     DarkMagenta       #8700af"}, | ||||
|     {{0x87, 0x00, 0xd7}, "92     DarkViolet        #8700d7"}, | ||||
|     {{0x87, 0x00, 0xff}, "93     Purple            #8700ff"}, | ||||
|     {{0x87, 0x5f, 0x00}, "94     Orange4           #875f00"}, | ||||
|     {{0x87, 0x5f, 0x5f}, "95     LightPink4        #875f5f"}, | ||||
|     {{0x87, 0x5f, 0x87}, "96     Plum4             #875f87"}, | ||||
|     {{0x87, 0x5f, 0xaf}, "97     MediumPurple3     #875faf"}, | ||||
|     {{0x87, 0x5f, 0xd7}, "98     MediumPurple3     #875fd7"}, | ||||
|     {{0x87, 0x5f, 0xff}, "99     SlateBlue1        #875fff"}, | ||||
|     {{0x87, 0x87, 0x00}, "100    Yellow4           #878700"}, | ||||
|     {{0x87, 0x87, 0x5f}, "101    Wheat4            #87875f"}, | ||||
|     {{0x87, 0x87, 0x87}, "102    Grey53            #878787"}, | ||||
|     {{0x87, 0x87, 0xaf}, "103    LightSlateGrey    #8787af"}, | ||||
|     {{0x87, 0x87, 0xd7}, "104    MediumPurple      #8787d7"}, | ||||
|     {{0x87, 0x87, 0xff}, "105    LightSlateBlue    #8787ff"}, | ||||
|     {{0x87, 0xaf, 0x00}, "106    Yellow4           #87af00"}, | ||||
|     {{0x87, 0xaf, 0x5f}, "107    DarkOliveGreen3   #87af5f"}, | ||||
|     {{0x87, 0xaf, 0x87}, "108    DarkSeaGreen      #87af87"}, | ||||
|     {{0x87, 0xaf, 0xaf}, "109    LightSkyBlue3     #87afaf"}, | ||||
|     {{0x87, 0xaf, 0xd7}, "110    LightSkyBlue3     #87afd7"}, | ||||
|     {{0x87, 0xaf, 0xff}, "111    SkyBlue2          #87afff"}, | ||||
|     {{0x87, 0xd7, 0x00}, "112    Chartreuse2       #87d700"}, | ||||
|     {{0x87, 0xd7, 0x5f}, "113    DarkOliveGreen3   #87d75f"}, | ||||
|     {{0x87, 0xd7, 0x87}, "114    PaleGreen3        #87d787"}, | ||||
|     {{0x87, 0xd7, 0xaf}, "115    DarkSeaGreen3     #87d7af"}, | ||||
|     {{0x87, 0xd7, 0xd7}, "116    DarkSlateGray3    #87d7d7"}, | ||||
|     {{0x87, 0xd7, 0xff}, "117    SkyBlue1          #87d7ff"}, | ||||
|     {{0x87, 0xff, 0x00}, "118    Chartreuse1       #87ff00"}, | ||||
|     {{0x87, 0xff, 0x5f}, "119    LightGreen        #87ff5f"}, | ||||
|     {{0x87, 0xff, 0x87}, "120    LightGreen        #87ff87"}, | ||||
|     {{0x87, 0xff, 0xaf}, "121    PaleGreen1        #87ffaf"}, | ||||
|     {{0x87, 0xff, 0xd7}, "122    Aquamarine1       #87ffd7"}, | ||||
|     {{0x87, 0xff, 0xff}, "123    DarkSlateGray1    #87ffff"}, | ||||
|     {{0xaf, 0x00, 0x00}, "124    Red3              #af0000"}, | ||||
|     {{0xaf, 0x00, 0x5f}, "125    DeepPink4         #af005f"}, | ||||
|     {{0xaf, 0x00, 0x87}, "126    MediumVioletRed   #af0087"}, | ||||
|     {{0xaf, 0x00, 0xaf}, "127    Magenta3          #af00af"}, | ||||
|     {{0xaf, 0x00, 0xd7}, "128    DarkViolet        #af00d7"}, | ||||
|     {{0xaf, 0x00, 0xff}, "129    Purple            #af00ff"}, | ||||
|     {{0xaf, 0x5f, 0x00}, "130    DarkOrange3       #af5f00"}, | ||||
|     {{0xaf, 0x5f, 0x5f}, "131    IndianRed         #af5f5f"}, | ||||
|     {{0xaf, 0x5f, 0x87}, "132    HotPink3          #af5f87"}, | ||||
|     {{0xaf, 0x5f, 0xaf}, "133    MediumOrchid3     #af5faf"}, | ||||
|     {{0xaf, 0x5f, 0xd7}, "134    MediumOrchid      #af5fd7"}, | ||||
|     {{0xaf, 0x5f, 0xff}, "135    MediumPurple2     #af5fff"}, | ||||
|     {{0xaf, 0x87, 0x00}, "136    DarkGoldenrod     #af8700"}, | ||||
|     {{0xaf, 0x87, 0x5f}, "137    LightSalmon3      #af875f"}, | ||||
|     {{0xaf, 0x87, 0x87}, "138    RosyBrown         #af8787"}, | ||||
|     {{0xaf, 0x87, 0xaf}, "139    Grey63            #af87af"}, | ||||
|     {{0xaf, 0x87, 0xd7}, "140    MediumPurple2     #af87d7"}, | ||||
|     {{0xaf, 0x87, 0xff}, "141    MediumPurple1     #af87ff"}, | ||||
|     {{0xaf, 0xaf, 0x00}, "142    Gold3             #afaf00"}, | ||||
|     {{0xaf, 0xaf, 0x5f}, "143    DarkKhaki         #afaf5f"}, | ||||
|     {{0xaf, 0xaf, 0x87}, "144    NavajoWhite3      #afaf87"}, | ||||
|     {{0xaf, 0xaf, 0xaf}, "145    Grey69            #afafaf"}, | ||||
|     {{0xaf, 0xaf, 0xd7}, "146    LightSteelBlue3   #afafd7"}, | ||||
|     {{0xaf, 0xaf, 0xff}, "147    LightSteelBlue    #afafff"}, | ||||
|     {{0xaf, 0xd7, 0x00}, "148    Yellow3           #afd700"}, | ||||
|     {{0xaf, 0xd7, 0x5f}, "149    DarkOliveGreen3   #afd75f"}, | ||||
|     {{0xaf, 0xd7, 0x87}, "150    DarkSeaGreen3     #afd787"}, | ||||
|     {{0xaf, 0xd7, 0xaf}, "151    DarkSeaGreen2     #afd7af"}, | ||||
|     {{0xaf, 0xd7, 0xd7}, "152    LightCyan3        #afd7d7"}, | ||||
|     {{0xaf, 0xd7, 0xff}, "153    LightSkyBlue1     #afd7ff"}, | ||||
|     {{0xaf, 0xff, 0x00}, "154    GreenYellow       #afff00"}, | ||||
|     {{0xaf, 0xff, 0x5f}, "155    DarkOliveGreen2   #afff5f"}, | ||||
|     {{0xaf, 0xff, 0x87}, "156    PaleGreen1        #afff87"}, | ||||
|     {{0xaf, 0xff, 0xaf}, "157    DarkSeaGreen2     #afffaf"}, | ||||
|     {{0xaf, 0xff, 0xd7}, "158    DarkSeaGreen1     #afffd7"}, | ||||
|     {{0xaf, 0xff, 0xff}, "159    PaleTurquoise1    #afffff"}, | ||||
|     {{0xd7, 0x00, 0x00}, "160    Red3              #d70000"}, | ||||
|     {{0xd7, 0x00, 0x5f}, "161    DeepPink3         #d7005f"}, | ||||
|     {{0xd7, 0x00, 0x87}, "162    DeepPink3         #d70087"}, | ||||
|     {{0xd7, 0x00, 0xaf}, "163    Magenta3          #d700af"}, | ||||
|     {{0xd7, 0x00, 0xd7}, "164    Magenta3          #d700d7"}, | ||||
|     {{0xd7, 0x00, 0xff}, "165    Magenta2          #d700ff"}, | ||||
|     {{0xd7, 0x5f, 0x00}, "166    DarkOrange3       #d75f00"}, | ||||
|     {{0xd7, 0x5f, 0x5f}, "167    IndianRed         #d75f5f"}, | ||||
|     {{0xd7, 0x5f, 0x87}, "168    HotPink3          #d75f87"}, | ||||
|     {{0xd7, 0x5f, 0xaf}, "169    HotPink2          #d75faf"}, | ||||
|     {{0xd7, 0x5f, 0xd7}, "170    Orchid            #d75fd7"}, | ||||
|     {{0xd7, 0x5f, 0xff}, "171    MediumOrchid1     #d75fff"}, | ||||
|     {{0xd7, 0x87, 0x00}, "172    Orange3           #d78700"}, | ||||
|     {{0xd7, 0x87, 0x5f}, "173    LightSalmon3      #d7875f"}, | ||||
|     {{0xd7, 0x87, 0x87}, "174    LightPink3        #d78787"}, | ||||
|     {{0xd7, 0x87, 0xaf}, "175    Pink3             #d787af"}, | ||||
|     {{0xd7, 0x87, 0xd7}, "176    Plum3             #d787d7"}, | ||||
|     {{0xd7, 0x87, 0xff}, "177    Violet            #d787ff"}, | ||||
|     {{0xd7, 0xaf, 0x00}, "178    Gold3             #d7af00"}, | ||||
|     {{0xd7, 0xaf, 0x5f}, "179    LightGoldenrod3   #d7af5f"}, | ||||
|     {{0xd7, 0xaf, 0x87}, "180    Tan               #d7af87"}, | ||||
|     {{0xd7, 0xaf, 0xaf}, "181    MistyRose3        #d7afaf"}, | ||||
|     {{0xd7, 0xaf, 0xd7}, "182    Thistle3          #d7afd7"}, | ||||
|     {{0xd7, 0xaf, 0xff}, "183    Plum2             #d7afff"}, | ||||
|     {{0xd7, 0xd7, 0x00}, "184    Yellow3           #d7d700"}, | ||||
|     {{0xd7, 0xd7, 0x5f}, "185    Khaki3            #d7d75f"}, | ||||
|     {{0xd7, 0xd7, 0x87}, "186    LightGoldenrod2   #d7d787"}, | ||||
|     {{0xd7, 0xd7, 0xaf}, "187    LightYellow3      #d7d7af"}, | ||||
|     {{0xd7, 0xd7, 0xd7}, "188    Grey84            #d7d7d7"}, | ||||
|     {{0xd7, 0xd7, 0xff}, "189    LightSteelBlue1   #d7d7ff"}, | ||||
|     {{0xd7, 0xff, 0x00}, "190    Yellow2           #d7ff00"}, | ||||
|     {{0xd7, 0xff, 0x5f}, "191    DarkOliveGreen1   #d7ff5f"}, | ||||
|     {{0xd7, 0xff, 0x87}, "192    DarkOliveGreen1   #d7ff87"}, | ||||
|     {{0xd7, 0xff, 0xaf}, "193    DarkSeaGreen1     #d7ffaf"}, | ||||
|     {{0xd7, 0xff, 0xd7}, "194    Honeydew2         #d7ffd7"}, | ||||
|     {{0xd7, 0xff, 0xff}, "195    LightCyan1        #d7ffff"}, | ||||
|     {{0xff, 0x00, 0x00}, "196    Red1              #ff0000"}, | ||||
|     {{0xff, 0x00, 0x5f}, "197    DeepPink2         #ff005f"}, | ||||
|     {{0xff, 0x00, 0x87}, "198    DeepPink1         #ff0087"}, | ||||
|     {{0xff, 0x00, 0xaf}, "199    DeepPink1         #ff00af"}, | ||||
|     {{0xff, 0x00, 0xd7}, "200    Magenta2          #ff00d7"}, | ||||
|     {{0xff, 0x00, 0xff}, "201    Magenta1          #ff00ff"}, | ||||
|     {{0xff, 0x5f, 0x00}, "202    OrangeRed1        #ff5f00"}, | ||||
|     {{0xff, 0x5f, 0x5f}, "203    IndianRed1        #ff5f5f"}, | ||||
|     {{0xff, 0x5f, 0x87}, "204    IndianRed1        #ff5f87"}, | ||||
|     {{0xff, 0x5f, 0xaf}, "205    HotPink           #ff5faf"}, | ||||
|     {{0xff, 0x5f, 0xd7}, "206    HotPink           #ff5fd7"}, | ||||
|     {{0xff, 0x5f, 0xff}, "207    MediumOrchid1     #ff5fff"}, | ||||
|     {{0xff, 0x87, 0x00}, "208    DarkOrange        #ff8700"}, | ||||
|     {{0xff, 0x87, 0x5f}, "209    Salmon1           #ff875f"}, | ||||
|     {{0xff, 0x87, 0x87}, "210    LightCoral        #ff8787"}, | ||||
|     {{0xff, 0x87, 0xaf}, "211    PaleVioletRed1    #ff87af"}, | ||||
|     {{0xff, 0x87, 0xd7}, "212    Orchid2           #ff87d7"}, | ||||
|     {{0xff, 0x87, 0xff}, "213    Orchid1           #ff87ff"}, | ||||
|     {{0xff, 0xaf, 0x00}, "214    Orange1           #ffaf00"}, | ||||
|     {{0xff, 0xaf, 0x5f}, "215    SandyBrown        #ffaf5f"}, | ||||
|     {{0xff, 0xaf, 0x87}, "216    LightSalmon1      #ffaf87"}, | ||||
|     {{0xff, 0xaf, 0xaf}, "217    LightPink1        #ffafaf"}, | ||||
|     {{0xff, 0xaf, 0xd7}, "218    Pink1             #ffafd7"}, | ||||
|     {{0xff, 0xaf, 0xff}, "219    Plum1             #ffafff"}, | ||||
|     {{0xff, 0xd7, 0x00}, "220    Gold1             #ffd700"}, | ||||
|     {{0xff, 0xd7, 0x5f}, "221    LightGoldenrod2   #ffd75f"}, | ||||
|     {{0xff, 0xd7, 0x87}, "222    LightGoldenrod2   #ffd787"}, | ||||
|     {{0xff, 0xd7, 0xaf}, "223    NavajoWhite1      #ffd7af"}, | ||||
|     {{0xff, 0xd7, 0xd7}, "224    MistyRose1        #ffd7d7"}, | ||||
|     {{0xff, 0xd7, 0xff}, "225    Thistle1          #ffd7ff"}, | ||||
|     {{0xff, 0xff, 0x00}, "226    Yellow1           #ffff00"}, | ||||
|     {{0xff, 0xff, 0x5f}, "227    LightGoldenrod1   #ffff5f"}, | ||||
|     {{0xff, 0xff, 0x87}, "228    Khaki1            #ffff87"}, | ||||
|     {{0xff, 0xff, 0xaf}, "229    Wheat1            #ffffaf"}, | ||||
|     {{0xff, 0xff, 0xd7}, "230    Cornsilk1         #ffffd7"}, | ||||
|     {{0xff, 0xff, 0xff}, "231    Grey100           #ffffff"}, | ||||
|     {{0x08, 0x08, 0x08}, "232    Grey3             #080808"}, | ||||
|     {{0x12, 0x12, 0x12}, "233    Grey7             #121212"}, | ||||
|     {{0x1c, 0x1c, 0x1c}, "234    Grey11            #1c1c1c"}, | ||||
|     {{0x26, 0x26, 0x26}, "235    Grey15            #262626"}, | ||||
|     {{0x30, 0x30, 0x30}, "236    Grey19            #303030"}, | ||||
|     {{0x3a, 0x3a, 0x3a}, "237    Grey23            #3a3a3a"}, | ||||
|     {{0x44, 0x44, 0x44}, "238    Grey27            #444444"}, | ||||
|     {{0x4e, 0x4e, 0x4e}, "239    Grey30            #4e4e4e"}, | ||||
|     {{0x58, 0x58, 0x58}, "240    Grey35            #585858"}, | ||||
|     {{0x62, 0x62, 0x62}, "241    Grey39            #626262"}, | ||||
|     {{0x6c, 0x6c, 0x6c}, "242    Grey42            #6c6c6c"}, | ||||
|     {{0x76, 0x76, 0x76}, "243    Grey46            #767676"}, | ||||
|     {{0x80, 0x80, 0x80}, "244    Grey50            #808080"}, | ||||
|     {{0x8a, 0x8a, 0x8a}, "245    Grey54            #8a8a8a"}, | ||||
|     {{0x94, 0x94, 0x94}, "246    Grey58            #949494"}, | ||||
|     {{0x9e, 0x9e, 0x9e}, "247    Grey62            #9e9e9e"}, | ||||
|     {{0xa8, 0xa8, 0xa8}, "248    Grey66            #a8a8a8"}, | ||||
|     {{0xb2, 0xb2, 0xb2}, "249    Grey70            #b2b2b2"}, | ||||
|     {{0xbc, 0xbc, 0xbc}, "250    Grey74            #bcbcbc"}, | ||||
|     {{0xc6, 0xc6, 0xc6}, "251    Grey78            #c6c6c6"}, | ||||
|     {{0xd0, 0xd0, 0xd0}, "252    Grey82            #d0d0d0"}, | ||||
|     {{0xda, 0xda, 0xda}, "253    Grey85            #dadada"}, | ||||
|     {{0xe4, 0xe4, 0xe4}, "254    Grey89            #e4e4e4"}, | ||||
|     {{0xee, 0xee, 0xee}, "255    Grey93            #eeeeee"}, | ||||
| }; | ||||
| 
 | ||||
| int main(int argc, char *argv[]) { | ||||
|   size_t i; | ||||
|   printf("BG FG BB BF XTERM NAME              HEX\n"); | ||||
|   for (i = 0; i < 256; ++i) { | ||||
|     printf("\e[48;5;%dm  \e[0m \e[38;5;%dm██\e[0m \e[1;48;5;%dm  " | ||||
|            "\e[0m \e[1;38;5;%dm██\e[0m %-6hhu%-18s#%02hhx%02hhx%02hhx\n", | ||||
|            i, i, i, i, i, IndexDoubleNulString(kXtermName, i), kXtermRgb[i].r, | ||||
|            kXtermRgb[i].g, kXtermRgb[i].b); | ||||
|   } | ||||
|   return 0; | ||||
| } | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue