The program uses pipes to manage multiple concurrent processes. When the program needs to write to pipe2
to then share it with the concurrent printToFile
process, it stops functioning correctly because when I read from pipe2
in printToFile
, nothing is read. The exact reason for this interruption is unclear, and further debugging is needed to identify the cause of this problem.
Through some debugging with various prints inserted here and there, I have been able to narrow down that the problem lies in the printToFile
function or at the end of the createTable
function when writing to pipe2[1]
in write mode.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <wchar.h>
#include <wctype.h>
#include <locale.h>
// Definition of the structure for an object containing a string, its frequency, and coordinates in the matrix
typedef struct {
wchar_t string[31];
float frequency;
int occurrence;
int x;
int y;
} Object;
// Definition of the structure for a matrix containing a list of objects and its dimensions
typedef struct {
Object** list;
int x;
int y;
} Matrix;
// Definition of the structure for the alphabet containing a sub-alphabet and a word
struct Alphabet {
struct Alphabet* subAlphabet[46];
Object *word;
};
// Definition of the type Dictionary as a pointer to struct Alphabet
typedef struct Alphabet Dictionary;
// Declaration of the recursive deallocation function
Dictionary* deallocate(Dictionary* dict);
int createTable(FILE* file, int index, Matrix* matrix, Dictionary* dict, int pipe1[], int pipe2[], wchar_t firstWord[]);
int asciiIndex(wchar_t character);
bool compareStrings(wchar_t* string1, wchar_t* string2);
bool operationalSearch(wchar_t string[], int index, Dictionary* dict, int i, int p, Matrix* m);
void readWordFromFile(FILE* file, int pipe1[], long int position);
void printToFile(FILE* sheet, int pipe2[], int MAX);
long int getFirstWord(FILE* file, Matrix* matrix);
int main() { // Declare the main function
setlocale(LC_ALL, "it_IT.UTF-8"); // Set a locale that supports Unicode
FILE* file = fopen("test.txt", "r");
FILE* sheet = fopen("output.csv", "w");
if (file == NULL || sheet == NULL) { // If either file does not open
exit(EXIT_FAILURE); // Exit with an error
}
Dictionary* dictionary = (Dictionary*)calloc(1, sizeof(Dictionary)); // Allocate the dictionary
dictionary->word = (Object*)calloc(1, sizeof(Object)); // Allocate a word in the dictionary
Matrix matrix; // Declare a matrix
matrix.list = (Object**)calloc(1, sizeof(Object*));
matrix.list[0] = (Object*)calloc(2, sizeof(Object));
long int position = getFirstWord(file, &matrix);
if (position == -1) {
exit(EXIT_FAILURE); // Exit with an error
}
int pipe1[2], pipe2[2]; // Declare two pipes
if (pipe(pipe1) == -1 || pipe(pipe2) == -1) { // If pipe creation fails
exit(EXIT_FAILURE); // Exit with an error
}
int MAX; // Maximum number of bytes to allocate in a row in the matrix
pid_t pid_Process1, pid_Process2, pid_Process3; // Declare the PIDs of the processes
pid_Process1 = fork(); // Create the first process
if (pid_Process1 == -1) { // If fork fails
perror("Fork error"); // Print an error
return 1; // Return 1
} else if (pid_Process1 == 0) { // If in the child process
close(pipe1[0]); // Close the read end of pipe1
readWordFromFile(file, pipe1, position); // Call the readWordFromFile function
exit(0); // Exit the process
} else { // If in the parent process
close(pipe1[1]); // Close the write end of pipe1
waitpid(pid_Process1, NULL, 0); // Wait for the termination of process 1
}
pid_Process2 = fork(); // Create the second process
if (pid_Process2 == -1) { // If fork fails
perror("Fork error"); // Print an error
return 1; // Return 1
} else if (pid_Process2 == 0) { // If in the child process
close(pipe2[0]); // Close the read end of pipe2
wchar_t firstWordArray[31]; // Ensure the size is sufficient
wcscpy(firstWordArray, matrix.list[0][0].string);
MAX = createTable(file, 0, &matrix, dictionary, pipe1, pipe2, firstWordArray); // Call the createTable function which returns the maximum number of bytes of the matrix rows
exit(0); // Exit the process
} else { // If in the parent process
close(pipe1[0]); // Close the read end of pipe1
close(pipe2[1]); // Close the write end of pipe2
waitpid(pid_Process2, NULL, 0); // Wait for the termination of process 2
}
pid_Process3 = fork(); // Create the third process
if (pid_Process3 == -1) { // If fork fails
perror("Fork error"); // Print an error
return 1; // Return 1
} else if (pid_Process3 == 0) { // If in the child process
close(pipe2[1]); // Close the write end of pipe2
printToFile(sheet, pipe2, MAX); // Call the printToFile function
close(pipe2[0]); // Close the read end of pipe2
exit(0); // Exit the process
}
waitpid(pid_Process3, NULL, 0); // Wait for the termination of process 3
wait(NULL); // Wait for the termination of all child processes
wait(NULL); // Wait for the termination of all child processes
wait(NULL); // Wait for the termination of all child processes
fclose(sheet); // Close the output file
fclose(file); // Close the input file
for (int i = 0; i < 46; i++) { // Free the memory of the dictionary
dictionary->subAlphabet[i] = deallocate(dictionary->subAlphabet[i]); // Call the deallocate function
}
free(dictionary->word); // Free the memory of the word
free(dictionary); // Free the memory of the dictionary
return 0; // Return 0
}
Dictionary* deallocate(Dictionary* dict) { // Declare the deallocation function
if (dict == NULL) { // If the dictionary is NULL
return NULL; // Return NULL
}
for (int i = 0; i < 46; i++) { // Iterate over the 46 elements of the sub-alphabet
dict->subAlphabet[i] = deallocate(dict->subAlphabet[i]); // Call the deallocation function recursively
}
free(dict->word); // Free the memory of the word
free(dict); // Free the memory of the dictionary
return NULL;
}
// Function to get the ASCII index of a character
int asciiIndex(wchar_t character) {
// Convert the character to lowercase
wchar_t c = towlower(character);
if (iswalpha(c)) {
// Handle non-accented letters
return c - L'a';
} else {
// Handle accented characters
switch (c) {
case L'à': return 26;
case L'è': return 27;
case L'é': return 28;
case L'ì': return 29;
case L'ò': return 30;
case L'ù': return 31;
case L'!': return 32;
case L'?': return 33;
case L'.': return 34;
case L''': return 35;
}
}
// Handle numbers
if (c >= L'0' && c <= L'9') {
return 36 + (c - L'0');
}
// Unrecognized character
return -1;
}
// Function to compare two strings
bool compareStrings(wchar_t* string1, wchar_t* string2) { // Declare the compareStrings function
if (*string1 == L'' && *string2 == L'') { // If both strings are terminated
return true; // Return true
}
if (*string1 == *string2 || (towlower((wchar_t)*string1) == towlower((wchar_t)*string2))) { // Check if the characters are equal or if they are equal in lowercase
return compareStrings(string1 + 1, string2 + 1); // Recursively call the function on the next character
}
return false; // If the characters are not equal, return false
}
// Function to find the first word in the file
long int getFirstWord(FILE* file, Matrix* matrix) {
char character;
const wchar_t* accentedCharacters = L"àèéìòóùÀÈÉÌÒÓÙ";
int index = 0; // Initialize the index to 0
long int pos = 0; // Initialize pos to 0
while ((character = fgetwc(file)) != WEOF) {
wchar_t next = fgetwc(file);
fseek(file, -1, SEEK_CUR);
if (character == L'n' || character == L' ') { // If the first characters are n or space, skip them
continue;
} else if (iswalnum(character) || (wcschr(accentedCharacters, character) != NULL)) { // If you find or when you find alphanumeric characters, then add to the matrix in the first position
matrix->list[0][0].string[index] = character;
index++;
if (next == L' ' || next == L'n' || next == L'!' || next == L'?' || next == L'.') { // If followed by space or newline, terminate the string
matrix->list[0][0].string[index] = L'';
return ftell(file);
} else if (next == L''') { // If followed by an apostrophe, append the apostrophe and terminate the string and the first word
matrix->list[0][0].string[index] = L''';
matrix->list[0][0].string[index + 1] = L'';
return ftell(file);
}
continue;
} else if (character == L'!' || character == L'?' || character == L'.') { // If you encounter special characters, add them to the matrix as separate characters
matrix->list[0][0].string[index] = character;
matrix->list[0][0].string[index + 1] = L'';
return ftell(file);
}
}
// If we reach here, it means we have reached the end of the file without finding a valid word
return -1; // Return -1 to indicate that a valid word was not found
}
// Function for operational search of a string in the matrix
bool operationalSearch(wchar_t string[], int index, Dictionary* dict, int i, int p, Matrix* m) { // Declare the operationalSearch function
Dictionary* currentDict = dict; // Initialize currentDict with dict
int ASCII; // Declare the ASCII variable
if (string[index] == '') { // If the current character is the string terminator
if (compareStrings(currentDict->word->string, m->list[i][0].string)) { // If the string of the dictionary word is equal to the matrix string
int n = 1; // Initialize n to 1
int y = currentDict->word->y; // Assign the y coordinate of the dictionary word to y
int x = currentDict->word->x; // Assign the x coordinate of the dictionary word to x
int found = 0; // Initialize found to 0
m->list[y][0].occurrence++; // Increment the occurrence of the word in the matrix
while (n <= m->x && m->list[y][n].x == n) { // As long as n is less than or equal to the x dimension of the matrix and the matrix element is equal to n
if (compareStrings(m->list[y][n].string, m->list[i][p].string)) { // If the current string is equal to the matrix string
m->list[y][n].occurrence++; // Increment the occurrence
m->list[y][n].frequency = (float)m->list[y][n].occurrence / (float)m->list[y][0].occurrence; // Calculate the frequency
found = 1; // Set found to 1
}
m->list[y][n].frequency = (float)m->list[y][n].occurrence / (float)m->list[y][0].occurrence; // Calculate the frequency
n++; // Increment n
}
if (!found) { // If the string was not found
if (n > m->x) { // If n is greater than the x dimension of the matrix
m->x = n; // Assign n to x
}
m->list[y] = realloc(m->list[y], (n + 1) * sizeof(Object)); // Reallocate memory for the row of the matrix
wcscpy(m->list[y][n].string, m->list[i][p].string); // Copy the string to the matrix
m->list[y][n].occurrence = 1; // Initialize the occurrence to 1
m->list[y][n].frequency = (float)m->list[y][n].occurrence / (float)m->list[y][0].occurrence; // Calculate the frequency
m->list[y][n].x = n; // Assign n to the x coordinate
}
return true; // Return true
}
wcscpy(currentDict->word->string, string); // Copy the string to the dictionary word
currentDict->word->x = p; // Assign p to the x coordinate of the word
currentDict->word->y = i; // Assign i to the y coordinate of the word
m->list[i][1].x = 1; // Assign 1 to the x coordinate of the matrix
m->list[i][0].x = 0; // Assign 0 to the x coordinate of the matrix
m->list[i][1].occurrence = 1; // Initialize the occurrence to 1
m->list[i][0].occurrence = 1; // Initialize the occurrence to 1
m->list[i][1].frequency = (float)m->list[i][1].occurrence / (float)m->list[i][0].occurrence; // Calculate the frequency
return false; // Return false
}
ASCII = asciiIndex(string[index]); // Calculate the ASCII index of the current character
if (currentDict->subAlphabet[ASCII] == NULL) { // If the current sub-alphabet is NULL
currentDict->subAlphabet[ASCII] = (Dictionary*)calloc(1, sizeof(Dictionary)); // Allocate memory for the sub-alphabet
if (currentDict->subAlphabet[ASCII] == NULL) { // If the memory was not allocated
exit(1); // Exit with an error
}
currentDict->subAlphabet[ASCII]->word = (Object*)calloc(1, sizeof(Object)); // Allocate memory for the sub-alphabet word
if (currentDict->subAlphabet[ASCII]->word == NULL) { // If the memory was not allocated
exit(1); // Exit with an error
}
}
currentDict = currentDict->subAlphabet[ASCII]; // Assign the current sub-alphabet to currentDict
return operationalSearch(string, index + 1, currentDict, i, p, m); // Recursively call the function
}
// Function to handle the end of a string
int createTable(FILE* file, int index, Matrix* matrix, Dictionary* dict, int pipe1[], int pipe2[], wchar_t firstWord[]) { // Declare the createTable function
wchar_t string1[31]; // Declare a string of 31 characters
matrix->x = 1; // Initialize the x dimension to 1
matrix->y = 1; // Initialize the y dimension to 1
matrix->list = NULL; // Initialize the list to NULL
matrix->list = (Object**)calloc(1, matrix->y * sizeof(Object*)); // Allocate memory for the matrix
matrix->list[matrix->y - 1] = (Object*)calloc(1, 2 * sizeof(Object)); // Allocate memory for a row of the matrix
wcscpy(matrix->list[0][0].string, firstWord); // Copy the first word to the matrix
// Read all words from pipe1 before writing to pipe2
while (read(pipe1[0], &string1, sizeof(string1)) > 0) { // Read all words from pipe1
if (string1[0] == '') { // If the string is empty
break; // Exit the loop
}
// Add words as values to the Matrix data structure
wcscpy(matrix->list[matrix->y - 1][1].string, string1); // Copy the string to the matrix
matrix->list[matrix->y - 1][1].x = 1; // Assign 1 to the x coordinate
matrix->list[matrix->y - 1][0].x = 0; // Assign 0 to the x coordinate
int control = operationalSearch(matrix->list[matrix->y - 1][0].string, 0, dict, matrix->y - 1, 1, matrix); // Call the operationalSearch function
if (control == 0) { // If control is 0
matrix->y++; // Increment the y dimension
matrix->list = realloc(matrix->list, matrix->y * sizeof(Object*)); // Reallocate memory for the matrix
matrix->list[matrix->y - 1] = (Object*)calloc(1, 2 * sizeof(Object)); // Allocate memory for a new row
}
wcscpy(matrix->list[matrix->y - 1][0].string, string1); // Copy the string to the matrix
string1[0] = ''; // Reset the string
}
// Handle the end
wcscpy(matrix->list[matrix->y - 1][1].string, matrix->list[0][0].string); // Copy the first word to the last row
int control = operationalSearch(matrix->list[matrix->y - 1][0].string, 0, dict, matrix->y - 1, 1, matrix); // Call the operationalSearch function
if (control == 0) { // If control is 0
matrix->y++; // Increment the y dimension
}
close(pipe1[0]); // Close pipe1
int rowDim = 31; // Minimum dimension of each row
int maxDim = 31; // Maximum dimension that a row in the matrix can assume
// Write the rows of the matrix to pipe2
for (int i = 0; i < matrix->y - 1; i++) { // Write the rows of the matrix to pipe2
wchar_t* row = calloc(1, rowDim * sizeof(wchar_t)); // Buffer to store the string representation of the row, dynamically allocated
int occurrences = 0; // Occurrence counter
swprintf(row, rowDim, L"%ls", matrix->list[i][0].string);
for (int j = 1; j < matrix->x + 1; j++) { // Iterate over the columns
if (occurrences == matrix->list[i][0].occurrence) { // If occurrences are equal
break; // Exit the loop
}
occurrences = occurrences + matrix->list[i][j].occurrence; // Increment occurrences
int increment = wcslen(matrix->list[i][j].string) + 6; // Calculate the increment in bytes to add each time
rowDim += increment; // Add to the dimension of that row
if (rowDim > maxDim) { // Check if this corresponds to the maximum dimension of the longest row in the matrix
maxDim = rowDim; // If so, assign that value
}
row = realloc(row, rowDim * sizeof(wchar_t)); // Extend the row buffer by reallocating it
swprintf(row + wcslen(row), rowDim - wcslen(row), L",%ls,%.4f", matrix->list[i][j].string, matrix->list[i][j].frequency); // Add the string and the frequency
}
if ((i + 1) != matrix->y - 1) { // If it is not the last row
swprintf(row + wcslen(row), rowDim - wcslen(row), L"%ls", L"n"); // Add a new line
}
wprintf(L"%ls", row);
write(pipe2[1], row, sizeof(row)); // Write the string representation of the row to pipe2
}
close(pipe2[1]); // Close pipe2
return maxDim; // Return maxDim
}
void printToFile(FILE* sheet, int pipe2[], int MAX) { // Declare the printToFile function
close(pipe2[1]); // Close the write end of pipe2
wchar_t row[MAX]; // Declare a buffer for the row with a byte dimension equal to the maximum dimension of the longest row in the matrix
while (read(pipe2[0], row, sizeof(row)) > 0) { // Read from pipe2
fwprintf(sheet, L"%ls", row); // Write the row to the file
}
}
// Function to read the input file
void readWordFromFile(FILE* file, int pipe1[], long int position) {
wchar_t string1[31];
int index = 0;
wchar_t character;
const wchar_t* accentedCharacters = L"àèéìòóùÀÈÉÌÒÓÙ";
fseek(file, position, SEEK_SET);
while ((character = fgetwc(file)) != WEOF) {
wchar_t next = fgetwc(file);
fseek(file, -1, SEEK_CUR);
if ((character == L' ' || character == L'n') && next == WEOF) {
// Handle the case where the last character is a space or newline
if (index > 0) {
string1[index] = L'';
write(pipe1[1], string1, sizeof(string1));
}
break;
}
if (character == L'!' || character == L'?' || character == L'.') {
if (index > 0) {
string1[index] = L'';
write(pipe1[1], string1, sizeof(string1));
index = 0;
}
string1[0] = character;
string1[1] = L'';
write(pipe1[1], string1, sizeof(string1));
if (next == WEOF) {
break;
}
} else if (iswalnum(character) || (wcschr(accentedCharacters, character) != NULL) || character == L''') {
string1[index++] = character;
if (next == L' ' || next == L'n' || next == WEOF ||
next == L'!' || next == L'?' || next == L'.' || character == L''') {
string1[index] = L'';
write(pipe1[1], string1, sizeof(string1));
index = 0;
}
} else if (character == L' ' || character == L'n') {
if (index > 0) {
string1[index] = L'';
write(pipe1[1], string1, sizeof(string1));
index = 0;
}
} else if (!(iswalnum(character) || (wcschr(accentedCharacters, character) != NULL) ||
character == L''' || character == L'!' ||
character == L'?' || character == L'.') &&
(next == L' ' || next == L'n')) {
if (index > 0) {
string1[index] = L'';
write(pipe1[1], string1, sizeof(string1));
index = 0;
}
continue;
}
if (next == WEOF) {
break;
}
}
close(pipe1[1]);
}
I tried using pipes to manage communication between multiple concurrent processes in a C program. Specifically, I expected the printToFile
function to read data written by the createTable
function through pipe2
, but it failed to read anything. Further debugging is needed to identify the exact cause of this issue.