Answered step by step
Verified Expert Solution
Link Copied!

Question

1 Approved Answer

CSC 376: Distributed Systems Last Modified 2019 September 19 Purpose: To go over multiprocessing on a single machine: pipes/socket pairs fork()/execl() Overview: enscript is a

CSC 376: Distributed Systems

Last Modified 2019 September 19

Purpose:

To go over multiprocessing on a single machine:

  • pipes/socket pairs
  • fork()/execl()

Overview:

enscript is a program that does several things, including creating Postscript files out of text files. ps2pdf converts Postscript files to PDF files. We will use them both to get a simple word-processor to "print" its text into the PDF file PDF_FILENAME (print.pdf).

Computing

Please ssh into one of the following: or use your own Linux machine.

Please submit your finished program

  1. Please copy-and-paste the following files (0 Points):

    cheapWordProc.c

    /*-------------------------------------------------------------------------* *--- ---* *--- wordProc_print.c ---* *--- ---* *--- A lame attempt at a word processor. ---* *--- ---* *--- ---- ---- ---- ---- ---- ---- ---- ---- ---* *--- ---* *--- Version 1a 2019 April 10 Joseph Phillips ---* *--- ---* *-------------------------------------------------------------------------*/ // // Compile with: // $ g++ wordProc_print.c -o wordProc_print -lncurses -g // // NOTE: // If this program crashes then you may not see what you type. // If that happens, just type: // // stty sane // // to your terminal, even though you cannot even see it. //--- ---// //--- Header file inclusions: ---// //--- ---// #include  #include  #include  #include  // For alarm() #include  #include  // For creat() #include  // For creat(), wait() #include  // For creat() #include  // For creat() #include  #include  //--- ---// //--- Definitions of constants: ---// //--- ---// #define SPELL_PROGRAM "/usr/bin/hunspell" #define SPELL_ARG1 "-d" #define SPELL_ARG2 "en_US" #define STOP_CHARS "*+-#&" #define PDF_FILENAME "print.pdf" #define TEXT_FILENAME "print.txt" const int HEIGHT = 5; const int WIDTH = 64; const int INIT_TEXT_LEN = 1024; const int MAX_TEXT_LEN = 65536; const char STOP_CHAR = (char)27; const char PRINT_CHAR = (char)0x10; const int BUFFER_LEN = 64 * 16; const int TYPING_WINDOW_BAR_Y = 0; const int CHECKING_WINDOW_BAR_Y = TYPING_WINDOW_BAR_Y + HEIGHT + 1; const int MESSAGE_WINDOW_BAR_Y = CHECKING_WINDOW_BAR_Y + HEIGHT + 1; const int NUM_MESSAGE_SECS = 4; //--- ---// //--- Definitions of global vars: ---// //--- ---// WINDOW* typingWindow; WINDOW* checkingWindow; WINDOW* messageWindow; pid_t childPid; int shouldRun = 1; //--- ---// //--- Definitions of global fncs: ---// //--- ---// // PURPOSE: To turn 'ncurses' on. No parameters. No return value. void onNCurses () { // I. Application validity check: // II. Turn 'ncurses' on: const int LINE_LEN = 80; char line[LINE_LEN]; initscr(); cbreak(); noecho(); nonl(); //intrflush(stdscr, FALSE); //keypad(stdscr, TRUE); typingWindow = newwin(HEIGHT,WIDTH,TYPING_WINDOW_BAR_Y+1,1); checkingWindow = newwin(HEIGHT,WIDTH,CHECKING_WINDOW_BAR_Y+1,1); messageWindow = newwin( 1,WIDTH,MESSAGE_WINDOW_BAR_Y,1); scrollok(typingWindow,TRUE); scrollok(checkingWindow,TRUE); snprintf(line,LINE_LEN,"'Esc' to quit. Ctrl-P to print to '%s'",PDF_FILENAME); mvaddstr(TYPING_WINDOW_BAR_Y,0,line); mvaddstr(CHECKING_WINDOW_BAR_Y,0,"Misspelling and suggested corrections:"); refresh(); wrefresh(typingWindow); // moves cursor back to 'typingWindow': // III. Finished: } // PURPOSE: To handle 'SIGALRM' signals. Ignores 'sig' (which will be // 'SIGALRM'). No return value. void sigAlarmHandler (int sig ) { mvwaddstr (messageWindow,0,0," "); wrefresh(messageWindow); wrefresh(typingWindow); // moves cursor back to 'typingWindow': } // PURPOSE: To save the 'lineIndex' chars at the beginning of 'line' to // to position '*endTextPtrPtr' in buffer '*bufferPtrPtr' of length // '*bufferLenPtr' and with end '*endBufferPtrPtr'. If there is not // enough space in '*bufferPtrPtr' then '*bufferLenPtr' will be doubled, // and '*bufferPtrPtr' will be 'realloc()'-ed to this new length. // No return value. void saveLine (size_t* bufferLenPtr, char** bufferPtrPtr, char** endTextPtrPtr, char** endBufferPtrPtr, const char* line, int lineIndex ) { // I. Application validity check: // II. Save 'line' to '*bufferPtrPtr': // II.A. Allocate more space if needed: if (lineIndex >= (*endBufferPtrPtr - *endTextPtrPtr + 1) ) { size_t textLen = *endTextPtrPtr - *bufferPtrPtr; (*bufferLenPtr) *= 2; (*bufferPtrPtr) = (char*)realloc(*bufferPtrPtr,*bufferLenPtr); (*endTextPtrPtr) = *bufferPtrPtr + textLen; (*endBufferPtrPtr) = *bufferPtrPtr + *bufferLenPtr; } // II.B. Save 'line' to '*bufferPtrPtr': memcpy(*endTextPtrPtr,line,lineIndex); (*endTextPtrPtr) += lineIndex; // III. Finished: } // PURPOSE: To attempt to write the text pointed to by 'bufferPtr' to a PDF // file named 'PDF_FILENAME'. 'endTextPtr' points to one char beyond // the end of the text to print in 'bufferPtr'. No return value. // // SIDE EFFECT: Prints to 'messageWindow' and sets process to receive // 'SIGALRM' 'NUM_MESSAGE_SECS' seconds in the future. // This will invoke 'sigAlarmHandler()', which erases the // text in 'messageWindow'. void printPdf (const char* bufferPtr, const char* endTextPtr ) { // I. Application validity check: // II. Print as .pdf: // II.A. Create pipes or socket-pairs: // YOUR CODE HERE // II.B. Do 'enscript' process work: // YOUR CODE HERE // II.C. Do 'ps2pdf' process work: // YOUR CODE HERE // II.D. Do parent process work: int status0; int status1; const char* msgCPtr = NULL; // YOUR CODE HERE if ( WIFEXITED(status0) && (WEXITSTATUS(status0) == EXIT_SUCCESS) && WIFEXITED(status1) && (WEXITSTATUS(status1) == EXIT_SUCCESS) ) { msgCPtr = "Printing succeeded"; } else { msgCPtr = "Printing failed"; } mvwaddstr(messageWindow,0,0,msgCPtr); wrefresh(messageWindow); wrefresh(typingWindow); // moves cursor back to 'typingWindow': alarm(NUM_MESSAGE_SECS); // III. Finished: } // PURPOSE: To allow the user to type, display what they type in // 'typingWindow', and to send what they type to the spell checking // process upon pressing 'Enter'. 'vPtr' comes in, perhaps pointing // to something. Returns 'NULL'. void* type (void* vPtr ) { // I. Application validity check: // II. Handle user typing: unsigned int c; char line[WIDTH+1]; int index = 0; size_t bufferLen = INIT_TEXT_LEN; char* bufferPtr = (char*)malloc(bufferLen); char* endTextPtr = bufferPtr; char* endBufferPtr = bufferPtr + bufferLen; // II.A. Each iteration handles another typed char: while ( (c = getch()) != STOP_CHAR ) { // II.A.1. Handle special chars: if (c == ' ') { // II.A.1.a. Treat carriage return like newline: c = ' '; } else if ( (c == 0x7) || (c == 127) ) { // II.A.1.b. Handle backspace: int col = getcurx(typingWindow); if (col > 0) { index--; wmove(typingWindow,getcury(typingWindow),col-1); wrefresh(typingWindow); } continue; } else if (c == PRINT_CHAR) { size_t textLen = endTextPtr - bufferPtr; saveLine(&bufferLen,&bufferPtr,&endTextPtr,&endBufferPtr,line,index); printPdf(bufferPtr,endTextPtr); endTextPtr = bufferPtr + textLen; continue; } else if (c == ERR) { continue; } // II.A.2. Print and record the char: waddch(typingWindow,c); wrefresh(typingWindow); line[index++] = c; // II.A.3. Handle when save 'line': if (c == ' ') { // II.A.3.a. Save 'line' when user types newline: saveLine(&bufferLen,&bufferPtr,&endTextPtr,&endBufferPtr,line,index); index = 0; } else if (index == WIDTH-1) { // II.A.3.b. Save 'line' when at last column: line[index] = ' '; index++; saveLine(&bufferLen,&bufferPtr,&endTextPtr,&endBufferPtr,line,index); index = 0; waddch(typingWindow,' '); wrefresh(typingWindow); } } // III. Finished: saveLine(&bufferLen,&bufferPtr,&endTextPtr,&endBufferPtr,line,index); int inFd = creat(TEXT_FILENAME,0640); write(inFd,bufferPtr,endTextPtr-bufferPtr); close(inFd); free(bufferPtr); return(NULL); } // PURPOSE: To turn off 'ncurses'. No parameters. No return value. void offNCurses () { sleep(1); nl(); echo(); refresh(); delwin(messageWindow); delwin(typingWindow); delwin(checkingWindow); endwin(); } // PURPOSE: To do the spell-checking word-processor. Ignores command line // arguments. Return 'EXIT_SUCCESS' to OS. int main () { struct sigaction act; memset(&act,'\0',sizeof(act)); act.sa_handler = sigAlarmHandler; sigaction(SIGALRM,&act,NULL); onNCurses(); type(NULL); offNCurses(); return(EXIT_SUCCESS); } 
  2. C programming (100 Points):

     parent process | | | fork() | /execl() enscript +--------------->| | | | | | fork()/execl() | ps2pdf +----------------|-------------->| | | | | | | | | | | write() | | +--------------->|read() | | | | | |write() | | |-------------->|read() | | | | stops | | |write() | |--------------> PDF_FILENAME | stops | ends 

    The program above starts 'ncurses', a package to control the cursor. (Already done.)

  3. Most of the work is done by type(), which gets what the user types and saves it into ever expanding char buffer bufferPtr. (Already done.)
  4. When the user presses Ctrl-P to print, type() calls printPdf(), which is the function that you must finish.
    1. You will need 2 pipes or 2 socket pairs
    2. Make a child process to run enscript. This child process should close() all unnessary pipes/sockets. Please also close() STDERR_FILENO, or else you might see annoying messages from enscript like "[ 1 page * 1 copy ] left in -".

      You will, however, need enscript to get input from its parent process, and need it to send its output to the other child process.

      Run /usr/bin/enscript with the following command line arguments:

      "--filter-stdin=-" Tells it to get input from stdin
      "-p" Tells it to send output to stdout
      "-"
      Remember how to use execl()!
      • How many times do we give the program name?
      • What do we have as the last argument?
    3. Make a child process to run ps2pdf. This child process should also close() all unnessary pipes/sockets. It does not need the parent-to-enscript pipe/socket at all.

      You will, however, need ps2pdf to get input from its sibling process, and need it to send its output to a file named PDF_FILENAME.

      Run /usr/bin/ps2pdf with the following command line arguments:

      "-" Tells it to get input from stdin
      "-" Tells it to send output to stdout
    4. Meanwhile, the parent process should close() all unnecessary file-descriptors. (It does not need the enscript-to-ps2pdf pipe/socket at all.)

      It should write() the endTextPtr-bufferPtr chars pointed to by bufferPtr to the enscript-child, and then close() whatever pipe/socket it used.

      The parent should then wait() for both children to finish. Put their statuses in integers status0 and status1, which my code checks to see how well the two children did.

  5. Add whatever variables you want (within reason).
  6. Now run the bad boy! Type something, and press Ctrl-P. Press Esc to quit.

    You should have a file print.pdf in your directory. Download it, and it should be a PDF file of what you had.

Step by Step Solution

There are 3 Steps involved in it

Step: 1

blur-text-image

Get Instant Access to Expert-Tailored Solutions

See step-by-step solutions with expert insights and AI powered tools for academic success

Step: 2

blur-text-image

Step: 3

blur-text-image

Ace Your Homework with AI

Get the answers you need in no time with our AI-driven, step-by-step assistance

Get Started

Recommended Textbook for

Sql All In One For Dummies 7 Books In One

Authors: Allen G Taylor ,Richard Blum

4th Edition

1394242298, 978-1394242290

More Books

Students also viewed these Databases questions