12

I would like to evaluate in org mode source code blocks in C++ containing "cin" instructions but I can't find a way to have an interactive evaluation (with user input) during evaluation. Example of code :

#+BEGIN_SRC C++  :results output :export code :tangle myfile.cpp 
#include <iostream>
using namespace std;

int main()
{
int a;
cin>>a;
cout<<a+1;
}
#+END_SRC

Is it possible to have such an interactive evaluation or to simulate (by giving to the source code a fake input) ?

3
  • Do you actually need it to be interactive, or do you just need to give it some input you may already know in advance, just not in this code block? The second case is easier: you could use :var varname=value in the header. In the second case you could still use :var, but in place of value use another code block with an ELisp function which asks for input.
    – wvxvw
    Aug 26, 2015 at 18:43
  • Thanks @wvxvw for your answer; What I want to do is to make a document with some program examples for students and therefore I would like to keep the source code block "as is"; so my preference would be the second case you mention; I will try to follow your suggestion (to use :var and an elisp code to ask for input), do you have a link or an example of such a call ?
    – Lgen
    Aug 27, 2015 at 6:46
  • Oh, sorry, there's been a bit of misunderstanding. The second example would use Emacs to read the input, but Babel won't call C++ program in the way such as to allow interaction. The only thing I can think about is that if you add some "polymorphic" function to your code, which has two implementations: one, where you read input interactively, and another one, where you read it from file or provide during code block evaluation.
    – wvxvw
    Aug 27, 2015 at 7:02

4 Answers 4

9

Like this:

#+begin_src C++ :results output :cmdline < in.txt
#include <iostream>
int main(int argc, char *argv[]) {
  int a;
  std::cin >> a;
  std::cout << a + 1;
  return 0;
}

#+end_src

#+RESULTS:
: 11

Create a file in.txt in the same directory as the Org file, with contents 10.

0
8

You can ask Emacs to get the interactive input instead using a named elisp block. Then pass the collected value to the C++ souce block using the :var c-variable=block-name syntax:

#+name: input_block
#+BEGIN_SRC elisp :export none :results none
(completing-read "a=" nil)

#+END_SRC

#+BEGIN_SRC C++  :results output :export code :tangle myfile.cpp :var input=input_block
  #include <stdlib.h>
  #include <iostream>
  using namespace std;

  int main()
  {
  int a = atoi(input);
  cout<<a+1;
  }
#+END_SRC 

Note that the outputs of source blocks are passed around as strings, so we have to convert it to an integer, hence the atoi and the extra #include.

2
  • 1
    Do as you like. However, your code is bound to Org-mode, while mine can be copy-pasted verbatim and readily compiled.
    – abo-abo
    Aug 27, 2015 at 12:40
  • 1
    Thanks @erikstrokes for this contribution; I had a similar idea (use an external block) and made a mix with abo-abo solution. I posted the result as an answer.
    – Lgen
    Aug 27, 2015 at 12:56
4

Thanks @abo-abo for your help. I have followed your suggestion which is right and even enhanced it a little to edit only my org file (and to create automatically the external input file). The idea is to create an external code block (here a bash script named build_input_file) which creates the data file and to call it automatically before evaluating the other block thanks to the:var tmp=build_input_file.

#+name: build_input_file
#+BEGIN_SRC bash  :results none :exports none 
echo "10 12" > in.txt
#+END_SRC

#+name: my_function_with_cin
#+BEGIN_SRC C++  :results output :exports both  :var tmp=build_input_file :cmdline < in.txt
#include <iostream>
using namespace std;

int main()
{
 int a,b;
 cin>>a>>b;
 cout<<a<<" "<<b;
}
#+END_SRC
2

If you would like use :stdin like awk block, just add this to your Emacs config:

Updated: I ended up with an Emacs package: https://github.com/cxa/ob-C-stdin/tree/main

(defun org-babel-C-execute/filter-args (args)
  (when-let* ((params (cadr args))
              (stdin (cdr (assoc :stdin params)))
              (res (org-babel-ref-resolve stdin))
              (stdin (org-babel-temp-file "c-stdin-")))
        (with-temp-file stdin (insert res))
    (let* ((cmdline (assoc :cmdline params))
           (cmdline-val (or (cdr cmdline) "")))
      (when cmdline (setq params (delq cmdline params)))
      (setq params
            (cons (cons :cmdline (concat cmdline-val " <" stdin))
                  params))
      (setf (cadr args) params)))
  args)

(with-eval-after-load 'ob-C
  (advice-add 'org-babel-C-execute :filter-args
              #'org-babel-C-execute/filter-args))

Then you can write your org like:

#+name: data
24444 4444

#+begin_src cpp :results output :stdin data
...
#+end_src

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.