Rev 4 | Rev 7 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed
/*
* (C) Copyright 2010, 2011 by Andreas Theofilu <andreas@theosys.at>
* All rights reserved!
*/
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include <signal.h>
#include <syslog.h>
#include <errno.h>
#include <pthread.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <fcntl.h>
#include <netdb.h>
#include <netinet/in.h>
#include <sys/param.h>
#include <sys/ioctl.h>
#include <pwd.h>
#include <grp.h>
#include "sensor.h"
#include "usb_comm.h"
#include "heizung.h"
typedef struct
{
int wday;
ulong start;
ulong end;
float temp;
}HEIZUNG;
typedef struct HEIZINDEX
{
HEIZUNG *heizung;
struct HEIZINDEX *next;
}HEIZINDEX;
CONFIGURE configs;
HEIZINDEX *HeizFirst;
float ActTemperature;
float ActPressure;
static pthread_t pthr_pars, pthr_temp_pars;
// Prototypes
void daemon_start(int ignsigcld);
void *pthr_temperature(void *pV_data);
void *pthr_parser(void *pV_data);
void sig_child(void);
int parseCommand(int s1, char *cmd);
void changeToUser(char *, char *);
HEIZINDEX *allocateMemory(void);
HEIZINDEX *insertMemory(HEIZINDEX *pos);
void freeMemory(void);
HEIZINDEX *freeChainMember(HEIZINDEX *member);
void freeDay(int wday);
void insertMember(int wday, long endt, float temp);
int readHeizPlan(void);
int writeHeizPlan(void);
void readConf(void);
char *readLine(int fd, char *buf, int bufLen);
char *trim(char *str);
char *remove_string(char *str, char *search, char *ret);
static pthread_mutex_t fastmutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t fastmutex_ser = PTHREAD_MUTEX_INITIALIZER;
/*
* The main program, initializing everything and start the daemon.
*/
int main(int argc, char *argv[])
{
int fd, index;
HeizFirst = NULL;
readConf();
// Initialize USB
serialDev.fd = -1;
serialDev.switch_fd = -1;
serialDev.handle = NULL;
// Now daemonize this application
daemon_start(0);
changeToUser(&configs.User[0], &configs.Grp[0]);
// Now start our Thread
if (pthread_create(&pthr_pars, NULL, pthr_parser, (void *)0) != 0)
{
syslog (LOG_DAEMON,"Create of thread \"pthr_parser\" failed!");
return 1;
}
// Here we start another thread to read the temperature
if (pthread_create(&pthr_temp_pars, NULL, pthr_temperature, (void *)0) != 0)
{
syslog(LOG_DAEMON,"Create of thread \"pthr_temperature\" failed!");
pthread_cancel(pthr_pars);
return 1;
}
while (1)
sleep(3600);
pthread_exit(NULL);
return 0;
}
/*
* Detach application from console and make it a daemon.
*/
void daemon_start (int ignsigcld)
{
int childpid, fd;
if (getpid () == 1)
goto out;
#ifdef SIGTTOU
signal (SIGTTOU, SIG_IGN);
#endif
#ifdef SIGTTIN
signal (SIGTTIN, SIG_IGN);
#endif
#ifdef SIGTSTP
signal (SIGTSTP, SIG_IGN);
#endif
if ((childpid = fork ()) < 0)
fprintf (stderr, "Can't fork this child\n");
else if (childpid > 0)
exit (0);
if (setpgrp () == -1)
fprintf (stderr, "Can't change process group\n");
signal (SIGHUP, SIG_IGN);
if ((childpid = fork ()) < 0)
syslog (LOG_DAEMON, "Can't fork second child");
else if (childpid > 0)
exit (0); /* first child */
/* second child */
out:
for (fd = 0; fd < NOFILE; fd++)
close (fd);
errno = 0;
chdir ("/");
umask (0);
if (ignsigcld)
{
//#ifdef SIGTSTP
// signal (SIGCLD, sig_child);
//#else
signal (SIGCLD, SIG_IGN);
//#endif
}
}
void sig_child ()
{
#if defined(BSD) && !defined(sinix) && !defined(Linux)
int pid;
union wait status;
while ((pid = wait3 (&status, WNOHANG, (struct rusage *)0)) > 0)
;
#endif
}
void changeToUser(char *usr, char *grp)
{
gid_t gr_gid;
if (usr && strlen(usr))
{
/* get uid */
struct passwd *userpwd;
struct group *usergrp;
if ((userpwd = getpwnam(usr)) == NULL)
{
syslog(LOG_DAEMON,"no such user: %s", usr);
exit(EXIT_FAILURE);
}
if (!grp || strlen(grp) || (usergrp = getgrnam(grp)) == NULL)
{
if (grp && strlen(grp))
syslog(LOG_WARNING,"no such group: %s", grp);
gr_gid = userpwd->pw_gid;
}
else
gr_gid = usergrp->gr_gid;
if (setgid(gr_gid) == -1)
{
syslog(LOG_DAEMON,"cannot setgid of user %s: %s", usr, strerror(errno));
exit(EXIT_FAILURE);
}
#ifdef _BSD_SOURCE
/* init suplementary groups
* (must be done before we change our uid)
*/
if (initgroups(usr, gr_gid) == -1)
syslog(LOG_DAEMON,"cannot init suplementary groups of user %s: %s", usr, strerror(errno));
#endif
/* set uid */
if (setuid(userpwd->pw_uid) == -1)
{
syslog(LOG_DAEMON,"cannot change to uid of user %s: %s\n", usr, strerror(errno));
exit(EXIT_FAILURE);
}
if(userpwd->pw_dir)
setenv("HOME", userpwd->pw_dir, 1);
}
}
void *pthr_temperature(void *pV_data)
{
time_t t, tstart;
struct tm *zeit, sz;
int sleep_sec;
// Initialize the serial port.
serial_set_method((strlen(configs.Device)) ? 1 : 0, configs.VID, configs.PID);
if (strlen(configs.Device))
serial_set_device(configs.Device);
if (!serial_open())
return NULL;
if (serialDev.switch_fd == -1)
{
if (!serial_open())
return NULL;
}
pthread_mutex_lock (&fastmutex_ser);
while(1)
{
HEIZINDEX *act;
ActTemperature = GetTemp();
sleep_sec = 300;
// Compare the actual temperature with the one that should be
// and switch heating on or off
if (HeizFirst)
{
int wday;
unsigned long loctm;
t = time (NULL);
sleep_sec = 300 - (int)((t + 300L) % 300L);
sleep_sec++;
zeit = localtime (&t);
wday = (zeit->tm_wday == 0) ? 7 : zeit->tm_wday;
memset (&sz, 0, sizeof (struct tm));
sz.tm_min = 0;
sz.tm_hour = 0;
sz.tm_mon = zeit->tm_mon;
sz.tm_mday = zeit->tm_mday;
sz.tm_year = zeit->tm_year;
sz.tm_isdst = zeit->tm_isdst;
tstart = mktime(&sz);
loctm = t - tstart; // Seconds since midnight
act = HeizFirst;
syslog(LOG_INFO,"wday: %d, loctm: %lu", wday, loctm);
while(act)
{
if (act->heizung->wday == wday && loctm >= act->heizung->start && loctm <= act->heizung->end)
{
syslog(LOG_INFO,"wday: %d, loctm: %lu, endt: %lu, solltemp: %.1f", wday, loctm, act->heizung->start, act->heizung->temp);
if (ActTemperature == 9999.0)
SwitchOff(); // No temperature, no heating
else if (ActTemperature < 5.0)
SwitchOn(); // Make sure it will not freeze
else if (ActTemperature > 30.0)
SwitchOff(); // Don't over heat
else if (ActTemperature <= (act->heizung->temp - 0.5))
SwitchOn();
else if (ActTemperature > act->heizung->temp)
SwitchOff();
}
act = act->next;
}
}
else
syslog(LOG_INFO,"Structure not initialized!");
sleep(sleep_sec); // Wait 5 Minutes
}
pthread_mutex_unlock(&fastmutex_ser);
}
void *pthr_parser( void *pV_data )
{
int i;
char ch, buf[128];
// socket structure
struct sockaddr_in client1, server1;
struct servent *serviceInfo;
int s1,s;
socklen_t length;
// socket server
if (configs.port > 0)
server1.sin_port = htons(configs.port);
else if ((serviceInfo = getservbyname ("heizung", "tcp")))
server1.sin_port = serviceInfo->s_port;
else
{
syslog(LOG_DAEMON,"Error: No TCP port defined!");
exit(EXIT_FAILURE);
}
server1.sin_family = AF_INET;
server1.sin_addr.s_addr = INADDR_ANY;
s = socket(AF_INET,SOCK_STREAM,0);
if (s < 0)
syslog (LOG_DAEMON, "Error in socket");
if (bind (s, (struct sockaddr *)&server1, sizeof (server1)) < 0)
syslog (LOG_DAEMON, "Error in bind");
if (listen (s, 5) < 0)
syslog (LOG_DAEMON, "Error in listen");
length = sizeof(client1);
syslog (LOG_DEBUG, "Server ready: %d",s);
while (1)
{
// Read time table at every loop, to be sure to have the latest
// version (User may change it at every time)
if (!readHeizPlan())
{
if (!HeizFirst)
{
syslog(LOG_DAEMON, "Error reading table with plan!");
return NULL;
}
else
syslog(LOG_DAEMON, "Error reading table with plan! Will work with old one.");
}
if ((s1 = accept (s, (struct sockaddr *)&client1, &length)) < 0)
syslog (LOG_DAEMON, "Error in accept: %d", s1);
pthread_mutex_lock (&fastmutex);
syslog (LOG_INFO, "Connected to client");
memset(&buf[0], 0, sizeof(buf));
i = 0;
while (read(s1,&ch,1) > 0)
{
if (i < (sizeof(buf) - 1))
{
buf[i] = ch;
if (ch == ';' || ch == 0x0d)
{
if (!strncmp(buf, "quit", 4))
break;
if (!parseCommand(s1,buf))
{
char hv0[128];
sprintf(&hv0[0],"INVALID COMMAND: %s;",buf);
write(s1,hv0,strlen(hv0));
}
else
write(s1,"OK;",3);
memset(&buf[0], 0, sizeof(buf));
i = 0;
continue;
}
}
i++;
}
close (s1);
pthread_mutex_unlock(&fastmutex);
}
serial_close();
return NULL;
}
int parseCommand(int s1, char *cmd)
{
char bef[32],par[1024], *p;
char hv0[256];
int i,j;
HEIZINDEX *act, *last;
memset(bef,0,sizeof(bef));
memset(par,0,sizeof(par));
if ((p = strchr(cmd,':')) != NULL) // do we have a parameter?
{
strncpy(bef,cmd,p - cmd);
strncpy(par,p+1,strlen(p+1));
}
else
strncpy(bef,cmd,strlen(cmd)-1);
if (!strcasecmp(bef, "LIST")) // Write out current list
{
int wday = 1;
i = 1; // The line counter
// We will write out the week days in the correct order.
// So we need 2 loops. The first one is runnung for every week day
// and the 2nd one will find every entry for the actual week day.
while (wday <= 7)
{
act = HeizFirst;
while (act)
{
if (act->heizung->wday == wday)
{
sprintf(&hv0[0], "LINE:%d:%d:%lu:%lu:%.1f;", i, act->heizung->wday,
act->heizung->start, act->heizung->end, act->heizung->temp);
write(s1, &hv0[0], strlen(hv0));
i++;
}
act = act->next;
}
wday++;
}
}
if (!strcasecmp(bef, "GET WDAY")) // Write out a particular week day
{
int wday = atoi(par);
if (wday < 1 || wday > 7)
{
strcpy(&hv0[0], "ERROR:Invalid week day");
write(s1, &hv0[0], strlen(hv0));
return 0;
}
act = HeizFirst;
while (act && act->heizung->wday != wday)
act = act->next;
if (!act)
{
sprintf(&hv0[0], "ERROR:No plan for week day %d", wday);
write(s1, &hv0[0], strlen(hv0));
return 0;
}
i = 1;
while (act && act->heizung->wday == wday)
{
sprintf(&hv0[0], "LINE:%d:%d:%lu:%lu:%.1f;", i, act->heizung->wday,
act->heizung->start, act->heizung->end, act->heizung->temp);
write(s1, &hv0[0], strlen(hv0));
i++;
act = act->next;
}
}
if (!strcasecmp(bef, "GET TEMP")) // Return actual temperature
{
sprintf(&hv0[0], "TEMP:%.1f;", ActTemperature);
write(s1, &hv0[0], strlen(hv0));
}
if (!strcasecmp(bef, "GET PRESSURE")) // Return the actual air pressure
{
sprintf(&hv0[0], "PRESSURE:%.3f;", ActPressure);
write(s1, &hv0[0], strlen(hv0));
}
// SET DAY:<count>:<day>:<end1>:<temp>[:<end2>:<temp>[:...]];
// <count> number of entries following
// <day> The day of the week
// <end1> The end time
// <temp> The temperature wanted until end time is reached
//
if (!strcasecmp(bef, "SET DAY")) // Set the plan for a particular day
{
int count, wday, i;
long endt;
float temp;
count = atoi(par);
remove_string(par, ":", &hv0[0]);
wday = atoi(par);
freeDay(wday);
last = NULL;
if (count > 0)
{
for (i = 0; i < count; i++)
{
remove_string(par, ":", &hv0[0]);
endt = atol(par);
remove_string(par, ":", &hv0[0]);
temp = atof(par);
if ((act = allocateMemory()) == NULL)
{
syslog(LOG_DAEMON,"Error allocating memory for a temperature line.");
sprintf(&hv0[0], "ERROR:Not enough memory!");
write(s1, &hv0[0], strlen(hv0));
return 0;
}
act->heizung->wday = wday;
act->heizung->end = endt;
act->heizung->temp = temp;
if (last)
act->heizung->start = last->heizung->end;
else
act->heizung->start = 0L;
last = act;
}
writeHeizPlan();
}
}
// SET TEMP:<wday>:<end>:<temp>;
if (!strcasecmp(bef, "SET TEMP")) // Set the temperature for a particular day and line
{
int wday;
unsigned long endt;
float tmp;
wday = atoi(par);
remove_string(par, ":", &hv0[0]);
endt = atol(par);
remove_string(par, ":", &hv0[0]);
tmp = atof(par);
insertMember(wday, endt, tmp);
writeHeizPlan();
}
return 1;
}
/*
* Remove a complete day
*/
void freeDay(int wday)
{
HEIZINDEX *act, *next, *prev;
act = HeizFirst;
prev = NULL;
while(act)
{
if (act->heizung->wday == wday)
act = freeChainMember(act);
act = act->next;
}
}
/*
* Insert a new entry
*/
void insertMember(int wday, long endt, float temp)
{
HEIZINDEX *act;
act = HeizFirst;
while(act)
{
if (act->heizung->wday == wday && act->heizung->end == endt)
{
act->heizung->temp = temp;
return;
}
act = act->next;
}
if ((act = allocateMemory()) != NULL)
{
act->heizung->wday = wday;
act->heizung->end = endt;
act->heizung->temp = temp;
}
}
/*
* Free the memory for the actual heizung plan.
*/
void freeMemory()
{
HEIZINDEX *act, *next;
act = HeizFirst;
while(act)
{
if (act->heizung)
{
free(act->heizung);
act->heizung = NULL;
}
next = act->next;
free(act);
act = next;
}
HeizFirst = NULL;
}
/*
* Free only one entry in the chain
*/
HEIZINDEX *freeChainMember(HEIZINDEX *member)
{
HEIZINDEX *act,*prev;
act = HeizFirst;
prev = NULL;
while(act != member)
{
prev = act;
act = act->next;
}
if (act == member)
{
if (prev)
prev->next = act->next;
else
{
prev = act->next;
if (act == HeizFirst)
HeizFirst = act->next;
}
if (act->heizung)
free(act->heizung);
free(act);
return prev;
}
return NULL;
}
/*
* Allocate the memory for the actual heizung plan.
* This function appends an element to the end of the chain.
*/
HEIZINDEX *allocateMemory()
{
HEIZINDEX *act, *last;
if (!HeizFirst)
{
HeizFirst = malloc(sizeof(HEIZINDEX));
if (HeizFirst)
{
HeizFirst->heizung = malloc(sizeof(HEIZUNG));
HeizFirst->next = NULL;
}
else
return NULL;
return HeizFirst;
}
else
{
// Find last element
last = HeizFirst;
while(last->next)
last = last->next;
act = malloc(sizeof(HEIZINDEX));
if (act)
{
act->heizung = malloc(sizeof(HEIZUNG));
act->next = NULL;
last->next = act;
}
else
return NULL;
return act;
}
return NULL;
}
/*
* Allocate the memory for the actual heizung plan.
* This function inserts an element into the chain.
*/
HEIZINDEX *insertMemory(HEIZINDEX *pos)
{
HEIZINDEX *act;
if (!HeizFirst)
{
HeizFirst = malloc(sizeof(HEIZINDEX));
if (HeizFirst)
{
HeizFirst->heizung = malloc(sizeof(HEIZUNG));
HeizFirst->next = NULL;
}
else
return NULL;
return HeizFirst;
}
else
{
act = malloc(sizeof(HEIZINDEX));
if (act)
{
act->heizung = malloc(sizeof(HEIZUNG));
act->next = pos->next;
pos->next = act;
}
else
return NULL;
return act;
}
return NULL;
}
/*
* The following functions read a config file and put the
* contents into a structure.
*/
void readConf(void)
{
int fd;
char confFile[512], line[512];
char *home, *p;
char hv0[64], hv1[128];
home = getenv("HOME");
fd = -1;
if (!access("/etc/heizung.conf",R_OK))
strcpy(confFile,"/etc/heizung.conf");
else if (!access("/etc/heizung/heizung.conf",R_OK))
strcpy(confFile,"/etc/heizung/heizung.conf");
else if (!access("/usr/etc/heizung.conf",R_OK))
strcpy(confFile,"/usr/etc/heizung.conf");
else if (home)
{
strcpy(confFile,home);
strcat(confFile,"/.heizung.conf");
if (access(confFile,R_OK))
{
syslog(LOG_WARNING,"Even config file %s was not found!", confFile);
confFile[0] = 0;
}
}
else
confFile[0] = 0;
memset(&configs, 0, sizeof(configs));
strcpy(configs.User,"nobody");
strcpy(configs.Grp,"nobody");
strcpy(configs.HeizPath, "/var/www/.HeizPlan.conf");
strcpy(configs.Werte, "/var/log/werte.dat");
strcpy(configs.Device, "/dev/ttyS1");
configs.port = 11001;
if (!confFile[0] || (fd = open(confFile,O_RDONLY)) == -1)
{
if (confFile[0])
syslog(LOG_WARNING,"Error opening the config file %s! Using built in defaults. (%s)", confFile, strerror(errno));
else
syslog(LOG_WARNING,"Error opening the config file! Using built in defaults.");
return;
}
while (readLine(fd, &line[0], sizeof(line)) != NULL)
{
int len;
trim (&line[0]);
if (line[0] == '#' || !strlen(line))
continue;
if ((p = strchr (line, '=')) == NULL)
continue;
*p = 0;
p++;
len = strlen(line);
if (len > sizeof(hv0))
len = sizeof(hv0) - 1;
strncpy (hv0, line, len);
hv0[len] = 0;
trim (hv0);
len = strlen(p);
if (len > sizeof(hv1))
len = sizeof(hv0) - 1;
strncpy (hv1, p, len);
hv1[len] = 0;
trim (hv1);
if (!strcasecmp(hv0, "user"))
{
syslog(LOG_INFO,"Found \"user\": %s", hv1);
strncpy (configs.User, hv1, sizeof(configs.User));
}
if (!strcasecmp(hv0, "group"))
{
syslog(LOG_INFO,"Found \"group\": %s", hv1);
strncpy (configs.Grp, hv1, sizeof(configs.Grp));
}
if (!strcasecmp(hv0, "port"))
{
syslog(LOG_INFO,"Found \"port\": %s", hv1);
configs.port = atoi (hv1);
}
if (!strcasecmp(hv0, "heizpath"))
{
syslog(LOG_INFO,"Found \"heizpath\": %s", hv1);
strncpy (configs.HeizPath, hv1, sizeof(configs.HeizPath));
}
if (!strcasecmp(hv0, "Werte"))
{
syslog(LOG_INFO,"Found \"Werte\": %s", hv1);
strncpy (configs.Werte, hv1, sizeof(configs.Werte));
}
if (!strcasecmp(hv0, "Device"))
{
syslog(LOG_INFO,"Found \"Device\": %s", hv1);
strncpy (configs.Device, hv1, sizeof(configs.Device));
}
if (!strcasecmp(hv0, "VID"))
{
syslog(LOG_INFO,"Found VendorID: %04x", atoi(hv1));
configs.VID = atoi(hv1);
}
if (!strcasecmp(hv0, "PID"))
{
syslog(LOG_INFO,"Found ProductID: %04x", atoi(hv1));
configs.PID = atoi(hv1);
}
}
close (fd);
}
int readHeizPlan(void)
{
int fd, i, wday;
ulong tim;
char line[512];
char *p, *xp;
char hv0[64], hv1[128];
float temperature;
long offset = 0;
HEIZINDEX *act, *prev;
fd = -1;
if (access(configs.HeizPath, R_OK))
{
syslog(LOG_DAEMON,"Access to file %s denied: %s", configs.HeizPath, strerror(errno));
return 0;
}
if ((fd = open(configs.HeizPath, O_RDONLY)) == -1)
{
syslog(LOG_DAEMON,"Error opening file %s: %s", configs.HeizPath, strerror(errno));
return 0;
}
act = prev = NULL;
freeMemory();
while (readLine(fd, &line[0], sizeof(line)) != NULL)
{
int len;
trim (&line[0]);
if (line[0] == '#' || !strlen(line) || strchr(line, ',') == NULL)
continue;
// We need a place to store the information
prev = act;
if ((act = allocateMemory()) == NULL)
{
close(fd);
syslog(LOG_DAEMON,"Error allocating memory for a temperature line! Stopped reading file %s.", configs.HeizPath);
return 0;
}
memset(act->heizung, 0, sizeof(HEIZUNG));
// Parse a line. The line has the format:
// <wday>,<end>,<temperature>
p = strtok(line, ",");
i = 1;
while(p)
{
switch(i)
{
case 1: // Week day
wday = atoi(p);
if (wday < 1 || wday > 7) // valid line?
{
if (prev)
wday = prev->heizung->wday;
if (wday < 1 || wday > 7)
{
p = strtok(NULL, ",");
i++;
continue;
}
}
act->heizung->wday = wday;
act->heizung->start = 0;
break;
case 2: // start/end time
if ((xp = strchr(p, ':')) != NULL)
{
int hour, min;
hour = atoi(p);
min = atoi(xp+1);
if (hour >= 0 && hour <= 23 && min >= 0 && min <= 59)
{
act->heizung->end = hour * 3600 + min * 60 + 59;
if (prev && prev->heizung->wday == act->heizung->wday)
act->heizung->start = prev->heizung->end;
}
}
break;
case 3: // temperature
temperature = atof(p);
if (temperature < 5.0 || temperature > 30.0)
{
p = strtok(NULL,",");
i++;
continue;
}
act->heizung->temp = temperature;
break;
}
p = strtok(NULL, ",");
i++;
}
}
close (fd);
return 1;
}
/*
* write the (may be) altered plan.
* This function allways writes whole plan.
*/
int writeHeizPlan()
{
int fd;
char hv0[512];
HEIZINDEX *act;
fd = -1;
if (access(configs.HeizPath, R_OK))
return 0;
if ((fd = open(configs.HeizPath, O_RDWR | O_TRUNC)) == -1)
return 0;
act = HeizFirst;
while(act)
{
if (act->heizung->wday)
{
int hour, min;
hour = act->heizung->end / 3600;
min = (act->heizung->end - (hour * 3600)) / 60;
if (hour > 23)
{
hour = 23;
min = 59;
}
sprintf(&hv0[0], "%d,%02d:%02d,%.1f\n",
act->heizung->wday, hour, min,
act->heizung->temp);
write(fd, &hv0[0], strlen(hv0));
}
act = act->next;
}
close(fd);
return 1;
}
char *readLine(int fd, char *buf, int bufLen)
{
int i, end;
char ch, *p;
if (fd <= 0)
{
syslog(LOG_DAEMON,"Function readLine was called with an invalid file descriptor of %d!", fd);
return NULL;
}
i = end = 0;
p = buf;
while (read(fd, &ch, 1) > 0)
{
end = 1;
if (ch == 0x0a)
{
*p = 0;
return buf;
}
if (ch == 0x0d) // ignore this!
continue;
if (i < (bufLen - 1))
{
*p = ch;
p++;
i++;
}
}
*p = 0;
if (end)
return buf;
else
return NULL;
}
char *trim(char *str)
{
char *p1, *p2, *p;
if (!str)
return NULL;
if (!strlen(str))
return str;
p = str;
p1 = p2 = NULL;
while (*p)
{
if (!p1 && *p != ' ')
{
p1 = p;
break;
}
p++;
}
p2 = str + (strlen(str) - 1);
while (p2 > str && *p2 == ' ')
p2--;
if (p2)
*(p2+1) = 0;
if (p1)
{
char *buf = strdup (p1);
strcpy (str, buf);
free (buf);
}
return str;
}
char *remove_string(char *str, char *search, char *ret)
{
char *p;
if (!strlen(str) || !strlen(search))
return NULL;
if ((p = strstr(str, search)) != NULL)
{
int len = strlen(search);
strncpy(ret, str, p - str + len);
ret[p - str + len] = 0;
memmove(str, p + len, strlen(p+len));
str[strlen(p+len)] = 0;
return ret;
}
return NULL;
}