ProgrammingThis forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
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 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?
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;
}
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.
#!/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)
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.