Processing large files with libsndfile - c++

Currently I've written a program (in Visual Studio C++) based on the available example code of "libsndfile" in which I've just added a subtraction-function to subtract one (channel of a) WAV-file with another.
The program worked perfectly for files with a limit of 4 channels.
The problem is that as soon as I upload a file with as many as 5 channels or more, the program refuses to execute the function. This is independent of the frame-size as I've managed to process 4-channel files which were many times larger than some 5/6-channel-files which I have used.
Has anyone encountered this or a similar problem before? If requested I will provide the source code.
My apologies for the bad structure, I don't really optimize until I get the whole deal working.
Code:
#include <sndfile.hh>
#include <tinyxml2.h>
#include <iostream>
#include <fstream>
#define BLOCK_SIZE 32
using TiXmlDocument = tinyxml2::XMLDocument;
using CStdStringA = std::string;
int main(int argc, char* argv[])
{
SNDFILE *infile = NULL;
SNDFILE *infile2 = NULL;
SNDFILE *outfile = NULL;
SF_INFO sfinfo;
SF_INFO sfinfo2;
SF_INFO sfinfoOut;
sf_count_t readcount;
//int filetype = SF_FORMAT_WAV | SF_FORMAT_PCM_24; // 24-bit Wav-Files
TiXmlDocument iDoc; // Init tinyXML
int i; // Iteration-var;
short BufferIn[BLOCK_SIZE]; // Buffer1
short BufferIn2[BLOCK_SIZE]; // Buffer2
short BufferOut[BLOCK_SIZE];
CStdStringA FileLoc, FileName, FileLocWav, FileLocTxt,FileLocRaw; // OutputFile locationstring
CStdStringA WavName, WavName2, FileIn, FileIn2;
FileLoc = "C:\\Testfiles\\";
//TextTitle(FileLoc); // Print console-header
printf("Name Wavefile 1:\n");
std::cin >> WavName;
FileIn = FileLoc + WavName + ".wav";
if((infile = sf_open(FileIn.c_str(),SFM_READ,&sfinfo)) == NULL) // Open Wav-file 2 instance
{
printf("Not able to open input file 1\n");
printf("\n\nPress any key to exit."); // Exit-text if file not present
puts(sf_strerror(NULL)) ;
return 1;
}
std::cout << "Wav file 1 succesfully opened." << std::endl;
std::cout << "\nChannels: " << sfinfo.channels << "\nFrames: " << sfinfo.frames << std::endl; // Print Channels & Frames
std::cout << "Samplerate: " << sfinfo.samplerate << "\n\n" << std::endl;// Print Samplerate
printf("Name Wavefile 2:\n");
std::cin >> WavName2;
FileIn2 = FileLoc + WavName2 + ".wav";
if((infile2 = sf_open(FileIn2.c_str(),SFM_READ,&sfinfo2)) == NULL) // Open Wav-file 2 instance
{
printf("Not able to open input file 2\n");
printf("\n\nPress any key to exit."); // Exit-text if file not present
puts(sf_strerror(NULL)) ;
return 1;
}
std::cout << "Wav file 2 succesfully opened." << std::endl;
std::cout << "\nChannels: " << sfinfo2.channels << "\nFrames: " << sfinfo2.frames << std::endl; // Print Channels & Frames
std::cout << "Samplerate: " << sfinfo2.samplerate << "\n\n" << std::endl;// Print Samplerate
//{
//std::cout << "Format differs from eachother, abort program.";
//printf("\n\nPress any key to exit."); // Exit-text
//return 1;
//}
if(sfinfo.channels != sfinfo2.channels) // Abort if channels not the same
{
std::cout << "Channelammount differs from eachother, abort program.";
printf("\n\nPress any key to exit."); // Exit-text
return 1;
}
if(sfinfo.samplerate != sfinfo2.samplerate) // Abort if samplerate not the same
{
std::cout << "Samplerate differs from eachother, abort program.";
printf("\n\nPress any key to exit."); // Exit-text
return 1;
}
std::cout << "Give a filename for Txt- & Wav-file: ";
std::cin >> FileName;
FileLoc += FileName; // Fuse Filelocation with given name
FileLocTxt = FileLoc + ".txt";
FileLocWav = FileLoc + ".wav";
FileLocRaw = FileLoc + "Raw.txt";
sfinfoOut.channels = sfinfo.channels;
sfinfoOut.format = sfinfo.format;
sfinfoOut.samplerate = sfinfo.samplerate;
if((outfile = sf_open(FileLocWav.c_str(),SFM_WRITE,&sfinfoOut)) == NULL) // Open Wav-file 2 instance
{
printf("Not able to create output file \n");
printf("\n\nPress any key to exit."); // Exit-text if file not present
puts(sf_strerror(NULL)) ;
return 1;
}
std::ofstream myfile;
myfile.open(FileLocTxt.c_str(),std::ios::app);
std::ofstream myfileRaw;
myfileRaw.open(FileLocRaw.c_str(),std::ios::app);
while((readcount = sf_read_short(infile, BufferIn, BLOCK_SIZE))) // While there are still frames to be processed
{
//process_data (data, readcount, sfinfo.channels) ;
auto readcount2 = sf_read_short(infile2, BufferIn2, BLOCK_SIZE);
for(i = 0; i < BLOCK_SIZE; i++) // BLOCK_SIZE decides the chunk-size
{
BufferOut[i] = BufferIn[i] - BufferIn2[i];
myfileRaw << BufferOut[i];
}
sf_write_short(outfile, BufferOut, BLOCK_SIZE) ; // Write the data to a new file
}
sf_close(infile); // Close Wav-file handlers
sf_close(infile2);
sf_close(outfile);
myfile.close(); // Close text-file handlers
printf("\n\nPress any key to exit."); // Exit-text
return 0;
}

The documentation states:
File Read Functions (Items)
sf_count_t sf_read_short (SNDFILE *sndfile, short *ptr, sf_count_t items) ;
sf_count_t sf_read_int (SNDFILE *sndfile, int *ptr, sf_count_t items) ;
sf_count_t sf_read_float (SNDFILE *sndfile, float *ptr, sf_count_t items) ;
sf_count_t sf_read_double (SNDFILE *sndfile, double *ptr, sf_count_t items) ;
The file read items functions fill the array pointed to by ptr with the requested number of items. The items parameter must be an integer product of the number of channels or an error will occur
There's your problem, since BLOCK_SIZE is a multiple of 1,2,4 but not of 3 and 5 - so that would fail.
About the problem that program completes as if calculations had taken place: add appropriate error handling.

Related

Add multiple files from buffers to ZIP archive using libzip

I'm trying to use libzip in a program that needs to archive several data chunks in different files. At the moment I have a code similar to the following snippet, edited from in-memory.c example in libzip examples.
The zip file is correctly saved with the files inside, but each file contains garbage.
Any help is appreciated.
bool push_files(zip_t* za) {
for (int i = 0; i < 10; i++) {
// Generate data
std::stringstream ss;
ss << "Test file #" << i;
std::string a = ss.str();
zip_source_t* source = zip_source_buffer(za, a.c_str(), a.size(), 0);
if (source == NULL) {
std::cerr << "error creating source: " << zip_strerror(za) << std::endl;
return false;
}
// Add buffer with filename
std::stringstream fname;
fname << "TEST-" << i;
a = fname.str();
if (zip_file_add(za, a.c_str(), source, ZIP_FL_ENC_UTF_8) < 0) {
std::cerr << "error adding source: " << zip_strerror(za) << std::endl;
return false;
}
}
return true;
}
int main() {
zip_source_t* src;
zip_error_t error;
zip_t* za;
zip_error_init(&error);
if ((src = zip_source_buffer_create(NULL, 0, 1, &error)) == NULL) {
std::cerr << "can't create source: " << zip_error_strerror(&error) << std::endl;
zip_error_fini(&error);
return 1;
}
if ((za = zip_open_from_source(src, ZIP_TRUNCATE, &error)) == NULL) {
std::cerr << "can't open zip from source: " << zip_error_strerror(&error) << std::endl;
zip_source_free(src);
zip_error_fini(&error);
return 1;
}
zip_error_fini(&error);
zip_source_keep(src);
if (!push_files(za))
return -1;
if (zip_close(za) < 0) {
std::cerr << "can't close zip archive" << zip_strerror(za) << std::endl;
return 1;
}
// ... omissis, save archive to file as in in-memory.c
}
zip_source_buffer does not copy the data out of the buffer - it just creates a zip_source_t which points to the same buffer. So you must keep the buffer alive until you're done adding the file.
Your code does not keep the buffer alive. The buffer you use is a.c_str() which is the data buffer of the string a. Fair enough, so far. But then before adding the file, you reassign the variable a = fname.str(); which (probably) frees that buffer and allocates a new one.
Solution: use a separate variable for the filename. Don't overwrite a until the file has been added.

Write vector of unsigned char to binary file c++

I am reading binary file cmd.exe into unsigned chars array. Total bytes read into bytes_read are 153. I converted it to base64 string and then decode this string back (code from 2nd answer base64 decode snippet in c++) into vector<'BYTE>. Here BYTE is unsigned char.
decodedData.size() is also 153. But when I write this vector to file in binary mode to get my cmd.exe file again I get only 1 KB file. What thing I missed?
// Reading size of file
FILE * file = fopen("cmd.exe", "r+");
if (file == NULL) return 1;
fseek(file, 0, SEEK_END);
long int size = ftell(file);
fclose(file);
// Reading data to array of unsigned chars
file = fopen("cmd.exe", "r+");
unsigned char * myData = (unsigned char *)malloc(size);
int bytes_read = fread(myData, sizeof(unsigned char), size, file);
fclose(file);
std::string encodedData = base64_encode(&myData[0], bytes_read);
std::vector<BYTE> decodedData = base64_decode(encodedData);
////write data to file
ofstream outfile("cmd.exe", ios::out | ios::binary);
outfile.write((const char *)decodedData.data(), decodedData.size());
Update:
Thanks #chux for suggesting "r+" --> "rb+" Problem resolved.
You marked this as C++.
This is one C++ approach using fstream to read a binary file. To simplify for this example, I created a somewhat bigger m_buff than needed. From the comments, it sounds like your fopen("cmd.exe", "r+") was in error, so I'm only providing a C++ binary read.
Method tReader() a) opens a file in binary mode, b) reads the data into m_buff, and c) captures gCount for display.
It also demonstrates one possible use of chrono to measure duration.
#include <chrono>
// 'compressed' chrono access --------------vvvvvvv
typedef std::chrono::high_resolution_clock HRClk_t;
typedef HRClk_t::time_point Time_t;
typedef std::chrono::microseconds US_t;
using namespace std::chrono_literals; // suffixes 100ms, 2s, 30us
#include <iostream>
#include <fstream>
#include <cassert>
class T516_t
{
enum BuffConstraints : uint32_t {
Meg = (1024 * 1024),
END_BuffConstraints
};
char* m_buff;
int64_t m_gCount;
public:
T516_t()
: m_buff (nullptr)
, m_gCount (0)
{
m_buff = new char[Meg];
}
~T516_t() = default;
int exec()
{
tReader();
return(0);
}
private: // methods
void tReader()
{
std::string pfn = "/home/dmoen/.wine/drive_c/windows/system32/cmd.exe";
// open file in binary mode
std::ifstream sIn (pfn, std::ios_base::binary);
if (!sIn.is_open()) {
std::cerr << "UNREACHABLE: unable to open sIn " << pfn
<< " priviledges? media offline?";
return;
}
Time_t start_us = HRClk_t::now();
do
{
// perform read
sIn.read (m_buff, Meg);
// If the input sequence runs out of characters to extract (i.e., the
// end-of-file is reached) before n characters have been successfully
// read, buff contains all the characters read until that point, and
// both eofbit and failbit flags are set
m_gCount = sIn.gcount();
if(sIn.eof()) { break; } // exit when no more data
if(sIn.failbit ) {
std::cerr << "sIn.faileBit() set" << std::endl;
}
}while(1);
auto duration_us = std::chrono::duration_cast<US_t>(HRClk_t::now() - start_us);
sIn.close();
std::cout << "\n " << pfn
<< " " << m_gCount << " bytes"
<< " " << duration_us.count() << " us"
<< std::endl;
} // int64_t tReader()
}; // class T516_t
int main(int , char**)
{
Time_t start_us = HRClk_t::now();
int retVal = -1;
{
T516_t t516;
retVal = t516.exec();
}
auto duration_us = std::chrono::duration_cast<US_t>(HRClk_t::now() - start_us);
std::cout << " FINI " << duration_us.count() << " us" << std::endl;
return(retVal);
}
One typical output on my system looks like:
/home/dmoen/.wine/drive_c/windows/system32/cmd.exe 722260 bytes 1180 us
FINI 1417 us
Your results will vary.
Your ofstream use looks good (so did not replicate).

Incorrectly generated wav file due to improper usage of sndfile library

Even though the text file to which I saved all the samples contains (possibly) proper samples, the sound file generated using the same set of data contains only the noise. The code responsible for writing the wav file:
void Filter::generateFrequencySound()
{
SNDFILE * outfile;
SF_INFO sfinfo;// = {0};
memset (&sfinfo, 0, sizeof (sfinfo)) ;
//preparing output file
sfinfo.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16;
sfinfo.channels = 1;
sfinfo.samplerate = 44100;
std::cout << "Trying to save samples to a file" << std::endl;
const char* path = "FilterInFrequency.wav";
outfile = sf_open(path, SFM_WRITE, &sfinfo);
if(!(outfile))
{
std::cout << "Failed to create output file" << std::endl;
sf_perror(outfile);
return;
}
unsigned long savedSamples = sf_write_double( outfile,
outputOfFrequencyFiltration,
bufferSize);
if(savedSamples > bufferSize)
{
std::cout << "Failed to save all samples into outflie. Number of sampels " << savedSamples << std::endl;
sf_close(outfile);
return;
}
sf_close(outfile);
QSound::play("FilterInFrequency.wav");
}
The code responsible for writing samples into a text file:
QFile file("finalResult_1.txt");
if(!file.open(QIODevice::WriteOnly))
{
std::cout << "something went wrong";
exit(16);
}
QTextStream outstream(&file);
for(unsigned long i = 0; i < bufferSize; i++)
{
QString line = QString::number(outputOfFrequencyFiltration[i]);
outstream << line << "\n";
}
file.close();
Comparison of divergence between wav and plotted text file can be seen in the attached image. The plots have been created using the same amount of data (~20500 samples- ~10% of the output file). The file size is same for both plots.
What could be the possible reason for the differences?
textfile
wavfile

Unhandled exception: Corrupted heap and access violation reading memory location

I'm trying to write a multithreading program for a hw assignment. So far, all I've got in my program is some code to read a set of binary data files (provided for the assignment), and read the contents of those files into a 2D data array. The program builds without any errors, but when I run it, it exits after reading the names of the DAT files from a specified metadata file. I cannot figure out where I'm going wrong, and any help will be appreciated!
This is the error I receive:
"Unhandled exception at 0x773a5c0c (ntdll.dll) in MultiThreading.exe: 0xC0000374: A heap has been corrupted."
Followed by:
"Unhandled exception at 0x7730d1ed (ntdll.dll) in MultiThreading.exe: 0xC0000005: Access violation reading location 0x0000001e."
This is my code, and I'm positive there's an error in there somewhere, but I'm new to C++ programming and I can't find it :-/
// MultiThreading.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <iostream>
#include <fstream>
#include <string>
#include <time.h>
#include <Windows.h>
//include the custom header file
//#include <Engine.h>
using namespace std;
using namespace System;
using namespace System::Threading;
void ReadData(char * filename, int * nVals, float ** dataVals);
int ReadMeta(char * metaFile, int * nThreads, int * nFiles, string ** filenames);
void main(int argc, char * argv[])
{
//set default # of threads in case no user input is provided
int nThreads = 12;
//assign default metainfo file in case no user input is provided
char metaFile[200] = "DataFiles\\MetaInfo.txt";
//check for console user input for threads and metainfo file, if available
if (argc > 1)
{
nThreads = atoi(argv[1]);
if (argc > 2)
{
strcpy_s(metaFile, argv[2]);
}
}
//initialize # of files and string to hold filenames
int nFiles = 0;
string * filenames = NULL;
//read metainfo to get # of data files and file names
//Call ReadMeta(metaFile, &nThreads, &nFiles, &filenames);
//check for errors in reading metainfo
if (ReadMeta(metaFile, &nThreads, &nFiles, &filenames) == 0)
{
cout << "Error reading data files and/or requesting threads."
<< "\nOperation aborted!\n\n";
}
//read file data into multiple arrays
for (int i = 0; i < nFiles; i++)
{
cout << "Reading contents of data file " << filenames[i];
int nVals = NULL;
float * dataArray = NULL;
//convert string to char for filename to pass to function
char * binFile = (char*)filenames[i].c_str();
//read files and write to dataArray
ReadData(binFile, &nVals, &dataArray);
}
//release memory
if (filenames) delete[] filenames;
filenames = NULL;
system("pause");
}
int ReadMeta(char * metaFile, int * nThreads, int * nFiles, string ** filenames)
{
ifstream inputFile(metaFile);
//check for error locating metainfo file
if (!inputFile)
{
cout << "ERROR: Target file " << metaFile << " was not found.\n";
return 0;
}
//assign # of files to *nFiles
inputFile >> (*nFiles);
//check if data files are listed in metainfo file
if (*nFiles < 1)
{
cout << "No data files are provided!\n";
inputFile.close();
return 0;
}
else if (*nFiles < 2)
{
cout << "NOTE: Only ONE data file is available.\n\n";
}
//print number of data files to screen
else
{
cout << *nFiles << " data files are available.\n\n";
}
//check for # of threads being requested and set to default value if reqd
if ((*nThreads <= 0) || (*nThreads > *nFiles))
{
cout << "WARNING: Invalid number of threads requested.\n"
<< "Number of threads truncated to valid range 2 - " << *nFiles
<< "\nDefault value is 2 threads.";
*nThreads = 2;
}
//print # of data files and threads to screen
cout << *nFiles << " files are available.\n"
<< *nThreads << " threads have been requested.\n"
<< "Each file is assigned to a separate thread.\n";
//adjust number of threads
if (*nThreads > *nFiles)
{
*nThreads = *nFiles;
cout << "Fewer threads will be created due to insufficient data files."
<< "That is, only " << *nThreads << " threads will be created.\n\n";
}
else if (*nThreads < *nFiles)
{
*nFiles = *nThreads;
cout << "Fewer files will be used to meet the thread requirements."
<< "That is, only " << *nFiles << " files will be used for "
<< *nThreads << " threads.\n\n";
}
//assign file names to *filenames
*filenames = new string[*nFiles];
for (int i = 1; i <= (*nFiles); i++)
{
inputFile >> (*filenames)[i];
cout << "\nData file #" << i << ": " << (*filenames)[i].c_str() ;
}
//close metainfo file
inputFile.close();
cout << endl << endl;
return 1;
}
void ReadData(char * filename, int * nVals, float ** dataVals)
{
//open the file "filename" passed to the function
FILE * thisFile;
fopen_s(&thisFile, filename, "rb");
//read the number of values contained in the file
fread(nVals, sizeof(int), 1, thisFile);
//create an exact sized array to hold the values contained in the file
*dataVals = new float[*nVals];
//read values from file to array
fread(*dataVals, sizeof(float), *nVals, thisFile);
//close the file
fclose(thisFile);
}
I'm using Visual Studio Community 2015 on a Windows 10 x64 system. The program is configured for Win32.
Absolutely ANY help or any directions that can help me fix this will be greatly, greatly appreciated.
Thanks!
*filenames = new string[*nFiles];
for (int i = 1; i <= (*nFiles); i++)
{
inputFile >> (*filenames)[i];
cout << "\nData file #" << i << ": " << (*filenames)[i].c_str() ;
}
Arrays in C++ start with index of 0. An array filename containing five elements contains elements filename[0] through filename[4].
In this case, you would allocate an array of five strings, but instead of initializing filename[0] through filename[4], you will attempt to initialize filename[1] through filename[5].
Since filename[5] does not exist, this result in undefined behavior. A runtime crash that you've observed is one of the likely results from this undefined behavior.

Unable to send message to parent process after multiple forks

I have a program that forks off four processes and calls execlp() to run different code for the child. I pass the child a number as an id. So far, all the child does is try to pass the id back to the parent process. The pipes work, if i put a string though the stream it prints out in the parent process. However, when i try to put the id as an int thought the stream, it does not work. I dont even get to the line of code after the fprintf() and fflush() command in the child.
I made some changes for how i created the file descriptors and added more code for an example. Now, in the child, i am unable to create the FILE* out. However, if i create out on file descriptor 1, it does print to the screen. I tried creating out on file descriptor 3 and the program just sits there and waits for input from the child that never comes.
Here is my parent:
Mom::Mom():childCount(0)
{
pipeCount = fileCount = 0;
int fd[2];
srand(time(NULL));
for(int c=0; c<NUMJOBS; ++c) jobs[c] = newJob();
//createFileDescriptors(fd);
ret = pipe(fd);
if(ret < 0) fatal("Error creating pipes");
//cout << fd[0] << "\t" << fd[1] << endl;
pipes[fileCount++] = fdopen(fd[0], "r");
fcntl( 3, F_SETFD, 0 );
//close(fd[1]);
//for(int c=3; c<FILEDESCRIPTORS; c+=2) pipes[pipeCount++] = fdopen(c, "w");
createChildren();
for(int c=0; c<4; c++)
{
int tmp = -1;
//cout << "About to read from children, tmp = " << tmp << endl;
ret = fscanf(pipes[0], "%d", &tmp);
//char* buffer = (char*) malloc(80*sizeof(char));
//char buffer[80];
//read(3, buffer, 80);
cout << ret << "\t" << tmp << endl;
//cout << ret << " " << tmp << endl;
//free(buffer);
}
//sleep(5);
}
/*------------------------------------------------------------------------------
Create all the children by using fork() and execlp()
----------------------------------------------------------------------------*/
void Mom::createChildren()
{
int fd[2];
fcntl( fd[IN], F_SETFD, 0 );
for(int c=0; c<NUMCHILDREN; c++)
{
ret = pipe(fd);
if(ret < 0) fatal("Error creating pipes");
int pid = fork();
//cout << pid << endl;
if(pid == 0)
{
setupChild(c, fd);
}
else
{
//close(fd[1]);
}
}
}
/*------------------------------------------------------------------------------
set up the child and call exec to run ChildMain
----------------------------------------------------------------------------*/
void Mom::setupChild(int count, int fd[])
{
//cout << "Creating child with id: " << count << endl;
char cnt = '0' + count;
string id_str (&cnt + '\0');
fcntl( fd[0], F_SETFD, 0 );
pipes[fileCount++] = fdopen(fd[1], "w");
//execlp("ChildMain", "ChildMain", id_str.c_str(), NULL);
execlp("ChildMain", id_str.c_str(), NULL);
}
And here is the child code:
int main(int argc, char* argv[])
{
//cout << argv[argc-1] << endl;
if(argc < 1) fatal("Not enough arguments provided to ChildMain");
int id = atoi(argv[argc-1]);
//cout << *argv[1] << " " << id << endl;
//redirect STDIN and STDOUT
/*int c_in = dup(0);
close(0);
dup((2*id) + 5);
int c_out = dup(1);
close(1);
dup(4);*/
/////////////////////////////
//Child kid((int) *argv[1]);
FILE* out = fdopen(4, "w");
if(out == NULL)
cout << "Error opening stream to parent in child: " << id << endl;
//char childID = '0' + id;
//char buf[80];
//strcpy(buf, "Child ");
//strcat(buf, &childID);
string buf ("Child");
//cout << tmp << " " << childID << endl;
//write(4, buf.c_str(), buf.length()+1);
//cout << id << endl;
int ret = fprintf(out, "%d", id);
fflush(out);
//fclose(out);
//cout << id << " " << ret << endl;
//ch.push_back((char) id);
//put STDIN and STDOUT back to correct file descriptors
/*close(1);
dup(c_out);
close(0);
dup(c_in);*/
////////////////////////////////////////////////////////
return 0;
}
I am very confused why this works for the first child, with id 0, but no the others. Does anyone know what is wrong with my code?
execlp(3) is expecting null terminated strings as it's args. &cnt won't be null terminated.
Simple fix:
void Mom::setupChild(int count, int fd[])
{
char cnt[2];
cnt[0] = '0' + count;
cnt[1] = '\0';
fcntl( fd[(2*count)+3], F_SETFD, 0 );
execlp("ChildMain", "ChildMain", &cnt, NULL);
}
This doesn't scale to 10 processes though, so I'd probably use a buffer and just sprintf() into it.
Here is a small example on how to implement the suggestion in my comment:
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
int main()
{
/* Need two sets of pipes: one for child stdin, one for child stdout */
int pipefds1[2];
int pipefds2[2];
pipe(pipefds1);
pipe(pipefds2);
int rc = fork();
if (rc == -1)
perror("fork");
else if (rc == 0)
{
/* In child */
/* Close the old stdin and stdout */
close(STDIN_FILENO);
close(STDOUT_FILENO);
/* Create new stdin/stroud from the pipes */
dup2(pipefds1[0], STDIN_FILENO);
dup2(pipefds2[1], STDOUT_FILENO);
/* Close the unneeded pipe handles */
close(pipefds1[1]);
close(pipefds2[0]);
/* Now pass control to the new program */
execl("/bin/ls", "ls", "-l", "/", NULL);
}
else
{
/* In parent */
/* Close the uneeded pipe handles */
close(pipefds1[0]);
close(pipefds2[1]);
/* We want to use stdio functions */
FILE *fp = fdopen(pipefds2[0], "r");
/* Read all from the child */
char buffer[128];
while (fgets(buffer, sizeof(buffer), fp))
{
printf("Input from child: %s\n", buffer);
}
fclose(fp);
/* Wait for child to exit */
wait(NULL);
}
return 0;
}
Hopefully this will be enough for you to build on.
The error handling is non-existant, but it is tested.