To start off with this is a homework assignment for my Operating Systems course and I am stumped.

The prof wants us to read in a source code file and take out all the comment lines and then output the file back into a new source code file.

We can only use unbuffered input and output using the read() and write() commands. The only problems are that 1) I am getting caught when trying to get the process ID when I am trying to do parallel processes and I am not sure how to take certain characters out of the buffer or at least keep them from getting into the buffer in the first place.

Here is my source code. If you have any questions please ask and I will try to answer as best as I can. The openFilesSequential function is left blank on purpose because I have not gotten to it yet.

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>

#define READ_FLAGS O_RDONLY
#define WRITE_FLAGS (O_WRONLY | O_CREAT | O_EXCL)
#define WRITE_PERMS (S_IRUSR | S_IWUSR)

#define BUFFER_SIZE 200

// Function Prototypes
void displayUsageMessage(void);
void openFilesSequential(int argc, char *argv[]);
void openFilesParallel(int argc, char *argv[]);

//#######################################################################
int main(int argc, char *argv[])
{
	int i;
	
	if(argc < 2)
	{
		displayUsageMessage();
		return 1;
	} // End if
	else
	{
		if(strncmp(argv[1], "-s", 2) == 0)
		{
			openFilesSequential(argc, argv);
		} // End if
		else if(strncmp(argv[1], "-p", 2) == 0)
		{
			openFilesParallel(argc, argv);
		} // End else if
		else
		{
			printf("get here");
			displayUsageMessage();
		} // End else
	} // End else
	
	return 0;
	
} // End main

//########################################################################
void displayUsageMessage(void)
{
	perror("Usage: a.exe {-s | -p} <file_name> [<file_name> ...]");
} // End displayUsageMessage

//########################################################################
void openFilesSequential(int argc, char *argv[])
{
		
} // End openFilesSequential

//#########################################################################
void openFilesParallel(int argc, char *argv[])
{
	pid_t childpid = 0;
	int i, nbrOfFiles;
	char inputFileName[20];
	char outputFileName[20];
	
	nbrOfFiles = argc - 2;
	
	
	for(i = 0; i < nbrOfFiles; i++)
	{
		strcpy(inputFileName, argv[2+i]);
		strcpy(outputFileName, "nc-");
		strncat(outputFileName, inputFileName, 20);
		
		childpid = fork();
		if(childpid == -1)
		{
			perror("Fork failed");
			exit(1);
		}// End if
		else if(childpid == 0)
		{
			printf("\n\n(%6ld) Reading from %s and writing to %s ...\n", getpid(), inputFileName, outputFileName);
			removeComments(i+2, argv, inputFileName, outputFileName);
			exit(0);
		}// End else if
		else
		{
			exit(0);
		}
	} // End for
		
} // End openFilesParallel
		
//##########################################################################
int removeComments(int fileNum, char *argv[], char *inputFile, char *outputFile)
{
	char myBuffer[BUFFER_SIZE];
	
	int bufferIndex = 0;
	int returnValue;
	ssize_t bytesRead;
	
	while(bufferIndex < BUFFER_SIZE - 1)
	{
		returnValue = read(argv[fileNum], myBuffer + bufferIndex, 1);
		
		if(returnValue == -1)
		{
			return -1;
		} // End if
		
		if(returnValue == 0)
		{
			if(bufferIndex == 0)
			{
				return 0;
			} // End if
			else
			{
				errno = EINVAL;
				return -1;
			} // End else
		} // End if
		
		bufferIndex++;
		
		if(myBuffer[bufferIndex - 1] == '\n')
		{
			myBuffer[bufferIndex] == '\0';
			return bufferIndex;
		} // End if
	} // End while
	
	bytesRead = returnValue;
	if(bytesRead < 201)
	{
		write(outputFile, myBuffer, bytesRead);
	}
	
	errno = EINVAL;
	return -1;
	
		
	
	
} // End removeComments

Thank you

Recommended Answers

All 18 Replies

The only problems are that 1) I am getting caught when trying to get the process ID ...

Can you explain what you meant by getting caught?

By getting caught I mean that it outputs what I want it to but instead of going past that or going to the command line again the cursor sits there like it is waiting for some kind of input. If I hit enter than it goes back to the command line but doesn't get any further into the program. It might be the way I coded it, accidentally, but that isn't what I want it to do.

By getting caught I mean that it outputs what I want it to but instead of going past that or going to the command line again the cursor sits there like it is waiting for some kind of input. If I hit enter than it goes back to the command line but doesn't get any further into the program. It might be the way I coded it, accidentally, but that isn't what I want it to do.

Ok. I don't know why exactly this is, but I think you should wait for your child processes to finish before exiting the parent process. May be that's what's causing it. See wait().

Secondly I think instead of reading the whole input file one character at a time and trying to filter out the comments and writing the whole buffer out to the file, I have a feeling that your professor wants you to read one character from the input file and output it, while changing your state from "outputting" to "not outputting" if you encounter comment characters (// or /*). When you encounter comment characters you stop outputting the characters until you get to either \n (for // case) or */ (for /* case).

Hope this helps.

OK. I changed up my code:

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>

#define READ_FLAGS O_RDONLY
#define WRITE_FLAGS (O_WRONLY | O_CREAT | O_EXCL)
#define WRITE_PERMS (S_IRUSR | S_IWUSR)

#define BUFFER_SIZE 200

// Function Prototypes
void displayUsageMessage(void);
void openFilesSequential(int argc, char *argv[]);
void openFilesParallel(int argc, char *argv[]);

//#######################################################################
int main(int argc, char *argv[])
{
	int i;
	
	if(argc < 2)
	{
		displayUsageMessage();
		return 1;
	} // End if
	else
	{
		if(strncmp(argv[1], "-s", 2) == 0)
		{
			openFilesSequential(argc, argv);
		} // End if
		else if(strncmp(argv[1], "-p", 2) == 0)
		{
			openFilesParallel(argc, argv);
		} // End else if
		else
		{
			printf("get here");
			displayUsageMessage();
		} // End else
	} // End else
	
	return 0;
	
} // End main

//########################################################################
void displayUsageMessage(void)
{
	perror("Usage: a.exe {-s | -p} <file_name> [<file_name> ...]");
} // End displayUsageMessage

//########################################################################
void openFilesSequential(int argc, char *argv[])
{
	int i, nbrOfFiles;
	char inputFileName[20];
	char outputFileName[20];
	
	for(i = 0; i < nbrOfFiles; i++)
	{
		strcpy(inputFileName, argv[2+i]);
		strcpy(outputFileName, "nc-");
		strncat(outputFileName, inputFileName, 20);
		
		removeComments(i+2, argv, inputFileName,outputFileName);
	} // End for
	
} // End openFilesSequential

//#########################################################################
void openFilesParallel(int argc, char *argv[])
{
	pid_t childpid = 0;
	int i, nbrOfFiles;
	char inputFileName[20];
	char outputFileName[20];
	
	nbrOfFiles = argc - 2;
	
	
	for(i = 0; i < nbrOfFiles; i++)
	{
		strcpy(inputFileName, argv[2+i]);
		strcpy(outputFileName, "nc-");
		strncat(outputFileName, inputFileName, 20);
		
		childpid = fork();
		if(childpid == -1)
		{
			perror("Fork failed");
			exit(1);
		}// End if
		else if(childpid == 0)
		{
			printf("\n\n(%6ld) Reading from %s and writing to %s ...\n", getpid(), inputFileName, outputFileName);
			removeComments(i+2, argv, inputFileName, outputFileName);
			wait(childpid);
		}// End else if
		else
		{
			wait(childpid);
		}
	} // End for
		
} // End openFilesParallel
		
//##########################################################################
int removeComments(int fileNum, char *argv[], char *inputFile, char *outputFile)
{
	char myBuffer[BUFFER_SIZE];
	
	int bufferIndex = 0;
	int returnValue;
	ssize_t bytesRead;
	
	while(bufferIndex < BUFFER_SIZE - 1)
	{
		returnValue = read(inputFile, myBuffer + bufferIndex, 1);
		
		if(returnValue == -1)
		{
			return -1;
		} // End if
		
		if(returnValue == 0)
		{
			if(bufferIndex == 0)
			{
				return 0;
			} // End if
			else
			{
				errno = EINVAL;
				return -1;
			} // End else
		} // End if
		
		if(myBuffer[bufferIndex] != '/')
		{
			write(outputFile, myBuffer, 1);
		}
		else if(myBuffer[bufferIndex] == '/' && myBuffer[bufferIndex-1] != '/')
		{
			write(outputFile, myBuffer, 1);
		}
		else
		{
			bufferIndex++;
		}
	}
} // End removeComments

Now I am getting these error message when I compile it:
lindow6.c: In function 'openFilesParallel':
lindow6.c:104: warning: passing arg 1 of 'wait' makes pointer from integer without a cast
lindow6.c:108: warning: passing arg 1 of 'wait' makes pointer from integer without a cast
lindow6.c: In function 'removeComments':
lindow6.c:125: warning: passing arg 1 of 'read' makes integer from pointer without a cast
lindow6.c:147: warning: passing arg 1 of 'write' makes integer from pointer without a cast
lindow6.c:151: warning: passing arg 1 of 'write' makes integer from pointer without a cast
lindow6.c:174:2: warning: no newline at end of file

and when I run the program it gives me these error messages:
2 [main] a 4404 _cygtls::handle_exceptions: Exception: STATUS_ACCESS_VIOLATION
1386 [main] a 4404 open_stackdumpfile: Dumping stack trace to a.exe.stackdump

I am no idea what I am doing wrong for it to throw up the warnings and have no idea what the runtime errors mean.

Do you have access to man or info?

I am sorry but could you restate that question please?

The input from the command line should be, after the program has compiled....

>a.exe {either -s or -p} <file_name>

and then can put in more than one filename

I hope this answers your question.

I'm assuming your running some version of Linux, right?

If you are then open a terminal window and type 'man 2 wait'
It should display something like below

WAIT(2) Linux Programmer's Manual WAIT(2)

NAME
wait, waitpid, waitid - wait for process to change state

SYNOPSIS
#include <sys/types.h>
#include <sys/wait.h>

pid_t wait(int *status);

pid_t waitpid(pid_t pid, int *status, int options);

int waitid(idtype_t idtype, id_t id, siginfo_t *infop, int options);

Now while still in the terminal scroll down until you see the example code...It will be towards the bottom

wait() takes an integer pointer and returns the exit status of the child process in it. It returns the child process id by name. You are passing pid_t childpid instead of int *. It is giving warnings at compile time and then it is crashing because it is treating it as an address.

Define a dummy variable, int returnStatus, and call

wait(&returnStatus);

Ignore the return value. Also you will have to enclose the above wait() call in a loop to wait for all the children.

And child processes do not need to wait.

Hope this helps.

OK I got that but I am still getting the warnings that I posted above. I think I am calling what I am wanting (inputFileName and outputFileName) incorrectly but I am not sure what it is wanting.

Unfortunately, I am not using Linux. I am using Windows 7 and using Cygwin to compile. The professor wanted us to use a UNIX environment and since I am using Windows I have to use CYGWIN to get what he wants.

Warnings on 104 and 108 should be gone. For the rest of the warnings, you need to cast the buffer with (void *) since read and write expect a void *

OK fixed all the compiling errors. Now I just have the STATUS_ACCESS_VIOLATION error messages to fix.

here is my new function:

int removeComments(int fileNum, char *argv[], char *inputFile, char *outputFile)
{
	char myBuffer[BUFFER_SIZE];
	
	int bufferIndex = 0;
	int returnValue;
	ssize_t bytesRead;
	
	while(bufferIndex < BUFFER_SIZE - 1)
	{
		returnValue = read(*inputFile, myBuffer + bufferIndex, 1);
		
		if(returnValue == -1)
		{
			return -1;
		} // End if
		
		if(returnValue == 0)
		{
			if(bufferIndex == 0)
			{
				return 0;
			} // End if
			else
			{
				errno = EINVAL;
				return -1;
			} // End else
		} // End if
		
		if(myBuffer[bufferIndex] != '/')
		{
			write(*outputFile, myBuffer, 1);
		}
		else if(myBuffer[bufferIndex] == '/' && myBuffer[bufferIndex-1] != '/')
		{
			write(*outputFile, myBuffer, 1);
		}
		else
		{
			bufferIndex++;
		}
	}
} // End removeComments

Did you remove wait() call from the child processes part of the code (after removeComments() call)? The children don't need to wait .

Yes I did.

Ok I looked at your removeComments() code closely and are you saying that the last code you posted is compiling without errors. The syntax of read() is as follows: ssize_t read(int fd, void *buf, size_t count); The first argument is the file descriptor. It is returned by open() so you need to open the file first. Instead you are passing the file name directly to read().

Here is the syntax of open:

http://linux.die.net/man/2/open

The same thing for write().

Also you haven't type cast the buffer to (void *) either. How you got rid of warnings and how it is compiling at all since you are passing char* instead of int in the first argument.

OK been making some changes while I have been on here. Here is the new code and I do not get any warnings but I still get the STATUS_ACCESS_VIOLATION error message (which I have no idea what those mean):

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>

#define READ_FLAGS O_RDONLY
#define WRITE_FLAGS (O_WRONLY | O_CREAT | O_EXCL)
#define WRITE_PERMS (S_IRUSR | S_IWUSR)

#define BUFFER_SIZE 200

// Function Prototypes
void displayUsageMessage(void);
void openFilesSequential(int argc, char *argv[]);
void openFilesParallel(int argc, char *argv[]);
int removeComments(int fileNum, char *argv[], char *inputFile, char *outputFile);

//#######################################################################
int main(int argc, char *argv[])
{
	int i;
	
	if(argc < 2)
	{
		displayUsageMessage();
		return 1;
	} // End if
	else
	{
		if(strncmp(argv[1], "-s", 2) == 0)
		{
			openFilesSequential(argc, argv);
		} // End if
		else if(strncmp(argv[1], "-p", 2) == 0)
		{
			openFilesParallel(argc, argv);
		} // End else if
		else
		{
			printf("get here");
			displayUsageMessage();
		} // End else
	} // End else
	
	return 0;
	
} // End main

//########################################################################
void displayUsageMessage(void)
{
	perror("Usage: a.exe {-s | -p} <file_name> [<file_name> ...]");
} // End displayUsageMessage

//########################################################################
void openFilesSequential(int argc, char *argv[])
{
	int i, nbrOfFiles;
	char inputFileName[20];
	char outputFileName[20];
	int fromFile;
	int toFile;
	
	for(i = 0; i < nbrOfFiles; i++)
	{
		strcpy(inputFileName, argv[2+i]);
		strcpy(outputFileName, "nc-");
		strncat(outputFileName, inputFileName, 20);
		
		removeComments(i+2, argv, inputFileName,outputFileName);
	} // End for
	
} // End openFilesSequential

//#########################################################################
void openFilesParallel(int argc, char *argv[])
{
	pid_t childpid = 0;
	int i, nbrOfFiles;
	char inputFileName[20];
	char outputFileName[20];
	int status;
	int fromFile;
	int toFile;
	
	nbrOfFiles = argc - 2;
	
	
	for(i = 0; i < nbrOfFiles; i++)
	{
		strcpy(inputFileName, argv[2+i]);
		strcpy(outputFileName, "nc-");
		strncat(outputFileName, inputFileName, 20);
		
		childpid = fork();
		if(childpid == -1)
		{
			perror("Fork failed");
			exit(1);
		}// End if
		else if(childpid == 0)
		{
			printf("\n\n(%6ld) Reading from %s and writing to %s ...\n", getpid(), inputFileName, outputFileName);
			fromFile = open(argv[i+2], READ_FLAGS);
			if(fromFile == -1)
			{
				perror("Failed to open input file");
				exit(0);
			}
			toFile = open(outputFileName, WRITE_FLAGS, WRITE_PERMS);
			if(toFile == -1)
			{
				perror("Failed to create output file");
				exit(0);
			}
			
			removeComments(i+2, argv, inputFileName, outputFileName);
			
			close(fromFile);
			close(toFile);
		}// End else if
		else
		{
			wait(&status);
		}
	} // End for
		
} // End openFilesParallel
		
//##########################################################################
int removeComments(int fileNum, char *argv[], char *inputFile, char *outputFile)
{
	char myBuffer[BUFFER_SIZE];
	
	int bufferIndex = 0;
	int returnValue;
	ssize_t bytesRead;
	
	while(bufferIndex < BUFFER_SIZE - 1)
	{
		returnValue = read(*inputFile, myBuffer + bufferIndex, 1);
		
		if(returnValue == -1)
		{
			return -1;
		} // End if
		
		if(returnValue == 0)
		{
			if(bufferIndex == 0)
			{
				return 0;
			} // End if
			else
			{
				errno = EINVAL;
				return -1;
			} // End else
		} // End if
		
		if(myBuffer[bufferIndex] != '/')
		{
			write(*outputFile, myBuffer, 1);
		}
		else if(myBuffer[bufferIndex] == '/' && myBuffer[bufferIndex-1] != '/')
		{
			write(*outputFile, myBuffer, 1);
		}
		else if(myBuffer[bufferIndex] == '/' && myBuffer[bufferIndex-1] == '/')
		{
			do
			{
				bufferIndex++;
			} while(myBuffer[bufferIndex] != '\n');
			
			if(myBuffer[bufferIndex-1] == '\n')
			{
				myBuffer[bufferIndex] = '\0';
			}
		}
		else if(myBuffer[bufferIndex] =='\n')
		{	
			myBuffer[bufferIndex] = '\0';
		}
		bufferIndex++;
	}
} // End removeComments

Unfortunately, I am not using Linux. I am using Windows 7 and using Cygwin to compile. The professor wanted us to use a UNIX environment and since I am using Windows I have to use CYGWIN to get what he wants.

Here's the web site for man wait

http://linux.die.net/man/2/wait

You are now opening the files but you are still not using the file descriptors returned by open(). You still continue to use the file names as the first parameter to read() and write() whereas it expects the file descriptor. You should actually open the files inside removeComments() and use the file descriptors returned by the two opens, namely fromFile and toFile as the first parameter to read() and write() respectively instead of the file names.

Also the parent needs to wait on all the children. In other words you will have to put the wait(&status) in a loop that runs as many times as their are children. Right now it will exit as soon as the first child exits.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.