X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=os2%2Fos2.c;h=4ebdd509a9994f5f60533b18320f83f9c87b72da;hb=fb063f91dc7f31f7c1489f10462283ee145673d0;hp=bf8891bfc625e6882cd556fcc769a559d266fb15;hpb=622913ab81739f4a9419ed541a122ff2495c8ab1;p=p5sagit%2Fp5-mst-13.2.git diff --git a/os2/os2.c b/os2/os2.c index bf8891b..4ebdd50 100644 --- a/os2/os2.c +++ b/os2/os2.c @@ -12,6 +12,7 @@ #include #include "dlfcn.h" #include +#include #include @@ -32,6 +33,14 @@ #include "EXTERN.h" #include "perl.h" +enum module_name_how { mod_name_handle, mod_name_shortname, mod_name_full, + mod_name_C_function = 0x100, mod_name_HMODULE = 0x200}; + +/* Find module name to which *this* subroutine is compiled */ +#define module_name(how) module_name_at(&module_name_at, how) + +static SV* module_name_at(void *pp, enum module_name_how how); + void croak_with_os2error(char *s) { @@ -118,6 +127,7 @@ static struct perlos2_state_t { int po2__my_pwent; /* = -1; */ int po2_DOS_harderr_state; /* = -1; */ signed char po2_DOS_suppression_state; /* = -1; */ + PFN po2_ExtFCN[ORD_NENTRIES]; /* Labeled by ord ORD_*. */ /* struct PMWIN_entries_t po2_PMWIN_entries; */ @@ -153,7 +163,10 @@ static struct perlos2_state_t { int po2_emx_runtime_init; /* If 1, we need to manually init it */ int po2_emx_exception_init; /* If 1, we need to manually set it */ int po2_emx_runtime_secondary; - + char* (*po2_perllib_mangle_installed)(char *s, unsigned int l); + char* po2_perl_sh_installed; + PGINFOSEG po2_gTable; + PLINFOSEG po2_lTable; } perlos2_state = { -1, /* po2__my_pwent */ -1, /* po2_DOS_harderr_state */ @@ -195,10 +208,13 @@ static struct perlos2_state_t { #define emx_runtime_init (Perl_po2()->po2_emx_runtime_init) #define emx_exception_init (Perl_po2()->po2_emx_exception_init) #define emx_runtime_secondary (Perl_po2()->po2_emx_runtime_secondary) +#define perllib_mangle_installed (Perl_po2()->po2_perllib_mangle_installed) +#define perl_sh_installed (Perl_po2()->po2_perl_sh_installed) +#define gTable (Perl_po2()->po2_gTable) +#define lTable (Perl_po2()->po2_lTable) const Perl_PFN * const pExtFCN = (Perl_po2()->po2_ExtFCN); - #if defined(USE_5005THREADS) || defined(USE_ITHREADS) typedef void (*emx_startroutine)(void *); @@ -344,7 +360,7 @@ pthread_startit(void *arg1) Renew(thread_join_data, thread_join_count, thread_join_t); Zero(thread_join_data + oc, thread_join_count - oc, thread_join_t); } else { - Newz(1323, thread_join_data, thread_join_count, thread_join_t); + Newxz(thread_join_data, thread_join_count, thread_join_t); } } if (thread_join_data[tid].state != pthreads_st_none) { @@ -474,7 +490,7 @@ os2_cond_wait(perl_cond *c, perl_mutex *m) int rc; STRLEN n_a; if ((rc = DosResetEventSem(*c,&n_a)) && (rc != ERROR_ALREADY_RESET)) - Perl_rc = rc, croak_with_os2error("panic: COND_WAIT-reset"); + Perl_rc = CheckOSError(rc), croak_with_os2error("panic: COND_WAIT-reset"); if (m) MUTEX_UNLOCK(m); if (CheckOSError(DosWaitEventSem(*c,SEM_INDEFINITE_WAIT)) && (rc != ERROR_INTERRUPT)) @@ -619,6 +635,9 @@ static const struct { {&pmwin_handle, NULL, 745}, /* WinFlashWindow */ {&pmwin_handle, NULL, 780}, /* WinLoadPointer */ {&pmwin_handle, NULL, 828}, /* WinQuerySysPointer */ + {&doscalls_handle, NULL, 417}, /* DosReplaceModule */ + {&doscalls_handle, NULL, 976}, /* DosPerfSysCall */ + {&rexxapi_handle, "RexxRegisterSubcomExe", 0}, }; HMODULE @@ -758,17 +777,19 @@ get_sysinfo(ULONG pid, ULONG flags) ULONG rc, buf_len = QSS_INI_BUFFER; PQTOPLEVEL psi; - if (!pidtid_lookup) { - pidtid_lookup = 1; - *(PFN*)&pDosVerifyPidTid = loadByOrdinal(ORD_DosVerifyPidTid, 0); - } - if (pDosVerifyPidTid) { /* Warp3 or later */ - /* Up to some fixpak QuerySysState() kills the system if a non-existent - pid is used. */ - if (CheckOSError(pDosVerifyPidTid(pid, 1))) - return 0; + if (pid) { + if (!pidtid_lookup) { + pidtid_lookup = 1; + *(PFN*)&pDosVerifyPidTid = loadByOrdinal(ORD_DosVerifyPidTid, 0); + } + if (pDosVerifyPidTid) { /* Warp3 or later */ + /* Up to some fixpak QuerySysState() kills the system if a non-existent + pid is used. */ + if (CheckOSError(pDosVerifyPidTid(pid, 1))) + return 0; + } } - New(1322, pbuffer, buf_len, char); + Newx(pbuffer, buf_len, char); /* QSS_PROCESS | QSS_MODULE | QSS_SEMAPHORES | QSS_SHARED */ rc = QuerySysState(flags, pid, pbuffer, buf_len); while (rc == ERROR_BUFFER_OVERFLOW) { @@ -781,7 +802,7 @@ get_sysinfo(ULONG pid, ULONG flags) return 0; } psi = (PQTOPLEVEL)pbuffer; - if (psi && pid && pid != psi->procdata->pid) { + if (psi && pid && psi->procdata && pid != psi->procdata->pid) { Safefree(psi); Perl_croak_nocontext("panic: wrong pid in sysinfo"); } @@ -961,7 +982,7 @@ do_spawn_ve(pTHX_ SV *really, U32 flag, U32 execf, char *inicmd, U32 addflag) { int trueflag = flag; int rc, pass = 1; - char *real_name; + char *real_name = NULL; /* Shut down the warning */ char const * args[4]; static const char * const fargs[4] = { "/bin/sh", "-c", "\"$@\"", "spawn-via-shell", }; @@ -977,7 +998,7 @@ do_spawn_ve(pTHX_ SV *really, U32 flag, U32 execf, char *inicmd, U32 addflag) if (flag == P_WAIT) flag = P_NOWAIT; if (really && !*(real_name = SvPV(really, n_a))) - really = Nullsv; + really = NULL; retry: if (strEQ(PL_Argv[0],"/bin/sh")) @@ -1126,7 +1147,7 @@ do_spawn_ve(pTHX_ SV *really, U32 flag, U32 execf, char *inicmd, U32 addflag) does not append ".exe", so we could have reached this place). */ sv_catpv(scrsv, ".exe"); - scr = SvPV(scrsv, n_a); /* Reload */ + PL_Argv[0] = scr = SvPV(scrsv, n_a); /* Reload */ if (PerlLIO_stat(scr,&PL_statbuf) >= 0 && !S_ISDIR(PL_statbuf.st_mode)) { /* Found */ real_name = scr; @@ -1244,7 +1265,7 @@ do_spawn_ve(pTHX_ SV *really, U32 flag, U32 execf, char *inicmd, U32 addflag) /* XXXX This is good only until we refuse quoted arguments... */ PL_Argv[0] = inicmd; - PL_Argv[1] = Nullch; + PL_Argv[1] = NULL; } } else if (!buf[0] && inicmd) { /* No file */ /* Start with the original cmdline. */ @@ -1252,7 +1273,7 @@ do_spawn_ve(pTHX_ SV *really, U32 flag, U32 execf, char *inicmd, U32 addflag) quoted arguments... */ PL_Argv[0] = inicmd; - PL_Argv[1] = Nullch; + PL_Argv[1] = NULL; nargs = 2; /* shell -c */ } @@ -1353,7 +1374,7 @@ do_spawn3(pTHX_ char *cmd, int execf, int flag) if (strnEQ(cmd,"/bin/sh",7) && isSPACE(cmd[7])) { STRLEN l = strlen(PL_sh_path); - New(1302, news, strlen(cmd) - 7 + l + 1, char); + Newx(news, strlen(cmd) - 7 + l + 1, char); strcpy(news, PL_sh_path); strcpy(news + l, cmd + 7); cmd = news; @@ -1426,7 +1447,7 @@ do_spawn3(pTHX_ char *cmd, int execf, int flag) } /* cmd="a" may lead to "sh", "-c", "\"$@\"", "a", "a.cmd", NULL */ - New(1303,PL_Argv, (s - cmd + 11) / 2, char*); + Newx(PL_Argv, (s - cmd + 11) / 2, char*); PL_Cmd = savepvn(cmd, s-cmd); a = PL_Argv; for (s = PL_Cmd; *s;) { @@ -1437,7 +1458,7 @@ do_spawn3(pTHX_ char *cmd, int execf, int flag) if (*s) *s++ = '\0'; } - *a = Nullch; + *a = NULL; if (PL_Argv[0]) rc = do_spawn_ve(aTHX_ NULL, flag, execf, cmd, mergestderr); else @@ -1448,42 +1469,47 @@ do_spawn3(pTHX_ char *cmd, int execf, int flag) return rc; } +#define ASPAWN_WAIT 0 +#define ASPAWN_EXEC 1 +#define ASPAWN_NOWAIT 2 + /* Array spawn/exec. */ int -os2_aspawn4(pTHX_ SV *really, register SV **vmark, register SV **vsp, int execing) +os2_aspawn_4(pTHX_ SV *really, register SV **args, I32 cnt, int execing) { - register SV **mark = (SV **)vmark; - register SV **sp = (SV **)vsp; + register SV **argp = (SV **)args; + register SV **last = argp + cnt; register char **a; int rc; int flag = P_WAIT, flag_set = 0; STRLEN n_a; - if (sp > mark) { - New(1301,PL_Argv, sp - mark + 3, char*); + if (cnt) { + Newx(PL_Argv, cnt + 3, char*); /* 3 extra to expand #! */ a = PL_Argv; - if (mark < sp && SvNIOKp(*(mark+1)) && !SvPOKp(*(mark+1))) { - ++mark; - flag = SvIVx(*mark); - flag_set = 1; - - } + if (cnt > 1 && SvNIOKp(*argp) && !SvPOKp(*argp)) { + flag = SvIVx(*argp); + flag_set = 1; + } else + --argp; - while (++mark <= sp) { - if (*mark) - *a++ = SvPVx(*mark, n_a); + while (++argp < last) { + if (*argp) + *a++ = SvPVx(*argp, n_a); else *a++ = ""; } - *a = Nullch; + *a = NULL; if ( flag_set && (a == PL_Argv + 1) - && !really && !execing ) { /* One arg? */ + && !really && execing == ASPAWN_WAIT ) { /* One arg? */ rc = do_spawn3(aTHX_ a[-1], EXECF_SPAWN_BYFLAG, flag); - } else - rc = do_spawn_ve(aTHX_ really, flag, - (execing ? EXECF_EXEC : EXECF_SPAWN), NULL, 0); + } else { + const int execf[3] = {EXECF_SPAWN, EXECF_EXEC, EXECF_SPAWN_NOWAIT}; + + rc = do_spawn_ve(aTHX_ really, flag, execf[execing], NULL, 0); + } } else rc = -1; do_execfree(); @@ -1494,14 +1520,14 @@ os2_aspawn4(pTHX_ SV *really, register SV **vmark, register SV **vsp, int execin int os2_do_aspawn(pTHX_ SV *really, register SV **vmark, register SV **vsp) { - return os2_aspawn4(aTHX_ really, vmark, vsp, 0); + return os2_aspawn_4(aTHX_ really, vmark + 1, vsp - vmark, ASPAWN_WAIT); } /* Array exec. */ bool Perl_do_aexec(pTHX_ SV* really, SV** vmark, SV** vsp) { - return os2_aspawn4(aTHX_ really, vmark, vsp, 1); + return os2_aspawn_4(aTHX_ really, vmark + 1, vsp - vmark, ASPAWN_EXEC); } int @@ -1517,7 +1543,7 @@ do_spawn_nowait(pTHX_ char *cmd) } bool -Perl_do_exec(pTHX_ char *cmd) +Perl_do_exec(pTHX_ const char *cmd) { do_spawn3(aTHX_ cmd, EXECF_EXEC, 0); return FALSE; @@ -1530,7 +1556,7 @@ os2exec(pTHX_ char *cmd) } PerlIO * -my_syspopen(pTHX_ char *cmd, char *mode) +my_syspopen4(pTHX_ char *cmd, char *mode, I32 cnt, SV** args) { #ifndef USE_POPEN int p[2]; @@ -1547,7 +1573,7 @@ my_syspopen(pTHX_ char *cmd, char *mode) taint_proper("Insecure %s%s", "EXEC"); } if (pipe(p) < 0) - return Nullfp; + return NULL; /* Now we need to spawn the child. */ if (p[this] == (*mode == 'r')) { /* if fh 0/1 was initially closed. */ int new = dup(p[this]); @@ -1566,7 +1592,7 @@ my_syspopen(pTHX_ char *cmd, char *mode) closepipes: close(p[0]); close(p[1]); - return Nullfp; + return NULL; } } else fh_fl = fcntl(*mode == 'r', F_GETFD); @@ -1578,7 +1604,10 @@ my_syspopen(pTHX_ char *cmd, char *mode) fcntl(p[this], F_SETFD, FD_CLOEXEC); if (newfd != -1) fcntl(newfd, F_SETFD, FD_CLOEXEC); - pid = do_spawn_nowait(aTHX_ cmd); + if (cnt) { /* Args: "Real cmd", before first arg, the last, execing */ + pid = os2_aspawn_4(aTHX_ NULL, args, cnt, ASPAWN_NOWAIT); + } else + pid = do_spawn_nowait(aTHX_ cmd); if (newfd == -1) close(*mode == 'r'); /* It was closed initially */ else if (newfd != (*mode == 'r')) { /* Probably this check is not needed */ @@ -1591,7 +1620,7 @@ my_syspopen(pTHX_ char *cmd, char *mode) close(p[that]); if (pid == -1) { close(p[this]); - return Nullfp; + return NULL; } if (p[that] < p[this]) { /* Make fh as small as possible */ dup2(p[this], p[that]); @@ -1609,6 +1638,9 @@ my_syspopen(pTHX_ char *cmd, char *mode) PerlIO *res; SV *sv; + if (cnt) + Perl_croak(aTHX_ "List form of piped open not implemented"); + # ifdef TRYSHELL res = popen(cmd, mode); # else @@ -1627,6 +1659,12 @@ my_syspopen(pTHX_ char *cmd, char *mode) } +PerlIO * +my_syspopen(pTHX_ char *cmd, char *mode) +{ + return my_syspopen4(aTHX_ cmd, mode, 0, NULL); +} + /******************************************************************/ #ifndef HAS_FORK @@ -1828,6 +1866,134 @@ XS(XS_File__Copy_syscopy) XSRETURN(1); } +/* APIRET APIENTRY DosReplaceModule (PCSZ pszOld, PCSZ pszNew, PCSZ pszBackup); */ + +DeclOSFuncByORD(ULONG,replaceModule,ORD_DosReplaceModule, + (char *old, char *new, char *backup), (old, new, backup)) + +XS(XS_OS2_replaceModule); /* prototype to pass -Wmissing-prototypes */ +XS(XS_OS2_replaceModule) +{ + dXSARGS; + if (items < 1 || items > 3) + Perl_croak(aTHX_ "Usage: OS2::replaceModule(target [, source [, backup]])"); + { + char * target = (char *)SvPV_nolen(ST(0)); + char * source = (items < 2) ? NULL : (char *)SvPV_nolen(ST(1)); + char * backup = (items < 3) ? NULL : (char *)SvPV_nolen(ST(2)); + + if (!replaceModule(target, source, backup)) + croak_with_os2error("replaceModule() error"); + } + XSRETURN_YES; +} + +/* APIRET APIENTRY DosPerfSysCall(ULONG ulCommand, ULONG ulParm1, + ULONG ulParm2, ULONG ulParm3); */ + +DeclOSFuncByORD(ULONG,perfSysCall,ORD_DosPerfSysCall, + (ULONG ulCommand, ULONG ulParm1, ULONG ulParm2, ULONG ulParm3), + (ulCommand, ulParm1, ulParm2, ulParm3)) + +#ifndef CMD_KI_RDCNT +# define CMD_KI_RDCNT 0x63 +#endif +#ifndef CMD_KI_GETQTY +# define CMD_KI_GETQTY 0x41 +#endif +#ifndef QSV_NUMPROCESSORS +# define QSV_NUMPROCESSORS 26 +#endif + +typedef unsigned long long myCPUUTIL[4]; /* time/idle/busy/intr */ + +/* +NO_OUTPUT ULONG +perfSysCall(ULONG ulCommand, ULONG ulParm1, ULONG ulParm2, ULONG ulParm3) + PREINIT: + ULONG rc; + POSTCALL: + if (!RETVAL) + croak_with_os2error("perfSysCall() error"); + */ + +static int +numprocessors(void) +{ + ULONG res; + + if (DosQuerySysInfo(QSV_NUMPROCESSORS, QSV_NUMPROCESSORS, (PVOID)&res, sizeof(res))) + return 1; /* Old system? */ + return res; +} + +XS(XS_OS2_perfSysCall); /* prototype to pass -Wmissing-prototypes */ +XS(XS_OS2_perfSysCall) +{ + dXSARGS; + if (items < 0 || items > 4) + Perl_croak(aTHX_ "Usage: OS2::perfSysCall(ulCommand = CMD_KI_RDCNT, ulParm1= 0, ulParm2= 0, ulParm3= 0)"); + SP -= items; + { + dXSTARG; + ULONG RETVAL, ulCommand, ulParm1, ulParm2, ulParm3, res; + myCPUUTIL u[64]; + int total = 0, tot2 = 0; + + if (items < 1) + ulCommand = CMD_KI_RDCNT; + else { + ulCommand = (ULONG)SvUV(ST(0)); + } + + if (items < 2) { + total = (ulCommand == CMD_KI_RDCNT ? numprocessors() : 0); + ulParm1 = (total ? (ULONG)u : 0); + + if (total > C_ARRAY_LENGTH(u)) + croak("Unexpected number of processors: %d", total); + } else { + ulParm1 = (ULONG)SvUV(ST(1)); + } + + if (items < 3) { + tot2 = (ulCommand == CMD_KI_GETQTY); + ulParm2 = (tot2 ? (ULONG)&res : 0); + } else { + ulParm2 = (ULONG)SvUV(ST(2)); + } + + if (items < 4) + ulParm3 = 0; + else { + ulParm3 = (ULONG)SvUV(ST(3)); + } + + RETVAL = perfSysCall(ulCommand, ulParm1, ulParm2, ulParm3); + if (!RETVAL) + croak_with_os2error("perfSysCall() error"); + XSprePUSH; + if (total) { + int i,j; + + if (GIMME_V != G_ARRAY) { + PUSHn(u[0][0]); /* Total ticks on the first processor */ + XSRETURN(1); + } + EXTEND(SP, 4*total); + for (i=0; i < total; i++) + for (j=0; j < 4; j++) + PUSHs(sv_2mortal(newSVnv(u[i][j]))); + XSRETURN(4*total); + } + if (tot2) { + PUSHu(res); + XSRETURN(1); + } + } + XSRETURN_EMPTY; +} + #define PERL_PATCHLEVEL_H_IMPLICIT /* Do not init local_patches. */ #include "patchlevel.h" #undef PERL_PATCHLEVEL_H_IMPLICIT @@ -1940,6 +2106,21 @@ os2error(int rc) case PMERR_NOT_IN_A_PM_SESSION: name = "PMERR_NOT_IN_A_PM_SESSION"; break; + case PMERR_INVALID_ATOM: + name = "PMERR_INVALID_ATOM"; + break; + case PMERR_INVALID_HATOMTBL: + name = "PMERR_INVALID_HATOMTMB"; + break; + case PMERR_INVALID_INTEGER_ATOM: + name = "PMERR_INVALID_INTEGER_ATOM"; + break; + case PMERR_INVALID_ATOM_NAME: + name = "PMERR_INVALID_ATOM_NAME"; + break; + case PMERR_ATOM_NAME_NOT_FOUND: + name = "PMERR_ATOM_NAME_NOT_FOUND"; + break; } sprintf(s, "%s%s[No description found in OSO001.MSG]", name, (*name ? "=" : "")); @@ -1969,34 +2150,50 @@ void CroakWinError(int die, char *name) { FillWinError; - if (die && Perl_rc) { - dTHX; + if (die && Perl_rc) + croak_with_os2error(name ? name : "Win* API call"); +} - Perl_croak(aTHX_ "%s: %s", (name ? name : "Win* API call"), os2error(Perl_rc)); - } +static char * +dllname2buffer(pTHX_ char *buf, STRLEN l) +{ + char *o; + STRLEN ll; + SV *dll = NULL; + + dll = module_name(mod_name_full); + o = SvPV(dll, ll); + if (ll < l) + memcpy(buf,o,ll); + SvREFCNT_dec(dll); + return (ll >= l ? "???" : buf); } -char * -os2_execname(pTHX) +static char * +execname2buffer(char *buf, STRLEN l, char *oname) { - char buf[300], *p, *o = PL_origargv[0], ok = 1; + char *p, *orig = oname, ok = oname != NULL; - if (_execname(buf, sizeof buf) != 0) - return o; + if (_execname(buf, l) != 0) { + if (!oname || strlen(oname) >= l) + return oname; + strcpy(buf, oname); + ok = 0; + } p = buf; while (*p) { if (*p == '\\') *p = '/'; if (*p == '/') { - if (ok && *o != '/' && *o != '\\') + if (ok && *oname != '/' && *oname != '\\') ok = 0; - } else if (ok && tolower(*o) != tolower(*p)) + } else if (ok && tolower(*oname) != tolower(*p)) ok = 0; p++; - o++; + oname++; } - if (ok) { /* PL_origargv[0] matches the real name. Use PL_origargv[0]: */ - strcpy(buf, PL_origargv[0]); /* _execname() is always uppercased */ + if (ok) { /* orig matches the real name. Use orig: */ + strcpy(buf, orig); /* _execname() is always uppercased */ p = buf; while (*p) { if (*p == '\\') @@ -2004,61 +2201,238 @@ os2_execname(pTHX) p++; } } - p = savepv(buf); + return buf; +} + +char * +os2_execname(pTHX) +{ + char buf[300], *p = execname2buffer(buf, sizeof buf, PL_origargv[0]); + + p = savepv(p); SAVEFREEPV(p); return p; } +int +Perl_OS2_handler_install(void *handler, enum Perlos2_handler how) +{ + char *s, b[300]; + + switch (how) { + case Perlos2_handler_mangle: + perllib_mangle_installed = (char *(*)(char *s, unsigned int l))handler; + return 1; + case Perlos2_handler_perl_sh: + s = (char *)handler; + s = dir_subst(s, strlen(s), b, sizeof b, 0, "handler_perl_sh"); + perl_sh_installed = savepv(s); + return 1; + case Perlos2_handler_perllib_from: + s = (char *)handler; + s = dir_subst(s, strlen(s), b, sizeof b, 0, "handler_perllib_from"); + oldl = strlen(s); + oldp = savepv(s); + return 1; + case Perlos2_handler_perllib_to: + s = (char *)handler; + s = dir_subst(s, strlen(s), b, sizeof b, 0, "handler_perllib_to"); + newl = strlen(s); + newp = savepv(s); + strcpy(mangle_ret, newp); + s = mangle_ret - 1; + while (*++s) + if (*s == '\\') + *s = '/'; + return 1; + default: + return 0; + } +} + +/* Returns a malloc()ed copy */ +char * +dir_subst(char *s, unsigned int l, char *b, unsigned int bl, enum dir_subst_e flags, char *msg) +{ + char *from, *to = b, *e = b; /* `to' assignment: shut down the warning */ + STRLEN froml = 0, tol = 0, rest = 0; /* froml: likewise */ + + if (l >= 2 && s[0] == '~') { + switch (s[1]) { + case 'i': case 'I': + from = "installprefix"; break; + case 'd': case 'D': + from = "dll"; break; + case 'e': case 'E': + from = "exe"; break; + default: + from = NULL; + froml = l + 1; /* Will not match */ + break; + } + if (from) + froml = strlen(from) + 1; + if (l >= froml && strnicmp(s + 2, from + 1, froml - 2) == 0) { + int strip = 1; + + switch (s[1]) { + case 'i': case 'I': + strip = 0; + tol = strlen(INSTALL_PREFIX); + if (tol >= bl) { + if (flags & dir_subst_fatal) + Perl_croak_nocontext("INSTALL_PREFIX too long: `%s'", INSTALL_PREFIX); + else + return NULL; + } + memcpy(b, INSTALL_PREFIX, tol + 1); + to = b; + e = b + tol; + break; + case 'd': case 'D': + if (flags & dir_subst_fatal) { + dTHX; + + to = dllname2buffer(aTHX_ b, bl); + } else { /* No Perl present yet */ + HMODULE self = find_myself(); + APIRET rc = DosQueryModuleName(self, bl, b); + + if (rc) + return 0; + to = b - 1; + while (*++to) + if (*to == '\\') + *to = '/'; + to = b; + } + break; + case 'e': case 'E': + if (flags & dir_subst_fatal) { + dTHX; + + to = execname2buffer(b, bl, PL_origargv[0]); + } else + to = execname2buffer(b, bl, NULL); + break; + } + if (!to) + return NULL; + if (strip) { + e = strrchr(to, '/'); + if (!e && (flags & dir_subst_fatal)) + Perl_croak_nocontext("%s: Can't parse EXE/DLL name: '%s'", msg, to); + else if (!e) + return NULL; + *e = 0; + } + s += froml; l -= froml; + if (!l) + return to; + if (!tol) + tol = strlen(to); + + while (l >= 3 && (s[0] == '/' || s[0] == '\\') + && s[1] == '.' && s[2] == '.' + && (l == 3 || s[3] == '/' || s[3] == '\\' || s[3] == ';')) { + e = strrchr(b, '/'); + if (!e && (flags & dir_subst_fatal)) + Perl_croak_nocontext("%s: Error stripping dirs from EXE/DLL/INSTALLDIR name", msg); + else if (!e) + return NULL; + *e = 0; + l -= 3; s += 3; + } + if (l && s[0] != '/' && s[0] != '\\' && s[0] != ';') + *e++ = '/'; + } + } /* Else: copy as is */ + if (l && (flags & dir_subst_pathlike)) { + STRLEN i = 0; + + while ( i < l - 2 && s[i] != ';') /* May have ~char after `;' */ + i++; + if (i < l - 2) { /* Found */ + rest = l - i - 1; + l = i + 1; + } + } + if (e + l >= b + bl) { + if (flags & dir_subst_fatal) + Perl_croak_nocontext("%s: name `%s%s' too long", msg, b, s); + else + return NULL; + } + memcpy(e, s, l); + if (rest) { + e = dir_subst(s + l, rest, e + l, bl - (e + l - b), flags, msg); + return e ? b : e; + } + e[l] = 0; + return b; +} + +char * +perllib_mangle_with(char *s, unsigned int l, char *from, unsigned int froml, char *to, unsigned int tol) +{ + if (!to) + return s; + if (l == 0) + l = strlen(s); + if (l < froml || strnicmp(from, s, froml) != 0) + return s; + if (l + tol - froml > STATIC_FILE_LENGTH || tol > STATIC_FILE_LENGTH) + Perl_croak_nocontext("Malformed PERLLIB_PREFIX"); + if (to && to != mangle_ret) + memcpy(mangle_ret, to, tol); + strcpy(mangle_ret + tol, s + froml); + return mangle_ret; +} + char * perllib_mangle(char *s, unsigned int l) { + char *name; + + if (perllib_mangle_installed && (name = perllib_mangle_installed(s,l))) + return name; if (!newp && !notfound) { - newp = getenv("PERLLIB_" STRINGIFY(PERL_REVISION) + newp = getenv(name = "PERLLIB_" STRINGIFY(PERL_REVISION) STRINGIFY(PERL_VERSION) STRINGIFY(PERL_SUBVERSION) "_PREFIX"); if (!newp) - newp = getenv("PERLLIB_" STRINGIFY(PERL_REVISION) + newp = getenv(name = "PERLLIB_" STRINGIFY(PERL_REVISION) STRINGIFY(PERL_VERSION) "_PREFIX"); if (!newp) - newp = getenv("PERLLIB_" STRINGIFY(PERL_REVISION) "_PREFIX"); + newp = getenv(name = "PERLLIB_" STRINGIFY(PERL_REVISION) "_PREFIX"); if (!newp) - newp = getenv("PERLLIB_PREFIX"); + newp = getenv(name = "PERLLIB_PREFIX"); if (newp) { - char *s; + char *s, b[300]; oldp = newp; - while (*newp && !isSPACE(*newp) && *newp != ';') { - newp++; oldl++; /* Skip digits. */ - } - while (*newp && (isSPACE(*newp) || *newp == ';')) { + while (*newp && !isSPACE(*newp) && *newp != ';') + newp++; /* Skip old name. */ + oldl = newp - oldp; + s = dir_subst(oldp, oldl, b, sizeof b, dir_subst_fatal, name); + oldp = savepv(s); + oldl = strlen(s); + while (*newp && (isSPACE(*newp) || *newp == ';')) newp++; /* Skip whitespace. */ - } - newl = strlen(newp); - if (newl == 0 || oldl == 0) { - Perl_croak_nocontext("Malformed PERLLIB_PREFIX"); - } - strcpy(mangle_ret, newp); - s = mangle_ret; - while (*s) { - if (*s == '\\') *s = '/'; - s++; - } - } else { + Perl_OS2_handler_install((void *)newp, Perlos2_handler_perllib_to); + if (newl == 0 || oldl == 0) + Perl_croak_nocontext("Malformed %s", name); + } else notfound = 1; - } } - if (!newp) { + if (!newp) return s; - } - if (l == 0) { + if (l == 0) l = strlen(s); - } - if (l < oldl || strnicmp(oldp, s, oldl) != 0) { + if (l < oldl || strnicmp(oldp, s, oldl) != 0) return s; - } - if (l + newl - oldl > STATIC_FILE_LENGTH || newl > STATIC_FILE_LENGTH) { + if (l + newl - oldl > STATIC_FILE_LENGTH || newl > STATIC_FILE_LENGTH) Perl_croak_nocontext("Malformed PERLLIB_PREFIX"); - } strcpy(mangle_ret + newl, s + oldl); return mangle_ret; } @@ -2263,6 +2637,105 @@ XS(XS_OS2_Errors2Drive) XSRETURN(1); } +int +async_mssleep(ULONG ms, int switch_priority) { + /* This is similar to DosSleep(), but has 8ms granularity in time-critical + threads even on Warp3. */ + HEV hevEvent1 = 0; /* Event semaphore handle */ + HTIMER htimerEvent1 = 0; /* Timer handle */ + APIRET rc = NO_ERROR; /* Return code */ + int ret = 1; + ULONG priority = 0, nesting; /* Shut down the warnings */ + PPIB pib; + PTIB tib; + char *e = NULL; + APIRET badrc; + + if (!(_emx_env & 0x200)) /* DOS */ + return !_sleep2(ms); + + os2cp_croak(DosCreateEventSem(NULL, /* Unnamed */ + &hevEvent1, /* Handle of semaphore returned */ + DC_SEM_SHARED, /* Shared needed for DosAsyncTimer */ + FALSE), /* Semaphore is in RESET state */ + "DosCreateEventSem"); + + if (ms >= switch_priority) + switch_priority = 0; + if (switch_priority) { + if (CheckOSError(DosGetInfoBlocks(&tib, &pib))) + switch_priority = 0; + else { + /* In Warp3, to switch scheduling to 8ms step, one needs to do + DosAsyncTimer() in time-critical thread. On laters versions, + more and more cases of wait-for-something are covered. + + It turns out that on Warp3fp42 it is the priority at the time + of DosAsyncTimer() which matters. Let's hope that this works + with later versions too... XXXX + */ + priority = (tib->tib_ptib2->tib2_ulpri); + if ((priority & 0xFF00) == 0x0300) /* already time-critical */ + switch_priority = 0; + /* Make us time-critical. Just modifying TIB is not enough... */ + /* tib->tib_ptib2->tib2_ulpri = 0x0300;*/ + /* We do not want to run at high priority if a signal causes us + to longjmp() out of this section... */ + if (DosEnterMustComplete(&nesting)) + switch_priority = 0; + else + DosSetPriority(PRTYS_THREAD, PRTYC_TIMECRITICAL, 0, 0); + } + } + + if ((badrc = DosAsyncTimer(ms, + (HSEM) hevEvent1, /* Semaphore to post */ + &htimerEvent1))) /* Timer handler (returned) */ + e = "DosAsyncTimer"; + + if (switch_priority && tib->tib_ptib2->tib2_ulpri == 0x0300) { + /* Nobody switched priority while we slept... Ignore errors... */ + /* tib->tib_ptib2->tib2_ulpri = priority; */ /* Get back... */ + if (!(rc = DosSetPriority(PRTYS_THREAD, (priority>>8) & 0xFF, 0, 0))) + rc = DosSetPriority(PRTYS_THREAD, 0, priority & 0xFF, 0); + } + if (switch_priority) + rc = DosExitMustComplete(&nesting); /* Ignore errors */ + + /* The actual blocking call is made with "normal" priority. This way we + should not bother with DosSleep(0) etc. to compensate for us interrupting + higher-priority threads. The goal is to prohibit the system spending too + much time halt()ing, not to run us "no matter what". */ + if (!e) /* Wait for AsyncTimer event */ + badrc = DosWaitEventSem(hevEvent1, SEM_INDEFINITE_WAIT); + + if (e) ; /* Do nothing */ + else if (badrc == ERROR_INTERRUPT) + ret = 0; + else if (badrc) + e = "DosWaitEventSem"; + if ((rc = DosCloseEventSem(hevEvent1)) && !e) { /* Get rid of semaphore */ + e = "DosCloseEventSem"; + badrc = rc; + } + if (e) + os2cp_croak(badrc, e); + return ret; +} + +XS(XS_OS2_ms_sleep) /* for testing only... */ +{ + dXSARGS; + ULONG ms, lim; + + if (items > 2 || items < 1) + Perl_croak_nocontext("Usage: OS2::ms_sleep(wait_ms [, high_priority_limit])"); + ms = SvUV(ST(0)); + lim = items > 1 ? SvUV(ST(1)) : ms + 1; + async_mssleep(ms, lim); + XSRETURN_YES; +} + ULONG (*pDosTmrQueryFreq) (PULONG); ULONG (*pDosTmrQueryTime) (unsigned long long *); @@ -2294,6 +2767,37 @@ XS(XS_OS2_Timer) XSRETURN(1); } +XS(XS_OS2_msCounter) +{ + dXSARGS; + + if (items != 0) + Perl_croak_nocontext("Usage: OS2::msCounter()"); + { + dXSTARG; + + XSprePUSH; PUSHu(msCounter()); + } + XSRETURN(1); +} + +XS(XS_OS2__InfoTable) +{ + dXSARGS; + int is_local = 0; + + if (items > 1) + Perl_croak_nocontext("Usage: OS2::_infoTable([isLocal])"); + if (items == 1) + is_local = (int)SvIV(ST(0)); + { + dXSTARG; + + XSprePUSH; PUSHu(InfoTable(is_local)); + } + XSRETURN(1); +} + static const char * const dc_fields[] = { "FAMILY", "IO_CAPS", @@ -2396,20 +2900,35 @@ XS(XS_OS2_DevCap) - CAPS_FAMILY + 1, si))) rc1 = Perl_rc; + else { + EXTEND(SP,2*(CAPS_DEVICE_POLYSET_POINTS - CAPS_FAMILY + 1)); + while (i < CAPS_DEVICE_POLYSET_POINTS - CAPS_FAMILY + 1) { + ST(j) = sv_newmortal(); + sv_setpv(ST(j++), dc_fields[i]); + ST(j) = sv_newmortal(); + sv_setiv(ST(j++), si[i]); + i++; + } + i = CAPS_DEVICE_POLYSET_POINTS + 1; + while (i < CAPS_DEVICE_POLYSET_POINTS + 11) { /* Just in case... */ + LONG l; + + if (CheckWinError(pDevQueryCaps(hScreenDC, i, 1, &l))) + break; + EXTEND(SP, j + 2); + ST(j) = sv_newmortal(); + sv_setiv(ST(j++), i); + ST(j) = sv_newmortal(); + sv_setiv(ST(j++), l); + i++; + } + } if (!items && CheckWinError(pDevCloseDC(hScreenDC))) Perl_warn_nocontext("DevCloseDC() failed: %s", os2error(Perl_rc)); if (rc1) Perl_rc = rc1, croak_with_os2error("DevQueryCaps() failed"); - EXTEND(SP,2*(CAPS_DEVICE_POLYSET_POINTS - CAPS_FAMILY + 1)); - while (i < CAPS_DEVICE_POLYSET_POINTS - CAPS_FAMILY + 1) { - ST(j) = sv_newmortal(); - sv_setpv(ST(j++), dc_fields[i]); - ST(j) = sv_newmortal(); - sv_setiv(ST(j++), si[i]); - i++; - } + XSRETURN(j); } - XSRETURN(2 * (CAPS_DEVICE_POLYSET_POINTS - CAPS_FAMILY + 1)); } LONG (*pWinQuerySysValue) (HWND hwndDesktop, LONG iSysValue); @@ -2607,7 +3126,7 @@ XS(XS_OS2_SysValues_set) if (CheckWinError(pWinSetSysValue(hwnd, which, val))) croak_with_os2error("SysValues_set()"); } - XSRETURN_EMPTY; + XSRETURN_YES; } #define QSV_MAX_WARP3 QSV_MAX_COMP_LENGTH @@ -2662,7 +3181,7 @@ XS(XS_OS2_SysInfo) (PVOID)si, sizeof(si)))) croak_with_os2error("DosQuerySysInfo() failed"); - while (last++ <= C_ARRAY_LENGTH(si)) { + while (++last <= C_ARRAY_LENGTH(si)) { if (CheckOSError(DosQuerySysInfo(last, last, /* One entry only */ (PVOID)(si+last-1), sizeof(*si)))) { @@ -2671,13 +3190,16 @@ XS(XS_OS2_SysInfo) break; } } - last--; + last--; /* Count of successfully processed offsets */ EXTEND(SP,2*last); while (i < last) { ST(j) = sv_newmortal(); - sv_setpv(ST(j++), si_fields[i]); + if (i < C_ARRAY_LENGTH(si_fields)) + sv_setpv(ST(j++), si_fields[i]); + else + sv_setiv(ST(j++), i + 1); ST(j) = sv_newmortal(); - sv_setiv(ST(j++), si[i]); + sv_setuv(ST(j++), si[i]); i++; } XSRETURN(2 * last); @@ -2749,7 +3271,7 @@ XS(XS_OS2_Beep) if (CheckOSError(DosBeep(freq, ms))) croak_with_os2error("SysValues_set()"); } - XSRETURN_EMPTY; + XSRETURN_YES; } @@ -2949,11 +3471,11 @@ XS(XS_Cwd_sys_cwd) XS(XS_Cwd_sys_abspath) { dXSARGS; - if (items < 1 || items > 2) - Perl_croak_nocontext("Usage: Cwd::sys_abspath(path, dir = NULL)"); + if (items > 2) + Perl_croak_nocontext("Usage: Cwd::sys_abspath(path = '.', dir = NULL)"); { STRLEN n_a; - char * path = (char *)SvPV(ST(0),n_a); + char * path = items ? (char *)SvPV(ST(0),n_a) : "."; char * dir, *s, *t, *e; char p[MAXPATHLEN]; char * RETVAL; @@ -3073,6 +3595,10 @@ XS(XS_Cwd_sys_abspath) *t = 0; SvCUR_set(sv, t - SvPVX(sv)); } +#ifndef INCOMPLETE_TAINTS + if (!items) + SvTAINTED_on(ST(0)); +#endif } XSRETURN(1); } @@ -3084,11 +3610,13 @@ typedef APIRET (*PELP)(PSZ path, ULONG type); #endif APIRET -ExtLIBPATH(ULONG ord, PSZ path, IV type) +ExtLIBPATH(ULONG ord, PSZ path, IV type, int fatal) { ULONG what; - PFN f = loadByOrdinal(ord, 1); /* Guarantied to load or die! */ + PFN f = loadByOrdinal(ord, fatal); /* if fatal: load or die! */ + if (!f) /* Impossible with fatal */ + return Perl_rc; if (type > 0) what = END_LIBPATH; else if (type == 0) @@ -3098,23 +3626,35 @@ ExtLIBPATH(ULONG ord, PSZ path, IV type) return (*(PELP)f)(path, what); } -#define extLibpath(to,type) \ - (CheckOSError(ExtLIBPATH(ORD_DosQueryExtLibpath, (to), (type))) ? NULL : (to) ) +#define extLibpath(to,type, fatal) \ + (CheckOSError(ExtLIBPATH(ORD_DosQueryExtLibpath, (to), (type), fatal)) ? NULL : (to) ) + +#define extLibpath_set(p,type, fatal) \ + (!CheckOSError(ExtLIBPATH(ORD_DosSetExtLibpath, (p), (type), fatal))) + +static void +early_error(char *msg1, char *msg2, char *msg3) +{ /* Buffer overflow detected; there is very little we can do... */ + ULONG rc; -#define extLibpath_set(p,type) \ - (!CheckOSError(ExtLIBPATH(ORD_DosSetExtLibpath, (p), (type)))) + DosWrite(2, msg1, strlen(msg1), &rc); + DosWrite(2, msg2, strlen(msg2), &rc); + DosWrite(2, msg3, strlen(msg3), &rc); + DosExit(EXIT_PROCESS, 2); +} XS(XS_Cwd_extLibpath) { dXSARGS; if (items < 0 || items > 1) - Perl_croak_nocontext("Usage: Cwd::extLibpath(type = 0)"); + Perl_croak_nocontext("Usage: OS2::extLibpath(type = 0)"); { IV type; char to[1024]; U32 rc; char * RETVAL; dXSTARG; + STRLEN l; if (items < 1) type = 0; @@ -3123,9 +3663,13 @@ XS(XS_Cwd_extLibpath) } to[0] = 1; to[1] = 0; /* Sometimes no error reported */ - RETVAL = extLibpath(to, type); + RETVAL = extLibpath(to, type, 1); /* Make errors fatal */ if (RETVAL && RETVAL[0] == 1 && RETVAL[1] == 0) - Perl_croak_nocontext("panic Cwd::extLibpath parameter"); + Perl_croak_nocontext("panic OS2::extLibpath parameter"); + l = strlen(to); + if (l >= sizeof(to)) + early_error("Buffer overflow while getting BEGIN/ENDLIBPATH: `", + to, "'\r\n"); /* Will not return */ sv_setpv(TARG, RETVAL); XSprePUSH; PUSHTARG; } @@ -3136,7 +3680,7 @@ XS(XS_Cwd_extLibpath_set) { dXSARGS; if (items < 1 || items > 2) - Perl_croak_nocontext("Usage: Cwd::extLibpath_set(s, type = 0)"); + Perl_croak_nocontext("Usage: OS2::extLibpath_set(s, type = 0)"); { STRLEN n_a; char * s = (char *)SvPV(ST(0),n_a); @@ -3150,13 +3694,74 @@ XS(XS_Cwd_extLibpath_set) type = SvIV(ST(1)); } - RETVAL = extLibpath_set(s, type); + RETVAL = extLibpath_set(s, type, 1); /* Make errors fatal */ ST(0) = boolSV(RETVAL); if (SvREFCNT(ST(0))) sv_2mortal(ST(0)); } XSRETURN(1); } +ULONG +fill_extLibpath(int type, char *pre, char *post, int replace, char *msg) +{ + char buf[2048], *to = buf, buf1[300], *s; + STRLEN l; + ULONG rc; + + if (!pre && !post) + return 0; + if (pre) { + pre = dir_subst(pre, strlen(pre), buf1, sizeof buf1, dir_subst_pathlike, msg); + if (!pre) + return ERROR_INVALID_PARAMETER; + l = strlen(pre); + if (l >= sizeof(buf)/2) + return ERROR_BUFFER_OVERFLOW; + s = pre - 1; + while (*++s) + if (*s == '/') + *s = '\\'; /* Be extra causious */ + memcpy(to, pre, l); + if (!l || to[l-1] != ';') + to[l++] = ';'; + to += l; + } + + if (!replace) { + to[0] = 1; to[1] = 0; /* Sometimes no error reported */ + rc = ExtLIBPATH(ORD_DosQueryExtLibpath, to, type, 0); /* Do not croak */ + if (rc) + return rc; + if (to[0] == 1 && to[1] == 0) + return ERROR_INVALID_PARAMETER; + to += strlen(to); + if (buf + sizeof(buf) - 1 <= to) /* Buffer overflow */ + early_error("Buffer overflow while getting BEGIN/ENDLIBPATH: `", + buf, "'\r\n"); /* Will not return */ + if (to > buf && to[-1] != ';') + *to++ = ';'; + } + if (post) { + post = dir_subst(post, strlen(post), buf1, sizeof buf1, dir_subst_pathlike, msg); + if (!post) + return ERROR_INVALID_PARAMETER; + l = strlen(post); + if (l + to - buf >= sizeof(buf) - 1) + return ERROR_BUFFER_OVERFLOW; + s = post - 1; + while (*++s) + if (*s == '/') + *s = '\\'; /* Be extra causious */ + memcpy(to, post, l); + if (!l || to[l-1] != ';') + to[l++] = ';'; + to += l; + } + *to = 0; + rc = ExtLIBPATH(ORD_DosSetExtLibpath, buf, type, 0); /* Do not croak */ + return rc; +} + /* Input: Address, BufLen APIRET APIENTRY DosQueryModFromEIP (HMODULE * hmod, ULONG * obj, ULONG BufLen, PCHAR Buf, @@ -3168,9 +3773,6 @@ DeclOSFuncByORD(APIRET, _DosQueryModFromEIP,ORD_DosQueryModFromEIP, ULONG * Offset, ULONG Address), (hmod, obj, BufLen, Buf, Offset, Address)) -enum module_name_how { mod_name_handle, mod_name_shortname, mod_name_full, - mod_name_C_function = 0x100, mod_name_HMODULE = 0x200}; - static SV* module_name_at(void *pp, enum module_name_how how) { @@ -3216,9 +3818,6 @@ module_name_of_cv(SV *cv, enum module_name_how how) return module_name_at(CvXSUB(SvRV(cv)), how); } -/* Find module name to which *this* subroutine is compiled */ -#define module_name(how) module_name_at(&module_name_at, how) - XS(XS_OS2_DLLname) { dXSARGS; @@ -3372,7 +3971,7 @@ XS(XS_OS2_mytype_set) else Perl_croak(aTHX_ "Usage: OS2::mytype_set(type)"); my_type_set(type); - XSRETURN_EMPTY; + XSRETURN_YES; } @@ -3443,6 +4042,459 @@ XS(XS_OS2_incrMaxFHandles) /* DosSetRelMaxFH */ XSRETURN(1); } +/* wait>0: force wait, wait<0: force nowait; + if restore, save/restore flags; otherwise flags are in oflags. + + Returns 1 if connected, 0 if not (due to nowait); croaks on error. */ +static ULONG +connectNPipe(ULONG hpipe, int wait, ULONG restore, ULONG oflags) +{ + ULONG ret = ERROR_INTERRUPT, rc, flags; + + if (restore && wait) + os2cp_croak(DosQueryNPHState(hpipe, &oflags), "DosQueryNPHState()"); + /* DosSetNPHState fails if more bits than NP_NOWAIT|NP_READMODE_MESSAGE */ + oflags &= (NP_NOWAIT | NP_READMODE_MESSAGE); + flags = (oflags & ~NP_NOWAIT) | (wait > 0 ? NP_WAIT : NP_NOWAIT); + /* We know (o)flags unless wait == 0 && restore */ + if (wait && (flags != oflags)) + os2cp_croak(DosSetNPHState(hpipe, flags), "DosSetNPHState()"); + while (ret == ERROR_INTERRUPT) + ret = DosConnectNPipe(hpipe); + (void)CheckOSError(ret); + if (restore && wait && (flags != oflags)) + os2cp_croak(DosSetNPHState(hpipe, oflags), "DosSetNPHState() back"); + /* We know flags unless wait == 0 && restore */ + if ( ((wait || restore) ? (flags & NP_NOWAIT) : 1) + && (ret == ERROR_PIPE_NOT_CONNECTED) ) + return 0; /* normal return value */ + if (ret == NO_ERROR) + return 1; + croak_with_os2error("DosConnectNPipe()"); +} + +/* With a lot of manual editing: +NO_OUTPUT ULONG +DosCreateNPipe(PCSZ pszName, OUTLIST HPIPE hpipe, ULONG ulOpenMode, int connect = 1, int count = 1, ULONG ulInbufLength = 8192, ULONG ulOutbufLength = ulInbufLength, ULONG ulPipeMode = count | NP_NOWAIT | NP_TYPE_BYTE | NP_READMODE_BYTE, ULONG ulTimeout = 0) + PREINIT: + ULONG rc; + C_ARGS: + pszName, &hpipe, ulOpenMode, ulPipeMode, ulInbufLength, ulOutbufLength, ulTimeout + POSTCALL: + if (CheckOSError(RETVAL)) + croak_with_os2error("OS2::mkpipe() error"); +*/ +XS(XS_OS2_pipe); /* prototype to pass -Wmissing-prototypes */ +XS(XS_OS2_pipe) +{ + dXSARGS; + if (items < 2 || items > 8) + Perl_croak(aTHX_ "Usage: OS2::pipe(pszName, ulOpenMode, connect= 1, count= 1, ulInbufLength= 8192, ulOutbufLength= ulInbufLength, ulPipeMode= count | NP_NOWAIT | NP_TYPE_BYTE | NP_READMODE_BYTE, ulTimeout= 0)"); + { + ULONG RETVAL; + PCSZ pszName = ( SvOK(ST(0)) ? (PCSZ)SvPV_nolen(ST(0)) : NULL ); + HPIPE hpipe; + SV *OpenMode = ST(1); + ULONG ulOpenMode; + int connect = 0, count, message_r = 0, message = 0, b = 0; + ULONG ulInbufLength, ulOutbufLength, ulPipeMode, ulTimeout, rc; + STRLEN len; + char *s, buf[10], *s1, *perltype = NULL; + PerlIO *perlio; + double timeout; + + if (!pszName || !*pszName) + Perl_croak(aTHX_ "OS2::pipe(): empty pipe name"); + s = SvPV(OpenMode, len); + if (len == 4 && strEQ(s, "wait")) { /* DosWaitNPipe() */ + ULONG ms = 0xFFFFFFFF, ret = ERROR_INTERRUPT; /* Indefinite */ + + if (items == 3) { + timeout = (double)SvNV(ST(2)); + ms = timeout * 1000; + if (timeout < 0) + ms = 0xFFFFFFFF; /* Indefinite */ + else if (timeout && !ms) + ms = 1; + } else if (items > 3) + Perl_croak(aTHX_ "OS2::pipe(): too many arguments for wait-for-connect: %ld", (long)items); + + while (ret == ERROR_INTERRUPT) + ret = DosWaitNPipe(pszName, ms); /* XXXX Update ms? */ + os2cp_croak(ret, "DosWaitNPipe()"); + XSRETURN_YES; + } + if (len == 4 && strEQ(s, "call")) { /* DosCallNPipe() */ + ULONG ms = 0xFFFFFFFF, got; /* Indefinite */ + STRLEN l; + char *s; + char buf[8192]; + STRLEN ll = sizeof(buf); + char *b = buf; + + if (items < 3 || items > 5) + Perl_croak(aTHX_ "usage: OS2::pipe(pszName, 'call', write [, timeout= 0xFFFFFFFF, buffsize = 8192])"); + s = SvPV(ST(2), l); + if (items >= 4) { + timeout = (double)SvNV(ST(3)); + ms = timeout * 1000; + if (timeout < 0) + ms = 0xFFFFFFFF; /* Indefinite */ + else if (timeout && !ms) + ms = 1; + } + if (items >= 5) { + STRLEN lll = SvUV(ST(4)); + SV *sv = NEWSV(914, lll); + + sv_2mortal(sv); + ll = lll; + b = SvPVX(sv); + } + + os2cp_croak(DosCallNPipe(pszName, s, l, b, ll, &got, ms), + "DosCallNPipe()"); + XSRETURN_PVN(b, got); + } + s1 = buf; + if (len && len <= 3 && !(*s >= '0' && *s <= '9')) { + int r, w, R, W; + + r = strchr(s, 'r') != 0; + w = strchr(s, 'w') != 0; + R = strchr(s, 'R') != 0; + W = strchr(s, 'W') != 0; + b = strchr(s, 'b') != 0; + if (r + w + R + W + b != len || (r && R) || (w && W)) + Perl_croak(aTHX_ "OS2::pipe(): unknown OpenMode argument: `%s'", s); + if ((r || R) && (w || W)) + ulOpenMode = NP_INHERIT | NP_NOWRITEBEHIND | NP_ACCESS_DUPLEX; + else if (r || R) + ulOpenMode = NP_INHERIT | NP_NOWRITEBEHIND | NP_ACCESS_INBOUND; + else + ulOpenMode = NP_INHERIT | NP_NOWRITEBEHIND | NP_ACCESS_OUTBOUND; + if (R) + message = message_r = 1; + if (W) + message = 1; + else if (w && R) + Perl_croak(aTHX_ "OS2::pipe(): can't have message read mode for non-message pipes"); + } else + ulOpenMode = (ULONG)SvUV(OpenMode); /* ST(1) */ + + if ( (ulOpenMode & 0x3) == NP_ACCESS_DUPLEX + || (ulOpenMode & 0x3) == NP_ACCESS_INBOUND ) + *s1++ = 'r'; + if ( (ulOpenMode & 0x3) == NP_ACCESS_DUPLEX ) + *s1++ = '+'; + if ( (ulOpenMode & 0x3) == NP_ACCESS_OUTBOUND ) + *s1++ = 'w'; + if (b) + *s1++ = 'b'; + *s1 = 0; + if ( (ulOpenMode & 0x3) == NP_ACCESS_DUPLEX ) + perltype = "+<&"; + else if ( (ulOpenMode & 0x3) == NP_ACCESS_OUTBOUND ) + perltype = ">&"; + else + perltype = "<&"; + + if (items < 3) + connect = -1; /* no wait */ + else if (SvTRUE(ST(2))) { + s = SvPV(ST(2), len); + if (len == 6 && strEQ(s, "nowait")) + connect = -1; /* no wait */ + else if (len == 4 && strEQ(s, "wait")) + connect = 1; /* wait */ + else + Perl_croak(aTHX_ "OS2::pipe(): unknown connect argument: `%s'", s); + } + + if (items < 4) + count = 1; + else + count = (int)SvIV(ST(3)); + + if (items < 5) + ulInbufLength = 8192; + else + ulInbufLength = (ULONG)SvUV(ST(4)); + + if (items < 6) + ulOutbufLength = ulInbufLength; + else + ulOutbufLength = (ULONG)SvUV(ST(5)); + + if (count < -1 || count == 0 || count >= 255) + Perl_croak(aTHX_ "OS2::pipe(): count should be -1 or between 1 and 254: %ld", (long)count); + if (count < 0 ) + count = 255; /* Unlimited */ + + ulPipeMode = count; + if (items < 7) + ulPipeMode |= (NP_WAIT + | (message ? NP_TYPE_MESSAGE : NP_TYPE_BYTE) + | (message_r ? NP_READMODE_MESSAGE : NP_READMODE_BYTE)); + else + ulPipeMode |= (ULONG)SvUV(ST(6)); + + if (items < 8) + timeout = 0; + else + timeout = (double)SvNV(ST(7)); + ulTimeout = timeout * 1000; + if (timeout < 0) + ulTimeout = 0xFFFFFFFF; /* Indefinite */ + else if (timeout && !ulTimeout) + ulTimeout = 1; + + RETVAL = DosCreateNPipe(pszName, &hpipe, ulOpenMode, ulPipeMode, ulInbufLength, ulOutbufLength, ulTimeout); + if (CheckOSError(RETVAL)) + croak_with_os2error("OS2::pipe(): DosCreateNPipe() error"); + + if (connect) + connectNPipe(hpipe, connect, 1, 0); /* XXXX wait, retval */ + hpipe = __imphandle(hpipe); + + perlio = PerlIO_fdopen(hpipe, buf); + ST(0) = sv_newmortal(); + { + GV *gv = newGVgen("OS2::pipe"); + if ( do_open(gv, perltype, strlen(perltype), FALSE, 0, 0, perlio) ) + sv_setsv(ST(0), sv_bless(newRV((SV*)gv), gv_stashpv("IO::Handle",1))); + else + ST(0) = &PL_sv_undef; + } + } + XSRETURN(1); +} + +XS(XS_OS2_pipeCntl); /* prototype to pass -Wmissing-prototypes */ +XS(XS_OS2_pipeCntl) +{ + dXSARGS; + if (items < 2 || items > 3) + Perl_croak(aTHX_ "Usage: OS2::pipeCntl(pipe, op [, wait])"); + { + ULONG rc; + PerlIO *perlio = IoIFP(sv_2io(ST(0))); + IV fn = PerlIO_fileno(perlio); + HPIPE hpipe = (HPIPE)fn; + STRLEN len; + char *s = SvPV(ST(1), len); + int wait = 0, disconnect = 0, connect = 0, message = -1, query = 0; + int peek = 0, state = 0, info = 0; + + if (fn < 0) + Perl_croak(aTHX_ "OS2::pipeCntl(): not a pipe"); + if (items == 3) + wait = (SvTRUE(ST(2)) ? 1 : -1); + + switch (len) { + case 4: + if (strEQ(s, "byte")) + message = 0; + else if (strEQ(s, "peek")) + peek = 1; + else if (strEQ(s, "info")) + info = 1; + else + goto unknown; + break; + case 5: + if (strEQ(s, "reset")) + disconnect = connect = 1; + else if (strEQ(s, "state")) + query = 1; + else + goto unknown; + break; + case 7: + if (strEQ(s, "connect")) + connect = 1; + else if (strEQ(s, "message")) + message = 1; + else + goto unknown; + break; + case 9: + if (!strEQ(s, "readstate")) + goto unknown; + state = 1; + break; + case 10: + if (!strEQ(s, "disconnect")) + goto unknown; + disconnect = 1; + break; + default: + unknown: + Perl_croak(aTHX_ "OS2::pipeCntl(): unknown argument: `%s'", s); + break; + } + + if (items == 3 && !connect) + Perl_croak(aTHX_ "OS2::pipeCntl(): no wait argument for `%s'", s); + + XSprePUSH; /* Do not need arguments any more */ + if (disconnect) { + os2cp_croak(DosDisConnectNPipe(hpipe), "OS2::pipeCntl(): DosDisConnectNPipe()"); + PerlIO_clearerr(perlio); + } + if (connect) { + if (!connectNPipe(hpipe, wait , 1, 0)) + XSRETURN_IV(-1); + } + if (query) { + ULONG flags; + + os2cp_croak(DosQueryNPHState(hpipe, &flags), "DosQueryNPHState()"); + XSRETURN_UV(flags); + } + if (peek || state || info) { + ULONG BytesRead, PipeState; + AVAILDATA BytesAvail; + + os2cp_croak( DosPeekNPipe(hpipe, NULL, 0, &BytesRead, &BytesAvail, + &PipeState), "DosPeekNPipe() for state"); + if (state) { + EXTEND(SP, 3); + mPUSHu(PipeState); + /* Bytes (available/in-message) */ + mPUSHi(BytesAvail.cbpipe); + mPUSHi(BytesAvail.cbmessage); + XSRETURN(3); + } else if (info) { + /* L S S C C C/Z* + ID of the (remote) computer + buffers (out/in) + instances (max/actual) + */ + struct pipe_info_t { + ULONG id; /* char id[4]; */ + PIPEINFO pInfo; + char buf[512]; + } b; + int size; + + os2cp_croak( DosQueryNPipeInfo(hpipe, 1, &b.pInfo, sizeof(b) - STRUCT_OFFSET(struct pipe_info_t, pInfo)), + "DosQueryNPipeInfo(1)"); + os2cp_croak( DosQueryNPipeInfo(hpipe, 2, &b.id, sizeof(b.id)), + "DosQueryNPipeInfo(2)"); + size = b.pInfo.cbName; + /* Trailing 0 is included in cbName - undocumented; so + one should always extract with Z* */ + if (size) /* name length 254 or less */ + size--; + else + size = strlen(b.pInfo.szName); + EXTEND(SP, 6); + mPUSHp(b.pInfo.szName, size); + mPUSHu(b.id); + mPUSHi(b.pInfo.cbOut); + mPUSHi(b.pInfo.cbIn); + mPUSHi(b.pInfo.cbMaxInst); + mPUSHi(b.pInfo.cbCurInst); + XSRETURN(6); + } else if (BytesAvail.cbpipe == 0) { + XSRETURN_NO; + } else { + SV *tmp = NEWSV(914, BytesAvail.cbpipe); + char *s = SvPVX(tmp); + + sv_2mortal(tmp); + os2cp_croak( DosPeekNPipe(hpipe, s, BytesAvail.cbpipe, &BytesRead, + &BytesAvail, &PipeState), "DosPeekNPipe()"); + SvCUR_set(tmp, BytesRead); + *SvEND(tmp) = 0; + SvPOK_on(tmp); + XSprePUSH; PUSHs(tmp); + XSRETURN(1); + } + } + if (message > -1) { + ULONG oflags, flags; + + os2cp_croak(DosQueryNPHState(hpipe, &oflags), "DosQueryNPHState()"); + /* DosSetNPHState fails if more bits than NP_NOWAIT|NP_READMODE_MESSAGE */ + oflags &= (NP_NOWAIT | NP_READMODE_MESSAGE); + flags = (oflags & NP_NOWAIT) + | (message ? NP_READMODE_MESSAGE : NP_READMODE_BYTE); + if (flags != oflags) + os2cp_croak(DosSetNPHState(hpipe, flags), "DosSetNPHState()"); + } + } + XSRETURN_YES; +} + +/* +NO_OUTPUT ULONG +DosOpen(PCSZ pszFileName, OUTLIST HFILE hFile, OUTLIST ULONG ulAction, ULONG ulOpenFlags, ULONG ulOpenMode = OPEN_ACTION_OPEN_IF_EXISTS | OPEN_ACTION_FAIL_IF_NEW, ULONG ulAttribute = FILE_NORMAL, ULONG ulFileSize = 0, PEAOP2 pEABuf = NULL); + PREINIT: + ULONG rc; + C_ARGS: + pszFileName, &hFile, &ulAction, ulFileSize, ulAttribute, ulOpenFlags, ulOpenMode, pEABuf + POSTCALL: + if (CheckOSError(RETVAL)) + croak_with_os2error("OS2::open() error"); +*/ +XS(XS_OS2_open); /* prototype to pass -Wmissing-prototypes */ +XS(XS_OS2_open) +{ + dXSARGS; + if (items < 2 || items > 6) + Perl_croak(aTHX_ "Usage: OS2::open(pszFileName, ulOpenMode, ulOpenFlags= OPEN_ACTION_OPEN_IF_EXISTS | OPEN_ACTION_FAIL_IF_NEW, ulAttribute= FILE_NORMAL, ulFileSize= 0, pEABuf= NULL)"); + { +#line 39 "pipe.xs" + ULONG rc; +#line 113 "pipe.c" + ULONG RETVAL; + PCSZ pszFileName = ( SvOK(ST(0)) ? (PCSZ)SvPV_nolen(ST(0)) : NULL ); + HFILE hFile; + ULONG ulAction; + ULONG ulOpenMode = (ULONG)SvUV(ST(1)); + ULONG ulOpenFlags; + ULONG ulAttribute; + ULONG ulFileSize; + PEAOP2 pEABuf; + + if (items < 3) + ulOpenFlags = OPEN_ACTION_OPEN_IF_EXISTS | OPEN_ACTION_FAIL_IF_NEW; + else { + ulOpenFlags = (ULONG)SvUV(ST(2)); + } + + if (items < 4) + ulAttribute = FILE_NORMAL; + else { + ulAttribute = (ULONG)SvUV(ST(3)); + } + + if (items < 5) + ulFileSize = 0; + else { + ulFileSize = (ULONG)SvUV(ST(4)); + } + + if (items < 6) + pEABuf = NULL; + else { + pEABuf = (PEAOP2)SvUV(ST(5)); + } + + RETVAL = DosOpen(pszFileName, &hFile, &ulAction, ulFileSize, ulAttribute, ulOpenFlags, ulOpenMode, pEABuf); + if (CheckOSError(RETVAL)) + croak_with_os2error("OS2::open() error"); + XSprePUSH; EXTEND(SP,2); + PUSHs(sv_newmortal()); + sv_setuv(ST(0), (UV)hFile); + PUSHs(sv_newmortal()); + sv_setuv(ST(1), (UV)ulAction); + } + XSRETURN(2); +} + int Xs_OS2_init(pTHX) { @@ -3454,6 +4506,8 @@ Xs_OS2_init(pTHX) newXS("File::Copy::syscopy", XS_File__Copy_syscopy, file); newXS("Cwd::extLibpath", XS_Cwd_extLibpath, file); newXS("Cwd::extLibpath_set", XS_Cwd_extLibpath_set, file); + newXS("OS2::extLibpath", XS_Cwd_extLibpath, file); + newXS("OS2::extLibpath_set", XS_Cwd_extLibpath_set, file); } newXS("OS2::Error", XS_OS2_Error, file); newXS("OS2::Errors2Drive", XS_OS2_Errors2Drive, file); @@ -3474,6 +4528,8 @@ Xs_OS2_init(pTHX) newXS("Cwd::sys_is_relative", XS_Cwd_sys_is_relative, file); newXS("Cwd::sys_cwd", XS_Cwd_sys_cwd, file); newXS("Cwd::sys_abspath", XS_Cwd_sys_abspath, file); + newXS("OS2::replaceModule", XS_OS2_replaceModule, file); + newXS("OS2::perfSysCall", XS_OS2_perfSysCall, file); newXSproto("OS2::_control87", XS_OS2__control87, file, "$$"); newXSproto("OS2::get_control87", XS_OS2_get_control87, file, ""); newXSproto("OS2::set_control87", XS_OS2_set_control87, file, ";$$"); @@ -3483,15 +4539,26 @@ Xs_OS2_init(pTHX) newXSproto("OS2::_headerInfo", XS_OS2__headerInfo, file, "$$;$$"); newXSproto("OS2::libPath", XS_OS2_libPath, file, ""); newXSproto("OS2::Timer", XS_OS2_Timer, file, ""); + newXSproto("OS2::msCounter", XS_OS2_msCounter, file, ""); + newXSproto("OS2::ms_sleep", XS_OS2_ms_sleep, file, "$;$"); + newXSproto("OS2::_InfoTable", XS_OS2__InfoTable, file, ";$"); newXSproto("OS2::incrMaxFHandles", XS_OS2_incrMaxFHandles, file, ";$"); newXSproto("OS2::SysValues", XS_OS2_SysValues, file, ";$$"); newXSproto("OS2::SysValues_set", XS_OS2_SysValues_set, file, "$$;$"); newXSproto("OS2::Beep", XS_OS2_Beep, file, ";$$"); + newXSproto("OS2::pipe", XS_OS2_pipe, file, "$$;$$$$$$"); + newXSproto("OS2::pipeCntl", XS_OS2_pipeCntl, file, "$$;$"); + newXSproto("OS2::open", XS_OS2_open, file, "$$;$$$$"); gv = gv_fetchpv("OS2::is_aout", TRUE, SVt_PV); GvMULTI_on(gv); #ifdef PERL_IS_AOUT sv_setiv(GvSV(gv), 1); #endif + gv = gv_fetchpv("OS2::is_static", TRUE, SVt_PV); + GvMULTI_on(gv); +#ifdef PERL_IS_AOUT + sv_setiv(GvSV(gv), 1); +#endif gv = gv_fetchpv("OS2::can_fork", TRUE, SVt_PV); GvMULTI_on(gv); sv_setiv(GvSV(gv), exe_is_aout()); @@ -3599,6 +4666,12 @@ force_init_emx_runtime(EXCEPTIONREGISTRATIONRECORD *preg, ULONG flags) oldstack = tib->tib_pstack; oldstackend = tib->tib_pstacklimit; + if ( (char*)&s < (char*)oldstack + 4*1024 + || (char *)oldstackend < (char*)oldstack + 52*1024 ) + early_error("It is a lunacy to try to run EMX Perl ", + "with less than 64K of stack;\r\n", + " at least with non-EMX starter...\r\n"); + /* Minimize the damage to the stack via reducing the size of argv. */ if (flags & FORCE_EMX_INIT_CONTRACT_ARGV) { pib->pib_pchcmd = "\0\0"; /* Need 3 concatenated strings */ @@ -3721,7 +4794,7 @@ extern ULONG __os_version(); /* See system.doc */ void check_emx_runtime(char **env, EXCEPTIONREGISTRATIONRECORD *preg) { - ULONG v_crt, v_emx, count = 0, rc, rc1, maybe_inited = 0; + ULONG v_crt, v_emx, count = 0, rc = NO_ERROR, rc1, maybe_inited = 0; static HMTX hmtx_emx_init = NULLHANDLE; static int emx_init_done = 0; @@ -3812,7 +4885,7 @@ check_emx_runtime(char **env, EXCEPTIONREGISTRATIONRECORD *preg) c++; e = e + strlen(e) + 1; } - New(1307, env, c + 1, char*); + Newx(env, c + 1, char*); ep = env; e = pib->pib_pchenv; while (c--) { @@ -3858,7 +4931,8 @@ Perl_OS2_init(char **env) void Perl_OS2_init3(char **env, void **preg, int flags) { - char *shell; + char *shell, *s; + ULONG rc; _uflags (_UF_SBRK_MODEL, _UF_SBRK_ARBITRARY); MALLOC_INIT; @@ -3867,16 +4941,21 @@ Perl_OS2_init3(char **env, void **preg, int flags) settmppath(); OS2_Perl_data.xs_init = &Xs_OS2_init; - if ( (shell = getenv("PERL_SH_DRIVE")) ) { - New(1304, PL_sh_path, strlen(SH_PATH) + 1, char); + if (perl_sh_installed) { + int l = strlen(perl_sh_installed); + + Newx(PL_sh_path, l + 1, char); + memcpy(PL_sh_path, perl_sh_installed, l + 1); + } else if ( (shell = getenv("PERL_SH_DRIVE")) ) { + Newx(PL_sh_path, strlen(SH_PATH) + 1, char); strcpy(PL_sh_path, SH_PATH); PL_sh_path[0] = shell[0]; } else if ( (shell = getenv("PERL_SH_DIR")) ) { int l = strlen(shell), i; - if (shell[l-1] == '/' || shell[l-1] == '\\') { + + while (l && (shell[l-1] == '/' || shell[l-1] == '\\')) l--; - } - New(1304, PL_sh_path, l + 8, char); + Newx(PL_sh_path, l + 8, char); strncpy(PL_sh_path, shell, l); strcpy(PL_sh_path + l, "/sh.exe"); for (i = 0; i < l; i++) { @@ -3890,10 +4969,67 @@ Perl_OS2_init3(char **env, void **preg, int flags) os2_mytype = my_type(); /* Do it before morphing. Needed? */ os2_mytype_ini = os2_mytype; Perl_os2_initial_mode = -1; /* Uninit */ + + s = getenv("PERL_BEGINLIBPATH"); + if (s) + rc = fill_extLibpath(0, s, NULL, 1, "PERL_BEGINLIBPATH"); + else + rc = fill_extLibpath(0, getenv("PERL_PRE_BEGINLIBPATH"), getenv("PERL_POST_BEGINLIBPATH"), 0, "PERL_(PRE/POST)_BEGINLIBPATH"); + if (!rc) { + s = getenv("PERL_ENDLIBPATH"); + if (s) + rc = fill_extLibpath(1, s, NULL, 1, "PERL_ENDLIBPATH"); + else + rc = fill_extLibpath(1, getenv("PERL_PRE_ENDLIBPATH"), getenv("PERL_POST_ENDLIBPATH"), 0, "PERL_(PRE/POST)_ENDLIBPATH"); + } + if (rc) { + char buf[1024]; + + snprintf(buf, sizeof buf, "Error setting BEGIN/ENDLIBPATH: %s\n", + os2error(rc)); + DosWrite(2, buf, strlen(buf), &rc); + exit(2); + } + + _emxload_env("PERL_EMXLOAD_SECS"); /* Some DLLs reset FP flags on load. We may have been linked with them */ _control87(MCW_EM, MCW_EM); } +int +fd_ok(int fd) +{ + static ULONG max_fh = 0; + + if (!(_emx_env & 0x200)) return 1; /* not OS/2. */ + if (fd >= max_fh) { /* Renew */ + LONG delta = 0; + + if (DosSetRelMaxFH(&delta, &max_fh)) /* Assume it OK??? */ + return 1; + } + return fd < max_fh; +} + +/* Kernels up to Oct 2003 trap on (invalid) dup(max_fh); [off-by-one + double fault]. */ +int +dup2(int from, int to) +{ + if (fd_ok(from < to ? to : from)) + return _dup2(from, to); + errno = EBADF; + return -1; +} + +int +dup(int from) +{ + if (fd_ok(from)) + return _dup(from); + errno = EBADF; + return -1; +} + #undef tmpnam #undef tmpfile @@ -3939,7 +5075,7 @@ my_rmdir (__const__ char *s) if (s[l-1] == '/' || s[l-1] == '\\') { /* EMX mkdir fails... */ if (l >= sizeof b) - New(1305, buf, l + 1, char); + Newx(buf, l + 1, char); strcpy(buf,s); while (l > 1 && (s[l-1] == '/' || s[l-1] == '\\')) l--; @@ -3964,7 +5100,7 @@ my_mkdir (__const__ char *s, long perm) if (s[l-1] == '/' || s[l-1] == '\\') { /* EMX mkdir fails... */ if (l >= sizeof b) - New(1305, buf, l + 1, char); + Newx(buf, l + 1, char); strcpy(buf,s); while (l > 1 && (s[l-1] == '/' || s[l-1] == '\\')) l--; @@ -4284,3 +5420,52 @@ int fork_with_resources() return rc; } +/* APIRET APIENTRY DosGetInfoSeg(PSEL pselGlobal, PSEL pselLocal); */ + +ULONG _THUNK_FUNCTION(Dos16GetInfoSeg)(USHORT *pGlobal, USHORT *pLocal); + +APIRET APIENTRY +myDosGetInfoSeg(PGINFOSEG *pGlobal, PLINFOSEG *pLocal) +{ + APIRET rc; + USHORT gSel, lSel; /* Will not cross 64K boundary */ + + rc = ((USHORT) + (_THUNK_PROLOG (4+4); + _THUNK_FLAT (&gSel); + _THUNK_FLAT (&lSel); + _THUNK_CALL (Dos16GetInfoSeg))); + if (rc) + return rc; + *pGlobal = MAKEPGINFOSEG(gSel); + *pLocal = MAKEPLINFOSEG(lSel); + return rc; +} + +static void +GetInfoTables(void) +{ + ULONG rc = 0; + + MUTEX_LOCK(&perlos2_state_mutex); + if (!gTable) + rc = myDosGetInfoSeg(&gTable, &lTable); + MUTEX_UNLOCK(&perlos2_state_mutex); + os2cp_croak(rc, "Dos16GetInfoSeg"); +} + +ULONG +msCounter(void) +{ /* XXXX Is not lTable thread-specific? */ + if (!gTable) + GetInfoTables(); + return gTable->SIS_MsCount; +} + +ULONG +InfoTable(int local) +{ + if (!gTable) + GetInfoTables(); + return local ? (ULONG)lTable : (ULONG)gTable; +}