us.clang.js 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. //有思工作室编程类,用于Windows下面的C语言。
  2. //说明:nodejs很多命令默认是在linux下面写的,所以windows平台的信息有些不准确。
  3. //不能调用spawn命令,spawn是最原始的,不能设置超时时间,但spawn可以用数组,这点方便。
  4. //知识要点:CL为编译命令。[]数组中为参数选项
  5. // /nolog为不输出微软的标志。
  6. //哎,用GCC吧。等以后node稳定了再做windows版本。
  7. var fs = require('fs');
  8. var exec = require('child_process').exec, free;
  9. //var exec = require('child_process').exec, free = exec('CL', ['hello.c', '/nologo']);
  10. //var spawn = require('child_process').spawn, free = spawn('hello.exe', ['hello.c']);
  11. //var spawn = require('child_process').spawn, free = spawn('free', ['-m']);
  12. //------------------------------------------------执行PHP等解释型语言,解释执行的必须加chroot做沙箱------------------------------------------------------------
  13. //PHP语言
  14. exports.exephp = function (res, f,type) {
  15. //编译指令//生成gcc命令。
  16. //再执行此执行文件,chroot是让命令执行在沙箱中。沙箱命令需要去除目录标识。
  17. var cmd = "chroot ./output php ./userfiles/" + f + ".php";
  18. console.log(cmd);
  19. //解释性语言异步执行编译生成的命令为空。
  20. interpreLang(res, cmd , f, type);
  21. }
  22. //Python语言
  23. exports.exepython = function (res, f,type) {
  24. var cmd = "chroot ./output python ./userfiles/" + f + ".py";
  25. console.log(cmd);
  26. interpreLang(res, cmd, f, type); ; //解释性语言异步执行编译生成的命令为空。
  27. }
  28. //Nodejs语言
  29. exports.exenodejs = function (res, f,type) {
  30. var cmd = "chroot ./output node ./userfiles/" + f + ".js";
  31. console.log(cmd);
  32. interpreLang(res, cmd, f, type); ; //解释性语言异步执行编译生成的命令为空。
  33. }
  34. //Ruby语言
  35. exports.exeruby = function (res, f,type) {
  36. var cmd = "chroot ./output ruby ./userfiles/" + f + ".rb";
  37. console.log(cmd);
  38. interpreLang(res, cmd, f, type); ; //解释性语言异步执行编译生成的命令为空。
  39. }
  40. //Perl语言
  41. exports.exeperl = function (res, f,type) {
  42. var cmd = "chroot ./output perl ./userfiles/" + f + ".pl";
  43. console.log(cmd);
  44. interpreLang(res, cmd, f, type); ; //解释性语言异步执行编译生成的命令为空。
  45. }
  46. //Lisp语言
  47. exports.exelisp = function (res, f,type) {
  48. var cmd = "chroot ./output clisp ./userfiles/" + f + ".lisp";
  49. console.log(cmd);
  50. interpreLang(res, cmd, f, type); ; //解释性语言异步执行编译生成的命令为空。
  51. }
  52. //解释性语言统一调用函数
  53. interpreLang = function (res, cmd,f, type) {
  54. var output = ""; //最终返回的错误信息,警告信息,执行成功信息以及生成的exe的执行信息。但如何区分?
  55. //解释性语言异步执行编译生成的命令为空。
  56. usexefile(res, cmd, "", f, output, type, interpreLangAsyn);
  57. }
  58. interpreLangAsyn = function (res, output,f, acmd, type) {
  59. output = "运行环境Linux+" + type + "语言:\n" + output;
  60. res.end(output); //php很简单,没C复杂
  61. }
  62. //------------------------------------------------执行Gcc Net Mono等编译型-----------------------------------------------------
  63. //执行Net和Mono
  64. //mono还需要 /proc才能运行,需要把/proc mount到 chroot目录
  65. //首先在choot目录下建立文件夹 /proc。
  66. //mount proc ./proc -t proc
  67. exports.exenet = function (res, f,type) {
  68. //Mono编译太慢,需要调整时间为5秒
  69. f = './output/userfiles/' + f; //给文件加上目录名
  70. var cmd = 'mcs ' + f + '.cs';
  71. //再执行此执行文件,chroot是让命令执行在沙箱中。沙箱命令需要去除目录标识。异步执行的命令
  72. var acmd = "chroot ./output mono ./userfiles/" + f.slice(19) + ".exe";
  73. execomplie(res, f, cmd, acmd,type);
  74. }
  75. //执行Gcc
  76. exports.exegcc = function (res, f,type) {
  77. //编译指令//生成gcc命令。
  78. f = './output/userfiles/' + f; //给文件加上目录名
  79. var cmd = 'gcc ' + f + '.c' + ' -o ' + f + '.exe';
  80. //再执行此执行文件,chroot是让命令执行在沙箱中。沙箱命令需要去除目录标识。异步执行的命令
  81. var acmd = "chroot ./output ./userfiles/" + f.slice(19) + ".exe";
  82. execomplie(res, f, cmd, acmd,type);
  83. }
  84. //------------------------------------------------------编译型命令封装-------------------------------------------
  85. //res是传递的http参数,f是文件,c是需要执行的编译命令,as是编译成功后执行可执行的exe文件命令
  86. execomplie = function (res, f,cmd,acmd,type) {
  87. //编译指令//生成gcc命令。
  88. var output = ""; //最终返回的错误信息,警告信息,执行成功信息以及生成的exe的执行信息。但如何区分?
  89. usexefile(res, cmd, acmd, f, output,type, execcompileAsyn);
  90. }
  91. //执行Gcc命令回调函数。参数1为执行gcc的返回数据,参数f为文件名。acmd是执行编译成功后可执行文件的命令
  92. execcompileAsyn = function (res, output, f,acmd,type) {
  93. //如何判断编译成功呢?暂时采用是否生成了可执行文件的方式。如果采用这种方式,好像windows平台也能做,但有问题,生成成功后再次生成即使错误也会判断成功。
  94. //对了,同时判断是否有错误输出就OK了。前台判断好还是后台判断好?
  95. //加Sync表示同步,此处异步好还是同步好呢?
  96. if (builderr(output)) res.end(output);
  97. else {
  98. if (fs.existsSync(f + '.exe')) {
  99. output += "运行环境Linux+" + type + "语言:\n";
  100. //再执行此执行文件,把异步命令作为执行命令,原来的异步命令为空。
  101. usexefile(res, acmd,"", f, output,type, execexeAsyn); //异步执行生成的exe文件。
  102. }
  103. }
  104. }
  105. //执行C语言可执行文件回调函数
  106. execexeAsyn = function (res, output, f) {
  107. //删除执行文件,准备下次运行。此处不好整理逻辑。
  108. res.end(output);
  109. }
  110. //判断编译是否发生错误,如果发送错误,则输出true,否则输出false
  111. builderr = function (output) {
  112. var z = output.replace(/\r\n/g, '\n').split('\n'), i;
  113. for (i = 0; i < z.length; i++) {
  114. if (z[i].indexOf('标准错误输出') > -1)
  115. return true;
  116. }
  117. return false;
  118. }
  119. //--------------------------------------执行控制台命名封装---------------------------------------
  120. //判断用户是否输出了加大的文字量,如果用户恶意输入,给他提示,结束程序。
  121. largeoutput = function (res,output) {
  122. if (output.length > 10000)
  123. res.end("哥们,别开玩笑!\n"+output);
  124. }
  125. //雨云科技执行文件函数,cmd是nycodex.com命令,callback是执行完毕后的回调函数
  126. usexefile = function (res, cmd, acmd, f, output,type, callback) {
  127. //var output = ""; //输出,因为stderr或者stdout会触发多次,用一个变量循环,为啥要触发多次,以后研究。
  128. //-Wall 把所有编译警告全部显示。-o指定输出目录
  129. //free = exec('gcc -Wall ./output/hello.c -o ./output/h.exe',
  130. free = exec(cmd, {
  131. encoding: 'utf8', //编码设置
  132. //encoding: null, //编码设置
  133. timeout: 8000, //超时时间设置。
  134. maxBuffer: 200 * 1024,
  135. killSignal: 'SIGTERM',
  136. cwd: null,
  137. env: process.env //windows环境设置或者linux环境设置,好像不成功
  138. });
  139. // 捕获标准输出并将其打印到控制台
  140. free.stdout.on('data', function (data) {
  141. //console.log('标准输出:\n' + data);//data != "\n" ? output += "标准输出: " + data : output += data; //给输出前面加上中文标示,便于学生理解
  142. output += data;
  143. //res.write(data);
  144. //if(output.length>1) res.end(output);
  145. //largeoutput(res, output);
  146. //res.end("AAAAAA");
  147. });
  148. // 捕获标准错误输出并将其打印到控制台 //console.log('标准错误输出:\n' + data);
  149. free.stderr.on('data', function (data) {
  150. (data != "\n"&&data != "\r") ? output += ("标准错误输出:" + data) : output += data; //给输出前面加上中文标示,便于学生理解。
  151. });
  152. // 注册子进程关闭事件 //console.log('子进程已退出,代码:' + code); console.log(output);
  153. free.on('exit', function (code, signal) {
  154. largeoutput(res, output);
  155. if (callback) callback(res, output, f,acmd,type); //如果有定义回调函数,则执行回调函数。
  156. });
  157. //free.stdin.write("4\n");
  158. //C语言处理标准输入,非常麻烦,暂时留在这里。这应该封装为一个函数。首先用resume恢复以前的进程,不过首先需要找到该进程。
  159. //free.stdin.resume(); //这句话是为了不让控制台推出
  160. //free.stdin.on('data', function (data) {
  161. //console.log('标准输出:\n' + data);//data != "\n" ? output += "标准输出: " + data : output += data; //给输出前面加上中文标示,便于学生理解
  162. //free.stdout.write('标准输入:' + data);
  163. //free.stdin.emit('end');
  164. //output += "本系统暂时不支持scanf输入语句,有高手能实现吗?请在意见反馈中联系我们,谢谢";
  165. //res.end(output);
  166. //free.stdout.write('data:'+data);
  167. //});
  168. //free.stdin.on('end', function () {
  169. //if(output.length>1) res.end(output);
  170. //output+="input end";
  171. //free.stdout.write('end');
  172. //output += "本系统暂时不支持scanf输入语句,有高手能实现吗?请在意见反馈中联系我们,谢谢";
  173. //});
  174. }