This repository has been archived on 2022-08-10. You can view files and clone it, but cannot push or open issues or pull requests.
chez-openbsd/c/prim5.c

2053 lines
67 KiB
C
Raw Normal View History

2022-07-29 15:12:07 +02:00
/* prim5.c
* Copyright 1984-2017 Cisco Systems, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "system.h"
#include "sort.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <limits.h>
#include <ctype.h>
#include <math.h>
/* locally defined functions */
static INT s_errno(void);
static iptr s_addr_in_heap(uptr x);
static iptr s_ptr_in_heap(ptr x);
static ptr s_generation(ptr x);
static iptr s_fxmul(iptr x, iptr y);
static iptr s_fxdiv(iptr x, iptr y);
static ptr s_trunc_rem(ptr x, ptr y);
static ptr s_fltofx(ptr x);
static ptr s_weak_pairp(ptr p);
static ptr s_ephemeron_cons(ptr car, ptr cdr);
static ptr s_ephemeron_pairp(ptr p);
static ptr s_oblist(void);
static ptr s_bigoddp(ptr n);
static ptr s_float(ptr x);
static ptr s_decode_float(ptr x);
#ifdef segment_t2_bits
static void s_show_info(FILE *out);
#endif
static void s_show_chunks(FILE *out, ptr sorted_chunks);
static ptr sort_chunks(ptr ls, uptr n);
static ptr merge_chunks(ptr ls1, ptr ls2);
static ptr sorted_chunk_list(void);
static void s_showalloc(IBOOL show_dump, const char *outfn);
static ptr s_system(const char *s);
static ptr s_process(char *s, IBOOL stderrp);
static I32 s_chdir(const char *inpath);
static char *s_getwd(void);
static ptr s_set_code_byte(ptr p, ptr n, ptr x);
static ptr s_set_code_word(ptr p, ptr n, ptr x);
static ptr s_set_code_long(ptr p, ptr n, ptr x);
static void s_set_code_long2(ptr p, ptr n, ptr h, ptr l);
static ptr s_set_code_quad(ptr p, ptr n, ptr x);
static ptr s_set_reloc(ptr p, ptr n, ptr e);
static ptr s_flush_instruction_cache(void);
static ptr s_make_code(iptr flags, iptr free, ptr name, ptr arity_mark, iptr n, ptr info, ptr pinfos);
static ptr s_make_reloc_table(ptr codeobj, ptr n);
static ptr s_make_closure(ptr offset, ptr codeobj);
static ptr s_fxrandom(ptr n);
static ptr s_flrandom(ptr x);
static U32 s_random_seed(void);
static void s_set_random_seed(U32 x);
static ptr s_intern(ptr x);
static ptr s_intern2(ptr x, ptr n);
static ptr s_strings_to_gensym(ptr pname_str, ptr uname_str);
static ptr s_intern3(ptr x, ptr n, ptr m);
static ptr s_delete_file(const char *inpath);
static ptr s_delete_directory(const char *inpath);
static ptr s_rename_file(const char *inpath1, const char *inpath2);
static ptr s_mkdir(const char *inpath, INT mode);
static ptr s_chmod(const char *inpath, INT mode);
static ptr s_getmod(const char *inpath, IBOOL followp);
static ptr s_path_atime(const char *inpath, IBOOL followp);
static ptr s_path_ctime(const char *inpath, IBOOL followp);
static ptr s_path_mtime(const char *inpath, IBOOL followp);
static ptr s_fd_atime(INT fd);
static ptr s_fd_ctime(INT fd);
static ptr s_fd_mtime(INT fd);
static IBOOL s_fd_regularp(INT fd);
static void s_nanosleep(ptr sec, ptr nsec);
static ptr s_set_collect_trip_bytes(ptr n);
static void c_exit(I32 status);
static ptr s_get_reloc(ptr co);
#ifdef PTHREADS
static s_thread_rv_t s_backdoor_thread_start(void *p);
static iptr s_backdoor_thread(ptr p);
static ptr s_threads(void);
static void s_mutex_acquire(scheme_mutex_t *m);
static ptr s_mutex_acquire_noblock(scheme_mutex_t *m);
static void s_condition_broadcast(s_thread_cond_t *c);
static void s_condition_signal(s_thread_cond_t *c);
#endif
static void s_byte_copy(ptr src, iptr srcoff, ptr dst, iptr dstoff, iptr cnt);
static void s_ptr_copy(ptr src, iptr srcoff, ptr dst, iptr dstoff, iptr cnt);
static ptr s_tlv(ptr x);
static void s_stlv(ptr x, ptr v);
static void s_test_schlib(void);
static void s_breakhere(ptr x);
static IBOOL s_interactivep(void);
static IBOOL s_same_devicep(INT fd1, INT fd2);
static uptr s_malloc(iptr n);
static void s_free(uptr n);
#ifdef FEATURE_ICONV
static ptr s_iconv_open(const char *tocode, const char *fromcode);
static void s_iconv_close(uptr cd);
static ptr s_iconv_from_string(uptr cd, ptr in, uptr i, uptr iend, ptr out, uptr o, uptr oend);
static ptr s_iconv_to_string(uptr cd, ptr in, uptr i, uptr iend, ptr out, uptr o, uptr oend);
#endif
#ifdef WIN32
static ptr s_multibytetowidechar(unsigned cp, ptr inbv);
static ptr s_widechartomultibyte(unsigned cp, ptr inbv);
#endif
static ptr s_profile_counters(void);
static ptr s_profile_release_counters(void);
#define require(test,who,msg,arg) if (!(test)) S_error1(who, msg, arg)
ptr S_strerror(INT errnum) {
ptr p; char *msg;
tc_mutex_acquire()
#ifdef WIN32
msg = Swide_to_utf8(_wcserror(errnum));
if (msg == NULL)
p = Sfalse;
else {
p = Sstring_utf8(msg, -1);
free(msg);
}
#else
p = (msg = strerror(errnum)) == NULL ? Sfalse : Sstring_utf8(msg, -1);
#endif
tc_mutex_release()
return p;
}
static INT s_errno(void) {
return errno;
}
static iptr s_addr_in_heap(uptr x) {
return MaybeSegInfo(addr_get_segment(x)) != NULL;
}
static iptr s_ptr_in_heap(ptr x) {
return MaybeSegInfo(ptr_get_segment(x)) != NULL;
}
static ptr s_generation(ptr x) {
seginfo *si = MaybeSegInfo(ptr_get_segment(x));
return si == NULL ? Sfalse : FIX(si->generation);
}
static iptr s_fxmul(iptr x, iptr y) {
return x * y;
}
static iptr s_fxdiv(iptr x, iptr y) {
return x / y;
}
static ptr s_trunc_rem(ptr x, ptr y) {
ptr q, r;
S_trunc_rem(get_thread_context(), x, y, &q, &r);
return Scons(q, r);
}
static ptr s_fltofx(ptr x) {
return FIX((iptr)FLODAT(x));
}
static ptr s_weak_pairp(ptr p) {
seginfo *si;
return Spairp(p) && (si = MaybeSegInfo(ptr_get_segment(p))) != NULL && (si->space & ~space_locked) == space_weakpair ? Strue : Sfalse;
}
static ptr s_ephemeron_cons(ptr car, ptr cdr) {
ptr p;
tc_mutex_acquire()
p = S_cons_in(space_ephemeron, 0, car, cdr);
tc_mutex_release()
return p;
}
static ptr s_ephemeron_pairp(ptr p) {
seginfo *si;
return Spairp(p) && (si = MaybeSegInfo(ptr_get_segment(p))) != NULL && (si->space & ~space_locked) == space_ephemeron ? Strue : Sfalse;
}
static ptr s_oblist(void) {
ptr ls = Snil;
iptr idx = S_G.oblist_length;
bucket *b;
while (idx-- != 0) {
for (b = S_G.oblist[idx]; b != NULL; b = b->next) {
ls = Scons(b->sym, ls);
}
}
return ls;
}
static ptr s_bigoddp(ptr n) {
return Sboolean(BIGIT(n, BIGLEN(n) - 1) & 1); /* last bigit */;
}
static ptr s_float(ptr x) {
return Sflonum(S_floatify(x));
}
static ptr s_decode_float(ptr x) {
require(Sflonump(x),"decode-float","~s is not a float",x);
return S_decode_float(FLODAT(x));
}
#define FMTBUFSIZE 120
#define CHUNKADDRLT(x, y) (((chunkinfo *)(Scar(x)))->addr < ((chunkinfo *)(Scar(y)))->addr)
mkmergesort(sort_chunks, merge_chunks, ptr, Snil, CHUNKADDRLT, INITCDR)
static ptr sorted_chunk_list(void) {
chunkinfo *chunk; INT i, n = 0; ptr ls = Snil;
for (i = PARTIAL_CHUNK_POOLS; i >= -1; i -= 1) {
for (chunk = (i == -1) ? S_chunks_full : S_chunks[i]; chunk != NULL; chunk = chunk->next) {
ls = Scons(chunk, ls);
n += 1;
}
}
return sort_chunks(ls, n);
}
#ifdef segment_t2_bits
static void s_show_info(FILE *out) {
void *max_addr = 0;
INT addrwidth;
const char *addrtitle = "address";
char fmtbuf[FMTBUFSIZE];
uptr i2;
#ifdef segment_t3_bits
INT byteswidth;
uptr i3;
for (i3 = 0; i3 < SEGMENT_T3_SIZE; i3 += 1) {
t2table *t2t = S_segment_info[i3];
if (t2t != NULL) {
if ((void *)t2t > max_addr) max_addr = (void *)t2t;
for (i2 = 0; i2 < SEGMENT_T2_SIZE; i2 += 1) {
t1table *t1t = t2t->t2[i2];
if (t1t != NULL) {
if ((void *)t1t > max_addr) max_addr = (void *)t1t;
}
}
}
}
addrwidth = snprintf(fmtbuf, FMTBUFSIZE, "%#tx", (ptrdiff_t)max_addr);
if (addrwidth < (INT)strlen(addrtitle)) addrwidth = (INT)strlen(addrtitle);
byteswidth = snprintf(fmtbuf, FMTBUFSIZE, "%#tx", (ptrdiff_t)(sizeof(t1table) > sizeof(t2table) ? sizeof(t1table) : sizeof(t2table)));
snprintf(fmtbuf, FMTBUFSIZE, "%%s %%-%ds %%-%ds\n\n", addrwidth, byteswidth);
fprintf(out, fmtbuf, "level", addrtitle, "bytes");
snprintf(fmtbuf, FMTBUFSIZE, "%%-5d %%#0%dtx %%#0%dtx\n", addrwidth, byteswidth);
for (i3 = 0; i3 < SEGMENT_T3_SIZE; i3 += 1) {
t2table *t2t = S_segment_info[i3];
if (t2t != NULL) {
fprintf(out, fmtbuf, 2, t2t, sizeof(t2table));
for (i2 = 0; i2 < SEGMENT_T2_SIZE; i2 += 1) {
t1table *t1t = t2t->t2[i2];
if (t1t != NULL) {
fprintf(out, fmtbuf, 1, (ptrdiff_t)t1t, (ptrdiff_t)sizeof(t1table));
}
}
}
}
#else
for (i2 = 0; i2 < SEGMENT_T2_SIZE; i2 += 1) {
t1table *t1t = S_segment_info[i2];
if (t1t != NULL) {
if ((void *)t1t > max_addr) max_addr = (void *)t1t;
}
}
addrwidth = 1 + snprintf(fmtbuf, FMTBUFSIZE, "%#tx", (ptrdiff_t)max_addr);
if (addrwidth < (INT)strlen(addrtitle) + 1) addrwidth = (INT)strlen(addrtitle) + 1;
snprintf(fmtbuf, FMTBUFSIZE, "%%s %%-%ds %%s\n\n", addrwidth);
fprintf(out, fmtbuf, "level", addrtitle, "bytes");
snprintf(fmtbuf, FMTBUFSIZE, "%%-5d %%#0%dtx %%#tx\n", (ptrdiff_t)addrwidth);
for (i2 = 0; i2 < SEGMENT_T2_SIZE; i2 += 1) {
t1table *t1t = S_segment_info[i2];
if (t1t != NULL) {
fprintf(out, fmtbuf, 1, (ptrdiff_t)t1t, (ptrdiff_t)sizeof(t1table));
}
}
#endif
}
#endif
static void s_show_chunks(FILE *out, ptr sorted_chunks) {
char fmtbuf[FMTBUFSIZE];
chunkinfo *chunk;
void *max_addr = 0;
void *max_header_addr = 0;
iptr max_segs = 0;
INT addrwidth, byteswidth, headeraddrwidth, headerbyteswidth, segswidth, headerwidth;
const char *addrtitle = "address", *bytestitle = "bytes", *headertitle = "(+ header)";
ptr ls;
for (ls = sorted_chunks; ls != Snil; ls = Scdr(ls)) {
chunk = Scar(ls);
max_addr = chunk->addr;
if (chunk->segs > max_segs) max_segs = chunk->segs;
if ((void *)chunk > max_header_addr) max_header_addr = (void *)chunk;
}
addrwidth = (INT)snprintf(fmtbuf, FMTBUFSIZE, "%#tx", (ptrdiff_t)max_addr);
if (addrwidth < (INT)strlen(addrtitle)) addrwidth = (INT)strlen(addrtitle);
byteswidth = (INT)snprintf(fmtbuf, FMTBUFSIZE, "%#tx", (ptrdiff_t)(max_segs * bytes_per_segment));
if (byteswidth < (INT)strlen(bytestitle)) byteswidth = (INT)strlen(bytestitle);
headerbyteswidth = (INT)snprintf(fmtbuf, FMTBUFSIZE, "%#tx", (ptrdiff_t)(sizeof(chunkinfo) + sizeof(seginfo) * max_segs));
headeraddrwidth = (INT)snprintf(fmtbuf, FMTBUFSIZE, "%#tx", (ptrdiff_t)max_header_addr);
segswidth = (INT)snprintf(fmtbuf, FMTBUFSIZE, "%td", (ptrdiff_t)max_segs);
headerwidth = headerbyteswidth + headeraddrwidth + 13;
snprintf(fmtbuf, FMTBUFSIZE, "%%-%ds %%-%ds %%-%ds %%s\n\n", addrwidth, byteswidth, headerwidth);
fprintf(out, fmtbuf, addrtitle, bytestitle, headertitle, "segments used");
snprintf(fmtbuf, FMTBUFSIZE, "%%#0%dtx %%#0%dtx (+ %%#0%dtx bytes @ %%#0%dtx) %%%dtd of %%%dtd\n",
addrwidth, byteswidth, headerbyteswidth, headeraddrwidth, segswidth, segswidth);
for (ls = sorted_chunks; ls != Snil; ls = Scdr(ls)) {
chunk = Scar(ls);
fprintf(out, fmtbuf, (ptrdiff_t)chunk->addr, (ptrdiff_t)chunk->bytes,
(ptrdiff_t)(sizeof(chunkinfo) + sizeof(seginfo) * chunk->segs),
(ptrdiff_t)chunk, (ptrdiff_t)chunk->nused_segs, (ptrdiff_t)chunk->segs);
}
}
#define space_bogus (max_space + 1)
#define space_total (space_bogus + 1)
#define generation_total (static_generation + 1)
#define INCRGEN(g) (g = g == S_G.max_nonstatic_generation ? static_generation : g+1)
static void s_showalloc(IBOOL show_dump, const char *outfn) {
FILE *out;
iptr count[generation_total+1][space_total+1];
uptr bytes[generation_total+1][space_total+1];
int i, column_size[generation_total+1];
char fmtbuf[FMTBUFSIZE];
static char *spacename[space_total+1] = { alloc_space_names, "bogus", "total" };
static char spacechar[space_total+1] = { alloc_space_chars, '?', 't' };
chunkinfo *chunk; seginfo *si; ISPC s; IGEN g;
ptr sorted_chunks;
tc_mutex_acquire()
if (outfn == NULL) {
out = stderr;
} else {
#ifdef WIN32
wchar_t *outfnw = Sutf8_to_wide(outfn);
out = _wfopen(outfnw, L"w");
free(outfnw);
#else
out = fopen(outfn, "w");
#endif
if (out == NULL) {
ptr msg = S_strerror(errno);
if (msg != Sfalse) {
tc_mutex_release()
S_error2("fopen", "open of ~s failed: ~a", Sstring_utf8(outfn, -1), msg);
} else {
tc_mutex_release()
S_error1("fopen", "open of ~s failed", Sstring_utf8(outfn, -1));
}
}
}
for (g = 0; g <= generation_total; INCRGEN(g))
for (s = 0; s <= space_total; s++)
count[g][s] = bytes[g][s] = 0;
for (g = 0; g <= static_generation; INCRGEN(g)) {
for (s = 0; s <= max_real_space; s++) {
/* add in bytes previously recorded */
bytes[g][s] += S_G.bytes_of_space[g][s];
/* add in bytes in active segments */
if (S_G.next_loc[g][s] != FIX(0))
bytes[g][s] += (char *)S_G.next_loc[g][s] - (char *)S_G.base_loc[g][s];
}
}
for (g = 0; g <= static_generation; INCRGEN(g)) {
for (s = 0; s <= max_real_space; s++) {
for (si = S_G.occupied_segments[g][s]; si != NULL; si = si->next) {
count[g][s] += 1;
}
}
}
for (g = 0; g < generation_total; INCRGEN(g)) {
for (s = 0; s < space_total; s++) {
count[g][space_total] += count[g][s];
count[generation_total][s] += count[g][s];
count[generation_total][space_total] += count[g][s];
bytes[g][space_total] += bytes[g][s];
bytes[generation_total][s] += bytes[g][s];
bytes[generation_total][space_total] += bytes[g][s];
}
}
for (g = 0; g <= generation_total; INCRGEN(g)) {
if (count[g][space_total] != 0) {
int n = 1 + snprintf(fmtbuf, FMTBUFSIZE, "%td", (ptrdiff_t)count[g][space_total]);
column_size[g] = n < 8 ? 8 : n;
}
}
fprintf(out, "Segments per space & generation:\n\n");
fprintf(out, "%8s", "");
for (g = 0; g <= generation_total; INCRGEN(g)) {
if (count[g][space_total] != 0) {
if (g == generation_total) {
/* coverity[uninit_use] */
snprintf(fmtbuf, FMTBUFSIZE, "%%%ds", column_size[g]);
fprintf(out, fmtbuf, "total");
} else if (g == static_generation) {
/* coverity[uninit_use] */
snprintf(fmtbuf, FMTBUFSIZE, "%%%ds", column_size[g]);
fprintf(out, fmtbuf, "static");
} else {
/* coverity[uninit_use] */
snprintf(fmtbuf, FMTBUFSIZE, "%%%dd", column_size[g]);
fprintf(out, fmtbuf, g);
}
}
}
fprintf(out, "\n");
for (s = 0; s <= space_total; s++) {
if (s != space_empty) {
if (count[generation_total][s] != 0) {
fprintf(out, "%7s:", spacename[s]);
for (g = 0; g <= generation_total; INCRGEN(g)) {
if (count[g][space_total] != 0) {
/* coverity[uninit_use] */
snprintf(fmtbuf, FMTBUFSIZE, "%%%dtd", column_size[g]);
fprintf(out, fmtbuf, (ptrdiff_t)(count[g][s]));
}
}
fprintf(out, "\n");
fprintf(out, "%8s", "");
for (g = 0; g <= generation_total; INCRGEN(g)) {
if (count[g][space_total] != 0) {
if (count[g][s] != 0 && s <= max_real_space) {
/* coverity[uninit_use] */
snprintf(fmtbuf, FMTBUFSIZE, "%%%dd%%%%", column_size[g] - 1);
fprintf(out, fmtbuf,
(int)(((double)bytes[g][s] /
((double)count[g][s] * bytes_per_segment)) * 100.0));
} else {
/* coverity[uninit_use] */
snprintf(fmtbuf, FMTBUFSIZE, "%%%ds", column_size[g]);
fprintf(out, fmtbuf, "");
}
}
}
fprintf(out, "\n");
}
}
}
fprintf(out, "segment size = %#tx bytes. percentages show the portion actually occupied.\n", (ptrdiff_t)bytes_per_segment);
fprintf(out, "%td segments are presently reserved for future allocation or collection.\n", (ptrdiff_t)S_G.number_of_empty_segments);
fprintf(out, "\nMemory chunks obtained and not returned to the O/S:\n\n");
sorted_chunks = sorted_chunk_list();
s_show_chunks(out, sorted_chunks);
#ifdef segment_t2_bits
fprintf(out, "\nDynamic memory occupied by segment info table:\n\n");
s_show_info(out);
#endif
fprintf(out, "\nAdditional memory might be used by C libraries and programs in the\nsame address space.\n");
if (show_dump) {
iptr max_seg = 0;
int segwidth, segsperline;
iptr next_base = 0;
int segsprinted = 0;
char spaceline[100], genline[100];
ptr ls;
for (ls = sorted_chunks; ls != Snil; ls = Scdr(ls)) {
iptr last_seg;
chunk = Scar(ls);
last_seg = chunk->base + chunk->segs;
if (last_seg > max_seg) max_seg = last_seg;
}
segwidth = snprintf(fmtbuf, FMTBUFSIZE, "%#tx ", (ptrdiff_t)max_seg);
segsperline = (99 - segwidth) & ~0xf;
snprintf(fmtbuf, FMTBUFSIZE, " %%-%ds", segwidth);
snprintf(genline, 100, fmtbuf, "");
fprintf(out, "\nMap of occupied segments:\n");
for (ls = sorted_chunks; ls != Snil; ls = Scdr(ls)) {
seginfo *si; ISPC real_s;
chunk = Scar(ls);
if (chunk->base != next_base && segsprinted != 0) {
for (;;) {
if (segsprinted == segsperline) {
fprintf(out, "\n%s", spaceline);
fprintf(out, "\n%s", genline);
break;
}
if (next_base == chunk->base) break;
spaceline[segwidth+segsprinted] = ' ';
genline[segwidth+segsprinted] = ' ';
segsprinted += 1;
next_base += 1;
}
}
if (chunk->base > next_base && next_base != 0) {
fprintf(out, "\n-------- skipping %td segments --------", (ptrdiff_t)(chunk->base - next_base));
}
for (i = 0; i < chunk->segs; i += 1) {
if (segsprinted >= segsperline) segsprinted = 0;
if (segsprinted == 0) {
if (i != 0) {
fprintf(out, "\n%s", spaceline);
fprintf(out, "\n%s", genline);
}
snprintf(fmtbuf, FMTBUFSIZE, "%%#0%dtx ", segwidth - 1);
snprintf(spaceline, 100, fmtbuf, (ptrdiff_t)(chunk->base + i));
segsprinted = 0;
}
si = &chunk->sis[i];
real_s = si->space;
s = real_s & ~(space_locked | space_old);
if (s < 0 || s > max_space) s = space_bogus;
spaceline[segwidth+segsprinted] =
real_s & (space_locked | space_old) ? toupper(spacechar[s]) : spacechar[s];
g = si->generation;
genline[segwidth+segsprinted] =
(s == space_empty) ? '.' :
(g < 10) ? '0' + g :
(g < 36) ? 'A' + g - 10 :
(g == static_generation) ? '*' : '+';
segsprinted += 1;
}
next_base = chunk->base + chunk->segs;
}
if (segsprinted != 0) {
spaceline[segwidth+segsprinted] = 0;
genline[segwidth+segsprinted] = 0;
fprintf(out, "\n%s", spaceline);
fprintf(out, "\n%s", genline);
}
fprintf(out, "\n\nSpaces:");
for (s = 0; s < space_total; s += 1)
fprintf(out, "%s%c = %s", s % 5 == 0 ? "\n " : "\t",
spacechar[s], spacename[s]);
fprintf(out, "\n\nGenerations:\n 0-9: 0<=g<=9; A-Z: 10<=g<=35; +: g>=36; *: g=static; .: empty\n\n");
}
if (outfn == NULL) {
fflush(out);
} else {
fclose(out);
}
tc_mutex_release()
}
#include <signal.h>
#ifdef WIN32
#include <io.h>
#include <process.h>
#include <fcntl.h>
#include <direct.h>
#include <malloc.h>
#else /* WIN32 */
#include <sys/param.h>
#include <sys/wait.h>
#endif /* WIN32 */
static ptr s_system(const char *s) {
INT status;
#ifdef PTHREADS
ptr tc = get_thread_context();
#endif
#ifdef PTHREADS
if (DISABLECOUNT(tc) == FIX(0)) deactivate_thread(tc);
#endif
status = SYSTEM(s);
#ifdef PTHREADS
if (DISABLECOUNT(tc) == FIX(0)) reactivate_thread(tc);
#endif
if ((status == -1) && (errno != 0)) {
ptr msg = S_strerror(errno);
if (msg != Sfalse)
S_error1("system", "~a", msg);
else
S_error("system", "subprocess execution failed");
}
#ifdef WIN32
return Sinteger(status);
#else
if WIFEXITED(status) return Sinteger(WEXITSTATUS(status));
if WIFSIGNALED(status) return Sinteger(-WTERMSIG(status));
S_error("system", "cannot determine subprocess exit status");
return 0 /* not reached */;
#endif /* WIN32 */
}
static ptr s_process(char *s, IBOOL stderrp) {
INT ifd = -1, ofd = -1, efd = -1, child = -1;
#ifdef WIN32
HANDLE hToRead, hToWrite, hFromRead, hFromWrite, hFromReadErr, hFromWriteErr, hProcess;
STARTUPINFOW si = {0};
PROCESS_INFORMATION pi;
char *comspec;
char *buffer;
wchar_t* bufferw;
/* Create non-inheritable pipes, important to eliminate zombee children
* when the parent sides are closed. */
if (!CreatePipe(&hToRead, &hToWrite, NULL, 0))
S_error("process", "cannot open pipes");
if (!CreatePipe(&hFromRead, &hFromWrite, NULL, 0)) {
CloseHandle(hToRead);
CloseHandle(hToWrite);
S_error("process", "cannot open pipes");
}
if (stderrp && !CreatePipe(&hFromReadErr, &hFromWriteErr, NULL, 0)) {
CloseHandle(hToRead);
CloseHandle(hToWrite);
CloseHandle(hFromRead);
CloseHandle(hFromWrite);
S_error("process", "cannot open pipes");
}
si.cb = sizeof(STARTUPINFO);
si.dwFlags = STARTF_USESTDHANDLES;
hProcess = GetCurrentProcess();
/* Duplicate the ToRead handle so that the child can inherit it. */
if (!DuplicateHandle(hProcess, hToRead, hProcess, &si.hStdInput,
GENERIC_READ, TRUE, 0)) {
CloseHandle(hToRead);
CloseHandle(hToWrite);
CloseHandle(hFromRead);
CloseHandle(hFromWrite);
if (stderrp) {
CloseHandle(hFromReadErr);
CloseHandle(hFromWriteErr);
}
S_error("process", "cannot open pipes");
}
CloseHandle(hToRead);
/* Duplicate the FromWrite handle so that the child can inherit it. */
if (!DuplicateHandle(hProcess, hFromWrite, hProcess, &si.hStdOutput,
GENERIC_WRITE, TRUE, 0)) {
CloseHandle(si.hStdInput);
CloseHandle(hToWrite);
CloseHandle(hFromRead);
CloseHandle(hFromWrite);
if (stderrp) {
CloseHandle(hFromReadErr);
CloseHandle(hFromWriteErr);
}
S_error("process", "cannot open pipes");
}
CloseHandle(hFromWrite);
if (stderrp) {
/* Duplicate the FromWrite handle so that the child can inherit it. */
if (!DuplicateHandle(hProcess, hFromWriteErr, hProcess, &si.hStdError,
GENERIC_WRITE, TRUE, 0)) {
CloseHandle(si.hStdInput);
CloseHandle(hToWrite);
CloseHandle(hFromRead);
CloseHandle(hFromWrite);
CloseHandle(hFromReadErr);
CloseHandle(hFromWriteErr);
S_error("process", "cannot open pipes");
}
CloseHandle(hFromWriteErr);
} else {
si.hStdError = si.hStdOutput;
}
if ((comspec = Sgetenv("COMSPEC"))) {
size_t n = strlen(comspec) + strlen(s) + 7;
buffer = (char *)_alloca(n);
snprintf(buffer, n, "\"%s\" /c %s", comspec, s);
free(comspec);
} else
buffer = s;
bufferw = Sutf8_to_wide(buffer);
if (!CreateProcessW(NULL, bufferw, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi)) {
free(bufferw);
CloseHandle(si.hStdInput);
CloseHandle(hToWrite);
CloseHandle(hFromRead);
CloseHandle(si.hStdOutput);
if (stderrp) {
CloseHandle(hFromReadErr);
CloseHandle(si.hStdError);
}
S_error("process", "cannot spawn subprocess");
}
free(bufferw);
CloseHandle(si.hStdInput);
CloseHandle(si.hStdOutput);
if (stderrp) {
CloseHandle(si.hStdError);
}
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
ifd = _open_osfhandle((intptr_t)hFromRead, 0);
ofd = _open_osfhandle((intptr_t)hToWrite, 0);
if (stderrp) {
efd = _open_osfhandle((intptr_t)hFromReadErr, 0);
}
child = pi.dwProcessId;
#else /* WIN32 */
INT tofds[2], fromfds[2], errfds[2];
struct sigaction act, oint_act;
if (pipe(tofds)) S_error("process","cannot open pipes");
if (pipe(fromfds)) {
CLOSE(tofds[0]); CLOSE(tofds[1]);
S_error("process","cannot open pipes");
}
if (stderrp) {
if (pipe(errfds)) {
CLOSE(tofds[0]); CLOSE(tofds[1]);
CLOSE(fromfds[0]); CLOSE(fromfds[1]);
S_error("process","cannot open pipes");
}
}
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
act.sa_handler = SIG_IGN;
sigaction(SIGINT, &act, &oint_act);
if ((child = fork()) == 0) {
/* child does this: */
CLOSE(0); if (dup(tofds[0]) != 0) _exit(1);
CLOSE(1); if (dup(fromfds[1]) != 1) _exit(1);
CLOSE(2); if (dup(stderrp ? errfds[1] : 1) != 2) _exit(1);
{INT i; for (i = 3; i < NOFILE; i++) (void)CLOSE(i);}
execl("/bin/sh", "/bin/sh", "-c", s, NULL);
_exit(1) /* only if execl fails */;
/*NOTREACHED*/
} else {
/* parent does this: */
CLOSE(tofds[0]); CLOSE(fromfds[1]); if (stderrp) CLOSE(errfds[1]);
if (child < 0) {
CLOSE(tofds[1]); CLOSE(fromfds[0]); if (stderrp) CLOSE(errfds[0]);
sigaction(SIGINT, &oint_act, (struct sigaction *)0);
S_error("process", "cannot fork subprocess");
/*NOTREACHED*/
} else {
ifd = fromfds[0];
ofd = tofds[1];
if (stderrp) efd = errfds[0];
sigaction(SIGINT, &oint_act, (struct sigaction *)0);
S_register_child_process(child);
}
}
#endif /* WIN32 */
if (stderrp)
return LIST4(FIX(ifd), FIX(efd), FIX(ofd), FIX(child));
else
return LIST3(FIX(ifd), FIX(ofd), FIX(child));
}
static I32 s_chdir(const char *inpath) {
char *path;
I32 status;
path = S_malloc_pathname(inpath);
#ifdef EINTR
while ((status = CHDIR(path)) != 0 && errno == EINTR) ;
#else /* EINTR */
status = CHDIR(path);
#endif /* EINTR */
free(path);
return status;
}
#ifdef GETWD
static char *s_getwd() {
return GETWD((char *)&BVIT(S_bytevector(PATH_MAX), 0));
}
#endif /* GETWD */
static ptr s_set_code_byte(ptr p, ptr n, ptr x) {
I8 *a;
a = (I8 *)((uptr)p + UNFIX(n));
*a = (I8)UNFIX(x);
return Svoid;
}
static ptr s_set_code_word(ptr p, ptr n, ptr x) {
I16 *a;
a = (I16 *)((uptr)p + UNFIX(n));
*a = (I16)UNFIX(x);
return Svoid;
}
static ptr s_set_code_long(ptr p, ptr n, ptr x) {
I32 *a;
a = (I32 *)((uptr)p + UNFIX(n));
*a = (I32)(Sfixnump(x) ? UNFIX(x) : Sinteger_value(x));
return Svoid;
}
static void s_set_code_long2(ptr p, ptr n, ptr h, ptr l) {
I32 *a;
a = (I32 *)((uptr)p + UNFIX(n));
*a = (I32)((UNFIX(h) << 16) + UNFIX(l));
}
static ptr s_set_code_quad(ptr p, ptr n, ptr x) {
I64 *a;
a = (I64 *)((uptr)p + UNFIX(n));
*a = Sfixnump(x) ? UNFIX(x) : S_int64_value("\\#set-code-quad!", x);
return Svoid;
}
static ptr s_set_reloc(ptr p, ptr n, ptr e) {
iptr *a;
a = (iptr *)(&RELOCIT(CODERELOC(p), UNFIX(n)));
*a = Sfixnump(e) ? UNFIX(e) : Sinteger_value(e);
return e;
}
static ptr s_flush_instruction_cache(void) {
tc_mutex_acquire()
S_flush_instruction_cache(get_thread_context());
tc_mutex_release()
return Svoid;
}
static ptr s_make_code(flags, free, name, arity_mark, n, info, pinfos)
iptr flags, free, n; ptr name, arity_mark, info, pinfos; {
ptr co;
tc_mutex_acquire()
co = S_code(get_thread_context(), type_code | (flags << code_flags_offset), n);
tc_mutex_release()
CODEFREE(co) = free;
CODENAME(co) = name;
CODEARITYMASK(co) = arity_mark;
CODEINFO(co) = info;
CODEPINFOS(co) = pinfos;
if (pinfos != Snil) {
S_G.profile_counters = Scons(S_weak_cons(co, pinfos), S_G.profile_counters);
}
return co;
}
static ptr s_make_reloc_table(ptr codeobj, ptr n) {
CODERELOC(codeobj) = S_relocation_table(UNFIX(n));
RELOCCODE(CODERELOC(codeobj)) = codeobj;
return Svoid;
}
static ptr s_make_closure(ptr offset, ptr codeobj) {
return S_closure((ptr)((iptr)codeobj + UNFIX(offset)), 0);
}
/* the random formula is based on Knuth. It returns a random fixnum
* between 0 and n-1.
*/
static ptr s_fxrandom(ptr p) {
ptr tc = get_thread_context();
uptr t, n = UNFIX(p);
t = (RANDOMSEED(tc) = RANDOMSEED(tc) * 72931 + 90763387) >> 16;
t = t | ((RANDOMSEED(tc) = RANDOMSEED(tc) * 72931 + 90763387) & 0xffff0000);
if (n <= 0xffffffff) /* trivially true if sizeof(ptr) <= sizeof(U32) */
return FIX(t % n);
else {
t = (t << 16) | ((RANDOMSEED(tc) = RANDOMSEED(tc) * 72931 + 90763387) >> 16);
t = (t << 16) | ((RANDOMSEED(tc) = RANDOMSEED(tc) * 72931 + 90763387) >> 16);
return FIX(t % n);
}
}
static ptr s_flrandom(ptr x) {
ptr tc = get_thread_context();
U32 t1, t2, t3, t4;
t1 = RANDOMSEED(tc) = RANDOMSEED(tc) * 72931 + 90763387;
t2 = RANDOMSEED(tc) = RANDOMSEED(tc) * 72931 + 90763387;
t3 = RANDOMSEED(tc) = RANDOMSEED(tc) * 72931 + 90763387;
t4 = RANDOMSEED(tc) = RANDOMSEED(tc) * 72931 + 90763387;
return Sflonum(S_random_double(t1, t2, t3, t4, FLODAT(x)));
}
static U32 s_random_seed() {
ptr tc = get_thread_context();
return RANDOMSEED(tc);
}
static void s_set_random_seed(U32 x) {
ptr tc = get_thread_context();
RANDOMSEED(tc) = x;
}
static ptr s_intern(ptr x) {
require(Sstringp(x),"string->symbol","~s is not a string",x);
return S_intern_sc(&STRIT(x, 0), Sstring_length(x), x);
}
static ptr s_intern2(ptr x, ptr n) {
return S_intern_sc(&STRIT(x, 0), UNFIX(n), Sfalse);
}
/* first n chars str are pretty name; remaining m-n are unique name */
static ptr s_intern3(ptr x, ptr n, ptr m) {
iptr plen = UNFIX(n);
return S_intern3(&STRIT(x, 0), plen, &STRIT(x, plen), UNFIX(m) - plen, Sfalse, Sfalse);
}
static ptr s_strings_to_gensym(ptr pname_str, ptr uname_str) {
return S_intern3(&STRIT(pname_str, 0), Sstring_length(pname_str),
&STRIT(uname_str, 0), Sstring_length(uname_str),
pname_str, uname_str);
}
static ptr s_mkdir(const char *inpath, INT mode) {
INT status; ptr res; char *path;
path = S_malloc_pathname(inpath);
#ifdef WIN32
status = S_windows_mkdir(path);
#else /* WIN32 */
status = mkdir(path, mode);
#endif /* WIN32 */
res = status == 0 ? Strue : S_strerror(errno);
free(path);
return res;
}
static ptr s_delete_file(const char *inpath) {
ptr res; char *path;
path = S_malloc_pathname(inpath);
res = UNLINK(path) == 0 ? Strue : S_strerror(errno);
free(path);
return res;
}
static ptr s_delete_directory(const char *inpath) {
ptr res; char *path;
path = S_malloc_pathname(inpath);
res = RMDIR(path) == 0 ? Strue : S_strerror(errno);
free(path);
return res;
}
static ptr s_rename_file(const char *inpath1, const char *inpath2) {
ptr res; char *path1, *path2;
path1 = S_malloc_pathname(inpath1);
path2 = S_malloc_pathname(inpath2);
res = RENAME(path1, path2) == 0 ? Strue : S_strerror(errno);
free(path1);
free(path2);
return res;
}
static ptr s_chmod(const char *inpath, INT mode) {
ptr res; INT status; char *path;
path = S_malloc_pathname(inpath);
#ifdef WIN32
/* pathetic approximation: (a) only handles user permissions, (b) doesn't
handle execute permissions, (c) windows won't make file not readable */
status = CHMOD(path,
(mode & 0400 ? S_IREAD : 0) |
(mode & 0200 ? S_IWRITE : 0));
#else /* WIN32 */
status = CHMOD(path, mode);
#endif /* WIN32 */
res = status == 0 ? Strue : S_strerror(errno);
free(path);
return res;
}
static ptr s_getmod(const char *inpath, IBOOL followp) {
ptr res; char *path; struct STATBUF statbuf;
path = S_malloc_pathname(inpath);
/* according to msdn, user read/write bits are set according to the file's
permission mode, and user execute bits are set according to the
filename extension. it says nothing about group and other execute bits. */
if ((followp ? STAT(path, &statbuf) : LSTAT(path, &statbuf)) != 0) {
res = S_strerror(errno);
} else {
res = FIX(statbuf.st_mode & 07777);
}
free(path);
return res;
}
static ptr s_path_atime(const char *inpath, IBOOL followp) {
#ifdef WIN32
ptr res;
wchar_t *wpath;
WIN32_FILE_ATTRIBUTE_DATA filedata;
__int64 total, sec; int nsec;
if ((wpath = S_malloc_wide_pathname(inpath)) == NULL) {
res = S_LastErrorString();
} else if (!GetFileAttributesExW(wpath, GetFileExInfoStandard, &filedata)) {
DWORD err = GetLastError();
res = err == ERROR_FILE_NOT_FOUND || err == ERROR_PATH_NOT_FOUND ?
Sstring("no such file or directory") :
S_LastErrorString();
} else {
total = filedata.ftLastAccessTime.dwHighDateTime;
total <<= 32;
total |= filedata.ftLastAccessTime.dwLowDateTime;
sec = total / 10000000 - 11644473600L;
nsec = (total % 10000000) * 100;
res = Scons(Sinteger64(sec), Sinteger32(nsec));
}
free(wpath);
return res;
#else /* WIN32 */
ptr res;
char *path;
struct STATBUF statbuf;
path = S_malloc_pathname(inpath);
if ((followp ? STAT(path, &statbuf) : LSTAT(path, &statbuf)) != 0) {
res = S_strerror(errno);
} else {
res = Scons(Sinteger64(SECATIME(statbuf)), Sinteger32(NSECATIME(statbuf)));
}
free(path);
return res;
#endif /* WIN32 */
}
static ptr s_path_ctime(const char *inpath, IBOOL followp) {
#ifdef WIN32
ptr res;
wchar_t *wpath;
WIN32_FILE_ATTRIBUTE_DATA filedata;
__int64 total, sec; int nsec;
if ((wpath = S_malloc_wide_pathname(inpath)) == NULL) {
res = S_LastErrorString();
} else if (!GetFileAttributesExW(wpath, GetFileExInfoStandard, &filedata)) {
DWORD err = GetLastError();
res = err == ERROR_FILE_NOT_FOUND || err == ERROR_PATH_NOT_FOUND ?
Sstring("no such file or directory") :
S_LastErrorString();
} else {
total = filedata.ftLastWriteTime.dwHighDateTime;
total <<= 32;
total |= filedata.ftLastWriteTime.dwLowDateTime;
sec = total / 10000000 - 11644473600L;
nsec = (total % 10000000) * 100;
res = Scons(Sinteger64(sec), Sinteger32(nsec));
}
free(wpath);
return res;
#else /* WIN32 */
ptr res;
char *path;
struct STATBUF statbuf;
path = S_malloc_pathname(inpath);
if ((followp ? STAT(path, &statbuf) : LSTAT(path, &statbuf)) != 0) {
res = S_strerror(errno);
} else {
res = Scons(Sinteger64(SECCTIME(statbuf)), Sinteger32(NSECCTIME(statbuf)));
}
free(path);
return res;
#endif /* WIN32 */
}
static ptr s_path_mtime(const char *inpath, IBOOL followp) {
#ifdef WIN32
ptr res;
wchar_t *wpath;
WIN32_FILE_ATTRIBUTE_DATA filedata;
__int64 total, sec; int nsec;
if ((wpath = S_malloc_wide_pathname(inpath)) == NULL) {
res = S_LastErrorString();
} else if (!GetFileAttributesExW(wpath, GetFileExInfoStandard, &filedata)) {
DWORD err = GetLastError();
res = err == ERROR_FILE_NOT_FOUND || err == ERROR_PATH_NOT_FOUND ?
Sstring("no such file or directory") :
S_LastErrorString();
} else {
total = filedata.ftLastWriteTime.dwHighDateTime;
total <<= 32;
total |= filedata.ftLastWriteTime.dwLowDateTime;
sec = total / 10000000 - 11644473600L;
nsec = (total % 10000000) * 100;
res = Scons(Sinteger64(sec), Sinteger32(nsec));
}
free(wpath);
return res;
#else /* WIN32 */
ptr res;
char *path;
struct STATBUF statbuf;
path = S_malloc_pathname(inpath);
if ((followp ? STAT(path, &statbuf) : LSTAT(path, &statbuf)) != 0) {
res = S_strerror(errno);
} else {
res = Scons(Sinteger64(SECMTIME(statbuf)), Sinteger32(NSECMTIME(statbuf)));
}
free(path);
return res;
#endif /* WIN32 */
}
static ptr s_fd_atime(INT fd) {
struct STATBUF statbuf;
if (FSTAT(fd, &statbuf) != 0) return S_strerror(errno);
return Scons(Sinteger64(SECATIME(statbuf)), Sinteger32(NSECATIME(statbuf)));
}
static ptr s_fd_ctime(INT fd) {
struct STATBUF statbuf;
if (FSTAT(fd, &statbuf) != 0) return S_strerror(errno);
return Scons(Sinteger64(SECCTIME(statbuf)), Sinteger32(NSECCTIME(statbuf)));
}
static ptr s_fd_mtime(INT fd) {
struct STATBUF statbuf;
if (FSTAT(fd, &statbuf) != 0) return S_strerror(errno);
return Scons(Sinteger64(SECMTIME(statbuf)), Sinteger32(NSECMTIME(statbuf)));
}
static IBOOL s_fd_regularp(INT fd) {
struct STATBUF statbuf;
if (FSTAT(fd, &statbuf) != 0) return 0;
return statbuf.st_mode & S_IFREG;
}
static void s_nanosleep(ptr xsec, ptr xnsec) {
ptr tc = get_thread_context();
U64 sec = Sunsigned64_value(xsec);
U32 nsec = Sunsigned32_value(xnsec);
#ifdef PTHREADS
if (DISABLECOUNT(tc) == 0) {
deactivate_thread(tc)
}
#endif /* PTHREADS */
/* give up our lightweight thread "quanta" */
if (DISABLECOUNT(tc) == 0) {
TRAP(get_thread_context()) = (ptr)1;
}
#ifdef WIN32
/* round to nearest ms represented by sec and nsec */
Sleep((DWORD)(sec * 1000 + (nsec + 500000) / 1000000));
#else /* WIN32 */
struct timespec rqtp;
rqtp.tv_sec = sec;
rqtp.tv_nsec = nsec;
nanosleep(&rqtp, NULL);
#endif /* WIN32 */
#ifdef PTHREADS
if (DISABLECOUNT(tc) == 0) {
reactivate_thread(tc)
}
#endif /* PTHREADS */
}
static int s_getpid(void) {
return GETPID();
}
static ptr s_set_collect_trip_bytes(ptr n) {
S_G.collect_trip_bytes = Sunsigned_value(n);
return Svoid;
}
static void c_exit(UNUSED I32 status) {
S_abnormal_exit();
}
static double s_mod(double x, double y) { return fmod(x, y); }
static double s_exp(double x) { return exp(x); }
static double s_log(double x) { return log(x); }
#if (machine_type == machine_type_i3fb || machine_type == machine_type_ti3fb)
#include <ieeefp.h>
/* freebsd's pow delivers precise results for integer inputs, e.g.,
* 10.0^21.0, only with * extended-precision (80-bit) floats */
static double s_pow(double x, double y) {
fp_prec_t p;
p = fpgetprec();
if (p != FP_PE) {
double ans;
fpsetprec(FP_PE);
ans = pow(x, y);
fpsetprec(p);
return ans;
} else
return pow(x, y);
}
#elif defined(MACOSX)
/* intel macosx delivers precise results for integer inputs, e.g.,
* 10.0^21.0, only with long double version of pow */
static double s_pow(double x, double y) { return powl(x, y); }
#else /* i3fb/ti3fb */
static double s_pow(double x, double y) { return pow(x, y); }
#endif /* i3fb/ti3fb */
static double s_sqrt(double x) { return sqrt(x); }
static double s_sin(double x) { return sin(x); }
static double s_cos(double x) { return cos(x); }
static double s_tan(double x) { return tan(x); }
static double s_asin(double x) { return asin(x); }
static double s_acos(double x) { return acos(x); }
static double s_atan(double x) { return atan(x); }
static double s_atan2(double x, double y) { return atan2(x, y); }
static double s_sinh(double x) { return sinh(x); }
static double s_cosh(double x) { return cosh(x); }
static double s_tanh(double x) { return tanh(x); }
static double s_floor(double x) { return floor(x); }
static double s_ceil(double x) { return ceil(x); }
static double s_hypot(double x, double y) { return HYPOT(x, y); }
#ifdef ARCHYPERBOLIC
static double s_asinh(double x) { return asinh(x); }
static double s_acosh(double x){ return acosh(x); }
static double s_atanh(double x) { return atanh(x); }
#endif /* ARCHHYPERBOLIC */
#ifdef LOG1P
static double s_log1p(double x) { return log1p(x); }
#endif /* LOG1P */
static ptr s_getenv(char *name) {
#ifdef WIN32
char *s = Sgetenv(name);
#else /* WIN32 */
char *s = getenv(name);
#endif /* WIN32 */
if (s == (char *)0)
return Sfalse;
else {
ptr r = Sstring_utf8(s, -1);
#ifdef WIN32
free(s);
#endif
return r;
}
}
static void s_putenv(char *name, char *value) {
#ifdef WIN32
wchar_t* namew;
wchar_t* valuew;
BOOL rc;
namew = Sutf8_to_wide(name);
valuew = Sutf8_to_wide(value);
rc = SetEnvironmentVariableW(namew, valuew);
free(namew);
free(valuew);
if (rc == 0)
S_error1("putenv", "environment extension failed: ~a", S_LastErrorString());
#else /* WIN32 */
if (setenv(name, value, 1) != 0) {
ptr msg = S_strerror(errno);
if (msg != Sfalse)
S_error1("putenv", "environment extension failed: ~a", msg);
else
S_error("putenv", "environment extension failed");
}
#endif /* WIN32 */
}
#ifdef PTHREADS
/* backdoor thread is for testing thread creation by Sactivate_thread */
#define display(s) { const char *S = (s); if (WRITE(1, S, (unsigned int)strlen(S))) {} }
static s_thread_rv_t s_backdoor_thread_start(void *p) {
display("backdoor thread started\n")
(void) Sactivate_thread();
display("thread activated\n")
Scall0((ptr)p);
(void) Sdeactivate_thread();
display("thread deactivated\n")
(void) Sactivate_thread();
display("thread reactivated\n")
Scall0((ptr)p);
Sdestroy_thread();
display("thread destroyed\n")
s_thread_return;
}
static iptr s_backdoor_thread(ptr p) {
display("creating thread\n");
return s_thread_create(s_backdoor_thread_start, (void *)p);
}
static ptr s_threads(void) {
return S_threads;
}
static void s_mutex_acquire(scheme_mutex_t *m) {
ptr tc = get_thread_context();
if (m == &S_tc_mutex) {
S_mutex_acquire(m);
return;
}
if (S_mutex_tryacquire(m) == 0) return;
if (DISABLECOUNT(tc) == 0) {
deactivate_thread(tc)
}
S_mutex_acquire(m);
if (DISABLECOUNT(tc) == 0) {
reactivate_thread(tc)
}
}
static ptr s_mutex_acquire_noblock(scheme_mutex_t *m) {
return S_mutex_tryacquire(m) == 0 ? Strue : Sfalse;
}
static void s_condition_broadcast(s_thread_cond_t *c) {
s_thread_cond_broadcast(c);
}
static void s_condition_signal(s_thread_cond_t *c) {
s_thread_cond_signal(c);
}
#endif
static ptr s_profile_counters(void) {
return S_G.profile_counters;
}
/* s_profile_release_counters assumes and maintains the property that each pair's
tail is not younger than the pair and thereby avoids dirty sets. */
static ptr s_profile_release_counters(void) {
ptr tossed, *p_keep, *p_toss, ls;
p_keep = &S_G.profile_counters;
p_toss = &tossed;
for (ls = *p_keep; ls != Snil && (MaybeSegInfo(ptr_get_segment(ls)))->generation <= S_G.prcgeneration; ls = Scdr(ls)) {
if (Sbwp_objectp(CAAR(ls))) {
*p_toss = ls;
p_toss = &Scdr(ls);
} else {
*p_keep = ls;
p_keep = &Scdr(ls);
}
}
*p_keep = ls;
*p_toss = Snil;
S_G.prcgeneration = 0;
return tossed;
}
void S_dump_tc(ptr tc) {
INT i;
printf("AC0=%p AC1=%p SFP=%p CP=%p\n", AC0(tc), AC1(tc), SFP(tc), CP(tc));
printf("ESP=%p AP=%p EAP=%p\n", ESP(tc), AP(tc), EAP(tc));
printf("TRAP=%p XP=%p YP=%p REAL_EAP=%p\n", TRAP(tc), XP(tc), YP(tc), REAL_EAP(tc));
printf("CCHAIN=%p RANDOMSEED=%ld SCHEMESTACK=%p STACKCACHE=%p\n", CCHAIN(tc), (long)RANDOMSEED(tc), SCHEMESTACK(tc), STACKCACHE(tc));
printf("STACKLINK=%p SCHEMESTACKSIZE=%ld WINDERS=%p U=%p\n", STACKLINK(tc), (long)SCHEMESTACKSIZE(tc), WINDERS(tc), U(tc));
printf("V=%p W=%p X=%p Y=%p\n", V(tc), W(tc), X(tc), Y(tc));
printf("SOMETHING=%p KBDPEND=%p SIGPEND=%p TIMERTICKS=%p\n", SOMETHINGPENDING(tc), KEYBOARDINTERRUPTPENDING(tc), SIGNALINTERRUPTPENDING(tc), TIMERTICKS(tc));
printf("DISABLECOUNT=%p PARAMETERS=%p\n", DISABLECOUNT(tc), PARAMETERS(tc));
for (i = 0 ; i < virtual_register_count ; i += 1) {
printf("VIRTREG[%d]=%p", i, VIRTREG(tc, i));
if ((i & 0x11) == 0x11 || i == virtual_register_count - 1) printf("\n");
}
fflush(stdout);
}
void S_prim5_init(void) {
if (!S_boot_time) return;
#ifdef PTHREADS
Sforeign_symbol("(cs)fork_thread", (void *)S_fork_thread);
Sforeign_symbol("(cs)make_mutex", (void *)S_make_mutex);
Sforeign_symbol("(cs)mutex_free", (void *)S_mutex_free);
Sforeign_symbol("(cs)backdoor_thread", (void *)s_backdoor_thread);
Sforeign_symbol("(cs)threads", (void *)s_threads);
Sforeign_symbol("(cs)mutex_acquire", (void *)s_mutex_acquire);
Sforeign_symbol("(cs)mutex_release", (void *)S_mutex_release);
Sforeign_symbol("(cs)mutex_acquire_noblock", (void *)s_mutex_acquire_noblock);
Sforeign_symbol("(cs)make_condition", (void *)S_make_condition);
Sforeign_symbol("(cs)condition_free", (void *)S_condition_free);
Sforeign_symbol("(cs)condition_broadcast", (void *)s_condition_broadcast);
Sforeign_symbol("(cs)condition_signal", (void *)s_condition_signal);
Sforeign_symbol("(cs)condition_wait", (void *)S_condition_wait);
#endif
Sforeign_symbol("(cs)s_addr_in_heap", (void *)s_addr_in_heap);
Sforeign_symbol("(cs)s_ptr_in_heap", (void *)s_ptr_in_heap);
Sforeign_symbol("(cs)generation", (void *)s_generation);
Sforeign_symbol("(cs)s_fltofx", (void *)s_fltofx);
Sforeign_symbol("(cs)s_weak_cons", (void *)S_weak_cons);
Sforeign_symbol("(cs)s_weak_pairp", (void *)s_weak_pairp);
Sforeign_symbol("(cs)s_ephemeron_cons", (void *)s_ephemeron_cons);
Sforeign_symbol("(cs)s_ephemeron_pairp", (void *)s_ephemeron_pairp);
Sforeign_symbol("(cs)continuation_depth", (void *)S_continuation_depth);
Sforeign_symbol("(cs)single_continuation", (void *)S_single_continuation);
Sforeign_symbol("(cs)c_exit", (void *)c_exit);
Sforeign_symbol("(cs)s_set_collect_trip_bytes", (void *)s_set_collect_trip_bytes);
Sforeign_symbol("(cs)s_oblist", (void *)s_oblist);
Sforeign_symbol("(cs)s_showalloc", (void *)s_showalloc);
Sforeign_symbol("(cs)s_system", (void *)s_system);
Sforeign_symbol("(cs)s_process", (void *)s_process);
Sforeign_symbol("(cs)s_set_code_byte", (void *)s_set_code_byte);
Sforeign_symbol("(cs)s_set_code_word", (void *)s_set_code_word);
Sforeign_symbol("(cs)s_set_code_long", (void *)s_set_code_long);
Sforeign_symbol("(cs)s_set_code_quad", (void *)s_set_code_quad);
Sforeign_symbol("(cs)s_set_reloc", (void *)s_set_reloc);
Sforeign_symbol("(cs)get_code_obj", (void *)S_get_code_obj);
Sforeign_symbol("(cs)s_flush_instruction_cache", (void *)s_flush_instruction_cache);
Sforeign_symbol("(cs)s_make_reloc_table", (void *)s_make_reloc_table);
Sforeign_symbol("(cs)s_make_closure", (void *)s_make_closure);
Sforeign_symbol("(cs)s_intern", (void *)s_intern);
Sforeign_symbol("(cs)s_intern2", (void *)s_intern2);
Sforeign_symbol("(cs)s_intern3", (void *)s_intern3);
Sforeign_symbol("(cs)s_strings_to_gensym", (void *)s_strings_to_gensym);
Sforeign_symbol("(cs)s_intern_gensym", (void *)S_intern_gensym);
Sforeign_symbol("(cs)cputime", (void *)S_cputime);
Sforeign_symbol("(cs)realtime", (void *)S_realtime);
Sforeign_symbol("(cs)clock_gettime", (void *)S_clock_gettime);
Sforeign_symbol("(cs)gmtime", (void *)S_gmtime);
Sforeign_symbol("(cs)asctime", (void *)S_asctime);
Sforeign_symbol("(cs)mktime", (void *)S_mktime);
Sforeign_symbol("(cs)unique_id", (void *)S_unique_id);
Sforeign_symbol("(cs)file_existsp", (void *)S_file_existsp);
Sforeign_symbol("(cs)file_regularp", (void *)S_file_regularp);
Sforeign_symbol("(cs)file_directoryp", (void *)S_file_directoryp);
Sforeign_symbol("(cs)file_symbolic_linkp", (void *)S_file_symbolic_linkp);
Sforeign_symbol("(cs)delete_file", (void *)s_delete_file);
Sforeign_symbol("(cs)delete_directory", (void *)s_delete_directory);
Sforeign_symbol("(cs)rename_file", (void *)s_rename_file);
Sforeign_symbol("(cs)mkdir", (void *)s_mkdir);
Sforeign_symbol("(cs)chmod", (void *)s_chmod);
Sforeign_symbol("(cs)getmod", (void *)s_getmod);
Sforeign_symbol("(cs)path_atime", (void *)s_path_atime);
Sforeign_symbol("(cs)path_ctime", (void *)s_path_ctime);
Sforeign_symbol("(cs)path_mtime", (void *)s_path_mtime);
Sforeign_symbol("(cs)fd_atime", (void *)s_fd_atime);
Sforeign_symbol("(cs)fd_ctime", (void *)s_fd_ctime);
Sforeign_symbol("(cs)fd_mtime", (void *)s_fd_mtime);
Sforeign_symbol("(cs)fd_regularp", (void *)s_fd_regularp);
Sforeign_symbol("(cs)nanosleep", (void *)s_nanosleep);
Sforeign_symbol("(cs)getpid", (void *)s_getpid);
Sforeign_symbol("(cs)fasl_read", (void *)S_fasl_read);
Sforeign_symbol("(cs)bv_fasl_read", (void *)S_bv_fasl_read);
Sforeign_symbol("(cs)s_decode_float", (void *)s_decode_float);
Sforeign_symbol("(cs)new_open_input_fd", (void *)S_new_open_input_fd);
Sforeign_symbol("(cs)new_open_output_fd", (void *)S_new_open_output_fd);
Sforeign_symbol("(cs)new_open_input_output_fd", (void *)S_new_open_input_output_fd);
Sforeign_symbol("(cs)close_fd", (void *)S_close_fd);
Sforeign_symbol("(cs)gzxfile_fd", (void *)S_gzxfile_fd);
Sforeign_symbol("(cs)compress_input_fd", (void *)S_compress_input_fd);
Sforeign_symbol("(cs)compress_output_fd", (void *)S_compress_output_fd);
Sforeign_symbol("(cs)bytevector_read", (void*)S_bytevector_read);
Sforeign_symbol("(cs)bytevector_read_nb", (void*)S_bytevector_read_nb);
Sforeign_symbol("(cs)bytevector_write", (void*)S_bytevector_write);
Sforeign_symbol("(cs)put_byte", (void*)S_put_byte);
Sforeign_symbol("(cs)get_fd_pos", (void*)S_get_fd_pos);
Sforeign_symbol("(cs)set_fd_pos", (void*)S_set_fd_pos);
Sforeign_symbol("(cs)get_fd_non_blocking", (void*)S_get_fd_non_blocking);
Sforeign_symbol("(cs)set_fd_non_blocking", (void*)S_set_fd_non_blocking);
Sforeign_symbol("(cs)get_fd_length", (void*)S_get_fd_length);
Sforeign_symbol("(cs)set_fd_length", (void*)S_set_fd_length);
Sforeign_symbol("(cs)bytevector_compress_size", (void*)S_bytevector_compress_size);
Sforeign_symbol("(cs)bytevector_compress", (void*)S_bytevector_compress);
Sforeign_symbol("(cs)bytevector_uncompress", (void*)S_bytevector_uncompress);
Sforeign_symbol("(cs)logand", (void *)S_logand);
Sforeign_symbol("(cs)logbitp", (void *)S_logbitp);
Sforeign_symbol("(cs)logbit0", (void *)S_logbit0);
Sforeign_symbol("(cs)logbit1", (void *)S_logbit1);
Sforeign_symbol("(cs)logtest", (void *)S_logtest);
Sforeign_symbol("(cs)logor", (void *)S_logor);
Sforeign_symbol("(cs)logxor", (void *)S_logxor);
Sforeign_symbol("(cs)lognot", (void *)S_lognot);
Sforeign_symbol("(cs)fxmul", (void *)s_fxmul);
Sforeign_symbol("(cs)fxdiv", (void *)s_fxdiv);
Sforeign_symbol("(cs)s_big_negate", (void *)S_big_negate);
Sforeign_symbol("(cs)add", (void *)S_add);
Sforeign_symbol("(cs)gcd", (void *)S_gcd);
Sforeign_symbol("(cs)mul", (void *)S_mul);
Sforeign_symbol("(cs)s_ash", (void *)S_ash);
Sforeign_symbol("(cs)s_big_positive_bit_field", (void *)S_big_positive_bit_field);
Sforeign_symbol("(cs)s_big_eq", (void *)S_big_eq);
Sforeign_symbol("(cs)s_big_lt", (void *)S_big_lt);
Sforeign_symbol("(cs)s_bigoddp", (void *)s_bigoddp);
Sforeign_symbol("(cs)s_div", (void *)S_div);
Sforeign_symbol("(cs)s_float", (void *)s_float);
Sforeign_symbol("(cs)s_flrandom", (void *)s_flrandom);
Sforeign_symbol("(cs)s_fxrandom", (void *)s_fxrandom);
Sforeign_symbol("(cs)s_integer_length", (void *)S_integer_length);
Sforeign_symbol("(cs)s_big_first_bit_set", (void *)S_big_first_bit_set);
Sforeign_symbol("(cs)s_make_code", (void *)s_make_code);
Sforeign_symbol("(cs)s_random_seed", (void *)s_random_seed);
Sforeign_symbol("(cs)s_set_code_long2", (void *)s_set_code_long2);
Sforeign_symbol("(cs)s_set_random_seed", (void *)s_set_random_seed);
Sforeign_symbol("(cs)ss_trunc", (void *)S_trunc);
Sforeign_symbol("(cs)ss_trunc_rem", (void *)s_trunc_rem);
Sforeign_symbol("(cs)sub", (void *)S_sub);
Sforeign_symbol("(cs)rem", (void *)S_rem);
#ifdef GETWD
Sforeign_symbol("(cs)s_getwd", (void *)s_getwd);
#endif
Sforeign_symbol("(cs)s_chdir", (void *)s_chdir);
#ifdef WIN32
Sforeign_symbol("(cs)find_files", (void *)S_find_files);
#else
Sforeign_symbol("(cs)directory_list", (void *)S_directory_list);
#endif
Sforeign_symbol("(cs)dequeue_scheme_signals", (void *)S_dequeue_scheme_signals);
Sforeign_symbol("(cs)register_scheme_signal", (void *)S_register_scheme_signal);
Sforeign_symbol("(cs)mod", (void *)s_mod);
Sforeign_symbol("(cs)exp", (void *)s_exp);
Sforeign_symbol("(cs)log", (void *)s_log);
Sforeign_symbol("(cs)pow", (void *)s_pow);
Sforeign_symbol("(cs)sqrt", (void *)s_sqrt);
Sforeign_symbol("(cs)sin", (void *)s_sin);
Sforeign_symbol("(cs)cos", (void *)s_cos);
Sforeign_symbol("(cs)tan", (void *)s_tan);
Sforeign_symbol("(cs)asin", (void *)s_asin);
Sforeign_symbol("(cs)acos", (void *)s_acos);
Sforeign_symbol("(cs)atan", (void *)s_atan);
Sforeign_symbol("(cs)atan2", (void *)s_atan2);
Sforeign_symbol("(cs)sinh", (void *)s_sinh);
Sforeign_symbol("(cs)cosh", (void *)s_cosh);
Sforeign_symbol("(cs)tanh", (void *)s_tanh);
Sforeign_symbol("(cs)floor", (void *)s_floor);
Sforeign_symbol("(cs)ceil", (void *)s_ceil);
Sforeign_symbol("(cs)hypot", (void *)s_hypot);
#ifdef ARCHYPERBOLIC
Sforeign_symbol("(cs)asinh", (void *)s_asinh);
Sforeign_symbol("(cs)acosh", (void *)s_acosh);
Sforeign_symbol("(cs)atanh", (void *)s_atanh);
#endif /* ARCHHYPERBOLIC */
#ifdef LOG1P
Sforeign_symbol("(cs)log1p", (void *)s_log1p);
#endif /* LOG1P */
Sforeign_symbol("(cs)s_get_reloc", (void *)s_get_reloc);
Sforeign_symbol("(cs)getenv", (void *)s_getenv);
Sforeign_symbol("(cs)putenv", (void *)s_putenv);
Sforeign_symbol("(cs)byte-copy", (void *)s_byte_copy);
Sforeign_symbol("(cs)ptr-copy", (void *)s_ptr_copy);
Sforeign_symbol("(cs)boot-error", (void *)S_boot_error);
Sforeign_symbol("(cs)s_tlv", (void *)s_tlv);
Sforeign_symbol("(cs)s_stlv", (void *)s_stlv);
Sforeign_symbol("(cs)s_test_schlib", (void *)s_test_schlib);
Sforeign_symbol("(cs)Sinteger_value", (void *)Sinteger_value);
Sforeign_symbol("(cs)Sinteger32_value", (void *)Sinteger32_value);
Sforeign_symbol("(cs)Sinteger64_value", (void *)Sinteger64_value);
Sforeign_symbol("(cs)s_breakhere", (void *)s_breakhere);
Sforeign_symbol("(cs)s_interactivep", (void *)s_interactivep);
Sforeign_symbol("(cs)same_devicep", (void *)s_same_devicep);
Sforeign_symbol("(cs)malloc", (void *)s_malloc);
Sforeign_symbol("(cs)free", (void *)s_free);
#ifdef FEATURE_ICONV
Sforeign_symbol("(cs)s_iconv_open", (void *)s_iconv_open);
Sforeign_symbol("(cs)s_iconv_close", (void *)s_iconv_close);
Sforeign_symbol("(cs)s_iconv_from_string", (void *)s_iconv_from_string);
Sforeign_symbol("(cs)s_iconv_to_string", (void *)s_iconv_to_string);
#endif
Sforeign_symbol("(cs)s_strerror", (void *)S_strerror);
Sforeign_symbol("(cs)s_errno", (void *)s_errno);
#ifdef WIN32
Sforeign_symbol("(cs)s_multibytetowidechar", (void *)s_multibytetowidechar);
Sforeign_symbol("(cs)s_widechartomultibyte", (void *)s_widechartomultibyte);
#endif
Sforeign_symbol("(cs)s_profile_counters", (void *)s_profile_counters);
Sforeign_symbol("(cs)s_profile_release_counters", (void *)s_profile_release_counters);
}
static ptr s_get_reloc(ptr co) {
ptr t, ls; uptr a, m, n;
require(Scodep(co),"s_get_reloc","~s is not a code object",co);
ls = Snil;
t = CODERELOC(co);
m = RELOCSIZE(t);
a = 0;
n = 0;
while (n < m) {
uptr entry, item_off, code_off; ptr obj;
entry = RELOCIT(t, n); n += 1;
if (RELOC_EXTENDED_FORMAT(entry)) {
item_off = RELOCIT(t, n); n += 1;
code_off = RELOCIT(t, n); n += 1;
} else {
item_off = RELOC_ITEM_OFFSET(entry);
code_off = RELOC_CODE_OFFSET(entry);
}
a += code_off;
obj = S_get_code_obj(RELOC_TYPE(entry), co, a, item_off);
if (!Sfixnump(obj)) {
ptr x;
for (x = ls; ; x = Scdr(x)) {
if (x == Snil) {
ls = Scons(obj,ls);
break;
} else if (Scar(x) == obj)
break;
}
}
}
return ls;
}
static void s_byte_copy(ptr src, iptr srcoff, ptr dst, iptr dstoff, iptr cnt) {
void *srcaddr = (void *)((iptr)src + srcoff);
void *dstaddr = (void *)((iptr)dst + dstoff);
if (dst != src)
memcpy(dstaddr, srcaddr, cnt);
else
memmove(dstaddr, srcaddr, cnt);
}
static void s_ptr_copy(ptr src, iptr srcoff, ptr dst, iptr dstoff, iptr cnt) {
void *srcaddr = (void *)((iptr)src + srcoff);
void *dstaddr = (void *)((iptr)dst + dstoff);
cnt = cnt << log2_ptr_bytes;
if (dst != src)
memcpy(dstaddr, srcaddr, cnt);
else
memmove(dstaddr, srcaddr, cnt);
}
/* these are used only for testing */
static ptr s_tlv(ptr x) {
return Stop_level_value(x);
}
static void s_stlv(ptr x, ptr v) {
Sset_top_level_value(x, v);
}
#define SCHLIBTEST(expr) {\
test += 1;\
if (!(expr)) S_error1("s_test_schlib", "test ~s failed", FIX(test));\
}
static void s_test_schlib(void) {
INT test = 0;
I32 n1 = 0x73215609;
I64 n2 = n1 * 37;
I32 n3 = (I32)1<<31;
I64 n4 = (I64)1<<63;
I32 n5 = -1;
SCHLIBTEST(Sinteger_value(Sinteger(n1)) == n1)
SCHLIBTEST(Sinteger_value(Sinteger(-n1)) == -n1)
SCHLIBTEST(Sinteger_value(Sunsigned(n1)) == n1)
SCHLIBTEST(Sinteger_value(Sunsigned(-n1)) == -n1)
SCHLIBTEST(Sinteger32_value(Sinteger32(n1)) == n1)
SCHLIBTEST(Sinteger32_value(Sinteger32(-n1)) == -n1)
SCHLIBTEST(Sinteger32_value(Sunsigned32(n1)) == n1)
SCHLIBTEST(Sinteger32_value(Sunsigned32(-n1)) == -n1)
SCHLIBTEST(Sinteger64_value(Sinteger64(n1)) == n1)
SCHLIBTEST(Sinteger64_value(Sinteger64(-n1)) == -n1)
SCHLIBTEST(Sinteger64_value(Sunsigned64(n1)) == n1)
SCHLIBTEST(Sinteger64_value(Sunsigned64(-n1)) == -n1)
#if (ptr_bits == 64)
SCHLIBTEST(Sinteger_value(Sinteger(n2)) == n2)
SCHLIBTEST(Sinteger_value(Sinteger(-n2)) == -n2)
SCHLIBTEST(Sinteger_value(Sunsigned(n2)) == n2)
SCHLIBTEST(Sinteger_value(Sunsigned(-n2)) == -n2)
#endif
SCHLIBTEST(Sinteger64_value(Sinteger64(n2)) == n2)
SCHLIBTEST(Sinteger64_value(Sinteger64(-n2)) == -n2)
SCHLIBTEST(Sinteger64_value(Sunsigned64(n2)) == n2)
SCHLIBTEST(Sinteger64_value(Sunsigned64(-n2)) == -n2)
SCHLIBTEST(Sinteger_value(Sinteger(n3)) == n3)
SCHLIBTEST(Sinteger_value(Sunsigned(n3)) == n3)
SCHLIBTEST(Sinteger32_value(Sinteger32(n3)) == n3)
SCHLIBTEST(Sinteger32_value(Sunsigned32(n3)) == n3)
SCHLIBTEST(Sinteger64_value(Sinteger64(n3)) == n3)
SCHLIBTEST(Sinteger64_value(Sunsigned64(n3)) == n3)
#if (ptr_bits == 64)
SCHLIBTEST(Sinteger_value(Sunsigned(n4)) == n4)
SCHLIBTEST(Sinteger_value(Sinteger(n4)) == n4)
SCHLIBTEST(Sinteger_value(Sunsigned(n4)) == n4)
#endif
SCHLIBTEST(Sinteger64_value(Sinteger64(n4)) == n4)
SCHLIBTEST(Sinteger64_value(Sunsigned64(n4)) == n4)
SCHLIBTEST(Sinteger_value(Sinteger(n5)) == n5)
SCHLIBTEST(Sinteger_value(Sinteger(-n5)) == -n5)
SCHLIBTEST(Sinteger_value(Sunsigned(n5)) == n5)
SCHLIBTEST(Sinteger_value(Sunsigned(-n5)) == -n5)
SCHLIBTEST(Sinteger32_value(Sinteger32(n5)) == n5)
SCHLIBTEST(Sinteger32_value(Sinteger32(-n5)) == -n5)
SCHLIBTEST(Sinteger32_value(Sunsigned32(n5)) == n5)
SCHLIBTEST(Sinteger32_value(Sunsigned32(-n5)) == -n5)
SCHLIBTEST(Sinteger64_value(Sinteger64(n5)) == n5)
SCHLIBTEST(Sinteger64_value(Sinteger64(-n5)) == -n5)
SCHLIBTEST(Sinteger64_value(Sunsigned64(n5)) == n5)
SCHLIBTEST(Sinteger64_value(Sunsigned64(-n5)) == -n5)
}
/* place to break when debugging */
static void s_breakhere(UNUSED ptr x) {
return;
}
static IBOOL s_interactivep(void) {
static INT interactivep = -1;
if (interactivep == -1) {
#ifdef WIN32
HANDLE hStdout, hStdin;
CONSOLE_SCREEN_BUFFER_INFO csbiInfo;
DWORD InMode, OutMode;
interactivep =
(hStdin = GetStdHandle(STD_INPUT_HANDLE)) != INVALID_HANDLE_VALUE
&& (hStdout = GetStdHandle(STD_OUTPUT_HANDLE)) != INVALID_HANDLE_VALUE
&& GetConsoleScreenBufferInfo(hStdout, &csbiInfo)
&& GetConsoleMode(hStdin, &InMode)
&& GetConsoleMode(hStdout, &OutMode);
#else /* WIN32 */
interactivep = isatty(0) && isatty(1);
#endif /* WIN32 */
}
return interactivep;
}
static IBOOL s_same_devicep(INT fd1, INT fd2) {
#ifdef WIN32
HANDLE h1, h2; DWORD mode1, mode2;
if ((h1 = (HANDLE)_get_osfhandle(fd1)) != INVALID_HANDLE_VALUE)
if ((h2 = (HANDLE)_get_osfhandle(fd2)) != INVALID_HANDLE_VALUE)
switch (GetFileType(h1)) {
case FILE_TYPE_CHAR:
if (GetFileType(h2) == FILE_TYPE_CHAR)
return GetConsoleMode(h1, &mode1) && GetConsoleMode(h2, &mode2);
break;
case FILE_TYPE_DISK:
if (GetFileType(h2) == FILE_TYPE_DISK) {
BY_HANDLE_FILE_INFORMATION info1, info2;
if (GetFileInformationByHandle(h1, &info1) && GetFileInformationByHandle(h1, &info2))
return info1.dwVolumeSerialNumber == info2.dwVolumeSerialNumber
&& info1.nFileIndexHigh == info2.nFileIndexHigh
&& info1.nFileIndexLow == info2.nFileIndexLow;
}
break;
case FILE_TYPE_PIPE:
/* no clue */
break;
default: break;
}
#else /* WIN32 */
struct STATBUF statbuf1, statbuf2;
if (FSTAT(fd1, &statbuf1) == 0 && FSTAT(fd2, &statbuf2) == 0)
return statbuf1.st_ino == statbuf2.st_ino;
#endif /* WIN32 */
return 0;
}
static uptr s_malloc(iptr n) {
void *p;
if ((p = malloc((size_t)n)) == NULL) {
ptr msg = S_strerror(errno);
if (msg != Sfalse)
S_error1("foreign-alloc", "~a", msg);
else
S_error("foreign-alloc", "malloc failed");
}
return (uptr)p;
}
static void s_free(uptr addr) {
free((void *)addr);
}
#ifdef FEATURE_ICONV
#ifdef WIN32
typedef void *iconv_t;
typedef __declspec(dllimport) iconv_t (*iconv_open_ft)(const char *tocode, const char *fromcode);
typedef __declspec(dllimport) size_t (*iconv_ft)(iconv_t cd, char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft);
typedef __declspec(dllimport) int (*iconv_close_ft)(iconv_t cd);
static iconv_open_ft iconv_open_f = (iconv_open_ft)0;
static iconv_ft iconv_f = (iconv_ft)0;
static iconv_close_ft iconv_close_f = (iconv_close_ft)0;
#define ICONV_OPEN iconv_open_f
#define ICONV iconv_f
#define ICONV_CLOSE iconv_close_f
#else
#include <iconv.h>
#define ICONV_OPEN iconv_open
#define ICONV iconv
#define ICONV_CLOSE iconv_close
#endif
#ifdef WIN32
static ptr s_iconv_trouble(HMODULE h, const char *what) {
wchar_t dllw[PATH_MAX];
char *dll;
size_t n;
char *msg;
ptr r;
if (0 != GetModuleFileNameW(h, dllw, PATH_MAX))
dll = Swide_to_utf8(dllw);
else
dll = NULL;
FreeLibrary(h);
n = strlen(what) + strlen(dll) + 17;
msg = (char *)malloc(n);
sprintf_s(msg, n, "cannot find %s in %s", what, dll);
free(dll);
r = Sstring_utf8(msg, -1);
free(msg);
return r;
}
#endif /* WIN32 */
static ptr s_iconv_open(const char *tocode, const char *fromcode) {
iconv_t cd;
#ifdef WIN32
static int iconv_is_loaded = 0;
if (!iconv_is_loaded) {
HMODULE h = LoadLibraryW(L"iconv.dll");
if (h == NULL) h = LoadLibraryW(L"libiconv.dll");
if (h == NULL) h = LoadLibraryW(L"libiconv-2.dll");
if (h == NULL) h = LoadLibraryW(L".\\iconv.dll");
if (h == NULL) h = LoadLibraryW(L".\\libiconv.dll");
if (h == NULL) h = LoadLibraryW(L".\\libiconv-2.dll");
if (h == NULL) return Sstring("cannot load iconv.dll, libiconv.dll, or libiconv-2.dll");
if ((iconv_open_f = (iconv_open_ft)GetProcAddress(h, "iconv_open")) == NULL &&
(iconv_open_f = (iconv_open_ft)GetProcAddress(h, "libiconv_open")) == NULL)
return s_iconv_trouble(h, "iconv_open or libiconv_open");
if ((iconv_f = (iconv_ft)GetProcAddress(h, "iconv")) == NULL &&
(iconv_f = (iconv_ft)GetProcAddress(h, "libiconv")) == NULL)
return s_iconv_trouble(h, "iconv or libiconv");
if ((iconv_close_f = (iconv_close_ft)GetProcAddress(h, "iconv_close")) == NULL &&
(iconv_close_f = (iconv_close_ft)GetProcAddress(h, "libiconv_close")) == NULL)
return s_iconv_trouble(h, "iconv_close or libiconv_close");
iconv_is_loaded = 1;
}
#endif /* WIN32 */
if ((cd = ICONV_OPEN(tocode, fromcode)) == (iconv_t)-1) return Sfalse;
/* have to be able to cast to int, since iconv_open can return (iconv_t)-1 */
return Sunsigned((uptr)cd);
}
static void s_iconv_close(uptr cd) {
ICONV_CLOSE((iconv_t)cd);
}
#define ICONV_BUFSIZ 400
static ptr s_iconv_from_string(uptr cd, ptr in, uptr i, uptr iend, ptr out, uptr o, uptr oend) {
U32 buf[ICONV_BUFSIZ];
char *inbuf, *outbuf;
size_t inbytesleft, outbytesleft;
uptr inmax, k, new_i, new_o;
outbuf = (char *)&BVIT(out, o);
outbytesleft = oend - o;
inmax = iend - i;
if (inmax > ICONV_BUFSIZ) inmax = ICONV_BUFSIZ;
if (inmax > outbytesleft) inmax = outbytesleft;
for (k = 0; k < inmax; k += 1) buf[k] = Sstring_ref(in, i + k);
inbuf = (char *)buf;
inbytesleft = inmax * sizeof(string_char);
/* we ignore the iconv return value because we consider success to be the consumption
of input or production of output. we set errno to 0 before calling iconv, even though
it should be set properly if neither input is consumed nor output is produced, because,
under Windows, the iconv dll might have been linked against a different C runtime
and might therefore set a different errno */
errno = 0;
ICONV((iconv_t)cd, (ICONV_INBUF_TYPE)&inbuf, &inbytesleft, &outbuf, &outbytesleft);
new_i = i + inmax - inbytesleft / sizeof(string_char);
new_o = oend - outbytesleft;
if (new_i != i || new_o != o) return Scons(Sinteger(new_i), Sinteger(new_o));
switch (errno) {
case EILSEQ: return FIX(SICONV_INVALID);
case EINVAL: return FIX(SICONV_INCOMPLETE);
case E2BIG: return FIX(SICONV_NOROOM);
default: return FIX(SICONV_DUNNO);
}
}
static ptr s_iconv_to_string(uptr cd, ptr in, uptr i, uptr iend, ptr out, uptr o, uptr oend) {
U32 buf[ICONV_BUFSIZ];
char *inbuf, *outbuf;
size_t inbytesleft, outbytesleft;
uptr outmax, k, new_i, new_o;
inbuf = (char *)&BVIT(in, i);
inbytesleft = iend - i;
outmax = oend - o;
if (outmax > ICONV_BUFSIZ) outmax = ICONV_BUFSIZ;
if (outmax > inbytesleft) outmax = inbytesleft;
outbuf = (char *)buf;
outbytesleft = outmax * sizeof(string_char);
/* see the comment about the iconv return value and errno in s_iconv_from_string */
errno = 0;
ICONV((iconv_t)cd, (ICONV_INBUF_TYPE)&inbuf, &inbytesleft, &outbuf, &outbytesleft);
outmax -= outbytesleft / sizeof(string_char);
for (k = 0; k < outmax; k += 1) Sstring_set(out, o + k, buf[k]);
new_i = iend - inbytesleft;
new_o = o + outmax;
if (new_i != i || new_o != o) return Scons(Sinteger(new_i), Sinteger(new_o));
switch (errno) {
case EILSEQ: return FIX(SICONV_INVALID);
case EINVAL: return FIX(SICONV_INCOMPLETE);
case E2BIG: return FIX(SICONV_NOROOM);
default: return FIX(SICONV_DUNNO);
}
}
#endif /* FEATURE_ICONV */
#ifdef WIN32
static ptr s_multibytetowidechar(unsigned cp, ptr inbv) {
uptr inbytes; int outwords; ptr outbv;
inbytes = Sbytevector_length(inbv);
#if (ptr_bits > int_bits)
if ((int)inbytes != inbytes) S_error1("multibyte->string", "input size ~s is beyond MultiByteToWideChar's limit", Sinteger(inbytes));
#endif
if ((outwords = MultiByteToWideChar(cp, 0, &BVIT(inbv,0), (int)inbytes, NULL, 0)) == 0)
S_error1("multibyte->string", "conversion failed: ~a", S_LastErrorString());
outbv = S_bytevector(outwords * 2);
if (MultiByteToWideChar(cp, 0, &BVIT(inbv,0), (int)inbytes, (wchar_t *)&BVIT(outbv, 0), outwords) == 0)
S_error1("multibyte->string", "conversion failed: ~a", S_LastErrorString());
return outbv;
}
static ptr s_widechartomultibyte(unsigned cp, ptr inbv) {
uptr inwords; int outbytes; ptr outbv;
inwords = Sbytevector_length(inbv) / 2;
#if (ptr_bits > int_bits)
if ((int)inwords != inwords) S_error1("multibyte->string", "input size ~s is beyond WideCharToMultiByte's limit", Sinteger(inwords));
#endif
if ((outbytes = WideCharToMultiByte(cp, 0, (wchar_t *)&BVIT(inbv,0), (int)inwords, NULL, 0, NULL, NULL)) == 0)
S_error1("string->multibyte", "conversion failed: ~a", S_LastErrorString());
outbv = S_bytevector(outbytes);
if (WideCharToMultiByte(cp, 0, (wchar_t *)&BVIT(inbv,0), (int)inwords, &BVIT(outbv, 0), outbytes, NULL, NULL) == 0)
S_error1("string->multibyte", "conversion failed: ~a", S_LastErrorString());
return outbv;
}
#endif /* WIN32 */