| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403 |
- /*
- * QuickJS C library
- *
- * Copyright (c) 2017-2021 Fabrice Bellard
- * Copyright (c) 2017-2021 Charlie Gordon
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
- #include <stdlib.h>
- #include <stdio.h>
- #include <stdarg.h>
- #include <inttypes.h>
- #include <string.h>
- #include <assert.h>
- #include <unistd.h>
- #include <errno.h>
- #include <fcntl.h>
- #include <sys/time.h>
- #include <time.h>
- #include <signal.h>
- #include <limits.h>
- #include <sys/stat.h>
- #include <dirent.h>
- #if defined(_WIN32)
- #include <windows.h>
- #include <conio.h>
- #include <utime.h>
- #else
- #include <dlfcn.h>
- #include <termios.h>
- #include <sys/ioctl.h>
- #include <sys/wait.h>
- #include <poll.h>
- #if defined(__FreeBSD__)
- extern char **environ;
- #endif
- #if defined(__APPLE__) || defined(__FreeBSD__)
- typedef sig_t sighandler_t;
- #endif
- #if defined(__APPLE__)
- #if !defined(environ)
- #include <crt_externs.h>
- #define environ (*_NSGetEnviron())
- #endif
- #endif /* __APPLE__ */
- #endif
- /* enable the os.Worker API. It relies on POSIX threads */
- #define USE_WORKER
- #ifdef USE_WORKER
- #include <pthread.h>
- #include <stdatomic.h>
- #endif
- #include "cutils.h"
- #include "list.h"
- #include "quickjs-libc.h"
- #if !defined(PATH_MAX)
- #define PATH_MAX 4096
- #endif
- /* TODO:
- - add socket calls
- */
- typedef struct {
- struct list_head link;
- int fd;
- int poll_fd_index; /* temporary use in js_os_poll() */
- JSValue rw_func[2];
- } JSOSRWHandler;
- typedef struct {
- struct list_head link;
- int sig_num;
- JSValue func;
- } JSOSSignalHandler;
- typedef struct {
- struct list_head link;
- int timer_id;
- int64_t timeout;
- JSValue func;
- } JSOSTimer;
- typedef struct {
- struct list_head link;
- uint8_t *data;
- size_t data_len;
- /* list of SharedArrayBuffers, necessary to free the message */
- uint8_t **sab_tab;
- size_t sab_tab_len;
- } JSWorkerMessage;
- typedef struct JSWaker {
- #ifdef _WIN32
- HANDLE handle;
- #else
- int read_fd;
- int write_fd;
- #endif
- } JSWaker;
- typedef struct {
- int ref_count;
- #ifdef USE_WORKER
- pthread_mutex_t mutex;
- #endif
- struct list_head msg_queue; /* list of JSWorkerMessage.link */
- JSWaker waker;
- } JSWorkerMessagePipe;
- typedef struct {
- struct list_head link;
- JSWorkerMessagePipe *recv_pipe;
- JSValue on_message_func;
- int poll_fd_index; /* temporary use in js_os_poll() */
- } JSWorkerMessageHandler;
- typedef struct {
- struct list_head link;
- JSValue promise;
- JSValue reason;
- } JSRejectedPromiseEntry;
- typedef struct JSThreadState {
- struct list_head os_rw_handlers; /* list of JSOSRWHandler.link */
- struct list_head os_signal_handlers; /* list JSOSSignalHandler.link */
- struct list_head os_timers; /* list of JSOSTimer.link */
- struct list_head port_list; /* list of JSWorkerMessageHandler.link */
- struct list_head rejected_promise_list; /* list of JSRejectedPromiseEntry.link */
- int eval_script_recurse; /* only used in the main thread */
- int next_timer_id; /* for setTimeout() */
- /* not used in the main thread */
- JSWorkerMessagePipe *recv_pipe, *send_pipe;
- #if !defined(_WIN32)
- struct pollfd *poll_fds;
- int poll_fds_size;
- #endif
- } JSThreadState;
- static uint64_t os_pending_signals;
- static int (*os_poll_func)(JSContext *ctx);
- static void js_std_dbuf_init(JSContext *ctx, DynBuf *s)
- {
- dbuf_init2(s, JS_GetRuntime(ctx), (DynBufReallocFunc *)js_realloc_rt);
- }
- static BOOL my_isdigit(int c)
- {
- return (c >= '0' && c <= '9');
- }
- /* XXX: use 'o' and 'O' for object using JS_PrintValue() ? */
- static JSValue js_printf_internal(JSContext *ctx,
- int argc, JSValueConst *argv, FILE *fp)
- {
- char fmtbuf[32];
- uint8_t cbuf[UTF8_CHAR_LEN_MAX+1];
- JSValue res;
- DynBuf dbuf;
- const char *fmt_str = NULL;
- const uint8_t *fmt, *fmt_end;
- const uint8_t *p;
- char *q;
- int i, c, len, mod;
- size_t fmt_len;
- int32_t int32_arg;
- int64_t int64_arg;
- double double_arg;
- const char *string_arg;
- /* Use indirect call to dbuf_printf to prevent gcc warning */
- int (*dbuf_printf_fun)(DynBuf *s, const char *fmt, ...) = (void*)dbuf_printf;
- js_std_dbuf_init(ctx, &dbuf);
- if (argc > 0) {
- fmt_str = JS_ToCStringLen(ctx, &fmt_len, argv[0]);
- if (!fmt_str)
- goto fail;
- i = 1;
- fmt = (const uint8_t *)fmt_str;
- fmt_end = fmt + fmt_len;
- while (fmt < fmt_end) {
- for (p = fmt; fmt < fmt_end && *fmt != '%'; fmt++)
- continue;
- dbuf_put(&dbuf, p, fmt - p);
- if (fmt >= fmt_end)
- break;
- q = fmtbuf;
- *q++ = *fmt++; /* copy '%' */
- /* flags */
- for(;;) {
- c = *fmt;
- if (c == '0' || c == '#' || c == '+' || c == '-' || c == ' ' ||
- c == '\'') {
- if (q >= fmtbuf + sizeof(fmtbuf) - 1)
- goto invalid;
- *q++ = c;
- fmt++;
- } else {
- break;
- }
- }
- /* width */
- if (*fmt == '*') {
- if (i >= argc)
- goto missing;
- if (JS_ToInt32(ctx, &int32_arg, argv[i++]))
- goto fail;
- q += snprintf(q, fmtbuf + sizeof(fmtbuf) - q, "%d", int32_arg);
- fmt++;
- } else {
- while (my_isdigit(*fmt)) {
- if (q >= fmtbuf + sizeof(fmtbuf) - 1)
- goto invalid;
- *q++ = *fmt++;
- }
- }
- if (*fmt == '.') {
- if (q >= fmtbuf + sizeof(fmtbuf) - 1)
- goto invalid;
- *q++ = *fmt++;
- if (*fmt == '*') {
- if (i >= argc)
- goto missing;
- if (JS_ToInt32(ctx, &int32_arg, argv[i++]))
- goto fail;
- q += snprintf(q, fmtbuf + sizeof(fmtbuf) - q, "%d", int32_arg);
- fmt++;
- } else {
- while (my_isdigit(*fmt)) {
- if (q >= fmtbuf + sizeof(fmtbuf) - 1)
- goto invalid;
- *q++ = *fmt++;
- }
- }
- }
- /* we only support the "l" modifier for 64 bit numbers */
- mod = ' ';
- if (*fmt == 'l') {
- mod = *fmt++;
- }
- /* type */
- c = *fmt++;
- if (q >= fmtbuf + sizeof(fmtbuf) - 1)
- goto invalid;
- *q++ = c;
- *q = '\0';
- switch (c) {
- case 'c':
- if (i >= argc)
- goto missing;
- if (JS_IsString(argv[i])) {
- string_arg = JS_ToCString(ctx, argv[i++]);
- if (!string_arg)
- goto fail;
- int32_arg = unicode_from_utf8((const uint8_t *)string_arg, UTF8_CHAR_LEN_MAX, &p);
- JS_FreeCString(ctx, string_arg);
- } else {
- if (JS_ToInt32(ctx, &int32_arg, argv[i++]))
- goto fail;
- }
- /* handle utf-8 encoding explicitly */
- if ((unsigned)int32_arg > 0x10FFFF)
- int32_arg = 0xFFFD;
- /* ignore conversion flags, width and precision */
- len = unicode_to_utf8(cbuf, int32_arg);
- dbuf_put(&dbuf, cbuf, len);
- break;
- case 'd':
- case 'i':
- case 'o':
- case 'u':
- case 'x':
- case 'X':
- if (i >= argc)
- goto missing;
- if (JS_ToInt64Ext(ctx, &int64_arg, argv[i++]))
- goto fail;
- if (mod == 'l') {
- /* 64 bit number */
- #if defined(_WIN32)
- if (q >= fmtbuf + sizeof(fmtbuf) - 3)
- goto invalid;
- q[2] = q[-1];
- q[-1] = 'I';
- q[0] = '6';
- q[1] = '4';
- q[3] = '\0';
- dbuf_printf_fun(&dbuf, fmtbuf, (int64_t)int64_arg);
- #else
- if (q >= fmtbuf + sizeof(fmtbuf) - 2)
- goto invalid;
- q[1] = q[-1];
- q[-1] = q[0] = 'l';
- q[2] = '\0';
- dbuf_printf_fun(&dbuf, fmtbuf, (long long)int64_arg);
- #endif
- } else {
- dbuf_printf_fun(&dbuf, fmtbuf, (int)int64_arg);
- }
- break;
- case 's':
- if (i >= argc)
- goto missing;
- /* XXX: handle strings containing null characters */
- string_arg = JS_ToCString(ctx, argv[i++]);
- if (!string_arg)
- goto fail;
- dbuf_printf_fun(&dbuf, fmtbuf, string_arg);
- JS_FreeCString(ctx, string_arg);
- break;
- case 'e':
- case 'f':
- case 'g':
- case 'a':
- case 'E':
- case 'F':
- case 'G':
- case 'A':
- if (i >= argc)
- goto missing;
- if (JS_ToFloat64(ctx, &double_arg, argv[i++]))
- goto fail;
- dbuf_printf_fun(&dbuf, fmtbuf, double_arg);
- break;
- case '%':
- dbuf_putc(&dbuf, '%');
- break;
- default:
- /* XXX: should support an extension mechanism */
- invalid:
- JS_ThrowTypeError(ctx, "invalid conversion specifier in format string");
- goto fail;
- missing:
- JS_ThrowReferenceError(ctx, "missing argument for conversion specifier");
- goto fail;
- }
- }
- JS_FreeCString(ctx, fmt_str);
- }
- if (dbuf.error) {
- res = JS_ThrowOutOfMemory(ctx);
- } else {
- if (fp) {
- len = fwrite(dbuf.buf, 1, dbuf.size, fp);
- res = JS_NewInt32(ctx, len);
- } else {
- res = JS_NewStringLen(ctx, (char *)dbuf.buf, dbuf.size);
- }
- }
- dbuf_free(&dbuf);
- return res;
- fail:
- JS_FreeCString(ctx, fmt_str);
- dbuf_free(&dbuf);
- return JS_EXCEPTION;
- }
- uint8_t *js_load_file(JSContext *ctx, size_t *pbuf_len, const char *filename)
- {
- FILE *f;
- uint8_t *buf;
- size_t buf_len;
- long lret;
- f = fopen(filename, "rb");
- if (!f)
- return NULL;
- if (fseek(f, 0, SEEK_END) < 0)
- goto fail;
- lret = ftell(f);
- if (lret < 0)
- goto fail;
- /* XXX: on Linux, ftell() return LONG_MAX for directories */
- if (lret == LONG_MAX) {
- errno = EISDIR;
- goto fail;
- }
- buf_len = lret;
- if (fseek(f, 0, SEEK_SET) < 0)
- goto fail;
- if (ctx)
- buf = js_malloc(ctx, buf_len + 1);
- else
- buf = malloc(buf_len + 1);
- if (!buf)
- goto fail;
- if (fread(buf, 1, buf_len, f) != buf_len) {
- errno = EIO;
- if (ctx)
- js_free(ctx, buf);
- else
- free(buf);
- fail:
- fclose(f);
- return NULL;
- }
- buf[buf_len] = '\0';
- fclose(f);
- *pbuf_len = buf_len;
- return buf;
- }
- /* load and evaluate a file */
- static JSValue js_loadScript(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- uint8_t *buf;
- const char *filename;
- JSValue ret;
- size_t buf_len;
- filename = JS_ToCString(ctx, argv[0]);
- if (!filename)
- return JS_EXCEPTION;
- buf = js_load_file(ctx, &buf_len, filename);
- if (!buf) {
- JS_ThrowReferenceError(ctx, "could not load '%s'", filename);
- JS_FreeCString(ctx, filename);
- return JS_EXCEPTION;
- }
- ret = JS_Eval(ctx, (char *)buf, buf_len, filename,
- JS_EVAL_TYPE_GLOBAL);
- js_free(ctx, buf);
- JS_FreeCString(ctx, filename);
- return ret;
- }
- /* load a file as a UTF-8 encoded string */
- static JSValue js_std_loadFile(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- uint8_t *buf;
- const char *filename;
- JSValue ret;
- size_t buf_len;
- filename = JS_ToCString(ctx, argv[0]);
- if (!filename)
- return JS_EXCEPTION;
- buf = js_load_file(ctx, &buf_len, filename);
- JS_FreeCString(ctx, filename);
- if (!buf)
- return JS_NULL;
- ret = JS_NewStringLen(ctx, (char *)buf, buf_len);
- js_free(ctx, buf);
- return ret;
- }
- typedef JSModuleDef *(JSInitModuleFunc)(JSContext *ctx,
- const char *module_name);
- #if defined(_WIN32)
- static JSModuleDef *js_module_loader_so(JSContext *ctx,
- const char *module_name)
- {
- JS_ThrowReferenceError(ctx, "shared library modules are not supported yet");
- return NULL;
- }
- #else
- static JSModuleDef *js_module_loader_so(JSContext *ctx,
- const char *module_name)
- {
- JSModuleDef *m;
- void *hd;
- JSInitModuleFunc *init;
- char *filename;
- if (!strchr(module_name, '/')) {
- /* must add a '/' so that the DLL is not searched in the
- system library paths */
- filename = js_malloc(ctx, strlen(module_name) + 2 + 1);
- if (!filename)
- return NULL;
- strcpy(filename, "./");
- strcpy(filename + 2, module_name);
- } else {
- filename = (char *)module_name;
- }
- /* C module */
- hd = dlopen(filename, RTLD_NOW | RTLD_LOCAL);
- if (filename != module_name)
- js_free(ctx, filename);
- if (!hd) {
- JS_ThrowReferenceError(ctx, "could not load module filename '%s' as shared library",
- module_name);
- goto fail;
- }
- init = dlsym(hd, "js_init_module");
- if (!init) {
- JS_ThrowReferenceError(ctx, "could not load module filename '%s': js_init_module not found",
- module_name);
- goto fail;
- }
- m = init(ctx, module_name);
- if (!m) {
- JS_ThrowReferenceError(ctx, "could not load module filename '%s': initialization error",
- module_name);
- fail:
- if (hd)
- dlclose(hd);
- return NULL;
- }
- return m;
- }
- #endif /* !_WIN32 */
- int js_module_set_import_meta(JSContext *ctx, JSValueConst func_val,
- JS_BOOL use_realpath, JS_BOOL is_main)
- {
- JSModuleDef *m;
- char buf[PATH_MAX + 16];
- JSValue meta_obj;
- JSAtom module_name_atom;
- const char *module_name;
- assert(JS_VALUE_GET_TAG(func_val) == JS_TAG_MODULE);
- m = JS_VALUE_GET_PTR(func_val);
- module_name_atom = JS_GetModuleName(ctx, m);
- module_name = JS_AtomToCString(ctx, module_name_atom);
- JS_FreeAtom(ctx, module_name_atom);
- if (!module_name)
- return -1;
- if (!strchr(module_name, ':')) {
- strcpy(buf, "file://");
- #if !defined(_WIN32)
- /* realpath() cannot be used with modules compiled with qjsc
- because the corresponding module source code is not
- necessarily present */
- if (use_realpath) {
- char *res = realpath(module_name, buf + strlen(buf));
- if (!res) {
- JS_ThrowTypeError(ctx, "realpath failure");
- JS_FreeCString(ctx, module_name);
- return -1;
- }
- } else
- #endif
- {
- pstrcat(buf, sizeof(buf), module_name);
- }
- } else {
- pstrcpy(buf, sizeof(buf), module_name);
- }
- JS_FreeCString(ctx, module_name);
- meta_obj = JS_GetImportMeta(ctx, m);
- if (JS_IsException(meta_obj))
- return -1;
- JS_DefinePropertyValueStr(ctx, meta_obj, "url",
- JS_NewString(ctx, buf),
- JS_PROP_C_W_E);
- JS_DefinePropertyValueStr(ctx, meta_obj, "main",
- JS_NewBool(ctx, is_main),
- JS_PROP_C_W_E);
- JS_FreeValue(ctx, meta_obj);
- return 0;
- }
- static int json_module_init(JSContext *ctx, JSModuleDef *m)
- {
- JSValue val;
- val = JS_GetModulePrivateValue(ctx, m);
- JS_SetModuleExport(ctx, m, "default", val);
- return 0;
- }
- static JSModuleDef *create_json_module(JSContext *ctx, const char *module_name, JSValue val)
- {
- JSModuleDef *m;
- m = JS_NewCModule(ctx, module_name, json_module_init);
- if (!m) {
- JS_FreeValue(ctx, val);
- return NULL;
- }
- /* only export the "default" symbol which will contain the JSON object */
- JS_AddModuleExport(ctx, m, "default");
- JS_SetModulePrivateValue(ctx, m, val);
- return m;
- }
- /* in order to conform with the specification, only the keys should be
- tested and not the associated values. */
- int js_module_check_attributes(JSContext *ctx, void *opaque,
- JSValueConst attributes)
- {
- JSPropertyEnum *tab;
- uint32_t i, len;
- int ret;
- const char *cstr;
- size_t cstr_len;
-
- if (JS_GetOwnPropertyNames(ctx, &tab, &len, attributes, JS_GPN_ENUM_ONLY | JS_GPN_STRING_MASK))
- return -1;
- ret = 0;
- for(i = 0; i < len; i++) {
- cstr = JS_AtomToCStringLen(ctx, &cstr_len, tab[i].atom);
- if (!cstr) {
- ret = -1;
- break;
- }
- if (!(cstr_len == 4 && !memcmp(cstr, "type", cstr_len))) {
- JS_ThrowTypeError(ctx, "import attribute '%s' is not supported", cstr);
- ret = -1;
- }
- JS_FreeCString(ctx, cstr);
- if (ret)
- break;
- }
- JS_FreePropertyEnum(ctx, tab, len);
- return ret;
- }
- /* return > 0 if the attributes indicate a JSON module */
- int js_module_test_json(JSContext *ctx, JSValueConst attributes)
- {
- JSValue str;
- const char *cstr;
- size_t len;
- BOOL res;
- if (JS_IsUndefined(attributes))
- return FALSE;
- str = JS_GetPropertyStr(ctx, attributes, "type");
- if (!JS_IsString(str))
- return FALSE;
- cstr = JS_ToCStringLen(ctx, &len, str);
- JS_FreeValue(ctx, str);
- if (!cstr)
- return FALSE;
- /* XXX: raise an error if unknown type ? */
- if (len == 4 && !memcmp(cstr, "json", len)) {
- res = 1;
- } else if (len == 5 && !memcmp(cstr, "json5", len)) {
- res = 2;
- } else {
- res = 0;
- }
- JS_FreeCString(ctx, cstr);
- return res;
- }
- JSModuleDef *js_module_loader(JSContext *ctx,
- const char *module_name, void *opaque,
- JSValueConst attributes)
- {
- JSModuleDef *m;
- int res;
-
- if (has_suffix(module_name, ".so")) {
- m = js_module_loader_so(ctx, module_name);
- } else {
- size_t buf_len;
- uint8_t *buf;
- buf = js_load_file(ctx, &buf_len, module_name);
- if (!buf) {
- JS_ThrowReferenceError(ctx, "could not load module filename '%s'",
- module_name);
- return NULL;
- }
- res = js_module_test_json(ctx, attributes);
- if (has_suffix(module_name, ".json") || res > 0) {
- /* compile as JSON or JSON5 depending on "type" */
- JSValue val;
- int flags;
- if (res == 2)
- flags = JS_PARSE_JSON_EXT;
- else
- flags = 0;
- val = JS_ParseJSON2(ctx, (char *)buf, buf_len, module_name, flags);
- js_free(ctx, buf);
- if (JS_IsException(val))
- return NULL;
- m = create_json_module(ctx, module_name, val);
- if (!m)
- return NULL;
- } else {
- JSValue func_val;
- /* compile the module */
- func_val = JS_Eval(ctx, (char *)buf, buf_len, module_name,
- JS_EVAL_TYPE_MODULE | JS_EVAL_FLAG_COMPILE_ONLY);
- js_free(ctx, buf);
- if (JS_IsException(func_val))
- return NULL;
- /* XXX: could propagate the exception */
- js_module_set_import_meta(ctx, func_val, TRUE, FALSE);
- /* the module is already referenced, so we must free it */
- m = JS_VALUE_GET_PTR(func_val);
- JS_FreeValue(ctx, func_val);
- }
- }
- return m;
- }
- static JSValue js_std_exit(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- int status;
- if (JS_ToInt32(ctx, &status, argv[0]))
- status = -1;
- exit(status);
- return JS_UNDEFINED;
- }
- static JSValue js_std_getenv(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- const char *name, *str;
- name = JS_ToCString(ctx, argv[0]);
- if (!name)
- return JS_EXCEPTION;
- str = getenv(name);
- JS_FreeCString(ctx, name);
- if (!str)
- return JS_UNDEFINED;
- else
- return JS_NewString(ctx, str);
- }
- #if defined(_WIN32)
- static void setenv(const char *name, const char *value, int overwrite)
- {
- char *str;
- size_t name_len, value_len;
- name_len = strlen(name);
- value_len = strlen(value);
- str = malloc(name_len + 1 + value_len + 1);
- memcpy(str, name, name_len);
- str[name_len] = '=';
- memcpy(str + name_len + 1, value, value_len);
- str[name_len + 1 + value_len] = '\0';
- _putenv(str);
- free(str);
- }
- static void unsetenv(const char *name)
- {
- setenv(name, "", TRUE);
- }
- #endif /* _WIN32 */
- static JSValue js_std_setenv(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- const char *name, *value;
- name = JS_ToCString(ctx, argv[0]);
- if (!name)
- return JS_EXCEPTION;
- value = JS_ToCString(ctx, argv[1]);
- if (!value) {
- JS_FreeCString(ctx, name);
- return JS_EXCEPTION;
- }
- setenv(name, value, TRUE);
- JS_FreeCString(ctx, name);
- JS_FreeCString(ctx, value);
- return JS_UNDEFINED;
- }
- static JSValue js_std_unsetenv(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- const char *name;
- name = JS_ToCString(ctx, argv[0]);
- if (!name)
- return JS_EXCEPTION;
- unsetenv(name);
- JS_FreeCString(ctx, name);
- return JS_UNDEFINED;
- }
- /* return an object containing the list of the available environment
- variables. */
- static JSValue js_std_getenviron(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- char **envp;
- const char *name, *p, *value;
- JSValue obj;
- uint32_t idx;
- size_t name_len;
- JSAtom atom;
- int ret;
- obj = JS_NewObject(ctx);
- if (JS_IsException(obj))
- return JS_EXCEPTION;
- envp = environ;
- for(idx = 0; envp[idx] != NULL; idx++) {
- name = envp[idx];
- p = strchr(name, '=');
- name_len = p - name;
- if (!p)
- continue;
- value = p + 1;
- atom = JS_NewAtomLen(ctx, name, name_len);
- if (atom == JS_ATOM_NULL)
- goto fail;
- ret = JS_DefinePropertyValue(ctx, obj, atom, JS_NewString(ctx, value),
- JS_PROP_C_W_E);
- JS_FreeAtom(ctx, atom);
- if (ret < 0)
- goto fail;
- }
- return obj;
- fail:
- JS_FreeValue(ctx, obj);
- return JS_EXCEPTION;
- }
- static JSValue js_std_gc(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JS_RunGC(JS_GetRuntime(ctx));
- return JS_UNDEFINED;
- }
- static int interrupt_handler(JSRuntime *rt, void *opaque)
- {
- return (os_pending_signals >> SIGINT) & 1;
- }
- static int get_bool_option(JSContext *ctx, BOOL *pbool,
- JSValueConst obj,
- const char *option)
- {
- JSValue val;
- val = JS_GetPropertyStr(ctx, obj, option);
- if (JS_IsException(val))
- return -1;
- if (!JS_IsUndefined(val)) {
- *pbool = JS_ToBool(ctx, val);
- }
- JS_FreeValue(ctx, val);
- return 0;
- }
- static JSValue js_evalScript(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSRuntime *rt = JS_GetRuntime(ctx);
- JSThreadState *ts = JS_GetRuntimeOpaque(rt);
- const char *str;
- size_t len;
- JSValue ret;
- JSValueConst options_obj;
- BOOL backtrace_barrier = FALSE;
- BOOL is_async = FALSE;
- int flags;
- if (argc >= 2) {
- options_obj = argv[1];
- if (get_bool_option(ctx, &backtrace_barrier, options_obj,
- "backtrace_barrier"))
- return JS_EXCEPTION;
- if (get_bool_option(ctx, &is_async, options_obj,
- "async"))
- return JS_EXCEPTION;
- }
- str = JS_ToCStringLen(ctx, &len, argv[0]);
- if (!str)
- return JS_EXCEPTION;
- if (!ts->recv_pipe && ++ts->eval_script_recurse == 1) {
- /* install the interrupt handler */
- JS_SetInterruptHandler(JS_GetRuntime(ctx), interrupt_handler, NULL);
- }
- flags = JS_EVAL_TYPE_GLOBAL;
- if (backtrace_barrier)
- flags |= JS_EVAL_FLAG_BACKTRACE_BARRIER;
- if (is_async)
- flags |= JS_EVAL_FLAG_ASYNC;
- ret = JS_Eval(ctx, str, len, "<evalScript>", flags);
- JS_FreeCString(ctx, str);
- if (!ts->recv_pipe && --ts->eval_script_recurse == 0) {
- /* remove the interrupt handler */
- JS_SetInterruptHandler(JS_GetRuntime(ctx), NULL, NULL);
- os_pending_signals &= ~((uint64_t)1 << SIGINT);
- /* convert the uncatchable "interrupted" error into a normal error
- so that it can be caught by the REPL */
- if (JS_IsException(ret))
- JS_SetUncatchableException(ctx, FALSE);
- }
- return ret;
- }
- static JSClassID js_std_file_class_id;
- typedef struct {
- FILE *f;
- BOOL close_in_finalizer;
- BOOL is_popen;
- } JSSTDFile;
- static void js_std_file_finalizer(JSRuntime *rt, JSValue val)
- {
- JSSTDFile *s = JS_GetOpaque(val, js_std_file_class_id);
- if (s) {
- if (s->f && s->close_in_finalizer) {
- if (s->is_popen)
- pclose(s->f);
- else
- fclose(s->f);
- }
- js_free_rt(rt, s);
- }
- }
- static ssize_t js_get_errno(ssize_t ret)
- {
- if (ret == -1)
- ret = -errno;
- return ret;
- }
- static JSValue js_std_strerror(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- int err;
- if (JS_ToInt32(ctx, &err, argv[0]))
- return JS_EXCEPTION;
- return JS_NewString(ctx, strerror(err));
- }
- static JSValue js_std_parseExtJSON(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSValue obj;
- const char *str;
- size_t len;
- str = JS_ToCStringLen(ctx, &len, argv[0]);
- if (!str)
- return JS_EXCEPTION;
- obj = JS_ParseJSON2(ctx, str, len, "<input>", JS_PARSE_JSON_EXT);
- JS_FreeCString(ctx, str);
- return obj;
- }
- static JSValue js_new_std_file(JSContext *ctx, FILE *f,
- BOOL close_in_finalizer,
- BOOL is_popen)
- {
- JSSTDFile *s;
- JSValue obj;
- obj = JS_NewObjectClass(ctx, js_std_file_class_id);
- if (JS_IsException(obj))
- return obj;
- s = js_mallocz(ctx, sizeof(*s));
- if (!s) {
- JS_FreeValue(ctx, obj);
- return JS_EXCEPTION;
- }
- s->close_in_finalizer = close_in_finalizer;
- s->is_popen = is_popen;
- s->f = f;
- JS_SetOpaque(obj, s);
- return obj;
- }
- static void js_set_error_object(JSContext *ctx, JSValue obj, int err)
- {
- if (!JS_IsUndefined(obj)) {
- JS_SetPropertyStr(ctx, obj, "errno", JS_NewInt32(ctx, err));
- }
- }
- static JSValue js_std_open(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- const char *filename, *mode = NULL;
- FILE *f;
- int err;
- filename = JS_ToCString(ctx, argv[0]);
- if (!filename)
- goto fail;
- mode = JS_ToCString(ctx, argv[1]);
- if (!mode)
- goto fail;
- if (mode[strspn(mode, "rwa+b")] != '\0') {
- JS_ThrowTypeError(ctx, "invalid file mode");
- goto fail;
- }
- f = fopen(filename, mode);
- if (!f)
- err = errno;
- else
- err = 0;
- if (argc >= 3)
- js_set_error_object(ctx, argv[2], err);
- JS_FreeCString(ctx, filename);
- JS_FreeCString(ctx, mode);
- if (!f)
- return JS_NULL;
- return js_new_std_file(ctx, f, TRUE, FALSE);
- fail:
- JS_FreeCString(ctx, filename);
- JS_FreeCString(ctx, mode);
- return JS_EXCEPTION;
- }
- static JSValue js_std_popen(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- const char *filename, *mode = NULL;
- FILE *f;
- int err;
- filename = JS_ToCString(ctx, argv[0]);
- if (!filename)
- goto fail;
- mode = JS_ToCString(ctx, argv[1]);
- if (!mode)
- goto fail;
- if (mode[strspn(mode, "rw")] != '\0') {
- JS_ThrowTypeError(ctx, "invalid file mode");
- goto fail;
- }
- f = popen(filename, mode);
- if (!f)
- err = errno;
- else
- err = 0;
- if (argc >= 3)
- js_set_error_object(ctx, argv[2], err);
- JS_FreeCString(ctx, filename);
- JS_FreeCString(ctx, mode);
- if (!f)
- return JS_NULL;
- return js_new_std_file(ctx, f, TRUE, TRUE);
- fail:
- JS_FreeCString(ctx, filename);
- JS_FreeCString(ctx, mode);
- return JS_EXCEPTION;
- }
- static JSValue js_std_fdopen(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- const char *mode;
- FILE *f;
- int fd, err;
- if (JS_ToInt32(ctx, &fd, argv[0]))
- return JS_EXCEPTION;
- mode = JS_ToCString(ctx, argv[1]);
- if (!mode)
- goto fail;
- if (mode[strspn(mode, "rwa+")] != '\0') {
- JS_ThrowTypeError(ctx, "invalid file mode");
- goto fail;
- }
- f = fdopen(fd, mode);
- if (!f)
- err = errno;
- else
- err = 0;
- if (argc >= 3)
- js_set_error_object(ctx, argv[2], err);
- JS_FreeCString(ctx, mode);
- if (!f)
- return JS_NULL;
- return js_new_std_file(ctx, f, TRUE, FALSE);
- fail:
- JS_FreeCString(ctx, mode);
- return JS_EXCEPTION;
- }
- static JSValue js_std_tmpfile(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- FILE *f;
- f = tmpfile();
- if (argc >= 1)
- js_set_error_object(ctx, argv[0], f ? 0 : errno);
- if (!f)
- return JS_NULL;
- return js_new_std_file(ctx, f, TRUE, FALSE);
- }
- static JSValue js_std_sprintf(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- return js_printf_internal(ctx, argc, argv, NULL);
- }
- static JSValue js_std_printf(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- return js_printf_internal(ctx, argc, argv, stdout);
- }
- static FILE *js_std_file_get(JSContext *ctx, JSValueConst obj)
- {
- JSSTDFile *s = JS_GetOpaque2(ctx, obj, js_std_file_class_id);
- if (!s)
- return NULL;
- if (!s->f) {
- JS_ThrowTypeError(ctx, "invalid file handle");
- return NULL;
- }
- return s->f;
- }
- static JSValue js_std_file_puts(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv, int magic)
- {
- FILE *f;
- int i;
- const char *str;
- size_t len;
- if (magic == 0) {
- f = stdout;
- } else {
- f = js_std_file_get(ctx, this_val);
- if (!f)
- return JS_EXCEPTION;
- }
- for(i = 0; i < argc; i++) {
- str = JS_ToCStringLen(ctx, &len, argv[i]);
- if (!str)
- return JS_EXCEPTION;
- fwrite(str, 1, len, f);
- JS_FreeCString(ctx, str);
- }
- return JS_UNDEFINED;
- }
- static JSValue js_std_file_close(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSSTDFile *s = JS_GetOpaque2(ctx, this_val, js_std_file_class_id);
- int err;
- if (!s)
- return JS_EXCEPTION;
- if (!s->f)
- return JS_ThrowTypeError(ctx, "invalid file handle");
- if (s->is_popen)
- err = js_get_errno(pclose(s->f));
- else
- err = js_get_errno(fclose(s->f));
- s->f = NULL;
- return JS_NewInt32(ctx, err);
- }
- static JSValue js_std_file_printf(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- FILE *f = js_std_file_get(ctx, this_val);
- if (!f)
- return JS_EXCEPTION;
- return js_printf_internal(ctx, argc, argv, f);
- }
- static void js_print_value_write(void *opaque, const char *buf, size_t len)
- {
- FILE *fo = opaque;
- fwrite(buf, 1, len, fo);
- }
- static JSValue js_std_file_printObject(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JS_PrintValue(ctx, js_print_value_write, stdout, argv[0], NULL);
- return JS_UNDEFINED;
- }
- static JSValue js_std_file_flush(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- FILE *f = js_std_file_get(ctx, this_val);
- if (!f)
- return JS_EXCEPTION;
- fflush(f);
- return JS_UNDEFINED;
- }
- static JSValue js_std_file_tell(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv, int is_bigint)
- {
- FILE *f = js_std_file_get(ctx, this_val);
- int64_t pos;
- if (!f)
- return JS_EXCEPTION;
- #if defined(__linux__) || defined(__GLIBC__)
- pos = ftello(f);
- #else
- pos = ftell(f);
- #endif
- if (is_bigint)
- return JS_NewBigInt64(ctx, pos);
- else
- return JS_NewInt64(ctx, pos);
- }
- static JSValue js_std_file_seek(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- FILE *f = js_std_file_get(ctx, this_val);
- int64_t pos;
- int whence, ret;
- if (!f)
- return JS_EXCEPTION;
- if (JS_ToInt64Ext(ctx, &pos, argv[0]))
- return JS_EXCEPTION;
- if (JS_ToInt32(ctx, &whence, argv[1]))
- return JS_EXCEPTION;
- #if defined(__linux__) || defined(__GLIBC__)
- ret = fseeko(f, pos, whence);
- #else
- ret = fseek(f, pos, whence);
- #endif
- if (ret < 0)
- ret = -errno;
- return JS_NewInt32(ctx, ret);
- }
- static JSValue js_std_file_eof(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- FILE *f = js_std_file_get(ctx, this_val);
- if (!f)
- return JS_EXCEPTION;
- return JS_NewBool(ctx, feof(f));
- }
- static JSValue js_std_file_error(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- FILE *f = js_std_file_get(ctx, this_val);
- if (!f)
- return JS_EXCEPTION;
- return JS_NewBool(ctx, ferror(f));
- }
- static JSValue js_std_file_clearerr(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- FILE *f = js_std_file_get(ctx, this_val);
- if (!f)
- return JS_EXCEPTION;
- clearerr(f);
- return JS_UNDEFINED;
- }
- static JSValue js_std_file_fileno(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- FILE *f = js_std_file_get(ctx, this_val);
- if (!f)
- return JS_EXCEPTION;
- return JS_NewInt32(ctx, fileno(f));
- }
- static JSValue js_std_file_read_write(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv, int magic)
- {
- FILE *f = js_std_file_get(ctx, this_val);
- uint64_t pos, len;
- size_t size, ret;
- uint8_t *buf;
- if (!f)
- return JS_EXCEPTION;
- if (JS_ToIndex(ctx, &pos, argv[1]))
- return JS_EXCEPTION;
- if (JS_ToIndex(ctx, &len, argv[2]))
- return JS_EXCEPTION;
- buf = JS_GetArrayBuffer(ctx, &size, argv[0]);
- if (!buf)
- return JS_EXCEPTION;
- if (pos + len > size)
- return JS_ThrowRangeError(ctx, "read/write array buffer overflow");
- if (magic)
- ret = fwrite(buf + pos, 1, len, f);
- else
- ret = fread(buf + pos, 1, len, f);
- return JS_NewInt64(ctx, ret);
- }
- /* XXX: could use less memory and go faster */
- static JSValue js_std_file_getline(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- FILE *f = js_std_file_get(ctx, this_val);
- int c;
- DynBuf dbuf;
- JSValue obj;
- if (!f)
- return JS_EXCEPTION;
- js_std_dbuf_init(ctx, &dbuf);
- for(;;) {
- c = fgetc(f);
- if (c == EOF) {
- if (dbuf.size == 0) {
- /* EOF */
- dbuf_free(&dbuf);
- return JS_NULL;
- } else {
- break;
- }
- }
- if (c == '\n')
- break;
- if (dbuf_putc(&dbuf, c)) {
- dbuf_free(&dbuf);
- return JS_ThrowOutOfMemory(ctx);
- }
- }
- obj = JS_NewStringLen(ctx, (const char *)dbuf.buf, dbuf.size);
- dbuf_free(&dbuf);
- return obj;
- }
- /* XXX: could use less memory and go faster */
- static JSValue js_std_file_readAsString(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- FILE *f = js_std_file_get(ctx, this_val);
- int c;
- DynBuf dbuf;
- JSValue obj;
- uint64_t max_size64;
- size_t max_size;
- JSValueConst max_size_val;
- if (!f)
- return JS_EXCEPTION;
- if (argc >= 1)
- max_size_val = argv[0];
- else
- max_size_val = JS_UNDEFINED;
- max_size = (size_t)-1;
- if (!JS_IsUndefined(max_size_val)) {
- if (JS_ToIndex(ctx, &max_size64, max_size_val))
- return JS_EXCEPTION;
- if (max_size64 < max_size)
- max_size = max_size64;
- }
- js_std_dbuf_init(ctx, &dbuf);
- while (max_size != 0) {
- c = fgetc(f);
- if (c == EOF)
- break;
- if (dbuf_putc(&dbuf, c)) {
- dbuf_free(&dbuf);
- return JS_EXCEPTION;
- }
- max_size--;
- }
- obj = JS_NewStringLen(ctx, (const char *)dbuf.buf, dbuf.size);
- dbuf_free(&dbuf);
- return obj;
- }
- static JSValue js_std_file_getByte(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- FILE *f = js_std_file_get(ctx, this_val);
- if (!f)
- return JS_EXCEPTION;
- return JS_NewInt32(ctx, fgetc(f));
- }
- static JSValue js_std_file_putByte(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- FILE *f = js_std_file_get(ctx, this_val);
- int c;
- if (!f)
- return JS_EXCEPTION;
- if (JS_ToInt32(ctx, &c, argv[0]))
- return JS_EXCEPTION;
- c = fputc(c, f);
- return JS_NewInt32(ctx, c);
- }
- /* urlGet */
- #define URL_GET_PROGRAM "curl -s -i --"
- #define URL_GET_BUF_SIZE 4096
- static int http_get_header_line(FILE *f, char *buf, size_t buf_size,
- DynBuf *dbuf)
- {
- int c;
- char *p;
- p = buf;
- for(;;) {
- c = fgetc(f);
- if (c < 0)
- return -1;
- if ((p - buf) < buf_size - 1)
- *p++ = c;
- if (dbuf)
- dbuf_putc(dbuf, c);
- if (c == '\n')
- break;
- }
- *p = '\0';
- return 0;
- }
- static int http_get_status(const char *buf)
- {
- const char *p = buf;
- while (*p != ' ' && *p != '\0')
- p++;
- if (*p != ' ')
- return 0;
- while (*p == ' ')
- p++;
- return atoi(p);
- }
- static JSValue js_std_urlGet(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- const char *url;
- DynBuf cmd_buf;
- DynBuf data_buf_s, *data_buf = &data_buf_s;
- DynBuf header_buf_s, *header_buf = &header_buf_s;
- char *buf;
- size_t i, len;
- int status;
- JSValue response = JS_UNDEFINED, ret_obj;
- JSValueConst options_obj;
- FILE *f;
- BOOL binary_flag, full_flag;
- url = JS_ToCString(ctx, argv[0]);
- if (!url)
- return JS_EXCEPTION;
- binary_flag = FALSE;
- full_flag = FALSE;
- if (argc >= 2) {
- options_obj = argv[1];
- if (get_bool_option(ctx, &binary_flag, options_obj, "binary"))
- goto fail_obj;
- if (get_bool_option(ctx, &full_flag, options_obj, "full")) {
- fail_obj:
- JS_FreeCString(ctx, url);
- return JS_EXCEPTION;
- }
- }
- js_std_dbuf_init(ctx, &cmd_buf);
- dbuf_printf(&cmd_buf, "%s '", URL_GET_PROGRAM);
- for(i = 0; url[i] != '\0'; i++) {
- unsigned char c = url[i];
- switch (c) {
- case '\'':
- /* shell single quoted string does not support \' */
- dbuf_putstr(&cmd_buf, "'\\''");
- break;
- case '[': case ']': case '{': case '}': case '\\':
- /* prevent interpretation by curl as range or set specification */
- dbuf_putc(&cmd_buf, '\\');
- /* FALLTHROUGH */
- default:
- dbuf_putc(&cmd_buf, c);
- break;
- }
- }
- JS_FreeCString(ctx, url);
- dbuf_putstr(&cmd_buf, "'");
- dbuf_putc(&cmd_buf, '\0');
- if (dbuf_error(&cmd_buf)) {
- dbuf_free(&cmd_buf);
- return JS_EXCEPTION;
- }
- // printf("%s\n", (char *)cmd_buf.buf);
- f = popen((char *)cmd_buf.buf, "r");
- dbuf_free(&cmd_buf);
- if (!f) {
- return JS_ThrowTypeError(ctx, "could not start curl");
- }
- js_std_dbuf_init(ctx, data_buf);
- js_std_dbuf_init(ctx, header_buf);
- buf = js_malloc(ctx, URL_GET_BUF_SIZE);
- if (!buf)
- goto fail;
- /* get the HTTP status */
- if (http_get_header_line(f, buf, URL_GET_BUF_SIZE, NULL) < 0) {
- status = 0;
- goto bad_header;
- }
- status = http_get_status(buf);
- if (!full_flag && !(status >= 200 && status <= 299)) {
- goto bad_header;
- }
- /* wait until there is an empty line */
- for(;;) {
- if (http_get_header_line(f, buf, URL_GET_BUF_SIZE, header_buf) < 0) {
- bad_header:
- response = JS_NULL;
- goto done;
- }
- if (!strcmp(buf, "\r\n"))
- break;
- }
- if (dbuf_error(header_buf))
- goto fail;
- header_buf->size -= 2; /* remove the trailing CRLF */
- /* download the data */
- for(;;) {
- len = fread(buf, 1, URL_GET_BUF_SIZE, f);
- if (len == 0)
- break;
- dbuf_put(data_buf, (uint8_t *)buf, len);
- }
- if (dbuf_error(data_buf))
- goto fail;
- if (binary_flag) {
- response = JS_NewArrayBufferCopy(ctx,
- data_buf->buf, data_buf->size);
- } else {
- response = JS_NewStringLen(ctx, (char *)data_buf->buf, data_buf->size);
- }
- if (JS_IsException(response))
- goto fail;
- done:
- js_free(ctx, buf);
- buf = NULL;
- pclose(f);
- f = NULL;
- dbuf_free(data_buf);
- data_buf = NULL;
- if (full_flag) {
- ret_obj = JS_NewObject(ctx);
- if (JS_IsException(ret_obj))
- goto fail;
- JS_DefinePropertyValueStr(ctx, ret_obj, "response",
- response,
- JS_PROP_C_W_E);
- if (!JS_IsNull(response)) {
- JS_DefinePropertyValueStr(ctx, ret_obj, "responseHeaders",
- JS_NewStringLen(ctx, (char *)header_buf->buf,
- header_buf->size),
- JS_PROP_C_W_E);
- JS_DefinePropertyValueStr(ctx, ret_obj, "status",
- JS_NewInt32(ctx, status),
- JS_PROP_C_W_E);
- }
- } else {
- ret_obj = response;
- }
- dbuf_free(header_buf);
- return ret_obj;
- fail:
- if (f)
- pclose(f);
- js_free(ctx, buf);
- if (data_buf)
- dbuf_free(data_buf);
- if (header_buf)
- dbuf_free(header_buf);
- JS_FreeValue(ctx, response);
- return JS_EXCEPTION;
- }
- static JSClassDef js_std_file_class = {
- "FILE",
- .finalizer = js_std_file_finalizer,
- };
- static const JSCFunctionListEntry js_std_error_props[] = {
- /* various errno values */
- #define DEF(x) JS_PROP_INT32_DEF(#x, x, JS_PROP_CONFIGURABLE )
- DEF(EINVAL),
- DEF(EIO),
- DEF(EACCES),
- DEF(EEXIST),
- DEF(ENOSPC),
- DEF(ENOSYS),
- DEF(EBUSY),
- DEF(ENOENT),
- DEF(EPERM),
- DEF(EPIPE),
- DEF(EBADF),
- #undef DEF
- };
- static const JSCFunctionListEntry js_std_funcs[] = {
- JS_CFUNC_DEF("exit", 1, js_std_exit ),
- JS_CFUNC_DEF("gc", 0, js_std_gc ),
- JS_CFUNC_DEF("evalScript", 1, js_evalScript ),
- JS_CFUNC_DEF("loadScript", 1, js_loadScript ),
- JS_CFUNC_DEF("getenv", 1, js_std_getenv ),
- JS_CFUNC_DEF("setenv", 1, js_std_setenv ),
- JS_CFUNC_DEF("unsetenv", 1, js_std_unsetenv ),
- JS_CFUNC_DEF("getenviron", 1, js_std_getenviron ),
- JS_CFUNC_DEF("urlGet", 1, js_std_urlGet ),
- JS_CFUNC_DEF("loadFile", 1, js_std_loadFile ),
- JS_CFUNC_DEF("strerror", 1, js_std_strerror ),
- JS_CFUNC_DEF("parseExtJSON", 1, js_std_parseExtJSON ),
- /* FILE I/O */
- JS_CFUNC_DEF("open", 2, js_std_open ),
- JS_CFUNC_DEF("popen", 2, js_std_popen ),
- JS_CFUNC_DEF("fdopen", 2, js_std_fdopen ),
- JS_CFUNC_DEF("tmpfile", 0, js_std_tmpfile ),
- JS_CFUNC_MAGIC_DEF("puts", 1, js_std_file_puts, 0 ),
- JS_CFUNC_DEF("printf", 1, js_std_printf ),
- JS_CFUNC_DEF("sprintf", 1, js_std_sprintf ),
- JS_PROP_INT32_DEF("SEEK_SET", SEEK_SET, JS_PROP_CONFIGURABLE ),
- JS_PROP_INT32_DEF("SEEK_CUR", SEEK_CUR, JS_PROP_CONFIGURABLE ),
- JS_PROP_INT32_DEF("SEEK_END", SEEK_END, JS_PROP_CONFIGURABLE ),
- JS_OBJECT_DEF("Error", js_std_error_props, countof(js_std_error_props), JS_PROP_CONFIGURABLE),
- JS_CFUNC_DEF("__printObject", 1, js_std_file_printObject ),
- };
- static const JSCFunctionListEntry js_std_file_proto_funcs[] = {
- JS_CFUNC_DEF("close", 0, js_std_file_close ),
- JS_CFUNC_MAGIC_DEF("puts", 1, js_std_file_puts, 1 ),
- JS_CFUNC_DEF("printf", 1, js_std_file_printf ),
- JS_CFUNC_DEF("flush", 0, js_std_file_flush ),
- JS_CFUNC_MAGIC_DEF("tell", 0, js_std_file_tell, 0 ),
- JS_CFUNC_MAGIC_DEF("tello", 0, js_std_file_tell, 1 ),
- JS_CFUNC_DEF("seek", 2, js_std_file_seek ),
- JS_CFUNC_DEF("eof", 0, js_std_file_eof ),
- JS_CFUNC_DEF("fileno", 0, js_std_file_fileno ),
- JS_CFUNC_DEF("error", 0, js_std_file_error ),
- JS_CFUNC_DEF("clearerr", 0, js_std_file_clearerr ),
- JS_CFUNC_MAGIC_DEF("read", 3, js_std_file_read_write, 0 ),
- JS_CFUNC_MAGIC_DEF("write", 3, js_std_file_read_write, 1 ),
- JS_CFUNC_DEF("getline", 0, js_std_file_getline ),
- JS_CFUNC_DEF("readAsString", 0, js_std_file_readAsString ),
- JS_CFUNC_DEF("getByte", 0, js_std_file_getByte ),
- JS_CFUNC_DEF("putByte", 1, js_std_file_putByte ),
- /* setvbuf, ... */
- };
- static int js_std_init(JSContext *ctx, JSModuleDef *m)
- {
- JSValue proto;
- /* FILE class */
- /* the class ID is created once */
- JS_NewClassID(&js_std_file_class_id);
- /* the class is created once per runtime */
- JS_NewClass(JS_GetRuntime(ctx), js_std_file_class_id, &js_std_file_class);
- proto = JS_NewObject(ctx);
- JS_SetPropertyFunctionList(ctx, proto, js_std_file_proto_funcs,
- countof(js_std_file_proto_funcs));
- JS_SetClassProto(ctx, js_std_file_class_id, proto);
- JS_SetModuleExportList(ctx, m, js_std_funcs,
- countof(js_std_funcs));
- JS_SetModuleExport(ctx, m, "in", js_new_std_file(ctx, stdin, FALSE, FALSE));
- JS_SetModuleExport(ctx, m, "out", js_new_std_file(ctx, stdout, FALSE, FALSE));
- JS_SetModuleExport(ctx, m, "err", js_new_std_file(ctx, stderr, FALSE, FALSE));
- return 0;
- }
- JSModuleDef *js_init_module_std(JSContext *ctx, const char *module_name)
- {
- JSModuleDef *m;
- m = JS_NewCModule(ctx, module_name, js_std_init);
- if (!m)
- return NULL;
- JS_AddModuleExportList(ctx, m, js_std_funcs, countof(js_std_funcs));
- JS_AddModuleExport(ctx, m, "in");
- JS_AddModuleExport(ctx, m, "out");
- JS_AddModuleExport(ctx, m, "err");
- return m;
- }
- /**********************************************************/
- /* 'os' object */
- static JSValue js_os_open(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- const char *filename;
- int flags, mode, ret;
- filename = JS_ToCString(ctx, argv[0]);
- if (!filename)
- return JS_EXCEPTION;
- if (JS_ToInt32(ctx, &flags, argv[1]))
- goto fail;
- if (argc >= 3 && !JS_IsUndefined(argv[2])) {
- if (JS_ToInt32(ctx, &mode, argv[2])) {
- fail:
- JS_FreeCString(ctx, filename);
- return JS_EXCEPTION;
- }
- } else {
- mode = 0666;
- }
- #if defined(_WIN32)
- /* force binary mode by default */
- if (!(flags & O_TEXT))
- flags |= O_BINARY;
- #endif
- ret = js_get_errno(open(filename, flags, mode));
- JS_FreeCString(ctx, filename);
- return JS_NewInt32(ctx, ret);
- }
- static JSValue js_os_close(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- int fd, ret;
- if (JS_ToInt32(ctx, &fd, argv[0]))
- return JS_EXCEPTION;
- ret = js_get_errno(close(fd));
- return JS_NewInt32(ctx, ret);
- }
- static JSValue js_os_seek(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- int fd, whence;
- int64_t pos, ret;
- BOOL is_bigint;
- if (JS_ToInt32(ctx, &fd, argv[0]))
- return JS_EXCEPTION;
- is_bigint = JS_IsBigInt(ctx, argv[1]);
- if (JS_ToInt64Ext(ctx, &pos, argv[1]))
- return JS_EXCEPTION;
- if (JS_ToInt32(ctx, &whence, argv[2]))
- return JS_EXCEPTION;
- ret = lseek(fd, pos, whence);
- if (ret == -1)
- ret = -errno;
- if (is_bigint)
- return JS_NewBigInt64(ctx, ret);
- else
- return JS_NewInt64(ctx, ret);
- }
- static JSValue js_os_read_write(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv, int magic)
- {
- int fd;
- uint64_t pos, len;
- size_t size;
- ssize_t ret;
- uint8_t *buf;
- if (JS_ToInt32(ctx, &fd, argv[0]))
- return JS_EXCEPTION;
- if (JS_ToIndex(ctx, &pos, argv[2]))
- return JS_EXCEPTION;
- if (JS_ToIndex(ctx, &len, argv[3]))
- return JS_EXCEPTION;
- buf = JS_GetArrayBuffer(ctx, &size, argv[1]);
- if (!buf)
- return JS_EXCEPTION;
- if (pos + len > size)
- return JS_ThrowRangeError(ctx, "read/write array buffer overflow");
- if (magic)
- ret = js_get_errno(write(fd, buf + pos, len));
- else
- ret = js_get_errno(read(fd, buf + pos, len));
- return JS_NewInt64(ctx, ret);
- }
- static JSValue js_os_isatty(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- int fd;
- if (JS_ToInt32(ctx, &fd, argv[0]))
- return JS_EXCEPTION;
- return JS_NewBool(ctx, isatty(fd));
- }
- #if defined(_WIN32)
- static JSValue js_os_ttyGetWinSize(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- int fd;
- HANDLE handle;
- CONSOLE_SCREEN_BUFFER_INFO info;
- JSValue obj;
- if (JS_ToInt32(ctx, &fd, argv[0]))
- return JS_EXCEPTION;
- handle = (HANDLE)_get_osfhandle(fd);
- if (!GetConsoleScreenBufferInfo(handle, &info))
- return JS_NULL;
- obj = JS_NewArray(ctx);
- if (JS_IsException(obj))
- return obj;
- JS_DefinePropertyValueUint32(ctx, obj, 0, JS_NewInt32(ctx, info.dwSize.X), JS_PROP_C_W_E);
- JS_DefinePropertyValueUint32(ctx, obj, 1, JS_NewInt32(ctx, info.dwSize.Y), JS_PROP_C_W_E);
- return obj;
- }
- /* Windows 10 built-in VT100 emulation */
- #define __ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004
- #define __ENABLE_VIRTUAL_TERMINAL_INPUT 0x0200
- static JSValue js_os_ttySetRaw(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- int fd;
- HANDLE handle;
- if (JS_ToInt32(ctx, &fd, argv[0]))
- return JS_EXCEPTION;
- handle = (HANDLE)_get_osfhandle(fd);
- SetConsoleMode(handle, ENABLE_WINDOW_INPUT | __ENABLE_VIRTUAL_TERMINAL_INPUT);
- _setmode(fd, _O_BINARY);
- if (fd == 0) {
- handle = (HANDLE)_get_osfhandle(1); /* corresponding output */
- SetConsoleMode(handle, ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT | __ENABLE_VIRTUAL_TERMINAL_PROCESSING);
- }
- return JS_UNDEFINED;
- }
- #else
- static JSValue js_os_ttyGetWinSize(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- int fd;
- struct winsize ws;
- JSValue obj;
- if (JS_ToInt32(ctx, &fd, argv[0]))
- return JS_EXCEPTION;
- if (ioctl(fd, TIOCGWINSZ, &ws) == 0 &&
- ws.ws_col >= 4 && ws.ws_row >= 4) {
- obj = JS_NewArray(ctx);
- if (JS_IsException(obj))
- return obj;
- JS_DefinePropertyValueUint32(ctx, obj, 0, JS_NewInt32(ctx, ws.ws_col), JS_PROP_C_W_E);
- JS_DefinePropertyValueUint32(ctx, obj, 1, JS_NewInt32(ctx, ws.ws_row), JS_PROP_C_W_E);
- return obj;
- } else {
- return JS_NULL;
- }
- }
- static struct termios oldtty;
- static void term_exit(void)
- {
- tcsetattr(0, TCSANOW, &oldtty);
- }
- /* XXX: should add a way to go back to normal mode */
- static JSValue js_os_ttySetRaw(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- struct termios tty;
- int fd;
- if (JS_ToInt32(ctx, &fd, argv[0]))
- return JS_EXCEPTION;
- memset(&tty, 0, sizeof(tty));
- tcgetattr(fd, &tty);
- oldtty = tty;
- tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP
- |INLCR|IGNCR|ICRNL|IXON);
- tty.c_oflag |= OPOST;
- tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN);
- tty.c_cflag &= ~(CSIZE|PARENB);
- tty.c_cflag |= CS8;
- tty.c_cc[VMIN] = 1;
- tty.c_cc[VTIME] = 0;
- tcsetattr(fd, TCSANOW, &tty);
- atexit(term_exit);
- return JS_UNDEFINED;
- }
- #endif /* !_WIN32 */
- static JSValue js_os_remove(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- const char *filename;
- int ret;
- filename = JS_ToCString(ctx, argv[0]);
- if (!filename)
- return JS_EXCEPTION;
- #if defined(_WIN32)
- {
- struct stat st;
- if (stat(filename, &st) == 0 && S_ISDIR(st.st_mode)) {
- ret = rmdir(filename);
- } else {
- ret = unlink(filename);
- }
- }
- #else
- ret = remove(filename);
- #endif
- ret = js_get_errno(ret);
- JS_FreeCString(ctx, filename);
- return JS_NewInt32(ctx, ret);
- }
- static JSValue js_os_rename(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- const char *oldpath, *newpath;
- int ret;
- oldpath = JS_ToCString(ctx, argv[0]);
- if (!oldpath)
- return JS_EXCEPTION;
- newpath = JS_ToCString(ctx, argv[1]);
- if (!newpath) {
- JS_FreeCString(ctx, oldpath);
- return JS_EXCEPTION;
- }
- ret = js_get_errno(rename(oldpath, newpath));
- JS_FreeCString(ctx, oldpath);
- JS_FreeCString(ctx, newpath);
- return JS_NewInt32(ctx, ret);
- }
- static BOOL is_main_thread(JSRuntime *rt)
- {
- JSThreadState *ts = JS_GetRuntimeOpaque(rt);
- return !ts->recv_pipe;
- }
- static JSOSRWHandler *find_rh(JSThreadState *ts, int fd)
- {
- JSOSRWHandler *rh;
- struct list_head *el;
- list_for_each(el, &ts->os_rw_handlers) {
- rh = list_entry(el, JSOSRWHandler, link);
- if (rh->fd == fd)
- return rh;
- }
- return NULL;
- }
- static void free_rw_handler(JSRuntime *rt, JSOSRWHandler *rh)
- {
- int i;
- list_del(&rh->link);
- for(i = 0; i < 2; i++) {
- JS_FreeValueRT(rt, rh->rw_func[i]);
- }
- js_free_rt(rt, rh);
- }
- static JSValue js_os_setReadHandler(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv, int magic)
- {
- JSRuntime *rt = JS_GetRuntime(ctx);
- JSThreadState *ts = JS_GetRuntimeOpaque(rt);
- JSOSRWHandler *rh;
- int fd;
- JSValueConst func;
- if (JS_ToInt32(ctx, &fd, argv[0]))
- return JS_EXCEPTION;
- func = argv[1];
- if (JS_IsNull(func)) {
- rh = find_rh(ts, fd);
- if (rh) {
- JS_FreeValue(ctx, rh->rw_func[magic]);
- rh->rw_func[magic] = JS_NULL;
- if (JS_IsNull(rh->rw_func[0]) &&
- JS_IsNull(rh->rw_func[1])) {
- /* remove the entry */
- free_rw_handler(JS_GetRuntime(ctx), rh);
- }
- }
- } else {
- if (!JS_IsFunction(ctx, func))
- return JS_ThrowTypeError(ctx, "not a function");
- rh = find_rh(ts, fd);
- if (!rh) {
- rh = js_mallocz(ctx, sizeof(*rh));
- if (!rh)
- return JS_EXCEPTION;
- rh->fd = fd;
- rh->rw_func[0] = JS_NULL;
- rh->rw_func[1] = JS_NULL;
- list_add_tail(&rh->link, &ts->os_rw_handlers);
- }
- JS_FreeValue(ctx, rh->rw_func[magic]);
- rh->rw_func[magic] = JS_DupValue(ctx, func);
- }
- return JS_UNDEFINED;
- }
- static JSOSSignalHandler *find_sh(JSThreadState *ts, int sig_num)
- {
- JSOSSignalHandler *sh;
- struct list_head *el;
- list_for_each(el, &ts->os_signal_handlers) {
- sh = list_entry(el, JSOSSignalHandler, link);
- if (sh->sig_num == sig_num)
- return sh;
- }
- return NULL;
- }
- static void free_sh(JSRuntime *rt, JSOSSignalHandler *sh)
- {
- list_del(&sh->link);
- JS_FreeValueRT(rt, sh->func);
- js_free_rt(rt, sh);
- }
- static void os_signal_handler(int sig_num)
- {
- os_pending_signals |= ((uint64_t)1 << sig_num);
- }
- #if defined(_WIN32)
- typedef void (*sighandler_t)(int sig_num);
- #endif
- static JSValue js_os_signal(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSRuntime *rt = JS_GetRuntime(ctx);
- JSThreadState *ts = JS_GetRuntimeOpaque(rt);
- JSOSSignalHandler *sh;
- uint32_t sig_num;
- JSValueConst func;
- sighandler_t handler;
- if (!is_main_thread(rt))
- return JS_ThrowTypeError(ctx, "signal handler can only be set in the main thread");
- if (JS_ToUint32(ctx, &sig_num, argv[0]))
- return JS_EXCEPTION;
- if (sig_num >= 64)
- return JS_ThrowRangeError(ctx, "invalid signal number");
- func = argv[1];
- /* func = null: SIG_DFL, func = undefined, SIG_IGN */
- if (JS_IsNull(func) || JS_IsUndefined(func)) {
- sh = find_sh(ts, sig_num);
- if (sh) {
- free_sh(JS_GetRuntime(ctx), sh);
- }
- if (JS_IsNull(func))
- handler = SIG_DFL;
- else
- handler = SIG_IGN;
- signal(sig_num, handler);
- } else {
- if (!JS_IsFunction(ctx, func))
- return JS_ThrowTypeError(ctx, "not a function");
- sh = find_sh(ts, sig_num);
- if (!sh) {
- sh = js_mallocz(ctx, sizeof(*sh));
- if (!sh)
- return JS_EXCEPTION;
- sh->sig_num = sig_num;
- list_add_tail(&sh->link, &ts->os_signal_handlers);
- }
- JS_FreeValue(ctx, sh->func);
- sh->func = JS_DupValue(ctx, func);
- signal(sig_num, os_signal_handler);
- }
- return JS_UNDEFINED;
- }
- #if defined(__linux__) || defined(__APPLE__)
- static int64_t get_time_ms(void)
- {
- struct timespec ts;
- clock_gettime(CLOCK_MONOTONIC, &ts);
- return (uint64_t)ts.tv_sec * 1000 + (ts.tv_nsec / 1000000);
- }
- static int64_t get_time_ns(void)
- {
- struct timespec ts;
- clock_gettime(CLOCK_MONOTONIC, &ts);
- return (uint64_t)ts.tv_sec * 1000000000 + ts.tv_nsec;
- }
- #else
- /* more portable, but does not work if the date is updated */
- static int64_t get_time_ms(void)
- {
- struct timeval tv;
- gettimeofday(&tv, NULL);
- return (int64_t)tv.tv_sec * 1000 + (tv.tv_usec / 1000);
- }
- static int64_t get_time_ns(void)
- {
- struct timeval tv;
- gettimeofday(&tv, NULL);
- return (int64_t)tv.tv_sec * 1000000000 + (tv.tv_usec * 1000);
- }
- #endif
- static JSValue js_os_now(JSContext *ctx, JSValue this_val,
- int argc, JSValue *argv)
- {
- return JS_NewFloat64(ctx, (double)get_time_ns() / 1e6);
- }
- static void free_timer(JSRuntime *rt, JSOSTimer *th)
- {
- list_del(&th->link);
- JS_FreeValueRT(rt, th->func);
- js_free_rt(rt, th);
- }
- static JSValue js_os_setTimeout(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSRuntime *rt = JS_GetRuntime(ctx);
- JSThreadState *ts = JS_GetRuntimeOpaque(rt);
- int64_t delay;
- JSValueConst func;
- JSOSTimer *th;
- func = argv[0];
- if (!JS_IsFunction(ctx, func))
- return JS_ThrowTypeError(ctx, "not a function");
- if (JS_ToInt64(ctx, &delay, argv[1]))
- return JS_EXCEPTION;
- th = js_mallocz(ctx, sizeof(*th));
- if (!th)
- return JS_EXCEPTION;
- th->timer_id = ts->next_timer_id;
- if (ts->next_timer_id == INT32_MAX)
- ts->next_timer_id = 1;
- else
- ts->next_timer_id++;
- th->timeout = get_time_ms() + delay;
- th->func = JS_DupValue(ctx, func);
- list_add_tail(&th->link, &ts->os_timers);
- return JS_NewInt32(ctx, th->timer_id);
- }
- static JSOSTimer *find_timer_by_id(JSThreadState *ts, int timer_id)
- {
- struct list_head *el;
- if (timer_id <= 0)
- return NULL;
- list_for_each(el, &ts->os_timers) {
- JSOSTimer *th = list_entry(el, JSOSTimer, link);
- if (th->timer_id == timer_id)
- return th;
- }
- return NULL;
- }
- static JSValue js_os_clearTimeout(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSRuntime *rt = JS_GetRuntime(ctx);
- JSThreadState *ts = JS_GetRuntimeOpaque(rt);
- JSOSTimer *th;
- int timer_id;
- if (JS_ToInt32(ctx, &timer_id, argv[0]))
- return JS_EXCEPTION;
- th = find_timer_by_id(ts, timer_id);
- if (!th)
- return JS_UNDEFINED;
- free_timer(rt, th);
- return JS_UNDEFINED;
- }
- /* return a promise */
- static JSValue js_os_sleepAsync(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSRuntime *rt = JS_GetRuntime(ctx);
- JSThreadState *ts = JS_GetRuntimeOpaque(rt);
- int64_t delay;
- JSOSTimer *th;
- JSValue promise, resolving_funcs[2];
- if (JS_ToInt64(ctx, &delay, argv[0]))
- return JS_EXCEPTION;
- promise = JS_NewPromiseCapability(ctx, resolving_funcs);
- if (JS_IsException(promise))
- return JS_EXCEPTION;
- th = js_mallocz(ctx, sizeof(*th));
- if (!th) {
- JS_FreeValue(ctx, promise);
- JS_FreeValue(ctx, resolving_funcs[0]);
- JS_FreeValue(ctx, resolving_funcs[1]);
- return JS_EXCEPTION;
- }
- th->timer_id = -1;
- th->timeout = get_time_ms() + delay;
- th->func = JS_DupValue(ctx, resolving_funcs[0]);
- list_add_tail(&th->link, &ts->os_timers);
- JS_FreeValue(ctx, resolving_funcs[0]);
- JS_FreeValue(ctx, resolving_funcs[1]);
- return promise;
- }
- static void call_handler(JSContext *ctx, JSValueConst func)
- {
- JSValue ret, func1;
- /* 'func' might be destroyed when calling itself (if it frees the
- handler), so must take extra care */
- func1 = JS_DupValue(ctx, func);
- ret = JS_Call(ctx, func1, JS_UNDEFINED, 0, NULL);
- JS_FreeValue(ctx, func1);
- if (JS_IsException(ret))
- js_std_dump_error(ctx);
- JS_FreeValue(ctx, ret);
- }
- #ifdef USE_WORKER
- #ifdef _WIN32
- static int js_waker_init(JSWaker *w)
- {
- w->handle = CreateEvent(NULL, TRUE, FALSE, NULL);
- return w->handle ? 0 : -1;
- }
- static void js_waker_signal(JSWaker *w)
- {
- SetEvent(w->handle);
- }
- static void js_waker_clear(JSWaker *w)
- {
- ResetEvent(w->handle);
- }
- static void js_waker_close(JSWaker *w)
- {
- CloseHandle(w->handle);
- w->handle = INVALID_HANDLE_VALUE;
- }
- #else // !_WIN32
- static int js_waker_init(JSWaker *w)
- {
- int fds[2];
- if (pipe(fds) < 0)
- return -1;
- w->read_fd = fds[0];
- w->write_fd = fds[1];
- return 0;
- }
- static void js_waker_signal(JSWaker *w)
- {
- int ret;
- for(;;) {
- ret = write(w->write_fd, "", 1);
- if (ret == 1)
- break;
- if (ret < 0 && (errno != EAGAIN || errno != EINTR))
- break;
- }
- }
- static void js_waker_clear(JSWaker *w)
- {
- uint8_t buf[16];
- int ret;
- for(;;) {
- ret = read(w->read_fd, buf, sizeof(buf));
- if (ret >= 0)
- break;
- if (errno != EAGAIN && errno != EINTR)
- break;
- }
- }
- static void js_waker_close(JSWaker *w)
- {
- close(w->read_fd);
- close(w->write_fd);
- w->read_fd = -1;
- w->write_fd = -1;
- }
- #endif // _WIN32
- static void js_free_message(JSWorkerMessage *msg);
- /* return 1 if a message was handled, 0 if no message */
- static int handle_posted_message(JSRuntime *rt, JSContext *ctx,
- JSWorkerMessageHandler *port)
- {
- JSWorkerMessagePipe *ps = port->recv_pipe;
- int ret;
- struct list_head *el;
- JSWorkerMessage *msg;
- JSValue obj, data_obj, func, retval;
- pthread_mutex_lock(&ps->mutex);
- if (!list_empty(&ps->msg_queue)) {
- el = ps->msg_queue.next;
- msg = list_entry(el, JSWorkerMessage, link);
- /* remove the message from the queue */
- list_del(&msg->link);
- if (list_empty(&ps->msg_queue))
- js_waker_clear(&ps->waker);
- pthread_mutex_unlock(&ps->mutex);
- data_obj = JS_ReadObject(ctx, msg->data, msg->data_len,
- JS_READ_OBJ_SAB | JS_READ_OBJ_REFERENCE);
- js_free_message(msg);
- if (JS_IsException(data_obj))
- goto fail;
- obj = JS_NewObject(ctx);
- if (JS_IsException(obj)) {
- JS_FreeValue(ctx, data_obj);
- goto fail;
- }
- JS_DefinePropertyValueStr(ctx, obj, "data", data_obj, JS_PROP_C_W_E);
- /* 'func' might be destroyed when calling itself (if it frees the
- handler), so must take extra care */
- func = JS_DupValue(ctx, port->on_message_func);
- retval = JS_Call(ctx, func, JS_UNDEFINED, 1, (JSValueConst *)&obj);
- JS_FreeValue(ctx, obj);
- JS_FreeValue(ctx, func);
- if (JS_IsException(retval)) {
- fail:
- js_std_dump_error(ctx);
- } else {
- JS_FreeValue(ctx, retval);
- }
- ret = 1;
- } else {
- pthread_mutex_unlock(&ps->mutex);
- ret = 0;
- }
- return ret;
- }
- #else
- static int handle_posted_message(JSRuntime *rt, JSContext *ctx,
- JSWorkerMessageHandler *port)
- {
- return 0;
- }
- #endif /* !USE_WORKER */
- #if defined(_WIN32)
- static int js_os_poll(JSContext *ctx)
- {
- JSRuntime *rt = JS_GetRuntime(ctx);
- JSThreadState *ts = JS_GetRuntimeOpaque(rt);
- int min_delay, count;
- int64_t cur_time, delay;
- JSOSRWHandler *rh;
- struct list_head *el;
- HANDLE handles[MAXIMUM_WAIT_OBJECTS]; // 64
- /* XXX: handle signals if useful */
- if (list_empty(&ts->os_rw_handlers) && list_empty(&ts->os_timers) &&
- list_empty(&ts->port_list)) {
- return -1; /* no more events */
- }
-
- if (!list_empty(&ts->os_timers)) {
- cur_time = get_time_ms();
- min_delay = 10000;
- list_for_each(el, &ts->os_timers) {
- JSOSTimer *th = list_entry(el, JSOSTimer, link);
- delay = th->timeout - cur_time;
- if (delay <= 0) {
- JSValue func;
- /* the timer expired */
- func = th->func;
- th->func = JS_UNDEFINED;
- free_timer(rt, th);
- call_handler(ctx, func);
- JS_FreeValue(ctx, func);
- return 0;
- } else if (delay < min_delay) {
- min_delay = delay;
- }
- }
- } else {
- min_delay = -1;
- }
- count = 0;
- list_for_each(el, &ts->os_rw_handlers) {
- rh = list_entry(el, JSOSRWHandler, link);
- if (rh->fd == 0 && !JS_IsNull(rh->rw_func[0])) {
- handles[count++] = (HANDLE)_get_osfhandle(rh->fd); // stdin
- if (count == (int)countof(handles))
- break;
- }
- }
- list_for_each(el, &ts->port_list) {
- JSWorkerMessageHandler *port = list_entry(el, JSWorkerMessageHandler, link);
- if (JS_IsNull(port->on_message_func))
- continue;
- handles[count++] = port->recv_pipe->waker.handle;
- if (count == (int)countof(handles))
- break;
- }
- if (count > 0) {
- DWORD ret, timeout = INFINITE;
- if (min_delay != -1)
- timeout = min_delay;
- ret = WaitForMultipleObjects(count, handles, FALSE, timeout);
- if (ret < count) {
- list_for_each(el, &ts->os_rw_handlers) {
- rh = list_entry(el, JSOSRWHandler, link);
- if (rh->fd == 0 && !JS_IsNull(rh->rw_func[0])) {
- call_handler(ctx, rh->rw_func[0]);
- /* must stop because the list may have been modified */
- goto done;
- }
- }
- list_for_each(el, &ts->port_list) {
- JSWorkerMessageHandler *port = list_entry(el, JSWorkerMessageHandler, link);
- if (!JS_IsNull(port->on_message_func)) {
- JSWorkerMessagePipe *ps = port->recv_pipe;
- if (ps->waker.handle == handles[ret]) {
- if (handle_posted_message(rt, ctx, port))
- goto done;
- }
- }
- }
- }
- } else {
- Sleep(min_delay);
- }
- done:
- return 0;
- }
- #else
- static no_inline int js_poll_expand(JSThreadState *ts)
- {
- struct pollfd *new_fds;
- int new_size = max_int(ts->poll_fds_size +
- ts->poll_fds_size / 2, 16);
- new_fds = realloc(ts->poll_fds, new_size * sizeof(struct pollfd));
- if (!new_fds)
- return -1;
- ts->poll_fds = new_fds;
- ts->poll_fds_size = new_size;
- return 0;
- }
- static int js_poll_add_poll_fd(JSThreadState *ts, int *pnfds, int fd, int events)
- {
- struct pollfd *fds;
- int nfds;
- nfds = *pnfds;
- if (unlikely(nfds >= ts->poll_fds_size)) {
- if (js_poll_expand(ts))
- return -1;
- }
- fds = &ts->poll_fds[nfds++];
- fds->fd = fd;
- fds->events = events;
- fds->revents = 0;
- *pnfds = nfds;
- return 0;
- }
- static int js_os_poll(JSContext *ctx)
- {
- JSRuntime *rt = JS_GetRuntime(ctx);
- JSThreadState *ts = JS_GetRuntimeOpaque(rt);
- int min_delay, nfds;
- int64_t cur_time, delay;
- JSOSRWHandler *rh;
- struct list_head *el;
- /* only check signals in the main thread */
- if (!ts->recv_pipe &&
- unlikely(os_pending_signals != 0)) {
- JSOSSignalHandler *sh;
- uint64_t mask;
- list_for_each(el, &ts->os_signal_handlers) {
- sh = list_entry(el, JSOSSignalHandler, link);
- mask = (uint64_t)1 << sh->sig_num;
- if (os_pending_signals & mask) {
- os_pending_signals &= ~mask;
- call_handler(ctx, sh->func);
- return 0;
- }
- }
- }
- if (list_empty(&ts->os_rw_handlers) && list_empty(&ts->os_timers) &&
- list_empty(&ts->port_list))
- return -1; /* no more events */
- if (!list_empty(&ts->os_timers)) {
- cur_time = get_time_ms();
- min_delay = 10000;
- list_for_each(el, &ts->os_timers) {
- JSOSTimer *th = list_entry(el, JSOSTimer, link);
- delay = th->timeout - cur_time;
- if (delay <= 0) {
- JSValue func;
- /* the timer expired */
- func = th->func;
- th->func = JS_UNDEFINED;
- free_timer(rt, th);
- call_handler(ctx, func);
- JS_FreeValue(ctx, func);
- return 0;
- } else if (delay < min_delay) {
- min_delay = delay;
- }
- }
- } else {
- min_delay = -1; /* infinite */
- }
- nfds = 0;
- list_for_each(el, &ts->os_rw_handlers) {
- int events;
- rh = list_entry(el, JSOSRWHandler, link);
- events = 0;
- if (!JS_IsNull(rh->rw_func[0]))
- events |= POLLIN;
- if (!JS_IsNull(rh->rw_func[1]))
- events |= POLLOUT;
- if (events) {
- rh->poll_fd_index = nfds;
- if (js_poll_add_poll_fd(ts, &nfds, rh->fd, events))
- return -1;
- }
- }
- list_for_each(el, &ts->port_list) {
- JSWorkerMessageHandler *port = list_entry(el, JSWorkerMessageHandler, link);
- if (!JS_IsNull(port->on_message_func)) {
- JSWorkerMessagePipe *ps = port->recv_pipe;
- port->poll_fd_index = nfds;
- if (js_poll_add_poll_fd(ts, &nfds, ps->waker.read_fd, POLLIN))
- return -1;
- }
- }
- nfds = poll(ts->poll_fds, nfds, min_delay);
- if (nfds > 0) {
- list_for_each(el, &ts->os_rw_handlers) {
- rh = list_entry(el, JSOSRWHandler, link);
- if (!JS_IsNull(rh->rw_func[0]) &&
- (ts->poll_fds[rh->poll_fd_index].revents & (POLLERR | POLLHUP | POLLNVAL | POLLIN))) {
- call_handler(ctx, rh->rw_func[0]);
- /* must stop because the list may have been modified */
- goto done;
- }
- if (!JS_IsNull(rh->rw_func[1]) &&
- (ts->poll_fds[rh->poll_fd_index].revents & (POLLERR | POLLHUP | POLLNVAL | POLLOUT))) {
- call_handler(ctx, rh->rw_func[1]);
- /* must stop because the list may have been modified */
- goto done;
- }
- }
- list_for_each(el, &ts->port_list) {
- JSWorkerMessageHandler *port = list_entry(el, JSWorkerMessageHandler, link);
- if (!JS_IsNull(port->on_message_func)) {
- if (ts->poll_fds[port->poll_fd_index].revents != 0) {
- if (handle_posted_message(rt, ctx, port))
- goto done;
- }
- }
- }
- }
- done:
- return 0;
- }
- #endif /* !_WIN32 */
- static JSValue make_obj_error(JSContext *ctx,
- JSValue obj,
- int err)
- {
- JSValue arr;
- if (JS_IsException(obj))
- return obj;
- arr = JS_NewArray(ctx);
- if (JS_IsException(arr))
- return JS_EXCEPTION;
- JS_DefinePropertyValueUint32(ctx, arr, 0, obj,
- JS_PROP_C_W_E);
- JS_DefinePropertyValueUint32(ctx, arr, 1, JS_NewInt32(ctx, err),
- JS_PROP_C_W_E);
- return arr;
- }
- static JSValue make_string_error(JSContext *ctx,
- const char *buf,
- int err)
- {
- return make_obj_error(ctx, JS_NewString(ctx, buf), err);
- }
- /* return [cwd, errorcode] */
- static JSValue js_os_getcwd(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- char buf[PATH_MAX];
- int err;
- if (!getcwd(buf, sizeof(buf))) {
- buf[0] = '\0';
- err = errno;
- } else {
- err = 0;
- }
- return make_string_error(ctx, buf, err);
- }
- static JSValue js_os_chdir(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- const char *target;
- int err;
- target = JS_ToCString(ctx, argv[0]);
- if (!target)
- return JS_EXCEPTION;
- err = js_get_errno(chdir(target));
- JS_FreeCString(ctx, target);
- return JS_NewInt32(ctx, err);
- }
- static JSValue js_os_mkdir(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- int mode, ret;
- const char *path;
- if (argc >= 2) {
- if (JS_ToInt32(ctx, &mode, argv[1]))
- return JS_EXCEPTION;
- } else {
- mode = 0777;
- }
- path = JS_ToCString(ctx, argv[0]);
- if (!path)
- return JS_EXCEPTION;
- #if defined(_WIN32)
- (void)mode;
- ret = js_get_errno(mkdir(path));
- #else
- ret = js_get_errno(mkdir(path, mode));
- #endif
- JS_FreeCString(ctx, path);
- return JS_NewInt32(ctx, ret);
- }
- /* return [array, errorcode] */
- static JSValue js_os_readdir(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- const char *path;
- DIR *f;
- struct dirent *d;
- JSValue obj;
- int err;
- uint32_t len;
- path = JS_ToCString(ctx, argv[0]);
- if (!path)
- return JS_EXCEPTION;
- obj = JS_NewArray(ctx);
- if (JS_IsException(obj)) {
- JS_FreeCString(ctx, path);
- return JS_EXCEPTION;
- }
- f = opendir(path);
- if (!f)
- err = errno;
- else
- err = 0;
- JS_FreeCString(ctx, path);
- if (!f)
- goto done;
- len = 0;
- for(;;) {
- errno = 0;
- d = readdir(f);
- if (!d) {
- err = errno;
- break;
- }
- JS_DefinePropertyValueUint32(ctx, obj, len++,
- JS_NewString(ctx, d->d_name),
- JS_PROP_C_W_E);
- }
- closedir(f);
- done:
- return make_obj_error(ctx, obj, err);
- }
- #if !defined(_WIN32)
- static int64_t timespec_to_ms(const struct timespec *tv)
- {
- return (int64_t)tv->tv_sec * 1000 + (tv->tv_nsec / 1000000);
- }
- #endif
- /* return [obj, errcode] */
- static JSValue js_os_stat(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv, int is_lstat)
- {
- const char *path;
- int err, res;
- struct stat st;
- JSValue obj;
- path = JS_ToCString(ctx, argv[0]);
- if (!path)
- return JS_EXCEPTION;
- #if defined(_WIN32)
- res = stat(path, &st);
- #else
- if (is_lstat)
- res = lstat(path, &st);
- else
- res = stat(path, &st);
- #endif
- if (res < 0)
- err = errno;
- else
- err = 0;
- JS_FreeCString(ctx, path);
- if (res < 0) {
- obj = JS_NULL;
- } else {
- obj = JS_NewObject(ctx);
- if (JS_IsException(obj))
- return JS_EXCEPTION;
- JS_DefinePropertyValueStr(ctx, obj, "dev",
- JS_NewInt64(ctx, st.st_dev),
- JS_PROP_C_W_E);
- JS_DefinePropertyValueStr(ctx, obj, "ino",
- JS_NewInt64(ctx, st.st_ino),
- JS_PROP_C_W_E);
- JS_DefinePropertyValueStr(ctx, obj, "mode",
- JS_NewInt32(ctx, st.st_mode),
- JS_PROP_C_W_E);
- JS_DefinePropertyValueStr(ctx, obj, "nlink",
- JS_NewInt64(ctx, st.st_nlink),
- JS_PROP_C_W_E);
- JS_DefinePropertyValueStr(ctx, obj, "uid",
- JS_NewInt64(ctx, st.st_uid),
- JS_PROP_C_W_E);
- JS_DefinePropertyValueStr(ctx, obj, "gid",
- JS_NewInt64(ctx, st.st_gid),
- JS_PROP_C_W_E);
- JS_DefinePropertyValueStr(ctx, obj, "rdev",
- JS_NewInt64(ctx, st.st_rdev),
- JS_PROP_C_W_E);
- JS_DefinePropertyValueStr(ctx, obj, "size",
- JS_NewInt64(ctx, st.st_size),
- JS_PROP_C_W_E);
- #if !defined(_WIN32)
- JS_DefinePropertyValueStr(ctx, obj, "blocks",
- JS_NewInt64(ctx, st.st_blocks),
- JS_PROP_C_W_E);
- #endif
- #if defined(_WIN32)
- JS_DefinePropertyValueStr(ctx, obj, "atime",
- JS_NewInt64(ctx, (int64_t)st.st_atime * 1000),
- JS_PROP_C_W_E);
- JS_DefinePropertyValueStr(ctx, obj, "mtime",
- JS_NewInt64(ctx, (int64_t)st.st_mtime * 1000),
- JS_PROP_C_W_E);
- JS_DefinePropertyValueStr(ctx, obj, "ctime",
- JS_NewInt64(ctx, (int64_t)st.st_ctime * 1000),
- JS_PROP_C_W_E);
- #elif defined(__APPLE__)
- JS_DefinePropertyValueStr(ctx, obj, "atime",
- JS_NewInt64(ctx, timespec_to_ms(&st.st_atimespec)),
- JS_PROP_C_W_E);
- JS_DefinePropertyValueStr(ctx, obj, "mtime",
- JS_NewInt64(ctx, timespec_to_ms(&st.st_mtimespec)),
- JS_PROP_C_W_E);
- JS_DefinePropertyValueStr(ctx, obj, "ctime",
- JS_NewInt64(ctx, timespec_to_ms(&st.st_ctimespec)),
- JS_PROP_C_W_E);
- #else
- JS_DefinePropertyValueStr(ctx, obj, "atime",
- JS_NewInt64(ctx, timespec_to_ms(&st.st_atim)),
- JS_PROP_C_W_E);
- JS_DefinePropertyValueStr(ctx, obj, "mtime",
- JS_NewInt64(ctx, timespec_to_ms(&st.st_mtim)),
- JS_PROP_C_W_E);
- JS_DefinePropertyValueStr(ctx, obj, "ctime",
- JS_NewInt64(ctx, timespec_to_ms(&st.st_ctim)),
- JS_PROP_C_W_E);
- #endif
- }
- return make_obj_error(ctx, obj, err);
- }
- #if !defined(_WIN32)
- static void ms_to_timeval(struct timeval *tv, uint64_t v)
- {
- tv->tv_sec = v / 1000;
- tv->tv_usec = (v % 1000) * 1000;
- }
- #endif
- static JSValue js_os_utimes(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- const char *path;
- int64_t atime, mtime;
- int ret;
- if (JS_ToInt64(ctx, &atime, argv[1]))
- return JS_EXCEPTION;
- if (JS_ToInt64(ctx, &mtime, argv[2]))
- return JS_EXCEPTION;
- path = JS_ToCString(ctx, argv[0]);
- if (!path)
- return JS_EXCEPTION;
- #if defined(_WIN32)
- {
- struct _utimbuf times;
- times.actime = atime / 1000;
- times.modtime = mtime / 1000;
- ret = js_get_errno(_utime(path, ×));
- }
- #else
- {
- struct timeval times[2];
- ms_to_timeval(×[0], atime);
- ms_to_timeval(×[1], mtime);
- ret = js_get_errno(utimes(path, times));
- }
- #endif
- JS_FreeCString(ctx, path);
- return JS_NewInt32(ctx, ret);
- }
- /* sleep(delay_ms) */
- static JSValue js_os_sleep(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- int64_t delay;
- int ret;
- if (JS_ToInt64(ctx, &delay, argv[0]))
- return JS_EXCEPTION;
- if (delay < 0)
- delay = 0;
- #if defined(_WIN32)
- {
- if (delay > INT32_MAX)
- delay = INT32_MAX;
- Sleep(delay);
- ret = 0;
- }
- #else
- {
- struct timespec ts;
- ts.tv_sec = delay / 1000;
- ts.tv_nsec = (delay % 1000) * 1000000;
- ret = js_get_errno(nanosleep(&ts, NULL));
- }
- #endif
- return JS_NewInt32(ctx, ret);
- }
- #if defined(_WIN32)
- static char *realpath(const char *path, char *buf)
- {
- if (!_fullpath(buf, path, PATH_MAX)) {
- errno = ENOENT;
- return NULL;
- } else {
- return buf;
- }
- }
- #endif
- /* return [path, errorcode] */
- static JSValue js_os_realpath(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- const char *path;
- char buf[PATH_MAX], *res;
- int err;
- path = JS_ToCString(ctx, argv[0]);
- if (!path)
- return JS_EXCEPTION;
- res = realpath(path, buf);
- JS_FreeCString(ctx, path);
- if (!res) {
- buf[0] = '\0';
- err = errno;
- } else {
- err = 0;
- }
- return make_string_error(ctx, buf, err);
- }
- #if !defined(_WIN32)
- static JSValue js_os_symlink(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- const char *target, *linkpath;
- int err;
- target = JS_ToCString(ctx, argv[0]);
- if (!target)
- return JS_EXCEPTION;
- linkpath = JS_ToCString(ctx, argv[1]);
- if (!linkpath) {
- JS_FreeCString(ctx, target);
- return JS_EXCEPTION;
- }
- err = js_get_errno(symlink(target, linkpath));
- JS_FreeCString(ctx, target);
- JS_FreeCString(ctx, linkpath);
- return JS_NewInt32(ctx, err);
- }
- /* return [path, errorcode] */
- static JSValue js_os_readlink(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- const char *path;
- char buf[PATH_MAX];
- int err;
- ssize_t res;
- path = JS_ToCString(ctx, argv[0]);
- if (!path)
- return JS_EXCEPTION;
- res = readlink(path, buf, sizeof(buf) - 1);
- if (res < 0) {
- buf[0] = '\0';
- err = errno;
- } else {
- buf[res] = '\0';
- err = 0;
- }
- JS_FreeCString(ctx, path);
- return make_string_error(ctx, buf, err);
- }
- static char **build_envp(JSContext *ctx, JSValueConst obj)
- {
- uint32_t len, i;
- JSPropertyEnum *tab;
- char **envp, *pair;
- const char *key, *str;
- JSValue val;
- size_t key_len, str_len;
- if (JS_GetOwnPropertyNames(ctx, &tab, &len, obj,
- JS_GPN_STRING_MASK | JS_GPN_ENUM_ONLY) < 0)
- return NULL;
- envp = js_mallocz(ctx, sizeof(envp[0]) * ((size_t)len + 1));
- if (!envp)
- goto fail;
- for(i = 0; i < len; i++) {
- val = JS_GetProperty(ctx, obj, tab[i].atom);
- if (JS_IsException(val))
- goto fail;
- str = JS_ToCString(ctx, val);
- JS_FreeValue(ctx, val);
- if (!str)
- goto fail;
- key = JS_AtomToCString(ctx, tab[i].atom);
- if (!key) {
- JS_FreeCString(ctx, str);
- goto fail;
- }
- key_len = strlen(key);
- str_len = strlen(str);
- pair = js_malloc(ctx, key_len + str_len + 2);
- if (!pair) {
- JS_FreeCString(ctx, key);
- JS_FreeCString(ctx, str);
- goto fail;
- }
- memcpy(pair, key, key_len);
- pair[key_len] = '=';
- memcpy(pair + key_len + 1, str, str_len);
- pair[key_len + 1 + str_len] = '\0';
- envp[i] = pair;
- JS_FreeCString(ctx, key);
- JS_FreeCString(ctx, str);
- }
- done:
- JS_FreePropertyEnum(ctx, tab, len);
- return envp;
- fail:
- if (envp) {
- for(i = 0; i < len; i++)
- js_free(ctx, envp[i]);
- js_free(ctx, envp);
- envp = NULL;
- }
- goto done;
- }
- /* execvpe is not available on non GNU systems */
- static int my_execvpe(const char *filename, char **argv, char **envp)
- {
- char *path, *p, *p_next, *p1;
- char buf[PATH_MAX];
- size_t filename_len, path_len;
- BOOL eacces_error;
- filename_len = strlen(filename);
- if (filename_len == 0) {
- errno = ENOENT;
- return -1;
- }
- if (strchr(filename, '/'))
- return execve(filename, argv, envp);
- path = getenv("PATH");
- if (!path)
- path = (char *)"/bin:/usr/bin";
- eacces_error = FALSE;
- p = path;
- for(p = path; p != NULL; p = p_next) {
- p1 = strchr(p, ':');
- if (!p1) {
- p_next = NULL;
- path_len = strlen(p);
- } else {
- p_next = p1 + 1;
- path_len = p1 - p;
- }
- /* path too long */
- if ((path_len + 1 + filename_len + 1) > PATH_MAX)
- continue;
- memcpy(buf, p, path_len);
- buf[path_len] = '/';
- memcpy(buf + path_len + 1, filename, filename_len);
- buf[path_len + 1 + filename_len] = '\0';
- execve(buf, argv, envp);
- switch(errno) {
- case EACCES:
- eacces_error = TRUE;
- break;
- case ENOENT:
- case ENOTDIR:
- break;
- default:
- return -1;
- }
- }
- if (eacces_error)
- errno = EACCES;
- return -1;
- }
- /* exec(args[, options]) -> exitcode */
- static JSValue js_os_exec(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSValueConst options, args = argv[0];
- JSValue val, ret_val;
- const char **exec_argv, *file = NULL, *str, *cwd = NULL;
- char **envp = environ;
- uint32_t exec_argc, i;
- int ret, pid, status;
- BOOL block_flag = TRUE, use_path = TRUE;
- static const char *std_name[3] = { "stdin", "stdout", "stderr" };
- int std_fds[3];
- uint32_t uid = -1, gid = -1;
- val = JS_GetPropertyStr(ctx, args, "length");
- if (JS_IsException(val))
- return JS_EXCEPTION;
- ret = JS_ToUint32(ctx, &exec_argc, val);
- JS_FreeValue(ctx, val);
- if (ret)
- return JS_EXCEPTION;
- /* arbitrary limit to avoid overflow */
- if (exec_argc < 1 || exec_argc > 65535) {
- return JS_ThrowTypeError(ctx, "invalid number of arguments");
- }
- exec_argv = js_mallocz(ctx, sizeof(exec_argv[0]) * (exec_argc + 1));
- if (!exec_argv)
- return JS_EXCEPTION;
- for(i = 0; i < exec_argc; i++) {
- val = JS_GetPropertyUint32(ctx, args, i);
- if (JS_IsException(val))
- goto exception;
- str = JS_ToCString(ctx, val);
- JS_FreeValue(ctx, val);
- if (!str)
- goto exception;
- exec_argv[i] = str;
- }
- exec_argv[exec_argc] = NULL;
- for(i = 0; i < 3; i++)
- std_fds[i] = i;
- /* get the options, if any */
- if (argc >= 2) {
- options = argv[1];
- if (get_bool_option(ctx, &block_flag, options, "block"))
- goto exception;
- if (get_bool_option(ctx, &use_path, options, "usePath"))
- goto exception;
- val = JS_GetPropertyStr(ctx, options, "file");
- if (JS_IsException(val))
- goto exception;
- if (!JS_IsUndefined(val)) {
- file = JS_ToCString(ctx, val);
- JS_FreeValue(ctx, val);
- if (!file)
- goto exception;
- }
- val = JS_GetPropertyStr(ctx, options, "cwd");
- if (JS_IsException(val))
- goto exception;
- if (!JS_IsUndefined(val)) {
- cwd = JS_ToCString(ctx, val);
- JS_FreeValue(ctx, val);
- if (!cwd)
- goto exception;
- }
- /* stdin/stdout/stderr handles */
- for(i = 0; i < 3; i++) {
- val = JS_GetPropertyStr(ctx, options, std_name[i]);
- if (JS_IsException(val))
- goto exception;
- if (!JS_IsUndefined(val)) {
- int fd;
- ret = JS_ToInt32(ctx, &fd, val);
- JS_FreeValue(ctx, val);
- if (ret)
- goto exception;
- std_fds[i] = fd;
- }
- }
- val = JS_GetPropertyStr(ctx, options, "env");
- if (JS_IsException(val))
- goto exception;
- if (!JS_IsUndefined(val)) {
- envp = build_envp(ctx, val);
- JS_FreeValue(ctx, val);
- if (!envp)
- goto exception;
- }
- val = JS_GetPropertyStr(ctx, options, "uid");
- if (JS_IsException(val))
- goto exception;
- if (!JS_IsUndefined(val)) {
- ret = JS_ToUint32(ctx, &uid, val);
- JS_FreeValue(ctx, val);
- if (ret)
- goto exception;
- }
- val = JS_GetPropertyStr(ctx, options, "gid");
- if (JS_IsException(val))
- goto exception;
- if (!JS_IsUndefined(val)) {
- ret = JS_ToUint32(ctx, &gid, val);
- JS_FreeValue(ctx, val);
- if (ret)
- goto exception;
- }
- }
- pid = fork();
- if (pid < 0) {
- JS_ThrowTypeError(ctx, "fork error");
- goto exception;
- }
- if (pid == 0) {
- /* child */
- /* remap the stdin/stdout/stderr handles if necessary */
- for(i = 0; i < 3; i++) {
- if (std_fds[i] != i) {
- if (dup2(std_fds[i], i) < 0)
- _exit(127);
- }
- }
- #if defined(HAVE_CLOSEFROM)
- /* closefrom() is available on many recent unix systems:
- Linux with glibc 2.34+, Solaris 9+, FreeBSD 7.3+,
- NetBSD 3.0+, OpenBSD 3.5+.
- Linux with the musl libc and macOS don't have it.
- */
- closefrom(3);
- #else
- {
- /* Close the file handles manually, limit to 1024 to avoid
- costly loop on linux Alpine where sysconf(_SC_OPEN_MAX)
- returns a huge value 1048576.
- Patch inspired by nicolas-duteil-nova. See also:
- https://stackoverflow.com/questions/73229353/
- https://stackoverflow.com/questions/899038/#918469
- */
- int fd_max = min_int(sysconf(_SC_OPEN_MAX), 1024);
- for(i = 3; i < fd_max; i++)
- close(i);
- }
- #endif
- if (cwd) {
- if (chdir(cwd) < 0)
- _exit(127);
- }
- if (gid != -1) {
- if (setgid(gid) < 0)
- _exit(127);
- }
- if (uid != -1) {
- if (setuid(uid) < 0)
- _exit(127);
- }
- if (!file)
- file = exec_argv[0];
- if (use_path)
- ret = my_execvpe(file, (char **)exec_argv, envp);
- else
- ret = execve(file, (char **)exec_argv, envp);
- _exit(127);
- }
- /* parent */
- if (block_flag) {
- for(;;) {
- ret = waitpid(pid, &status, 0);
- if (ret == pid) {
- if (WIFEXITED(status)) {
- ret = WEXITSTATUS(status);
- break;
- } else if (WIFSIGNALED(status)) {
- ret = -WTERMSIG(status);
- break;
- }
- }
- }
- } else {
- ret = pid;
- }
- ret_val = JS_NewInt32(ctx, ret);
- done:
- JS_FreeCString(ctx, file);
- JS_FreeCString(ctx, cwd);
- for(i = 0; i < exec_argc; i++)
- JS_FreeCString(ctx, exec_argv[i]);
- js_free(ctx, exec_argv);
- if (envp && envp != environ) {
- char **p;
- p = envp;
- while (*p != NULL) {
- js_free(ctx, *p);
- p++;
- }
- js_free(ctx, envp);
- }
- return ret_val;
- exception:
- ret_val = JS_EXCEPTION;
- goto done;
- }
- /* getpid() -> pid */
- static JSValue js_os_getpid(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- return JS_NewInt32(ctx, getpid());
- }
- /* waitpid(pid, block) -> [pid, status] */
- static JSValue js_os_waitpid(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- int pid, status, options, ret;
- JSValue obj;
- if (JS_ToInt32(ctx, &pid, argv[0]))
- return JS_EXCEPTION;
- if (JS_ToInt32(ctx, &options, argv[1]))
- return JS_EXCEPTION;
- ret = waitpid(pid, &status, options);
- if (ret < 0) {
- ret = -errno;
- status = 0;
- }
- obj = JS_NewArray(ctx);
- if (JS_IsException(obj))
- return obj;
- JS_DefinePropertyValueUint32(ctx, obj, 0, JS_NewInt32(ctx, ret),
- JS_PROP_C_W_E);
- JS_DefinePropertyValueUint32(ctx, obj, 1, JS_NewInt32(ctx, status),
- JS_PROP_C_W_E);
- return obj;
- }
- /* pipe() -> [read_fd, write_fd] or null if error */
- static JSValue js_os_pipe(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- int pipe_fds[2], ret;
- JSValue obj;
- ret = pipe(pipe_fds);
- if (ret < 0)
- return JS_NULL;
- obj = JS_NewArray(ctx);
- if (JS_IsException(obj))
- return obj;
- JS_DefinePropertyValueUint32(ctx, obj, 0, JS_NewInt32(ctx, pipe_fds[0]),
- JS_PROP_C_W_E);
- JS_DefinePropertyValueUint32(ctx, obj, 1, JS_NewInt32(ctx, pipe_fds[1]),
- JS_PROP_C_W_E);
- return obj;
- }
- /* kill(pid, sig) */
- static JSValue js_os_kill(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- int pid, sig, ret;
- if (JS_ToInt32(ctx, &pid, argv[0]))
- return JS_EXCEPTION;
- if (JS_ToInt32(ctx, &sig, argv[1]))
- return JS_EXCEPTION;
- ret = js_get_errno(kill(pid, sig));
- return JS_NewInt32(ctx, ret);
- }
- /* dup(fd) */
- static JSValue js_os_dup(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- int fd, ret;
- if (JS_ToInt32(ctx, &fd, argv[0]))
- return JS_EXCEPTION;
- ret = js_get_errno(dup(fd));
- return JS_NewInt32(ctx, ret);
- }
- /* dup2(fd) */
- static JSValue js_os_dup2(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- int fd, fd2, ret;
- if (JS_ToInt32(ctx, &fd, argv[0]))
- return JS_EXCEPTION;
- if (JS_ToInt32(ctx, &fd2, argv[1]))
- return JS_EXCEPTION;
- ret = js_get_errno(dup2(fd, fd2));
- return JS_NewInt32(ctx, ret);
- }
- #endif /* !_WIN32 */
- #ifdef USE_WORKER
- /* Worker */
- typedef struct {
- JSWorkerMessagePipe *recv_pipe;
- JSWorkerMessagePipe *send_pipe;
- JSWorkerMessageHandler *msg_handler;
- } JSWorkerData;
- typedef struct {
- char *filename; /* module filename */
- char *basename; /* module base name */
- JSWorkerMessagePipe *recv_pipe, *send_pipe;
- int strip_flags;
- } WorkerFuncArgs;
- typedef struct {
- int ref_count;
- uint64_t buf[0];
- } JSSABHeader;
- static JSClassID js_worker_class_id;
- static JSContext *(*js_worker_new_context_func)(JSRuntime *rt);
- static int atomic_add_int(int *ptr, int v)
- {
- return atomic_fetch_add((_Atomic(uint32_t) *)ptr, v) + v;
- }
- /* shared array buffer allocator */
- static void *js_sab_alloc(void *opaque, size_t size)
- {
- JSSABHeader *sab;
- sab = malloc(sizeof(JSSABHeader) + size);
- if (!sab)
- return NULL;
- sab->ref_count = 1;
- return sab->buf;
- }
- static void js_sab_free(void *opaque, void *ptr)
- {
- JSSABHeader *sab;
- int ref_count;
- sab = (JSSABHeader *)((uint8_t *)ptr - sizeof(JSSABHeader));
- ref_count = atomic_add_int(&sab->ref_count, -1);
- assert(ref_count >= 0);
- if (ref_count == 0) {
- free(sab);
- }
- }
- static void js_sab_dup(void *opaque, void *ptr)
- {
- JSSABHeader *sab;
- sab = (JSSABHeader *)((uint8_t *)ptr - sizeof(JSSABHeader));
- atomic_add_int(&sab->ref_count, 1);
- }
- static JSWorkerMessagePipe *js_new_message_pipe(void)
- {
- JSWorkerMessagePipe *ps;
- ps = malloc(sizeof(*ps));
- if (!ps)
- return NULL;
- if (js_waker_init(&ps->waker)) {
- free(ps);
- return NULL;
- }
- ps->ref_count = 1;
- init_list_head(&ps->msg_queue);
- pthread_mutex_init(&ps->mutex, NULL);
- return ps;
- }
- static JSWorkerMessagePipe *js_dup_message_pipe(JSWorkerMessagePipe *ps)
- {
- atomic_add_int(&ps->ref_count, 1);
- return ps;
- }
- static void js_free_message(JSWorkerMessage *msg)
- {
- size_t i;
- /* free the SAB */
- for(i = 0; i < msg->sab_tab_len; i++) {
- js_sab_free(NULL, msg->sab_tab[i]);
- }
- free(msg->sab_tab);
- free(msg->data);
- free(msg);
- }
- static void js_free_message_pipe(JSWorkerMessagePipe *ps)
- {
- struct list_head *el, *el1;
- JSWorkerMessage *msg;
- int ref_count;
- if (!ps)
- return;
- ref_count = atomic_add_int(&ps->ref_count, -1);
- assert(ref_count >= 0);
- if (ref_count == 0) {
- list_for_each_safe(el, el1, &ps->msg_queue) {
- msg = list_entry(el, JSWorkerMessage, link);
- js_free_message(msg);
- }
- pthread_mutex_destroy(&ps->mutex);
- js_waker_close(&ps->waker);
- free(ps);
- }
- }
- static void js_free_port(JSRuntime *rt, JSWorkerMessageHandler *port)
- {
- if (port) {
- js_free_message_pipe(port->recv_pipe);
- JS_FreeValueRT(rt, port->on_message_func);
- if (port->link.prev)
- list_del(&port->link);
- js_free_rt(rt, port);
- }
- }
- static void js_worker_finalizer(JSRuntime *rt, JSValue val)
- {
- JSWorkerData *worker = JS_GetOpaque(val, js_worker_class_id);
- if (worker) {
- js_free_message_pipe(worker->recv_pipe);
- js_free_message_pipe(worker->send_pipe);
- js_free_port(rt, worker->msg_handler);
- js_free_rt(rt, worker);
- }
- }
- static void js_worker_mark(JSRuntime *rt, JSValueConst val,
- JS_MarkFunc *mark_func)
- {
- JSWorkerData *worker = JS_GetOpaque(val, js_worker_class_id);
- if (worker) {
- JSWorkerMessageHandler *port = worker->msg_handler;
- if (port) {
- JS_MarkValue(rt, port->on_message_func, mark_func);
- }
- }
- }
- static JSClassDef js_worker_class = {
- "Worker",
- .finalizer = js_worker_finalizer,
- .gc_mark = js_worker_mark,
- };
- static void *worker_func(void *opaque)
- {
- WorkerFuncArgs *args = opaque;
- JSRuntime *rt;
- JSThreadState *ts;
- JSContext *ctx;
- JSValue val;
- rt = JS_NewRuntime();
- if (rt == NULL) {
- fprintf(stderr, "JS_NewRuntime failure");
- exit(1);
- }
- JS_SetStripInfo(rt, args->strip_flags);
- js_std_init_handlers(rt);
- JS_SetModuleLoaderFunc2(rt, NULL, js_module_loader, js_module_check_attributes, NULL);
- /* set the pipe to communicate with the parent */
- ts = JS_GetRuntimeOpaque(rt);
- ts->recv_pipe = args->recv_pipe;
- ts->send_pipe = args->send_pipe;
- /* function pointer to avoid linking the whole JS_NewContext() if
- not needed */
- ctx = js_worker_new_context_func(rt);
- if (ctx == NULL) {
- fprintf(stderr, "JS_NewContext failure");
- }
- JS_SetCanBlock(rt, TRUE);
- js_std_add_helpers(ctx, -1, NULL);
- val = JS_LoadModule(ctx, args->basename, args->filename);
- free(args->filename);
- free(args->basename);
- free(args);
- val = js_std_await(ctx, val);
- if (JS_IsException(val))
- js_std_dump_error(ctx);
- JS_FreeValue(ctx, val);
- js_std_loop(ctx);
- JS_FreeContext(ctx);
- js_std_free_handlers(rt);
- JS_FreeRuntime(rt);
- return NULL;
- }
- static JSValue js_worker_ctor_internal(JSContext *ctx, JSValueConst new_target,
- JSWorkerMessagePipe *recv_pipe,
- JSWorkerMessagePipe *send_pipe)
- {
- JSValue obj = JS_UNDEFINED, proto;
- JSWorkerData *s;
- /* create the object */
- if (JS_IsUndefined(new_target)) {
- proto = JS_GetClassProto(ctx, js_worker_class_id);
- } else {
- proto = JS_GetPropertyStr(ctx, new_target, "prototype");
- if (JS_IsException(proto))
- goto fail;
- }
- obj = JS_NewObjectProtoClass(ctx, proto, js_worker_class_id);
- JS_FreeValue(ctx, proto);
- if (JS_IsException(obj))
- goto fail;
- s = js_mallocz(ctx, sizeof(*s));
- if (!s)
- goto fail;
- s->recv_pipe = js_dup_message_pipe(recv_pipe);
- s->send_pipe = js_dup_message_pipe(send_pipe);
- JS_SetOpaque(obj, s);
- return obj;
- fail:
- JS_FreeValue(ctx, obj);
- return JS_EXCEPTION;
- }
- static JSValue js_worker_ctor(JSContext *ctx, JSValueConst new_target,
- int argc, JSValueConst *argv)
- {
- JSRuntime *rt = JS_GetRuntime(ctx);
- WorkerFuncArgs *args = NULL;
- pthread_t tid;
- pthread_attr_t attr;
- JSValue obj = JS_UNDEFINED;
- int ret;
- const char *filename = NULL, *basename;
- JSAtom basename_atom;
- /* XXX: in order to avoid problems with resource liberation, we
- don't support creating workers inside workers */
- if (!is_main_thread(rt))
- return JS_ThrowTypeError(ctx, "cannot create a worker inside a worker");
- /* base name, assuming the calling function is a normal JS
- function */
- basename_atom = JS_GetScriptOrModuleName(ctx, 1);
- if (basename_atom == JS_ATOM_NULL) {
- return JS_ThrowTypeError(ctx, "could not determine calling script or module name");
- }
- basename = JS_AtomToCString(ctx, basename_atom);
- JS_FreeAtom(ctx, basename_atom);
- if (!basename)
- goto fail;
- /* module name */
- filename = JS_ToCString(ctx, argv[0]);
- if (!filename)
- goto fail;
- args = malloc(sizeof(*args));
- if (!args)
- goto oom_fail;
- memset(args, 0, sizeof(*args));
- args->filename = strdup(filename);
- args->basename = strdup(basename);
- /* ports */
- args->recv_pipe = js_new_message_pipe();
- if (!args->recv_pipe)
- goto oom_fail;
- args->send_pipe = js_new_message_pipe();
- if (!args->send_pipe)
- goto oom_fail;
- args->strip_flags = JS_GetStripInfo(rt);
-
- obj = js_worker_ctor_internal(ctx, new_target,
- args->send_pipe, args->recv_pipe);
- if (JS_IsException(obj))
- goto fail;
- pthread_attr_init(&attr);
- /* no join at the end */
- pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
- ret = pthread_create(&tid, &attr, worker_func, args);
- pthread_attr_destroy(&attr);
- if (ret != 0) {
- JS_ThrowTypeError(ctx, "could not create worker");
- goto fail;
- }
- JS_FreeCString(ctx, basename);
- JS_FreeCString(ctx, filename);
- return obj;
- oom_fail:
- JS_ThrowOutOfMemory(ctx);
- fail:
- JS_FreeCString(ctx, basename);
- JS_FreeCString(ctx, filename);
- if (args) {
- free(args->filename);
- free(args->basename);
- js_free_message_pipe(args->recv_pipe);
- js_free_message_pipe(args->send_pipe);
- free(args);
- }
- JS_FreeValue(ctx, obj);
- return JS_EXCEPTION;
- }
- static JSValue js_worker_postMessage(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSWorkerData *worker = JS_GetOpaque2(ctx, this_val, js_worker_class_id);
- JSWorkerMessagePipe *ps;
- size_t data_len, sab_tab_len, i;
- uint8_t *data;
- JSWorkerMessage *msg;
- uint8_t **sab_tab;
- if (!worker)
- return JS_EXCEPTION;
- data = JS_WriteObject2(ctx, &data_len, argv[0],
- JS_WRITE_OBJ_SAB | JS_WRITE_OBJ_REFERENCE,
- &sab_tab, &sab_tab_len);
- if (!data)
- return JS_EXCEPTION;
- msg = malloc(sizeof(*msg));
- if (!msg)
- goto fail;
- msg->data = NULL;
- msg->sab_tab = NULL;
- /* must reallocate because the allocator may be different */
- msg->data = malloc(data_len);
- if (!msg->data)
- goto fail;
- memcpy(msg->data, data, data_len);
- msg->data_len = data_len;
- if (sab_tab_len > 0) {
- msg->sab_tab = malloc(sizeof(msg->sab_tab[0]) * sab_tab_len);
- if (!msg->sab_tab)
- goto fail;
- memcpy(msg->sab_tab, sab_tab, sizeof(msg->sab_tab[0]) * sab_tab_len);
- }
- msg->sab_tab_len = sab_tab_len;
- js_free(ctx, data);
- js_free(ctx, sab_tab);
- /* increment the SAB reference counts */
- for(i = 0; i < msg->sab_tab_len; i++) {
- js_sab_dup(NULL, msg->sab_tab[i]);
- }
- ps = worker->send_pipe;
- pthread_mutex_lock(&ps->mutex);
- /* indicate that data is present */
- if (list_empty(&ps->msg_queue))
- js_waker_signal(&ps->waker);
- list_add_tail(&msg->link, &ps->msg_queue);
- pthread_mutex_unlock(&ps->mutex);
- return JS_UNDEFINED;
- fail:
- if (msg) {
- free(msg->data);
- free(msg->sab_tab);
- free(msg);
- }
- js_free(ctx, data);
- js_free(ctx, sab_tab);
- return JS_EXCEPTION;
- }
- static JSValue js_worker_set_onmessage(JSContext *ctx, JSValueConst this_val,
- JSValueConst func)
- {
- JSRuntime *rt = JS_GetRuntime(ctx);
- JSThreadState *ts = JS_GetRuntimeOpaque(rt);
- JSWorkerData *worker = JS_GetOpaque2(ctx, this_val, js_worker_class_id);
- JSWorkerMessageHandler *port;
- if (!worker)
- return JS_EXCEPTION;
- port = worker->msg_handler;
- if (JS_IsNull(func)) {
- if (port) {
- js_free_port(rt, port);
- worker->msg_handler = NULL;
- }
- } else {
- if (!JS_IsFunction(ctx, func))
- return JS_ThrowTypeError(ctx, "not a function");
- if (!port) {
- port = js_mallocz(ctx, sizeof(*port));
- if (!port)
- return JS_EXCEPTION;
- port->recv_pipe = js_dup_message_pipe(worker->recv_pipe);
- port->on_message_func = JS_NULL;
- list_add_tail(&port->link, &ts->port_list);
- worker->msg_handler = port;
- }
- JS_FreeValue(ctx, port->on_message_func);
- port->on_message_func = JS_DupValue(ctx, func);
- }
- return JS_UNDEFINED;
- }
- static JSValue js_worker_get_onmessage(JSContext *ctx, JSValueConst this_val)
- {
- JSWorkerData *worker = JS_GetOpaque2(ctx, this_val, js_worker_class_id);
- JSWorkerMessageHandler *port;
- if (!worker)
- return JS_EXCEPTION;
- port = worker->msg_handler;
- if (port) {
- return JS_DupValue(ctx, port->on_message_func);
- } else {
- return JS_NULL;
- }
- }
- static const JSCFunctionListEntry js_worker_proto_funcs[] = {
- JS_CFUNC_DEF("postMessage", 1, js_worker_postMessage ),
- JS_CGETSET_DEF("onmessage", js_worker_get_onmessage, js_worker_set_onmessage ),
- };
- #endif /* USE_WORKER */
- void js_std_set_worker_new_context_func(JSContext *(*func)(JSRuntime *rt))
- {
- #ifdef USE_WORKER
- js_worker_new_context_func = func;
- #endif
- }
- #if defined(_WIN32)
- #define OS_PLATFORM "win32"
- #elif defined(__APPLE__)
- #define OS_PLATFORM "darwin"
- #elif defined(__EMSCRIPTEN__)
- #define OS_PLATFORM "js"
- #else
- #define OS_PLATFORM "linux"
- #endif
- #define OS_FLAG(x) JS_PROP_INT32_DEF(#x, x, JS_PROP_CONFIGURABLE )
- static const JSCFunctionListEntry js_os_funcs[] = {
- JS_CFUNC_DEF("open", 2, js_os_open ),
- OS_FLAG(O_RDONLY),
- OS_FLAG(O_WRONLY),
- OS_FLAG(O_RDWR),
- OS_FLAG(O_APPEND),
- OS_FLAG(O_CREAT),
- OS_FLAG(O_EXCL),
- OS_FLAG(O_TRUNC),
- #if defined(_WIN32)
- OS_FLAG(O_BINARY),
- OS_FLAG(O_TEXT),
- #endif
- JS_CFUNC_DEF("close", 1, js_os_close ),
- JS_CFUNC_DEF("seek", 3, js_os_seek ),
- JS_CFUNC_MAGIC_DEF("read", 4, js_os_read_write, 0 ),
- JS_CFUNC_MAGIC_DEF("write", 4, js_os_read_write, 1 ),
- JS_CFUNC_DEF("isatty", 1, js_os_isatty ),
- JS_CFUNC_DEF("ttyGetWinSize", 1, js_os_ttyGetWinSize ),
- JS_CFUNC_DEF("ttySetRaw", 1, js_os_ttySetRaw ),
- JS_CFUNC_DEF("remove", 1, js_os_remove ),
- JS_CFUNC_DEF("rename", 2, js_os_rename ),
- JS_CFUNC_MAGIC_DEF("setReadHandler", 2, js_os_setReadHandler, 0 ),
- JS_CFUNC_MAGIC_DEF("setWriteHandler", 2, js_os_setReadHandler, 1 ),
- JS_CFUNC_DEF("signal", 2, js_os_signal ),
- OS_FLAG(SIGINT),
- OS_FLAG(SIGABRT),
- OS_FLAG(SIGFPE),
- OS_FLAG(SIGILL),
- OS_FLAG(SIGSEGV),
- OS_FLAG(SIGTERM),
- #if !defined(_WIN32)
- OS_FLAG(SIGQUIT),
- OS_FLAG(SIGPIPE),
- OS_FLAG(SIGALRM),
- OS_FLAG(SIGUSR1),
- OS_FLAG(SIGUSR2),
- OS_FLAG(SIGCHLD),
- OS_FLAG(SIGCONT),
- OS_FLAG(SIGSTOP),
- OS_FLAG(SIGTSTP),
- OS_FLAG(SIGTTIN),
- OS_FLAG(SIGTTOU),
- #endif
- JS_CFUNC_DEF("now", 0, js_os_now ),
- JS_CFUNC_DEF("setTimeout", 2, js_os_setTimeout ),
- JS_CFUNC_DEF("clearTimeout", 1, js_os_clearTimeout ),
- JS_CFUNC_DEF("sleepAsync", 1, js_os_sleepAsync ),
- JS_PROP_STRING_DEF("platform", OS_PLATFORM, 0 ),
- JS_CFUNC_DEF("getcwd", 0, js_os_getcwd ),
- JS_CFUNC_DEF("chdir", 0, js_os_chdir ),
- JS_CFUNC_DEF("mkdir", 1, js_os_mkdir ),
- JS_CFUNC_DEF("readdir", 1, js_os_readdir ),
- /* st_mode constants */
- OS_FLAG(S_IFMT),
- OS_FLAG(S_IFIFO),
- OS_FLAG(S_IFCHR),
- OS_FLAG(S_IFDIR),
- OS_FLAG(S_IFBLK),
- OS_FLAG(S_IFREG),
- #if !defined(_WIN32)
- OS_FLAG(S_IFSOCK),
- OS_FLAG(S_IFLNK),
- OS_FLAG(S_ISGID),
- OS_FLAG(S_ISUID),
- #endif
- JS_CFUNC_MAGIC_DEF("stat", 1, js_os_stat, 0 ),
- JS_CFUNC_DEF("utimes", 3, js_os_utimes ),
- JS_CFUNC_DEF("sleep", 1, js_os_sleep ),
- JS_CFUNC_DEF("realpath", 1, js_os_realpath ),
- #if !defined(_WIN32)
- JS_CFUNC_MAGIC_DEF("lstat", 1, js_os_stat, 1 ),
- JS_CFUNC_DEF("symlink", 2, js_os_symlink ),
- JS_CFUNC_DEF("readlink", 1, js_os_readlink ),
- JS_CFUNC_DEF("exec", 1, js_os_exec ),
- JS_CFUNC_DEF("getpid", 0, js_os_getpid ),
- JS_CFUNC_DEF("waitpid", 2, js_os_waitpid ),
- OS_FLAG(WNOHANG),
- JS_CFUNC_DEF("pipe", 0, js_os_pipe ),
- JS_CFUNC_DEF("kill", 2, js_os_kill ),
- JS_CFUNC_DEF("dup", 1, js_os_dup ),
- JS_CFUNC_DEF("dup2", 2, js_os_dup2 ),
- #endif
- };
- static int js_os_init(JSContext *ctx, JSModuleDef *m)
- {
- os_poll_func = js_os_poll;
- #ifdef USE_WORKER
- {
- JSRuntime *rt = JS_GetRuntime(ctx);
- JSThreadState *ts = JS_GetRuntimeOpaque(rt);
- JSValue proto, obj;
- /* Worker class */
- JS_NewClassID(&js_worker_class_id);
- JS_NewClass(JS_GetRuntime(ctx), js_worker_class_id, &js_worker_class);
- proto = JS_NewObject(ctx);
- JS_SetPropertyFunctionList(ctx, proto, js_worker_proto_funcs, countof(js_worker_proto_funcs));
- obj = JS_NewCFunction2(ctx, js_worker_ctor, "Worker", 1,
- JS_CFUNC_constructor, 0);
- JS_SetConstructor(ctx, obj, proto);
- JS_SetClassProto(ctx, js_worker_class_id, proto);
- /* set 'Worker.parent' if necessary */
- if (ts->recv_pipe && ts->send_pipe) {
- JS_DefinePropertyValueStr(ctx, obj, "parent",
- js_worker_ctor_internal(ctx, JS_UNDEFINED, ts->recv_pipe, ts->send_pipe),
- JS_PROP_C_W_E);
- }
- JS_SetModuleExport(ctx, m, "Worker", obj);
- }
- #endif /* USE_WORKER */
- return JS_SetModuleExportList(ctx, m, js_os_funcs,
- countof(js_os_funcs));
- }
- JSModuleDef *js_init_module_os(JSContext *ctx, const char *module_name)
- {
- JSModuleDef *m;
- m = JS_NewCModule(ctx, module_name, js_os_init);
- if (!m)
- return NULL;
- JS_AddModuleExportList(ctx, m, js_os_funcs, countof(js_os_funcs));
- #ifdef USE_WORKER
- JS_AddModuleExport(ctx, m, "Worker");
- #endif
- return m;
- }
- /**********************************************************/
- static JSValue js_print(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- int i;
- JSValueConst v;
-
- for(i = 0; i < argc; i++) {
- if (i != 0)
- putchar(' ');
- v = argv[i];
- if (JS_IsString(v)) {
- const char *str;
- size_t len;
- str = JS_ToCStringLen(ctx, &len, v);
- if (!str)
- return JS_EXCEPTION;
- fwrite(str, 1, len, stdout);
- JS_FreeCString(ctx, str);
- } else {
- JS_PrintValue(ctx, js_print_value_write, stdout, v, NULL);
- }
- }
- putchar('\n');
- return JS_UNDEFINED;
- }
- static JSValue js_console_log(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSValue ret;
- ret = js_print(ctx, this_val, argc, argv);
- fflush(stdout);
- return ret;
- }
- void js_std_add_helpers(JSContext *ctx, int argc, char **argv)
- {
- JSValue global_obj, console, args, performance;
- int i;
- /* XXX: should these global definitions be enumerable? */
- global_obj = JS_GetGlobalObject(ctx);
- console = JS_NewObject(ctx);
- JS_SetPropertyStr(ctx, console, "log",
- JS_NewCFunction(ctx, js_console_log, "log", 1));
- JS_SetPropertyStr(ctx, global_obj, "console", console);
- performance = JS_NewObject(ctx);
- JS_SetPropertyStr(ctx, performance, "now",
- JS_NewCFunction(ctx, js_os_now, "now", 0));
- JS_SetPropertyStr(ctx, global_obj, "performance", performance);
- /* same methods as the mozilla JS shell */
- if (argc >= 0) {
- args = JS_NewArray(ctx);
- for(i = 0; i < argc; i++) {
- JS_SetPropertyUint32(ctx, args, i, JS_NewString(ctx, argv[i]));
- }
- JS_SetPropertyStr(ctx, global_obj, "scriptArgs", args);
- }
- JS_SetPropertyStr(ctx, global_obj, "print",
- JS_NewCFunction(ctx, js_print, "print", 1));
- JS_SetPropertyStr(ctx, global_obj, "__loadScript",
- JS_NewCFunction(ctx, js_loadScript, "__loadScript", 1));
- JS_FreeValue(ctx, global_obj);
- }
- void js_std_init_handlers(JSRuntime *rt)
- {
- JSThreadState *ts;
- ts = malloc(sizeof(*ts));
- if (!ts) {
- fprintf(stderr, "Could not allocate memory for the worker");
- exit(1);
- }
- memset(ts, 0, sizeof(*ts));
- init_list_head(&ts->os_rw_handlers);
- init_list_head(&ts->os_signal_handlers);
- init_list_head(&ts->os_timers);
- init_list_head(&ts->port_list);
- init_list_head(&ts->rejected_promise_list);
- ts->next_timer_id = 1;
- JS_SetRuntimeOpaque(rt, ts);
- #ifdef USE_WORKER
- /* set the SharedArrayBuffer memory handlers */
- {
- JSSharedArrayBufferFunctions sf;
- memset(&sf, 0, sizeof(sf));
- sf.sab_alloc = js_sab_alloc;
- sf.sab_free = js_sab_free;
- sf.sab_dup = js_sab_dup;
- JS_SetSharedArrayBufferFunctions(rt, &sf);
- }
- #endif
- }
- void js_std_free_handlers(JSRuntime *rt)
- {
- JSThreadState *ts = JS_GetRuntimeOpaque(rt);
- struct list_head *el, *el1;
- list_for_each_safe(el, el1, &ts->os_rw_handlers) {
- JSOSRWHandler *rh = list_entry(el, JSOSRWHandler, link);
- free_rw_handler(rt, rh);
- }
- list_for_each_safe(el, el1, &ts->os_signal_handlers) {
- JSOSSignalHandler *sh = list_entry(el, JSOSSignalHandler, link);
- free_sh(rt, sh);
- }
- list_for_each_safe(el, el1, &ts->os_timers) {
- JSOSTimer *th = list_entry(el, JSOSTimer, link);
- free_timer(rt, th);
- }
- list_for_each_safe(el, el1, &ts->rejected_promise_list) {
- JSRejectedPromiseEntry *rp = list_entry(el, JSRejectedPromiseEntry, link);
- JS_FreeValueRT(rt, rp->promise);
- JS_FreeValueRT(rt, rp->reason);
- free(rp);
- }
- #ifdef USE_WORKER
- js_free_message_pipe(ts->recv_pipe);
- js_free_message_pipe(ts->send_pipe);
- list_for_each_safe(el, el1, &ts->port_list) {
- JSWorkerMessageHandler *port = list_entry(el, JSWorkerMessageHandler, link);
- /* unlink the message ports. They are freed by the Worker object */
- port->link.prev = NULL;
- port->link.next = NULL;
- }
- #endif
- #if !defined(_WIN32)
- free(ts->poll_fds);
- #endif
- free(ts);
- JS_SetRuntimeOpaque(rt, NULL); /* fail safe */
- }
- static void js_std_dump_error1(JSContext *ctx, JSValueConst exception_val)
- {
- JS_PrintValue(ctx, js_print_value_write, stderr, exception_val, NULL);
- fputc('\n', stderr);
- }
- void js_std_dump_error(JSContext *ctx)
- {
- JSValue exception_val;
- exception_val = JS_GetException(ctx);
- js_std_dump_error1(ctx, exception_val);
- JS_FreeValue(ctx, exception_val);
- }
- static JSRejectedPromiseEntry *find_rejected_promise(JSContext *ctx, JSThreadState *ts,
- JSValueConst promise)
- {
- struct list_head *el;
- list_for_each(el, &ts->rejected_promise_list) {
- JSRejectedPromiseEntry *rp = list_entry(el, JSRejectedPromiseEntry, link);
- if (JS_SameValue(ctx, rp->promise, promise))
- return rp;
- }
- return NULL;
- }
- void js_std_promise_rejection_tracker(JSContext *ctx, JSValueConst promise,
- JSValueConst reason,
- BOOL is_handled, void *opaque)
- {
- JSRuntime *rt = JS_GetRuntime(ctx);
- JSThreadState *ts = JS_GetRuntimeOpaque(rt);
- JSRejectedPromiseEntry *rp;
- if (!is_handled) {
- /* add a new entry if needed */
- rp = find_rejected_promise(ctx, ts, promise);
- if (!rp) {
- rp = malloc(sizeof(*rp));
- if (rp) {
- rp->promise = JS_DupValue(ctx, promise);
- rp->reason = JS_DupValue(ctx, reason);
- list_add_tail(&rp->link, &ts->rejected_promise_list);
- }
- }
- } else {
- /* the rejection is handled, so the entry can be removed if present */
- rp = find_rejected_promise(ctx, ts, promise);
- if (rp) {
- JS_FreeValue(ctx, rp->promise);
- JS_FreeValue(ctx, rp->reason);
- list_del(&rp->link);
- free(rp);
- }
- }
- }
- /* check if there are pending promise rejections. It must be done
- asynchrously in case a rejected promise is handled later. Currently
- we do it once the application is about to sleep. It could be done
- more often if needed. */
- static void js_std_promise_rejection_check(JSContext *ctx)
- {
- JSRuntime *rt = JS_GetRuntime(ctx);
- JSThreadState *ts = JS_GetRuntimeOpaque(rt);
- struct list_head *el;
- if (unlikely(!list_empty(&ts->rejected_promise_list))) {
- list_for_each(el, &ts->rejected_promise_list) {
- JSRejectedPromiseEntry *rp = list_entry(el, JSRejectedPromiseEntry, link);
- fprintf(stderr, "Possibly unhandled promise rejection: ");
- js_std_dump_error1(ctx, rp->reason);
- }
- exit(1);
- }
- }
- /* main loop which calls the user JS callbacks */
- void js_std_loop(JSContext *ctx)
- {
- int err;
- for(;;) {
- /* execute the pending jobs */
- for(;;) {
- err = JS_ExecutePendingJob(JS_GetRuntime(ctx), NULL);
- if (err <= 0) {
- if (err < 0)
- js_std_dump_error(ctx);
- break;
- }
- }
- js_std_promise_rejection_check(ctx);
-
- if (!os_poll_func || os_poll_func(ctx))
- break;
- }
- }
- /* Wait for a promise and execute pending jobs while waiting for
- it. Return the promise result or JS_EXCEPTION in case of promise
- rejection. */
- JSValue js_std_await(JSContext *ctx, JSValue obj)
- {
- JSValue ret;
- int state;
- for(;;) {
- state = JS_PromiseState(ctx, obj);
- if (state == JS_PROMISE_FULFILLED) {
- ret = JS_PromiseResult(ctx, obj);
- JS_FreeValue(ctx, obj);
- break;
- } else if (state == JS_PROMISE_REJECTED) {
- ret = JS_Throw(ctx, JS_PromiseResult(ctx, obj));
- JS_FreeValue(ctx, obj);
- break;
- } else if (state == JS_PROMISE_PENDING) {
- int err;
- err = JS_ExecutePendingJob(JS_GetRuntime(ctx), NULL);
- if (err < 0) {
- js_std_dump_error(ctx);
- }
- if (err == 0) {
- js_std_promise_rejection_check(ctx);
- if (os_poll_func)
- os_poll_func(ctx);
- }
- } else {
- /* not a promise */
- ret = obj;
- break;
- }
- }
- return ret;
- }
- void js_std_eval_binary(JSContext *ctx, const uint8_t *buf, size_t buf_len,
- int load_only)
- {
- JSValue obj, val;
- obj = JS_ReadObject(ctx, buf, buf_len, JS_READ_OBJ_BYTECODE);
- if (JS_IsException(obj))
- goto exception;
- if (load_only) {
- if (JS_VALUE_GET_TAG(obj) == JS_TAG_MODULE) {
- js_module_set_import_meta(ctx, obj, FALSE, FALSE);
- }
- JS_FreeValue(ctx, obj);
- } else {
- if (JS_VALUE_GET_TAG(obj) == JS_TAG_MODULE) {
- if (JS_ResolveModule(ctx, obj) < 0) {
- JS_FreeValue(ctx, obj);
- goto exception;
- }
- js_module_set_import_meta(ctx, obj, FALSE, TRUE);
- val = JS_EvalFunction(ctx, obj);
- val = js_std_await(ctx, val);
- } else {
- val = JS_EvalFunction(ctx, obj);
- }
- if (JS_IsException(val)) {
- exception:
- js_std_dump_error(ctx);
- exit(1);
- }
- JS_FreeValue(ctx, val);
- }
- }
- void js_std_eval_binary_json_module(JSContext *ctx,
- const uint8_t *buf, size_t buf_len,
- const char *module_name)
- {
- JSValue obj;
- JSModuleDef *m;
-
- obj = JS_ReadObject(ctx, buf, buf_len, 0);
- if (JS_IsException(obj))
- goto exception;
- m = create_json_module(ctx, module_name, obj);
- if (!m) {
- exception:
- js_std_dump_error(ctx);
- exit(1);
- }
- }
|