quickjs-libc.c 122 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403
  1. /*
  2. * QuickJS C library
  3. *
  4. * Copyright (c) 2017-2021 Fabrice Bellard
  5. * Copyright (c) 2017-2021 Charlie Gordon
  6. *
  7. * Permission is hereby granted, free of charge, to any person obtaining a copy
  8. * of this software and associated documentation files (the "Software"), to deal
  9. * in the Software without restriction, including without limitation the rights
  10. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  11. * copies of the Software, and to permit persons to whom the Software is
  12. * furnished to do so, subject to the following conditions:
  13. *
  14. * The above copyright notice and this permission notice shall be included in
  15. * all copies or substantial portions of the Software.
  16. *
  17. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  18. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  19. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  20. * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  21. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  22. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  23. * THE SOFTWARE.
  24. */
  25. #include <stdlib.h>
  26. #include <stdio.h>
  27. #include <stdarg.h>
  28. #include <inttypes.h>
  29. #include <string.h>
  30. #include <assert.h>
  31. #include <unistd.h>
  32. #include <errno.h>
  33. #include <fcntl.h>
  34. #include <sys/time.h>
  35. #include <time.h>
  36. #include <signal.h>
  37. #include <limits.h>
  38. #include <sys/stat.h>
  39. #include <dirent.h>
  40. #if defined(_WIN32)
  41. #include <windows.h>
  42. #include <conio.h>
  43. #include <utime.h>
  44. #else
  45. #include <dlfcn.h>
  46. #include <termios.h>
  47. #include <sys/ioctl.h>
  48. #include <sys/wait.h>
  49. #include <poll.h>
  50. #if defined(__FreeBSD__)
  51. extern char **environ;
  52. #endif
  53. #if defined(__APPLE__) || defined(__FreeBSD__)
  54. typedef sig_t sighandler_t;
  55. #endif
  56. #if defined(__APPLE__)
  57. #if !defined(environ)
  58. #include <crt_externs.h>
  59. #define environ (*_NSGetEnviron())
  60. #endif
  61. #endif /* __APPLE__ */
  62. #endif
  63. /* enable the os.Worker API. It relies on POSIX threads */
  64. #define USE_WORKER
  65. #ifdef USE_WORKER
  66. #include <pthread.h>
  67. #include <stdatomic.h>
  68. #endif
  69. #include "cutils.h"
  70. #include "list.h"
  71. #include "quickjs-libc.h"
  72. #if !defined(PATH_MAX)
  73. #define PATH_MAX 4096
  74. #endif
  75. /* TODO:
  76. - add socket calls
  77. */
  78. typedef struct {
  79. struct list_head link;
  80. int fd;
  81. int poll_fd_index; /* temporary use in js_os_poll() */
  82. JSValue rw_func[2];
  83. } JSOSRWHandler;
  84. typedef struct {
  85. struct list_head link;
  86. int sig_num;
  87. JSValue func;
  88. } JSOSSignalHandler;
  89. typedef struct {
  90. struct list_head link;
  91. int timer_id;
  92. int64_t timeout;
  93. JSValue func;
  94. } JSOSTimer;
  95. typedef struct {
  96. struct list_head link;
  97. uint8_t *data;
  98. size_t data_len;
  99. /* list of SharedArrayBuffers, necessary to free the message */
  100. uint8_t **sab_tab;
  101. size_t sab_tab_len;
  102. } JSWorkerMessage;
  103. typedef struct JSWaker {
  104. #ifdef _WIN32
  105. HANDLE handle;
  106. #else
  107. int read_fd;
  108. int write_fd;
  109. #endif
  110. } JSWaker;
  111. typedef struct {
  112. int ref_count;
  113. #ifdef USE_WORKER
  114. pthread_mutex_t mutex;
  115. #endif
  116. struct list_head msg_queue; /* list of JSWorkerMessage.link */
  117. JSWaker waker;
  118. } JSWorkerMessagePipe;
  119. typedef struct {
  120. struct list_head link;
  121. JSWorkerMessagePipe *recv_pipe;
  122. JSValue on_message_func;
  123. int poll_fd_index; /* temporary use in js_os_poll() */
  124. } JSWorkerMessageHandler;
  125. typedef struct {
  126. struct list_head link;
  127. JSValue promise;
  128. JSValue reason;
  129. } JSRejectedPromiseEntry;
  130. typedef struct JSThreadState {
  131. struct list_head os_rw_handlers; /* list of JSOSRWHandler.link */
  132. struct list_head os_signal_handlers; /* list JSOSSignalHandler.link */
  133. struct list_head os_timers; /* list of JSOSTimer.link */
  134. struct list_head port_list; /* list of JSWorkerMessageHandler.link */
  135. struct list_head rejected_promise_list; /* list of JSRejectedPromiseEntry.link */
  136. int eval_script_recurse; /* only used in the main thread */
  137. int next_timer_id; /* for setTimeout() */
  138. /* not used in the main thread */
  139. JSWorkerMessagePipe *recv_pipe, *send_pipe;
  140. #if !defined(_WIN32)
  141. struct pollfd *poll_fds;
  142. int poll_fds_size;
  143. #endif
  144. } JSThreadState;
  145. static uint64_t os_pending_signals;
  146. static int (*os_poll_func)(JSContext *ctx);
  147. static void js_std_dbuf_init(JSContext *ctx, DynBuf *s)
  148. {
  149. dbuf_init2(s, JS_GetRuntime(ctx), (DynBufReallocFunc *)js_realloc_rt);
  150. }
  151. static BOOL my_isdigit(int c)
  152. {
  153. return (c >= '0' && c <= '9');
  154. }
  155. /* XXX: use 'o' and 'O' for object using JS_PrintValue() ? */
  156. static JSValue js_printf_internal(JSContext *ctx,
  157. int argc, JSValueConst *argv, FILE *fp)
  158. {
  159. char fmtbuf[32];
  160. uint8_t cbuf[UTF8_CHAR_LEN_MAX+1];
  161. JSValue res;
  162. DynBuf dbuf;
  163. const char *fmt_str = NULL;
  164. const uint8_t *fmt, *fmt_end;
  165. const uint8_t *p;
  166. char *q;
  167. int i, c, len, mod;
  168. size_t fmt_len;
  169. int32_t int32_arg;
  170. int64_t int64_arg;
  171. double double_arg;
  172. const char *string_arg;
  173. /* Use indirect call to dbuf_printf to prevent gcc warning */
  174. int (*dbuf_printf_fun)(DynBuf *s, const char *fmt, ...) = (void*)dbuf_printf;
  175. js_std_dbuf_init(ctx, &dbuf);
  176. if (argc > 0) {
  177. fmt_str = JS_ToCStringLen(ctx, &fmt_len, argv[0]);
  178. if (!fmt_str)
  179. goto fail;
  180. i = 1;
  181. fmt = (const uint8_t *)fmt_str;
  182. fmt_end = fmt + fmt_len;
  183. while (fmt < fmt_end) {
  184. for (p = fmt; fmt < fmt_end && *fmt != '%'; fmt++)
  185. continue;
  186. dbuf_put(&dbuf, p, fmt - p);
  187. if (fmt >= fmt_end)
  188. break;
  189. q = fmtbuf;
  190. *q++ = *fmt++; /* copy '%' */
  191. /* flags */
  192. for(;;) {
  193. c = *fmt;
  194. if (c == '0' || c == '#' || c == '+' || c == '-' || c == ' ' ||
  195. c == '\'') {
  196. if (q >= fmtbuf + sizeof(fmtbuf) - 1)
  197. goto invalid;
  198. *q++ = c;
  199. fmt++;
  200. } else {
  201. break;
  202. }
  203. }
  204. /* width */
  205. if (*fmt == '*') {
  206. if (i >= argc)
  207. goto missing;
  208. if (JS_ToInt32(ctx, &int32_arg, argv[i++]))
  209. goto fail;
  210. q += snprintf(q, fmtbuf + sizeof(fmtbuf) - q, "%d", int32_arg);
  211. fmt++;
  212. } else {
  213. while (my_isdigit(*fmt)) {
  214. if (q >= fmtbuf + sizeof(fmtbuf) - 1)
  215. goto invalid;
  216. *q++ = *fmt++;
  217. }
  218. }
  219. if (*fmt == '.') {
  220. if (q >= fmtbuf + sizeof(fmtbuf) - 1)
  221. goto invalid;
  222. *q++ = *fmt++;
  223. if (*fmt == '*') {
  224. if (i >= argc)
  225. goto missing;
  226. if (JS_ToInt32(ctx, &int32_arg, argv[i++]))
  227. goto fail;
  228. q += snprintf(q, fmtbuf + sizeof(fmtbuf) - q, "%d", int32_arg);
  229. fmt++;
  230. } else {
  231. while (my_isdigit(*fmt)) {
  232. if (q >= fmtbuf + sizeof(fmtbuf) - 1)
  233. goto invalid;
  234. *q++ = *fmt++;
  235. }
  236. }
  237. }
  238. /* we only support the "l" modifier for 64 bit numbers */
  239. mod = ' ';
  240. if (*fmt == 'l') {
  241. mod = *fmt++;
  242. }
  243. /* type */
  244. c = *fmt++;
  245. if (q >= fmtbuf + sizeof(fmtbuf) - 1)
  246. goto invalid;
  247. *q++ = c;
  248. *q = '\0';
  249. switch (c) {
  250. case 'c':
  251. if (i >= argc)
  252. goto missing;
  253. if (JS_IsString(argv[i])) {
  254. string_arg = JS_ToCString(ctx, argv[i++]);
  255. if (!string_arg)
  256. goto fail;
  257. int32_arg = unicode_from_utf8((const uint8_t *)string_arg, UTF8_CHAR_LEN_MAX, &p);
  258. JS_FreeCString(ctx, string_arg);
  259. } else {
  260. if (JS_ToInt32(ctx, &int32_arg, argv[i++]))
  261. goto fail;
  262. }
  263. /* handle utf-8 encoding explicitly */
  264. if ((unsigned)int32_arg > 0x10FFFF)
  265. int32_arg = 0xFFFD;
  266. /* ignore conversion flags, width and precision */
  267. len = unicode_to_utf8(cbuf, int32_arg);
  268. dbuf_put(&dbuf, cbuf, len);
  269. break;
  270. case 'd':
  271. case 'i':
  272. case 'o':
  273. case 'u':
  274. case 'x':
  275. case 'X':
  276. if (i >= argc)
  277. goto missing;
  278. if (JS_ToInt64Ext(ctx, &int64_arg, argv[i++]))
  279. goto fail;
  280. if (mod == 'l') {
  281. /* 64 bit number */
  282. #if defined(_WIN32)
  283. if (q >= fmtbuf + sizeof(fmtbuf) - 3)
  284. goto invalid;
  285. q[2] = q[-1];
  286. q[-1] = 'I';
  287. q[0] = '6';
  288. q[1] = '4';
  289. q[3] = '\0';
  290. dbuf_printf_fun(&dbuf, fmtbuf, (int64_t)int64_arg);
  291. #else
  292. if (q >= fmtbuf + sizeof(fmtbuf) - 2)
  293. goto invalid;
  294. q[1] = q[-1];
  295. q[-1] = q[0] = 'l';
  296. q[2] = '\0';
  297. dbuf_printf_fun(&dbuf, fmtbuf, (long long)int64_arg);
  298. #endif
  299. } else {
  300. dbuf_printf_fun(&dbuf, fmtbuf, (int)int64_arg);
  301. }
  302. break;
  303. case 's':
  304. if (i >= argc)
  305. goto missing;
  306. /* XXX: handle strings containing null characters */
  307. string_arg = JS_ToCString(ctx, argv[i++]);
  308. if (!string_arg)
  309. goto fail;
  310. dbuf_printf_fun(&dbuf, fmtbuf, string_arg);
  311. JS_FreeCString(ctx, string_arg);
  312. break;
  313. case 'e':
  314. case 'f':
  315. case 'g':
  316. case 'a':
  317. case 'E':
  318. case 'F':
  319. case 'G':
  320. case 'A':
  321. if (i >= argc)
  322. goto missing;
  323. if (JS_ToFloat64(ctx, &double_arg, argv[i++]))
  324. goto fail;
  325. dbuf_printf_fun(&dbuf, fmtbuf, double_arg);
  326. break;
  327. case '%':
  328. dbuf_putc(&dbuf, '%');
  329. break;
  330. default:
  331. /* XXX: should support an extension mechanism */
  332. invalid:
  333. JS_ThrowTypeError(ctx, "invalid conversion specifier in format string");
  334. goto fail;
  335. missing:
  336. JS_ThrowReferenceError(ctx, "missing argument for conversion specifier");
  337. goto fail;
  338. }
  339. }
  340. JS_FreeCString(ctx, fmt_str);
  341. }
  342. if (dbuf.error) {
  343. res = JS_ThrowOutOfMemory(ctx);
  344. } else {
  345. if (fp) {
  346. len = fwrite(dbuf.buf, 1, dbuf.size, fp);
  347. res = JS_NewInt32(ctx, len);
  348. } else {
  349. res = JS_NewStringLen(ctx, (char *)dbuf.buf, dbuf.size);
  350. }
  351. }
  352. dbuf_free(&dbuf);
  353. return res;
  354. fail:
  355. JS_FreeCString(ctx, fmt_str);
  356. dbuf_free(&dbuf);
  357. return JS_EXCEPTION;
  358. }
  359. uint8_t *js_load_file(JSContext *ctx, size_t *pbuf_len, const char *filename)
  360. {
  361. FILE *f;
  362. uint8_t *buf;
  363. size_t buf_len;
  364. long lret;
  365. f = fopen(filename, "rb");
  366. if (!f)
  367. return NULL;
  368. if (fseek(f, 0, SEEK_END) < 0)
  369. goto fail;
  370. lret = ftell(f);
  371. if (lret < 0)
  372. goto fail;
  373. /* XXX: on Linux, ftell() return LONG_MAX for directories */
  374. if (lret == LONG_MAX) {
  375. errno = EISDIR;
  376. goto fail;
  377. }
  378. buf_len = lret;
  379. if (fseek(f, 0, SEEK_SET) < 0)
  380. goto fail;
  381. if (ctx)
  382. buf = js_malloc(ctx, buf_len + 1);
  383. else
  384. buf = malloc(buf_len + 1);
  385. if (!buf)
  386. goto fail;
  387. if (fread(buf, 1, buf_len, f) != buf_len) {
  388. errno = EIO;
  389. if (ctx)
  390. js_free(ctx, buf);
  391. else
  392. free(buf);
  393. fail:
  394. fclose(f);
  395. return NULL;
  396. }
  397. buf[buf_len] = '\0';
  398. fclose(f);
  399. *pbuf_len = buf_len;
  400. return buf;
  401. }
  402. /* load and evaluate a file */
  403. static JSValue js_loadScript(JSContext *ctx, JSValueConst this_val,
  404. int argc, JSValueConst *argv)
  405. {
  406. uint8_t *buf;
  407. const char *filename;
  408. JSValue ret;
  409. size_t buf_len;
  410. filename = JS_ToCString(ctx, argv[0]);
  411. if (!filename)
  412. return JS_EXCEPTION;
  413. buf = js_load_file(ctx, &buf_len, filename);
  414. if (!buf) {
  415. JS_ThrowReferenceError(ctx, "could not load '%s'", filename);
  416. JS_FreeCString(ctx, filename);
  417. return JS_EXCEPTION;
  418. }
  419. ret = JS_Eval(ctx, (char *)buf, buf_len, filename,
  420. JS_EVAL_TYPE_GLOBAL);
  421. js_free(ctx, buf);
  422. JS_FreeCString(ctx, filename);
  423. return ret;
  424. }
  425. /* load a file as a UTF-8 encoded string */
  426. static JSValue js_std_loadFile(JSContext *ctx, JSValueConst this_val,
  427. int argc, JSValueConst *argv)
  428. {
  429. uint8_t *buf;
  430. const char *filename;
  431. JSValue ret;
  432. size_t buf_len;
  433. filename = JS_ToCString(ctx, argv[0]);
  434. if (!filename)
  435. return JS_EXCEPTION;
  436. buf = js_load_file(ctx, &buf_len, filename);
  437. JS_FreeCString(ctx, filename);
  438. if (!buf)
  439. return JS_NULL;
  440. ret = JS_NewStringLen(ctx, (char *)buf, buf_len);
  441. js_free(ctx, buf);
  442. return ret;
  443. }
  444. typedef JSModuleDef *(JSInitModuleFunc)(JSContext *ctx,
  445. const char *module_name);
  446. #if defined(_WIN32)
  447. static JSModuleDef *js_module_loader_so(JSContext *ctx,
  448. const char *module_name)
  449. {
  450. JS_ThrowReferenceError(ctx, "shared library modules are not supported yet");
  451. return NULL;
  452. }
  453. #else
  454. static JSModuleDef *js_module_loader_so(JSContext *ctx,
  455. const char *module_name)
  456. {
  457. JSModuleDef *m;
  458. void *hd;
  459. JSInitModuleFunc *init;
  460. char *filename;
  461. if (!strchr(module_name, '/')) {
  462. /* must add a '/' so that the DLL is not searched in the
  463. system library paths */
  464. filename = js_malloc(ctx, strlen(module_name) + 2 + 1);
  465. if (!filename)
  466. return NULL;
  467. strcpy(filename, "./");
  468. strcpy(filename + 2, module_name);
  469. } else {
  470. filename = (char *)module_name;
  471. }
  472. /* C module */
  473. hd = dlopen(filename, RTLD_NOW | RTLD_LOCAL);
  474. if (filename != module_name)
  475. js_free(ctx, filename);
  476. if (!hd) {
  477. JS_ThrowReferenceError(ctx, "could not load module filename '%s' as shared library",
  478. module_name);
  479. goto fail;
  480. }
  481. init = dlsym(hd, "js_init_module");
  482. if (!init) {
  483. JS_ThrowReferenceError(ctx, "could not load module filename '%s': js_init_module not found",
  484. module_name);
  485. goto fail;
  486. }
  487. m = init(ctx, module_name);
  488. if (!m) {
  489. JS_ThrowReferenceError(ctx, "could not load module filename '%s': initialization error",
  490. module_name);
  491. fail:
  492. if (hd)
  493. dlclose(hd);
  494. return NULL;
  495. }
  496. return m;
  497. }
  498. #endif /* !_WIN32 */
  499. int js_module_set_import_meta(JSContext *ctx, JSValueConst func_val,
  500. JS_BOOL use_realpath, JS_BOOL is_main)
  501. {
  502. JSModuleDef *m;
  503. char buf[PATH_MAX + 16];
  504. JSValue meta_obj;
  505. JSAtom module_name_atom;
  506. const char *module_name;
  507. assert(JS_VALUE_GET_TAG(func_val) == JS_TAG_MODULE);
  508. m = JS_VALUE_GET_PTR(func_val);
  509. module_name_atom = JS_GetModuleName(ctx, m);
  510. module_name = JS_AtomToCString(ctx, module_name_atom);
  511. JS_FreeAtom(ctx, module_name_atom);
  512. if (!module_name)
  513. return -1;
  514. if (!strchr(module_name, ':')) {
  515. strcpy(buf, "file://");
  516. #if !defined(_WIN32)
  517. /* realpath() cannot be used with modules compiled with qjsc
  518. because the corresponding module source code is not
  519. necessarily present */
  520. if (use_realpath) {
  521. char *res = realpath(module_name, buf + strlen(buf));
  522. if (!res) {
  523. JS_ThrowTypeError(ctx, "realpath failure");
  524. JS_FreeCString(ctx, module_name);
  525. return -1;
  526. }
  527. } else
  528. #endif
  529. {
  530. pstrcat(buf, sizeof(buf), module_name);
  531. }
  532. } else {
  533. pstrcpy(buf, sizeof(buf), module_name);
  534. }
  535. JS_FreeCString(ctx, module_name);
  536. meta_obj = JS_GetImportMeta(ctx, m);
  537. if (JS_IsException(meta_obj))
  538. return -1;
  539. JS_DefinePropertyValueStr(ctx, meta_obj, "url",
  540. JS_NewString(ctx, buf),
  541. JS_PROP_C_W_E);
  542. JS_DefinePropertyValueStr(ctx, meta_obj, "main",
  543. JS_NewBool(ctx, is_main),
  544. JS_PROP_C_W_E);
  545. JS_FreeValue(ctx, meta_obj);
  546. return 0;
  547. }
  548. static int json_module_init(JSContext *ctx, JSModuleDef *m)
  549. {
  550. JSValue val;
  551. val = JS_GetModulePrivateValue(ctx, m);
  552. JS_SetModuleExport(ctx, m, "default", val);
  553. return 0;
  554. }
  555. static JSModuleDef *create_json_module(JSContext *ctx, const char *module_name, JSValue val)
  556. {
  557. JSModuleDef *m;
  558. m = JS_NewCModule(ctx, module_name, json_module_init);
  559. if (!m) {
  560. JS_FreeValue(ctx, val);
  561. return NULL;
  562. }
  563. /* only export the "default" symbol which will contain the JSON object */
  564. JS_AddModuleExport(ctx, m, "default");
  565. JS_SetModulePrivateValue(ctx, m, val);
  566. return m;
  567. }
  568. /* in order to conform with the specification, only the keys should be
  569. tested and not the associated values. */
  570. int js_module_check_attributes(JSContext *ctx, void *opaque,
  571. JSValueConst attributes)
  572. {
  573. JSPropertyEnum *tab;
  574. uint32_t i, len;
  575. int ret;
  576. const char *cstr;
  577. size_t cstr_len;
  578. if (JS_GetOwnPropertyNames(ctx, &tab, &len, attributes, JS_GPN_ENUM_ONLY | JS_GPN_STRING_MASK))
  579. return -1;
  580. ret = 0;
  581. for(i = 0; i < len; i++) {
  582. cstr = JS_AtomToCStringLen(ctx, &cstr_len, tab[i].atom);
  583. if (!cstr) {
  584. ret = -1;
  585. break;
  586. }
  587. if (!(cstr_len == 4 && !memcmp(cstr, "type", cstr_len))) {
  588. JS_ThrowTypeError(ctx, "import attribute '%s' is not supported", cstr);
  589. ret = -1;
  590. }
  591. JS_FreeCString(ctx, cstr);
  592. if (ret)
  593. break;
  594. }
  595. JS_FreePropertyEnum(ctx, tab, len);
  596. return ret;
  597. }
  598. /* return > 0 if the attributes indicate a JSON module */
  599. int js_module_test_json(JSContext *ctx, JSValueConst attributes)
  600. {
  601. JSValue str;
  602. const char *cstr;
  603. size_t len;
  604. BOOL res;
  605. if (JS_IsUndefined(attributes))
  606. return FALSE;
  607. str = JS_GetPropertyStr(ctx, attributes, "type");
  608. if (!JS_IsString(str))
  609. return FALSE;
  610. cstr = JS_ToCStringLen(ctx, &len, str);
  611. JS_FreeValue(ctx, str);
  612. if (!cstr)
  613. return FALSE;
  614. /* XXX: raise an error if unknown type ? */
  615. if (len == 4 && !memcmp(cstr, "json", len)) {
  616. res = 1;
  617. } else if (len == 5 && !memcmp(cstr, "json5", len)) {
  618. res = 2;
  619. } else {
  620. res = 0;
  621. }
  622. JS_FreeCString(ctx, cstr);
  623. return res;
  624. }
  625. JSModuleDef *js_module_loader(JSContext *ctx,
  626. const char *module_name, void *opaque,
  627. JSValueConst attributes)
  628. {
  629. JSModuleDef *m;
  630. int res;
  631. if (has_suffix(module_name, ".so")) {
  632. m = js_module_loader_so(ctx, module_name);
  633. } else {
  634. size_t buf_len;
  635. uint8_t *buf;
  636. buf = js_load_file(ctx, &buf_len, module_name);
  637. if (!buf) {
  638. JS_ThrowReferenceError(ctx, "could not load module filename '%s'",
  639. module_name);
  640. return NULL;
  641. }
  642. res = js_module_test_json(ctx, attributes);
  643. if (has_suffix(module_name, ".json") || res > 0) {
  644. /* compile as JSON or JSON5 depending on "type" */
  645. JSValue val;
  646. int flags;
  647. if (res == 2)
  648. flags = JS_PARSE_JSON_EXT;
  649. else
  650. flags = 0;
  651. val = JS_ParseJSON2(ctx, (char *)buf, buf_len, module_name, flags);
  652. js_free(ctx, buf);
  653. if (JS_IsException(val))
  654. return NULL;
  655. m = create_json_module(ctx, module_name, val);
  656. if (!m)
  657. return NULL;
  658. } else {
  659. JSValue func_val;
  660. /* compile the module */
  661. func_val = JS_Eval(ctx, (char *)buf, buf_len, module_name,
  662. JS_EVAL_TYPE_MODULE | JS_EVAL_FLAG_COMPILE_ONLY);
  663. js_free(ctx, buf);
  664. if (JS_IsException(func_val))
  665. return NULL;
  666. /* XXX: could propagate the exception */
  667. js_module_set_import_meta(ctx, func_val, TRUE, FALSE);
  668. /* the module is already referenced, so we must free it */
  669. m = JS_VALUE_GET_PTR(func_val);
  670. JS_FreeValue(ctx, func_val);
  671. }
  672. }
  673. return m;
  674. }
  675. static JSValue js_std_exit(JSContext *ctx, JSValueConst this_val,
  676. int argc, JSValueConst *argv)
  677. {
  678. int status;
  679. if (JS_ToInt32(ctx, &status, argv[0]))
  680. status = -1;
  681. exit(status);
  682. return JS_UNDEFINED;
  683. }
  684. static JSValue js_std_getenv(JSContext *ctx, JSValueConst this_val,
  685. int argc, JSValueConst *argv)
  686. {
  687. const char *name, *str;
  688. name = JS_ToCString(ctx, argv[0]);
  689. if (!name)
  690. return JS_EXCEPTION;
  691. str = getenv(name);
  692. JS_FreeCString(ctx, name);
  693. if (!str)
  694. return JS_UNDEFINED;
  695. else
  696. return JS_NewString(ctx, str);
  697. }
  698. #if defined(_WIN32)
  699. static void setenv(const char *name, const char *value, int overwrite)
  700. {
  701. char *str;
  702. size_t name_len, value_len;
  703. name_len = strlen(name);
  704. value_len = strlen(value);
  705. str = malloc(name_len + 1 + value_len + 1);
  706. memcpy(str, name, name_len);
  707. str[name_len] = '=';
  708. memcpy(str + name_len + 1, value, value_len);
  709. str[name_len + 1 + value_len] = '\0';
  710. _putenv(str);
  711. free(str);
  712. }
  713. static void unsetenv(const char *name)
  714. {
  715. setenv(name, "", TRUE);
  716. }
  717. #endif /* _WIN32 */
  718. static JSValue js_std_setenv(JSContext *ctx, JSValueConst this_val,
  719. int argc, JSValueConst *argv)
  720. {
  721. const char *name, *value;
  722. name = JS_ToCString(ctx, argv[0]);
  723. if (!name)
  724. return JS_EXCEPTION;
  725. value = JS_ToCString(ctx, argv[1]);
  726. if (!value) {
  727. JS_FreeCString(ctx, name);
  728. return JS_EXCEPTION;
  729. }
  730. setenv(name, value, TRUE);
  731. JS_FreeCString(ctx, name);
  732. JS_FreeCString(ctx, value);
  733. return JS_UNDEFINED;
  734. }
  735. static JSValue js_std_unsetenv(JSContext *ctx, JSValueConst this_val,
  736. int argc, JSValueConst *argv)
  737. {
  738. const char *name;
  739. name = JS_ToCString(ctx, argv[0]);
  740. if (!name)
  741. return JS_EXCEPTION;
  742. unsetenv(name);
  743. JS_FreeCString(ctx, name);
  744. return JS_UNDEFINED;
  745. }
  746. /* return an object containing the list of the available environment
  747. variables. */
  748. static JSValue js_std_getenviron(JSContext *ctx, JSValueConst this_val,
  749. int argc, JSValueConst *argv)
  750. {
  751. char **envp;
  752. const char *name, *p, *value;
  753. JSValue obj;
  754. uint32_t idx;
  755. size_t name_len;
  756. JSAtom atom;
  757. int ret;
  758. obj = JS_NewObject(ctx);
  759. if (JS_IsException(obj))
  760. return JS_EXCEPTION;
  761. envp = environ;
  762. for(idx = 0; envp[idx] != NULL; idx++) {
  763. name = envp[idx];
  764. p = strchr(name, '=');
  765. name_len = p - name;
  766. if (!p)
  767. continue;
  768. value = p + 1;
  769. atom = JS_NewAtomLen(ctx, name, name_len);
  770. if (atom == JS_ATOM_NULL)
  771. goto fail;
  772. ret = JS_DefinePropertyValue(ctx, obj, atom, JS_NewString(ctx, value),
  773. JS_PROP_C_W_E);
  774. JS_FreeAtom(ctx, atom);
  775. if (ret < 0)
  776. goto fail;
  777. }
  778. return obj;
  779. fail:
  780. JS_FreeValue(ctx, obj);
  781. return JS_EXCEPTION;
  782. }
  783. static JSValue js_std_gc(JSContext *ctx, JSValueConst this_val,
  784. int argc, JSValueConst *argv)
  785. {
  786. JS_RunGC(JS_GetRuntime(ctx));
  787. return JS_UNDEFINED;
  788. }
  789. static int interrupt_handler(JSRuntime *rt, void *opaque)
  790. {
  791. return (os_pending_signals >> SIGINT) & 1;
  792. }
  793. static int get_bool_option(JSContext *ctx, BOOL *pbool,
  794. JSValueConst obj,
  795. const char *option)
  796. {
  797. JSValue val;
  798. val = JS_GetPropertyStr(ctx, obj, option);
  799. if (JS_IsException(val))
  800. return -1;
  801. if (!JS_IsUndefined(val)) {
  802. *pbool = JS_ToBool(ctx, val);
  803. }
  804. JS_FreeValue(ctx, val);
  805. return 0;
  806. }
  807. static JSValue js_evalScript(JSContext *ctx, JSValueConst this_val,
  808. int argc, JSValueConst *argv)
  809. {
  810. JSRuntime *rt = JS_GetRuntime(ctx);
  811. JSThreadState *ts = JS_GetRuntimeOpaque(rt);
  812. const char *str;
  813. size_t len;
  814. JSValue ret;
  815. JSValueConst options_obj;
  816. BOOL backtrace_barrier = FALSE;
  817. BOOL is_async = FALSE;
  818. int flags;
  819. if (argc >= 2) {
  820. options_obj = argv[1];
  821. if (get_bool_option(ctx, &backtrace_barrier, options_obj,
  822. "backtrace_barrier"))
  823. return JS_EXCEPTION;
  824. if (get_bool_option(ctx, &is_async, options_obj,
  825. "async"))
  826. return JS_EXCEPTION;
  827. }
  828. str = JS_ToCStringLen(ctx, &len, argv[0]);
  829. if (!str)
  830. return JS_EXCEPTION;
  831. if (!ts->recv_pipe && ++ts->eval_script_recurse == 1) {
  832. /* install the interrupt handler */
  833. JS_SetInterruptHandler(JS_GetRuntime(ctx), interrupt_handler, NULL);
  834. }
  835. flags = JS_EVAL_TYPE_GLOBAL;
  836. if (backtrace_barrier)
  837. flags |= JS_EVAL_FLAG_BACKTRACE_BARRIER;
  838. if (is_async)
  839. flags |= JS_EVAL_FLAG_ASYNC;
  840. ret = JS_Eval(ctx, str, len, "<evalScript>", flags);
  841. JS_FreeCString(ctx, str);
  842. if (!ts->recv_pipe && --ts->eval_script_recurse == 0) {
  843. /* remove the interrupt handler */
  844. JS_SetInterruptHandler(JS_GetRuntime(ctx), NULL, NULL);
  845. os_pending_signals &= ~((uint64_t)1 << SIGINT);
  846. /* convert the uncatchable "interrupted" error into a normal error
  847. so that it can be caught by the REPL */
  848. if (JS_IsException(ret))
  849. JS_SetUncatchableException(ctx, FALSE);
  850. }
  851. return ret;
  852. }
  853. static JSClassID js_std_file_class_id;
  854. typedef struct {
  855. FILE *f;
  856. BOOL close_in_finalizer;
  857. BOOL is_popen;
  858. } JSSTDFile;
  859. static void js_std_file_finalizer(JSRuntime *rt, JSValue val)
  860. {
  861. JSSTDFile *s = JS_GetOpaque(val, js_std_file_class_id);
  862. if (s) {
  863. if (s->f && s->close_in_finalizer) {
  864. if (s->is_popen)
  865. pclose(s->f);
  866. else
  867. fclose(s->f);
  868. }
  869. js_free_rt(rt, s);
  870. }
  871. }
  872. static ssize_t js_get_errno(ssize_t ret)
  873. {
  874. if (ret == -1)
  875. ret = -errno;
  876. return ret;
  877. }
  878. static JSValue js_std_strerror(JSContext *ctx, JSValueConst this_val,
  879. int argc, JSValueConst *argv)
  880. {
  881. int err;
  882. if (JS_ToInt32(ctx, &err, argv[0]))
  883. return JS_EXCEPTION;
  884. return JS_NewString(ctx, strerror(err));
  885. }
  886. static JSValue js_std_parseExtJSON(JSContext *ctx, JSValueConst this_val,
  887. int argc, JSValueConst *argv)
  888. {
  889. JSValue obj;
  890. const char *str;
  891. size_t len;
  892. str = JS_ToCStringLen(ctx, &len, argv[0]);
  893. if (!str)
  894. return JS_EXCEPTION;
  895. obj = JS_ParseJSON2(ctx, str, len, "<input>", JS_PARSE_JSON_EXT);
  896. JS_FreeCString(ctx, str);
  897. return obj;
  898. }
  899. static JSValue js_new_std_file(JSContext *ctx, FILE *f,
  900. BOOL close_in_finalizer,
  901. BOOL is_popen)
  902. {
  903. JSSTDFile *s;
  904. JSValue obj;
  905. obj = JS_NewObjectClass(ctx, js_std_file_class_id);
  906. if (JS_IsException(obj))
  907. return obj;
  908. s = js_mallocz(ctx, sizeof(*s));
  909. if (!s) {
  910. JS_FreeValue(ctx, obj);
  911. return JS_EXCEPTION;
  912. }
  913. s->close_in_finalizer = close_in_finalizer;
  914. s->is_popen = is_popen;
  915. s->f = f;
  916. JS_SetOpaque(obj, s);
  917. return obj;
  918. }
  919. static void js_set_error_object(JSContext *ctx, JSValue obj, int err)
  920. {
  921. if (!JS_IsUndefined(obj)) {
  922. JS_SetPropertyStr(ctx, obj, "errno", JS_NewInt32(ctx, err));
  923. }
  924. }
  925. static JSValue js_std_open(JSContext *ctx, JSValueConst this_val,
  926. int argc, JSValueConst *argv)
  927. {
  928. const char *filename, *mode = NULL;
  929. FILE *f;
  930. int err;
  931. filename = JS_ToCString(ctx, argv[0]);
  932. if (!filename)
  933. goto fail;
  934. mode = JS_ToCString(ctx, argv[1]);
  935. if (!mode)
  936. goto fail;
  937. if (mode[strspn(mode, "rwa+b")] != '\0') {
  938. JS_ThrowTypeError(ctx, "invalid file mode");
  939. goto fail;
  940. }
  941. f = fopen(filename, mode);
  942. if (!f)
  943. err = errno;
  944. else
  945. err = 0;
  946. if (argc >= 3)
  947. js_set_error_object(ctx, argv[2], err);
  948. JS_FreeCString(ctx, filename);
  949. JS_FreeCString(ctx, mode);
  950. if (!f)
  951. return JS_NULL;
  952. return js_new_std_file(ctx, f, TRUE, FALSE);
  953. fail:
  954. JS_FreeCString(ctx, filename);
  955. JS_FreeCString(ctx, mode);
  956. return JS_EXCEPTION;
  957. }
  958. static JSValue js_std_popen(JSContext *ctx, JSValueConst this_val,
  959. int argc, JSValueConst *argv)
  960. {
  961. const char *filename, *mode = NULL;
  962. FILE *f;
  963. int err;
  964. filename = JS_ToCString(ctx, argv[0]);
  965. if (!filename)
  966. goto fail;
  967. mode = JS_ToCString(ctx, argv[1]);
  968. if (!mode)
  969. goto fail;
  970. if (mode[strspn(mode, "rw")] != '\0') {
  971. JS_ThrowTypeError(ctx, "invalid file mode");
  972. goto fail;
  973. }
  974. f = popen(filename, mode);
  975. if (!f)
  976. err = errno;
  977. else
  978. err = 0;
  979. if (argc >= 3)
  980. js_set_error_object(ctx, argv[2], err);
  981. JS_FreeCString(ctx, filename);
  982. JS_FreeCString(ctx, mode);
  983. if (!f)
  984. return JS_NULL;
  985. return js_new_std_file(ctx, f, TRUE, TRUE);
  986. fail:
  987. JS_FreeCString(ctx, filename);
  988. JS_FreeCString(ctx, mode);
  989. return JS_EXCEPTION;
  990. }
  991. static JSValue js_std_fdopen(JSContext *ctx, JSValueConst this_val,
  992. int argc, JSValueConst *argv)
  993. {
  994. const char *mode;
  995. FILE *f;
  996. int fd, err;
  997. if (JS_ToInt32(ctx, &fd, argv[0]))
  998. return JS_EXCEPTION;
  999. mode = JS_ToCString(ctx, argv[1]);
  1000. if (!mode)
  1001. goto fail;
  1002. if (mode[strspn(mode, "rwa+")] != '\0') {
  1003. JS_ThrowTypeError(ctx, "invalid file mode");
  1004. goto fail;
  1005. }
  1006. f = fdopen(fd, mode);
  1007. if (!f)
  1008. err = errno;
  1009. else
  1010. err = 0;
  1011. if (argc >= 3)
  1012. js_set_error_object(ctx, argv[2], err);
  1013. JS_FreeCString(ctx, mode);
  1014. if (!f)
  1015. return JS_NULL;
  1016. return js_new_std_file(ctx, f, TRUE, FALSE);
  1017. fail:
  1018. JS_FreeCString(ctx, mode);
  1019. return JS_EXCEPTION;
  1020. }
  1021. static JSValue js_std_tmpfile(JSContext *ctx, JSValueConst this_val,
  1022. int argc, JSValueConst *argv)
  1023. {
  1024. FILE *f;
  1025. f = tmpfile();
  1026. if (argc >= 1)
  1027. js_set_error_object(ctx, argv[0], f ? 0 : errno);
  1028. if (!f)
  1029. return JS_NULL;
  1030. return js_new_std_file(ctx, f, TRUE, FALSE);
  1031. }
  1032. static JSValue js_std_sprintf(JSContext *ctx, JSValueConst this_val,
  1033. int argc, JSValueConst *argv)
  1034. {
  1035. return js_printf_internal(ctx, argc, argv, NULL);
  1036. }
  1037. static JSValue js_std_printf(JSContext *ctx, JSValueConst this_val,
  1038. int argc, JSValueConst *argv)
  1039. {
  1040. return js_printf_internal(ctx, argc, argv, stdout);
  1041. }
  1042. static FILE *js_std_file_get(JSContext *ctx, JSValueConst obj)
  1043. {
  1044. JSSTDFile *s = JS_GetOpaque2(ctx, obj, js_std_file_class_id);
  1045. if (!s)
  1046. return NULL;
  1047. if (!s->f) {
  1048. JS_ThrowTypeError(ctx, "invalid file handle");
  1049. return NULL;
  1050. }
  1051. return s->f;
  1052. }
  1053. static JSValue js_std_file_puts(JSContext *ctx, JSValueConst this_val,
  1054. int argc, JSValueConst *argv, int magic)
  1055. {
  1056. FILE *f;
  1057. int i;
  1058. const char *str;
  1059. size_t len;
  1060. if (magic == 0) {
  1061. f = stdout;
  1062. } else {
  1063. f = js_std_file_get(ctx, this_val);
  1064. if (!f)
  1065. return JS_EXCEPTION;
  1066. }
  1067. for(i = 0; i < argc; i++) {
  1068. str = JS_ToCStringLen(ctx, &len, argv[i]);
  1069. if (!str)
  1070. return JS_EXCEPTION;
  1071. fwrite(str, 1, len, f);
  1072. JS_FreeCString(ctx, str);
  1073. }
  1074. return JS_UNDEFINED;
  1075. }
  1076. static JSValue js_std_file_close(JSContext *ctx, JSValueConst this_val,
  1077. int argc, JSValueConst *argv)
  1078. {
  1079. JSSTDFile *s = JS_GetOpaque2(ctx, this_val, js_std_file_class_id);
  1080. int err;
  1081. if (!s)
  1082. return JS_EXCEPTION;
  1083. if (!s->f)
  1084. return JS_ThrowTypeError(ctx, "invalid file handle");
  1085. if (s->is_popen)
  1086. err = js_get_errno(pclose(s->f));
  1087. else
  1088. err = js_get_errno(fclose(s->f));
  1089. s->f = NULL;
  1090. return JS_NewInt32(ctx, err);
  1091. }
  1092. static JSValue js_std_file_printf(JSContext *ctx, JSValueConst this_val,
  1093. int argc, JSValueConst *argv)
  1094. {
  1095. FILE *f = js_std_file_get(ctx, this_val);
  1096. if (!f)
  1097. return JS_EXCEPTION;
  1098. return js_printf_internal(ctx, argc, argv, f);
  1099. }
  1100. static void js_print_value_write(void *opaque, const char *buf, size_t len)
  1101. {
  1102. FILE *fo = opaque;
  1103. fwrite(buf, 1, len, fo);
  1104. }
  1105. static JSValue js_std_file_printObject(JSContext *ctx, JSValueConst this_val,
  1106. int argc, JSValueConst *argv)
  1107. {
  1108. JS_PrintValue(ctx, js_print_value_write, stdout, argv[0], NULL);
  1109. return JS_UNDEFINED;
  1110. }
  1111. static JSValue js_std_file_flush(JSContext *ctx, JSValueConst this_val,
  1112. int argc, JSValueConst *argv)
  1113. {
  1114. FILE *f = js_std_file_get(ctx, this_val);
  1115. if (!f)
  1116. return JS_EXCEPTION;
  1117. fflush(f);
  1118. return JS_UNDEFINED;
  1119. }
  1120. static JSValue js_std_file_tell(JSContext *ctx, JSValueConst this_val,
  1121. int argc, JSValueConst *argv, int is_bigint)
  1122. {
  1123. FILE *f = js_std_file_get(ctx, this_val);
  1124. int64_t pos;
  1125. if (!f)
  1126. return JS_EXCEPTION;
  1127. #if defined(__linux__) || defined(__GLIBC__)
  1128. pos = ftello(f);
  1129. #else
  1130. pos = ftell(f);
  1131. #endif
  1132. if (is_bigint)
  1133. return JS_NewBigInt64(ctx, pos);
  1134. else
  1135. return JS_NewInt64(ctx, pos);
  1136. }
  1137. static JSValue js_std_file_seek(JSContext *ctx, JSValueConst this_val,
  1138. int argc, JSValueConst *argv)
  1139. {
  1140. FILE *f = js_std_file_get(ctx, this_val);
  1141. int64_t pos;
  1142. int whence, ret;
  1143. if (!f)
  1144. return JS_EXCEPTION;
  1145. if (JS_ToInt64Ext(ctx, &pos, argv[0]))
  1146. return JS_EXCEPTION;
  1147. if (JS_ToInt32(ctx, &whence, argv[1]))
  1148. return JS_EXCEPTION;
  1149. #if defined(__linux__) || defined(__GLIBC__)
  1150. ret = fseeko(f, pos, whence);
  1151. #else
  1152. ret = fseek(f, pos, whence);
  1153. #endif
  1154. if (ret < 0)
  1155. ret = -errno;
  1156. return JS_NewInt32(ctx, ret);
  1157. }
  1158. static JSValue js_std_file_eof(JSContext *ctx, JSValueConst this_val,
  1159. int argc, JSValueConst *argv)
  1160. {
  1161. FILE *f = js_std_file_get(ctx, this_val);
  1162. if (!f)
  1163. return JS_EXCEPTION;
  1164. return JS_NewBool(ctx, feof(f));
  1165. }
  1166. static JSValue js_std_file_error(JSContext *ctx, JSValueConst this_val,
  1167. int argc, JSValueConst *argv)
  1168. {
  1169. FILE *f = js_std_file_get(ctx, this_val);
  1170. if (!f)
  1171. return JS_EXCEPTION;
  1172. return JS_NewBool(ctx, ferror(f));
  1173. }
  1174. static JSValue js_std_file_clearerr(JSContext *ctx, JSValueConst this_val,
  1175. int argc, JSValueConst *argv)
  1176. {
  1177. FILE *f = js_std_file_get(ctx, this_val);
  1178. if (!f)
  1179. return JS_EXCEPTION;
  1180. clearerr(f);
  1181. return JS_UNDEFINED;
  1182. }
  1183. static JSValue js_std_file_fileno(JSContext *ctx, JSValueConst this_val,
  1184. int argc, JSValueConst *argv)
  1185. {
  1186. FILE *f = js_std_file_get(ctx, this_val);
  1187. if (!f)
  1188. return JS_EXCEPTION;
  1189. return JS_NewInt32(ctx, fileno(f));
  1190. }
  1191. static JSValue js_std_file_read_write(JSContext *ctx, JSValueConst this_val,
  1192. int argc, JSValueConst *argv, int magic)
  1193. {
  1194. FILE *f = js_std_file_get(ctx, this_val);
  1195. uint64_t pos, len;
  1196. size_t size, ret;
  1197. uint8_t *buf;
  1198. if (!f)
  1199. return JS_EXCEPTION;
  1200. if (JS_ToIndex(ctx, &pos, argv[1]))
  1201. return JS_EXCEPTION;
  1202. if (JS_ToIndex(ctx, &len, argv[2]))
  1203. return JS_EXCEPTION;
  1204. buf = JS_GetArrayBuffer(ctx, &size, argv[0]);
  1205. if (!buf)
  1206. return JS_EXCEPTION;
  1207. if (pos + len > size)
  1208. return JS_ThrowRangeError(ctx, "read/write array buffer overflow");
  1209. if (magic)
  1210. ret = fwrite(buf + pos, 1, len, f);
  1211. else
  1212. ret = fread(buf + pos, 1, len, f);
  1213. return JS_NewInt64(ctx, ret);
  1214. }
  1215. /* XXX: could use less memory and go faster */
  1216. static JSValue js_std_file_getline(JSContext *ctx, JSValueConst this_val,
  1217. int argc, JSValueConst *argv)
  1218. {
  1219. FILE *f = js_std_file_get(ctx, this_val);
  1220. int c;
  1221. DynBuf dbuf;
  1222. JSValue obj;
  1223. if (!f)
  1224. return JS_EXCEPTION;
  1225. js_std_dbuf_init(ctx, &dbuf);
  1226. for(;;) {
  1227. c = fgetc(f);
  1228. if (c == EOF) {
  1229. if (dbuf.size == 0) {
  1230. /* EOF */
  1231. dbuf_free(&dbuf);
  1232. return JS_NULL;
  1233. } else {
  1234. break;
  1235. }
  1236. }
  1237. if (c == '\n')
  1238. break;
  1239. if (dbuf_putc(&dbuf, c)) {
  1240. dbuf_free(&dbuf);
  1241. return JS_ThrowOutOfMemory(ctx);
  1242. }
  1243. }
  1244. obj = JS_NewStringLen(ctx, (const char *)dbuf.buf, dbuf.size);
  1245. dbuf_free(&dbuf);
  1246. return obj;
  1247. }
  1248. /* XXX: could use less memory and go faster */
  1249. static JSValue js_std_file_readAsString(JSContext *ctx, JSValueConst this_val,
  1250. int argc, JSValueConst *argv)
  1251. {
  1252. FILE *f = js_std_file_get(ctx, this_val);
  1253. int c;
  1254. DynBuf dbuf;
  1255. JSValue obj;
  1256. uint64_t max_size64;
  1257. size_t max_size;
  1258. JSValueConst max_size_val;
  1259. if (!f)
  1260. return JS_EXCEPTION;
  1261. if (argc >= 1)
  1262. max_size_val = argv[0];
  1263. else
  1264. max_size_val = JS_UNDEFINED;
  1265. max_size = (size_t)-1;
  1266. if (!JS_IsUndefined(max_size_val)) {
  1267. if (JS_ToIndex(ctx, &max_size64, max_size_val))
  1268. return JS_EXCEPTION;
  1269. if (max_size64 < max_size)
  1270. max_size = max_size64;
  1271. }
  1272. js_std_dbuf_init(ctx, &dbuf);
  1273. while (max_size != 0) {
  1274. c = fgetc(f);
  1275. if (c == EOF)
  1276. break;
  1277. if (dbuf_putc(&dbuf, c)) {
  1278. dbuf_free(&dbuf);
  1279. return JS_EXCEPTION;
  1280. }
  1281. max_size--;
  1282. }
  1283. obj = JS_NewStringLen(ctx, (const char *)dbuf.buf, dbuf.size);
  1284. dbuf_free(&dbuf);
  1285. return obj;
  1286. }
  1287. static JSValue js_std_file_getByte(JSContext *ctx, JSValueConst this_val,
  1288. int argc, JSValueConst *argv)
  1289. {
  1290. FILE *f = js_std_file_get(ctx, this_val);
  1291. if (!f)
  1292. return JS_EXCEPTION;
  1293. return JS_NewInt32(ctx, fgetc(f));
  1294. }
  1295. static JSValue js_std_file_putByte(JSContext *ctx, JSValueConst this_val,
  1296. int argc, JSValueConst *argv)
  1297. {
  1298. FILE *f = js_std_file_get(ctx, this_val);
  1299. int c;
  1300. if (!f)
  1301. return JS_EXCEPTION;
  1302. if (JS_ToInt32(ctx, &c, argv[0]))
  1303. return JS_EXCEPTION;
  1304. c = fputc(c, f);
  1305. return JS_NewInt32(ctx, c);
  1306. }
  1307. /* urlGet */
  1308. #define URL_GET_PROGRAM "curl -s -i --"
  1309. #define URL_GET_BUF_SIZE 4096
  1310. static int http_get_header_line(FILE *f, char *buf, size_t buf_size,
  1311. DynBuf *dbuf)
  1312. {
  1313. int c;
  1314. char *p;
  1315. p = buf;
  1316. for(;;) {
  1317. c = fgetc(f);
  1318. if (c < 0)
  1319. return -1;
  1320. if ((p - buf) < buf_size - 1)
  1321. *p++ = c;
  1322. if (dbuf)
  1323. dbuf_putc(dbuf, c);
  1324. if (c == '\n')
  1325. break;
  1326. }
  1327. *p = '\0';
  1328. return 0;
  1329. }
  1330. static int http_get_status(const char *buf)
  1331. {
  1332. const char *p = buf;
  1333. while (*p != ' ' && *p != '\0')
  1334. p++;
  1335. if (*p != ' ')
  1336. return 0;
  1337. while (*p == ' ')
  1338. p++;
  1339. return atoi(p);
  1340. }
  1341. static JSValue js_std_urlGet(JSContext *ctx, JSValueConst this_val,
  1342. int argc, JSValueConst *argv)
  1343. {
  1344. const char *url;
  1345. DynBuf cmd_buf;
  1346. DynBuf data_buf_s, *data_buf = &data_buf_s;
  1347. DynBuf header_buf_s, *header_buf = &header_buf_s;
  1348. char *buf;
  1349. size_t i, len;
  1350. int status;
  1351. JSValue response = JS_UNDEFINED, ret_obj;
  1352. JSValueConst options_obj;
  1353. FILE *f;
  1354. BOOL binary_flag, full_flag;
  1355. url = JS_ToCString(ctx, argv[0]);
  1356. if (!url)
  1357. return JS_EXCEPTION;
  1358. binary_flag = FALSE;
  1359. full_flag = FALSE;
  1360. if (argc >= 2) {
  1361. options_obj = argv[1];
  1362. if (get_bool_option(ctx, &binary_flag, options_obj, "binary"))
  1363. goto fail_obj;
  1364. if (get_bool_option(ctx, &full_flag, options_obj, "full")) {
  1365. fail_obj:
  1366. JS_FreeCString(ctx, url);
  1367. return JS_EXCEPTION;
  1368. }
  1369. }
  1370. js_std_dbuf_init(ctx, &cmd_buf);
  1371. dbuf_printf(&cmd_buf, "%s '", URL_GET_PROGRAM);
  1372. for(i = 0; url[i] != '\0'; i++) {
  1373. unsigned char c = url[i];
  1374. switch (c) {
  1375. case '\'':
  1376. /* shell single quoted string does not support \' */
  1377. dbuf_putstr(&cmd_buf, "'\\''");
  1378. break;
  1379. case '[': case ']': case '{': case '}': case '\\':
  1380. /* prevent interpretation by curl as range or set specification */
  1381. dbuf_putc(&cmd_buf, '\\');
  1382. /* FALLTHROUGH */
  1383. default:
  1384. dbuf_putc(&cmd_buf, c);
  1385. break;
  1386. }
  1387. }
  1388. JS_FreeCString(ctx, url);
  1389. dbuf_putstr(&cmd_buf, "'");
  1390. dbuf_putc(&cmd_buf, '\0');
  1391. if (dbuf_error(&cmd_buf)) {
  1392. dbuf_free(&cmd_buf);
  1393. return JS_EXCEPTION;
  1394. }
  1395. // printf("%s\n", (char *)cmd_buf.buf);
  1396. f = popen((char *)cmd_buf.buf, "r");
  1397. dbuf_free(&cmd_buf);
  1398. if (!f) {
  1399. return JS_ThrowTypeError(ctx, "could not start curl");
  1400. }
  1401. js_std_dbuf_init(ctx, data_buf);
  1402. js_std_dbuf_init(ctx, header_buf);
  1403. buf = js_malloc(ctx, URL_GET_BUF_SIZE);
  1404. if (!buf)
  1405. goto fail;
  1406. /* get the HTTP status */
  1407. if (http_get_header_line(f, buf, URL_GET_BUF_SIZE, NULL) < 0) {
  1408. status = 0;
  1409. goto bad_header;
  1410. }
  1411. status = http_get_status(buf);
  1412. if (!full_flag && !(status >= 200 && status <= 299)) {
  1413. goto bad_header;
  1414. }
  1415. /* wait until there is an empty line */
  1416. for(;;) {
  1417. if (http_get_header_line(f, buf, URL_GET_BUF_SIZE, header_buf) < 0) {
  1418. bad_header:
  1419. response = JS_NULL;
  1420. goto done;
  1421. }
  1422. if (!strcmp(buf, "\r\n"))
  1423. break;
  1424. }
  1425. if (dbuf_error(header_buf))
  1426. goto fail;
  1427. header_buf->size -= 2; /* remove the trailing CRLF */
  1428. /* download the data */
  1429. for(;;) {
  1430. len = fread(buf, 1, URL_GET_BUF_SIZE, f);
  1431. if (len == 0)
  1432. break;
  1433. dbuf_put(data_buf, (uint8_t *)buf, len);
  1434. }
  1435. if (dbuf_error(data_buf))
  1436. goto fail;
  1437. if (binary_flag) {
  1438. response = JS_NewArrayBufferCopy(ctx,
  1439. data_buf->buf, data_buf->size);
  1440. } else {
  1441. response = JS_NewStringLen(ctx, (char *)data_buf->buf, data_buf->size);
  1442. }
  1443. if (JS_IsException(response))
  1444. goto fail;
  1445. done:
  1446. js_free(ctx, buf);
  1447. buf = NULL;
  1448. pclose(f);
  1449. f = NULL;
  1450. dbuf_free(data_buf);
  1451. data_buf = NULL;
  1452. if (full_flag) {
  1453. ret_obj = JS_NewObject(ctx);
  1454. if (JS_IsException(ret_obj))
  1455. goto fail;
  1456. JS_DefinePropertyValueStr(ctx, ret_obj, "response",
  1457. response,
  1458. JS_PROP_C_W_E);
  1459. if (!JS_IsNull(response)) {
  1460. JS_DefinePropertyValueStr(ctx, ret_obj, "responseHeaders",
  1461. JS_NewStringLen(ctx, (char *)header_buf->buf,
  1462. header_buf->size),
  1463. JS_PROP_C_W_E);
  1464. JS_DefinePropertyValueStr(ctx, ret_obj, "status",
  1465. JS_NewInt32(ctx, status),
  1466. JS_PROP_C_W_E);
  1467. }
  1468. } else {
  1469. ret_obj = response;
  1470. }
  1471. dbuf_free(header_buf);
  1472. return ret_obj;
  1473. fail:
  1474. if (f)
  1475. pclose(f);
  1476. js_free(ctx, buf);
  1477. if (data_buf)
  1478. dbuf_free(data_buf);
  1479. if (header_buf)
  1480. dbuf_free(header_buf);
  1481. JS_FreeValue(ctx, response);
  1482. return JS_EXCEPTION;
  1483. }
  1484. static JSClassDef js_std_file_class = {
  1485. "FILE",
  1486. .finalizer = js_std_file_finalizer,
  1487. };
  1488. static const JSCFunctionListEntry js_std_error_props[] = {
  1489. /* various errno values */
  1490. #define DEF(x) JS_PROP_INT32_DEF(#x, x, JS_PROP_CONFIGURABLE )
  1491. DEF(EINVAL),
  1492. DEF(EIO),
  1493. DEF(EACCES),
  1494. DEF(EEXIST),
  1495. DEF(ENOSPC),
  1496. DEF(ENOSYS),
  1497. DEF(EBUSY),
  1498. DEF(ENOENT),
  1499. DEF(EPERM),
  1500. DEF(EPIPE),
  1501. DEF(EBADF),
  1502. #undef DEF
  1503. };
  1504. static const JSCFunctionListEntry js_std_funcs[] = {
  1505. JS_CFUNC_DEF("exit", 1, js_std_exit ),
  1506. JS_CFUNC_DEF("gc", 0, js_std_gc ),
  1507. JS_CFUNC_DEF("evalScript", 1, js_evalScript ),
  1508. JS_CFUNC_DEF("loadScript", 1, js_loadScript ),
  1509. JS_CFUNC_DEF("getenv", 1, js_std_getenv ),
  1510. JS_CFUNC_DEF("setenv", 1, js_std_setenv ),
  1511. JS_CFUNC_DEF("unsetenv", 1, js_std_unsetenv ),
  1512. JS_CFUNC_DEF("getenviron", 1, js_std_getenviron ),
  1513. JS_CFUNC_DEF("urlGet", 1, js_std_urlGet ),
  1514. JS_CFUNC_DEF("loadFile", 1, js_std_loadFile ),
  1515. JS_CFUNC_DEF("strerror", 1, js_std_strerror ),
  1516. JS_CFUNC_DEF("parseExtJSON", 1, js_std_parseExtJSON ),
  1517. /* FILE I/O */
  1518. JS_CFUNC_DEF("open", 2, js_std_open ),
  1519. JS_CFUNC_DEF("popen", 2, js_std_popen ),
  1520. JS_CFUNC_DEF("fdopen", 2, js_std_fdopen ),
  1521. JS_CFUNC_DEF("tmpfile", 0, js_std_tmpfile ),
  1522. JS_CFUNC_MAGIC_DEF("puts", 1, js_std_file_puts, 0 ),
  1523. JS_CFUNC_DEF("printf", 1, js_std_printf ),
  1524. JS_CFUNC_DEF("sprintf", 1, js_std_sprintf ),
  1525. JS_PROP_INT32_DEF("SEEK_SET", SEEK_SET, JS_PROP_CONFIGURABLE ),
  1526. JS_PROP_INT32_DEF("SEEK_CUR", SEEK_CUR, JS_PROP_CONFIGURABLE ),
  1527. JS_PROP_INT32_DEF("SEEK_END", SEEK_END, JS_PROP_CONFIGURABLE ),
  1528. JS_OBJECT_DEF("Error", js_std_error_props, countof(js_std_error_props), JS_PROP_CONFIGURABLE),
  1529. JS_CFUNC_DEF("__printObject", 1, js_std_file_printObject ),
  1530. };
  1531. static const JSCFunctionListEntry js_std_file_proto_funcs[] = {
  1532. JS_CFUNC_DEF("close", 0, js_std_file_close ),
  1533. JS_CFUNC_MAGIC_DEF("puts", 1, js_std_file_puts, 1 ),
  1534. JS_CFUNC_DEF("printf", 1, js_std_file_printf ),
  1535. JS_CFUNC_DEF("flush", 0, js_std_file_flush ),
  1536. JS_CFUNC_MAGIC_DEF("tell", 0, js_std_file_tell, 0 ),
  1537. JS_CFUNC_MAGIC_DEF("tello", 0, js_std_file_tell, 1 ),
  1538. JS_CFUNC_DEF("seek", 2, js_std_file_seek ),
  1539. JS_CFUNC_DEF("eof", 0, js_std_file_eof ),
  1540. JS_CFUNC_DEF("fileno", 0, js_std_file_fileno ),
  1541. JS_CFUNC_DEF("error", 0, js_std_file_error ),
  1542. JS_CFUNC_DEF("clearerr", 0, js_std_file_clearerr ),
  1543. JS_CFUNC_MAGIC_DEF("read", 3, js_std_file_read_write, 0 ),
  1544. JS_CFUNC_MAGIC_DEF("write", 3, js_std_file_read_write, 1 ),
  1545. JS_CFUNC_DEF("getline", 0, js_std_file_getline ),
  1546. JS_CFUNC_DEF("readAsString", 0, js_std_file_readAsString ),
  1547. JS_CFUNC_DEF("getByte", 0, js_std_file_getByte ),
  1548. JS_CFUNC_DEF("putByte", 1, js_std_file_putByte ),
  1549. /* setvbuf, ... */
  1550. };
  1551. static int js_std_init(JSContext *ctx, JSModuleDef *m)
  1552. {
  1553. JSValue proto;
  1554. /* FILE class */
  1555. /* the class ID is created once */
  1556. JS_NewClassID(&js_std_file_class_id);
  1557. /* the class is created once per runtime */
  1558. JS_NewClass(JS_GetRuntime(ctx), js_std_file_class_id, &js_std_file_class);
  1559. proto = JS_NewObject(ctx);
  1560. JS_SetPropertyFunctionList(ctx, proto, js_std_file_proto_funcs,
  1561. countof(js_std_file_proto_funcs));
  1562. JS_SetClassProto(ctx, js_std_file_class_id, proto);
  1563. JS_SetModuleExportList(ctx, m, js_std_funcs,
  1564. countof(js_std_funcs));
  1565. JS_SetModuleExport(ctx, m, "in", js_new_std_file(ctx, stdin, FALSE, FALSE));
  1566. JS_SetModuleExport(ctx, m, "out", js_new_std_file(ctx, stdout, FALSE, FALSE));
  1567. JS_SetModuleExport(ctx, m, "err", js_new_std_file(ctx, stderr, FALSE, FALSE));
  1568. return 0;
  1569. }
  1570. JSModuleDef *js_init_module_std(JSContext *ctx, const char *module_name)
  1571. {
  1572. JSModuleDef *m;
  1573. m = JS_NewCModule(ctx, module_name, js_std_init);
  1574. if (!m)
  1575. return NULL;
  1576. JS_AddModuleExportList(ctx, m, js_std_funcs, countof(js_std_funcs));
  1577. JS_AddModuleExport(ctx, m, "in");
  1578. JS_AddModuleExport(ctx, m, "out");
  1579. JS_AddModuleExport(ctx, m, "err");
  1580. return m;
  1581. }
  1582. /**********************************************************/
  1583. /* 'os' object */
  1584. static JSValue js_os_open(JSContext *ctx, JSValueConst this_val,
  1585. int argc, JSValueConst *argv)
  1586. {
  1587. const char *filename;
  1588. int flags, mode, ret;
  1589. filename = JS_ToCString(ctx, argv[0]);
  1590. if (!filename)
  1591. return JS_EXCEPTION;
  1592. if (JS_ToInt32(ctx, &flags, argv[1]))
  1593. goto fail;
  1594. if (argc >= 3 && !JS_IsUndefined(argv[2])) {
  1595. if (JS_ToInt32(ctx, &mode, argv[2])) {
  1596. fail:
  1597. JS_FreeCString(ctx, filename);
  1598. return JS_EXCEPTION;
  1599. }
  1600. } else {
  1601. mode = 0666;
  1602. }
  1603. #if defined(_WIN32)
  1604. /* force binary mode by default */
  1605. if (!(flags & O_TEXT))
  1606. flags |= O_BINARY;
  1607. #endif
  1608. ret = js_get_errno(open(filename, flags, mode));
  1609. JS_FreeCString(ctx, filename);
  1610. return JS_NewInt32(ctx, ret);
  1611. }
  1612. static JSValue js_os_close(JSContext *ctx, JSValueConst this_val,
  1613. int argc, JSValueConst *argv)
  1614. {
  1615. int fd, ret;
  1616. if (JS_ToInt32(ctx, &fd, argv[0]))
  1617. return JS_EXCEPTION;
  1618. ret = js_get_errno(close(fd));
  1619. return JS_NewInt32(ctx, ret);
  1620. }
  1621. static JSValue js_os_seek(JSContext *ctx, JSValueConst this_val,
  1622. int argc, JSValueConst *argv)
  1623. {
  1624. int fd, whence;
  1625. int64_t pos, ret;
  1626. BOOL is_bigint;
  1627. if (JS_ToInt32(ctx, &fd, argv[0]))
  1628. return JS_EXCEPTION;
  1629. is_bigint = JS_IsBigInt(ctx, argv[1]);
  1630. if (JS_ToInt64Ext(ctx, &pos, argv[1]))
  1631. return JS_EXCEPTION;
  1632. if (JS_ToInt32(ctx, &whence, argv[2]))
  1633. return JS_EXCEPTION;
  1634. ret = lseek(fd, pos, whence);
  1635. if (ret == -1)
  1636. ret = -errno;
  1637. if (is_bigint)
  1638. return JS_NewBigInt64(ctx, ret);
  1639. else
  1640. return JS_NewInt64(ctx, ret);
  1641. }
  1642. static JSValue js_os_read_write(JSContext *ctx, JSValueConst this_val,
  1643. int argc, JSValueConst *argv, int magic)
  1644. {
  1645. int fd;
  1646. uint64_t pos, len;
  1647. size_t size;
  1648. ssize_t ret;
  1649. uint8_t *buf;
  1650. if (JS_ToInt32(ctx, &fd, argv[0]))
  1651. return JS_EXCEPTION;
  1652. if (JS_ToIndex(ctx, &pos, argv[2]))
  1653. return JS_EXCEPTION;
  1654. if (JS_ToIndex(ctx, &len, argv[3]))
  1655. return JS_EXCEPTION;
  1656. buf = JS_GetArrayBuffer(ctx, &size, argv[1]);
  1657. if (!buf)
  1658. return JS_EXCEPTION;
  1659. if (pos + len > size)
  1660. return JS_ThrowRangeError(ctx, "read/write array buffer overflow");
  1661. if (magic)
  1662. ret = js_get_errno(write(fd, buf + pos, len));
  1663. else
  1664. ret = js_get_errno(read(fd, buf + pos, len));
  1665. return JS_NewInt64(ctx, ret);
  1666. }
  1667. static JSValue js_os_isatty(JSContext *ctx, JSValueConst this_val,
  1668. int argc, JSValueConst *argv)
  1669. {
  1670. int fd;
  1671. if (JS_ToInt32(ctx, &fd, argv[0]))
  1672. return JS_EXCEPTION;
  1673. return JS_NewBool(ctx, isatty(fd));
  1674. }
  1675. #if defined(_WIN32)
  1676. static JSValue js_os_ttyGetWinSize(JSContext *ctx, JSValueConst this_val,
  1677. int argc, JSValueConst *argv)
  1678. {
  1679. int fd;
  1680. HANDLE handle;
  1681. CONSOLE_SCREEN_BUFFER_INFO info;
  1682. JSValue obj;
  1683. if (JS_ToInt32(ctx, &fd, argv[0]))
  1684. return JS_EXCEPTION;
  1685. handle = (HANDLE)_get_osfhandle(fd);
  1686. if (!GetConsoleScreenBufferInfo(handle, &info))
  1687. return JS_NULL;
  1688. obj = JS_NewArray(ctx);
  1689. if (JS_IsException(obj))
  1690. return obj;
  1691. JS_DefinePropertyValueUint32(ctx, obj, 0, JS_NewInt32(ctx, info.dwSize.X), JS_PROP_C_W_E);
  1692. JS_DefinePropertyValueUint32(ctx, obj, 1, JS_NewInt32(ctx, info.dwSize.Y), JS_PROP_C_W_E);
  1693. return obj;
  1694. }
  1695. /* Windows 10 built-in VT100 emulation */
  1696. #define __ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004
  1697. #define __ENABLE_VIRTUAL_TERMINAL_INPUT 0x0200
  1698. static JSValue js_os_ttySetRaw(JSContext *ctx, JSValueConst this_val,
  1699. int argc, JSValueConst *argv)
  1700. {
  1701. int fd;
  1702. HANDLE handle;
  1703. if (JS_ToInt32(ctx, &fd, argv[0]))
  1704. return JS_EXCEPTION;
  1705. handle = (HANDLE)_get_osfhandle(fd);
  1706. SetConsoleMode(handle, ENABLE_WINDOW_INPUT | __ENABLE_VIRTUAL_TERMINAL_INPUT);
  1707. _setmode(fd, _O_BINARY);
  1708. if (fd == 0) {
  1709. handle = (HANDLE)_get_osfhandle(1); /* corresponding output */
  1710. SetConsoleMode(handle, ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT | __ENABLE_VIRTUAL_TERMINAL_PROCESSING);
  1711. }
  1712. return JS_UNDEFINED;
  1713. }
  1714. #else
  1715. static JSValue js_os_ttyGetWinSize(JSContext *ctx, JSValueConst this_val,
  1716. int argc, JSValueConst *argv)
  1717. {
  1718. int fd;
  1719. struct winsize ws;
  1720. JSValue obj;
  1721. if (JS_ToInt32(ctx, &fd, argv[0]))
  1722. return JS_EXCEPTION;
  1723. if (ioctl(fd, TIOCGWINSZ, &ws) == 0 &&
  1724. ws.ws_col >= 4 && ws.ws_row >= 4) {
  1725. obj = JS_NewArray(ctx);
  1726. if (JS_IsException(obj))
  1727. return obj;
  1728. JS_DefinePropertyValueUint32(ctx, obj, 0, JS_NewInt32(ctx, ws.ws_col), JS_PROP_C_W_E);
  1729. JS_DefinePropertyValueUint32(ctx, obj, 1, JS_NewInt32(ctx, ws.ws_row), JS_PROP_C_W_E);
  1730. return obj;
  1731. } else {
  1732. return JS_NULL;
  1733. }
  1734. }
  1735. static struct termios oldtty;
  1736. static void term_exit(void)
  1737. {
  1738. tcsetattr(0, TCSANOW, &oldtty);
  1739. }
  1740. /* XXX: should add a way to go back to normal mode */
  1741. static JSValue js_os_ttySetRaw(JSContext *ctx, JSValueConst this_val,
  1742. int argc, JSValueConst *argv)
  1743. {
  1744. struct termios tty;
  1745. int fd;
  1746. if (JS_ToInt32(ctx, &fd, argv[0]))
  1747. return JS_EXCEPTION;
  1748. memset(&tty, 0, sizeof(tty));
  1749. tcgetattr(fd, &tty);
  1750. oldtty = tty;
  1751. tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP
  1752. |INLCR|IGNCR|ICRNL|IXON);
  1753. tty.c_oflag |= OPOST;
  1754. tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN);
  1755. tty.c_cflag &= ~(CSIZE|PARENB);
  1756. tty.c_cflag |= CS8;
  1757. tty.c_cc[VMIN] = 1;
  1758. tty.c_cc[VTIME] = 0;
  1759. tcsetattr(fd, TCSANOW, &tty);
  1760. atexit(term_exit);
  1761. return JS_UNDEFINED;
  1762. }
  1763. #endif /* !_WIN32 */
  1764. static JSValue js_os_remove(JSContext *ctx, JSValueConst this_val,
  1765. int argc, JSValueConst *argv)
  1766. {
  1767. const char *filename;
  1768. int ret;
  1769. filename = JS_ToCString(ctx, argv[0]);
  1770. if (!filename)
  1771. return JS_EXCEPTION;
  1772. #if defined(_WIN32)
  1773. {
  1774. struct stat st;
  1775. if (stat(filename, &st) == 0 && S_ISDIR(st.st_mode)) {
  1776. ret = rmdir(filename);
  1777. } else {
  1778. ret = unlink(filename);
  1779. }
  1780. }
  1781. #else
  1782. ret = remove(filename);
  1783. #endif
  1784. ret = js_get_errno(ret);
  1785. JS_FreeCString(ctx, filename);
  1786. return JS_NewInt32(ctx, ret);
  1787. }
  1788. static JSValue js_os_rename(JSContext *ctx, JSValueConst this_val,
  1789. int argc, JSValueConst *argv)
  1790. {
  1791. const char *oldpath, *newpath;
  1792. int ret;
  1793. oldpath = JS_ToCString(ctx, argv[0]);
  1794. if (!oldpath)
  1795. return JS_EXCEPTION;
  1796. newpath = JS_ToCString(ctx, argv[1]);
  1797. if (!newpath) {
  1798. JS_FreeCString(ctx, oldpath);
  1799. return JS_EXCEPTION;
  1800. }
  1801. ret = js_get_errno(rename(oldpath, newpath));
  1802. JS_FreeCString(ctx, oldpath);
  1803. JS_FreeCString(ctx, newpath);
  1804. return JS_NewInt32(ctx, ret);
  1805. }
  1806. static BOOL is_main_thread(JSRuntime *rt)
  1807. {
  1808. JSThreadState *ts = JS_GetRuntimeOpaque(rt);
  1809. return !ts->recv_pipe;
  1810. }
  1811. static JSOSRWHandler *find_rh(JSThreadState *ts, int fd)
  1812. {
  1813. JSOSRWHandler *rh;
  1814. struct list_head *el;
  1815. list_for_each(el, &ts->os_rw_handlers) {
  1816. rh = list_entry(el, JSOSRWHandler, link);
  1817. if (rh->fd == fd)
  1818. return rh;
  1819. }
  1820. return NULL;
  1821. }
  1822. static void free_rw_handler(JSRuntime *rt, JSOSRWHandler *rh)
  1823. {
  1824. int i;
  1825. list_del(&rh->link);
  1826. for(i = 0; i < 2; i++) {
  1827. JS_FreeValueRT(rt, rh->rw_func[i]);
  1828. }
  1829. js_free_rt(rt, rh);
  1830. }
  1831. static JSValue js_os_setReadHandler(JSContext *ctx, JSValueConst this_val,
  1832. int argc, JSValueConst *argv, int magic)
  1833. {
  1834. JSRuntime *rt = JS_GetRuntime(ctx);
  1835. JSThreadState *ts = JS_GetRuntimeOpaque(rt);
  1836. JSOSRWHandler *rh;
  1837. int fd;
  1838. JSValueConst func;
  1839. if (JS_ToInt32(ctx, &fd, argv[0]))
  1840. return JS_EXCEPTION;
  1841. func = argv[1];
  1842. if (JS_IsNull(func)) {
  1843. rh = find_rh(ts, fd);
  1844. if (rh) {
  1845. JS_FreeValue(ctx, rh->rw_func[magic]);
  1846. rh->rw_func[magic] = JS_NULL;
  1847. if (JS_IsNull(rh->rw_func[0]) &&
  1848. JS_IsNull(rh->rw_func[1])) {
  1849. /* remove the entry */
  1850. free_rw_handler(JS_GetRuntime(ctx), rh);
  1851. }
  1852. }
  1853. } else {
  1854. if (!JS_IsFunction(ctx, func))
  1855. return JS_ThrowTypeError(ctx, "not a function");
  1856. rh = find_rh(ts, fd);
  1857. if (!rh) {
  1858. rh = js_mallocz(ctx, sizeof(*rh));
  1859. if (!rh)
  1860. return JS_EXCEPTION;
  1861. rh->fd = fd;
  1862. rh->rw_func[0] = JS_NULL;
  1863. rh->rw_func[1] = JS_NULL;
  1864. list_add_tail(&rh->link, &ts->os_rw_handlers);
  1865. }
  1866. JS_FreeValue(ctx, rh->rw_func[magic]);
  1867. rh->rw_func[magic] = JS_DupValue(ctx, func);
  1868. }
  1869. return JS_UNDEFINED;
  1870. }
  1871. static JSOSSignalHandler *find_sh(JSThreadState *ts, int sig_num)
  1872. {
  1873. JSOSSignalHandler *sh;
  1874. struct list_head *el;
  1875. list_for_each(el, &ts->os_signal_handlers) {
  1876. sh = list_entry(el, JSOSSignalHandler, link);
  1877. if (sh->sig_num == sig_num)
  1878. return sh;
  1879. }
  1880. return NULL;
  1881. }
  1882. static void free_sh(JSRuntime *rt, JSOSSignalHandler *sh)
  1883. {
  1884. list_del(&sh->link);
  1885. JS_FreeValueRT(rt, sh->func);
  1886. js_free_rt(rt, sh);
  1887. }
  1888. static void os_signal_handler(int sig_num)
  1889. {
  1890. os_pending_signals |= ((uint64_t)1 << sig_num);
  1891. }
  1892. #if defined(_WIN32)
  1893. typedef void (*sighandler_t)(int sig_num);
  1894. #endif
  1895. static JSValue js_os_signal(JSContext *ctx, JSValueConst this_val,
  1896. int argc, JSValueConst *argv)
  1897. {
  1898. JSRuntime *rt = JS_GetRuntime(ctx);
  1899. JSThreadState *ts = JS_GetRuntimeOpaque(rt);
  1900. JSOSSignalHandler *sh;
  1901. uint32_t sig_num;
  1902. JSValueConst func;
  1903. sighandler_t handler;
  1904. if (!is_main_thread(rt))
  1905. return JS_ThrowTypeError(ctx, "signal handler can only be set in the main thread");
  1906. if (JS_ToUint32(ctx, &sig_num, argv[0]))
  1907. return JS_EXCEPTION;
  1908. if (sig_num >= 64)
  1909. return JS_ThrowRangeError(ctx, "invalid signal number");
  1910. func = argv[1];
  1911. /* func = null: SIG_DFL, func = undefined, SIG_IGN */
  1912. if (JS_IsNull(func) || JS_IsUndefined(func)) {
  1913. sh = find_sh(ts, sig_num);
  1914. if (sh) {
  1915. free_sh(JS_GetRuntime(ctx), sh);
  1916. }
  1917. if (JS_IsNull(func))
  1918. handler = SIG_DFL;
  1919. else
  1920. handler = SIG_IGN;
  1921. signal(sig_num, handler);
  1922. } else {
  1923. if (!JS_IsFunction(ctx, func))
  1924. return JS_ThrowTypeError(ctx, "not a function");
  1925. sh = find_sh(ts, sig_num);
  1926. if (!sh) {
  1927. sh = js_mallocz(ctx, sizeof(*sh));
  1928. if (!sh)
  1929. return JS_EXCEPTION;
  1930. sh->sig_num = sig_num;
  1931. list_add_tail(&sh->link, &ts->os_signal_handlers);
  1932. }
  1933. JS_FreeValue(ctx, sh->func);
  1934. sh->func = JS_DupValue(ctx, func);
  1935. signal(sig_num, os_signal_handler);
  1936. }
  1937. return JS_UNDEFINED;
  1938. }
  1939. #if defined(__linux__) || defined(__APPLE__)
  1940. static int64_t get_time_ms(void)
  1941. {
  1942. struct timespec ts;
  1943. clock_gettime(CLOCK_MONOTONIC, &ts);
  1944. return (uint64_t)ts.tv_sec * 1000 + (ts.tv_nsec / 1000000);
  1945. }
  1946. static int64_t get_time_ns(void)
  1947. {
  1948. struct timespec ts;
  1949. clock_gettime(CLOCK_MONOTONIC, &ts);
  1950. return (uint64_t)ts.tv_sec * 1000000000 + ts.tv_nsec;
  1951. }
  1952. #else
  1953. /* more portable, but does not work if the date is updated */
  1954. static int64_t get_time_ms(void)
  1955. {
  1956. struct timeval tv;
  1957. gettimeofday(&tv, NULL);
  1958. return (int64_t)tv.tv_sec * 1000 + (tv.tv_usec / 1000);
  1959. }
  1960. static int64_t get_time_ns(void)
  1961. {
  1962. struct timeval tv;
  1963. gettimeofday(&tv, NULL);
  1964. return (int64_t)tv.tv_sec * 1000000000 + (tv.tv_usec * 1000);
  1965. }
  1966. #endif
  1967. static JSValue js_os_now(JSContext *ctx, JSValue this_val,
  1968. int argc, JSValue *argv)
  1969. {
  1970. return JS_NewFloat64(ctx, (double)get_time_ns() / 1e6);
  1971. }
  1972. static void free_timer(JSRuntime *rt, JSOSTimer *th)
  1973. {
  1974. list_del(&th->link);
  1975. JS_FreeValueRT(rt, th->func);
  1976. js_free_rt(rt, th);
  1977. }
  1978. static JSValue js_os_setTimeout(JSContext *ctx, JSValueConst this_val,
  1979. int argc, JSValueConst *argv)
  1980. {
  1981. JSRuntime *rt = JS_GetRuntime(ctx);
  1982. JSThreadState *ts = JS_GetRuntimeOpaque(rt);
  1983. int64_t delay;
  1984. JSValueConst func;
  1985. JSOSTimer *th;
  1986. func = argv[0];
  1987. if (!JS_IsFunction(ctx, func))
  1988. return JS_ThrowTypeError(ctx, "not a function");
  1989. if (JS_ToInt64(ctx, &delay, argv[1]))
  1990. return JS_EXCEPTION;
  1991. th = js_mallocz(ctx, sizeof(*th));
  1992. if (!th)
  1993. return JS_EXCEPTION;
  1994. th->timer_id = ts->next_timer_id;
  1995. if (ts->next_timer_id == INT32_MAX)
  1996. ts->next_timer_id = 1;
  1997. else
  1998. ts->next_timer_id++;
  1999. th->timeout = get_time_ms() + delay;
  2000. th->func = JS_DupValue(ctx, func);
  2001. list_add_tail(&th->link, &ts->os_timers);
  2002. return JS_NewInt32(ctx, th->timer_id);
  2003. }
  2004. static JSOSTimer *find_timer_by_id(JSThreadState *ts, int timer_id)
  2005. {
  2006. struct list_head *el;
  2007. if (timer_id <= 0)
  2008. return NULL;
  2009. list_for_each(el, &ts->os_timers) {
  2010. JSOSTimer *th = list_entry(el, JSOSTimer, link);
  2011. if (th->timer_id == timer_id)
  2012. return th;
  2013. }
  2014. return NULL;
  2015. }
  2016. static JSValue js_os_clearTimeout(JSContext *ctx, JSValueConst this_val,
  2017. int argc, JSValueConst *argv)
  2018. {
  2019. JSRuntime *rt = JS_GetRuntime(ctx);
  2020. JSThreadState *ts = JS_GetRuntimeOpaque(rt);
  2021. JSOSTimer *th;
  2022. int timer_id;
  2023. if (JS_ToInt32(ctx, &timer_id, argv[0]))
  2024. return JS_EXCEPTION;
  2025. th = find_timer_by_id(ts, timer_id);
  2026. if (!th)
  2027. return JS_UNDEFINED;
  2028. free_timer(rt, th);
  2029. return JS_UNDEFINED;
  2030. }
  2031. /* return a promise */
  2032. static JSValue js_os_sleepAsync(JSContext *ctx, JSValueConst this_val,
  2033. int argc, JSValueConst *argv)
  2034. {
  2035. JSRuntime *rt = JS_GetRuntime(ctx);
  2036. JSThreadState *ts = JS_GetRuntimeOpaque(rt);
  2037. int64_t delay;
  2038. JSOSTimer *th;
  2039. JSValue promise, resolving_funcs[2];
  2040. if (JS_ToInt64(ctx, &delay, argv[0]))
  2041. return JS_EXCEPTION;
  2042. promise = JS_NewPromiseCapability(ctx, resolving_funcs);
  2043. if (JS_IsException(promise))
  2044. return JS_EXCEPTION;
  2045. th = js_mallocz(ctx, sizeof(*th));
  2046. if (!th) {
  2047. JS_FreeValue(ctx, promise);
  2048. JS_FreeValue(ctx, resolving_funcs[0]);
  2049. JS_FreeValue(ctx, resolving_funcs[1]);
  2050. return JS_EXCEPTION;
  2051. }
  2052. th->timer_id = -1;
  2053. th->timeout = get_time_ms() + delay;
  2054. th->func = JS_DupValue(ctx, resolving_funcs[0]);
  2055. list_add_tail(&th->link, &ts->os_timers);
  2056. JS_FreeValue(ctx, resolving_funcs[0]);
  2057. JS_FreeValue(ctx, resolving_funcs[1]);
  2058. return promise;
  2059. }
  2060. static void call_handler(JSContext *ctx, JSValueConst func)
  2061. {
  2062. JSValue ret, func1;
  2063. /* 'func' might be destroyed when calling itself (if it frees the
  2064. handler), so must take extra care */
  2065. func1 = JS_DupValue(ctx, func);
  2066. ret = JS_Call(ctx, func1, JS_UNDEFINED, 0, NULL);
  2067. JS_FreeValue(ctx, func1);
  2068. if (JS_IsException(ret))
  2069. js_std_dump_error(ctx);
  2070. JS_FreeValue(ctx, ret);
  2071. }
  2072. #ifdef USE_WORKER
  2073. #ifdef _WIN32
  2074. static int js_waker_init(JSWaker *w)
  2075. {
  2076. w->handle = CreateEvent(NULL, TRUE, FALSE, NULL);
  2077. return w->handle ? 0 : -1;
  2078. }
  2079. static void js_waker_signal(JSWaker *w)
  2080. {
  2081. SetEvent(w->handle);
  2082. }
  2083. static void js_waker_clear(JSWaker *w)
  2084. {
  2085. ResetEvent(w->handle);
  2086. }
  2087. static void js_waker_close(JSWaker *w)
  2088. {
  2089. CloseHandle(w->handle);
  2090. w->handle = INVALID_HANDLE_VALUE;
  2091. }
  2092. #else // !_WIN32
  2093. static int js_waker_init(JSWaker *w)
  2094. {
  2095. int fds[2];
  2096. if (pipe(fds) < 0)
  2097. return -1;
  2098. w->read_fd = fds[0];
  2099. w->write_fd = fds[1];
  2100. return 0;
  2101. }
  2102. static void js_waker_signal(JSWaker *w)
  2103. {
  2104. int ret;
  2105. for(;;) {
  2106. ret = write(w->write_fd, "", 1);
  2107. if (ret == 1)
  2108. break;
  2109. if (ret < 0 && (errno != EAGAIN || errno != EINTR))
  2110. break;
  2111. }
  2112. }
  2113. static void js_waker_clear(JSWaker *w)
  2114. {
  2115. uint8_t buf[16];
  2116. int ret;
  2117. for(;;) {
  2118. ret = read(w->read_fd, buf, sizeof(buf));
  2119. if (ret >= 0)
  2120. break;
  2121. if (errno != EAGAIN && errno != EINTR)
  2122. break;
  2123. }
  2124. }
  2125. static void js_waker_close(JSWaker *w)
  2126. {
  2127. close(w->read_fd);
  2128. close(w->write_fd);
  2129. w->read_fd = -1;
  2130. w->write_fd = -1;
  2131. }
  2132. #endif // _WIN32
  2133. static void js_free_message(JSWorkerMessage *msg);
  2134. /* return 1 if a message was handled, 0 if no message */
  2135. static int handle_posted_message(JSRuntime *rt, JSContext *ctx,
  2136. JSWorkerMessageHandler *port)
  2137. {
  2138. JSWorkerMessagePipe *ps = port->recv_pipe;
  2139. int ret;
  2140. struct list_head *el;
  2141. JSWorkerMessage *msg;
  2142. JSValue obj, data_obj, func, retval;
  2143. pthread_mutex_lock(&ps->mutex);
  2144. if (!list_empty(&ps->msg_queue)) {
  2145. el = ps->msg_queue.next;
  2146. msg = list_entry(el, JSWorkerMessage, link);
  2147. /* remove the message from the queue */
  2148. list_del(&msg->link);
  2149. if (list_empty(&ps->msg_queue))
  2150. js_waker_clear(&ps->waker);
  2151. pthread_mutex_unlock(&ps->mutex);
  2152. data_obj = JS_ReadObject(ctx, msg->data, msg->data_len,
  2153. JS_READ_OBJ_SAB | JS_READ_OBJ_REFERENCE);
  2154. js_free_message(msg);
  2155. if (JS_IsException(data_obj))
  2156. goto fail;
  2157. obj = JS_NewObject(ctx);
  2158. if (JS_IsException(obj)) {
  2159. JS_FreeValue(ctx, data_obj);
  2160. goto fail;
  2161. }
  2162. JS_DefinePropertyValueStr(ctx, obj, "data", data_obj, JS_PROP_C_W_E);
  2163. /* 'func' might be destroyed when calling itself (if it frees the
  2164. handler), so must take extra care */
  2165. func = JS_DupValue(ctx, port->on_message_func);
  2166. retval = JS_Call(ctx, func, JS_UNDEFINED, 1, (JSValueConst *)&obj);
  2167. JS_FreeValue(ctx, obj);
  2168. JS_FreeValue(ctx, func);
  2169. if (JS_IsException(retval)) {
  2170. fail:
  2171. js_std_dump_error(ctx);
  2172. } else {
  2173. JS_FreeValue(ctx, retval);
  2174. }
  2175. ret = 1;
  2176. } else {
  2177. pthread_mutex_unlock(&ps->mutex);
  2178. ret = 0;
  2179. }
  2180. return ret;
  2181. }
  2182. #else
  2183. static int handle_posted_message(JSRuntime *rt, JSContext *ctx,
  2184. JSWorkerMessageHandler *port)
  2185. {
  2186. return 0;
  2187. }
  2188. #endif /* !USE_WORKER */
  2189. #if defined(_WIN32)
  2190. static int js_os_poll(JSContext *ctx)
  2191. {
  2192. JSRuntime *rt = JS_GetRuntime(ctx);
  2193. JSThreadState *ts = JS_GetRuntimeOpaque(rt);
  2194. int min_delay, count;
  2195. int64_t cur_time, delay;
  2196. JSOSRWHandler *rh;
  2197. struct list_head *el;
  2198. HANDLE handles[MAXIMUM_WAIT_OBJECTS]; // 64
  2199. /* XXX: handle signals if useful */
  2200. if (list_empty(&ts->os_rw_handlers) && list_empty(&ts->os_timers) &&
  2201. list_empty(&ts->port_list)) {
  2202. return -1; /* no more events */
  2203. }
  2204. if (!list_empty(&ts->os_timers)) {
  2205. cur_time = get_time_ms();
  2206. min_delay = 10000;
  2207. list_for_each(el, &ts->os_timers) {
  2208. JSOSTimer *th = list_entry(el, JSOSTimer, link);
  2209. delay = th->timeout - cur_time;
  2210. if (delay <= 0) {
  2211. JSValue func;
  2212. /* the timer expired */
  2213. func = th->func;
  2214. th->func = JS_UNDEFINED;
  2215. free_timer(rt, th);
  2216. call_handler(ctx, func);
  2217. JS_FreeValue(ctx, func);
  2218. return 0;
  2219. } else if (delay < min_delay) {
  2220. min_delay = delay;
  2221. }
  2222. }
  2223. } else {
  2224. min_delay = -1;
  2225. }
  2226. count = 0;
  2227. list_for_each(el, &ts->os_rw_handlers) {
  2228. rh = list_entry(el, JSOSRWHandler, link);
  2229. if (rh->fd == 0 && !JS_IsNull(rh->rw_func[0])) {
  2230. handles[count++] = (HANDLE)_get_osfhandle(rh->fd); // stdin
  2231. if (count == (int)countof(handles))
  2232. break;
  2233. }
  2234. }
  2235. list_for_each(el, &ts->port_list) {
  2236. JSWorkerMessageHandler *port = list_entry(el, JSWorkerMessageHandler, link);
  2237. if (JS_IsNull(port->on_message_func))
  2238. continue;
  2239. handles[count++] = port->recv_pipe->waker.handle;
  2240. if (count == (int)countof(handles))
  2241. break;
  2242. }
  2243. if (count > 0) {
  2244. DWORD ret, timeout = INFINITE;
  2245. if (min_delay != -1)
  2246. timeout = min_delay;
  2247. ret = WaitForMultipleObjects(count, handles, FALSE, timeout);
  2248. if (ret < count) {
  2249. list_for_each(el, &ts->os_rw_handlers) {
  2250. rh = list_entry(el, JSOSRWHandler, link);
  2251. if (rh->fd == 0 && !JS_IsNull(rh->rw_func[0])) {
  2252. call_handler(ctx, rh->rw_func[0]);
  2253. /* must stop because the list may have been modified */
  2254. goto done;
  2255. }
  2256. }
  2257. list_for_each(el, &ts->port_list) {
  2258. JSWorkerMessageHandler *port = list_entry(el, JSWorkerMessageHandler, link);
  2259. if (!JS_IsNull(port->on_message_func)) {
  2260. JSWorkerMessagePipe *ps = port->recv_pipe;
  2261. if (ps->waker.handle == handles[ret]) {
  2262. if (handle_posted_message(rt, ctx, port))
  2263. goto done;
  2264. }
  2265. }
  2266. }
  2267. }
  2268. } else {
  2269. Sleep(min_delay);
  2270. }
  2271. done:
  2272. return 0;
  2273. }
  2274. #else
  2275. static no_inline int js_poll_expand(JSThreadState *ts)
  2276. {
  2277. struct pollfd *new_fds;
  2278. int new_size = max_int(ts->poll_fds_size +
  2279. ts->poll_fds_size / 2, 16);
  2280. new_fds = realloc(ts->poll_fds, new_size * sizeof(struct pollfd));
  2281. if (!new_fds)
  2282. return -1;
  2283. ts->poll_fds = new_fds;
  2284. ts->poll_fds_size = new_size;
  2285. return 0;
  2286. }
  2287. static int js_poll_add_poll_fd(JSThreadState *ts, int *pnfds, int fd, int events)
  2288. {
  2289. struct pollfd *fds;
  2290. int nfds;
  2291. nfds = *pnfds;
  2292. if (unlikely(nfds >= ts->poll_fds_size)) {
  2293. if (js_poll_expand(ts))
  2294. return -1;
  2295. }
  2296. fds = &ts->poll_fds[nfds++];
  2297. fds->fd = fd;
  2298. fds->events = events;
  2299. fds->revents = 0;
  2300. *pnfds = nfds;
  2301. return 0;
  2302. }
  2303. static int js_os_poll(JSContext *ctx)
  2304. {
  2305. JSRuntime *rt = JS_GetRuntime(ctx);
  2306. JSThreadState *ts = JS_GetRuntimeOpaque(rt);
  2307. int min_delay, nfds;
  2308. int64_t cur_time, delay;
  2309. JSOSRWHandler *rh;
  2310. struct list_head *el;
  2311. /* only check signals in the main thread */
  2312. if (!ts->recv_pipe &&
  2313. unlikely(os_pending_signals != 0)) {
  2314. JSOSSignalHandler *sh;
  2315. uint64_t mask;
  2316. list_for_each(el, &ts->os_signal_handlers) {
  2317. sh = list_entry(el, JSOSSignalHandler, link);
  2318. mask = (uint64_t)1 << sh->sig_num;
  2319. if (os_pending_signals & mask) {
  2320. os_pending_signals &= ~mask;
  2321. call_handler(ctx, sh->func);
  2322. return 0;
  2323. }
  2324. }
  2325. }
  2326. if (list_empty(&ts->os_rw_handlers) && list_empty(&ts->os_timers) &&
  2327. list_empty(&ts->port_list))
  2328. return -1; /* no more events */
  2329. if (!list_empty(&ts->os_timers)) {
  2330. cur_time = get_time_ms();
  2331. min_delay = 10000;
  2332. list_for_each(el, &ts->os_timers) {
  2333. JSOSTimer *th = list_entry(el, JSOSTimer, link);
  2334. delay = th->timeout - cur_time;
  2335. if (delay <= 0) {
  2336. JSValue func;
  2337. /* the timer expired */
  2338. func = th->func;
  2339. th->func = JS_UNDEFINED;
  2340. free_timer(rt, th);
  2341. call_handler(ctx, func);
  2342. JS_FreeValue(ctx, func);
  2343. return 0;
  2344. } else if (delay < min_delay) {
  2345. min_delay = delay;
  2346. }
  2347. }
  2348. } else {
  2349. min_delay = -1; /* infinite */
  2350. }
  2351. nfds = 0;
  2352. list_for_each(el, &ts->os_rw_handlers) {
  2353. int events;
  2354. rh = list_entry(el, JSOSRWHandler, link);
  2355. events = 0;
  2356. if (!JS_IsNull(rh->rw_func[0]))
  2357. events |= POLLIN;
  2358. if (!JS_IsNull(rh->rw_func[1]))
  2359. events |= POLLOUT;
  2360. if (events) {
  2361. rh->poll_fd_index = nfds;
  2362. if (js_poll_add_poll_fd(ts, &nfds, rh->fd, events))
  2363. return -1;
  2364. }
  2365. }
  2366. list_for_each(el, &ts->port_list) {
  2367. JSWorkerMessageHandler *port = list_entry(el, JSWorkerMessageHandler, link);
  2368. if (!JS_IsNull(port->on_message_func)) {
  2369. JSWorkerMessagePipe *ps = port->recv_pipe;
  2370. port->poll_fd_index = nfds;
  2371. if (js_poll_add_poll_fd(ts, &nfds, ps->waker.read_fd, POLLIN))
  2372. return -1;
  2373. }
  2374. }
  2375. nfds = poll(ts->poll_fds, nfds, min_delay);
  2376. if (nfds > 0) {
  2377. list_for_each(el, &ts->os_rw_handlers) {
  2378. rh = list_entry(el, JSOSRWHandler, link);
  2379. if (!JS_IsNull(rh->rw_func[0]) &&
  2380. (ts->poll_fds[rh->poll_fd_index].revents & (POLLERR | POLLHUP | POLLNVAL | POLLIN))) {
  2381. call_handler(ctx, rh->rw_func[0]);
  2382. /* must stop because the list may have been modified */
  2383. goto done;
  2384. }
  2385. if (!JS_IsNull(rh->rw_func[1]) &&
  2386. (ts->poll_fds[rh->poll_fd_index].revents & (POLLERR | POLLHUP | POLLNVAL | POLLOUT))) {
  2387. call_handler(ctx, rh->rw_func[1]);
  2388. /* must stop because the list may have been modified */
  2389. goto done;
  2390. }
  2391. }
  2392. list_for_each(el, &ts->port_list) {
  2393. JSWorkerMessageHandler *port = list_entry(el, JSWorkerMessageHandler, link);
  2394. if (!JS_IsNull(port->on_message_func)) {
  2395. if (ts->poll_fds[port->poll_fd_index].revents != 0) {
  2396. if (handle_posted_message(rt, ctx, port))
  2397. goto done;
  2398. }
  2399. }
  2400. }
  2401. }
  2402. done:
  2403. return 0;
  2404. }
  2405. #endif /* !_WIN32 */
  2406. static JSValue make_obj_error(JSContext *ctx,
  2407. JSValue obj,
  2408. int err)
  2409. {
  2410. JSValue arr;
  2411. if (JS_IsException(obj))
  2412. return obj;
  2413. arr = JS_NewArray(ctx);
  2414. if (JS_IsException(arr))
  2415. return JS_EXCEPTION;
  2416. JS_DefinePropertyValueUint32(ctx, arr, 0, obj,
  2417. JS_PROP_C_W_E);
  2418. JS_DefinePropertyValueUint32(ctx, arr, 1, JS_NewInt32(ctx, err),
  2419. JS_PROP_C_W_E);
  2420. return arr;
  2421. }
  2422. static JSValue make_string_error(JSContext *ctx,
  2423. const char *buf,
  2424. int err)
  2425. {
  2426. return make_obj_error(ctx, JS_NewString(ctx, buf), err);
  2427. }
  2428. /* return [cwd, errorcode] */
  2429. static JSValue js_os_getcwd(JSContext *ctx, JSValueConst this_val,
  2430. int argc, JSValueConst *argv)
  2431. {
  2432. char buf[PATH_MAX];
  2433. int err;
  2434. if (!getcwd(buf, sizeof(buf))) {
  2435. buf[0] = '\0';
  2436. err = errno;
  2437. } else {
  2438. err = 0;
  2439. }
  2440. return make_string_error(ctx, buf, err);
  2441. }
  2442. static JSValue js_os_chdir(JSContext *ctx, JSValueConst this_val,
  2443. int argc, JSValueConst *argv)
  2444. {
  2445. const char *target;
  2446. int err;
  2447. target = JS_ToCString(ctx, argv[0]);
  2448. if (!target)
  2449. return JS_EXCEPTION;
  2450. err = js_get_errno(chdir(target));
  2451. JS_FreeCString(ctx, target);
  2452. return JS_NewInt32(ctx, err);
  2453. }
  2454. static JSValue js_os_mkdir(JSContext *ctx, JSValueConst this_val,
  2455. int argc, JSValueConst *argv)
  2456. {
  2457. int mode, ret;
  2458. const char *path;
  2459. if (argc >= 2) {
  2460. if (JS_ToInt32(ctx, &mode, argv[1]))
  2461. return JS_EXCEPTION;
  2462. } else {
  2463. mode = 0777;
  2464. }
  2465. path = JS_ToCString(ctx, argv[0]);
  2466. if (!path)
  2467. return JS_EXCEPTION;
  2468. #if defined(_WIN32)
  2469. (void)mode;
  2470. ret = js_get_errno(mkdir(path));
  2471. #else
  2472. ret = js_get_errno(mkdir(path, mode));
  2473. #endif
  2474. JS_FreeCString(ctx, path);
  2475. return JS_NewInt32(ctx, ret);
  2476. }
  2477. /* return [array, errorcode] */
  2478. static JSValue js_os_readdir(JSContext *ctx, JSValueConst this_val,
  2479. int argc, JSValueConst *argv)
  2480. {
  2481. const char *path;
  2482. DIR *f;
  2483. struct dirent *d;
  2484. JSValue obj;
  2485. int err;
  2486. uint32_t len;
  2487. path = JS_ToCString(ctx, argv[0]);
  2488. if (!path)
  2489. return JS_EXCEPTION;
  2490. obj = JS_NewArray(ctx);
  2491. if (JS_IsException(obj)) {
  2492. JS_FreeCString(ctx, path);
  2493. return JS_EXCEPTION;
  2494. }
  2495. f = opendir(path);
  2496. if (!f)
  2497. err = errno;
  2498. else
  2499. err = 0;
  2500. JS_FreeCString(ctx, path);
  2501. if (!f)
  2502. goto done;
  2503. len = 0;
  2504. for(;;) {
  2505. errno = 0;
  2506. d = readdir(f);
  2507. if (!d) {
  2508. err = errno;
  2509. break;
  2510. }
  2511. JS_DefinePropertyValueUint32(ctx, obj, len++,
  2512. JS_NewString(ctx, d->d_name),
  2513. JS_PROP_C_W_E);
  2514. }
  2515. closedir(f);
  2516. done:
  2517. return make_obj_error(ctx, obj, err);
  2518. }
  2519. #if !defined(_WIN32)
  2520. static int64_t timespec_to_ms(const struct timespec *tv)
  2521. {
  2522. return (int64_t)tv->tv_sec * 1000 + (tv->tv_nsec / 1000000);
  2523. }
  2524. #endif
  2525. /* return [obj, errcode] */
  2526. static JSValue js_os_stat(JSContext *ctx, JSValueConst this_val,
  2527. int argc, JSValueConst *argv, int is_lstat)
  2528. {
  2529. const char *path;
  2530. int err, res;
  2531. struct stat st;
  2532. JSValue obj;
  2533. path = JS_ToCString(ctx, argv[0]);
  2534. if (!path)
  2535. return JS_EXCEPTION;
  2536. #if defined(_WIN32)
  2537. res = stat(path, &st);
  2538. #else
  2539. if (is_lstat)
  2540. res = lstat(path, &st);
  2541. else
  2542. res = stat(path, &st);
  2543. #endif
  2544. if (res < 0)
  2545. err = errno;
  2546. else
  2547. err = 0;
  2548. JS_FreeCString(ctx, path);
  2549. if (res < 0) {
  2550. obj = JS_NULL;
  2551. } else {
  2552. obj = JS_NewObject(ctx);
  2553. if (JS_IsException(obj))
  2554. return JS_EXCEPTION;
  2555. JS_DefinePropertyValueStr(ctx, obj, "dev",
  2556. JS_NewInt64(ctx, st.st_dev),
  2557. JS_PROP_C_W_E);
  2558. JS_DefinePropertyValueStr(ctx, obj, "ino",
  2559. JS_NewInt64(ctx, st.st_ino),
  2560. JS_PROP_C_W_E);
  2561. JS_DefinePropertyValueStr(ctx, obj, "mode",
  2562. JS_NewInt32(ctx, st.st_mode),
  2563. JS_PROP_C_W_E);
  2564. JS_DefinePropertyValueStr(ctx, obj, "nlink",
  2565. JS_NewInt64(ctx, st.st_nlink),
  2566. JS_PROP_C_W_E);
  2567. JS_DefinePropertyValueStr(ctx, obj, "uid",
  2568. JS_NewInt64(ctx, st.st_uid),
  2569. JS_PROP_C_W_E);
  2570. JS_DefinePropertyValueStr(ctx, obj, "gid",
  2571. JS_NewInt64(ctx, st.st_gid),
  2572. JS_PROP_C_W_E);
  2573. JS_DefinePropertyValueStr(ctx, obj, "rdev",
  2574. JS_NewInt64(ctx, st.st_rdev),
  2575. JS_PROP_C_W_E);
  2576. JS_DefinePropertyValueStr(ctx, obj, "size",
  2577. JS_NewInt64(ctx, st.st_size),
  2578. JS_PROP_C_W_E);
  2579. #if !defined(_WIN32)
  2580. JS_DefinePropertyValueStr(ctx, obj, "blocks",
  2581. JS_NewInt64(ctx, st.st_blocks),
  2582. JS_PROP_C_W_E);
  2583. #endif
  2584. #if defined(_WIN32)
  2585. JS_DefinePropertyValueStr(ctx, obj, "atime",
  2586. JS_NewInt64(ctx, (int64_t)st.st_atime * 1000),
  2587. JS_PROP_C_W_E);
  2588. JS_DefinePropertyValueStr(ctx, obj, "mtime",
  2589. JS_NewInt64(ctx, (int64_t)st.st_mtime * 1000),
  2590. JS_PROP_C_W_E);
  2591. JS_DefinePropertyValueStr(ctx, obj, "ctime",
  2592. JS_NewInt64(ctx, (int64_t)st.st_ctime * 1000),
  2593. JS_PROP_C_W_E);
  2594. #elif defined(__APPLE__)
  2595. JS_DefinePropertyValueStr(ctx, obj, "atime",
  2596. JS_NewInt64(ctx, timespec_to_ms(&st.st_atimespec)),
  2597. JS_PROP_C_W_E);
  2598. JS_DefinePropertyValueStr(ctx, obj, "mtime",
  2599. JS_NewInt64(ctx, timespec_to_ms(&st.st_mtimespec)),
  2600. JS_PROP_C_W_E);
  2601. JS_DefinePropertyValueStr(ctx, obj, "ctime",
  2602. JS_NewInt64(ctx, timespec_to_ms(&st.st_ctimespec)),
  2603. JS_PROP_C_W_E);
  2604. #else
  2605. JS_DefinePropertyValueStr(ctx, obj, "atime",
  2606. JS_NewInt64(ctx, timespec_to_ms(&st.st_atim)),
  2607. JS_PROP_C_W_E);
  2608. JS_DefinePropertyValueStr(ctx, obj, "mtime",
  2609. JS_NewInt64(ctx, timespec_to_ms(&st.st_mtim)),
  2610. JS_PROP_C_W_E);
  2611. JS_DefinePropertyValueStr(ctx, obj, "ctime",
  2612. JS_NewInt64(ctx, timespec_to_ms(&st.st_ctim)),
  2613. JS_PROP_C_W_E);
  2614. #endif
  2615. }
  2616. return make_obj_error(ctx, obj, err);
  2617. }
  2618. #if !defined(_WIN32)
  2619. static void ms_to_timeval(struct timeval *tv, uint64_t v)
  2620. {
  2621. tv->tv_sec = v / 1000;
  2622. tv->tv_usec = (v % 1000) * 1000;
  2623. }
  2624. #endif
  2625. static JSValue js_os_utimes(JSContext *ctx, JSValueConst this_val,
  2626. int argc, JSValueConst *argv)
  2627. {
  2628. const char *path;
  2629. int64_t atime, mtime;
  2630. int ret;
  2631. if (JS_ToInt64(ctx, &atime, argv[1]))
  2632. return JS_EXCEPTION;
  2633. if (JS_ToInt64(ctx, &mtime, argv[2]))
  2634. return JS_EXCEPTION;
  2635. path = JS_ToCString(ctx, argv[0]);
  2636. if (!path)
  2637. return JS_EXCEPTION;
  2638. #if defined(_WIN32)
  2639. {
  2640. struct _utimbuf times;
  2641. times.actime = atime / 1000;
  2642. times.modtime = mtime / 1000;
  2643. ret = js_get_errno(_utime(path, &times));
  2644. }
  2645. #else
  2646. {
  2647. struct timeval times[2];
  2648. ms_to_timeval(&times[0], atime);
  2649. ms_to_timeval(&times[1], mtime);
  2650. ret = js_get_errno(utimes(path, times));
  2651. }
  2652. #endif
  2653. JS_FreeCString(ctx, path);
  2654. return JS_NewInt32(ctx, ret);
  2655. }
  2656. /* sleep(delay_ms) */
  2657. static JSValue js_os_sleep(JSContext *ctx, JSValueConst this_val,
  2658. int argc, JSValueConst *argv)
  2659. {
  2660. int64_t delay;
  2661. int ret;
  2662. if (JS_ToInt64(ctx, &delay, argv[0]))
  2663. return JS_EXCEPTION;
  2664. if (delay < 0)
  2665. delay = 0;
  2666. #if defined(_WIN32)
  2667. {
  2668. if (delay > INT32_MAX)
  2669. delay = INT32_MAX;
  2670. Sleep(delay);
  2671. ret = 0;
  2672. }
  2673. #else
  2674. {
  2675. struct timespec ts;
  2676. ts.tv_sec = delay / 1000;
  2677. ts.tv_nsec = (delay % 1000) * 1000000;
  2678. ret = js_get_errno(nanosleep(&ts, NULL));
  2679. }
  2680. #endif
  2681. return JS_NewInt32(ctx, ret);
  2682. }
  2683. #if defined(_WIN32)
  2684. static char *realpath(const char *path, char *buf)
  2685. {
  2686. if (!_fullpath(buf, path, PATH_MAX)) {
  2687. errno = ENOENT;
  2688. return NULL;
  2689. } else {
  2690. return buf;
  2691. }
  2692. }
  2693. #endif
  2694. /* return [path, errorcode] */
  2695. static JSValue js_os_realpath(JSContext *ctx, JSValueConst this_val,
  2696. int argc, JSValueConst *argv)
  2697. {
  2698. const char *path;
  2699. char buf[PATH_MAX], *res;
  2700. int err;
  2701. path = JS_ToCString(ctx, argv[0]);
  2702. if (!path)
  2703. return JS_EXCEPTION;
  2704. res = realpath(path, buf);
  2705. JS_FreeCString(ctx, path);
  2706. if (!res) {
  2707. buf[0] = '\0';
  2708. err = errno;
  2709. } else {
  2710. err = 0;
  2711. }
  2712. return make_string_error(ctx, buf, err);
  2713. }
  2714. #if !defined(_WIN32)
  2715. static JSValue js_os_symlink(JSContext *ctx, JSValueConst this_val,
  2716. int argc, JSValueConst *argv)
  2717. {
  2718. const char *target, *linkpath;
  2719. int err;
  2720. target = JS_ToCString(ctx, argv[0]);
  2721. if (!target)
  2722. return JS_EXCEPTION;
  2723. linkpath = JS_ToCString(ctx, argv[1]);
  2724. if (!linkpath) {
  2725. JS_FreeCString(ctx, target);
  2726. return JS_EXCEPTION;
  2727. }
  2728. err = js_get_errno(symlink(target, linkpath));
  2729. JS_FreeCString(ctx, target);
  2730. JS_FreeCString(ctx, linkpath);
  2731. return JS_NewInt32(ctx, err);
  2732. }
  2733. /* return [path, errorcode] */
  2734. static JSValue js_os_readlink(JSContext *ctx, JSValueConst this_val,
  2735. int argc, JSValueConst *argv)
  2736. {
  2737. const char *path;
  2738. char buf[PATH_MAX];
  2739. int err;
  2740. ssize_t res;
  2741. path = JS_ToCString(ctx, argv[0]);
  2742. if (!path)
  2743. return JS_EXCEPTION;
  2744. res = readlink(path, buf, sizeof(buf) - 1);
  2745. if (res < 0) {
  2746. buf[0] = '\0';
  2747. err = errno;
  2748. } else {
  2749. buf[res] = '\0';
  2750. err = 0;
  2751. }
  2752. JS_FreeCString(ctx, path);
  2753. return make_string_error(ctx, buf, err);
  2754. }
  2755. static char **build_envp(JSContext *ctx, JSValueConst obj)
  2756. {
  2757. uint32_t len, i;
  2758. JSPropertyEnum *tab;
  2759. char **envp, *pair;
  2760. const char *key, *str;
  2761. JSValue val;
  2762. size_t key_len, str_len;
  2763. if (JS_GetOwnPropertyNames(ctx, &tab, &len, obj,
  2764. JS_GPN_STRING_MASK | JS_GPN_ENUM_ONLY) < 0)
  2765. return NULL;
  2766. envp = js_mallocz(ctx, sizeof(envp[0]) * ((size_t)len + 1));
  2767. if (!envp)
  2768. goto fail;
  2769. for(i = 0; i < len; i++) {
  2770. val = JS_GetProperty(ctx, obj, tab[i].atom);
  2771. if (JS_IsException(val))
  2772. goto fail;
  2773. str = JS_ToCString(ctx, val);
  2774. JS_FreeValue(ctx, val);
  2775. if (!str)
  2776. goto fail;
  2777. key = JS_AtomToCString(ctx, tab[i].atom);
  2778. if (!key) {
  2779. JS_FreeCString(ctx, str);
  2780. goto fail;
  2781. }
  2782. key_len = strlen(key);
  2783. str_len = strlen(str);
  2784. pair = js_malloc(ctx, key_len + str_len + 2);
  2785. if (!pair) {
  2786. JS_FreeCString(ctx, key);
  2787. JS_FreeCString(ctx, str);
  2788. goto fail;
  2789. }
  2790. memcpy(pair, key, key_len);
  2791. pair[key_len] = '=';
  2792. memcpy(pair + key_len + 1, str, str_len);
  2793. pair[key_len + 1 + str_len] = '\0';
  2794. envp[i] = pair;
  2795. JS_FreeCString(ctx, key);
  2796. JS_FreeCString(ctx, str);
  2797. }
  2798. done:
  2799. JS_FreePropertyEnum(ctx, tab, len);
  2800. return envp;
  2801. fail:
  2802. if (envp) {
  2803. for(i = 0; i < len; i++)
  2804. js_free(ctx, envp[i]);
  2805. js_free(ctx, envp);
  2806. envp = NULL;
  2807. }
  2808. goto done;
  2809. }
  2810. /* execvpe is not available on non GNU systems */
  2811. static int my_execvpe(const char *filename, char **argv, char **envp)
  2812. {
  2813. char *path, *p, *p_next, *p1;
  2814. char buf[PATH_MAX];
  2815. size_t filename_len, path_len;
  2816. BOOL eacces_error;
  2817. filename_len = strlen(filename);
  2818. if (filename_len == 0) {
  2819. errno = ENOENT;
  2820. return -1;
  2821. }
  2822. if (strchr(filename, '/'))
  2823. return execve(filename, argv, envp);
  2824. path = getenv("PATH");
  2825. if (!path)
  2826. path = (char *)"/bin:/usr/bin";
  2827. eacces_error = FALSE;
  2828. p = path;
  2829. for(p = path; p != NULL; p = p_next) {
  2830. p1 = strchr(p, ':');
  2831. if (!p1) {
  2832. p_next = NULL;
  2833. path_len = strlen(p);
  2834. } else {
  2835. p_next = p1 + 1;
  2836. path_len = p1 - p;
  2837. }
  2838. /* path too long */
  2839. if ((path_len + 1 + filename_len + 1) > PATH_MAX)
  2840. continue;
  2841. memcpy(buf, p, path_len);
  2842. buf[path_len] = '/';
  2843. memcpy(buf + path_len + 1, filename, filename_len);
  2844. buf[path_len + 1 + filename_len] = '\0';
  2845. execve(buf, argv, envp);
  2846. switch(errno) {
  2847. case EACCES:
  2848. eacces_error = TRUE;
  2849. break;
  2850. case ENOENT:
  2851. case ENOTDIR:
  2852. break;
  2853. default:
  2854. return -1;
  2855. }
  2856. }
  2857. if (eacces_error)
  2858. errno = EACCES;
  2859. return -1;
  2860. }
  2861. /* exec(args[, options]) -> exitcode */
  2862. static JSValue js_os_exec(JSContext *ctx, JSValueConst this_val,
  2863. int argc, JSValueConst *argv)
  2864. {
  2865. JSValueConst options, args = argv[0];
  2866. JSValue val, ret_val;
  2867. const char **exec_argv, *file = NULL, *str, *cwd = NULL;
  2868. char **envp = environ;
  2869. uint32_t exec_argc, i;
  2870. int ret, pid, status;
  2871. BOOL block_flag = TRUE, use_path = TRUE;
  2872. static const char *std_name[3] = { "stdin", "stdout", "stderr" };
  2873. int std_fds[3];
  2874. uint32_t uid = -1, gid = -1;
  2875. val = JS_GetPropertyStr(ctx, args, "length");
  2876. if (JS_IsException(val))
  2877. return JS_EXCEPTION;
  2878. ret = JS_ToUint32(ctx, &exec_argc, val);
  2879. JS_FreeValue(ctx, val);
  2880. if (ret)
  2881. return JS_EXCEPTION;
  2882. /* arbitrary limit to avoid overflow */
  2883. if (exec_argc < 1 || exec_argc > 65535) {
  2884. return JS_ThrowTypeError(ctx, "invalid number of arguments");
  2885. }
  2886. exec_argv = js_mallocz(ctx, sizeof(exec_argv[0]) * (exec_argc + 1));
  2887. if (!exec_argv)
  2888. return JS_EXCEPTION;
  2889. for(i = 0; i < exec_argc; i++) {
  2890. val = JS_GetPropertyUint32(ctx, args, i);
  2891. if (JS_IsException(val))
  2892. goto exception;
  2893. str = JS_ToCString(ctx, val);
  2894. JS_FreeValue(ctx, val);
  2895. if (!str)
  2896. goto exception;
  2897. exec_argv[i] = str;
  2898. }
  2899. exec_argv[exec_argc] = NULL;
  2900. for(i = 0; i < 3; i++)
  2901. std_fds[i] = i;
  2902. /* get the options, if any */
  2903. if (argc >= 2) {
  2904. options = argv[1];
  2905. if (get_bool_option(ctx, &block_flag, options, "block"))
  2906. goto exception;
  2907. if (get_bool_option(ctx, &use_path, options, "usePath"))
  2908. goto exception;
  2909. val = JS_GetPropertyStr(ctx, options, "file");
  2910. if (JS_IsException(val))
  2911. goto exception;
  2912. if (!JS_IsUndefined(val)) {
  2913. file = JS_ToCString(ctx, val);
  2914. JS_FreeValue(ctx, val);
  2915. if (!file)
  2916. goto exception;
  2917. }
  2918. val = JS_GetPropertyStr(ctx, options, "cwd");
  2919. if (JS_IsException(val))
  2920. goto exception;
  2921. if (!JS_IsUndefined(val)) {
  2922. cwd = JS_ToCString(ctx, val);
  2923. JS_FreeValue(ctx, val);
  2924. if (!cwd)
  2925. goto exception;
  2926. }
  2927. /* stdin/stdout/stderr handles */
  2928. for(i = 0; i < 3; i++) {
  2929. val = JS_GetPropertyStr(ctx, options, std_name[i]);
  2930. if (JS_IsException(val))
  2931. goto exception;
  2932. if (!JS_IsUndefined(val)) {
  2933. int fd;
  2934. ret = JS_ToInt32(ctx, &fd, val);
  2935. JS_FreeValue(ctx, val);
  2936. if (ret)
  2937. goto exception;
  2938. std_fds[i] = fd;
  2939. }
  2940. }
  2941. val = JS_GetPropertyStr(ctx, options, "env");
  2942. if (JS_IsException(val))
  2943. goto exception;
  2944. if (!JS_IsUndefined(val)) {
  2945. envp = build_envp(ctx, val);
  2946. JS_FreeValue(ctx, val);
  2947. if (!envp)
  2948. goto exception;
  2949. }
  2950. val = JS_GetPropertyStr(ctx, options, "uid");
  2951. if (JS_IsException(val))
  2952. goto exception;
  2953. if (!JS_IsUndefined(val)) {
  2954. ret = JS_ToUint32(ctx, &uid, val);
  2955. JS_FreeValue(ctx, val);
  2956. if (ret)
  2957. goto exception;
  2958. }
  2959. val = JS_GetPropertyStr(ctx, options, "gid");
  2960. if (JS_IsException(val))
  2961. goto exception;
  2962. if (!JS_IsUndefined(val)) {
  2963. ret = JS_ToUint32(ctx, &gid, val);
  2964. JS_FreeValue(ctx, val);
  2965. if (ret)
  2966. goto exception;
  2967. }
  2968. }
  2969. pid = fork();
  2970. if (pid < 0) {
  2971. JS_ThrowTypeError(ctx, "fork error");
  2972. goto exception;
  2973. }
  2974. if (pid == 0) {
  2975. /* child */
  2976. /* remap the stdin/stdout/stderr handles if necessary */
  2977. for(i = 0; i < 3; i++) {
  2978. if (std_fds[i] != i) {
  2979. if (dup2(std_fds[i], i) < 0)
  2980. _exit(127);
  2981. }
  2982. }
  2983. #if defined(HAVE_CLOSEFROM)
  2984. /* closefrom() is available on many recent unix systems:
  2985. Linux with glibc 2.34+, Solaris 9+, FreeBSD 7.3+,
  2986. NetBSD 3.0+, OpenBSD 3.5+.
  2987. Linux with the musl libc and macOS don't have it.
  2988. */
  2989. closefrom(3);
  2990. #else
  2991. {
  2992. /* Close the file handles manually, limit to 1024 to avoid
  2993. costly loop on linux Alpine where sysconf(_SC_OPEN_MAX)
  2994. returns a huge value 1048576.
  2995. Patch inspired by nicolas-duteil-nova. See also:
  2996. https://stackoverflow.com/questions/73229353/
  2997. https://stackoverflow.com/questions/899038/#918469
  2998. */
  2999. int fd_max = min_int(sysconf(_SC_OPEN_MAX), 1024);
  3000. for(i = 3; i < fd_max; i++)
  3001. close(i);
  3002. }
  3003. #endif
  3004. if (cwd) {
  3005. if (chdir(cwd) < 0)
  3006. _exit(127);
  3007. }
  3008. if (gid != -1) {
  3009. if (setgid(gid) < 0)
  3010. _exit(127);
  3011. }
  3012. if (uid != -1) {
  3013. if (setuid(uid) < 0)
  3014. _exit(127);
  3015. }
  3016. if (!file)
  3017. file = exec_argv[0];
  3018. if (use_path)
  3019. ret = my_execvpe(file, (char **)exec_argv, envp);
  3020. else
  3021. ret = execve(file, (char **)exec_argv, envp);
  3022. _exit(127);
  3023. }
  3024. /* parent */
  3025. if (block_flag) {
  3026. for(;;) {
  3027. ret = waitpid(pid, &status, 0);
  3028. if (ret == pid) {
  3029. if (WIFEXITED(status)) {
  3030. ret = WEXITSTATUS(status);
  3031. break;
  3032. } else if (WIFSIGNALED(status)) {
  3033. ret = -WTERMSIG(status);
  3034. break;
  3035. }
  3036. }
  3037. }
  3038. } else {
  3039. ret = pid;
  3040. }
  3041. ret_val = JS_NewInt32(ctx, ret);
  3042. done:
  3043. JS_FreeCString(ctx, file);
  3044. JS_FreeCString(ctx, cwd);
  3045. for(i = 0; i < exec_argc; i++)
  3046. JS_FreeCString(ctx, exec_argv[i]);
  3047. js_free(ctx, exec_argv);
  3048. if (envp && envp != environ) {
  3049. char **p;
  3050. p = envp;
  3051. while (*p != NULL) {
  3052. js_free(ctx, *p);
  3053. p++;
  3054. }
  3055. js_free(ctx, envp);
  3056. }
  3057. return ret_val;
  3058. exception:
  3059. ret_val = JS_EXCEPTION;
  3060. goto done;
  3061. }
  3062. /* getpid() -> pid */
  3063. static JSValue js_os_getpid(JSContext *ctx, JSValueConst this_val,
  3064. int argc, JSValueConst *argv)
  3065. {
  3066. return JS_NewInt32(ctx, getpid());
  3067. }
  3068. /* waitpid(pid, block) -> [pid, status] */
  3069. static JSValue js_os_waitpid(JSContext *ctx, JSValueConst this_val,
  3070. int argc, JSValueConst *argv)
  3071. {
  3072. int pid, status, options, ret;
  3073. JSValue obj;
  3074. if (JS_ToInt32(ctx, &pid, argv[0]))
  3075. return JS_EXCEPTION;
  3076. if (JS_ToInt32(ctx, &options, argv[1]))
  3077. return JS_EXCEPTION;
  3078. ret = waitpid(pid, &status, options);
  3079. if (ret < 0) {
  3080. ret = -errno;
  3081. status = 0;
  3082. }
  3083. obj = JS_NewArray(ctx);
  3084. if (JS_IsException(obj))
  3085. return obj;
  3086. JS_DefinePropertyValueUint32(ctx, obj, 0, JS_NewInt32(ctx, ret),
  3087. JS_PROP_C_W_E);
  3088. JS_DefinePropertyValueUint32(ctx, obj, 1, JS_NewInt32(ctx, status),
  3089. JS_PROP_C_W_E);
  3090. return obj;
  3091. }
  3092. /* pipe() -> [read_fd, write_fd] or null if error */
  3093. static JSValue js_os_pipe(JSContext *ctx, JSValueConst this_val,
  3094. int argc, JSValueConst *argv)
  3095. {
  3096. int pipe_fds[2], ret;
  3097. JSValue obj;
  3098. ret = pipe(pipe_fds);
  3099. if (ret < 0)
  3100. return JS_NULL;
  3101. obj = JS_NewArray(ctx);
  3102. if (JS_IsException(obj))
  3103. return obj;
  3104. JS_DefinePropertyValueUint32(ctx, obj, 0, JS_NewInt32(ctx, pipe_fds[0]),
  3105. JS_PROP_C_W_E);
  3106. JS_DefinePropertyValueUint32(ctx, obj, 1, JS_NewInt32(ctx, pipe_fds[1]),
  3107. JS_PROP_C_W_E);
  3108. return obj;
  3109. }
  3110. /* kill(pid, sig) */
  3111. static JSValue js_os_kill(JSContext *ctx, JSValueConst this_val,
  3112. int argc, JSValueConst *argv)
  3113. {
  3114. int pid, sig, ret;
  3115. if (JS_ToInt32(ctx, &pid, argv[0]))
  3116. return JS_EXCEPTION;
  3117. if (JS_ToInt32(ctx, &sig, argv[1]))
  3118. return JS_EXCEPTION;
  3119. ret = js_get_errno(kill(pid, sig));
  3120. return JS_NewInt32(ctx, ret);
  3121. }
  3122. /* dup(fd) */
  3123. static JSValue js_os_dup(JSContext *ctx, JSValueConst this_val,
  3124. int argc, JSValueConst *argv)
  3125. {
  3126. int fd, ret;
  3127. if (JS_ToInt32(ctx, &fd, argv[0]))
  3128. return JS_EXCEPTION;
  3129. ret = js_get_errno(dup(fd));
  3130. return JS_NewInt32(ctx, ret);
  3131. }
  3132. /* dup2(fd) */
  3133. static JSValue js_os_dup2(JSContext *ctx, JSValueConst this_val,
  3134. int argc, JSValueConst *argv)
  3135. {
  3136. int fd, fd2, ret;
  3137. if (JS_ToInt32(ctx, &fd, argv[0]))
  3138. return JS_EXCEPTION;
  3139. if (JS_ToInt32(ctx, &fd2, argv[1]))
  3140. return JS_EXCEPTION;
  3141. ret = js_get_errno(dup2(fd, fd2));
  3142. return JS_NewInt32(ctx, ret);
  3143. }
  3144. #endif /* !_WIN32 */
  3145. #ifdef USE_WORKER
  3146. /* Worker */
  3147. typedef struct {
  3148. JSWorkerMessagePipe *recv_pipe;
  3149. JSWorkerMessagePipe *send_pipe;
  3150. JSWorkerMessageHandler *msg_handler;
  3151. } JSWorkerData;
  3152. typedef struct {
  3153. char *filename; /* module filename */
  3154. char *basename; /* module base name */
  3155. JSWorkerMessagePipe *recv_pipe, *send_pipe;
  3156. int strip_flags;
  3157. } WorkerFuncArgs;
  3158. typedef struct {
  3159. int ref_count;
  3160. uint64_t buf[0];
  3161. } JSSABHeader;
  3162. static JSClassID js_worker_class_id;
  3163. static JSContext *(*js_worker_new_context_func)(JSRuntime *rt);
  3164. static int atomic_add_int(int *ptr, int v)
  3165. {
  3166. return atomic_fetch_add((_Atomic(uint32_t) *)ptr, v) + v;
  3167. }
  3168. /* shared array buffer allocator */
  3169. static void *js_sab_alloc(void *opaque, size_t size)
  3170. {
  3171. JSSABHeader *sab;
  3172. sab = malloc(sizeof(JSSABHeader) + size);
  3173. if (!sab)
  3174. return NULL;
  3175. sab->ref_count = 1;
  3176. return sab->buf;
  3177. }
  3178. static void js_sab_free(void *opaque, void *ptr)
  3179. {
  3180. JSSABHeader *sab;
  3181. int ref_count;
  3182. sab = (JSSABHeader *)((uint8_t *)ptr - sizeof(JSSABHeader));
  3183. ref_count = atomic_add_int(&sab->ref_count, -1);
  3184. assert(ref_count >= 0);
  3185. if (ref_count == 0) {
  3186. free(sab);
  3187. }
  3188. }
  3189. static void js_sab_dup(void *opaque, void *ptr)
  3190. {
  3191. JSSABHeader *sab;
  3192. sab = (JSSABHeader *)((uint8_t *)ptr - sizeof(JSSABHeader));
  3193. atomic_add_int(&sab->ref_count, 1);
  3194. }
  3195. static JSWorkerMessagePipe *js_new_message_pipe(void)
  3196. {
  3197. JSWorkerMessagePipe *ps;
  3198. ps = malloc(sizeof(*ps));
  3199. if (!ps)
  3200. return NULL;
  3201. if (js_waker_init(&ps->waker)) {
  3202. free(ps);
  3203. return NULL;
  3204. }
  3205. ps->ref_count = 1;
  3206. init_list_head(&ps->msg_queue);
  3207. pthread_mutex_init(&ps->mutex, NULL);
  3208. return ps;
  3209. }
  3210. static JSWorkerMessagePipe *js_dup_message_pipe(JSWorkerMessagePipe *ps)
  3211. {
  3212. atomic_add_int(&ps->ref_count, 1);
  3213. return ps;
  3214. }
  3215. static void js_free_message(JSWorkerMessage *msg)
  3216. {
  3217. size_t i;
  3218. /* free the SAB */
  3219. for(i = 0; i < msg->sab_tab_len; i++) {
  3220. js_sab_free(NULL, msg->sab_tab[i]);
  3221. }
  3222. free(msg->sab_tab);
  3223. free(msg->data);
  3224. free(msg);
  3225. }
  3226. static void js_free_message_pipe(JSWorkerMessagePipe *ps)
  3227. {
  3228. struct list_head *el, *el1;
  3229. JSWorkerMessage *msg;
  3230. int ref_count;
  3231. if (!ps)
  3232. return;
  3233. ref_count = atomic_add_int(&ps->ref_count, -1);
  3234. assert(ref_count >= 0);
  3235. if (ref_count == 0) {
  3236. list_for_each_safe(el, el1, &ps->msg_queue) {
  3237. msg = list_entry(el, JSWorkerMessage, link);
  3238. js_free_message(msg);
  3239. }
  3240. pthread_mutex_destroy(&ps->mutex);
  3241. js_waker_close(&ps->waker);
  3242. free(ps);
  3243. }
  3244. }
  3245. static void js_free_port(JSRuntime *rt, JSWorkerMessageHandler *port)
  3246. {
  3247. if (port) {
  3248. js_free_message_pipe(port->recv_pipe);
  3249. JS_FreeValueRT(rt, port->on_message_func);
  3250. if (port->link.prev)
  3251. list_del(&port->link);
  3252. js_free_rt(rt, port);
  3253. }
  3254. }
  3255. static void js_worker_finalizer(JSRuntime *rt, JSValue val)
  3256. {
  3257. JSWorkerData *worker = JS_GetOpaque(val, js_worker_class_id);
  3258. if (worker) {
  3259. js_free_message_pipe(worker->recv_pipe);
  3260. js_free_message_pipe(worker->send_pipe);
  3261. js_free_port(rt, worker->msg_handler);
  3262. js_free_rt(rt, worker);
  3263. }
  3264. }
  3265. static void js_worker_mark(JSRuntime *rt, JSValueConst val,
  3266. JS_MarkFunc *mark_func)
  3267. {
  3268. JSWorkerData *worker = JS_GetOpaque(val, js_worker_class_id);
  3269. if (worker) {
  3270. JSWorkerMessageHandler *port = worker->msg_handler;
  3271. if (port) {
  3272. JS_MarkValue(rt, port->on_message_func, mark_func);
  3273. }
  3274. }
  3275. }
  3276. static JSClassDef js_worker_class = {
  3277. "Worker",
  3278. .finalizer = js_worker_finalizer,
  3279. .gc_mark = js_worker_mark,
  3280. };
  3281. static void *worker_func(void *opaque)
  3282. {
  3283. WorkerFuncArgs *args = opaque;
  3284. JSRuntime *rt;
  3285. JSThreadState *ts;
  3286. JSContext *ctx;
  3287. JSValue val;
  3288. rt = JS_NewRuntime();
  3289. if (rt == NULL) {
  3290. fprintf(stderr, "JS_NewRuntime failure");
  3291. exit(1);
  3292. }
  3293. JS_SetStripInfo(rt, args->strip_flags);
  3294. js_std_init_handlers(rt);
  3295. JS_SetModuleLoaderFunc2(rt, NULL, js_module_loader, js_module_check_attributes, NULL);
  3296. /* set the pipe to communicate with the parent */
  3297. ts = JS_GetRuntimeOpaque(rt);
  3298. ts->recv_pipe = args->recv_pipe;
  3299. ts->send_pipe = args->send_pipe;
  3300. /* function pointer to avoid linking the whole JS_NewContext() if
  3301. not needed */
  3302. ctx = js_worker_new_context_func(rt);
  3303. if (ctx == NULL) {
  3304. fprintf(stderr, "JS_NewContext failure");
  3305. }
  3306. JS_SetCanBlock(rt, TRUE);
  3307. js_std_add_helpers(ctx, -1, NULL);
  3308. val = JS_LoadModule(ctx, args->basename, args->filename);
  3309. free(args->filename);
  3310. free(args->basename);
  3311. free(args);
  3312. val = js_std_await(ctx, val);
  3313. if (JS_IsException(val))
  3314. js_std_dump_error(ctx);
  3315. JS_FreeValue(ctx, val);
  3316. js_std_loop(ctx);
  3317. JS_FreeContext(ctx);
  3318. js_std_free_handlers(rt);
  3319. JS_FreeRuntime(rt);
  3320. return NULL;
  3321. }
  3322. static JSValue js_worker_ctor_internal(JSContext *ctx, JSValueConst new_target,
  3323. JSWorkerMessagePipe *recv_pipe,
  3324. JSWorkerMessagePipe *send_pipe)
  3325. {
  3326. JSValue obj = JS_UNDEFINED, proto;
  3327. JSWorkerData *s;
  3328. /* create the object */
  3329. if (JS_IsUndefined(new_target)) {
  3330. proto = JS_GetClassProto(ctx, js_worker_class_id);
  3331. } else {
  3332. proto = JS_GetPropertyStr(ctx, new_target, "prototype");
  3333. if (JS_IsException(proto))
  3334. goto fail;
  3335. }
  3336. obj = JS_NewObjectProtoClass(ctx, proto, js_worker_class_id);
  3337. JS_FreeValue(ctx, proto);
  3338. if (JS_IsException(obj))
  3339. goto fail;
  3340. s = js_mallocz(ctx, sizeof(*s));
  3341. if (!s)
  3342. goto fail;
  3343. s->recv_pipe = js_dup_message_pipe(recv_pipe);
  3344. s->send_pipe = js_dup_message_pipe(send_pipe);
  3345. JS_SetOpaque(obj, s);
  3346. return obj;
  3347. fail:
  3348. JS_FreeValue(ctx, obj);
  3349. return JS_EXCEPTION;
  3350. }
  3351. static JSValue js_worker_ctor(JSContext *ctx, JSValueConst new_target,
  3352. int argc, JSValueConst *argv)
  3353. {
  3354. JSRuntime *rt = JS_GetRuntime(ctx);
  3355. WorkerFuncArgs *args = NULL;
  3356. pthread_t tid;
  3357. pthread_attr_t attr;
  3358. JSValue obj = JS_UNDEFINED;
  3359. int ret;
  3360. const char *filename = NULL, *basename;
  3361. JSAtom basename_atom;
  3362. /* XXX: in order to avoid problems with resource liberation, we
  3363. don't support creating workers inside workers */
  3364. if (!is_main_thread(rt))
  3365. return JS_ThrowTypeError(ctx, "cannot create a worker inside a worker");
  3366. /* base name, assuming the calling function is a normal JS
  3367. function */
  3368. basename_atom = JS_GetScriptOrModuleName(ctx, 1);
  3369. if (basename_atom == JS_ATOM_NULL) {
  3370. return JS_ThrowTypeError(ctx, "could not determine calling script or module name");
  3371. }
  3372. basename = JS_AtomToCString(ctx, basename_atom);
  3373. JS_FreeAtom(ctx, basename_atom);
  3374. if (!basename)
  3375. goto fail;
  3376. /* module name */
  3377. filename = JS_ToCString(ctx, argv[0]);
  3378. if (!filename)
  3379. goto fail;
  3380. args = malloc(sizeof(*args));
  3381. if (!args)
  3382. goto oom_fail;
  3383. memset(args, 0, sizeof(*args));
  3384. args->filename = strdup(filename);
  3385. args->basename = strdup(basename);
  3386. /* ports */
  3387. args->recv_pipe = js_new_message_pipe();
  3388. if (!args->recv_pipe)
  3389. goto oom_fail;
  3390. args->send_pipe = js_new_message_pipe();
  3391. if (!args->send_pipe)
  3392. goto oom_fail;
  3393. args->strip_flags = JS_GetStripInfo(rt);
  3394. obj = js_worker_ctor_internal(ctx, new_target,
  3395. args->send_pipe, args->recv_pipe);
  3396. if (JS_IsException(obj))
  3397. goto fail;
  3398. pthread_attr_init(&attr);
  3399. /* no join at the end */
  3400. pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
  3401. ret = pthread_create(&tid, &attr, worker_func, args);
  3402. pthread_attr_destroy(&attr);
  3403. if (ret != 0) {
  3404. JS_ThrowTypeError(ctx, "could not create worker");
  3405. goto fail;
  3406. }
  3407. JS_FreeCString(ctx, basename);
  3408. JS_FreeCString(ctx, filename);
  3409. return obj;
  3410. oom_fail:
  3411. JS_ThrowOutOfMemory(ctx);
  3412. fail:
  3413. JS_FreeCString(ctx, basename);
  3414. JS_FreeCString(ctx, filename);
  3415. if (args) {
  3416. free(args->filename);
  3417. free(args->basename);
  3418. js_free_message_pipe(args->recv_pipe);
  3419. js_free_message_pipe(args->send_pipe);
  3420. free(args);
  3421. }
  3422. JS_FreeValue(ctx, obj);
  3423. return JS_EXCEPTION;
  3424. }
  3425. static JSValue js_worker_postMessage(JSContext *ctx, JSValueConst this_val,
  3426. int argc, JSValueConst *argv)
  3427. {
  3428. JSWorkerData *worker = JS_GetOpaque2(ctx, this_val, js_worker_class_id);
  3429. JSWorkerMessagePipe *ps;
  3430. size_t data_len, sab_tab_len, i;
  3431. uint8_t *data;
  3432. JSWorkerMessage *msg;
  3433. uint8_t **sab_tab;
  3434. if (!worker)
  3435. return JS_EXCEPTION;
  3436. data = JS_WriteObject2(ctx, &data_len, argv[0],
  3437. JS_WRITE_OBJ_SAB | JS_WRITE_OBJ_REFERENCE,
  3438. &sab_tab, &sab_tab_len);
  3439. if (!data)
  3440. return JS_EXCEPTION;
  3441. msg = malloc(sizeof(*msg));
  3442. if (!msg)
  3443. goto fail;
  3444. msg->data = NULL;
  3445. msg->sab_tab = NULL;
  3446. /* must reallocate because the allocator may be different */
  3447. msg->data = malloc(data_len);
  3448. if (!msg->data)
  3449. goto fail;
  3450. memcpy(msg->data, data, data_len);
  3451. msg->data_len = data_len;
  3452. if (sab_tab_len > 0) {
  3453. msg->sab_tab = malloc(sizeof(msg->sab_tab[0]) * sab_tab_len);
  3454. if (!msg->sab_tab)
  3455. goto fail;
  3456. memcpy(msg->sab_tab, sab_tab, sizeof(msg->sab_tab[0]) * sab_tab_len);
  3457. }
  3458. msg->sab_tab_len = sab_tab_len;
  3459. js_free(ctx, data);
  3460. js_free(ctx, sab_tab);
  3461. /* increment the SAB reference counts */
  3462. for(i = 0; i < msg->sab_tab_len; i++) {
  3463. js_sab_dup(NULL, msg->sab_tab[i]);
  3464. }
  3465. ps = worker->send_pipe;
  3466. pthread_mutex_lock(&ps->mutex);
  3467. /* indicate that data is present */
  3468. if (list_empty(&ps->msg_queue))
  3469. js_waker_signal(&ps->waker);
  3470. list_add_tail(&msg->link, &ps->msg_queue);
  3471. pthread_mutex_unlock(&ps->mutex);
  3472. return JS_UNDEFINED;
  3473. fail:
  3474. if (msg) {
  3475. free(msg->data);
  3476. free(msg->sab_tab);
  3477. free(msg);
  3478. }
  3479. js_free(ctx, data);
  3480. js_free(ctx, sab_tab);
  3481. return JS_EXCEPTION;
  3482. }
  3483. static JSValue js_worker_set_onmessage(JSContext *ctx, JSValueConst this_val,
  3484. JSValueConst func)
  3485. {
  3486. JSRuntime *rt = JS_GetRuntime(ctx);
  3487. JSThreadState *ts = JS_GetRuntimeOpaque(rt);
  3488. JSWorkerData *worker = JS_GetOpaque2(ctx, this_val, js_worker_class_id);
  3489. JSWorkerMessageHandler *port;
  3490. if (!worker)
  3491. return JS_EXCEPTION;
  3492. port = worker->msg_handler;
  3493. if (JS_IsNull(func)) {
  3494. if (port) {
  3495. js_free_port(rt, port);
  3496. worker->msg_handler = NULL;
  3497. }
  3498. } else {
  3499. if (!JS_IsFunction(ctx, func))
  3500. return JS_ThrowTypeError(ctx, "not a function");
  3501. if (!port) {
  3502. port = js_mallocz(ctx, sizeof(*port));
  3503. if (!port)
  3504. return JS_EXCEPTION;
  3505. port->recv_pipe = js_dup_message_pipe(worker->recv_pipe);
  3506. port->on_message_func = JS_NULL;
  3507. list_add_tail(&port->link, &ts->port_list);
  3508. worker->msg_handler = port;
  3509. }
  3510. JS_FreeValue(ctx, port->on_message_func);
  3511. port->on_message_func = JS_DupValue(ctx, func);
  3512. }
  3513. return JS_UNDEFINED;
  3514. }
  3515. static JSValue js_worker_get_onmessage(JSContext *ctx, JSValueConst this_val)
  3516. {
  3517. JSWorkerData *worker = JS_GetOpaque2(ctx, this_val, js_worker_class_id);
  3518. JSWorkerMessageHandler *port;
  3519. if (!worker)
  3520. return JS_EXCEPTION;
  3521. port = worker->msg_handler;
  3522. if (port) {
  3523. return JS_DupValue(ctx, port->on_message_func);
  3524. } else {
  3525. return JS_NULL;
  3526. }
  3527. }
  3528. static const JSCFunctionListEntry js_worker_proto_funcs[] = {
  3529. JS_CFUNC_DEF("postMessage", 1, js_worker_postMessage ),
  3530. JS_CGETSET_DEF("onmessage", js_worker_get_onmessage, js_worker_set_onmessage ),
  3531. };
  3532. #endif /* USE_WORKER */
  3533. void js_std_set_worker_new_context_func(JSContext *(*func)(JSRuntime *rt))
  3534. {
  3535. #ifdef USE_WORKER
  3536. js_worker_new_context_func = func;
  3537. #endif
  3538. }
  3539. #if defined(_WIN32)
  3540. #define OS_PLATFORM "win32"
  3541. #elif defined(__APPLE__)
  3542. #define OS_PLATFORM "darwin"
  3543. #elif defined(__EMSCRIPTEN__)
  3544. #define OS_PLATFORM "js"
  3545. #else
  3546. #define OS_PLATFORM "linux"
  3547. #endif
  3548. #define OS_FLAG(x) JS_PROP_INT32_DEF(#x, x, JS_PROP_CONFIGURABLE )
  3549. static const JSCFunctionListEntry js_os_funcs[] = {
  3550. JS_CFUNC_DEF("open", 2, js_os_open ),
  3551. OS_FLAG(O_RDONLY),
  3552. OS_FLAG(O_WRONLY),
  3553. OS_FLAG(O_RDWR),
  3554. OS_FLAG(O_APPEND),
  3555. OS_FLAG(O_CREAT),
  3556. OS_FLAG(O_EXCL),
  3557. OS_FLAG(O_TRUNC),
  3558. #if defined(_WIN32)
  3559. OS_FLAG(O_BINARY),
  3560. OS_FLAG(O_TEXT),
  3561. #endif
  3562. JS_CFUNC_DEF("close", 1, js_os_close ),
  3563. JS_CFUNC_DEF("seek", 3, js_os_seek ),
  3564. JS_CFUNC_MAGIC_DEF("read", 4, js_os_read_write, 0 ),
  3565. JS_CFUNC_MAGIC_DEF("write", 4, js_os_read_write, 1 ),
  3566. JS_CFUNC_DEF("isatty", 1, js_os_isatty ),
  3567. JS_CFUNC_DEF("ttyGetWinSize", 1, js_os_ttyGetWinSize ),
  3568. JS_CFUNC_DEF("ttySetRaw", 1, js_os_ttySetRaw ),
  3569. JS_CFUNC_DEF("remove", 1, js_os_remove ),
  3570. JS_CFUNC_DEF("rename", 2, js_os_rename ),
  3571. JS_CFUNC_MAGIC_DEF("setReadHandler", 2, js_os_setReadHandler, 0 ),
  3572. JS_CFUNC_MAGIC_DEF("setWriteHandler", 2, js_os_setReadHandler, 1 ),
  3573. JS_CFUNC_DEF("signal", 2, js_os_signal ),
  3574. OS_FLAG(SIGINT),
  3575. OS_FLAG(SIGABRT),
  3576. OS_FLAG(SIGFPE),
  3577. OS_FLAG(SIGILL),
  3578. OS_FLAG(SIGSEGV),
  3579. OS_FLAG(SIGTERM),
  3580. #if !defined(_WIN32)
  3581. OS_FLAG(SIGQUIT),
  3582. OS_FLAG(SIGPIPE),
  3583. OS_FLAG(SIGALRM),
  3584. OS_FLAG(SIGUSR1),
  3585. OS_FLAG(SIGUSR2),
  3586. OS_FLAG(SIGCHLD),
  3587. OS_FLAG(SIGCONT),
  3588. OS_FLAG(SIGSTOP),
  3589. OS_FLAG(SIGTSTP),
  3590. OS_FLAG(SIGTTIN),
  3591. OS_FLAG(SIGTTOU),
  3592. #endif
  3593. JS_CFUNC_DEF("now", 0, js_os_now ),
  3594. JS_CFUNC_DEF("setTimeout", 2, js_os_setTimeout ),
  3595. JS_CFUNC_DEF("clearTimeout", 1, js_os_clearTimeout ),
  3596. JS_CFUNC_DEF("sleepAsync", 1, js_os_sleepAsync ),
  3597. JS_PROP_STRING_DEF("platform", OS_PLATFORM, 0 ),
  3598. JS_CFUNC_DEF("getcwd", 0, js_os_getcwd ),
  3599. JS_CFUNC_DEF("chdir", 0, js_os_chdir ),
  3600. JS_CFUNC_DEF("mkdir", 1, js_os_mkdir ),
  3601. JS_CFUNC_DEF("readdir", 1, js_os_readdir ),
  3602. /* st_mode constants */
  3603. OS_FLAG(S_IFMT),
  3604. OS_FLAG(S_IFIFO),
  3605. OS_FLAG(S_IFCHR),
  3606. OS_FLAG(S_IFDIR),
  3607. OS_FLAG(S_IFBLK),
  3608. OS_FLAG(S_IFREG),
  3609. #if !defined(_WIN32)
  3610. OS_FLAG(S_IFSOCK),
  3611. OS_FLAG(S_IFLNK),
  3612. OS_FLAG(S_ISGID),
  3613. OS_FLAG(S_ISUID),
  3614. #endif
  3615. JS_CFUNC_MAGIC_DEF("stat", 1, js_os_stat, 0 ),
  3616. JS_CFUNC_DEF("utimes", 3, js_os_utimes ),
  3617. JS_CFUNC_DEF("sleep", 1, js_os_sleep ),
  3618. JS_CFUNC_DEF("realpath", 1, js_os_realpath ),
  3619. #if !defined(_WIN32)
  3620. JS_CFUNC_MAGIC_DEF("lstat", 1, js_os_stat, 1 ),
  3621. JS_CFUNC_DEF("symlink", 2, js_os_symlink ),
  3622. JS_CFUNC_DEF("readlink", 1, js_os_readlink ),
  3623. JS_CFUNC_DEF("exec", 1, js_os_exec ),
  3624. JS_CFUNC_DEF("getpid", 0, js_os_getpid ),
  3625. JS_CFUNC_DEF("waitpid", 2, js_os_waitpid ),
  3626. OS_FLAG(WNOHANG),
  3627. JS_CFUNC_DEF("pipe", 0, js_os_pipe ),
  3628. JS_CFUNC_DEF("kill", 2, js_os_kill ),
  3629. JS_CFUNC_DEF("dup", 1, js_os_dup ),
  3630. JS_CFUNC_DEF("dup2", 2, js_os_dup2 ),
  3631. #endif
  3632. };
  3633. static int js_os_init(JSContext *ctx, JSModuleDef *m)
  3634. {
  3635. os_poll_func = js_os_poll;
  3636. #ifdef USE_WORKER
  3637. {
  3638. JSRuntime *rt = JS_GetRuntime(ctx);
  3639. JSThreadState *ts = JS_GetRuntimeOpaque(rt);
  3640. JSValue proto, obj;
  3641. /* Worker class */
  3642. JS_NewClassID(&js_worker_class_id);
  3643. JS_NewClass(JS_GetRuntime(ctx), js_worker_class_id, &js_worker_class);
  3644. proto = JS_NewObject(ctx);
  3645. JS_SetPropertyFunctionList(ctx, proto, js_worker_proto_funcs, countof(js_worker_proto_funcs));
  3646. obj = JS_NewCFunction2(ctx, js_worker_ctor, "Worker", 1,
  3647. JS_CFUNC_constructor, 0);
  3648. JS_SetConstructor(ctx, obj, proto);
  3649. JS_SetClassProto(ctx, js_worker_class_id, proto);
  3650. /* set 'Worker.parent' if necessary */
  3651. if (ts->recv_pipe && ts->send_pipe) {
  3652. JS_DefinePropertyValueStr(ctx, obj, "parent",
  3653. js_worker_ctor_internal(ctx, JS_UNDEFINED, ts->recv_pipe, ts->send_pipe),
  3654. JS_PROP_C_W_E);
  3655. }
  3656. JS_SetModuleExport(ctx, m, "Worker", obj);
  3657. }
  3658. #endif /* USE_WORKER */
  3659. return JS_SetModuleExportList(ctx, m, js_os_funcs,
  3660. countof(js_os_funcs));
  3661. }
  3662. JSModuleDef *js_init_module_os(JSContext *ctx, const char *module_name)
  3663. {
  3664. JSModuleDef *m;
  3665. m = JS_NewCModule(ctx, module_name, js_os_init);
  3666. if (!m)
  3667. return NULL;
  3668. JS_AddModuleExportList(ctx, m, js_os_funcs, countof(js_os_funcs));
  3669. #ifdef USE_WORKER
  3670. JS_AddModuleExport(ctx, m, "Worker");
  3671. #endif
  3672. return m;
  3673. }
  3674. /**********************************************************/
  3675. static JSValue js_print(JSContext *ctx, JSValueConst this_val,
  3676. int argc, JSValueConst *argv)
  3677. {
  3678. int i;
  3679. JSValueConst v;
  3680. for(i = 0; i < argc; i++) {
  3681. if (i != 0)
  3682. putchar(' ');
  3683. v = argv[i];
  3684. if (JS_IsString(v)) {
  3685. const char *str;
  3686. size_t len;
  3687. str = JS_ToCStringLen(ctx, &len, v);
  3688. if (!str)
  3689. return JS_EXCEPTION;
  3690. fwrite(str, 1, len, stdout);
  3691. JS_FreeCString(ctx, str);
  3692. } else {
  3693. JS_PrintValue(ctx, js_print_value_write, stdout, v, NULL);
  3694. }
  3695. }
  3696. putchar('\n');
  3697. return JS_UNDEFINED;
  3698. }
  3699. static JSValue js_console_log(JSContext *ctx, JSValueConst this_val,
  3700. int argc, JSValueConst *argv)
  3701. {
  3702. JSValue ret;
  3703. ret = js_print(ctx, this_val, argc, argv);
  3704. fflush(stdout);
  3705. return ret;
  3706. }
  3707. void js_std_add_helpers(JSContext *ctx, int argc, char **argv)
  3708. {
  3709. JSValue global_obj, console, args, performance;
  3710. int i;
  3711. /* XXX: should these global definitions be enumerable? */
  3712. global_obj = JS_GetGlobalObject(ctx);
  3713. console = JS_NewObject(ctx);
  3714. JS_SetPropertyStr(ctx, console, "log",
  3715. JS_NewCFunction(ctx, js_console_log, "log", 1));
  3716. JS_SetPropertyStr(ctx, global_obj, "console", console);
  3717. performance = JS_NewObject(ctx);
  3718. JS_SetPropertyStr(ctx, performance, "now",
  3719. JS_NewCFunction(ctx, js_os_now, "now", 0));
  3720. JS_SetPropertyStr(ctx, global_obj, "performance", performance);
  3721. /* same methods as the mozilla JS shell */
  3722. if (argc >= 0) {
  3723. args = JS_NewArray(ctx);
  3724. for(i = 0; i < argc; i++) {
  3725. JS_SetPropertyUint32(ctx, args, i, JS_NewString(ctx, argv[i]));
  3726. }
  3727. JS_SetPropertyStr(ctx, global_obj, "scriptArgs", args);
  3728. }
  3729. JS_SetPropertyStr(ctx, global_obj, "print",
  3730. JS_NewCFunction(ctx, js_print, "print", 1));
  3731. JS_SetPropertyStr(ctx, global_obj, "__loadScript",
  3732. JS_NewCFunction(ctx, js_loadScript, "__loadScript", 1));
  3733. JS_FreeValue(ctx, global_obj);
  3734. }
  3735. void js_std_init_handlers(JSRuntime *rt)
  3736. {
  3737. JSThreadState *ts;
  3738. ts = malloc(sizeof(*ts));
  3739. if (!ts) {
  3740. fprintf(stderr, "Could not allocate memory for the worker");
  3741. exit(1);
  3742. }
  3743. memset(ts, 0, sizeof(*ts));
  3744. init_list_head(&ts->os_rw_handlers);
  3745. init_list_head(&ts->os_signal_handlers);
  3746. init_list_head(&ts->os_timers);
  3747. init_list_head(&ts->port_list);
  3748. init_list_head(&ts->rejected_promise_list);
  3749. ts->next_timer_id = 1;
  3750. JS_SetRuntimeOpaque(rt, ts);
  3751. #ifdef USE_WORKER
  3752. /* set the SharedArrayBuffer memory handlers */
  3753. {
  3754. JSSharedArrayBufferFunctions sf;
  3755. memset(&sf, 0, sizeof(sf));
  3756. sf.sab_alloc = js_sab_alloc;
  3757. sf.sab_free = js_sab_free;
  3758. sf.sab_dup = js_sab_dup;
  3759. JS_SetSharedArrayBufferFunctions(rt, &sf);
  3760. }
  3761. #endif
  3762. }
  3763. void js_std_free_handlers(JSRuntime *rt)
  3764. {
  3765. JSThreadState *ts = JS_GetRuntimeOpaque(rt);
  3766. struct list_head *el, *el1;
  3767. list_for_each_safe(el, el1, &ts->os_rw_handlers) {
  3768. JSOSRWHandler *rh = list_entry(el, JSOSRWHandler, link);
  3769. free_rw_handler(rt, rh);
  3770. }
  3771. list_for_each_safe(el, el1, &ts->os_signal_handlers) {
  3772. JSOSSignalHandler *sh = list_entry(el, JSOSSignalHandler, link);
  3773. free_sh(rt, sh);
  3774. }
  3775. list_for_each_safe(el, el1, &ts->os_timers) {
  3776. JSOSTimer *th = list_entry(el, JSOSTimer, link);
  3777. free_timer(rt, th);
  3778. }
  3779. list_for_each_safe(el, el1, &ts->rejected_promise_list) {
  3780. JSRejectedPromiseEntry *rp = list_entry(el, JSRejectedPromiseEntry, link);
  3781. JS_FreeValueRT(rt, rp->promise);
  3782. JS_FreeValueRT(rt, rp->reason);
  3783. free(rp);
  3784. }
  3785. #ifdef USE_WORKER
  3786. js_free_message_pipe(ts->recv_pipe);
  3787. js_free_message_pipe(ts->send_pipe);
  3788. list_for_each_safe(el, el1, &ts->port_list) {
  3789. JSWorkerMessageHandler *port = list_entry(el, JSWorkerMessageHandler, link);
  3790. /* unlink the message ports. They are freed by the Worker object */
  3791. port->link.prev = NULL;
  3792. port->link.next = NULL;
  3793. }
  3794. #endif
  3795. #if !defined(_WIN32)
  3796. free(ts->poll_fds);
  3797. #endif
  3798. free(ts);
  3799. JS_SetRuntimeOpaque(rt, NULL); /* fail safe */
  3800. }
  3801. static void js_std_dump_error1(JSContext *ctx, JSValueConst exception_val)
  3802. {
  3803. JS_PrintValue(ctx, js_print_value_write, stderr, exception_val, NULL);
  3804. fputc('\n', stderr);
  3805. }
  3806. void js_std_dump_error(JSContext *ctx)
  3807. {
  3808. JSValue exception_val;
  3809. exception_val = JS_GetException(ctx);
  3810. js_std_dump_error1(ctx, exception_val);
  3811. JS_FreeValue(ctx, exception_val);
  3812. }
  3813. static JSRejectedPromiseEntry *find_rejected_promise(JSContext *ctx, JSThreadState *ts,
  3814. JSValueConst promise)
  3815. {
  3816. struct list_head *el;
  3817. list_for_each(el, &ts->rejected_promise_list) {
  3818. JSRejectedPromiseEntry *rp = list_entry(el, JSRejectedPromiseEntry, link);
  3819. if (JS_SameValue(ctx, rp->promise, promise))
  3820. return rp;
  3821. }
  3822. return NULL;
  3823. }
  3824. void js_std_promise_rejection_tracker(JSContext *ctx, JSValueConst promise,
  3825. JSValueConst reason,
  3826. BOOL is_handled, void *opaque)
  3827. {
  3828. JSRuntime *rt = JS_GetRuntime(ctx);
  3829. JSThreadState *ts = JS_GetRuntimeOpaque(rt);
  3830. JSRejectedPromiseEntry *rp;
  3831. if (!is_handled) {
  3832. /* add a new entry if needed */
  3833. rp = find_rejected_promise(ctx, ts, promise);
  3834. if (!rp) {
  3835. rp = malloc(sizeof(*rp));
  3836. if (rp) {
  3837. rp->promise = JS_DupValue(ctx, promise);
  3838. rp->reason = JS_DupValue(ctx, reason);
  3839. list_add_tail(&rp->link, &ts->rejected_promise_list);
  3840. }
  3841. }
  3842. } else {
  3843. /* the rejection is handled, so the entry can be removed if present */
  3844. rp = find_rejected_promise(ctx, ts, promise);
  3845. if (rp) {
  3846. JS_FreeValue(ctx, rp->promise);
  3847. JS_FreeValue(ctx, rp->reason);
  3848. list_del(&rp->link);
  3849. free(rp);
  3850. }
  3851. }
  3852. }
  3853. /* check if there are pending promise rejections. It must be done
  3854. asynchrously in case a rejected promise is handled later. Currently
  3855. we do it once the application is about to sleep. It could be done
  3856. more often if needed. */
  3857. static void js_std_promise_rejection_check(JSContext *ctx)
  3858. {
  3859. JSRuntime *rt = JS_GetRuntime(ctx);
  3860. JSThreadState *ts = JS_GetRuntimeOpaque(rt);
  3861. struct list_head *el;
  3862. if (unlikely(!list_empty(&ts->rejected_promise_list))) {
  3863. list_for_each(el, &ts->rejected_promise_list) {
  3864. JSRejectedPromiseEntry *rp = list_entry(el, JSRejectedPromiseEntry, link);
  3865. fprintf(stderr, "Possibly unhandled promise rejection: ");
  3866. js_std_dump_error1(ctx, rp->reason);
  3867. }
  3868. exit(1);
  3869. }
  3870. }
  3871. /* main loop which calls the user JS callbacks */
  3872. void js_std_loop(JSContext *ctx)
  3873. {
  3874. int err;
  3875. for(;;) {
  3876. /* execute the pending jobs */
  3877. for(;;) {
  3878. err = JS_ExecutePendingJob(JS_GetRuntime(ctx), NULL);
  3879. if (err <= 0) {
  3880. if (err < 0)
  3881. js_std_dump_error(ctx);
  3882. break;
  3883. }
  3884. }
  3885. js_std_promise_rejection_check(ctx);
  3886. if (!os_poll_func || os_poll_func(ctx))
  3887. break;
  3888. }
  3889. }
  3890. /* Wait for a promise and execute pending jobs while waiting for
  3891. it. Return the promise result or JS_EXCEPTION in case of promise
  3892. rejection. */
  3893. JSValue js_std_await(JSContext *ctx, JSValue obj)
  3894. {
  3895. JSValue ret;
  3896. int state;
  3897. for(;;) {
  3898. state = JS_PromiseState(ctx, obj);
  3899. if (state == JS_PROMISE_FULFILLED) {
  3900. ret = JS_PromiseResult(ctx, obj);
  3901. JS_FreeValue(ctx, obj);
  3902. break;
  3903. } else if (state == JS_PROMISE_REJECTED) {
  3904. ret = JS_Throw(ctx, JS_PromiseResult(ctx, obj));
  3905. JS_FreeValue(ctx, obj);
  3906. break;
  3907. } else if (state == JS_PROMISE_PENDING) {
  3908. int err;
  3909. err = JS_ExecutePendingJob(JS_GetRuntime(ctx), NULL);
  3910. if (err < 0) {
  3911. js_std_dump_error(ctx);
  3912. }
  3913. if (err == 0) {
  3914. js_std_promise_rejection_check(ctx);
  3915. if (os_poll_func)
  3916. os_poll_func(ctx);
  3917. }
  3918. } else {
  3919. /* not a promise */
  3920. ret = obj;
  3921. break;
  3922. }
  3923. }
  3924. return ret;
  3925. }
  3926. void js_std_eval_binary(JSContext *ctx, const uint8_t *buf, size_t buf_len,
  3927. int load_only)
  3928. {
  3929. JSValue obj, val;
  3930. obj = JS_ReadObject(ctx, buf, buf_len, JS_READ_OBJ_BYTECODE);
  3931. if (JS_IsException(obj))
  3932. goto exception;
  3933. if (load_only) {
  3934. if (JS_VALUE_GET_TAG(obj) == JS_TAG_MODULE) {
  3935. js_module_set_import_meta(ctx, obj, FALSE, FALSE);
  3936. }
  3937. JS_FreeValue(ctx, obj);
  3938. } else {
  3939. if (JS_VALUE_GET_TAG(obj) == JS_TAG_MODULE) {
  3940. if (JS_ResolveModule(ctx, obj) < 0) {
  3941. JS_FreeValue(ctx, obj);
  3942. goto exception;
  3943. }
  3944. js_module_set_import_meta(ctx, obj, FALSE, TRUE);
  3945. val = JS_EvalFunction(ctx, obj);
  3946. val = js_std_await(ctx, val);
  3947. } else {
  3948. val = JS_EvalFunction(ctx, obj);
  3949. }
  3950. if (JS_IsException(val)) {
  3951. exception:
  3952. js_std_dump_error(ctx);
  3953. exit(1);
  3954. }
  3955. JS_FreeValue(ctx, val);
  3956. }
  3957. }
  3958. void js_std_eval_binary_json_module(JSContext *ctx,
  3959. const uint8_t *buf, size_t buf_len,
  3960. const char *module_name)
  3961. {
  3962. JSValue obj;
  3963. JSModuleDef *m;
  3964. obj = JS_ReadObject(ctx, buf, buf_len, 0);
  3965. if (JS_IsException(obj))
  3966. goto exception;
  3967. m = create_json_module(ctx, module_name, obj);
  3968. if (!m) {
  3969. exception:
  3970. js_std_dump_error(ctx);
  3971. exit(1);
  3972. }
  3973. }