33 #if defined(__MINGW32__) && defined(HAVE_DIRECT_H)
38 #if defined(HAVE_BACKTRACE)
39 #define USE_GETWORD_BACKTRACE 1
41 #define USE_GETWORD_BACKTRACE 0
44 static char mtab1[12][4]={
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
"Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec"};
54 #if USE_GETWORD_BACKTRACE
55 static void getword_backtrace(
void)
61 n=backtrace(buffer,
sizeof(buffer)/
sizeof(buffer[0]));
63 calls=backtrace_symbols(buffer,n);
65 debuga(__FILE__,__LINE__,
_(
"getword backtrace:\n"));
66 for (i=0 ; i<n ; i++) {
67 fprintf(stderr,
"SARG: %d:%s\n",i+1,calls[i]);
72 #endif //USE_GETWORD_BACKTRACE
84 debuga(__FILE__,__LINE__,
_(
"Cannot parse again the line as it was modified\n"));
94 for (x=0;((gwarea->
current[x]) && (gwarea->
current[x] != stop ));x++) {
100 debuga(__FILE__,__LINE__,
_(
"End of word not found in %s after %d bytes.\n"),__func__,x);
103 debuga(__FILE__,__LINE__,
_(
"searching for \'x%x\'\n"),stop);
104 word[(limit>0) ? limit-1 : 0]=
'\0';
105 #if USE_GETWORD_BACKTRACE
124 for (x=0; x<limit && gwarea->
current[x] && gwarea->
current[x] != stop ;x++) {
138 for (x=0;((gwarea->
current[x]) && (gwarea->
current[x] != stop ));x++) {
140 debuga(__FILE__,__LINE__,
_(
"End of word not found in %s after %d bytes.\n"),__func__,x);
143 debuga(__FILE__,__LINE__,
_(
"searching for \'x%x\'\n"),stop);
144 if (limit>0) word[limit-1]=
'\0';
145 #if USE_GETWORD_BACKTRACE
164 for (x=0;(gwarea->
current[x] && (gwarea->
current[x] != stop ));x++) {
166 debuga(__FILE__,__LINE__,
_(
"End of word not found in %s after %d bytes.\n"),__func__,x);
169 debuga(__FILE__,__LINE__,
_(
"searching for \'x%x\'\n"),stop);
170 #if USE_GETWORD_BACKTRACE
188 if (gwarea->
current[0] ==
'-') {
191 }
else if (gwarea->
current[0] ==
'+') {
195 for (x=0;isdigit(gwarea->
current[x]);x++) {
197 if (*number >= (LLONG_MAX-digit)/10) {
202 debuga(__FILE__,__LINE__,
_(
"Integer overflow detected in %s in line %s\n"),__func__,gwarea->
beginning);
205 *number=(*number * 10) + digit;
211 debuga(__FILE__,__LINE__,
_(
"End of number not found in %s after %d bytes.\n"),__func__,x);
214 debuga(__FILE__,__LINE__,
_(
"searching for \'x%x\'\n"),stop);
215 #if USE_GETWORD_BACKTRACE
233 if (gwarea->
current[0] ==
'-') {
236 }
else if (gwarea->
current[0] ==
'+') {
240 for (x=0;isdigit(gwarea->
current[x]);x++) {
242 if (*number > (INT_MAX-digit)/10) {
243 debuga(__FILE__,__LINE__,
_(
"Integer overflow detected in %s in line %s\n"),__func__,gwarea->
beginning);
246 *number=(*number * 10) + digit;
249 debuga(__FILE__,__LINE__,
_(
"End of number not found in %s after %d bytes.\n"),__func__,x);
252 debuga(__FILE__,__LINE__,
_(
"searching for \'x%x\'\n"),stop);
253 #if USE_GETWORD_BACKTRACE
271 if (gwarea->
current[0] ==
'-') {
274 }
else if (gwarea->
current[0] ==
'+') {
278 for (x=0;isdigit(gwarea->
current[x]);x++) {
280 if (*number > (LONG_MAX-digit)/10) {
281 debuga(__FILE__,__LINE__,
_(
"Integer overflow detected in %s in line %s\n"),__func__,gwarea->
beginning);
284 *number=(*number * 10) + digit;
287 debuga(__FILE__,__LINE__,
_(
"End of number not found in %s after %d bytes.\n"),__func__,x);
290 debuga(__FILE__,__LINE__,
_(
"searching for \'x%x\'\n"),stop);
291 #if USE_GETWORD_BACKTRACE
308 if (gwarea->
current[0] ==
'-') {
309 debuga(__FILE__,__LINE__,
_(
"getword_atolu got a negative number.\n"));
314 if (gwarea->
current[0] ==
'+') {
318 for (x=0;isdigit(gwarea->
current[x]);x++) {
320 if (*number > (ULONG_MAX-digit)/10) {
321 debuga(__FILE__,__LINE__,
_(
"Integer overflow detected in %s in line %s\n"),__func__,gwarea->
beginning);
324 *number=(*number * 10) + digit;
327 debuga(__FILE__,__LINE__,
_(
"End of number not found in %s after %d bytes.\n"),__func__,x);
330 debuga(__FILE__,__LINE__,
_(
"searching for \'x%x\'\n"),stop);
331 #if USE_GETWORD_BACKTRACE
355 if (orig_line && orig_line!=gwarea->
beginning) {
356 debuga(__FILE__,__LINE__,
_(
"Invalid buffer passed to getword_ptr\n"));
361 if (word && orig_line) *word=orig_line+start;
362 for (x=0;((gwarea->
current[x]) && (gwarea->
current[x] != stop ));x++);
363 sep=(gwarea->
current[x]!=
'\0');
364 if (word && orig_line) orig_line[start+x] =
'\0';
372 long long int my_atoll (const char *nptr)
374 long long int returnval=0LL;
378 while (isspace( *nptr )) {
386 while (--max_digits && isdigit( *nptr ))
388 returnval = ( returnval * 10 ) + ( *nptr++ -
'0' ) ;
396 if (*path==
'/')
return(1);
398 if (isalpha(path[0]) && path[1]==
':')
return(1);
405 #if defined(__linux__)
406 int mkerror=mkdir(path,mode);
409 int mkerror=_mkdir(path);
424 bool created =
false;
428 debuga(__FILE__,__LINE__,
_(
"Invalid path (%s). Please, use absolute paths only.\n"),
name);
433 for (i=0 ;
name[i] ; i++) {
435 debuga(__FILE__,__LINE__,
_(
"Path too long: "));
439 if (chars>0 &&
name[i] ==
'/') {
441 if (access(w0, R_OK) != 0) {
443 debuga(__FILE__,__LINE__,
_(
"Cannot create directory \"%s\": %s\n"),w0,strerror(errno));
448 if (
name[i] !=
'/') chars++;
452 if (access(
name, R_OK) != 0) {
454 debuga(__FILE__,__LINE__,
_(
"Cannot create directory \"%s\": %s\n"),
name,strerror(errno));
463 if (stat(
name, &st)) {
464 debuga(__FILE__,__LINE__,
_(
"Cannot stat \"%s\": %s\n"),
name, strerror(errno));
467 if (!S_ISDIR(st.st_mode)) {
468 debuga(__FILE__,__LINE__,
_(
"Directory \"%s\" can't be created because the path already exists and is not a directory\n"),
name);
488 if (
debug)
debuga(__FILE__, __LINE__,
_(
"Purging temporary directory \"%s\"\n"),
tmp);
493 void my_lltoa(
unsigned long long int n,
char *s,
int ssize,
int len)
502 debuga(__FILE__,__LINE__,
_(
"The requested number of digits passed to my_lltoa (%d) is bigger than the output buffer size (%d)\n"),len,ssize);
507 s[slen++] = (n % 10) +
'0';
508 }
while ((n /= 10) > 0 && slen<ssize);
511 for (i = 0, j = slen-1; i<j; i++, j--) {
519 for (j=slen; j>=0; j--)
521 for (j=0 ; j<i ; j++)
530 for (m=0 ; m<12 && strcmp(
mtab1[m],month) != 0; m++);
536 return(year*10000+month*100+day);
551 if (date1->tm_year<date2->tm_year)
return(-1);
552 if (date1->tm_year>date2->tm_year)
return(1);
553 if (date1->tm_mon<date2->tm_mon)
return(-1);
554 if (date1->tm_mon>date2->tm_mon)
return(1);
555 if (date1->tm_mday<date2->tm_mday)
return(-1);
556 if (date1->tm_mday>date2->tm_mday)
return(1);
557 if (date1->tm_hour<date2->tm_hour)
return(-1);
558 if (date1->tm_hour>date2->tm_hour)
return(1);
559 if (date1->tm_min<date2->tm_min)
return(-1);
560 if (date1->tm_min>date2->tm_min)
return(1);
561 if (date1->tm_sec<date2->tm_sec)
return(-1);
562 if (date1->tm_sec>date2->tm_sec)
return(1);
566 void buildymd(
const char *dia,
const char *mes,
const char *ano,
char *wdata,
int wdata_size)
571 snprintf(wdata,wdata_size,
"%04d%02d%02d",atoi(ano),nmes+1,atoi(dia));
579 for (x=0; x<12 && strncmp(
mtab1[x],month,3)!=0; x++);
588 if (month<1 || month>12) {
589 snprintf(str,
sizeof(str),
"%03d",month);
592 return(
mtab1[month-1]);
601 void debuga(
const char *File,
int Line,
const char *msg,...)
609 const char *ptr=strrchr(File,
'/');
613 fprintf(stderr,
_(
"SARG(%s:%d): "),ptr,Line);
617 fputs(
_(
"SARG: "),stderr);
620 vfprintf(stderr,msg,ap);
636 vfprintf(stderr,msg,ap);
646 void debugaz(
const char *File,
int Line,
const char *msg,...)
654 const char *ptr=strrchr(File,
'/');
658 fprintf(stderr,
_(
"SARG(%s:%d): (info) "),ptr,Line);
662 fputs(
_(
"SARG: (info) "),stderr);
665 vfprintf(stderr,msg,ap);
672 #define MAXLEN_FIXNUM 256
678 register int i, j, k;
680 static char abbrev[30]=
"";
682 my_lltoa(value, num,
sizeof(num), 0);
685 numlen = strlen(num);
688 else if (numlen%3 == 1) {
695 else if (numlen%3 == 2) {
703 else if (numlen%3 == 0) {
716 else if (numlen <= 6)
718 else if (numlen <= 9)
720 else if (numlen <= 12)
722 else if (numlen <= 15)
724 else if (numlen >= 18)
726 else if (numlen <= 21)
728 else if (numlen <= 24)
730 else if (numlen <= 27)
733 strcat(abbrev,
"???");
744 for ( i = strlen(num) - 1, j = 0 ; i > -1; i--) {
745 if ( k == 2 && i != 0 ) {
758 for ( i = strlen(pbuf) - 1, j = 0 ; i > -1; i--, j++)
769 #define MAXLEN_FIXNUM2 1024
775 register int i, j, k;
777 my_lltoa(value, num,
sizeof(num), 0);
784 for ( i = strlen(num) - 1, j = 0 ; i > -1; i--) {
785 if ( k == 2 && i != 0 ) {
798 for ( i = strlen(pbuf) - 1, j = 0 ; i > -1; i--, j++)
809 long int num = elap / 1000LL;
816 min=(num % 3600L) / 60L;
818 snprintf(buf,
sizeof(buf),
"%02d:%02d:%02d",hor,min,sec);
840 if (snprintf(wdir,
sizeof(wdir),
"%s%s/sarg-date",dirname,
name)>=
sizeof(wdir)) {
841 debuga(__FILE__,__LINE__,
_(
"Buffer too small to store "));
845 if ((fp_in = fopen(wdir,
"rt")) == 0) {
846 if (snprintf(wdir,
sizeof(wdir),
"%s%s/date",dirname,
name)>=
sizeof(wdir)) {
847 debuga(__FILE__,__LINE__,
_(
"Buffer too small to store "));
851 if ((fp_in = fopen(wdir,
"rt")) == 0) {
857 if (!fgets(data,80,fp_in)) {
858 debuga(__FILE__,__LINE__,
_(
"Failed to read the date in file \"%s\"\n"),wdir);
861 if (fclose(fp_in)==EOF) {
862 debuga(__FILE__,__LINE__,
_(
"Read error in \"%s\": %s\n"),wdir,strerror(errno));
871 void formatdate(
char *date,
int date_size,
int year,
int month,
int day,
int hour,
int minute,
int second,
int dst)
877 memset(<m,0,
sizeof(ltm));
878 if (year>=1900) ltm.tm_year=year-1900;
879 if (month>=1 && month<=12) ltm.tm_mon=month-1;
880 if (day>=1 && day<=31) ltm.tm_mday=day;
881 if (hour>=0 && hour<24) ltm.tm_hour=hour;
882 if (minute>=0 && minute<60) ltm.tm_min=minute;
883 if (second>=0 && second<60) ltm.tm_sec=second;
885 unixtime=mktime(<m);
886 fulltm=localtime(&unixtime);
888 strftime(date,date_size,
"%c",fulltm);
894 memset(t,0,
sizeof(*t));
895 t->tm_year=year-1900;
908 if (snprintf(wdir,
sizeof(wdir),
"%s%s/sarg-users",dirname,
name)>=
sizeof(wdir)) {
909 debuga(__FILE__,__LINE__,
_(
"Buffer too small to store "));
913 if ((fp_in=fopen(wdir,
"r"))==NULL) {
914 if (snprintf(wdir,
sizeof(wdir),
"%s%s/users",dirname,
name)>=
sizeof(wdir)) {
915 debuga(__FILE__,__LINE__,
_(
"Buffer too small to store "));
919 if ((fp_in=fopen(wdir,
"r"))==NULL) {
924 if (!fgets(tuser,
sizeof(tuser),fp_in)) {
925 debuga(__FILE__,__LINE__,
_(
"Failed to read the number of users in file \"%s\"\n"),wdir);
928 if (fclose(fp_in)==EOF) {
929 debuga(__FILE__,__LINE__,
_(
"Read error in \"%s\": %s\n"),wdir,strerror(errno));
938 void obttotal(
const char *dirname,
const char *
name,
int nuser,
long long int *tbytes,
long long int *media)
951 if (snprintf(wdir,
sizeof(wdir),
"%s%s/sarg-general",dirname,
name)>=
sizeof(wdir)) {
952 debuga(__FILE__,__LINE__,
_(
"Buffer too small to store "));
957 if (snprintf(wdir,
sizeof(wdir),
"%s%s/general",dirname,
name)>=
sizeof(wdir)) {
958 debuga(__FILE__,__LINE__,
_(
"Buffer too small to store "));
968 debuga(__FILE__,__LINE__,
_(
"Not enough memory to read file \"%s\"\n"),wdir);
973 if (strncmp(buf,
"TOTAL\t",6) == 0)
975 else if (strncmp(buf,
"TOTAL ",6) == 0)
980 if (
getword(user,
sizeof(user),&gwarea,sep)<0) {
981 debuga(__FILE__,__LINE__,
_(
"Invalid user in file \"%s\"\n"),wdir);
984 if (strcmp(user,
"TOTAL") != 0)
987 debuga(__FILE__,__LINE__,
_(
"Invalid total number of accesses in file \"%s\"\n"),wdir);
991 debuga(__FILE__,__LINE__,
_(
"Invalid number of bytes in file \"%s\"\n"),wdir);
1005 *media=*tbytes / nuser;
1012 int day0, month0, year0, hour0, minute0;
1013 int day1, month1, year1, hour1, minute1;
1019 while((str=strstr(str,
"sarg-"))!=NULL) {
1021 if (!isdigit(str[0]) || !isdigit(str[1]))
continue;
1022 day0=(str[0]-
'0')*10+(str[1]-
'0');
1023 if (day0<1 || day0>31)
continue;
1025 month0=(str[0]-
'0')*10+(str[1]-
'0')-1;
1026 if (month0<0 || month0>11)
continue;
1029 for (i=0 ; isdigit(str[i]) && i<4 ; i++) year0=year0*10+(str[i]-
'0');
1030 if (i!=4 || year0<1900)
continue;
1032 if (str[0]!=
'_')
continue;
1035 if (!isdigit(str[0]) || !isdigit(str[1]))
continue;
1036 hour0=(str[0]-
'0')*10+(str[1]-
'0');
1038 if (!isdigit(str[0]) || !isdigit(str[1]))
continue;
1039 minute0=(str[0]-
'0')*10+(str[1]-
'0');
1042 if (*str !=
'-')
continue;
1045 if (!isdigit(str[0]) || !isdigit(str[1]))
continue;
1046 day1=(str[0]-
'0')*10+(str[1]-
'0');
1047 if (day1<1 || day1>31)
continue;
1049 month1=(str[0]-
'0')*10+(str[1]-
'0')-1;
1050 if (month1<0 || month1>11)
continue;
1053 for (i=0 ; isdigit(str[i]) && i<4 ; i++) year1=year1*10+(str[i]-
'0');
1054 if (i!=4 || year1<1900)
continue;
1057 if (str[0]!=
'_')
continue;
1060 if (!isdigit(str[0]) || !isdigit(str[1]))
continue;
1061 hour1=(str[0]-
'0')*10+(str[1]-
'0');
1063 if (!isdigit(str[0]) || !isdigit(str[1]))
continue;
1064 minute1=(str[0]-
'0')*10+(str[1]-
'0');
1101 period->
end.tm_year=(duntil/10000)-1900;
1127 mdate=(
main->start.tm_year)*10000+(
main->start.tm_mon)*100+
main->start.tm_mday;
1128 cdate=(candidate->
start.tm_year)*10000+(candidate->
start.tm_mon)*100+candidate->
start.tm_mday;
1129 if (mdate==0 || cdate<mdate) memcpy(&
main->start,&candidate->
start,
sizeof(
struct tm));
1131 mdate=(
main->end.tm_year)*10000+(
main->end.tm_mon)*100+
main->end.tm_mday;
1132 cdate=(candidate->
end.tm_year)*10000+(candidate->
end.tm_mon)*100+candidate->
end.tm_mday;
1133 if (cdate>mdate) memcpy(&
main->end,&candidate->
end,
sizeof(
struct tm));
1140 char text1[40], text2[40];
1143 i=strftime(text1,
sizeof(text1),
"%Y %b %d", &
period->
start);
1144 }
else if (
df==
'e') {
1145 i=strftime(text1,
sizeof(text1),
"%d %b %Y", &
period->
start);
1148 i=strftime(text1,
sizeof(text1),
"%Y.%U", &
period->
start);
1150 if (i == 0)
return(-1);
1157 i=strftime(text2,
sizeof(text2)-i,
"%Y %b %d", &
period->
end);
1158 }
else if (
df==
'e') {
1159 i=strftime(text2,
sizeof(text2)-i,
"%d %b %Y", &
period->
end);
1161 i=strftime(text2,
sizeof(text2)-i,
"%Y.%U", &
period->
end);
1163 if (i == 0)
return(-1);
1178 FILE *img_in, *img_ou;
1183 struct dirent *direntp;
1188 if (snprintf(images,
sizeof(images),
"%simages",
outdir)>=
sizeof(images)) {
1189 debuga(__FILE__,__LINE__,
_(
"Cannot copy images to target directory %simages\n"),
outdir);
1192 if (access(images,R_OK)!=0) {
1194 debuga(__FILE__,__LINE__,
_(
"Cannot create directory \"%s\": %s\n"),images,strerror(errno));
1201 debuga(__FILE__,__LINE__,
_(
"Cannot open directory \"%s\": %s\n"),
ImageDir,strerror(errno));
1204 while ((direntp = readdir( dirp )) != NULL ){
1205 if (direntp->d_name[0]==
'.')
1207 if (snprintf(srcfile,
sizeof(srcfile),
"%s/%s",
ImageDir,direntp->d_name)>=
sizeof(srcfile)) {
1208 debuga(__FILE__,__LINE__,
_(
"Buffer too small to store "));
1212 if (stat(srcfile,&info)) {
1213 debuga(__FILE__,__LINE__,
_(
"Cannot stat \"%s\": %s\n"),srcfile,strerror(errno));
1216 if (S_ISREG(info.st_mode)) {
1217 if (snprintf(dstfile,
sizeof(dstfile),
"%s/%s",images,direntp->d_name)>=
sizeof(dstfile)) {
1218 debuga(__FILE__,__LINE__,
_(
"Buffer too small to store "));
1222 img_in = fopen(srcfile,
"rb");
1224 img_ou = fopen(dstfile,
"wb");
1226 while ((nread = fread(buffer,1,
sizeof(buffer),img_in))>0) {
1227 if (fwrite(buffer,1,nread,img_ou)!=nread) {
1228 debuga(__FILE__,__LINE__,
_(
"Failed to copy image \"%s\" to \"%s\"\n"),srcfile,dstfile);
1232 if (fclose(img_ou)==EOF) {
1233 debuga(__FILE__,__LINE__,
_(
"Write error in \"%s\": %s\n"),dstfile,strerror(errno));
1237 debuga(__FILE__,__LINE__,
_(
"Cannot open file \"%s\": %s\n"), dstfile, strerror(errno));
1238 if (fclose(img_in)==EOF) {
1239 debuga(__FILE__,__LINE__,
_(
"Read error in \"%s\": %s\n"),srcfile,strerror(errno));
1243 debuga(__FILE__,__LINE__,
_(
"Cannot open file \"%s\": %s\n"), srcfile, strerror(errno));
1246 (void) closedir(dirp);
1263 if (!isdigit(Name[0]) || !isdigit(Name[1]))
return(
false);
1265 if (isdigit(Name[2]) && isdigit(Name[3]))
1271 if (!isdigit(Name[5]) || !isdigit(Name[6]))
return(
false);
1279 if (!isalpha(Name[0]) || !isalpha(Name[1]) || !isalpha(Name[2]))
return(
false);
1280 for (i=11 ; i>=0 && memcmp(
mtab1[i],Name,3) ; i--);
1281 if (i<0)
return(
false);
1285 if (!isdigit(Name[0]) || !isdigit(Name[1]))
return(
false);
1290 else if (isalpha(Name[2]) && isalpha(Name[3]) && isalpha(Name[4]))
1296 if (!isalpha(Name[0]) || !isalpha(Name[1]) || !isalpha(Name[2]))
return(
false);
1297 for (i=11 ; i>=0 && memcmp(
mtab1[i],Name,3) ; i--);
1298 if (i<0)
return(
false);
1302 if (!isdigit(Name[0]) || !isdigit(Name[1]) || !isdigit(Name[2]) || !isdigit(Name[3]))
return(
false);
1310 if (Name[0]!=
'-')
return(
false);
1315 if (!isdigit(Name[0]) || !isdigit(Name[1]) || !isdigit(Name[2]) || !isdigit(Name[3]))
return(
false);
1318 if (!isalpha(Name[0]) || !isalpha(Name[1]) || !isalpha(Name[2]))
return(
false);
1319 for (i=11 ; i>=0 && memcmp(
mtab1[i],Name,3) ; i--);
1320 if (i<0)
return(
false);
1323 if (!isdigit(Name[0]) || !isdigit(Name[1]))
return(
false);
1328 if (!isdigit(Name[0]) || !isdigit(Name[1]))
return(
false);
1331 if (!isalpha(Name[0]) || !isalpha(Name[1]) || !isalpha(Name[2]))
return(
false);
1332 for (i=11 ; i>=0 && memcmp(
mtab1[i],Name,3) ; i--);
1333 if (i<0)
return(
false);
1336 if (!isdigit(Name[0]) || !isdigit(Name[1]) || !isdigit(Name[2]) || !isdigit(Name[3]))
return(
false);
1352 if (!isdigit(Name[0]) || !isdigit(Name[1]) || !isdigit(Name[2]) || !isdigit(Name[3]))
return(
false);
1357 if (!isdigit(Name[0]) || !isdigit(Name[1]) || !isdigit(Name[2]) || !isdigit(Name[3]))
return(
false);
1360 if (Name[0])
return(
false);
1372 if (!isdigit(Name[0]) || !isdigit(Name[1]))
return(
false);
1373 m=(Name[0]-
'0')*10+(Name[1]-
'0');
1374 if (m<1 || m>12)
return(
false);
1379 if (!isdigit(Name[0]) || !isdigit(Name[1]))
return(
false);
1380 m=(Name[0]-
'0')*10+(Name[1]-
'0');
1381 if (m<1 || m>12)
return(
false);
1384 if (Name[0])
return(
false);
1396 if (!isdigit(Name[0]) || !isdigit(Name[1]))
return(
false);
1397 d=(Name[0]-
'0')*10+(Name[1]-
'0');
1398 if (d<1 || d>31)
return(
false);
1402 if (!isdigit(Name[0]) || !isdigit(Name[1]))
return(
false);
1403 d=(Name[0]-
'0')*10+(Name[1]-
'0');
1404 if (d<1 || d>31)
return(
false);
1440 y1=per1->
start.tm_year+1900;
1441 y2=per1->
end.tm_year+1900;
1442 m1=per1->
start.tm_mon+1;
1443 m2=per1->
end.tm_mon+1;
1444 d1=per1->
start.tm_mday;
1445 d2=per1->
end.tm_mday;
1447 wlen+=sprintf(wdir+wlen,
"%04d",y1);
1448 if (y1!=y2) wlen+=sprintf(wdir+wlen,
"-%04d",y2);
1449 if (access(wdir, R_OK) != 0)
1452 wlen+=sprintf(wdir+wlen,
"/%02d",m1);
1453 if (m1 != m2) wlen+=sprintf(wdir+wlen,
"-%02d",m2);
1454 if (access(wdir, R_OK) != 0)
1457 wlen+=sprintf(wdir+wlen,
"/%02d",d1);
1458 if (d1!=d2) wlen+=sprintf(wdir+wlen,
"-%02d",d2);
1461 wlen=snprintf(wdir+wlen,
sizeof(wdir)-wlen,
"%04d%s%02d-%04d%s%02d",y1,
1463 }
else if (
df ==
'e') {
1464 wlen=snprintf(wdir+wlen,
sizeof(wdir)-wlen,
"%02d%s%04d-%02d%s%04d",d1,
1466 }
else if (
df ==
'w') {
1467 wlen2=strftime(wdir+wlen,
sizeof(wdir)-wlen,
"%Y.%U", &per1->
start);
1468 if (wlen2==0)
return(-1);
1473 if (
us[0] !=
'\0') {
1480 if (
addr[0] !=
'\0') {
1484 if (
site[0] !=
'\0') {
1495 while (access(wdir,R_OK)==0 || errno==EACCES)
1502 debuga(__FILE__,__LINE__,
_(
"File \"%s\" already exists, moved to \"%s\"\n"),
outdirname,wdir);
1513 if (snprintf(wdir,
sizeof(wdir),
"%s/sarg-date",
outdirname)>=
sizeof(wdir)) {
1514 debuga(__FILE__,__LINE__,
_(
"Buffer too small to store "));
1518 if ((fp_ou = fopen(wdir,
"wt")) == 0) {
1519 debuga(__FILE__,__LINE__,
_(
"Cannot open file \"%s\": %s\n"),wdir,strerror(errno));
1525 loctm=localtime(&curtime);
1526 strftime(wdir,
sizeof(wdir),
"%Y-%m-%d %H:%M:%S",loctm);
1527 if (fprintf(fp_ou,
"%s %d\n",wdir,loctm->tm_isdst)<0) {
1528 debuga(__FILE__,__LINE__,
_(
"Failed to write the date in \"%s\"\n"),wdir);
1532 if (fclose(fp_ou)==EOF) {
1533 debuga(__FILE__,__LINE__,
_(
"Write error in \"%s\": %s\n"),wdir,strerror(errno));
1553 debuga(__FILE__,__LINE__,
_(
"Invalid buffer length passed to the function to safely copy a string\n"));
1556 strncpy(dest,src,length-1);
1557 dest[length-1]=
'\0';
1567 for (i=0;line[i];i++){
1569 if (line[i]==
';') skip=0;
1587 local = localtime(&t);
1589 strftime(ftime, ftimesize,
"%b/%d/%Y %H:%M", local);
1591 strftime(ftime, ftimesize,
"%d/%b/%Y-%H:%M", local);
1593 strftime(ftime, ftimesize,
"%W-%H-%M", local);
1600 long int num = elap / 1000LL;
1604 static char buf[20];
1607 min=(num % 3600L) / 60L;
1610 if (hor==0 && min==0 && sec==0)
1613 snprintf(buf,
sizeof(buf),
"%d:%02d:%02d",hor,min,sec);
1631 if (sscanf(
ReadFilter->
DateRange,
"%d/%d/%d%n",&d0,&m0,&y0,&next)!=3 || y0<100 || m0<1 || m0>12 || d0<1 || d0>31 || next<0) {
1632 debuga(__FILE__,__LINE__,
_(
"The date passed as argument is not formated as dd/mm/yyyy or dd/mm/yyyy-dd/mm/yyyy\n"));
1636 if (sscanf(
ReadFilter->
DateRange+next+1,
"%d/%d/%d",&d1,&m1,&y1)!=3 || y1<100 || m1<1 || m1>12 || d1<1 || d1>31) {
1637 debuga(__FILE__,__LINE__,
_(
"The date range passed as argument is not formated as dd/mm/yyyy or dd/mm/yyyy-dd/mm/yyyy\n"));
1641 debuga(__FILE__,__LINE__,
_(
"The date range passed as argument is not formated as dd/mm/yyyy or dd/mm/yyyy-dd/mm/yyyy\n"));
1651 struct tm *Date0,Date1;
1653 if (time(&Today)==(time_t)-1) {
1654 debuga(__FILE__,__LINE__,
_(
"Failed to get the current time\n"));
1659 debuga(__FILE__,__LINE__,
_(
"Invalid number of days in -d parameter\n"));
1663 Date0=localtime(&Today);
1665 debuga(__FILE__,__LINE__,
_(
"Cannot convert local time: %s\n"),strerror(errno));
1668 y0=y1=Date0->tm_year+1900;
1669 m0=m1=Date0->tm_mon+1;
1670 d0=d1=Date0->tm_mday;
1680 const int FirstWeekDay=1;
1684 debuga(__FILE__,__LINE__,
_(
"Invalid number of weeks in -d parameter\n"));
1687 Date0=localtime(&Today);
1689 debuga(__FILE__,__LINE__,
_(
"Cannot convert local time: %s\n"),strerror(errno));
1692 WeekBegin=Today-((Date0->tm_wday-FirstWeekDay+7)%7)*24*60*60;
1693 WeekBegin-=i*7*24*60*60;
1694 Date0=localtime(&WeekBegin);
1696 debuga(__FILE__,__LINE__,
_(
"Cannot convert local time: %s\n"),strerror(errno));
1699 y0=Date0->tm_year+1900;
1702 WeekBegin+=6*24*60*60;
1703 Date0=localtime(&WeekBegin);
1705 debuga(__FILE__,__LINE__,
_(
"Cannot convert local time: %s\n"),strerror(errno));
1708 y1=Date0->tm_year+1900;
1713 debuga(__FILE__,__LINE__,
_(
"Invalid number of months in -d parameter\n"));
1716 Date0=localtime(&Today);
1718 debuga(__FILE__,__LINE__,
_(
"Cannot convert local time: %s\n"),strerror(errno));
1721 if (Date0->tm_mon<i%12) {
1722 y0=Date0->tm_year+1900-i/12-1;
1723 m0=(Date0->tm_mon+12-i%12)%12+1;
1726 y0=Date0->tm_year+1900-i/12;
1727 m0=Date0->tm_mon-i%12+1;
1730 memcpy(&Date1,Date0,
sizeof(
struct tm));
1735 Date1.tm_year=y0-1900;
1738 Date1.tm_year=y0-1900+1;
1742 Date0=localtime(&t1);
1743 y1=Date0->tm_year+1900;
1747 debuga(__FILE__,__LINE__,
_(
"Invalid date range passed on command line\n"));
1765 for (s =
string; *s; ++s)
1781 for (s =
string; *s; ++s)
1798 debuga(__FILE__,__LINE__,
_(
"Purging temporary file sarg-general\n"));
1800 if (snprintf(filename,
sizeof(filename),
"%s/sarg-general",
outdir)>=
sizeof(filename)) {
1801 debuga(__FILE__,__LINE__,
_(
"Path too long: "));
1805 if ((fp_gen=fopen(filename,
"w"))==NULL){
1806 debuga(__FILE__,__LINE__,
_(
"Cannot open file \"%s\": %s\n"),filename,strerror(errno));
1810 if (fclose(fp_gen)==EOF) {
1811 debuga(__FILE__,__LINE__,
_(
"Write error in \"%s\": %s\n"),filename,strerror(errno));
1828 debuga(__FILE__,__LINE__,
_(
"Cannot open file \"%s\": %s\n"),
ExcludeCodes,strerror(errno));
1832 if (fseek(fp_in, 0, SEEK_END)==-1) {
1833 debuga(__FILE__,__LINE__,
_(
"Failed to move till the end of file \"%s\": %s\n"),
ExcludeCodes,strerror(errno));
1836 MemSize = ftell(fp_in);
1841 if (fseek(fp_in, 0, SEEK_SET)==-1) {
1842 debuga(__FILE__,__LINE__,
_(
"Failed to rewind file \"%s\": %s\n"),
ExcludeCodes,strerror(errno));
1847 if ((
excludecode=(
char *) malloc(MemSize))==NULL) {
1848 debuga(__FILE__,__LINE__,
_(
"malloc error (%ld bytes required)\n"),MemSize);
1854 while(fgets(data,
sizeof(data),fp_in)!=NULL) {
1855 if (data[0]==
'#')
continue;
1856 for (i=strlen(data)-1 ; i>=0 && (
unsigned char)data[i]<=
' ' ; i--) data[i]=
'\0';
1858 if (Stored+i+2>=MemSize) {
1867 if (fclose(fp_in)==EOF) {
1891 if (strncmp(
code,cod,clen)==0 && cod[clen]==
';')
1893 cod=strchr(cod,
';');
1904 for (i=strlen(str)-1 ; i>=0 && (
unsigned char)str[i]<=
' ' ; i--);
1905 if (i==3 && strncmp(str,
"none",4) == 0)
1915 for (i=strlen(str)-1 ; i>=0 && (
unsigned char)str[i]<=
' ' ; i--) str[i]=0;
1918 #ifdef LEGACY_TESTVALIDUSERCHAR
1925 for (x=0; x<strlen(user); x++) {
1936 const char * p_user ;
1938 while( *p_UserInvalidChar ) {
1941 if ( *p_UserInvalidChar == *p_user )
1945 p_UserInvalidChar++ ;
1953 if ( *(
int *)a > *(
int *)b )
return 1;
1954 if ( *(
int *)a < *(
int *)b )
return -1;
1978 debuga(__FILE__,__LINE__,
_(
"Ending value %d is less than or equal to starting value %d in parameter \"%s\"\n"),d,d0,paramname);
1981 for (i=d0 ; i<=d ; i++) list[i]=1;
1998 void getnumlist(
const char *paramname,
const char *buffer,
int *list,
int maxvalue)
2005 while (*buffer && *buffer!=
' ' && *buffer!=
'\t') buffer++;
2008 debuga(__FILE__,__LINE__,
_(
"Missing values for parameter \"%s\"\n"),paramname);
2013 for (i=0 ; i<maxvalue ; i++) list[i]=0;
2019 for ( ; *buffer ; buffer++)
2021 if (isdigit(*buffer))
2023 d=d*10+(*buffer-
'0');
2026 debuga(__FILE__,__LINE__,
_(
"Value too big found in parameter \"%s\" (max value is %d)\n"),paramname,maxvalue-1);
2031 else if (*buffer==
'-')
2035 debuga(__FILE__,__LINE__,
_(
"Missing start value before \"-\" in parameter \"%s\"\n"),paramname);
2042 else if (*buffer==
',')
2046 debuga(__FILE__,__LINE__,
_(
"Missing value before \",\" in parameter \"%s\"\n"),paramname);
2055 else if (*buffer==
'\r' || *buffer==
'\n')
2059 else if (*buffer!=
' ' && *buffer!=
'\t')
2061 debuga(__FILE__,__LINE__,
_(
"Invalid character \"%c\" found in parameter \"%s\"\n"),*buffer,paramname);
2072 debuga(__FILE__,__LINE__,
_(
"Missing ending value in range for parameter \"%s\"\n"),paramname);
2077 debuga(__FILE__,__LINE__,
_(
"Parameter \"%s\" is empty\n"),paramname);
2093 if (value<0 || value>=maxvalue)
return(
false);
2094 return(list[value]!=0);
2102 zdate(ftime,
sizeof(ftime),
df);
2103 fputs(
"<div class=\"info\">",fp_ou);
2104 fprintf(fp_ou,
_(
"Generated by <a href=\"%s\">%s-%s</a> on %s"),
URL,
PGM,
VERSION,ftime);
2105 fputs(
"</div>\n",fp_ou);
2113 fputs(
"<div class=\"logo\"><a href=\"http://sarg.sourceforge.net\"><img src=\"",fp_ou);
2114 for (i=0 ; i<depth ; i++)
2116 fputs(
"images/sarg.png\" title=\"SARG, Squid Analysis Report Generator. Logo by Osamu Matsuzaki\" alt=\"Sarg\"></a> Squid Analysis Report Generator</div>\n",fp_ou);
2122 fprintf(fp_ou,
"<div class=\"logo\"><img src=\"%s\" width=\"%s\" height=\"%s\" alt=\"Logo\"> %s</div>\n",
LogoImage,
Width,
Height,
LogoText);
2129 fputs(
"<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\">\n<html>\n",fp_ou);
2130 fprintf(fp_ou,
"<head>\n <meta http-equiv=\"Content-Type\" content=\"text/html; charset=%s\">\n",
CharSet);
2131 if (page_title) fprintf(fp_ou,
"<title>%s</title>\n",page_title);
2134 fputs(
"<script type=\"text/javascript\" src=\"",fp_ou);
2136 for (i=0 ; i<depth ; i++) fputs(
"../",fp_ou);
2139 fputs(
"\"></script>\n",fp_ou);
2141 fputs(
"</head>\n<body>\n",fp_ou);
2149 fprintf(fp_ou,
"<div class=\"title\"><table cellpadding=\"0\" cellspacing=\"0\">\n<tr><th class=\"title_c\">%s</th></tr>\n",
Title);
2154 fputs(
"</table></div>\n",fp_ou);
2160 fputs(
"</body>\n</html>\n",fp_ou);
2167 while (*str && (maxlen<=0 || i<maxlen)) {
2170 fputs(
"&",fp_ou);
2173 fputs(
"<",fp_ou);
2176 fputs(
">",fp_ou);
2179 fputs(
""",fp_ou);
2182 fputs(
"'",fp_ou);
2190 if (maxlen>0 && i>=maxlen)
2191 fputs(
"…",fp_ou);
2198 fputs(
"&",fp_ou);
2221 fputs(
"<a href=\"http://",fp_ou);
2223 fputs(
"<a href=\"",fp_ou);
2227 fputs(
"</a>",fp_ou);
2237 for (x=strlen(url)-1; x>=0; x--) {
2238 if (url[x] ==
'/' || y>=
sizeof(w)-1)
break;
2247 for (y=y-1; y>=0; y--) {
2267 for (i=0 ; url[i] && url[i]!=
'/' && url[i]!=
'?' ; i++);
2280 if (isalnum(url[i]) || url[i]==
'-' || url[i]==
'_' || url[i]==
'.') {
2284 if (!skip) anchor[--j]=
'_';
2302 printf(
_(
"SARG Version: %s\n"),
VERSION);
2303 #if defined(ENABLE_NLS) && defined(HAVE_LOCALE_H)
2305 printf(
_(
"\nFor the translation to work, a valid message file should be copied to "
2306 "\"%s/<Locale>/LC_MESSAGES/%s.mo\" where <Locale> is derived from the effective locale.\n"),LOCALEDIR,PACKAGE_NAME);
2308 printf(
_(
"Currently effective locale is \"%s\".\n"),
CurrentLocale);
2310 printf(
_(
"Locale is not set in the environment variable.\n"));
2313 printf(
_(
"If this message is in English, then your language is not supported or not correctly installed.\n"));
2318 printf(
_(
"File globbing compiled in.\n"));
2320 printf(
_(
"File globbing NOT compiled in.\n"));
2330 while (*line==
' ' || *line==
'\t') line++;
2332 if (strncasecmp(line,param,plen))
return(NULL);
2333 if (line[plen]!=
' ' && line[plen]!=
'\t')
return(NULL);
2335 while (*line==
' ' || *line==
'\t') line++;
2343 struct dirent *direntp;
2349 while ((direntp = readdir(dirp)) != NULL) {
2350 if (direntp->d_name[0] ==
'.' && (direntp->d_name[1] ==
'\0' ||
2351 (direntp->d_name[1] ==
'.' && direntp->d_name[2] ==
'\0')))
2353 if (snprintf(dname,
sizeof(dname),
"%s/%s",dir,direntp->d_name)>=
sizeof(dname)) {
2354 debuga(__FILE__,__LINE__,
_(
"Path too long: "));
2359 err=lstat(dname,&st);
2361 err=stat(dname,&st);
2364 debuga(__FILE__,__LINE__,
_(
"Cannot stat \"%s\": %s\n"),dname,strerror(errno));
2367 if (S_ISREG(st.st_mode)) {
2368 if (unlink(dname)) {
2369 debuga(__FILE__,__LINE__,
_(
"Cannot delete \"%s\": %s\n"),dname,strerror(errno));
2372 }
else if (S_ISDIR(st.st_mode)) {
2375 debuga(__FILE__,__LINE__,
_(
"Don't know how to delete \"%s\" (not a regular file nor a directory)\n"),dname);
2382 debuga(__FILE__,__LINE__,
_(
"Cannot delete \"%s\": %s\n"),dir,strerror(errno));
2405 struct dirent *direntp;
2411 static const char *TmpExt[]=
2430 while ((direntp = readdir(dirp)) != NULL) {
2431 if (direntp->d_name[0] ==
'.' && (direntp->d_name[1] ==
'\0' ||
2432 (direntp->d_name[1] ==
'.' && direntp->d_name[2] ==
'\0')))
2436 dlen=strlen(direntp->d_name);
2437 for (i=
sizeof(TmpExt)/
sizeof(TmpExt[0])-1 ; i>=0 ; i--) {
2438 elen=strlen(TmpExt[i]);
2439 if (dlen>=elen && strcasecmp(direntp->d_name+dlen-elen,TmpExt[i])==0)
break;
2442 debuga(__FILE__,__LINE__,
_(
"Unknown file \"%s\" found in temporary directory \"%s\". It is not one of our files. "
2443 "Please check the temporary directory you gave to sarg. Adjust the path to a safe "
2444 "directory or manually delete the content of \"%s\"\n"),direntp->d_name,dir,dir);
2448 if (snprintf(dname,
sizeof(dname),
"%s/%s",dir,direntp->d_name)>=
sizeof(dname)) {
2449 debuga(__FILE__,__LINE__,
_(
"Path too long: "));
2455 err=lstat(dname,&st);
2457 err=stat(dname,&st);
2460 debuga(__FILE__,__LINE__,
_(
"Cannot stat \"%s\": %s\n"),dname,strerror(errno));
2463 if (!S_ISDIR(st.st_mode) && !S_ISREG(st.st_mode)) {
2464 debuga(__FILE__,__LINE__,
_(
"Unknown path type for \"%s\". Check temporary directory\n"),dname);
2471 while ((direntp = readdir(dirp)) != NULL) {
2472 if (direntp->d_name[0] ==
'.' && (direntp->d_name[1] ==
'\0' ||
2473 (direntp->d_name[1] ==
'.' && direntp->d_name[2] ==
'\0')))
2477 dlen=strlen(direntp->d_name);
2478 for (i=
sizeof(TmpExt)/
sizeof(TmpExt[0])-1 ; i>=0 ; i--) {
2479 elen=strlen(TmpExt[i]);
2480 if (dlen>=elen && strcasecmp(direntp->d_name+dlen-elen,TmpExt[i])==0)
break;
2483 debuga(__FILE__,__LINE__,
_(
"Unknown file \"%s\" found in temporary directory \"%s\". It is not one of our files. "
2484 "Please check the temporary directory you gave to sarg. Adjust the path to a safe "
2485 "directory or manually delete the content of \"%s\"\n"),direntp->d_name,dir,dir);
2489 if (snprintf(dname,
sizeof(dname),
"%s/%s",dir,direntp->d_name)>=
sizeof(dname)) {
2490 debuga(__FILE__,__LINE__,
_(
"Path too long: "));
2495 err=lstat(dname,&st);
2497 err=stat(dname,&st);
2500 debuga(__FILE__,__LINE__,
_(
"Cannot stat \"%s\": %s\n"),dname,strerror(errno));
2503 if (S_ISDIR(st.st_mode)) {
2505 }
else if (S_ISREG(st.st_mode)) {
2506 if (unlink(dname)) {
2507 debuga(__FILE__,__LINE__,
_(
"Cannot delete \"%s\": %s\n"),dname,strerror(errno));
2511 debuga(__FILE__,__LINE__,
_(
"Don't know how to delete \"%s\" (not a regular file)\n"),dname);
2534 int extract_address_mask(
const char *buf,
const char **text,
unsigned char *ipv4,
unsigned short int *ipv6,
int *nbits,
const char **next)
2539 unsigned int value4, value6;
2540 unsigned short int addr[8];
2551 while (*buf && (*buf==
' ' || *buf==
'\t')) buf++;
2554 ip_size=0x60 | 0x04;
2565 for (i=0 ; (
unsigned char)buf[i]>
' ' && buf[i]!=
'/' && buf[i]!=
'?' && (!bracket || buf[i]!=
']') && ip_size ; i++) {
2566 if (ip_size & 0x04) {
2567 if (isdigit(buf[i])) {
2569 port_num=port_num*10+(buf[i]-
'0');
2570 if (port_num>65535) ip_size&=~0x04;
2572 value4=value4*10+(buf[i]-
'0');
2573 if (value4>0xFFU) ip_size&=~0x04;
2575 }
else if (buf[i]==
'.' && addr_len<4) {
2576 addr[addr_len++]=(
unsigned short)(value4 & 0xFFU);
2578 }
else if (!port && buf[i]==
':') {
2584 if (ip_size & 0x60) {
2585 if (isdigit(buf[i])) {
2586 value6=(value6<<4)+(buf[i]-
'0');
2588 if (value6>0xFFFFU) ip_size&=~0x60;
2589 }
else if (toupper(buf[i])>=
'A' && toupper(buf[i])<=
'F') {
2590 value6=(value6<<4)+(toupper(buf[i])-
'A'+10);
2592 if (value6>0xFFFFU) ip_size&=~0x60;
2593 }
else if (buf[i]==
':' && addr_len<8) {
2594 if (nibble6_len>0) {
2595 addr[addr_len++]=(
unsigned short)(value6 & 0xFFFFU);
2599 if (buf[i+1]==
':') {
2608 if (i==0)
return(0);
2609 if (ip_size & 0x04) {
2613 addr[addr_len++]=(
unsigned short)(value4 & 0xFFU);
2615 if (ip_size & 0x60) {
2616 if (pad_pos<0 && addr_len!=7) {
2618 }
else if (pad_pos>=0 && addr_len>=7)
2620 else if (nibble6_len>0)
2621 addr[addr_len++]=(
unsigned short)(value6 & 0xFFFFU);
2626 if (bracket) (*text)--;
2628 while ((
unsigned char)buf[i]>
' ') i++;
2629 if (next) *next=buf+i;
2632 max_mask=(ip_size & 0x04) ? 4*8 : 8*16;
2636 while (isdigit(buf[i])) i++;
2637 if (mask<0 || mask>max_mask)
mask=max_mask;
2640 if (ip_size & 0x60 && bracket && buf[i]==
']') i++;
2641 if (next) *next=buf+i;
2642 if (ip_size & 0x04) {
2643 if (nbits) *nbits=
mask;
2644 for (i=0 ; i<addr_len ; i++)
2645 ipv4[i]=(
unsigned char)
addr[i];
2650 if (nbits) *nbits=
mask;
2655 ipv6[j++]=(
unsigned short int)
addr[i++];
2657 while (j<pad_pos+pad_len)
2661 ipv6[j++]=(
unsigned short int)
addr[i++];
2665 int format_path(
const char *file,
int line,
char *output_buffer,
int buffer_size,
const char *format,...)
2670 va_start(ap, format);
2671 output_length = vsnprintf(output_buffer, buffer_size, format, ap);
2672 if (output_length >= buffer_size) {
2673 debuga(file, line,
_(
"Path too long: "));
2674 vfprintf(stderr, format, ap);
2678 return output_length;
2683 int length = strlen(base_path);
2686 if (append[0] ==
'/') append++;
2687 if (length > 0 && base_path[length-1] !=
'/') {
2688 if (length+1 >= base_path_size) {
2689 debuga(__FILE__, __LINE__,
_(
"Path too long: "));
2690 fprintf(stderr,
"%s/%s", base_path, append);
2693 base_path[length++] =
'/';
2695 append_length = strlen(append);
2696 if (length+append_length >= base_path_size) {
2697 debuga(__FILE__, __LINE__,
_(
"Path too long: "));
2698 base_path[length] =
'\0';
2699 fprintf(stderr,
"%s%s", base_path, append);
2702 strcpy(base_path + length, append);