Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

ReesAcheson

macrumors newbie
Original poster
Dec 31, 2014
6
0
I have a small utility that I use under Linux that I would like to make available on my wife's Mac (running 10.8.5, Moutain Lion). I am looking for someone to compile it for me. It is only 170 lines long and uses only stdio.h, stdlib.h & string.h and so should present no problems.

I tried to install XCode to enable then installing a C compiler, but the installation crashed her computer and I had to reinstall the OS and the backup. I do not want to try it again - I'm still in the dog house from the last attempt.

Any volenteers? If so, please recommend how to get the code to you. Email? Post it here? What?

Thanks,
Rees
 
Post the code here, using CODE tags.

170 lines probably won't hit any post-size limits, and it lets potential volunteers see it first.

Code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/* Program to read text from a file or from stdin, buffering text and searching for a string.
   When 2 CRs are found (a paragraph) if a match was found in it the buffer is 
   printed to stdout.  The buffer is cleared and reading contuned.
   The effect is to print the entire paragraph if it contains a match.
 */

FILE	*intext;
typedef char bufstr[0x7fff];	//32k buffer
typedef char shortstr[63];
typedef char filenamestr[255];

bufstr buffer;
int bufpos;

shortstr	srchst, SRCHST; 
char		Ch, LastCh;
char		t;
filenamestr	filename;
int		Found, ReadFromStdIn, i, BufOverflow;
int		SrchIndex;
int 		ShowFn;  /*If ShowFn then display Fn before displaying lines  */


void AddCh (char c) {
  if (bufpos < sizeof(buffer)-2) {
    buffer[bufpos] = c;
    bufpos ++;
    buffer[bufpos] = 0;
    }
  else {
      BufOverflow = 1;
    printf ("buffer full, program terminated\n");
  }
}

void ClearBuf () {
  bufpos = 0;
  buffer[bufpos] = 0;
}

void PrintBuf () {
  printf("%s", buffer);
  printf("\n");
}


void stupper(char *str) {			/* string uppercase, usage: stupper(srchst); */
	int i;							/*this uppercases the original */
	for (i = 0; str[i]; i++) 
		str[ i ] = toupper( str[ i ] );
}

void stlower(char *str) {			/* string lowercase, usage: stlower(srchst); */
	int i;							/*this lowercases the original */
	for (i = 0; str[i]; i++) 
		str[ i ] = tolower( str[ i ] );
}



void syntax(char *prog) {			/* this does work (call syntax(srchst) */
	printf("Syntax: cat filename | %s [-f] [-h] srchst\n", prog);
	printf("  filename is piped into %s.  Paragraphs that contain srchst\n", prog);
	printf("  are printed.  srch is not case sensitive.\n");
	printf("  Use double quotes around multi-word srearch phrases.\n");
	printf("Or,");
	printf("Syntax: %s srchst filename\n", prog);
	printf("  -h  Help\n");
	printf("  -f  Display filename of files that contain srchst\n");
}


/* ********************************************************* */



int main ( int argc, char *argv[] ) {

  int i, stlen;
  BufOverflow = 0;
  ShowFn = 0;  	/*  Set this to 1 if filename is to be displayed, 0 otherwise */
//  FnContains = 0;
  ReadFromStdIn = 1;
  filenamestr	argument;
  int args, ArgNum;
  ArgNum = 0;
  args=argc;	

  if (argc == 1) { 			 /*Should be > 1; argc[1] = argv[0] is programname */
    strncpy(filename, argv[0], sizeof(filename)-1);  //copy programname to srchst for syntax to use
    syntax(filename);
    return 1;			//Exit with error 1
  }

  for (i = 1; i < args; i++) {
    strncpy(argument, argv[i], sizeof(argument)-1);
    if (argument[0] == '-') {
	    /* printf("we have a hyphen\n"); */
      switch (argument[1]) {
        case 'h': strncpy(filename, argv[0], sizeof(filename)-1); 
                  syntax(filename);	
                  return 1;
                  break;
        case 'f': ShowFn = 1; 	
                  break;
         default: printf("Unrecognized switch %c\n", argument[1]); 
                  break;
      }	//switch
    }		//if
    else {
      ArgNum ++;
      switch (ArgNum) {
        case 1: strncpy(srchst, argument, sizeof(srchst)-1); break;
        case 2: strncpy(filename, argument, sizeof(filename)-1);
                ReadFromStdIn = 0; break;
       default: printf("Too many Arguments\n"); break;
      }	//switch
    }	//else
   } // for

  strcpy(SRCHST, srchst);
  stupper(SRCHST);			//The uppercase search string
  stlower(srchst);			//The lowercase one

  if (ReadFromStdIn == 0) { 
    intext=fopen(filename,"r");		/* open filename for reading */	
  }
  else {
    intext=fopen("/dev/stdin","r");	/* open stdin for reading */	  
  }
    /* printf("reading in file...\n");*/
  if(intext == NULL) 		   					/* did it open? */
    printf ("unable to open file");
  else {		//OK, let's do it
    Found = 0;
    LastCh = 0;
    Ch = 0;
    Found = 0;
    SrchIndex=0;
    do   {
      if (Ch != ' ')		/*Do not count a line of spaces as a line of text*/
        LastCh = Ch;
      Ch = fgetc(intext);
      if( feof(intext) )
        break ;
      if (Ch == '\n' && LastCh == '\n')  {   //if 2 CRs in a row
      /*    printf("New Paragraph\n"); */
        if (Found == 1)	//If anything found the the Paragraph, then print it
          PrintBuf();
        ClearBuf();
        Found = 0;
      }
      else  {		//not 2 CRs so add the ch to buffer
        AddCh(Ch);
        if (! Found) {	//If we already have a match, no need to look again
          if ( srchst[SrchIndex] == '?' || 		//Wild card?
                    Ch == srchst[SrchIndex] || 		//lowercase match?
                    Ch == SRCHST[SrchIndex])  { 		//uppercase match?
             SrchIndex ++;				//check next character
             if (srchst[SrchIndex] == 0)  {	/* if end of srchst, we have a match */
               SrchIndex = 0;			//reset for next test
               Found = 1;
               //printf("bingo!"); 
             }
          }
          else	//No match
            SrchIndex = 0;
          }
        }
    } while (! BufOverflow);	//do; an exit is provided with break at feof
  }			//else, do it
  if (Found == 1)	//If a match still pending then print it
    PrintBuf();
  ClearBuf();
  fclose(intext);
}	//main
 
Compiled as x86_64 executable on 10.8.5 Mountain Lion. Attached as zip file.

Source file was named "ach.c". Command line was:
Code:
make ach
Output produced from compile:
Code:
cc     ach.c   -o ach
ach.c:54:14: warning: implicit declaration of function 'toupper' is invalid in C99
      [-Wimplicit-function-declaration]
                str[ i ] = toupper( str[ i ] );
                           ^
ach.c:60:14: warning: implicit declaration of function 'tolower' is invalid in C99
      [-Wimplicit-function-declaration]
                str[ i ] = tolower( str[ i ] );
                           ^
2 warnings generated.

I leave the testing to you.

Happy New Year!
 

Attachments

  • ach.zip
    3 KB · Views: 208
#include <ctype.h>

You should #include the header file <ctype.h>. This will get rid of the compiler warnings. This shouldn't compile without it. Maybe you have something set different than I do but with my XCode, I couldn't compile this code without it.
 
Compiled as x86_64 executable on 10.8.5 Mountain Lion. Attached as zip file.

I leave the testing to you.

Happy New Year!

Thank you so much. It works when fed a filename but not with stdin. Perhaps this has to do with Senor Cuete's point about missing #include <ctype.h>, although the warnings you posted don't seem to point to stdin not working.

Could you please try it again with the <ctype.h> addition? If need be, I could use it as is, but I would rather pipe in the input text. Thank you very much for your efforts so far.

Rees.
 
Will do.

Could you post some sample input and expected output, so I have a decent test case? Again, use code tags around the data so it preserves all the spacing.

Code:
 echo "To announce that there must be no criticism of the President or that we are to stand by the President, right or wrong, is not only unpatriotic and servile, it is morally treasonable to the American Public.   President Theodore 
Roosevelt" |greph moral

If excecuted on the command line, the above should print the quote to the screen. Changing the search string at the end to something like "morak" should produce no output.

By the way, Happy New Year!

Rees
 
Here's the one with ctype.h included.

Source changed to:
Code:
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
...no other changes...
It was built the same way: at the command-line with 'make' and its default build rule.


Tested on my 10.8.5 MacBook Pro, both the new and old versions had the same output for the given sample inputs. That is,
Code:
echo ..blahblah.. | ./greph morak
did NOT produce any output text (the expected result).

Here's all the tests I ran. The file 'grin' was made using the 'echo' command with output redirected to 'grin'.
Code:
mine:grephing me$  echo "To announce that there must be no criticism of the President or that we are to stand by the President, right or wrong, is not only unpatriotic and servile, it is morally treasonable to the American Public.   President Theodore Roosevelt" | ./greph moral
To announce that there must be no criticism of the President or that we are to stand by the President, right or wrong, is not only unpatriotic and servile, it is morally treasonable to the American Public.   President Theodore Roosevelt

mine:grephing me$ 
mine:grephing me$  echo "To announce that there must be no criticism of the President or that we are to stand by the President, right or wrong, is not only unpatriotic and servile, it is morally treasonable to the American Public.   President Theodore Roosevelt" | ./greph morak
mine:grephing me$ 

mine:grephing me$ 
mine:grephing me$ cat grin | ./greph moral
To announce that there must be no criticism of the President or that we are to stand by the President, right or wrong, is not only unpatriotic and servile, it is morally treasonable to the American Public.   President Theodore Roosevelt

mine:grephing me$ 
mine:grephing me$ cat grin | ./greph morak
mine:grephing me$ 
mine:grephing me$ ./greph moral <grin
To announce that there must be no criticism of the President or that we are to stand by the President, right or wrong, is not only unpatriotic and servile, it is morally treasonable to the American Public.   President Theodore Roosevelt

mine:grephing me$ 
mine:grephing me$ ./greph morak <grin
mine:grephing me$ 
mine:grephing me$ ./greph moral grin
To announce that there must be no criticism of the President or that we are to stand by the President, right or wrong, is not only unpatriotic and servile, it is morally treasonable to the American Public.   President Theodore Roosevelt

mine:grephing me$ 
mine:grephing me$ ./greph morak grin
mine:grephing me$


For the following command, run on the old and new versions, the output is as shown.
Old:
Code:
nm greph | grep lower
0000000100001550 T _stlower
                 U _tolower
New:
Code:
nm greph | grep lower
                 U ___tolower
00000001000014e0 T _stlower
0000000100001540 t _tolower
The ctype.h file defines tolower() as a macro and/or inline func that eventually leads to __tolower(), the symbol marked as U above. In this context, a U symbol will mean a function residing in a library. Lower-case means the symbol is "static" (non-extern).


If you want to examine any unexpected behavior, I think you'll need a simplified test-case focusing exclusively on the functions at issue, and specific input and output data.
 
chown33,

The new version with the included ctype.h seems to produce the desired output for each of the various type of inputs you tested. And you tested all that I can think of.

Your explanation of the nm object list:
The ctype.h file defines tolower() as a macro and/or inline func that eventually leads to __tolower(), the symbol marked as U above. In this context, a U symbol will mean a function residing in a library. Lower-case means the symbol is "static" (non-extern).
appears to indicate how ctype.h solves the problem, but I am sorry to say that I did not follow it all the way to how the difference of reading from a file or from piping or redirection effects it. I would like to know the anwer to that, but I initially asked for a volunteer, which I spelled correctly this time - I did not ask for your additional effort at debugging, which I very much thank you for. I am a bit uncomfortable asking for that explanation.

Now, unless I missed it, I think you forgot to attach the executable. I assume it is now fixed, I have not been able to try it yet here,

Rees
 
You should #include the header file <ctype.h>. This will get rid of the compiler warnings. This shouldn't compile without it. Maybe you have something set different than I do but with my XCode, I couldn't compile this code without it.

I didn't compile with Xcode. I used 'make' and Terminal, as shown in the earlier post.

I have the Xcode command line tools installed on this MBPro, but not Xcode itself.

For reference, the C compiler that 'make' runs is this:
Code:
[B]cc --version[/B]
Apple LLVM version 5.1 (clang-503.0.40) (based on LLVM 3.4svn)
Target: x86_64-apple-darwin12.5.0
Thread model: posix
 
Somehow the attachment didn't upload, and with all the other stuff in the post, I failed to notice.

Should be here this time.

Got it. And it works just fine. Thank you. I've been trying to compile this for her for about two months. Thank you, thank you.

Rees
 
With a very low turnaround rate and no authentication, if those are acceptable tradeoffs.

Yeah, while I'm glad you were able to help out the OP, I'd strongly discourage this sort of thing. OP: don't run random executables from people on the internet. It would have been trivial for chown33 to add a persistent backdoor to the code, or to make it delete files, or....
 
Yeah, while I'm glad you were able to help out the OP, I'd strongly discourage this sort of thing. OP: don't run random executables from people on the internet. It would have been trivial for chown33 to add a persistent backdoor to the code, or to make it delete files, or....

To be honest, I agree with you.

One reason I didn't reply with any comments about trustworthiness or authenticity is because the OP said he came from Linux. It was also clear to me he'd been programming for a while. If he'd been a complete noob I likely wouldn't have replied at all, or would have launched the "Are you sure you understand all the security implications?" conversation.

I might also have suggested rewriting the utility in an interpreted language that OS X has by default, such as python, perl, or awk. These are installed by default (I'm pretty sure), and they're interpreted so no compilation needed.
 
To be honest, I agree with you.

One reason I didn't reply with any comments about trustworthiness or authenticity is because the OP said he came from Linux. It was also clear to me he'd been programming for a while. If he'd been a complete noob I likely wouldn't have replied at all, or would have launched the "Are you sure you understand all the security implications?" conversation.

I might also have suggested rewriting the utility in an interpreted language that OS X has by default, such as python, perl, or awk. These are installed by default (I'm pretty sure), and they're interpreted so no compilation needed.

Reading the 'description' of the problem makes it seem like it could have been done in any language with regex, and possibly even pure bash with pipes into grep etc. "for free"
 
I tried to install XCode to enable then installing a C compiler, but the installation crashed her computer and I had to reinstall the OS and the backup.

You don't need to install a C compiler if you install Xcode. Xcode comes with one: LLVM.

Edit: But I'm glad you got help. Thank you, chown!


----------

I would try doing compiling over the command line if xcode fails to install.

I think the C compiler installation caused the error, not the Xcode installation. Xcode comes from the App store, so it's very unlikely its installation caused the crash.
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.