Thread: Logic approach

  1. #1
    Registered User
    Join Date
    Aug 2009
    Posts
    70

    Logic approach

    I have fixed the -s option to eliminate excess blank lines but still am having some difficulty with parsing multiple command line options eg -ns. Is it possible to do this using this approach that i am trying?

    If i attempt to pass ./prog -ns file.txt in the command line it returns

    Case n!
    File -ns couldn't be opened!
    Segmentation fault

    Rather than listing lines and eliminating excess blank lines.
    When -n file.txt is passed it no longer prints newlines due to my logic problem.

    Code:
       void concatenate_files(char option){
        for(index = optind; index < argc; index++){
          fp = fopen(argv[index], "r");
          if(fp == NULL){
            fprintf(stdout,"File %s couldn't be opened!\n", argv[index]);
          }else{
            printf("File opened!\n");
          }
            printf("%c\n", option);
            int c;
            int aflag = 1;
            int bflag = 1;
            while((c = fgetc(fp)) != EOF){
              if(aflag != 0 && option == 'n'){
                printf("%d  ", lineCount);
                lineCount++;
                aflag = 0;
              }
              if(c == '\n' && bflag != 0 && option == 's'){
                printf("%c", c);
                bflag = 0;
              }
              if(c != '\n'){
                printf("%c", c);
                bflag = 1;
              }
              if(c == '\n'){
                aflag = 1;
              }
            }
          fclose(fp);
        }
      }

    Code:
      while((optchar = getopt (argc, argv, "nsvt")) != -1){
        switch(optchar){
          case 'n':
                printf("Case n!\n");
                concatenate_files('n');
            break;
          case 's':
                 printf("Case s!\n");
                 concatenate_files('s');
            break;
          case 'v':
            break;
          case 't':
            break;
          }
        }
    Last edited by erasm; 08-09-2009 at 09:05 AM. Reason: New code

  2. #2
    Registered User
    Join Date
    Sep 2008
    Posts
    53
    i cant see that well. i have a eye condition so bear with me if i am wrong. but it seems like you are opening the same file using two different functions at the same time and the error message cant open file -n means that your are not parsing the options correct.

    i posted a program i made just for the example of how i would have organized the program. this program opens the files and does something depending on the flags /options giving correct. (i tested it two times on each option but it could have small flaws ,i am still newbie. )

    Code:
    #include <ctype.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    #include <errno.h>
    
    
    
    void PrintUsage(const char *progname);
    
    
    int  main (int argc, char **argv)
    {
               int nflg = 0;
               int sflg = 0;
               int vflg = 0;
    	   int tflg= 0;
               int index;
               int c;
    
              opterr = 0;
              FILE *fp;
    	   
    	   	 /* if the program has no arguments at all then print usage*/
                     if(argc == 1)
    	        {
    		           PrintUsage(argv[0]);
    			   exit(0);
    	        }
    	   
                     /* parse the options */
                  while ((c = getopt (argc, argv, "nsvt")) != -1)
                            switch (c)
                           {
                                          case 'n': nflg = 1;       break;
                                          case 's': sflg = 1;       break;
                                          case 'v': vflg = 1;       break;
    				      case 't': tflg = 1;       break;
                                          case '?':
                                          if (isprint (optopt))
    			             {
                                                 fprintf (stderr, "Unknown option `-%c'.\n", optopt);
                                         }
    			              else
    			             {
                                                       fprintf (stderr,
                                                                   "Unknown option character `\\x%x'.\n",
                                                                 optopt);
                                                          exit(EXIT_FAILURE);
    			             }
    					 
                                         default:
           			             abort ();
                              }    
    				
    			/* the version flag triggered here */
    			
                             if(vflg != 0)
    			{
    			            printf("version is beta version 1 \n");
    			           exit(EXIT_SUCCESS);
    		        }
    			
                      /* the things that happens in the program here*/
    		   for (index = optind; index < argc; index++)
    	         {
                                     if((fp=fopen(argv[index],"r")) == NULL)
    				 {
    					 printf("error in opening file %s",argv[index]);
    				 }
    				 
    				 while((c=getc(fp)) != EOF)
    				 {
    					 /* do some stuff here with the file */
    					  if(nflg)
    					  {
    						  if(c == '\n')
    				             		     printf("%c<br>",c);
    						  else 	 
    					                    printf("%d",c);
    					  }
    					  
    					  if(sflg)
    					  {
    						    printf("%c\t%d",c,c);
    					  }	 
    					  
    					  if(tflg)
    					  { 
                                                       printf("%0xhh",c);
    					
                		                  }else
    					            printf("%c",c);
    					 
    				 }
    				 fclose(fp);	 
    				  
    		   }	 
    	   
           return 0;
    }
    
    void PrintUsage(const char *progname)
    {
    	 fprintf(stdout,"USAGE:%s [options]\n"
    	                "barebones usage help text\n",
    			 progname);
    }

  3. #3
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Here is a better way to do this:
    Code:
    #include <stdio.h>
    #include <unistd.h>
    
    int main(int argc, char *argv[]) {
    	char options[]="x:y:z:";
    	int opt;
    	if (argc>1) {
    		while ((opt=getopt(argc, argv, options))>0) {
    			if (opt=='?') {puts("Wrong!");return -1;}
    			printf("option: %c argument: %s\n",opt,optarg);
    		}	 
    	}
    	return 0;	
    }
    So, for example, if you ran "./a.out -x this -y that" the output would be:

    option: x argument: this
    option: y argument: that


    If you do it like that, you can simply pass the filename as a string to concatenate_files(), and not have to bother with the stuff you are trying to do there (which is impossible anyway, argc and argv ARE NOT GLOBAL and hence do not exist in the function).
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  4. #4
    Registered User
    Join Date
    Aug 2009
    Posts
    70
    Hmm i am not suppose to be using option arguments.

    I am going to have a go at cmay's suggestion. Just need to figure out some way to do this logic.
    Last edited by erasm; 08-09-2009 at 10:31 AM.

  5. #5
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300

    Thumbs up

    Quote Originally Posted by erasm View Post
    Hmm i am not suppose to be using option arguments.
    So that would explain why this is in the Original Post:
    Code:
    while((optchar = getopt (argc, argv, "nsvt")) != -1){
        switch(optchar){
    and your question was:
    I have fixed the -s option to eliminate excess blank lines but still am having some difficulty with parsing multiple command line options eg -ns. Is it possible to do this using this approach that i am trying?
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  6. #6
    Registered User
    Join Date
    Aug 2009
    Posts
    70
    Aren't command line arguments different to command line option arguments?

  7. #7
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Quote Originally Posted by erasm View Post
    Aren't command line arguments different to command line option arguments?
    Well, I don't want to ruin your assignment but that is a strange distinction IMO.

    Are you allowed to use getopt() (you were/are)? That functionality is part of getopt. I do know that students are sometimes told they cannot use getopt() at all and must manually parse the command line arguments.

    You are trying to deal with filenames on the command line, and process switches (eg -s), right? I would say either you are allowed to use getopt() for that, or not. It would be a bad idea to use it only for part of that, since it does modify the contents of argv, I believe. So if you do use getopt() you might as well use it properly.
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  8. #8
    Registered User
    Join Date
    Aug 2009
    Posts
    70
    I am trying to emulate the unix cat command which uses ./prog -nstv argfile.txt argfile2.txt

    Edit: it appears multiple options are working now. Is it possible to implement the rest of these options -stv using conditions? This is going to get fairly messy, would there be a better approach to this program? processing lines in buffer? Though i am quite happy doing it this way but i do need some help.

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    
    int main(int argc, char *argv[]){
      int optchar;
      int index;
      FILE *fp;
      int lineCount = 1;
      int nflag = 0;
      int sflag = 0;
      int vflag = 0;
      int tflag = 0;
    
      while((optchar = getopt (argc, argv, "nsvt")) != -1){
        switch(optchar){
          case 'n':
                nflag = 1;
            break;
          case 's':
                sflag = 1;
            break;
          case 'v':
                vflag = 1;
            break;
          case 't':
                tflag = 1;
            break;
        }
      }
    
      for(index = optind; index < argc; index++){
        fp = fopen(argv[index], "r");
          if(fp == NULL){
            fprintf(stdout,"File %s couldn't be opened!\n", argv[index]);
          }
            int c;
            while((c = fgetc(fp)) != EOF){
              if(nflag != 0){
                printf("%d  ", lineCount);
                lineCount++;
                nflag = 0;
              }
              if(c != '\n'){
                sflag = 1;
              }
              if(sflag == 1){
                printf("%c", c);
              }
              if(c == '\n'){
                nflag = 1;
              }
            }
        fclose(fp);
      }
      return 0;
    }
    Last edited by erasm; 08-09-2009 at 11:14 AM.

  9. #9
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Quote Originally Posted by erasm View Post
    I am trying to emulate the unix cat command which uses ./prog -nstv argfile.txt argfile2.txt
    Hmm. Okay. Well, I was wrong, getopt() does not destroy argv (it may modify it slightly...watch), and it ignores anything that is not part of what it is looking for. So here's an illustrative variation on my previous example:
    Code:
    #include <stdio.h>
    #include <unistd.h>
    
    int main(int argc, char *argv[]) {
    	char options[]="ax:y:z:";
    	int opt, i;
    	if (argc>1) {
    		while ((opt=getopt(argc, argv, options))>0) {
    			if (opt=='?') {puts("Wrong!");return -1;}
    			printf("option: %c argument: %s\n",opt,optarg);
    		}	 
    	}
    	for (i=0; i<argc; i++) {
    		printf("\t%d: %s\n",i,argv[i]);
    	}
    	return 0;	
    }
    [root~/C/example-usage] ./a.out -a blah -x this -y that now then
    option: a argument: (null)
    option: x argument: this
    option: y argument: that
    0: ./a.out
    1: -a
    2: -x
    3: this
    4: -y
    5: that
    6: blah
    7: now
    8: then

    Option "a" is defined to not take an argument, here:
    Code:
    char options[]="ax:y:z:";
    because it doen't have a colon after it. So a's argument is (null), even tho I put the word "blah" after it. But look what happens to argv after getopt has run: "blah" got moved from argv[2] to argv[6]! But if you keep the filenames at the end, that should not matter much.

    So you just want to use options with no arguments, and use argv[argc-2] and argv[argc-1] for the filenames. Which it looks like you are doing basically that, with optind. Is there still a problem?
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  10. #10
    Registered User
    Join Date
    Aug 2009
    Posts
    70
    Quote Originally Posted by MK27 View Post
    Is there still a problem?
    It appears multiple options are working now. Is it possible to implement the rest of these options -stv using if conditions? This is going to get fairly heavy for me, would there be a better approach to this program? processing lines in buffer? Though i am quite happy doing it this way but i do need some help.

    Sorry i didnt mention what the options are lol.

    -n lists line number at the beginning of each line
    -s merges multiple concurrent into one
    -v displays printable characters
    Last edited by erasm; 08-09-2009 at 11:27 AM.

  11. #11
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Here is a little issue:
    Code:
              if(c == '\n'){
                nflag = 1;
              }
    Even if you don't use -n, that means every line after the first one will be numbered. I don't think you should alter nflag at all in this loop; you need another flag, to indicate that the last character was a '\n' so the condition could be like this:
    Code:
    int end=1;
             if((nflag != 0) && (end ==1)){
                printf("%d  ", lineCount);
                lineCount++;
                end = 0;
              }
             if(c == '\n'){
                end = 1;
              }
    Notice end is initially set to 1 so that the first line gets a number if nflag is set*.

    Depending on what else you are doing, it *might* be easier to use fgets() to take a whole line, then send it to another function for processing character by character if necessary (I think that is what your -v switch will involve). Of course, that means reading each byte twice, but in the context of dealing with a file that is outputted to the console, this slight inefficiency will be irrelevant.

    * you don't have to use != and == with boolean (1 or 0) values all the time. 0 is false, everything else is true so you can say "if (!nflag)" instead of "if (nflag == 0)" and "if (nflag)" instead of "if (nflag == 1)". So that condition could be "if (nflag && end) {"
    Last edited by MK27; 08-09-2009 at 11:44 AM.
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  12. #12
    Registered User
    Join Date
    Aug 2009
    Posts
    70
    I have -n and -s each working alone fine. But i can't get -ns correctly working.

    for example ./prog -ns file.txt will output

    1 Welcome.
    2
    3 4 5 after 3 blank lines!
    6 this is text file one.
    7
    8 9 this line is after 2 blank lines!
    10 here is line 2.
    11 the end.
    12

    I can't seem to get the conditions right

    Here is what i have.

    Code:
        
    while((c = fgetc(fp)) != EOF){
      if(c != '\n'){
        newlineCount = 0;
      }
      if(nflag && endline){
        if(sflag && newlineCount < 2){
          printf("%d  ", lineCount);			  
        }else{
          printf("%d  ", lineCount);
        }
        lineCount++;
        endline = 0;
      }
              		  
      if(newlineCount < 2 && sflag){
        printf("%c", c);
      }
      if(!sflag){
        printf("%c", c);
      }  
      if(c == '\n'){
        endline = 1;
        newlineCount++;				
      }		  
    }

  13. #13
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300

    Thumbs up

    Quote Originally Posted by erasm View Post
    I can't seem to get the conditions right
    Your current version works, I think. Are you aware of the continue statement? You can simplify some of the logic that way:
    Code:
    while((c = fgetc(fp)) != EOF){
    	if (endline && nflag) printf("%d  ", lineCount++);	/* always print the line number (if) */		  
    	if(c == '\n'){                          /* now deal with newlines */
    		endline = 1;
    		if (sflag) {
    			if (++newlineCount < 3) printf("%c",c);
    		} else printf("%c",c);
    		continue;                   /* start loop again... */
    	}
    	printf("%c",c);               /* ...or default events */
    	endline = 0;
    	newlineCount = 0;
    }
    Notice in the block dealing with newlines, I set endline right away, since this will happen no matter what if c == '\n'. That way, I do not have to worry about doing it in one (or more) of the nested conditionals. Then, because of continue, we don't have to worry about special cases involving newlines in the rest of the loop.

    This is a more sane "branch & complete" strategy rather than having to repeatedly test the same condition over and over -- eg, witness I did not have to test any flag or condition, including the value of "c", more than once. That's the kind of logic you want to use as a framework when programming with loops.
    Last edited by MK27; 08-09-2009 at 02:53 PM.
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  14. #14
    Registered User
    Join Date
    Aug 2009
    Posts
    70
    This seems to have it working. hazza! thank you forest fairy.

    Code:
    while((c = fgetc(fp)) != EOF){
      if(c != '\n'){
        newlineCount = 0;
      }
      if(nflag && endline){
        if(sflag && newlineCount < 2){
          printf("%d  ", lineCount);
          lineCount++;
        }
        if(!sflag){
          printf("%d  ", lineCount);
          lineCount++;
        }
        endline = 0;
      }
      if(newlineCount < 2 && sflag){
        printf("%c", c);
      }
      if(!sflag){
        printf("%c", c);
      }  
      if(c == '\n'){
        endline = 1;
        newlineCount++;				
      } 		  
    }

  15. #15
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    You're welcome. You still have some inefficiencies going on. Here's the note I added to my last post while you were writing your last post:

    Quote Originally Posted by MK27 View Post
    This is a more sane "branch & complete" strategy rather than having to repeatedly test the same condition over and over -- eg, witness I did not have to test any flag or condition, including the value of "c", more than once. That's the kind of logic you want to use as a framework when programming with loops.
    When ever you find yourself repeating lines:
    Code:
        printf("%d  ", lineCount);
    You should think about that. It is not always true -- it could be the opposite -- but it usually is (I constantly end up compressing blocks by looking at the duplicated calls) and I'm pretty sure it is in this case. Getting the order things happen in straight is the key (which is why they call C an imperative or procedurally oriented language).
    Last edited by MK27; 08-09-2009 at 03:02 PM.
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Handling logic and draw cycles
    By DavidP in forum Game Programming
    Replies: 1
    Last Post: 07-25-2009, 10:15 AM
  2. Digital Logic
    By strokebow in forum Tech Board
    Replies: 3
    Last Post: 12-09-2006, 01:05 PM
  3. Actors, cues, event based logic.
    By Shamino in forum Game Programming
    Replies: 2
    Last Post: 04-27-2006, 10:58 PM
  4. Circular Logic
    By DavidP in forum A Brief History of Cprogramming.com
    Replies: 1
    Last Post: 10-15-2001, 08:10 PM