-
Your formatting can do with a bit more whitespace. This is just one example - I'm too lazy to copy and paste all instances where I think it should be formatted similar to this:
Code:
while (isdigit(*t) || *t == 'e' || *t == '+' || *t == '-' || *t == '.') { t++; offset++; }
should be:
Code:
while (isdigit(*t) || *t == 'e' || *t == '+' || *t == '-' || *t == '.')
{
t++;
offset++;
}
Also, I'd suggest you write a stack pop/push function:
Code:
--top; *top = atof(e);
...
b = *top; top++;
a = *top; top++;
--top; *top = postfix_apply(*e, a, b);
...
It would then also be simple to add some range checking to see if the expression fits on the stack.
--
Mats
-
Thanks Mats.
Yeah, I too noticed, that, my formatting was too dense, and hard on eyes.
But when I tidy up the code it becomes even harder to understand, the function that was fitting on one page now takes more. So it becomes very difficult to grasp the logic.
This is tidy version of arith example:
Code:
void arith_err_die(char *p, int offset, char *msg)
{
printf("%s\n", p);
while (offset--) printf(" ");
printf("^\n%s\n", msg);
exit(1);
}
double arith_apply(char op, double a, double b)
{
double t = 0.0;
if (op == '+')
{
t = a + b;
}
else if (op == '-')
{
t = a - b;
}
else if (op == 'x')
{
t = a * b;
}
else if (op == '/')
{
t = a / b;
}
else if (op == '^')
{
t = pow(a, b);
}
return t;
}
double arith(char *p)
{
double a, b;
int is_a, is_op;
int offset;
char *e, op;
e = p;
is_a = is_op = 0;
offset = 0;
while (*e)
{
if (*e == '-' && isdigit(e[1]) || isdigit(*e))
{
if (is_a)
{
if (is_op)
{
b = atof(e);
a = arith_apply(op, a, b);
is_op = 0;
}
else
{
arith_err_die(p, offset, "bad expression");
}
}
else
{
a = atof(e);
is_a = 1;
}
while (isdigit(*e) || *e == 'e' || *e == '+' || *e == '-' || *e == '.')
{
e++;
offset++;
}
}
else if (strchr("+-x/^", *e))
{
op = *e;
is_op = 1;
e++;
offset++;
}
else if (isspace(*e))
{
e++;
offset++;
}
else if (*e)
{
arith_err_die(p, offset, "bad token");
}
}
if (! is_a)
{
arith_err_die(p, offset, "bad expression");
}
return a;
}
PS: Sorry for the ill formatting. The code is properly formatted/indented in my source file. (I used 4 space tab, and replace tab with spaces option, using Crimson Editor). But after pasting here the formatting becomes ugly!
-
If a function gets too long to manage with proper formatting, then it's a sign that it needs to be split up.
I think you'll find that this:
Code:
a = atof(e);
is_a = 1;
}
while (isdigit(*e) || *e == 'e' || *e == '+' || *e == '-' || *e == '.')
{
e++;
offset++;
can be replaced with simpler logic if you use strtod() and make use of the end-pointer to know where the new e should be [you'd have to figure out how much to change "offset", but that shouldn't be too much of a problem]. As a side-effect, incorrectly written numbers [e.g."2.-+e5ee--+"] will not be skipped over [after parsing as 2.0] but you can report it as a bad number.
And, I find that in an if/else if branching tree, you take the simplest option first - in this case, isspace() - because it's just a case of skipping over it.
--
Mats
-
Kill a process by name (or command line):
[Linux specific may be]
Code:
#include <stdio.h>
int main(int argc, char **argv) {
int pid;
FILE *p;
char buff[256];
if (argc != 2) { return 1; }
snprintf(buff, sizeof(buff), "ps -a | grep -i %s", argv[1]);
p = popen(buff, "r");
if (! p) { return 2; }
fgets(buff, sizeof(buff), p);
pid = atoi(buff);
fclose(p);
snprintf(buff, sizeof(buff), "kill %d", pid);
system(buff);
return 0;
}
/* Usage:
* my-kill a.out
*/
-
my day time server
Code:
/*
* M Y - D A Y - T I M E - S E R V E R . C
*
* Day time server. Uses port 13, needs root permissions to run!
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <time.h>
#include <stdio.h>
#include <string.h>
#define DAY_TIME_PORT 13
char *get_time_str() {
time_t rawtime;
struct tm * timeinfo;
time(&rawtime);
timeinfo = localtime(&rawtime);
return asctime(timeinfo);
}
int main() {
struct sockaddr_in server_addr, client_addr;
int server_sock, client_sock;
socklen_t addr_size;
char *tmp;
if ((server_sock = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
perror("socket");
return 1;
}
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(DAY_TIME_PORT);
server_addr.sin_addr.s_addr = INADDR_ANY;
memset(&server_addr.sin_zero, '\0', sizeof server_addr.sin_zero);
if (bind(server_sock, (struct sockaddr*) &server_addr, sizeof server_addr) == -1) {
perror("bind");
return 2;
}
if (listen(server_sock, SOMAXCONN) == -1) {
perror("listen");
return 3;
}
printf("server listening at 13...\n");
while (1) {
addr_size = sizeof client_addr;
memset(&client_addr, '\0', addr_size);
if ((client_sock = accept(server_sock, (struct sockaddr*) &client_addr, &addr_size)) == -1) {
perror("accept");
return 4;
}
tmp = get_time_str();
printf("Client: %s port: %x (hex) at: %s\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port), tmp);
send(client_sock, tmp, strlen(tmp), 0);
shutdown(client_sock, 2);
close(client_sock);
}
return 0;
}
-
get host info
Code:
/*
* GET-HOST-INFO . C
*
* Get information for a host.
*/
#include <stdio.h>
#include <netdb.h>
#include <arpa/inet.h>
int main(int argc, char **argv) {
struct hostent *hent;
char *host, **p;
if (argc != 2) {
puts("\nUsage:\n\tget-host-info <host-name>\n"
"example:\n\tget-host-info mail.yahoo.com\n");
return 1;
} else {
host = argv[1];
}
if ((hent = gethostbyname(host)) == NULL) {
herror(argv[1]);
return 2;
}
printf("\n[%s]\n\n", host);
printf("Official name: %s\n", hent->h_name);
printf("Aliases:\n");
for (p = hent->h_aliases; *p; p++) {
printf("\t%s\n", *p);
}
if (p == hent->h_aliases) {
printf("\tnone\n");
}
printf("IP addresses:\n");
for (p = hent->h_addr_list; *p; p++) {
printf("\t%s\n", inet_ntoa(*((struct in_addr *)*p)));
}
return 0;
}