1 #include <stdlib.h>
2 #include <assert.h>
3 #include <unistd.h>
4 #include <fcntl.h>
5 
6 #include "lub/string.h"
7 #include "private.h"
8 
9 /*----------------------------------------------------------- */
clish_shell_push(clish_shell_t * this,FILE * file,const char * fname,bool_t stop_on_error)10 static int clish_shell_push(clish_shell_t * this, FILE * file,
11 	const char *fname, bool_t stop_on_error)
12 {
13 	/* Allocate a control node */
14 	clish_shell_file_t *node = malloc(sizeof(clish_shell_file_t));
15 
16 	assert(this);
17 	assert(node);
18 
19 	/* intialise the node */
20 	node->file = file;
21 	if (fname)
22 		node->fname = lub_string_dup(fname);
23 	else
24 		node->fname = NULL;
25 	node->line = 0;
26 	node->stop_on_error = stop_on_error;
27 	node->next = this->current_file;
28 
29 	/* put the node at the top of the file stack */
30 	this->current_file = node;
31 
32 	/* now switch the terminal's input stream */
33 	tinyrl__set_istream(this->tinyrl, file);
34 
35 	return 0;
36 }
37 
38 /*----------------------------------------------------------- */
clish_shell_push_file(clish_shell_t * this,const char * fname,bool_t stop_on_error)39 int clish_shell_push_file(clish_shell_t * this, const char * fname,
40 	bool_t stop_on_error)
41 {
42 	FILE *file;
43 	int res;
44 
45 	assert(this);
46 	if (!fname)
47 		return -1;
48 	file = fopen(fname, "r");
49 	if (!file)
50 		return -1;
51 #ifdef FD_CLOEXEC
52        fcntl(fileno(file), F_SETFD, fcntl(fileno(file), F_GETFD) | FD_CLOEXEC);
53 #endif
54 	res = clish_shell_push(this, file, fname, stop_on_error);
55 	if (res)
56 		fclose(file);
57 
58 	return res;
59 }
60 
61 /*----------------------------------------------------------- */
clish_shell_push_fd(clish_shell_t * this,FILE * file,bool_t stop_on_error)62 int clish_shell_push_fd(clish_shell_t *this, FILE *file,
63 	bool_t stop_on_error)
64 {
65 	return clish_shell_push(this, file, NULL, stop_on_error);
66 }
67 
68 /*----------------------------------------------------------- */
clish_shell_pop_file(clish_shell_t * this)69 int clish_shell_pop_file(clish_shell_t *this)
70 {
71 	int result = -1;
72 	clish_shell_file_t *node = this->current_file;
73 
74 	if (!node)
75 		return -1;
76 
77 	/* remove the current file from the stack... */
78 	this->current_file = node->next;
79 	/* and close the current file... */
80 	fclose(node->file);
81 	if (node->next) {
82 		/* now switch the terminal's input stream */
83 		tinyrl__set_istream(this->tinyrl, node->next->file);
84 		result = 0;
85 	}
86 	/* and free up the memory */
87 	if (node->fname)
88 		lub_string_free(node->fname);
89 	free(node);
90 
91 	return result;
92 }
93 
94 /*----------------------------------------------------------- */
95