r827: Fix a crash when no audio output device can be opened.
[cinelerra_cv.git] / cinelerra / pipe.C
blob1128ef2c0e8297d456dfdbe7ddadc939a7e4975f
1 #include <fcntl.h>
2 #include <string.h>
3 #include <errno.h>
4 #include <signal.h>
6 #include "defaults.h"
7 #include "file.h"
8 #include "guicast.h"
9 #include "interlacemodes.h"
10 #include "pipe.h"
12 extern "C" {
13         int pipe_sigpipe_received;
15         void pipe_handle_sigpipe(int signum) {
16                 printf("Received sigpipe\n");
17                 pipe_sigpipe_received++;
18         }
21 Pipe::Pipe(char *command, char *sub_str, char sub_char) { 
22         this->command = command;
23         this->sub_str = sub_str;
24         this->sub_char = sub_char;
26         complete[0] = '\0';
27         file = NULL;
28         fd = -1;
30         // FUTURE: could probably set to SIG_IGN once things work
31         signal(SIGPIPE, pipe_handle_sigpipe);
34 Pipe::~Pipe() {         
35         close();
38 int Pipe::substitute() {
39         if (command == NULL) {
40                 strcpy(complete, "");
41                 return 0;
42         }
44         if (sub_str == NULL || sub_char == '\0') {
45                 strcpy(complete, command);
46                 return 0;
47         }
49         int count = 0;
50         char *c = command;
51         char *f = complete;
52         while (*c) {
53                 // directly copy anything substitution char
54                 if (*c != sub_char) {
55                         *f++ = *c++;
56                         continue;
57                 }
58                 
59                 // move over the substitution character
60                 c++;
62                 // two substitution characters in a row is literal
63                 if (*c == sub_char) {
64                         *f++ = *c++;
65                         continue;
66                 }
68                 // insert the file string at the substitution point
69                 if (f + strlen(sub_str) - complete > sizeof(complete)) {
70                         printf("Pipe::substitute(): max length exceeded\n");
71                         return -1;
72                 }
73                 strcpy(f, sub_str);
74                 f += strlen(sub_str);
75                 count++;
76         }
78         return count;
80         
81         
83 int Pipe::open(char *mode) {
84         if (file) close();
86         if (mode == NULL) {
87                 printf("Pipe::open(): no mode given\n");
88                 return 1;
89         }
91         if (substitute() < 0) {
92                 return 1;
93         }
95         if (complete == NULL || strlen(complete) == 0) {
96                 printf("Pipe::open(): no pipe to open\n");
97                 return 1;
98         }
100         printf("trying popen(%s)\n", complete);
101         file = popen(complete, mode);
102         if (file != NULL) {
103                 fd = fileno(file);
104                 return 0;
105         }
107         // NOTE: popen() fails only if fork/exec fails
108         //       there is no immediate way to see if command failed
109         //       As such, one must expect to raise SIGPIPE on failure
110         printf("Pipe::open(%s,%s) failed: %s\n", 
111                complete, mode, strerror(errno));
112         return 1;
113 }       
115 int Pipe::open_read() {
116         return open("r");
119 int Pipe::open_write() {
120         return open("w");
123 void Pipe::close() {
124         pclose(file);
125         file = 0;
126         fd = -1;
130 PipeConfig::PipeConfig(BC_WindowBase *window, Defaults *defaults, Asset *asset)
132         this->window = window;
133         this->defaults = defaults;
134         this->asset = asset;
137 // NOTE: Default destructor should destroy all subwindows
139 int PipeConfig::create_objects(int x, int y, int textbox_width, int format) {
140         int x1 = x;
141         BC_Title *titlew;
142         // NOTE: out of order so pipe_textbox is available to pipe_checkbox
143         textbox = new BC_TextBox(x + 120, y, textbox_width, 1, asset->pipe);
144         window->add_subwindow(textbox);
145         if (! asset->use_pipe) textbox->disable();
147         window->add_subwindow(new BC_Title(x, y, _("Use Pipe:")));
148         checkbox = new PipeCheckBox(85, y - 5, asset->use_pipe, textbox);
149         window->add_subwindow(checkbox);
151         x += 120;       
152         x += textbox_width;
154         recent = new BC_RecentList("PIPE", defaults, textbox,
155                                 10, x, y, 350, 100);
156         window->add_subwindow(recent);
157         recent->load_items(FILE_FORMAT_PREFIX(format));
159         x = x1;
160         y += 30;
161         window->add_subwindow(titlew = new BC_Title(x, y, _("Stream Header:"), MEDIUMFONT, RED));
162         x = x1 + 10;
163         y += 30;
165         window->add_subwindow(new BC_Title(x, y, _("Interlacing:")));
166         char string[BCTEXTLEN];
167         ilacemode_to_text(string,asset->interlace_mode);
168         window->add_subwindow(new BC_Title(x + titlew->get_w() + 5, y, string, MEDIUMFONT, YELLOW));
171 PipeCheckBox::PipeCheckBox(int x, int y, int value, BC_TextBox *textbox)
172         : BC_CheckBox(x, y, value)
174         this->textbox = textbox;
176 int PipeCheckBox::handle_event() {
177         if (get_value()) textbox->enable();
178         else textbox->disable();
181 PipeStatus::PipeStatus(int x, int y, char *default_string) 
182         : BC_Title(x, y, default_string)
184         this->default_string = default_string;
186 int PipeStatus::set_status(Asset *asset) {
187         if (! asset->use_pipe || ! asset->pipe || ! *(asset->pipe)) {
188                 set_color(BLACK);
189                 sprintf(status, default_string);
190         }
191         else {
192                 set_color(RED);
193                 sprintf(status, "| %s", asset->pipe);
194         }
196         update(status);
201 PipePreset::PipePreset(int x, int y, char *title, PipeConfig *config)
202         : BC_PopupMenu(x, y, 150, title)
204         this->config = config;
205         this->title = title;
208 int PipePreset::handle_event() {
209         char *text = get_text();
210         // NOTE: preset items must have a '|' before the actual command
211         char *pipe = strchr(text, '|');
212         // pipe + 1 to skip over the '|'
213         if (pipe) config->textbox->update(pipe + 1);
215         config->textbox->enable();
216         config->checkbox->set_value(1, 1);
217         
218         // menuitem sets the title after selection but we reset it
219         set_text(title);