Commits (8)
/* Synchronet Control Panel (GUI Borland C++ Builder Project for Win32) */
/* $Id: StatsLogFormUnit.cpp,v 1.4 2018/07/24 01:11:29 rswindell Exp $ */
/****************************************************************************
* @format.tab-size 4 (Plain Text/Source Code File Header) *
* @format.use-tabs true (see http://www.synchro.net/ptsc_hdr.html) *
......@@ -15,21 +13,9 @@
* See the GNU General Public License for more details: gpl.txt or *
* http://www.fsf.org/copyleft/gpl.html *
* *
* Anonymous FTP access to the most recent released source is available at *
* ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net *
* *
* Anonymous CVS access to the development source and modification history *
* is available at cvs.synchro.net:/cvsroot/sbbs, example: *
* cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs login *
* (just hit return, no password is necessary) *
* cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs checkout src *
* *
* For Synchronet coding style and modification guidelines, see *
* http://www.synchro.net/source.html *
* *
* You are encouraged to submit any modifications (preferably in Unix diff *
* format) via e-mail to mods@synchro.net *
* *
* Note: If this box doesn't appear square, then you need to fix your tabs. *
****************************************************************************/
......@@ -37,13 +23,15 @@
#include <vcl.h>
#pragma hdrstop
#include <io.h> // filelength()
#include <stdio.h> // sprintf()
#include <time.h> // time_t
#include <fcntl.h> // O_RDONLY
#include <share.h>
#include "MainFormUnit.h"
#include "StatsLogFormUnit.h"
#include "getstats.h"
#include "dat_file.h"
#include "xpdatetime.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
......@@ -57,81 +45,43 @@ __fastcall TStatsLogForm::TStatsLogForm(TComponent* Owner)
void __fastcall TStatsLogForm::FormShow(TObject *Sender)
{
char str[256],path[256],*p;
BYTE *buf;
int i,file;
char ulbytes[32];
char dlbytes[32];
FILE* fp;
time_t timestamp;
struct tm* tm;
long l;
DWORD length,
logons,
timeon,
posts,
emails,
fbacks,
ulb,
uls,
dlb,
dls;
stats_t stats = {0};
sprintf(path,"%sCSTS.DAB",MainForm->global.ctrl_dir);
if((file=_sopen(path,O_RDONLY|O_BINARY,SH_DENYNO))==-1) {
sprintf(str,"!Error opening %s",path);
Log->Lines->Add(AnsiString(str));
return;
}
length=filelength(file);
if(length<40) {
close(file);
return;
}
if((buf=(char *)malloc(length))==NULL) {
close(file);
sprintf(str,"!Error allocating %lu bytes",length);
SAFEPRINTF(path, "%scsts.tab", MainForm->global.ctrl_dir);
if((fp = _fsopen(path, "rb", SH_DENYNO)) == NULL) {
SAFEPRINTF(str, "!Error opening %s", path);
Log->Lines->Add(AnsiString(str));
return;
}
read(file,buf,length);
close(file);
l=length-4;
while(l>-1L) {
fbacks=buf[l]|((long)buf[l+1]<<8)|((long)buf[l+2]<<16)
|((long)buf[l+3]<<24);
l-=4;
emails=buf[l]|((long)buf[l+1]<<8)|((long)buf[l+2]<<16)
|((long)buf[l+3]<<24);
l-=4;
posts=buf[l]|((long)buf[l+1]<<8)|((long)buf[l+2]<<16)
|((long)buf[l+3]<<24);
l-=4;
dlb=buf[l]|((long)buf[l+1]<<8)|((long)buf[l+2]<<16)
|((long)buf[l+3]<<24);
l-=4;
dls=buf[l]|((long)buf[l+1]<<8)|((long)buf[l+2]<<16)
|((long)buf[l+3]<<24);
l-=4;
ulb=buf[l]|((long)buf[l+1]<<8)|((long)buf[l+2]<<16)
|((long)buf[l+3]<<24);
l-=4;
uls=buf[l]|((long)buf[l+1]<<8)|((long)buf[l+2]<<16)
|((long)buf[l+3]<<24);
l-=4;
timeon=buf[l]|((long)buf[l+1]<<8)|((long)buf[l+2]<<16)
|((long)buf[l+3]<<24);
l-=4;
logons=buf[l]|((long)buf[l+1]<<8)|((long)buf[l+2]<<16)
|((long)buf[l+3]<<24);
l-=4;
timestamp=buf[l]|((long)buf[l+1]<<8)|((long)buf[l+2]<<16)
|((long)buf[l+3]<<24);
l-=4;
str_list_t columns = NULL;
Screen->Cursor=crHourGlass;
str_list_t* records = tabReadFile(fp, &columns);
fclose(fp);
long l;
COUNT_LIST_ITEMS(records, l);
for(--l; l >= 0; --l) {
parse_cstats(records[l], &stats);
timestamp=isoDateTime_to_time(strtoul(records[l][CSTATS_DATE], NULL, 10), 0);
timestamp-=(24*60*60); /* 1 day less than stamp */
tm=localtime(&timestamp);
sprintf(str,"%2.2d/%2.2d/%2.2d T:%5lu L:%3lu P:%3lu "
"E:%3lu F:%3lu U:%6luk %3lu D:%6luk %3lu"
,tm->tm_mon+1,tm->tm_mday,tm->tm_year%100,timeon,logons,posts,emails
,fbacks,ulb/1024,uls,dlb/1024,dls);
sprintf(str,"%u/%2.2d/%2.2d T:%5lu L:%3lu P:%3lu "
"E:%3lu F:%3lu U:%5s %5lu D:%5s %5lu N:%3lu"
,1900 + tm->tm_year,tm->tm_mon+1,tm->tm_mday
,stats.ttoday,stats.ltoday,stats.ptoday,stats.etoday
,stats.ftoday
,byte_estimate_to_str(stats.ulb, ulbytes, sizeof(ulbytes), 1, 0), stats.uls
,byte_estimate_to_str(stats.dlb, dlbytes, sizeof(dlbytes), 1, 0), stats.dls
,stats.nusers
);
Log->Lines->Add(AnsiString(str));
}
free(buf);
tabListFree(records);
strListFree(&columns);
Screen->Cursor=crDefault;
}
//---------------------------------------------------------------------------
......@@ -131,6 +131,16 @@ char* seconds_to_str(uint seconds, char* str)
return p;
}
/* Returns a duration in minutes into a string */
char* minutes_to_str(uint min, char* str, size_t size)
{
safe_snprintf(str, size, "%ud %uh %um"
,min / (24 *60)
,(min % (24 * 60)) / 60
,min % 60);
return str;
}
/****************************************************************************/
/****************************************************************************/
char* hhmmtostr(scfg_t* cfg, struct tm* tm, char* str)
......
......@@ -39,8 +39,9 @@ DLLEXPORT char * sectostr(uint sec, char *str);
DLLEXPORT char * seconds_to_str(uint, char*);
DLLEXPORT char * hhmmtostr(scfg_t* cfg, struct tm* tm, char* str);
DLLEXPORT char * timestr(scfg_t* cfg, time32_t intime, char* str);
DLLEXPORT char* minutes_to_str(uint min, char* str, size_t);
#ifdef __cplusplus
}
#endif
#endif /* Don't add anything after this line */
\ No newline at end of file
#endif /* Don't add anything after this line */
......@@ -293,6 +293,20 @@ BOOL fwrite_cstats(FILE* fp, const stats_t* stats)
return fprintf(fp, "%.*s\n", (int)(sizeof(pad) - (len + 1)), pad) > 0;
}
void parse_cstats(str_list_t record, stats_t* stats)
{
stats->ltoday = strtoul(record[CSTATS_LOGONS], NULL, 10);
stats->ttoday = strtoul(record[CSTATS_TIMEON], NULL, 10);
stats->nusers = strtoul(record[CSTATS_NUSERS], NULL, 10);
stats->ftoday = strtoul(record[CSTATS_FBACKS], NULL, 10);
stats->etoday = strtoul(record[CSTATS_EMAIL], NULL, 10);
stats->ptoday = strtoul(record[CSTATS_POSTS], NULL, 10);
stats->uls = strtoul(record[CSTATS_UPLOADS], NULL, 10);
stats->ulb = strtoull(record[CSTATS_UPLOADB], NULL, 10);
stats->dls = strtoul(record[CSTATS_DNLOADS], NULL, 10);
stats->dlb = strtoull(record[CSTATS_DNLOADB], NULL, 10);
}
/****************************************************************************/
/* Returns the number of files in the directory 'dirnum' */
/****************************************************************************/
......
......@@ -37,6 +37,7 @@ DLLEXPORT BOOL fclose_dstats(FILE*);
DLLEXPORT BOOL fread_dstats(FILE*, stats_t*);
DLLEXPORT BOOL fwrite_dstats(FILE*, const stats_t*);
DLLEXPORT BOOL fwrite_cstats(FILE*, const stats_t*);
DLLEXPORT void parse_cstats(str_list_t, stats_t*);
DLLEXPORT BOOL getstats(scfg_t*, uint node, stats_t*);
DLLEXPORT BOOL putstats(scfg_t*, uint node, const stats_t*);
DLLEXPORT ulong getposts(scfg_t*, uint subnum);
......
......@@ -1087,6 +1087,19 @@ typedef struct { /* System/Node Statistics */
} stats_t;
#define LEN_CSTATS_RECORD 128
enum CSTATS_FIELD {
CSTATS_DATE
,CSTATS_LOGONS
,CSTATS_TIMEON
,CSTATS_UPLOADS
,CSTATS_UPLOADB
,CSTATS_DNLOADS
,CSTATS_DNLOADB
,CSTATS_POSTS
,CSTATS_EMAIL
,CSTATS_FBACKS
,CSTATS_NUSERS
};
typedef struct { /* Sub-board scan information */
uint16_t cfg; /* User's configuration */
......
/* SLOG.C */
/* Statistics Log Viewer */
/* Developed 1990-1997 by Rob Swindell; PO Box 501, Yorba Linda, CA 92885 */
/****************************************************************************
* @format.tab-size 4 (Plain Text/Source Code File Header) *
* @format.use-tabs true (see http://www.synchro.net/ptsc_hdr.html) *
* *
* Copyright Rob Swindell - http://www.synchro.net/copyright.html *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License *
* as published by the Free Software Foundation; either version 2 *
* of the License, or (at your option) any later version. *
* See the GNU General Public License for more details: gpl.txt or *
* http://www.fsf.org/copyleft/gpl.html *
* *
* For Synchronet coding style and modification guidelines, see *
* http://www.synchro.net/source.html *
* *
* Note: If this box doesn't appear square, then you need to fix your tabs. *
****************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <time.h>
#include <errno.h>
#include <stdbool.h>
#include "sbbsdefs.h"
#include "nopen.h"
#include "dirwrap.h"
#include "conwrap.h"
#include "sbbs.h"
#include "dat_file.h"
/****************************************************************************/
/* Lists system statistics for everyday the bbs has been running. */
......@@ -22,102 +31,121 @@
int main(int argc, char **argv)
{
char str[256],dir[256]={""},*p;
uchar *buf;
int i,file,pause=0,lncntr=0;
FILE* fp;
int i, lncntr=0, rows=20;
uint days = 0;
uint count = 0;
bool pause = false;
time_t timestamp;
long l;
off_t length;
ulong logons,
timeon,
posts,
emails,
fbacks,
ulb,
uls,
dlb,
dls;
time_t yesterday;
struct tm *curdate;
stats_t stats = {0};
totals_t total = {0};
bool totals = false;
time_t yesterday;
struct tm* tm;
ZERO_VAR(total);
printf("\nSynchronet System/Node Statistics Log Viewer v2.0\n\n");
printf("\nSynchronet System/Node Statistics Log Viewer v1.02\n\n");
for(i=1;i<argc;i++) {
if(stricmp(argv[i],"/P") == 0 || strncmp(argv[i], "-p", 2) == 0) {
pause = true;
if(IS_DIGIT(argv[i][2]))
rows = atoi(argv[i] + 2);
}
else if(strcmp(argv[i],"-t") == 0)
totals = true;
else if(strncmp(argv[i], "-d", 2) == 0)
days = atoi(argv[i] + 2);
else if(isdir(argv[i]))
SAFECOPY(dir, argv[i]);
else {
fprintf(stderr, "usage: %s [-opt [...]] [path]\n"
"\n"
" opts:\n"
"\t-p[rows] enable screen pause prompt\n"
"\t-d<days> specify maximum number of days\n"
"\t-t display totals\n"
,argv[0]
);
return EXIT_SUCCESS;
}
}
if(!dir[0]) {
p=getenv("SBBSCTRL");
if(p == NULL)
p = SBBSCTRL_DEFAULT;
SAFECOPY(dir,p);
}
for(i=1;i<argc;i++)
if(!stricmp(argv[i],"/P"))
pause=1;
else
SAFECOPY(dir,argv[1]);
if(!dir[0]) {
p=getenv("SBBSCTRL");
if(p!=NULL)
SAFECOPY(dir,p); }
backslash(dir);
backslash(dir);
SAFEPRINTF(str,"%scsts.tab",dir);
if(!fexistcase(str)) {
fprintf(stderr, "%s does not exist\n",str);
return EXIT_FAILURE;
}
if((fp = fopen(str, "rb")) == NULL) {
fprintf(stderr, "Error %d opening %s\n", errno, str);
return EXIT_FAILURE;
}
SAFEPRINTF(str,"%scsts.dab",dir);
if(!fexistcase(str)) {
printf("%s does not exist\r\n",str);
return(1); }
if((file=nopen(str,O_RDONLY))==-1) {
printf("Error opening %s\r\n",str);
return(1); }
length=filelength(file);
if(length<40) {
close(file);
return(1); }
if((buf=malloc((size_t)length))==0) {
close(file);
printf("error allocating %lu bytes\r\n",(ulong)length);
return(1); }
read(file,buf,(uint)length);
close(file);
l=(long)(length-4);
while(l>-1L) {
fbacks=buf[l]|((long)buf[l+1]<<8)|((long)buf[l+2]<<16)
|((long)buf[l+3]<<24);
l-=4;
emails=buf[l]|((long)buf[l+1]<<8)|((long)buf[l+2]<<16)
|((long)buf[l+3]<<24);
l-=4;
posts=buf[l]|((long)buf[l+1]<<8)|((long)buf[l+2]<<16)
|((long)buf[l+3]<<24);
l-=4;
dlb=buf[l]|((long)buf[l+1]<<8)|((long)buf[l+2]<<16)
|((long)buf[l+3]<<24);
l-=4;
dls=buf[l]|((long)buf[l+1]<<8)|((long)buf[l+2]<<16)
|((long)buf[l+3]<<24);
l-=4;
ulb=buf[l]|((long)buf[l+1]<<8)|((long)buf[l+2]<<16)
|((long)buf[l+3]<<24);
l-=4;
uls=buf[l]|((long)buf[l+1]<<8)|((long)buf[l+2]<<16)
|((long)buf[l+3]<<24);
l-=4;
timeon=buf[l]|((long)buf[l+1]<<8)|((long)buf[l+2]<<16)
|((long)buf[l+3]<<24);
l-=4;
logons=buf[l]|((long)buf[l+1]<<8)|((long)buf[l+2]<<16)
|((long)buf[l+3]<<24);
l-=4;
timestamp=buf[l]|((long)buf[l+1]<<8)|((long)buf[l+2]<<16)
|((long)buf[l+3]<<24);
l-=4;
yesterday=timestamp-(24*60*60); /* 1 day less than stamp */
curdate=localtime(&yesterday);
printf("%2.2d/%2.2d/%2.2d T:%5lu L:%3lu P:%3lu "
"E:%3lu F:%3lu U:%6luk %3lu D:%6luk %3lu\n"
,curdate->tm_mon+1,curdate->tm_mday,curdate->tm_year%100,timeon,logons,posts,emails
,fbacks,ulb/1024,uls,dlb/1024,dls);
lncntr++;
if(pause && lncntr>=20) {
printf("More (Y/n) ? ");
fflush(stdout);
int ch = getchar();
if(ch == CTRL_C || toupper(ch) == 'N')
str_list_t columns = NULL;
str_list_t* records = tabReadFile(fp, &columns);
fclose(fp);
long l;
COUNT_LIST_ITEMS(records, l);
for(--l; l >= 0; --l) {
parse_cstats(records[l], &stats);
timestamp = isoDateTime_to_time(strtoul(records[l][CSTATS_DATE], NULL, 10), 0);
yesterday = timestamp-(24*60*60); /* 1 day less than stamp */
tm = localtime(&yesterday);
printf("%02d/%02d/%02d", tm->tm_year % 100, tm->tm_mon + 1, tm->tm_mday);
printf(" T:%4lu L:%3lu P:%3lu E:%3lu F:%3lu"
,stats.ttoday, stats.ltoday, stats.ptoday, stats.etoday, stats.ftoday);
printf(" U:%5s %5lu"
,byte_estimate_to_str(stats.ulb, str, sizeof(str), 1, 0), stats.uls);
printf(" D:%5s %5lu"
,byte_estimate_to_str(stats.dlb, str, sizeof(str), 1, 0), stats.dls);
printf(" N:%2lu\n", stats.nusers);
total.timeon += stats.ttoday;
total.logons += stats.ltoday;
total.posts += stats.ptoday;
total.email += stats.etoday;
total.fbacks += stats.ftoday;
total.uls += stats.uls;
total.ulb += stats.ulb;
total.dls += stats.dls;
total.dlb += stats.dlb;
total.nusers += stats.nusers;
lncntr++;
count++;
if(days && count >= days)
break;
printf("\r");
lncntr=0; } }
free(buf);
return(0);
if(pause && lncntr>=rows) {
printf("More (Y/n) ? ");
fflush(stdout);
int ch = getchar();
if(ch == CTRL_C || toupper(ch) == 'N')
break;
printf("\r");
lncntr=0; }
}
if(totals) {
printf("\n");
printf("%10s\n", "===TOTAL===");
char sep = ',';
printf("%10s : %13s\n", columns[CSTATS_TIMEON], minutes_to_str(total.timeon, str, sizeof(str)));
printf("%10s : %13s\n", columns[CSTATS_LOGONS], u32toac(total.logons, str, sep));
printf("%10s : %13s\n", columns[CSTATS_POSTS], u32toac(total.posts, str, sep));
printf("%10s : %13s\n", "Email Sent", u32toac(total.email, str, sep));
printf("%10s : %13s\n", "Feedbacks", u32toac(total.fbacks, str, sep));
printf("%10s : %13s\n", "New Users", u32toac(total.nusers, str, sep));
printf("%10s : %7s bytes", "Uploads", byte_estimate_to_str(total.ulb, str, sizeof(str), 1, 1));
printf(" in %s files\n", u32toac(total.uls, str, sep));
printf("%10s : %7s bytes", "Downloads", byte_estimate_to_str(total.dlb, str, sizeof(str), 1, 1));
printf(" in %s files\n", u32toac(total.dls, str, sep));
}
return EXIT_SUCCESS;
}
......@@ -37,6 +37,7 @@
<Import Project="..\build\undeprecate.props" />
<Import Project="..\build\target_ia32.props" />
<Import Project="..\hash\hash.props" />
<Import Project="..\encode\encode.props" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
......@@ -46,6 +47,7 @@
<Import Project="..\build\undeprecate.props" />
<Import Project="..\build\target_ia32.props" />
<Import Project="..\hash\hash.props" />
<Import Project="..\encode\encode.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
......@@ -138,12 +140,6 @@
</Bscmake>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="nopen.c">
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<ClCompile Include="slog.c">
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
......@@ -156,6 +152,9 @@
<Project>{7428a1e8-56b7-4868-9c0e-29d031689feb}</Project>
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
</ProjectReference>
<ProjectReference Include="sbbs.vcxproj">
<Project>{48637a68-3478-4bed-a924-07d59d474bbe}</Project>
</ProjectReference>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
......
......@@ -2465,6 +2465,9 @@ BOOL user_posted_msg(scfg_t* cfg, user_t* user, int count)
user->posts =(ushort)adjustuserrec(cfg, user->number, U_POSTS, count);
user->ptoday=(ushort)adjustuserrec(cfg, user->number, U_PTODAY, count);
if(user->rest & FLAG('Q'))
return TRUE;
return inc_post_stats(cfg, count);
}
......
/* dat_file.c */
/* Functions to deal with comma (CSV) and tab-delimited files and lists */
/* $Id: dat_file.c,v 1.8 2018/07/24 01:13:09 rswindell Exp $ */
/****************************************************************************
* @format.tab-size 4 (Plain Text/Source Code File Header) *
* @format.use-tabs true (see http://www.synchro.net/ptsc_hdr.html) *
......@@ -15,23 +11,11 @@
* as published by the Free Software Foundation; either version 2 *
* of the License, or (at your option) any later version. *
* See the GNU Lesser General Public License for more details: lgpl.txt or *
* http://www.fsf.org/copyleft/lesser.html *
* *
* Anonymous FTP access to the most recent released source is available at *
* ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net *
* *
* Anonymous CVS access to the development source and modification history *
* is available at cvs.synchro.net:/cvsroot/sbbs, example: *
* cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs login *
* (just hit return, no password is necessary) *
* cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs checkout src *
* https://www.gnu.org/licenses/old-licenses/lgpl-2.0.html *
* *
* For Synchronet coding style and modification guidelines, see *
* http://www.synchro.net/source.html *
* *
* You are encouraged to submit any modifications (preferably in Unix diff *
* format) via e-mail to mods@synchro.net *
* *
* Note: If this box doesn't appear square, then you need to fix your tabs. *
****************************************************************************/
......@@ -288,3 +272,26 @@ str_list_t* dataReadFile(FILE* fp, str_list_t* columns, dataLineParser_t linePar
return(records);
}
BOOL dataListFree(str_list_t* list)
{
size_t i;
if(list == NULL)
return FALSE;
for(i=0; list[i]!=NULL; i++)
strListFree(&list[i]);
strListFree(list);
return TRUE;
}
FILE* dataOpenFile(const char* path, const char* mode)
{
return fopen(path, mode);
}
int dataCloseFile(FILE* fp)
{
return fclose(fp);
}
......@@ -58,6 +58,9 @@ str_list_t* dataReadFile(FILE* fp, str_list_t* columns, dataLineParser_t);
str_list_t dataCreateList(const str_list_t records[], const str_list_t columns, dataLineCreator_t);
BOOL dataWriteFile(FILE* fp, const str_list_t records[], const str_list_t columns
,const char* separator, dataLineCreator_t);
FILE* dataOpenFile(const char* path, const char* mode);
int dataCloseFile(FILE*);
BOOL dataListFree(str_list_t*);
/* CSV (comma separated value) API */
char* csvLineCreator(const str_list_t);
......@@ -66,6 +69,9 @@ str_list_t csvLineParser(const char* line);
#define csvCreateList(rec,col) dataCreateList(rec,col,csvLineCreator)
#define csvReadFile(fp,col) dataReadFile(fp,col,csvLineParser)
#define csvWriteFile(fp,rec,sep,col) dataWriteFile(fp,rec,col,sep,csvLineCreator)
#define cvsOpenFile(path, mode) dataOpenFile(path, mode)
#define csvCloseFile(fp) dataCloseFile(fp)
#define cvsListFree(list) dataListFree(list)
/* Tab-delimited API */
char* tabLineCreator(const str_list_t);
......@@ -74,6 +80,9 @@ str_list_t tabLineParser(const char* line);
#define tabCreateList(rec,col) dataCreateList(rec,col,tabLineCreator)
#define tabReadFile(fp,col) dataReadFile(fp,col,tabLineParser)
#define tabWriteFile(fp,rec,sep,col) dataWriteFile(fp,rec,col,sep,tabLineCreator)
#define tabOpenFile(path, mode) dataOpenFile(path, mode)
#define tabCloseFile(fp) dataCloseFile(fp)
#define tabListFree(list) dataListFree(list)
#if defined(__cplusplus)
}
......
......@@ -314,9 +314,10 @@ int globi(const char *p, int flags,
{
char pattern[MAX_PATH * 2] = "";
int len = 0;
char* fname = getfname(p);
char* fname;
if(p != NULL) {
fname = getfname(p);
while(*p != '\0' && len < MAX_PATH) {
if(p >= fname && IS_ALPHA(*p))
len += sprintf(pattern + len, "[%c%c]", toupper(*p), tolower(*p));
......
......@@ -144,5 +144,5 @@ BOOL semfile_signal(const char* fname, const char* text)
/* update the time stamp */
ut.actime = ut.modtime = time(NULL);
return utime(fname, &ut)==0 && wrlen == textlen;
return utime(fname, &ut)==0 && wrlen == (ssize_t)textlen;
}