Thread: Modifying live input

  1. #1
    Registered User
    Join Date
    Sep 2010
    Posts
    12

    Modifying live input

    I currently have a program that does the following:

    It does a vfork() then executes another binary. This new binary takes its input on descriptors 0 and descriptors 1.

    Meanwhile, back in my program, I open two files and I use dup2() to redirect the first file to descriptor 0 and the second file to descriptor 1.

    This works very well.

    What I'm trying to do now is to modify the data as it's being read from file #2. I basically need to add a line of text before the first bare \n that's being found and then send the data on its way to descriptor 1. What is the easiest/fastest way to do this ?

    My only thoughts so far were to read the file, do the modification, write back to the file. Then open it back again and do the dup2() but it seems a very inefficient way to do things.

  2. #2
    Registered User
    Join Date
    Sep 2006
    Posts
    8,868
    I'd probably use fgets() to read a line at a time, into a char array. Then use strcat() to add the string you want to add, to the target line. Then continue writing out the char array, to the new (updated) file.

    If you imagine that you have no table of contents or index, and you had to do this job yourself, by hand; you'll probably have a pretty efficient algorithm to design your program around.

    Be sure to include string.h to let the string functions above, work.

  3. #3
    Registered User
    Join Date
    Sep 2010
    Posts
    12
    So basically you're saying to:

    1. open the file, do my change, save the file
    2. re-open the file, do the dup2()

    There's no way to do the string modification on the fly ?

  4. #4
    Registered User
    Join Date
    Sep 2006
    Posts
    8,868
    Not quite.

    I'm saying get your input, put it into a string, then add your change string with strcat().

    Now output the data twice, once to the new original file, and once to the dup of that new file. There's no problem having two files opened for output at the same time, is there?
    Last edited by Adak; 09-25-2010 at 08:18 AM.

  5. #5
    Registered User
    Join Date
    Sep 2010
    Posts
    12
    Quote Originally Posted by Adak View Post
    Not quite.

    I'm saying get your input, put it into a string, then add your change string with strcat().

    Now output the data twice, once to the new original file, and once to the dup of that new file. There's no problem having two files opened for output at the same time, is there?
    Sorry but I don't think I'm following.

    I can tell you that once the file is read/modified, I no longer need it - there is actually code to remove it after it was read once.

    I also have to use fread() instead of fgets() and I have to add more data in the middle of the buffer.

    Finally, how do I print to descriptor 1 ? Should I eliminate dup2() altogether and do a fprintf(1, "%s", buffer) for example ?

  6. #6
    Registered User
    Join Date
    Sep 2006
    Posts
    8,868
    fgets() isn't necessary, it was just an example. You have a string from the file. You can use strcat() or other logic, to make the changes you need to make.

    Post your code and give a small example of the input you have, and the output you want. Then these general idea's can be replaced with solutions instead of posting around in circles for lack of specifics.

  7. #7
    Registered User
    Join Date
    Sep 2010
    Posts
    12
    Here's the current code. It's meant to deal with e-mail messages and I want to add a newline in the headers of the message. The headers in an e-mail are from the first line and until the first line that only contains a single '\n'. I would want to add my custom line right before that single '\n'

    Current code starts here:

    Code:
      /* open the message read only*/
      if ( (fd = open(message_name, O_RDONLY)) == -1 ) {
        exit_clean(EXIT_400);
      }
    
      /* open the address read only */
      if ( (fd_per = open(addr_name, O_RDONLY)) == -1 ) {
        exit_clean(EXIT_400);
      }
    
      /* set the standard input to be the new file */
      if ( fd_move(1,fd_per)  == -1 ) {
        exit_clean(EXIT_400);
      }
    
    if ( pipe(pim) != 0 ) return(-1);
    
      switch(pid = vfork()) {
        case -1:
          close(pim[0]);
          close(pim[1]);
          exit_clean(EXIT_400);
        case 0:
          close(pim[1]);
          dup2(pim[0],0);
          execl(queue, queue, 0);
          _exit(-1);
      }
      close(pim[0]);
    
      while( (ret = read(fd, buffer, sizeof(buffer))) > 0 ) {
        if ( write(pim[1], buffer,ret) == -1 ) {
          exit_clean(EXIT_400);
        }
      }
      close(pim[1]);
      close(fd);



    So it's between the read and the write that my modification should take place.

  8. #8
    Registered User
    Join Date
    Sep 2006
    Posts
    8,868
    The code is very clear - and I get it that you need to make your changes after you read in the data, and before you write the data back out.

    Good one!

    Show an example of the header, and the line you want to add, one time. Should be very simple.

    I see no mention of what you want to add, in your code. Do you have this in a string, someplace in your code?

  9. #9
    Registered User
    Join Date
    Sep 2010
    Posts
    12
    Quote Originally Posted by Adak View Post
    The code is very clear - and I get it that you need to make your changes after you read in the data, and before you write the data back out.

    Good one!

    Show an example of the header, and the line you want to add, one time. Should be very simple.

    I see no mention of what you want to add, in your code. Do you have this in a string, someplace in your code?
    Glad I made myself clear. Here's an example of the data being contained in the message file.


    Code:
    Received: by sphinx (mbox mlande) (with Cubic Circle's cucipop (v1.31 1998/05/13) Wed Aug 20 19:41:38 2003) 
    X-From_: [email protected] Wed Aug 20 19:40:22 2003 
    Return-Path: <[email protected]> 
    Received: from psmtp.com (exprod5mx37.postini.com [12.158.34.194]) by sphinx.got.net (8.12.3/8.12.3/Debian-6.3) with SMTP id for <[email protected]>; Wed, 20 Aug 2003 19:40:05 -0700 
    Message-Id: <[email protected]> 
    Received: from source ([69.9.251.177]) by exprod5mx37.postini.com ([12.158.34.245]) with SMTP; Wed, 20 Aug 2003 21:40:05 CDT 
    From: <[email protected]>
    To: <[email protected]>
    Subject: whatever
    
    Start of message here
    Like I mentioned before, it's that new line that marks the separation between headers and body. The line I wish to add right before the newline is something like: X-Test: hello world

    Thanks for your help by the way!

  10. #10
    Registered User
    Join Date
    Sep 2006
    Posts
    8,868
    Ok, so your buffer with the header in it, needs the current newline deleted, by moving the end of string char, over (decrement it by one element of the buffer array).

    Then you can strcat() your string, right onto the buffer. That will delete the old end of string char, add your string to the end of the buffer, including your strings end of string char, so the header is rebuilt. It's just rebuilt as a longer string.
    Code:
    include string.h
    int len;
    
    len=strlen(buffer);
    buffer[len-1] should be the old newline you don't want, so
    buffer[len-1] = '\0';
    strcat(buffer, yourString);
    printf("%s", buffer);
    Try that. Make sure that your buffer is large enough for the old buffer char's + the new string, + 2 char's you can't see (the newline and the end of string char).

    You're welcome.

    Edit: an example of strcat():
    Code:
    #include <string.h>
    #include <stdio.h>
    
    int main(void)
    {
       char destination[25];
       char *blank = " ", *c = "C++", *turbo = "Turbo";
    
       strcpy(destination, turbo);
       strcat(destination, blank);
       strcat(destination, c);
    
       printf("%s\n", destination);
       return 0;
    }
    Last edited by Adak; 09-25-2010 at 10:46 AM.

  11. #11
    Registered User
    Join Date
    Sep 2010
    Posts
    12
    The buffer variable doesn't contain just the header and it doesn't end with a newline necessarily.

    The buffer reads 2048 bytes at a time from the entire e-mail file. So it might read half the header first, then the other half + half the message.

    I have to search for that first newline in each buffer read, and insert my line right before. The newline (\n) must not be replaced. I simply want to add something before.

  12. #12
    Registered User
    Join Date
    Sep 2006
    Posts
    8,868
    Ah! Then use strchr() to get the location of the newline.

    Code:
     #include <string.h>
     #include <stdio.h>
    
    int main(void)
     {
        char string[15];
        char *ptr, c = 'r';
    
        strcpy(string, "This is a string");
        ptr = strchr(string, c);
        if (ptr)
           printf("The character %c is at position: %d\n", c, ptr-string);
        else
           printf("The character was not found\n");
        return 0;
     }

  13. #13
    Registered User
    Join Date
    Sep 2010
    Posts
    12
    Quote Originally Posted by Adak View Post
    Ah! Then use strchr() to get the location of the newline.

    Code:
     #include <string.h>
     #include <stdio.h>
    
    int main(void)
     {
        char string[15];
        char *ptr, c = 'r';
    
        strcpy(string, "This is a string");
        ptr = strchr(string, c);
        if (ptr)
           printf("The character %c is at position: %d\n", c, ptr-string);
        else
           printf("The character was not found\n");
        return 0;
     }

    and then I use strcat() to append my line there ?

    Finally, how do I search for a 'line' containing just \n on it ? I'm asking because each 'line' ends with a \n or \r\n and just searching for a \n is not enough. I'm assuming I'd have to do a search for \n\n ?

  14. #14
    Registered User
    Join Date
    Sep 2006
    Posts
    8,868
    Yes, you have to search for the unique string that marks the target area of the buffer, you want to add your string into.

    When found, you need to have code that will move the char's out of the area of the buffer where you want to insert your own string.

    If your add on string is 15 char's long, then you need to shift every char after the point of insertion on buffer, 15 char's upward.

    buffer will then have:

    1) the part before the insertion point
    2) an empty space big enough for your add on string to be placed into
    3) the rest of the original buffer char's - everything from the point of insertion, to the end of the buffer.

    And then you can copy your add on string, into the buffer.

    Since your add on string is being put into the middle of the buffer, I'd just use memcpy, and not strcat(). or copy the add on string, manually.

    You will not some code similar to this

    Code:
     memmove:   Copies a block of n bytes from src to dest.
    
     Syntax:
       void *memmove(void *dest, const void *src, size_t n);
    
     Prototype in:
     mem.h   string.h
    
     Remarks:
    memmove copies a block of n bytes from src to dest.
    
    Even when the source and destination blocks overlap, bytes in the
    overlapping locations are copied correctly.
    
     Return Value:
    memmove returns dest.
    
     Portability:
    memmove is available on UNIX System V systems and is compatible with ANSI C.
    
     Example:
     #include <string.h> 
     #include <stdio.h>
    
     int main(void)
     {
       char dest[] = "abcdefghijklmnopqrstuvwxyz0123456789";
       char *src = "******************************";
       printf("destination prior to memmove: %s\n", dest);
       memmove(dest, src, 26);
       printf("destination after memmove:    %s\n", dest);
       return 0;
     }
    I'll post up a bit of code to show what I'm describing, using the example of memmove, above. It will show how to shift, and etc.
    Last edited by Adak; 09-25-2010 at 12:46 PM.

  15. #15
    Registered User
    Join Date
    Sep 2006
    Posts
    8,868
    This is an example of one way to insert a string of char's, into the middle of another string.

    I believe this is what you want:

    Code:
     #include <stdio.h>
     #include <string.h> 
    
     int shift(char *dest, char *src, int len_dest, int len_src, int size);
    
     int main(void)
     {
       size_t size;
       int len_dest, len_src, ip;
       //dest[] must be oversized to handle it's current char's + the char's
       //that will be inserted.
       char dest[68] = "abcdefghijklmnopqrstuvwxyz0123456789";
       char *src = "******************************";
       len_dest = strlen(dest);
       len_src = strlen(src);
       size = sizeof(dest);
    
       printf("\n\n\ndestination prior to memmove:\n%s", dest);
       ip = shift(dest, src, len_dest, len_src, size);
       memmove(dest+ip, src, len_src);
       printf("\ndestination after memmove:\n%s", dest);
       ip=getchar();
       return 0;
     }
    int shift(char *dest, char *src, int len_dest, int len_src, int size) {
      int i, j, ipoint;
      char *iptr;
      if(size < (len_dest + len_src))
        printf("\n Destination buffer is too small");
      else {
        //find the insertion point:
        iptr = strstr(dest, "defghij"); //
        ipoint = iptr-dest;
    
        //shift the char's after the insertion point
        for(i=len_dest,j=len_dest+len_src;i>=ipoint;i--, j--) {
          dest[j] = dest[i];
        }
        /*After the shift, the string may not view correctly, until after
          the memmove(). Shifted letters may not appear. They are there ;)
        */   
      }
      return ipoint;
    }

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Linked List from Standard Input
    By mercuryfrost in forum C Programming
    Replies: 14
    Last Post: 08-24-2009, 12:05 AM
  2. input redirection
    By sashaKap in forum C Programming
    Replies: 6
    Last Post: 06-25-2009, 01:59 AM
  3. Input statement problem
    By une in forum C Programming
    Replies: 3
    Last Post: 05-29-2007, 11:16 PM
  4. For loop problems, input please.
    By xIcyx in forum C Programming
    Replies: 2
    Last Post: 04-22-2007, 03:54 AM
  5. Simple Console Input for Beginners
    By jlou in forum C++ Programming
    Replies: 0
    Last Post: 06-21-2005, 01:50 PM