diff --git a/jupyter_c_kernel/kernel.py b/jupyter_c_kernel/kernel.py index 502ac9c..68eda6a 100644 --- a/jupyter_c_kernel/kernel.py +++ b/jupyter_c_kernel/kernel.py @@ -72,8 +72,10 @@ class RealTimeSubprocess(subprocess.Popen): if(len(contents) > 0): self._write_to_stdout(contents) readLine = self._read_from_stdin() + # need to add newline since it is not captured by frontend + readLine += "\n" + os.write(1, readLine.encode()); self.stdin.write(readLine.encode()) - self.stdin.write(b"\n") else: self._write_to_stdout(contents) @@ -88,7 +90,7 @@ class CKernel(Kernel): language = 'c' language_version = 'C11' language_info = {'name': 'text/x-csrc', - 'mimetype': 'text/plain', + 'mimetype': 'text/x-csrc', 'file_extension': '.c'} banner = "C kernel.\n" \ "Uses gcc, compiles in C11, and creates source code files and executables in temporary folder.\n" @@ -188,10 +190,10 @@ class CKernel(Kernel): # also add common magics like -lm def _add_main(self, magics, code): # remove comments - tmpCode = re.sub("//.*", "", code) - tmpCode = re.sub("/\*.*?\*/", "", tmpCode, flags=re.M|re.S) + tmpCode = re.sub(r"//.*", "", code) + tmpCode = re.sub(r"/\*.*?\*/", "", tmpCode, flags=re.M|re.S) - x = re.search("int\s+main\s*\(", tmpCode) + x = re.search(r"int\s+main\s*\(", tmpCode) if not x: code = self.main_head + code + self.main_foot @@ -234,6 +236,11 @@ class CKernel(Kernel): p = self.create_jupyter_subprocess([self.master_path, binary_file.name] + magics['args']) while p.poll() is None: p.write_contents() + + # wait for threads to finish, so output is always shown + p._stdout_thread.join() + p._stderr_thread.join() + p.write_contents() # now remove the files we have just created diff --git a/jupyter_c_kernel/resources/stdio_wrap.h b/jupyter_c_kernel/resources/stdio_wrap.h index e7a1ebf..9c431cc 100644 --- a/jupyter_c_kernel/resources/stdio_wrap.h +++ b/jupyter_c_kernel/resources/stdio_wrap.h @@ -3,22 +3,76 @@ #include <stdio.h> #include <stdarg.h> +#include <string.h> + +/* Need input buffer to know whether we need another input request */ +char inputBuff[1<<10] = ""; + +/* read remaining input into buffer so it can be used in next call */ +void readIntoBuffer() { + long length = strlen(inputBuff); + char nextChar = 0; + while((nextChar = getchar()) != '\n'){ + inputBuff[length++] = nextChar; + } + inputBuff[length++] = '\n'; + inputBuff[length] = '\0'; +} /* Define the functions to overload the old ones */ int scanf_wrap(const char *format, ...) { - printf("<inputRequest>"); - fflush(stdout); + /* unget chars in buffer */ + int doRequest = 1; + long index = strlen(inputBuff) - 1; + // printf("Start index: %ld\n", index); + for(; index >= 0; --index) { + ungetc(inputBuff[index], stdin); + /* if there already is a newline in buffer + we need no input request */ + if(inputBuff[index] == '\n') { + doRequest = 0; + } + } + /* Buffer will always be empty after scanf call + since there is no way to enter more than one + newline in the frontend */ + inputBuff[0] = '\0'; + // printf("doRequest: %d\n", doRequest); + if(doRequest) { + printf("<inputRequest>"); + fflush(stdout); + } va_list arglist; va_start( arglist, format ); int result = vscanf( format, arglist ); va_end( arglist ); + return result; } int getchar_wrap(){ - printf("<inputRequest>"); - fflush(stdout); - return getchar(); + /* check if there is still something in the input buffer*/ + char input = 0; + long length = strlen(inputBuff); + if(length <= 0) { + printf("<inputRequest>"); + fflush(stdout); + + input = getchar(); + readIntoBuffer(); + } else { + input = inputBuff[0]; + /* shift all chars one to the left */ + int i = 1; + for(; i < 100; ++i){ + inputBuff[i-1] = inputBuff[i]; + if(inputBuff[i] == '\0') { + break; + } + } + } + + return input; } /* Replace all the necessary input functions