?
Solved

need help with cprogram

Posted on 2003-03-15
14
Medium Priority
?
279 Views
Last Modified: 2007-12-19
I need to write a cgi-bin program capitals.c that keeps information about the capital of a number of countries (at least ten) and, given as request parameter the country, returns the capital name. For example, if the country requested is America, it returns the information that "The capital of America is WashingtonDC" or "I do not know what is the capital of America".

How should i start, I tried to write something but was confused, do i need to make an array, I am not very good at C.

need help

 
0
Comment
Question by:ashi2
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 8
  • 6
14 Comments
 
LVL 2

Accepted Solution

by:
ewest earned 60 total points
ID: 8144980
This sounds like a homework exercise... Correct me if I am wrong.

As a general approach:

Create an array of structs, where each struct has two fields: name of country and name of capital

Each request for a capital amounts to a table lookup:

    for (i = 0; i < N; i++) {
        if (!strcmp(countries[i].country, user_input) {
              break;
        }
    }

    if (i == N) {
        printf("unknown country\n");
    } else {
        printf("capital = %s\n", countries[i].capital);
    }

I'll leave the rest to you...
0
 

Author Comment

by:ashi2
ID: 8146165
Thanx! evest, I think I got a idea of how to do I will do it and submit again to chk if i am doing right.

No its not an official homework excerise but sort of sample question, which I need to practise for exam.


0
 

Author Comment

by:ashi2
ID: 8146260
Hello ewest, This is what I tried but don't know if I doing right, how will i enter the capital, do i need another struct of it, can I do it togther.

include <stdio.h>

typedef struct       /* Define a structure */
{
  char Country[20];
  char *Capital[30];
} country = {
  "America",
  "Australia",
  "China".
  "CostaRica"
} ;

int main()
{
  printf("Enter the name of country to see its capital"\n");
  scanf(-----------

for (i = 0; i < N; i++) {
       if (!strcmp(countries[i].country, user_input) {
             break;
       }
   }

   if (i == N) {
       printf("unknown country\n");
   } else {
       printf("capital = %s\n", countries[i].capital);
   }

 
0
Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 2

Expert Comment

by:ewest
ID: 8146851
You can initialize the struct with

typedef struct       /* Define a structure */
{
 const char *Country;
 const char *Capital;
} country = {
 {"N.America", "Washington D.C."},
 {"Australia", "Canberra"},
 {"China", "Beijing"},
 {"CostaRica", "San Jose"},
 { NULL, NULL }
} ;

You are initializing an array of structs, not a simple array.
Note too I've initialized the table with string literals.

0
 

Author Comment

by:ashi2
ID: 8147129
what is the pupose of NULL NULL, not very clear with it
0
 
LVL 2

Expert Comment

by:ewest
ID: 8147808
These are just guard values. When you create a table lookup with string literals, you can scan until you hit a NULL guard value. Using guard values allows you to extend the table with additional entries without having to maintain a count value.

For example, using the guard value approach the lookup becomes:

     struct {
         char *name;
         int   value;
     } table[] = {{"blue",  1},
                  {"red",   2},
                  {"green", 3},
                  {NULL,   -1}};

   
    for (i=0; NULL != table[i].name; i++) {
           /* look for name */
    }

It should be apparent that I can add entries before the guard value without having to change the termination value of the for loop.

As I look at your code, I see you need to remove the typedef and add the array brackets:

          struct {
              const char * country;
              const char * capital;
          } countries[] = {
              {"N.America", "Washington DC"},
              {"Australia", "Canberra"},
                 ...
              { NULL, NULL }};


0
 

Author Comment

by:ashi2
ID: 8148077
this is what i changed in following, did i do rite, but I am stil having errors,

what does it mean, initialized country? I got this as an warning. and some other errors as countries not decleared but I fixed that.

#include <stdio.h>
#include <string.h>

 struct       /* Define a structure */
{
  const char *Country;
  const char *Capital;
} countries[] =
  {"N.America", "Washington D.C."},
  {"Australia", "Sydney"},
  {"China", "Beijing"},
  {"CostaRica", "San Jose"},
  {"Germany", "Berlin" },
  {"Iraq", "Baghdad"},
  {"Israel","Jerusalem"},
  {"Italy", "Rome"),
  {"Japan", "Tokyo"},
  {NULL,NULL}
};

int main(){
   int i,N;

  printf("Enter the name of Country to see its capital:\n");
 
for (i = 0; i < N; i++) {
  if (!strcmp(countries[i].country, user_input) {
    break;
  }
}
  if (i == N) {
    printf("unknown country\n");
  } else {
    printf("capital = %s\n", countries[i].capital);
  }
}
0
 
LVL 2

Expert Comment

by:ewest
ID: 8149012
I see you took my sample code snippet without filling in the "blanks". Your for loop as coded uses N as a limit. However N was not set to any known value. Worse it has a random value that may be greater than the maximum index to the countries array. If you  *really* want to use N. You can initialize it to the number of elements in countries with

     N = sizeof(countries)/sizeof(countries[0])

On the other hand, using the guard values, write the for loop as

     char *capital = NULL

     for (i = 0; NULL != countries[i]; i++) {
         if (!strcmp(countries[i].Country, user_input)) {
              capital = &countries[i].Capital;
              break;
         }
     }
     if (NULL == capital) {
          /* handle error */
     } else {
          /* found the capital */
     }

You still haven't addressed how to get the user supplied country name into user_input. In fact you haven't properly declared user_input.

Question: are you expected to be fluent in C for this exam?

0
 

Author Comment

by:ashi2
ID: 8149106
no not really, but still its high level and I am not good at it
0
 

Author Comment

by:ashi2
ID: 8188426
Hello ewest,

I need help  for web server code, this is an assignement, a web server is give to me and I have to make it as concurent server. I have written the code from Unix Network Programming book and understood the way they have explained it by using fork. but I am getting some errors and I am sure its the way I have placed it.

I am not sure if i should paste the code in here as my class mates must be seekign help from here, is it a way I can e-mail it to you, if not then I will post it here.


0
 
LVL 2

Expert Comment

by:ewest
ID: 8188787
I'd prefer to keep the "conversation" here in EE.

What errors are you getting?

Can you just post the relevant code snippets?
0
 

Author Comment

by:ashi2
ID: 8189824
ok ewest, I will post here,

this is 2 question on assignment. we are given a file tiny.c and I working just with that file.

I have to
1)Change this sequential server to be a concurrent server that forks a separate handler for each request. The handler will terminate when it completes its response. The parent must reap (have a wait statement) for the children.

2)All HTTP headers received and sent by the server should also be printed to the screen by the server. Try not to interleave lines from different interactions (here by interaction I mean a request or a response) of different handlers.

For reference I am taking help with UNIX Network Programming.

last nite I worked on it, and fix the errors atleast which I was getting with fork and signals, now I am trying to insert semaphores in my code and I am not getting, how can i insert semaphores code in my program though I have code written for semaphores.

also can u tell me if i have inserted fork and signals correctly. and for the second part printing http header where I should change. lastly how can i run, I start server and thenc client, I run the post as tiny 09872 &
then I go to client and comile after that the scren just goes away and does not let me type anything.

where ever I have made a change I have written as comment
//change here

following is the code

/* $begin tinymain */
/*
 * tiny.c - A simple, iterative HTTP/1.0 Web server that uses the
 *     GET method to serve static and dynamic content.
 */
#include "csapp.h"

#define dport 09872 // change here

void doit(int fd);
void read_requesthdrs(rio_t *rp);
int parse_uri(char *uri, char *filename, char *cgiargs);
void serve_static(int fd, char *filename, int filesize);
void get_filetype(char *filename, char *filetype);
void serve_dynamic(int fd, char *filename, char *cgiargs);
void clienterror(int fd, char *cause, char *errnum,
                 char *shortmsg, char *longmsg);

//change here
void sigchld_handler(int sig)
{
  while (waitpid(-1, 0, WNOHANG) > 0)
    ;
  return;
}
 

int main(int argc, char **argv)
{
    int listenfd, connfd, port, clientlen;
    struct sockaddr_in clientaddr;
   
   

    // pid_t childpid; //change here

    /* Check command line args */
    if (argc != 2) {
        fprintf(stderr, "usage: %s <port>\n", argv[0]);
        exit(1);
    }
    port = atoi(argv[1]);

   
     // making change here
Signal(SIGCHLD, sigchld_handler); // change here
    listenfd = Open_listenfd(port);
    while (1) {
        clientlen = sizeof(clientaddr);
        connfd = Accept(listenfd, (SA *)&clientaddr, &clientlen);
      if (Fork() == 0) { // change here
        // change here
      Close(listenfd); /* Child closes its listening socket */
        doit(connfd);
        Close(connfd);
      //change here
      exit(0); /* Child exits */
      }
      //change here
      Close(connfd); /* Parent closes connected socket (important!) */

    }
}
/* $end tinymain */

/*
 * doit - handle one HTTP request/response transaction
 */
/* $begin doit */
void doit(int fd)
{
    int is_static;
    struct stat sbuf;
    char buf[MAXLINE], method[MAXLINE], uri[MAXLINE], version[MAXLINE];
    char filename[MAXLINE], cgiargs[MAXLINE];
    rio_t rio;
 
    /* Read request line and headers */
    Rio_readinitb(&rio, fd);
    Rio_readlineb(&rio, buf, MAXLINE);
    sscanf(buf, "%s %s %s", method, uri, version);
    if (strcasecmp(method, "GET")) {
       clienterror(fd, method, "501", "Not Implemented",
                "Tiny does not implement this method");
        return;
    }
    read_requesthdrs(&rio);

    /* Parse URI from GET request */
    is_static = parse_uri(uri, filename, cgiargs);
    if (stat(filename, &sbuf) < 0) {
        clienterror(fd, filename, "404", "Not found",
                    "Tiny couldn't find this file");
        return;
    }

    if (is_static) { /* Serve static content */
        if (!(S_ISREG(sbuf.st_mode)) || !(S_IRUSR & sbuf.st_mode)) {
            clienterror(fd, filename, "403", "Forbidden",
                        "Tiny couldn't read the file");
            return;
        }
        serve_static(fd, filename, sbuf.st_size);
    }
    else { /* Serve dynamic content */
        if (!(S_ISREG(sbuf.st_mode)) || !(S_IXUSR & sbuf.st_mode)) {
            clienterror(fd, filename, "403", "Forbidden",
                        "Tiny couldn't run the CGI program");
            return;
        }
        serve_dynamic(fd, filename, cgiargs);
    }
}
/* $end doit */

/*
 * read_requesthdrs - read and parse HTTP request headers
 */
/* $begin read_requesthdrs */
void read_requesthdrs(rio_t *rp)
{
    char buf[MAXLINE];

    Rio_readlineb(rp, buf, MAXLINE);
    while(strcmp(buf, "\r\n"))
        Rio_readlineb(rp, buf, MAXLINE);
    return;
}
/* $end read_requesthdrs */

/*
 * parse_uri - parse URI into filename and CGI args
 *             return 0 if dynamic content, 1 if static
 */
/* $begin parse_uri */
int parse_uri(char *uri, char *filename, char *cgiargs)
{
    char *ptr;
    if (!strstr(uri, "cgi-bin")) {  /* Static content */
        strcpy(cgiargs, "");
        strcpy(filename, ".");
        strcat(filename, uri);
        if (uri[strlen(uri)-1] == '/')
            strcat(filename, "home.html");
        return 1;
    }
    else {  /* Dynamic content */
        ptr = index(uri, '?');
        if (ptr) {
            strcpy(cgiargs, ptr+1);
            *ptr = '\0';
        }
        else
            strcpy(cgiargs, "");
        strcpy(filename, ".");
        strcat(filename, uri);
        return 0;
    }
}
/* $end parse_uri */

/*
 * serve_static - copy a file back to the client
 */
/* $begin serve_static */
void serve_static(int fd, char *filename, int filesize)
{
    int srcfd;
    char *srcp, filetype[MAXLINE], buf[MAXBUF];
 
    /* Send response headers to client */
    get_filetype(filename, filetype);
    sprintf(buf, "HTTP/1.0 200 OK\r\n");
    sprintf(buf, "%sServer: Tiny Web Server\r\n", buf);
    sprintf(buf, "%sContent-length: %d\r\n", buf, filesize);
    sprintf(buf, "%sContent-type: %s\r\n\r\n", buf, filetype);
    Rio_writen(fd, buf, strlen(buf));

    /* Send response body to client */
    srcfd = Open(filename, O_RDONLY, 0);
    srcp = Mmap(0, filesize, PROT_READ, MAP_PRIVATE, srcfd, 0);
    Close(srcfd);
    Rio_writen(fd, srcp, filesize);
    Munmap(srcp, filesize);
}

/*
 * get_filetype - derive file type from file name
 */
void get_filetype(char *filename, char *filetype)
{
    if (strstr(filename, ".html"))
        strcpy(filetype, "text/html");
    else if (strstr(filename, ".gif"))
        strcpy(filetype, "image/gif");
    else if (strstr(filename, ".jpg"))
        strcpy(filetype, "image/jpeg");
    else
        strcpy(filetype, "text/plain");
}  
/* $end serve_static */

/*
 * serve_dynamic - run a CGI program on behalf of the client
 */
/* $begin serve_dynamic */
void serve_dynamic(int fd, char *filename, char *cgiargs)
{
    char buf[MAXLINE], *emptylist[] = { NULL };

    /* Return first part of HTTP response */
    sprintf(buf, "HTTP/1.0 200 OK\r\n");
    Rio_writen(fd, buf, strlen(buf));
    sprintf(buf, "Server: Tiny Web Server\r\n");
    Rio_writen(fd, buf, strlen(buf));
 
    if (Fork() == 0) { /* child */
        /* Real server would set all CGI vars here */
        setenv("QUERY_STRING", cgiargs, 1);
        Dup2(fd, STDOUT_FILENO);         /* Redirect stdout to client */
        Execve(filename, emptylist, environ); /* Run CGI program */
    }
    Wait(NULL); /* Parent waits for and reaps child */
}
/* $end serve_dynamic */

/*
 * clienterror - returns an error message to the client
 */
/* $begin clienterror */
void clienterror(int fd, char *cause, char *errnum,
                 char *shortmsg, char *longmsg)
{
    char buf[MAXLINE], body[MAXBUF];

    /* Build the HTTP response body */
    sprintf(body, "<html><title>Tiny Error</title>");
    sprintf(body, "%s<body bgcolor=""ffffff"">\r\n", body);
    sprintf(body, "%s%s: %s\r\n", body, errnum, shortmsg);
    sprintf(body, "%s<p>%s: %s\r\n", body, longmsg, cause);
    sprintf(body, "%s<hr><em>The Tiny Web server</em>\r\n", body);

    /* Print the HTTP response */
    sprintf(buf, "HTTP/1.0 %s %s\r\n", errnum, shortmsg);
    Rio_writen(fd, buf, strlen(buf));
    sprintf(buf, "Content-type: text/html\r\n");
    Rio_writen(fd, buf, strlen(buf));
    sprintf(buf, "Content-length: %d\r\n\r\n", strlen(body));
    Rio_writen(fd, buf, strlen(buf));
    Rio_writen(fd, body, strlen(body));
}
/* $end clienterror */

//#ifndef SEM_H
//# define SEM_H

//# include <sys/sem.h>
//# include <sys/types.h>
//# include <stdio.h>
//# include <stdlib.h>

//typedef int semaphore;

//void sem_init(semaphore *, int);
//void P(const semaphore *);
//void V(const semaphore *);
//void sem_destroy(const semaphore *);

//# define binary_sem_init(s) sem_init(s, 1);

//#endif

//sem.c

//#include "sem.h"

//static struct sembuf acquire = {0, -1, SEM_UNDO},
//release = {0,  1, SEM_UNDO};

//void sem_init(semaphore *s, int value)
//{
//*s = 0;

//if ((*s = semget(0, 1, IPC_CREAT | IPC_EXCL | 0600)) == -1) {
//  perror("sem_init: semget: ");
//  exit(1);
//}
//if(semctl(*s, 0, SETVAL, value) == -1) {
//  perror("sem_init: semctl: ");
//  exit(1);
// }
//}

//void P(const semaphore *s)
//{
//if (semop(*s, &acquire, 1) == -1) {
//  perror("P: ");
//  exit(1);
//}
//}

//void V(const semaphore *s)
//{
//if (semop(*s, &release, 1) == -1) {
//  perror("V: ");
//  exit(1);
//}
//}

//void sem_destroy(const semaphore *s)
//{
//if (semctl(*s, 0, IPC_RMID, NULL) == -1) {
//  perror("sem_destroy: semctl: ");
//   exit(1);
//}
//}


 
0
 

Author Comment

by:ashi2
ID: 8198583
its ok ewest,

I am done with it.
0
 
LVL 2

Expert Comment

by:ewest
ID: 8199922
Congrats!
0

Featured Post

Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Preface I don't like visual development tools that are supposed to write a program for me. Even if it is Xcode and I can use Interface Builder. Yes, it is a perfect tool and has helped me a lot, mainly, in the beginning, when my programs were small…
This is a short and sweet, but (hopefully) to the point article. There seems to be some fundamental misunderstanding about the function prototype for the "main" function in C and C++, more specifically what type this function should return. I see so…
Video by: Grant
The goal of this video is to provide viewers with basic examples to understand and use for-loops in the C programming language.
The goal of this video is to provide viewers with basic examples to understand how to create, access, and change arrays in the C programming language.
Suggested Courses
Course of the Month12 days, 18 hours left to enroll

777 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question