LinuxQuestions.org
Share your knowledge at the LQ Wiki.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 04-04-2012, 08:55 AM   #1
parminides
LQ Newbie
 
Registered: Apr 2012
Posts: 4

Rep: Reputation: Disabled
substitute for spawvp in linux C


I would like to ressurect the C version of an old and very simple program I wrote in Fortran ages ago. I never learned C but once translated it with some fortran to C converter. For some reason I cannot find the fortran version on any backup CDs.

The program is completely terminal-based. It opens a file with vocabulary words and phrases to practice Chinese. It's essentially a non-gui flash card program.

I don't remember enough Fortran to rewrite it, and C to Fortran converters don't seem to exist, so I'm forced to work with C, which I never learned in the first place.

Right now it won't compile. My gcc compiler is version (Ubuntu/Linaro 4.4.4-14ubuntu5.1) 4.4.5.

I've consulted the forums to fix a couple of errors and am down to only one complaint:

Code:
$ gcc wei.c
/tmp/cc37c0dL.o: In function `main':
wei.c:(.text+0x263): undefined reference to `spawnvp'
collect2: ld returned 1 exit status
The pertinent code is:

Code:
spawnvp(P_WAIT, "sort", "sort /home/clarkb/000files/list/chinese.tmp -o /home/clarkb/000files/list/wei.lis");
(The file chinese.tmp is a temporary file with the randomized words and wei.lis is the main word file.) That's the only place spawnvp is called.

The spawnvp function appears to "load and execute a new child process." It is apparently Windows specific, but one forum indicates that "The spawn() family can be accomplished by fork()ing, then exec()ing in the new child process."

Great. One function that I don't understand replaced by two that I don't understand! My program is very simple, and I don't know why it would want to do something crazy like spawn a child process. Its fortran predecessor got by just fine without such shenanigans (or at least without me having to program them).

Does someone know a quick way to just make it work?
 
Old 04-04-2012, 09:48 AM   #2
dwhitney67
Senior Member
 
Registered: Jun 2006
Location: Maryland
Distribution: Kubuntu, Fedora, RHEL
Posts: 1,541

Rep: Reputation: 335Reputation: 335Reputation: 335Reputation: 335
Quote:
Originally Posted by parminides View Post
Does someone know a quick way to just make it work?
If you don't mind editing your code, then something like shown below could be used. Note that I do not know what P_WAIT is meant to imply (I'm not a Windows programmer), so I removed it from the context below. Also, I had to provide the fully-qualified path to "sort", which is /bin/sort in Linux.

Anyhow, the code below provides a quick/dirty implementation for spawnvp().
Code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>

int spawnvp(const char* progname, const char* execStatement);


int main()
{
    //int ret = spawnvp(P_WAIT, "sort", "sort /home/clarkb/000files/list/chinese.tmp -o /home/clarkb/000files/list/wei.lis");

    int ret = spawnvp("/bin/sort", "/bin/sort /home/clarkb/000files/list/chinese.tmp -o /home/clarkb/000files/list/wei.lis");

    return (ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
}


int spawnvp(const char* progname, const char* execStatement)
{
    char* execStatementCopy = strdup(execStatement);
    char* ptrCopy = execStatementCopy;

    int   argc = 0;
    char* argv[20] = {NULL};

    char* arg = strtok(ptrCopy, " ");

    while (arg != NULL)
    {
        if (argc == 19)
        {
            /* only allow up to 19 args; number 20 must remain NULL */
            break;
        }

        argv[argc++] = arg;

        arg = strtok(NULL, " ");
    }

    free(execStatementCopy);

    pid_t pid = -1;

    if ((pid = fork()) == 0)
    {
        /* child */
        execv(progname, argv);

        printf("Failed to invoke execv(); error is %s (%d)\n", strerror(errno), errno);
    }
    else if (pid > 0)
    {
        /* parent */
        return 0;
    }

    return -1;
}
 
Old 04-04-2012, 10:53 AM   #3
parminides
LQ Newbie
 
Registered: Apr 2012
Posts: 4

Original Poster
Rep: Reputation: Disabled
Thank you dwhitney67 for your quick reply. I really appreciate the help.

P_WAIT is an integer defined to be 0.

I don't mind altering the code at all. After I implemented dwhitney67's suggested changes, the program compiled...but didn't do anything. The most likely problem is that I don't know what I'm doing and put the changes in the wrong places.

If anyone wants to have a further look, below are the two main files: wei.c (the program before the suggested changes) and wei.lis (an abbreviated sample data file).

wei.c:

Code:
/**
 ** wei.c ---- program to study Chinese
 **            
 ** todo list: recycle over missed words
 **            quit any time 'q' is encountered in getch()
 **            
 **/

/* #include <process.h> */
/* #include <unistd.h> */
#include <stdio.h>
#include <string.h>
#include <time.h>

#define CMAX 75
#define P_WAIT 1
#define WMAX 500

int main()
{
char buff[CMAX];
char estring, chstring;
char *epointer, *cpointer;
char sflag;
char control, ctrlstr;
char qstring[7];
int i, len;
int iword=0;
int iflag=0;
int qflag=0;
int idummy=0;
int iran=333; 
FILE *infile, *tmpfile, *wrdfile;
char *args[] = {
  "sort",   /* supposedly ignores the first arg */
  "/home/clarkb/000files/list/chinese.tmp",
  "-o",
  "/home/clarkb/000files/list/wei.lis",
  0         /* last arg is NULL */
};

srand((int)time(NULL));
strcpy(qstring, "What is");

/*printf("Have you sorted the current version of \n");
printf("    /home/clarkb/000files/list/chinese.txt      and saved it as \n");
printf("    /home/clarkb/000files/list/wei.lis? ");
scanf("%s", &sflag);
if( sflag == 'y' || sflag == 'Y')
    idummy=1;
else{
    printf("Please do so and then rerun program! \n");
    return;
} */

infile = fopen("/home/clarkb/000files/list/chinese.lis","r");
if(infile == NULL) return;

tmpfile = fopen("/home/clarkb/000files/list/chinese.tmp","w");
/* tmpfile = fopen("/home/clarkb/000files/list/chinese.txt","w"); */

while(fgets(buff,299,infile) != NULL) {
    int len = strlen(buff);
    iword++;
    while(--len >= 0) {
        if(buff[len] == '\n') { buff[len] = '\0'; continue; }
	if(buff[len] == '\r') { buff[len] = '\0'; continue; }
        break;
    }

/* find English part of buffer*/
    epointer=buff;
    while(*epointer != '-') epointer++;
    epointer++;
    while(*epointer == ' ') epointer++;

/* find Chinese part of buffer */
    cpointer=strtok(buff, "-"); 

/* assign random #'s to each line and put in temporary output file */
    iran=rand(); 
    fprintf(tmpfile,"%d @ %s - %s\n", iran, cpointer, epointer);
}

fclose(infile);
fclose(tmpfile);

/* sort the tmpfile and make the randomized wrdfile */
//spawnvp(P_WAIT, "sort", args);
//spawnvp(P_WAIT, args);
spawnvp(P_WAIT, "sort", "sort /home/clarkb/000files/list/chinese.tmp -o /home/clarkb/000files/list/wei.lis");

printf("Do you want to be prompted with English [1] or Chinese [2] words? ");
scanf("%d", &iflag);
if(iflag != 1 && iflag != 2){
printf("Please enter 1 or 2: ");
scanf("%d", &iflag);
}
if(iflag != 1 && iflag != 2){
printf("THIS IS YOUR LAST CHANCE! ENTER 1 OR 2: ");
scanf("%d", &iflag);
}
if(iflag != 1 && iflag != 2) return;
/* iflag=1;  uncomment for debugging */

/* open and read word file */
wrdfile = fopen("/home/clarkb/000files/list/wei.lis","r"); 

while(fgets(buff,299,infile) != NULL) {
    int len = strlen(buff);
    while(--len >= 0) {
        if(buff[len] == '\n') { buff[len] = '\0'; continue; }
	if(buff[len] == '\r') { buff[len] = '\0'; continue; }
	break;
    }

/* find English part of buffer*/
    epointer=buff;
    while(*epointer != '-') epointer++; 
    epointer++;
    while(*epointer == ' ') epointer++;

/* find Chinese part of buffer */
    cpointer=strtok(buff, "-");
    while(*cpointer != '@') cpointer++;
    cpointer++;

/*    GrClearScreen(GrBlack()); 
    GrTextXY(0,0,qstring,GrWhite(),GrNOCOLOR); */

    if( iflag == 1 ){
        printf("%s -> ", epointer);
        control=ctrlquit(infile,wrdfile,qflag);  /* not passing qflag,
                                                    so now cannot quit
                                                    on first prompt;
                                                    probably not passing
                                                    filenames correctly
                                                    either */
        printf("%s \n", cpointer); 

        control=ctrlquit(infile,wrdfile,qflag);
    }
    else{
        printf("%s -> ", cpointer);
        control=ctrlquit(infile,wrdfile,qflag);  /* not passing qflag,
                                                    so now cannot quit
                                                    on first prompt;
                                                    probably not passing
                                                    filenames correctly
                                                    either */
        printf("%s \n", epointer); 

        control=ctrlquit(infile,wrdfile,qflag);
    }
}
/* function not passing flags, so comment out
if(qflag == 0)
    printf("You've exhausted the database. Now, get back to work!"); */
return;
}

/* int ctrlquit(FILE *file1, FILE *file2, int iquit) */
int ctrlquit(FILE *file1, FILE *file2, int iquit)
{
#include <stdio.h>  
#include <string.h>

/* int iquit=0; */
char ctrlstr;
/* FILE *file1, *file2; */

iquit=0;

/* ctrlstr=getch(); */
ctrlstr=getchar();

if(ctrlstr == 'q'){
    iquit=1;
    fclose(file1);
    fclose(file2);
    return;
}
}
wei.lis:

Code:
1014397292 @ huang2  - yellow
1016230060 @ shang4 ban1  - to go to work
10193955 @ er2 zi  - son
1042731458 @ zo3     - left
1046695493 @ x:ue2 sheng1  - student

Last edited by parminides; 04-04-2012 at 10:56 AM.
 
Old 04-05-2012, 03:00 AM   #4
Nominal Animal
Senior Member
 
Registered: Dec 2010
Location: Finland
Distribution: Xubuntu, CentOS, LFS
Posts: 1,723
Blog Entries: 3

Rep: Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948
How about rewriting it in plain Bash?
Code:
#!/bin/bash

# Check parameters, and output help if necessary.
if [ $# -lt 1 ] || [ $# -gt 2 ] || [ "$1" = "-h" ] || [ "$1" = "--help" ]; then
    # Help is output to standard error.
    exec >&2

    echo ""
    echo "Usage: $0 [-h|--help]"
    echo "       $0 DICTIONARY-FILE [SIDE]"
    echo ""
    echo "DICTIONARY-FILE"
    echo "    Contains pair of words or sentences on each line,"
    echo "    separated by vertical bar, |."
    echo ""
    echo "SIDE"
    echo "    Optional argument, specifies whether the first [1]"
    echo "    or second [2] language is shown."
    echo "    Default is 1, i.e. first word/sentence on each line"
    echo "    in DICTIONARY-FILE is shown."
    echo ""

    exit 1
fi

# Check the SIDE parameter.
case "$2" in
    1|[Ff]*)        # 1 or first
        SIDE=1
        ;;
    2|[Ss]*|[Oo])   # 2 or second or other
        SIDE=2
        ;;
    "")             # Not specified; set default
        SIDE=1
        ;;
    *)  echo "$3: I don't understand which side you mean." >&2
        exit 1
        ;;
esac

# Load all the words from the first file.
Word1=()
Word2=()
Words=0
IFS='|'
while read -r w1 w2 w3 ; do
    [ "$w1" = "" ] && continue
    [ "$w2" = "" ] && continue
    Words=$[Words+1]
    if [ $SIDE -eq 1 ]; then
        Word1[Words]="$w1"
        Word2[Words]="$w2"
    else
        Word1[Words]="$w2"
        Word2[Words]="$w1"
    fi
done < <( sed -e 's@^[\t\n\v\f\r ]*@@; s@[\t\n\v\f\r ]*|[\t\n\v\f\r ]*@|@g; s@[\t\n\v\f\r ]*$@@;' "$1") || exit $?
if [ $Words -lt 1 ]; then
    echo "$1: No word or sentence pairs in file." >&2
    exit 1
fi

# Shuffle.
echo -n "Read $Words entries from '$1'. Shuffling.." >&2
for ((round=1; round<=13; round++)); do
    for ((i=1; i<=Words; i++)); do
        k=$[1 + RANDOM % Words]
        w1="${Word1[i]}"
        w2="${Word2[i]}"
        Word1[i]="${Word1[k]}"
        Word2[i]="${Word2[k]}"
        Word1[k]="$w1"
        Word2[k]="$w2"
    done
done
echo " and done." >&2

# Empty line is too easy to type, so let's make a . as the exit command.
echo "" >&2
echo "Press Ctrl+D or type only . to exit." >&2
echo "" >&2

correct=0
wrong=0
for ((i=1; i<=Words; i++)); do

    answer=""

    while [ "$answer" = "" ]; do
        printf '%d / %d: (%d out of %d correct thus far)\n\t  %s\n' $i $Words $correct $[correct+wrong] "${Word1[i]}"
        read -p $'\t> ' answer || answer="."
    done

    [ "$answer" = "." ] && break

    if [ "$answer" = "${Word2[i]}" ]; then
        correct=$[correct + 1]
        echo "Correct."
    else
        wrong=$[wrong + 1]
        echo "Incorrect. '${Word2[i]}'"
    fi
done

echo ""
echo "You answered $[i-1] of $Words questions."
echo "You got $correct out of $[correct+wrong] correct."
echo ""
The dictionary format is a bit different:
Code:
huang2       | yellow
shang4 ban1  | to go to work
er2 zi       | son
zo3          | left
x:ue2 sheng1 | student
The script itself will shuffle all the words automatically; the dictionary file is only read, nor modified.

You can liven up the output by sprinkling in suitable ANSI escape codes. Use either printf or echo -e and
Code:
\e[0;30m    black
\e[0;31m    red
\e[0;32m    green
\e[0;33m    brown/yellow
\e[0;34m    blue
\e[0;35m    magenta
\e[0;36m    cyan
\e[0;37m    light gray
\e[1;30m    dark gray
\e[1;31m    light red
\e[1;32m    light green
\e[1;33m    yellow
\e[1;34m    light blue
\e[1;35m    light magenta
\e[1;36m    light cyan
\e[1;37m    white
\e[0m       to return to default (recommended at end of each line)
 
Old 04-05-2012, 07:12 AM   #5
parminides
LQ Newbie
 
Registered: Apr 2012
Posts: 4

Original Poster
Rep: Reputation: Disabled
Wow, Nominal Animal. Thanks. It works like a charm.
 
Old 04-05-2012, 08:40 AM   #6
parminides
LQ Newbie
 
Registered: Apr 2012
Posts: 4

Original Poster
Rep: Reputation: Disabled
It even has extra features (like keeping score). I really appreciate your help.
 
  


Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
ClipMate Substitute for Linux Rud Linux - Software 5 03-24-2009 10:57 AM
Looking for a Linux Garage Band Substitute - Recommendations + which Distro to run un denzelthegnome Linux - Software 1 02-09-2008 10:18 AM
Use Linux as a substitute for UNIX? saiz66 Linux - General 12 09-15-2004 07:30 AM
Linux substitute for Zonelabs and Spybot? mjewell Linux - Software 3 01-19-2004 11:49 AM
Could there be a substitute of VB in RH Linux Alasis Linux - Software 3 09-10-2002 04:55 PM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 10:49 PM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration