"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "zfuncs.cc" between
fotoxx-23.0.tar.gz and fotoxx-23.1.tar.gz

About: fotoxx is a program for photo editing and collection management.

zfuncs.cc  (fotoxx-23.0):zfuncs.cc  (fotoxx-23.1)
skipping to change at line 294 skipping to change at line 294
******************************************************************************** */ ******************************************************************************** */
namespace zfuncs namespace zfuncs
{ {
GdkDisplay *display; // workstation (KB, mouse, screen) GdkDisplay *display; // workstation (KB, mouse, screen)
GdkScreen *screen; // screen, N monitors GdkScreen *screen; // screen, N monitors
GdkDevice *mouse; // pointer device GdkDevice *mouse; // pointer device
GtkSettings *gtksettings = 0; // screen settings GtkSettings *gtksettings = 0; // screen settings
GtkWidget *mainwin = 0; // main window GtkWidget *mainwin = 0; // main window
GtkTextView *curr_textview_widget; // curr. GtkTextView widget 22.15 GtkTextView *curr_textview_widget; // curr. GtkTextView widget 22.15
cchar *zcontact = "mkornelix@gmail.com"; ch zcontact[] = "mkornelix@gmail.com";
// author contact // author contact
cchar *build_date_time = __DATE__ " " __TIME__; ch *build_date_time = __DATE__ " " __TIME__;
// build date and time // build date and time
char *progexe = 0; ch *progexe = 0;
// executable image file // executable image file
timeb startime; // application start time timeb startime; // application start time
int Floglevel = 1; // 0/1/2 = errs/infos/dialog inputs int Floglevel = 1; // 0/1/2 = errs/infos/dialog inputs
int monitor_ww, monitor_hh; // monitor dimensions int monitor_ww, monitor_hh; // monitor dimensions
int appfontsize = 10; // application font size int appfontsize = 10; // application font size
cchar *appfont = "sans 10"; ch *appfont = "sans 10";
// application font defaults // application font defaults
cchar *appboldfont = "sans bold 10"; ch *appboldfont = "sans bold 10";
cchar *appmonofont = "mono 10"; ch *appmonofont = "mono 10";
cchar *appmonoboldfont = "mono bold 10"; ch *appmonoboldfont = "mono bold 10";
char zappname[40] = "undefined"; ch zappname[40] = "undefined";
// appname without version // appname without version
char zappvers[40] = "undefined"; ch zappvers[40] = "undefined";
// appname-N.N // appname-N.N
char zprefix[200], zdatadir[200], zdocdir[200]; ch zprefix[200], zdatadir[200], zdocdir[200];
// app folders // app folders
char zimagedir[200], zhomedir[200]; ch zimagedir[200], zhomedir[200];
pthread_t tid_main = 0; // main() thread ID pthread_t tid_main = 0; // main() thread ID
int vmenuclickposn; // Vmenu image click posn. 0-100 int vmenuclickposn; // Vmenu image click posn. 0-100
int vmenuclickbutton; // button: 1/2/3 = L/M/R mouse int vmenuclickbutton; // button: 1/2/3 = L/M/R mouse
int vmenustop; // setupfunc() stop flag int vmenustop; // setupfunc() stop flag
zdialog *zdialog_list[zdialog_max]; // active zdialog list zdialog *zdialog_list[zdialog_max]; // active zdialog list
int zdialog_count = 0; // total zdialogs (new - free) int zdialog_count = 0; // total zdialogs (new - free)
int zdialog_busy = 0; // open zdialogs (run - destroy) int zdialog_busy = 0; // open zdialogs (run - destroy)
float splcurve_minx = 5; // min. anchor point dist, % scale float splcurve_minx = 5; // min. anchor point dist, % scale
cchar *zappcrash_context1 = 0, *zappcrash_context2 = 0; ch *zappcrash_context1 = 0, *zappcrash_context2 = 0;
} }
using namespace zfuncs; using namespace zfuncs;
/******************************************************************************* * /******************************************************************************* *
system-level utility functions system-level utility functions
******************************************************************************** */ ******************************************************************************** */
/******************************************************************************* * /******************************************************************************* *
skipping to change at line 345 skipping to change at line 345
by zmalloc_report(). zmalloc_report() reports total allocated memory by tag t o by zmalloc_report(). zmalloc_report() reports total allocated memory by tag t o
standard output. Allocation counts and bytes are listed for zmalloc() calls standard output. Allocation counts and bytes are listed for zmalloc() calls
not yet matched by zfree() calls. not yet matched by zfree() calls.
******************************************************************************** */ ******************************************************************************** */
#define zmalloc_extra 36 #define zmalloc_extra 36
int64 zmalloc_tot = 0; int64 zmalloc_tot = 0;
int zmalloc_lock = 0; int zmalloc_lock = 0;
void zmalloc_tabulate(cchar *tag, int64 cc); // private function void zmalloc_tabulate(ch *tag, int64 cc); // private function
void * zmalloc(int64 cc, cchar *tag) // bytes, tag void * zmalloc(int64 cc, ch *tag) // bytes, tag
{ {
double memavail; double memavail;
static int ftf = 1, memcheck = 1; static int ftf = 1, memcheck = 1;
double mcc; double mcc;
while (! resource_lock(zmalloc_lock)) zsleep(0.001); // 22.15 while (! resource_lock(zmalloc_lock)) zsleep(0.001); // 22.15
cchar *OOMmessage = " \n" // big and obvious ch *OOMmessage = " \n" // big and obvious
" --------------- \n" " --------------- \n"
" OUT OF MEMORY \n" " OUT OF MEMORY \n"
" --------------- \n"; " --------------- \n";
if (ftf) { // first call if (ftf) { // first call
ftf = 0; ftf = 0;
memavail = availmemory(); memavail = availmemory();
if (! memavail) memcheck = 0; // memory checking not possible, disable if (! memavail) memcheck = 0; // memory checking not possible, disable
} }
if (cc <= 0) zappcrash("zmalloc: %lld bytes",cc); if (cc <= 0) zappcrash("zmalloc: %lld bytes",cc);
skipping to change at line 380 skipping to change at line 380
memavail = availmemory(); // avail. memory, MB memavail = availmemory(); // avail. memory, MB
if (memavail - mcc < 500) { if (memavail - mcc < 500) {
Plog(0,"memory request for %.0f MB failed\n",mcc); Plog(0,"memory request for %.0f MB failed\n",mcc);
zexit(1,OOMmessage); zexit(1,OOMmessage);
exit(-1); exit(-1);
} }
} }
if (! tag) tag = "zmalloc notag"; if (! tag) tag = "zmalloc notag";
void * maddr = malloc(cc + zmalloc_extra); // 0 allocate void * maddr = malloc(cc + zmalloc_extra); // 0 allocated
d memory with extra space memory with extra space
int64 *pcc = (int64 *) maddr; // 0..8 caller b int64 *pcc = (int64 *) maddr; // 0..8 caller byt
yte count e count
char *psen1 = (char *) maddr + 8; // 8..11 sentinel ch *psen1 = (ch *) maddr + 8; // 8..11 sentinel "
"sen1" sen1"
char *ptag = (char *) maddr + 12; // 12..31 tag, < 2 ch *ptag = (ch *) maddr + 12; // 12..31 tag, < 20
0 chars. chars.
char *puser = (char *) maddr + 32; // 32..B+31 user dat ch *puser = (ch *) maddr + 32; // 32..B+31 user data,
a, B chars. B chars.
char *psen2 = (char *) puser + cc; // B+32..B+35 sentinel ch *psen2 = (ch *) puser + cc; // B+32..B+35 sentinel "
"sen2" sen2"
if (! maddr) { if (! maddr) {
zexit(1,OOMmessage); zexit(1,OOMmessage);
exit(-1); exit(-1);
} }
*pcc = cc; *pcc = cc;
strncpy(psen1,"sen1",4); // set leading sentinel strncpy(psen1,"sen1",4); // set leading sentinel
strncpy0(ptag,tag,20); // set tag strncpy0(ptag,tag,20); // set tag
strncpy(psen2,"sen2",4); // set following sentinel strncpy(psen2,"sen2",4); // set following sentinel
skipping to change at line 412 skipping to change at line 412
resource_unlock(zmalloc_lock); resource_unlock(zmalloc_lock);
return puser; return puser;
} }
// free memory allocated by zmalloc(). checks for overflow. // free memory allocated by zmalloc(). checks for overflow.
void zfree(void *puser) void zfree(void *puser)
{ {
if (! puser) zappcrash("zfree: null address"); if (! puser) zappcrash("zfree: null address");
void *maddr = (char *) puser - 32; void *maddr = (ch *) puser - 32;
int64 *pcc = (int64 *) maddr; int64 *pcc = (int64 *) maddr;
char *psen1 = (char *) maddr + 8; ch *psen1 = (ch *) maddr + 8;
char *ptag = (char *) maddr + 12; ch *ptag = (ch *) maddr + 12;
int64 cc = *pcc; int64 cc = *pcc;
char *psen2 = (char *) puser + cc; ch *psen2 = (ch *) puser + cc;
while (! resource_lock(zmalloc_lock)) zsleep(0.001); // 22.15 while (! resource_lock(zmalloc_lock)) zsleep(0.001); // 22.15
if (strncmp("sen1",psen1,4) || strncmp("sen2",psen2,4)) // check sentinels if (strncmp("sen1",psen1,4) || strncmp("sen2",psen2,4)) // check sentinels
zappcrash("zfree: sentinels clobbered"); zappcrash("zfree: sentinels clobbered");
*psen1 = *psen2 = 0; // destroy sentinels *psen1 = *psen2 = 0; // destroy sentinels
char * puser2 = (char *) puser; // clobber to detect use after free ch * puser2 = (ch *) puser; // clobber to detect use after free
*puser2 = '*'; *puser2 = '*';
zmalloc_tot -= cc; zmalloc_tot -= cc;
zmalloc_tabulate(ptag,-cc); // track usage by tag zmalloc_tabulate(ptag,-cc); // track usage by tag
free(maddr); // free memory (must be last) free(maddr); // free memory (must be last)
resource_unlock(zmalloc_lock); resource_unlock(zmalloc_lock);
return; return;
} }
// private function. track how much memory is in use, per tag. // private function. track how much memory is in use, per tag.
// real tag capacity is about 80% of nominal 'zmhtcap' // real tag capacity is about 80% of nominal 'zmhtcap'
#define zmhtcap 500 // 22.15 #define zmhtcap 500 // 22.15
HashTab *zmalloc_hashtab = 0; HashTab *zmalloc_hashtab = 0;
int64 zmalloc_count[zmhtcap]; int64 zmalloc_count[zmhtcap];
int64 zmalloc_bytes[zmhtcap]; int64 zmalloc_bytes[zmhtcap];
void zmalloc_tabulate(cchar *ptag, int64 cc) void zmalloc_tabulate(ch *ptag, int64 cc)
{ {
int ii; int ii;
if (! zmalloc_hashtab) { if (! zmalloc_hashtab) {
zmalloc_hashtab = new HashTab(20,zmhtcap); zmalloc_hashtab = new HashTab(20,zmhtcap);
memset(zmalloc_count, 0, zmhtcap * sizeof(int64)); memset(zmalloc_count, 0, zmhtcap * sizeof(int64));
memset(zmalloc_bytes, 0, zmhtcap * sizeof(int64)); memset(zmalloc_bytes, 0, zmhtcap * sizeof(int64));
} }
ii = zmalloc_hashtab->Find(ptag); ii = zmalloc_hashtab->Find(ptag);
skipping to change at line 473 skipping to change at line 473
return; return;
} }
// report total memory allocated per tag - leak detection utility // report total memory allocated per tag - leak detection utility
// GUI popup report // GUI popup report
void zmalloc_report(void *vzd) void zmalloc_report(void *vzd)
{ {
int count, ii, first = 1; int count, ii, first = 1;
int64 cc; int64 cc;
char tag[20]; ch tag[20];
zdialog *zd = (zdialog *) vzd; zdialog *zd = (zdialog *) vzd;
popup_report_write(zd,0,"zmalloc total memory: %lld \n",zmalloc_tot); popup_report_write(zd,0,"zmalloc total memory: %lld \n",zmalloc_tot);
while (true) while (true)
{ {
ii = zmalloc_hashtab->GetNext(first,tag); ii = zmalloc_hashtab->GetNext(first,tag);
if (ii < 0) break; if (ii < 0) break;
ii = zmalloc_hashtab->Find(tag); ii = zmalloc_hashtab->Find(tag);
if (ii < 0) zappcrash("zmalloc hash table bug: %s",tag); if (ii < 0) zappcrash("zmalloc hash table bug: %s",tag);
skipping to change at line 501 skipping to change at line 501
return; return;
} }
// report total memory allocated per tag - leak detection utility // report total memory allocated per tag - leak detection utility
// report only tags with increased memory consumption since prior report // report only tags with increased memory consumption since prior report
void zmalloc_growth(void *vzd) void zmalloc_growth(void *vzd)
{ {
int count, ii, first = 1; int count, ii, first = 1;
int64 cc; int64 cc;
char tag[20]; ch tag[20];
zdialog *zd = (zdialog *) vzd; zdialog *zd = (zdialog *) vzd;
static int pne = 0; // table of prior tag and cc values static int pne = 0; // table of prior tag and cc values
static char *ptag[1000]; static ch *ptag[1000];
static int64 pcc[1000]; static int64 pcc[1000];
popup_report_write(zd,0,"zmalloc total memory: %lld \n",zmalloc_tot); popup_report_write(zd,0,"zmalloc total memory: %lld \n",zmalloc_tot);
while (true) // loop all tags in table while (true) // loop all tags in table
{ {
ii = zmalloc_hashtab->GetNext(first,tag); ii = zmalloc_hashtab->GetNext(first,tag);
if (ii < 0) break; if (ii < 0) break;
ii = zmalloc_hashtab->Find(tag); ii = zmalloc_hashtab->Find(tag);
if (ii < 0) zappcrash("zmalloc hash table bug: %s",tag); if (ii < 0) zappcrash("zmalloc hash table bug: %s",tag);
skipping to change at line 559 skipping to change at line 559
Plog(0,"planned memory allocation of %.0f MB failed \n",mb); Plog(0,"planned memory allocation of %.0f MB failed \n",mb);
return 0; // not OK return 0; // not OK
} }
// get real memory in MB units // get real memory in MB units
// typical < 0.1 milliseconds // typical < 0.1 milliseconds
double realmemory() double realmemory()
{ {
FILE *fid; FILE *fid;
char buff[100], *pp; ch buff[100], *pp;
double rmem = 0; double rmem = 0;
fid = fopen("/proc/meminfo","r"); fid = fopen("/proc/meminfo","r");
if (! fid) return 0; if (! fid) return 0;
while (true) while (true)
{ {
pp = fgets(buff,100,fid); pp = fgets(buff,100,fid);
if (! pp) break; if (! pp) break;
if (strmatchN(pp,"MemAvailable:",13)) { // free + file cache if (strmatchN(pp,"MemAvailable:",13)) { // free + file cache
skipping to change at line 585 skipping to change at line 585
fclose(fid); fclose(fid);
return rmem; return rmem;
} }
// get available memory in MB units // get available memory in MB units
// typical < 0.1 milliseconds // typical < 0.1 milliseconds
double availmemory() double availmemory()
{ {
FILE *fid; FILE *fid;
char buff[100], *pp; ch buff[100], *pp;
double avmem = 0; double avmem = 0;
int Ngot = 0; int Ngot = 0;
fid = fopen("/proc/meminfo","r"); fid = fopen("/proc/meminfo","r");
if (! fid) return 0; if (! fid) return 0;
while (true) while (true)
{ {
pp = fgets(buff,100,fid); pp = fgets(buff,100,fid);
if (! pp) break; if (! pp) break;
skipping to change at line 613 skipping to change at line 613
if (++Ngot == 2) break; if (++Ngot == 2) break;
} }
} }
fclose(fid); fclose(fid);
return avmem; return avmem;
} }
// duplicate string in allocated memory, with additional space at end // duplicate string in allocated memory, with additional space at end
char * zstrdup(cchar *zstring, cchar *tag, int addcc) ch * zstrdup(ch *zstring, ch *tag, int addcc)
{ {
if (! zstring) zappcrash("zstrdup() null arg"); if (! zstring) zappcrash("zstrdup() null arg");
if (! tag) tag = "zstrdup notag"; if (! tag) tag = "zstrdup notag";
char *pp = (char *) zmalloc(strlen(zstring) + 1 + addcc, tag); // add additional chars, clear ch *pp = (ch *) zmalloc(strlen(zstring) + 1 + addcc, tag); // add additional chars, clear
strcpy(pp,zstring); strcpy(pp,zstring);
return pp; return pp;
} }
// replace zstring with string + added cc // replace zstring with string + added cc
int zstrcopy(char *&zstring, cchar *string, cchar *tag, int addcc) // 22.18 int zstrcopy(ch *&zstring, ch *string, ch *tag, int addcc) // 22.18
{ {
if (! tag) tag = "zstrcopy notag"; if (! tag) tag = "zstrcopy notag";
if (zstring == string) zstring = 0; // if same string, make a duplicate if (zstring == string) zstring = 0; // if same string, make a duplicate
if (zstring) zfree(zstring); if (zstring) zfree(zstring);
int cc = strlen(string) + 1 + addcc; int cc = strlen(string) + 1 + addcc;
zstring = (char *) zmalloc(cc,tag); zstring = (ch *) zmalloc(cc,tag);
strcpy(zstring,string); strcpy(zstring,string);
return cc; return cc;
} }
/******************************************************************************* */ /******************************************************************************* */
// add message to stdout log file if Floglevel >= message level // add message to stdout log file if Floglevel >= message level
// flush every output immediately even if stdout is a file // flush every output immediately even if stdout is a file
// use lev = 0 for mandatory error message // use lev = 0 for mandatory error message
// lev = 1 for informative message // lev = 1 for informative message
// lev = 2 for everything // lev = 2 for everything
void Plog(int lev, cchar *format, ...) void Plog(int lev, ch *format, ...)
{ {
if (lev > Floglevel) return; if (lev > Floglevel) return;
va_list arglist; va_list arglist;
va_start(arglist,format); va_start(arglist,format);
vprintf(format,arglist); vprintf(format,arglist);
va_end(arglist); va_end(arglist);
fflush(stdout); fflush(stdout);
return; return;
} }
/******************************************************************************* */ /******************************************************************************* */
// output a popup message not requiring GTK // output a popup message not requiring GTK
void xmessage(cchar *message) void xmessage(ch *message)
{ {
char command[200]; ch command[200];
cchar *font = "-*-*-*-*-*--*-200-*-*-*-*-*-*"; ch *font = "-*-*-*-*-*--*-200-*-*-*-*-*-*";
// big font // big font
Plog(0,"%s\n",message); Plog(0,"%s\n",message);
snprintf(command,200,"xmessage -font \'%s\' -center \" %s \" ",font,message); snprintf(command,200,"xmessage -font \'%s\' -center \" %s \" ",font,message);
int err = system(command); // do not use zshell int err = system(command); // do not use zshell
if (err) return; // avoid gcc warning if (err) return; // avoid gcc warning
return; return;
} }
/******************************************************************************* */ /******************************************************************************* */
// Output a status or error message and kill all processes in the process group . // Output a status or error message and kill all processes in the process group .
// killpg(0,SIGKILL) kills all processes, including the caller. // killpg(0,SIGKILL) kills all processes, including the caller.
// if 'popup' true, popup an xmessage window with error message. // if 'popup' true, popup an xmessage window with error message.
void zexit(int popup, cchar *errmess, ...) void zexit(int popup, ch *errmess, ...)
{ {
va_list arglist; va_list arglist;
char mess[1000]; ch mess[1000];
if (errmess) { // output error message if (errmess) { // output error message
va_start(arglist,errmess); va_start(arglist,errmess);
vsnprintf(mess,1000,errmess,arglist); vsnprintf(mess,1000,errmess,arglist);
Plog(0,"zexit: %s\n",mess); Plog(0,"zexit: %s\n",mess);
if (popup) xmessage(mess); // popup message 22.40 if (popup) xmessage(mess); // popup message 22.40
} }
else Plog(0,"zexit\n"); else Plog(0,"zexit\n");
killpg(0,SIGKILL); // kill all processes in group killpg(0,SIGKILL); // kill all processes in group
skipping to change at line 717 skipping to change at line 717
return; return;
} }
/******************************************************************************* */ /******************************************************************************* */
// Write an error message and backtrace dump to a file and to a popup window. // Write an error message and backtrace dump to a file and to a popup window.
// Error message works like printf(). // Error message works like printf().
// Depends on program addr2line() in binutils package. // Depends on program addr2line() in binutils package.
void zappcrash(cchar *format, ... ) void zappcrash(ch *format, ... )
{ {
static int crash = 0; static int crash = 0;
struct utsname unbuff; struct utsname unbuff;
va_list arglist; va_list arglist;
FILE *fid1, *fid2, *fid3; FILE *fid1, *fid2, *fid3;
int fd, ii, err, cc, nstack = 100; int fd, ii, err, cc, nstack = 100;
int Flinenos = 1; int Flinenos = 1;
void *stacklist[100]; void *stacklist[100];
char OS1[60] = "?", OS2[60] = "?", OS3[60] = "?"; ch OS1[60] = "?", OS2[60] = "?", OS3[60] = "?";
char message[300], progexe[300]; ch message[300], progexe[300];
char buff1[300], buff2[300], hexaddr[20]; ch buff1[300], buff2[300], hexaddr[20];
char *arch, *pp1, *pp2, dlim, *pfunc; ch *arch, *pp1, *pp2, dlim, *pfunc;
if (crash++) return; // re-entry or multiple threads crash if (crash++) return; // re-entry or multiple threads crash
va_start(arglist,format); va_start(arglist,format);
vsnprintf(message,300,format,arglist); vsnprintf(message,300,format,arglist);
va_end(arglist); va_end(arglist);
uname(&unbuff); // get cpu arch. 32/64 bit uname(&unbuff); // get cpu arch. 32/64 bit
arch = unbuff.machine; arch = unbuff.machine;
fid1 = popen("lsb_release -d","r"); // get Linux flavor and release fid1 = popen("lsb_release -d","r"); // get Linux flavor and release
skipping to change at line 851 skipping to change at line 851
sigaction(SIGFPE,&sigact,0); sigaction(SIGFPE,&sigact,0);
sigaction(SIGBUS,&sigact,0); sigaction(SIGBUS,&sigact,0);
sigaction(SIGABRT,&sigact,0); // heap or stack corruption sigaction(SIGABRT,&sigact,0); // heap or stack corruption
return; return;
} }
// catch fatal signals and produce backtrace dumps on-screen // catch fatal signals and produce backtrace dumps on-screen
void sighandler(int signal) void sighandler(int signal)
{ {
const char *signame = "unknown"; cch *signame = "unknown";
if (signal == SIGTERM) zexit(0,"TERMINATED"); if (signal == SIGTERM) zexit(0,"TERMINATED");
if (signal == SIGKILL) zexit(0,"KILLED"); if (signal == SIGKILL) zexit(0,"KILLED");
if (signal == SIGSEGV) signame = "segment fault"; if (signal == SIGSEGV) signame = "segment fault";
if (signal == SIGILL) signame = "illegal operation"; if (signal == SIGILL) signame = "illegal operation";
if (signal == SIGFPE) signame = "arithmetic exception"; if (signal == SIGFPE) signame = "arithmetic exception";
if (signal == SIGBUS) signame = "bus error (bad memory)"; if (signal == SIGBUS) signame = "bus error (bad memory)";
if (signal == SIGABRT) signame = "abort"; if (signal == SIGABRT) signame = "abort";
zappcrash("fatal signal: %s",signame); zappcrash("fatal signal: %s",signame);
skipping to change at line 873 skipping to change at line 873
} }
/******************************************************************************* */ /******************************************************************************* */
// Implement the TRACE macro. // Implement the TRACE macro.
// Trace program execution by function and source code line number. // Trace program execution by function and source code line number.
// tracedump() dumps last 50 uses of TRACE macro, latest first. // tracedump() dumps last 50 uses of TRACE macro, latest first.
namespace tracenames namespace tracenames
{ {
char filebuff[50][100]; ch filebuff[50][100];
// last 50 TRACE calls // last 50 TRACE calls
char funcbuff[50][60]; ch funcbuff[50][60];
int linebuff[50]; int linebuff[50];
void *addrbuff[50]; void *addrbuff[50];
int ii, ftf = 1; int ii, ftf = 1;
}; };
// Args are source file, source function name, source code line number, // Args are source file, source function name, source code line number,
// caller address. These all come from the GCC compiler and TRACE macro. // caller address. These all come from the GCC compiler and TRACE macro.
void trace(cchar *file, cchar *func, int line, void *addr) void trace(ch *file, ch *func, int line, void *addr)
{ {
using namespace tracenames; using namespace tracenames;
if (ftf) { if (ftf) {
ftf = 0; ftf = 0;
for (ii = 0; ii < 50; ii++) { for (ii = 0; ii < 50; ii++) {
filebuff[ii][99] = 0; filebuff[ii][99] = 0;
funcbuff[ii][39] = 0; funcbuff[ii][39] = 0;
linebuff[ii] = 0; linebuff[ii] = 0;
addrbuff[ii] = 0; addrbuff[ii] = 0;
skipping to change at line 951 skipping to change at line 951
fclose(fid); fclose(fid);
return; return;
} }
/******************************************************************************* */ /******************************************************************************* */
// restart the current program as root user (after sudo success) // restart the current program as root user (after sudo success)
// argc and argv are the original command line arguments // argc and argv are the original command line arguments
void beroot(int argc, char *argv[]) void beroot(int argc, ch *argv[])
{ {
int err, cc; int err, cc;
char command[500], *args; ch command[500], *args;
if (getuid() == 0) return; // already root if (getuid() == 0) return; // already root
cc = readlink("/proc/self/exe",command,500); // use own program path 22.1 cc = readlink("/proc/self/exe",command,500); // use own program path 22.1
if (cc > 0) command[cc] = 0; // readlink() quirk if (cc > 0) command[cc] = 0; // readlink() quirk
else { else {
Plog(0,"beroot() readlink failed \n"); Plog(0,"beroot() readlink failed \n");
exit(1); exit(1);
} }
skipping to change at line 980 skipping to change at line 980
/******************************************************************************* */ /******************************************************************************* */
// run a command or program as root user // run a command or program as root user
// command: shell command or filespec of the program to start // command: shell command or filespec of the program to start
// return: 0 OK // return: 0 OK
// 1 password not entered // 1 password not entered
// N other error // N other error
// this fails for appimage executables, for unknown reasons // this fails for appimage executables, for unknown reasons
int runroot(cchar *command) // 22.1 int runroot(ch *command) // 22.1
{ {
int err; int err;
char *pw, command2[500]; ch *pw, command2[500];
Plog(0,"runroot: %s \n",command); Plog(0,"runroot: %s \n",command);
pw = zdialog_text1(0,"root password",0); // get password from user pw = zdialog_text1(0,"root password",0); // get password from user
if (! pw || ! pw[0]) { if (! pw || ! pw[0]) {
zmessageACK(0,"nothing done"); zmessageACK(0,"nothing done");
return 1; return 1;
} }
snprintf(command2,500,"echo %s | sudo -S %s &\n",pw,command); // sudo with password and user command snprintf(command2,500,"echo %s | sudo -S %s &\n",pw,command); // sudo with password and user command
skipping to change at line 1006 skipping to change at line 1006
return err; return err;
} }
/******************************************************************************* */ /******************************************************************************* */
// appimage problem: // appimage problem:
// command line args are separated by blanks even for strings enclosed in // command line args are separated by blanks even for strings enclosed in
// quotes: "aaaa bbbb" becomes two argv[] elements, "aaaa" and "bbbb" // quotes: "aaaa bbbb" becomes two argv[] elements, "aaaa" and "bbbb"
// this makes it impossible to get file path args with embedded spaces // this makes it impossible to get file path args with embedded spaces
// //
// char * combine_argvs(int argc, char *argv[], Nth) // ch * combine_argvs(int argc, ch *argv[], Nth)
// combine argv[ii] elements from Nth to last // combine argv[ii] elements from Nth to last
// a single space is inserted between each argv[ii] element // a single space is inserted between each argv[ii] element
// command ... aaaaa bbbbb ccccc produces "aaaaa bbbbb ccccc" // command ... aaaaa bbbbb ccccc produces "aaaaa bbbbb ccccc"
char * combine_argvs(int argc, char *argv[], int Nth) ch * combine_argvs(int argc, ch *argv[], int Nth)
{ {
int ii, ccv, outcc = 0; int ii, ccv, outcc = 0;
static char output[XFCC]; static ch output[XFCC];
for (ii = Nth; ii < argc; ii++) for (ii = Nth; ii < argc; ii++)
{ {
ccv = strlen(argv[ii]); ccv = strlen(argv[ii]);
if (outcc + ccv > XFCC - 2) return 0; if (outcc + ccv > XFCC - 2) return 0;
strcpy(output+outcc,argv[ii]); strcpy(output+outcc,argv[ii]);
outcc += ccv; outcc += ccv;
output[outcc] = ' '; output[outcc] = ' ';
outcc++; outcc++;
} }
skipping to change at line 1059 skipping to change at line 1059
// log elapsed time since last log point // log elapsed time since last log point
// logtime_init(text) initialize timer // logtime_init(text) initialize timer
// logtime(text) report time since last logtime() call // logtime(text) report time since last logtime() call
namespace logtime_names namespace logtime_names
{ {
timespec time1, time2; timespec time1, time2;
double elapsed; double elapsed;
} }
void logtime_init(cchar *text) void logtime_init(ch *text)
{ {
using namespace logtime_names; using namespace logtime_names;
printf("logtime init: %s\n",text); printf("logtime init: %s\n",text);
clock_gettime(CLOCK_MONOTONIC_RAW,&time1); clock_gettime(CLOCK_MONOTONIC_RAW,&time1);
return; return;
} }
void logtime(cchar *text) void logtime(ch *text)
{ {
using namespace logtime_names; using namespace logtime_names;
clock_gettime(CLOCK_MONOTONIC_RAW,&time2); clock_gettime(CLOCK_MONOTONIC_RAW,&time2);
elapsed = time2.tv_sec - time1.tv_sec; elapsed = time2.tv_sec - time1.tv_sec;
elapsed += 0.000000001 * (time2.tv_nsec - time1.tv_nsec); elapsed += 0.000000001 * (time2.tv_nsec - time1.tv_nsec);
time1 = time2; time1 = time2;
printf("logtime %s: %.8f \n",text,elapsed); printf("logtime %s: %.8f \n",text,elapsed);
return; return;
} }
skipping to change at line 1156 skipping to change at line 1156
return utime + stime; return utime + stime;
} }
/******************************************************************************* */ /******************************************************************************* */
// get elapsed process time for my process, including threads and child process es. // get elapsed process time for my process, including threads and child process es.
double jobtime() double jobtime()
{ {
double jiffy = 1.0 / sysconf(_SC_CLK_TCK); // "jiffy" time slice = 1.0 / HZ double jiffy = 1.0 / sysconf(_SC_CLK_TCK); // "jiffy" time slice = 1.0 / HZ
char buff[200]; ch buff[200];
double cpu1, cpu2, cpu3, cpu4; double cpu1, cpu2, cpu3, cpu4;
FILE *fid; FILE *fid;
char *pp; ch *pp;
fid = fopen("/proc/self/stat","r"); fid = fopen("/proc/self/stat","r");
if (! fid) return 0; if (! fid) return 0;
pp = fgets(buff,200,fid); pp = fgets(buff,200,fid);
fclose(fid); fclose(fid);
if (! pp) return 0; if (! pp) return 0;
parseprocrec(pp,14,&cpu1,15,&cpu2,16,&cpu3,17,&cpu4,null); parseprocrec(pp,14,&cpu1,15,&cpu2,16,&cpu3,17,&cpu4,null);
return (cpu1 + cpu2 + cpu3 + cpu4) * jiffy; return (cpu1 + cpu2 + cpu3 + cpu4) * jiffy;
} }
/******************************************************************************* */ /******************************************************************************* */
// convert a time_t date/time (e.g. st_mtime from stat() call) // convert a time_t date/time (e.g. st_mtime from stat() call)
// into a compact date/time format "yyyymmddhhmmss" // into a compact date/time format "yyyymmddhhmmss"
void compact_time(const time_t DT, char *compactDT) void compact_time(time_t DT, ch *compactDT)
{ {
struct tm *fdt; struct tm *fdt;
int year, mon, day, hour, min, sec; int year, mon, day, hour, min, sec;
fdt = localtime(&DT); fdt = localtime(&DT);
year = fdt->tm_year + 1900; year = fdt->tm_year + 1900;
mon = fdt->tm_mon + 1; mon = fdt->tm_mon + 1;
day = fdt->tm_mday; day = fdt->tm_mday;
hour = fdt->tm_hour; hour = fdt->tm_hour;
skipping to change at line 1214 skipping to change at line 1214
compactDT[14] = 0; compactDT[14] = 0;
return; return;
} }
/******************************************************************************* */ /******************************************************************************* */
// convert a time_t date/time (e.g. st_mtime from stat() call) // convert a time_t date/time (e.g. st_mtime from stat() call)
// into a pretty date/time format "yyyy-mm-dd hh:mm:ss" // into a pretty date/time format "yyyy-mm-dd hh:mm:ss"
void pretty_datetime(const time_t DT, char *prettyDT) void pretty_datetime(time_t DT, ch *prettyDT)
{ {
struct tm *fdt; struct tm *fdt;
int year, mon, day, hour, min, sec; int year, mon, day, hour, min, sec;
fdt = localtime(&DT); fdt = localtime(&DT);
year = fdt->tm_year + 1900; year = fdt->tm_year + 1900;
mon = fdt->tm_mon + 1; mon = fdt->tm_mon + 1;
day = fdt->tm_mday; day = fdt->tm_mday;
hour = fdt->tm_hour; hour = fdt->tm_hour;
skipping to change at line 1294 skipping to change at line 1294
tsecs = mktime(&tmx); tsecs = mktime(&tmx);
*secs = tsecs; *secs = tsecs;
return; return;
} }
/******************************************************************************* */ /******************************************************************************* */
// Read and parse /proc file with records formatted "parmname xxxxxxx" // Read and parse /proc file with records formatted "parmname xxxxxxx"
// Find all requested parameters and return their numeric values // Find all requested parameters and return their numeric values
int parseprocfile(cchar *pfile, cchar *pname, double *value, ...) // EOL = 0 int parseprocfile(ch *pfile, ch *pname, double *value, ...) // EOL = 0
{ {
FILE *fid; FILE *fid;
va_list arglist; va_list arglist;
char buff[1000]; ch buff[1000];
cchar *pnames[20]; ch *pnames[20];
double *values[20]; double *values[20];
int ii, fcc, wanted, found; int ii, fcc, wanted, found;
pnames[0] = pname; // 1st parameter pnames[0] = pname; // 1st parameter
values[0] = value; values[0] = value;
*value = 0; *value = 0;
va_start(arglist,value); va_start(arglist,value);
for (ii = 1; ii < 20; ii++) // get all parameters for (ii = 1; ii < 20; ii++) // get all parameters
{ {
pnames[ii] = va_arg(arglist,char *); pnames[ii] = va_arg(arglist,ch *);
if (! pnames[ii] || pnames[ii] == (cchar *) 0x100000000) break; if (! pnames[ii] || pnames[ii] == (ch *) 0x100000000) break;
// ARM bug // ARM bug
values[ii] = va_arg(arglist,double *); values[ii] = va_arg(arglist,double *);
*values[ii] = 0; // initialize to zero *values[ii] = 0; // initialize to zero
} }
va_end(arglist); va_end(arglist);
if (ii == 20) zappcrash("parseProcFile, too many fields"); if (ii == 20) zappcrash("parseProcFile, too many fields");
wanted = ii; wanted = ii;
found = 0; found = 0;
skipping to change at line 1348 skipping to change at line 1348
if (found == wanted) break; // stop when all found if (found == wanted) break; // stop when all found
} }
fclose(fid); fclose(fid);
return found; return found;
} }
// Parse /proc record of the type "xxx xxxxx xxxxx xxxxxxxx xxx" // Parse /proc record of the type "xxx xxxxx xxxxx xxxxxxxx xxx"
// Return numeric values for requested fields (starting with 1) // Return numeric values for requested fields (starting with 1)
int parseprocrec(char *prec, int field, double *value, ...) // EOL = 0 int parseprocrec(ch *prec, int field, double *value, ...) // EOL = 0
{ {
va_list arglist; va_list arglist;
int xfield = 1, found = 0; int xfield = 1, found = 0;
va_start(arglist,value); va_start(arglist,value);
while (*prec == ' ') prec++; // skip leading blanks while (*prec == ' ') prec++; // skip leading blanks
while (field > 0) while (field > 0)
{ {
skipping to change at line 1396 skipping to change at line 1396
/******************************************************************************* */ /******************************************************************************* */
// Get processor performance and efficiency core counts (SMP counts). // Get processor performance and efficiency core counts (SMP counts).
// Return status: 0 = success, +N = error // Return status: 0 = success, +N = error
int get_smp_counts(int &Nperf, int &Neff) // 22.40 int get_smp_counts(int &Nperf, int &Neff) // 22.40
{ {
FILE *fid; FILE *fid;
int Nthreads, Nsockets; int Nthreads, Nsockets;
char *pp, buff[100] = ""; ch *pp, buff[100] = "";
fid = popen("lscpu | grep 'CPU(s):'","r"); fid = popen("lscpu | grep 'CPU(s):'","r");
if (! fid) goto erret; if (! fid) goto erret;
pp = fgets(buff,100,fid); pp = fgets(buff,100,fid);
pclose(fid); pclose(fid);
if (! pp || ! strmatchN(pp,"CPU(s):",7)) goto erret; if (! pp || ! strmatchN(pp,"CPU(s):",7)) goto erret;
Nthreads = atoi(pp+8); Nthreads = atoi(pp+8);
if (Nthreads < 1) goto erret; if (Nthreads < 1) goto erret;
fid = popen("lscpu | grep 'Core(s) per socket:'","r"); fid = popen("lscpu | grep 'Core(s) per socket:'","r");
skipping to change at line 1434 skipping to change at line 1434
/******************************************************************************* */ /******************************************************************************* */
// get current CPU temperature // get current CPU temperature
// returns 0 if cannot find // returns 0 if cannot find
int coretemp() // use package temp 22.1 int coretemp() // use package temp 22.1
{ {
FILE *fid; FILE *fid;
static int ftf = 1, zone, temp; static int ftf = 1, zone, temp;
static char Tfile[200]; static ch Tfile[200];
char buff[200], *pp; ch buff[200], *pp;
if (ftf) // first call, setup if (ftf) // first call, setup
{ // dump files ".../thermal_zone*/type" { // dump files ".../thermal_zone*/type"
ftf = 0; ftf = 0;
fid = popen("cat /sys/class/thermal/thermal_zone*/type","r"); // find file containing "pkg_temp" fid = popen("cat /sys/class/thermal/thermal_zone*/type","r"); // find file containing "pkg_temp"
if (! fid) return 0; if (! fid) return 0;
for (zone = 0; ; zone++) { for (zone = 0; ; zone++) {
pp = fgets(buff,200,fid); pp = fgets(buff,200,fid);
if (! pp) break; if (! pp) break;
pp = strstr(pp,"pkg_temp"); pp = strstr(pp,"pkg_temp");
skipping to change at line 1472 skipping to change at line 1472
if (! pp) return 0; if (! pp) return 0;
temp = atoi(pp) / 1000; // get temp, deg. C x 1000 temp = atoi(pp) / 1000; // get temp, deg. C x 1000
return temp; return temp;
} }
/******************************************************************************* */ /******************************************************************************* */
// get current temperature for given disk, e.g. "/dev/sda" // get current temperature for given disk, e.g. "/dev/sda"
// depends on "smartctl" command from package smartmontools // depends on "smartctl" command from package smartmontools
int disktemp(char *disk) int disktemp(ch *disk)
{ {
int id, temp; int id, temp;
char *pp, *pp2; ch *pp, *pp2;
char buff[200], command[100]; ch buff[200], command[100];
FILE *ffid; FILE *ffid;
temp = 0; temp = 0;
pp2 = 0; pp2 = 0;
snprintf(command,100,"smartctl -A %s",disk); snprintf(command,100,"smartctl -A %s",disk);
ffid = popen(command,"r"); ffid = popen(command,"r");
if (! ffid) return 0; if (! ffid) return 0;
while (true) { while (true) {
pp = fgets(buff,200,ffid); // revised for smartctl report pp = fgets(buff,200,ffid); // revised for smartctl report
skipping to change at line 1567 skipping to change at line 1567
// Lock or unlock a multi-process multi-thread resource. // Lock or unlock a multi-process multi-thread resource.
// Only one process/thread may possess a given lock. // Only one process/thread may possess a given lock.
// A reboot or process exit or crash releases the lock. // A reboot or process exit or crash releases the lock.
// lockfile is typically "/tmp/filename" and does not have to exist // lockfile is typically "/tmp/filename" and does not have to exist
// //
// fd = global_lock(lockfile); // fd = global_lock(lockfile);
// ... protected code // only one process/thread at a time // ... protected code // only one process/thread at a time
// global_unlock(fd,lockfile); // global_unlock(fd,lockfile);
int global_lock(cchar *lockfile) int global_lock(ch *lockfile)
{ {
int err, fd; int err, fd;
while (true) // loop until success while (true) // loop until success
{ {
fd = open(lockfile,O_RDWR|O_CREAT,0666); // open the lock file fd = open(lockfile,O_RDWR|O_CREAT,0666); // open the lock file
if (fd < 0) zappcrash("global_lock() %s",strerror(errno)); if (fd < 0) zappcrash("global_lock() %s",strerror(errno));
err = flock(fd,LOCK_EX); // request exclusive lock err = flock(fd,LOCK_EX); // request exclusive lock
if (! err) return fd + 1; // return value >= 1 if (! err) return fd + 1; // return value >= 1
close(fd); // failed close(fd); // failed
zsleep(0.001); // wait a bit and try again zsleep(0.001); // wait a bit and try again
} }
} }
void global_unlock(int fd, cchar *lockfile) void global_unlock(int fd, ch *lockfile)
{ {
int err = close(fd-1); int err = close(fd-1);
if (err < 0) zappcrash("global_unlock() %s",strerror(errno)); if (err < 0) zappcrash("global_unlock() %s",strerror(errno));
return; return;
} }
/******************************************************************************* */ /******************************************************************************* */
// lock or unlock a resource // lock or unlock a resource
// does not spin or wait for resource. // does not spin or wait for resource.
skipping to change at line 1662 skipping to change at line 1662
param = retval; param = retval;
mutex_unlock(&zget_lock); mutex_unlock(&zget_lock);
return retval; return retval;
} }
/******************************************************************************* */ /******************************************************************************* */
// Start a detached thread using a simplified protocol. // Start a detached thread using a simplified protocol.
// Will not make a zombie if caller exits without checking thread status. // Will not make a zombie if caller exits without checking thread status.
void start_detached_thread(void * threadfunc(void *), void * arg) pthread_t start_detached_thread(void * threadfunc(void *), void * arg)
{ {
pthread_attr_t pthattr; pthread_attr_t pthattr;
pthread_t pthtid; pthread_t pthtid;
int ii, err; int ii, err;
pthread_attr_init(&pthattr); pthread_attr_init(&pthattr);
pthread_attr_setdetachstate(&pthattr,PTHREAD_CREATE_DETACHED); pthread_attr_setdetachstate(&pthattr,PTHREAD_CREATE_DETACHED);
for (ii = 0; ii < 1000; ii++) for (ii = 0; ii < 1000; ii++)
{ {
err = pthread_create(&pthtid,&pthattr,threadfunc,arg); err = pthread_create(&pthtid,&pthattr,threadfunc,arg);
if (! err) return; if (! err) return pthtid;
zsleep(0.001); zsleep(0.001);
if (err == EAGAIN) continue; // this shit happens if (err == EAGAIN) continue; // this shit happens
break; break;
} }
zexit(1,"pthread_create() failure: %s",strerror(err)); zexit(1,"pthread_create() failure: %s",strerror(err));
return 0; // avoid compiler warning
} }
/******************************************************************************* */ /******************************************************************************* */
// Start a thread using a simplified protocol. // Start a thread using a simplified protocol.
// Caller must call wait_Jthread() to avoid creating a zombie process. // Caller must call wait_Jthread() to avoid creating a zombie process.
pthread_t start_Jthread(void * threadfunc(void *), void * arg) pthread_t start_Jthread(void * threadfunc(void *), void * arg)
{ {
pthread_t tid; pthread_t tid;
skipping to change at line 1783 skipping to change at line 1784
CPU_ZERO(&cpuset); CPU_ZERO(&cpuset);
CPU_SET(cpu,&cpuset); CPU_SET(cpu,&cpuset);
err = sched_setaffinity(0,sizeof(cpuset),&cpuset); err = sched_setaffinity(0,sizeof(cpuset),&cpuset);
if (err) Plog(2,"set_cpu_affinity() %s \n",strerror(errno)); if (err) Plog(2,"set_cpu_affinity() %s \n",strerror(errno));
return; return;
} }
/******************************************************************************* * /******************************************************************************* *
int err = zshell(cchar *options, cchar *command, ...) int err = zshell(ch *options, ch *command, ...)
Format and perform a shell command, wait for completion, return status. Format and perform a shell command, wait for completion, return status.
Suitable for commands that do not stop the GTK main loop > 2 seconds. Suitable for commands that do not stop the GTK main loop > 2 seconds.
options: may be null or may contain any of the following substrings: options: may be null or may contain any of the following substrings:
"log" write command to log file, stdout "log" write command to log file, stdout
"ack" popup user ACK message if the shell command has an error "ack" popup user ACK message if the shell command has an error
command: shell command with optional '%' printf formats command: shell command with optional '%' printf formats
... : optional arguments to stuff into printf formats ... : optional arguments to stuff into printf formats
returns: status of the shell command returns: status of the shell command
***/ ***/
int zshell(cchar *options, cchar *command, ...) int zshell(ch *options, ch *command, ...)
{ {
int Flog, Fack; int Flog, Fack;
va_list arglist; va_list arglist;
int err, cc, ccmax = 2*XFCC; int err, cc, ccmax = 2*XFCC;
char command2[2*XFCC]; ch command2[2*XFCC];
Flog = Fack = 0; Flog = Fack = 0;
if (options) { if (options) {
if (strstr(options,"log")) Flog = 1; // set options if (strstr(options,"log")) Flog = 1; // set options
if (strstr(options,"ack")) Fack = 1; if (strstr(options,"ack")) Fack = 1;
} }
va_start(arglist,command); // format command va_start(arglist,command); // format command
cc = vsnprintf(command2,ccmax,command,arglist); cc = vsnprintf(command2,ccmax,command,arglist);
skipping to change at line 1835 skipping to change at line 1836
Plog(0,"zshell error: %s \n",strerror(err)); // log error Plog(0,"zshell error: %s \n",strerror(err)); // log error
if (Fack) zmessageACK(mainwin,"command: %s \n error: %s", if (Fack) zmessageACK(mainwin,"command: %s \n error: %s",
command2, strerror(err)); // popup error to user if wanted command2, strerror(err)); // popup error to user if wanted
} }
return err; // return completion status return err; // return completion status
} }
/******************************************************************************* * /******************************************************************************* *
int err = zshell_gtk(cchar *options, cchar *command, ...) int err = zshell_gtk(ch *options, ch *command, ...)
Format and perform a shell command, wait for completion, return status. Format and perform a shell command, wait for completion, return status.
Shell command is done in a thread while caller process does GTK main loop. Shell command is done in a thread while caller process does GTK main loop.
This avoids "not responding" from GTK. This avoids "not responding" from GTK.
options: may be null or may contain any of the following substrings: options: may be null or may contain any of the following substrings:
"log" write command to log file, stdout "log" write command to log file, stdout
"ack" popup user ACK message if the shell command has an error "ack" popup user ACK message if the shell command has an error
command: shell command with optional '%' printf formats command: shell command with optional '%' printf formats
... : optional arguments to stuff into printf formats ... : optional arguments to stuff into printf formats
returns: status of the shell command returns: status of the shell command
***/ ***/
typedef struct { typedef struct {
char *command; ch *command;
int done; int done;
int err; int err;
} zshdat_t; } zshdat_t;
int zshell_gtk(cchar *options, cchar *command, ...) int zshell_gtk(ch *options, ch *command, ...)
{ {
void * zshell_thread(void *); void * zshell_thread(void *);
zshdat_t zshdat; zshdat_t zshdat;
int Flog, Fack; int Flog, Fack;
va_list arglist; va_list arglist;
int jj, cc, cc2; int jj, cc, cc2;
Flog = Fack = 0; Flog = Fack = 0;
if (options) { if (options) {
if (strstr(options,"log")) Flog = 1; // set options if (strstr(options,"log")) Flog = 1; // set options
if (strstr(options,"ack")) Fack = 1; if (strstr(options,"ack")) Fack = 1;
} }
cc = strlen(command) + 1000; cc = strlen(command) + 1000;
zshdat.command = (char *) zmalloc(cc+1,"zshell"); // allocate memory zshdat.command = (ch *) zmalloc(cc+1,"zshell"); // allocate memory
va_start(arglist,command); // format command va_start(arglist,command); // format command
cc2 = vsnprintf(zshdat.command,cc,command,arglist); cc2 = vsnprintf(zshdat.command,cc,command,arglist);
va_end(arglist); va_end(arglist);
if (cc2 >= cc) zappcrash("zshell: buffer overflow: %d",cc2); if (cc2 >= cc) zappcrash("zshell: buffer overflow: %d",cc2);
if (Flog) Plog(0,"zshell: %s \n",zshdat.command); // command > log file if wanted if (Flog) Plog(0,"zshell: %s \n",zshdat.command); // command > log file if wanted
zshdat.done = 0; zshdat.done = 0;
start_detached_thread(zshell_thread,(void *) &zshdat); // do command in parallel thread start_detached_thread(zshell_thread,(void *) &zshdat); // do command in parallel thread
skipping to change at line 1937 skipping to change at line 1938
To get the command exit status: status = command_status(contx). To get the command exit status: status = command_status(contx).
If the command is still busy, -1 is returned. If the command is still busy, -1 is returned.
To kill a command before output is complete: command_kill(contx); To kill a command before output is complete: command_kill(contx);
Outputs are subjects for zfree(). Outputs are subjects for zfree().
***/ ***/
FILE * CO_contx[10] = { 0,0,0,0,0,0,0,0,0,0 }; FILE * CO_contx[10] = { 0,0,0,0,0,0,0,0,0,0 };
int CO_status[10]; int CO_status[10];
char * command_output(int &contx, cchar *command, ...) // simplify, allow parallel usage ch * command_output(int &contx, ch *command, ...) // simplify, allow parallel usage
{ {
FILE *fid; FILE *fid;
va_list arglist; va_list arglist;
char buff[10000], *prec; ch buff[10000], *prec;
if (contx == 0) // start new command if (contx == 0) // start new command
{ {
for (contx = 1; contx < 10; contx++) for (contx = 1; contx < 10; contx++)
if (CO_contx[contx] == 0) break; if (CO_contx[contx] == 0) break;
if (contx == 10) { if (contx == 10) {
Plog(0,"*** command_output(), parallel usage > 9 \n"); Plog(0,"*** command_output(), parallel usage > 9 \n");
return 0; return 0;
} }
skipping to change at line 1996 skipping to change at line 1997
CO_contx[contx] = 0; // mark context free CO_contx[contx] = 0; // mark context free
return 0; return 0;
} }
/******************************************************************************* */ /******************************************************************************* */
// Signal a running subprocess by name (name of executable or shell command). // Signal a running subprocess by name (name of executable or shell command).
// Signal is "pause", "resume" or "kill". If process is paused, kill may not wo rk, // Signal is "pause", "resume" or "kill". If process is paused, kill may not wo rk,
// so issue resume first if process is paused. // so issue resume first if process is paused.
int signalProc(cchar *pname, cchar *signal) int signalProc(ch *pname, ch *signal)
{ {
pid_t pid; pid_t pid;
FILE *fid; FILE *fid;
char buff[100], *pp; ch buff[100], *pp;
int err, nsignal = 0; int err, nsignal = 0;
snprintf(buff,100,"ps -C %s h o pid",pname); snprintf(buff,100,"ps -C %s h o pid",pname);
fid = popen(buff,"r"); // popen() instead of system() fid = popen(buff,"r"); // popen() instead of system()
if (! fid) return 2; if (! fid) return 2;
pp = fgets(buff,100,fid); pp = fgets(buff,100,fid);
pclose(fid); pclose(fid);
if (! pp) return 4; if (! pp) return 4;
pid = atoi(buff); pid = atoi(buff);
skipping to change at line 2027 skipping to change at line 2028
err = kill(pid,nsignal); err = kill(pid,nsignal);
return err; return err;
} }
/******************************************************************************* */ /******************************************************************************* */
// fgets() with additional feature: trailing \n \r are removed. // fgets() with additional feature: trailing \n \r are removed.
// optional bf flag: true if trailing blanks are to be removed. // optional bf flag: true if trailing blanks are to be removed.
// trailing null character is assured. // trailing null character is assured.
char * fgets_trim(char *buff, int maxcc, FILE *fid, int bf) ch * fgets_trim(ch *buff, int maxcc, FILE *fid, int bf)
{ {
int cc; int cc;
char *pp; ch *pp;
pp = fgets(buff,maxcc,fid); pp = fgets(buff,maxcc,fid);
if (! pp) return pp; if (! pp) return pp;
cc = strlen(buff); cc = strlen(buff);
if (bf) while (cc && buff[cc-1] > 0 && buff[cc-1] <= ' ') --cc; if (bf) while (cc && buff[cc-1] > 0 && buff[cc-1] <= ' ') --cc;
else while (cc && buff[cc-1] > 0 && buff[cc-1] < ' ') --cc; else while (cc && buff[cc-1] > 0 && buff[cc-1] < ' ') --cc;
buff[cc] = 0; buff[cc] = 0;
return pp; return pp;
} }
/******************************************************************************* */ /******************************************************************************* */
// Return 1 if both filespecs have the same folder, else return 0. // Return 1 if both filespecs have the same folder, else return 0.
// Both folders must be specified, at least one with ending '/' // Both folders must be specified, at least one with ending '/'
// (true if a file name is present) // (true if a file name is present)
int samefolder(cchar *file1, cchar *file2) int samefolder(ch *file1, ch *file2)
{ {
cchar *p1, *p2; ch *p1, *p2;
int cc1, cc2, cc; int cc1, cc2, cc;
p1 = strrchr(file1,'/'); // /dir1/dir2 p1 = strrchr(file1,'/'); // /dir1/dir2
p2 = strrchr(file2,'/'); // /dir1/dir2/file p2 = strrchr(file2,'/'); // /dir1/dir2/file
cc1 = cc2 = 0; cc1 = cc2 = 0;
if (p1) cc1 = p1 - file1; // /dir1/dir2/file if (p1) cc1 = p1 - file1; // /dir1/dir2/file
if (p2) cc2 = p2 - file2; // | | if (p2) cc2 = p2 - file2; // | |
if (cc2 > cc1) cc = cc2; // 0 cc if (cc2 > cc1) cc = cc2; // 0 cc
else cc = cc1; else cc = cc1;
if (cc == 0) return 0; if (cc == 0) return 0;
skipping to change at line 2084 skipping to change at line 2085
/name1/name2/ folder /name1/name2/ with no file /name1/name2/ folder /name1/name2/ with no file
/name1/name2 folder /name1/name2/ if name2 a folder, /name1/name2 folder /name1/name2/ if name2 a folder,
otherwise folder /name1/ and file name2 otherwise folder /name1/ and file name2
/name1/name2.xxx if .xxx < 8 chars, returns file name2 and ext .xxx, /name1/name2.xxx if .xxx < 8 chars, returns file name2 and ext .xxx,
otherwise returns file name2.xxx and no ext otherwise returns file name2.xxx and no ext
returns 0 if no error, else 1 returns 0 if no error, else 1
******************************************************************************** */ ******************************************************************************** */
int parsefile(cchar *ppath, char **pfolder, char **pfile, char **pext) int parsefile(ch *ppath, ch **pfolder, ch **pfile, ch **pext)
{ {
STATB statB; STATB statB;
static char folder[1000], file[200], ext[8]; static ch folder[1000], file[200], ext[8];
char *pp; ch *pp;
int err, cc1, cc2; int err, cc1, cc2;
*pfolder = *pfile = *pext = null; *pfolder = *pfile = *pext = null;
cc1 = strlen(ppath); cc1 = strlen(ppath);
if (cc1 > 999) return 1; // ppath too long if (cc1 > 999) return 1; // ppath too long
strcpy(folder,ppath); strcpy(folder,ppath);
*pfolder = folder; *pfolder = folder;
err = stat(folder,&statB); // have folder only err = stat(folder,&statB); // have folder only
if (! err && S_ISDIR(statB.st_mode)) return 0; if (! err && S_ISDIR(statB.st_mode)) return 0;
pp = (char *) strrchr(folder,'/'); pp = (ch *) strrchr(folder,'/');
if (! pp) return 1; // illegal if (! pp) return 1; // illegal
pp++; pp++;
cc2 = pp - folder; cc2 = pp - folder;
if (cc2 < 2 || cc2 == cc1) return 0; // have /xxxx or /xxxx/ if (cc2 < 2 || cc2 == cc1) return 0; // have /xxxx or /xxxx/
if (strlen(pp) > 199) return 1; // filename too long if (strlen(pp) > 199) return 1; // filename too long
strcpy(file,pp); // file part strcpy(file,pp); // file part
*pfile = file; *pfile = file;
*pp = 0; // remove from folder part *pp = 0; // remove from folder part
pp = (char *) strrchr(file,'.'); pp = (ch *) strrchr(file,'.');
if (! pp || strlen(pp) > 7) return 0; // file part, no .ext if (! pp || strlen(pp) > 7) return 0; // file part, no .ext
strcpy(ext,pp); // .ext part strcpy(ext,pp); // .ext part
*pext = ext; *pext = ext;
*pp = 0; // remove from file part *pp = 0; // remove from file part
return 0; return 0;
} }
/******************************************************************************* */ /******************************************************************************* */
// Move a source file to a destination file and delete the source file. // Move a source file to a destination file and delete the source file.
// Equivalent to rename(), but the two files MAY be on different file systems. // Equivalent to rename(), but the two files MAY be on different file systems.
// Pathnames must be absolute (start with '/'). // Pathnames must be absolute (start with '/').
// Returns 0 if OK, +N if not. // Returns 0 if OK, +N if not.
// file names with embedded quote (") will fail // file names with embedded quote (") will fail
int renamez(cchar *file1, cchar *file2) int renamez(ch *file1, ch *file2)
{ {
char *pp1, *pp2; ch *pp1, *pp2;
int err, Frename = 0; int err, Frename = 0;
if (*file1 != '/' || *file2 != '/') return 1; // not absolute pathnames if (*file1 != '/' || *file2 != '/') return 1; // not absolute pathnames
pp1 = strchr((char *) file1+1,'/'); pp1 = strchr((ch *) file1+1,'/');
pp2 = strchr((char *) file2+1,'/'); pp2 = strchr((ch *) file2+1,'/');
if (! pp1 || ! pp2) return 2; if (! pp1 || ! pp2) return 2;
*pp1 = *pp2 = 0; *pp1 = *pp2 = 0;
if (strmatch(file1,file2)) Frename = 1; if (strmatch(file1,file2)) Frename = 1;
*pp1 = *pp2 = '/'; *pp1 = *pp2 = '/';
if (Frename) { // same top folder if (Frename) { // same top folder
err = rename(file1,file2); err = rename(file1,file2);
if (err) return errno; if (err) return errno;
else return 0; else return 0;
skipping to change at line 2163 skipping to change at line 2164
err = zshell(0,"mv -f \"%s\" \"%s\" ",file1,file2); // not err = zshell(0,"mv -f \"%s\" \"%s\" ",file1,file2); // not
return err; return err;
} }
/******************************************************************************* */ /******************************************************************************* */
// Check if a folder exists. If not, ask user if it should be created. // Check if a folder exists. If not, ask user if it should be created.
// Returns 0 if OK or +N if error or user refused to create. // Returns 0 if OK or +N if error or user refused to create.
// The user is notified of failure, no other message needed. // The user is notified of failure, no other message needed.
int check_create_dir(char *path) int check_create_dir(ch *path)
{ {
int err, yn; int err, yn;
STATB statB; STATB statB;
err = stat(path,&statB); // check status err = stat(path,&statB); // check status
if (! err) { if (! err) {
if (S_ISDIR(statB.st_mode)) return 0; // exists, folder, OK if (S_ISDIR(statB.st_mode)) return 0; // exists, folder, OK
else { else {
zmessageACK(mainwin,"%s \n %s",path,strerror(ENOTDIR)); // exists, not a folder zmessageACK(mainwin,"%s \n %s",path,strerror(ENOTDIR)); // exists, not a folder
return ENOTDIR; return ENOTDIR;
skipping to change at line 2198 skipping to change at line 2199
zmessageACK(mainwin,"%s \n %s",path,strerror(errno)); // failed to create zmessageACK(mainwin,"%s \n %s",path,strerror(errno)); // failed to create
return errno; return errno;
} }
/******************************************************************************* */ /******************************************************************************* */
// Copy file to file or file to an existing folder. // Copy file to file or file to an existing folder.
// Missing output folders will be created. // Missing output folders will be created.
// If input file is a symlink, copy the symlink, not the file. // If input file is a symlink, copy the symlink, not the file.
int copyFile(cchar *sfile, cchar *dfile) int copyFile(ch *sfile, ch *dfile)
{ {
#define BIOCC (1024*1024) // read/write block size #define BIOCC (1024*1024) // read/write block size
int fid1, fid2, err, cc; int fid1, fid2, err, cc;
char *pp1, *pp2, buff[BIOCC]; ch *pp1, *pp2, buff[BIOCC];
STATB statB; STATB statB;
static char *dfile2 = 0; static ch *dfile2 = 0;
if (dfile2) zfree(dfile2); // stop memory leak if (dfile2) zfree(dfile2); // stop memory leak
dfile2 = 0; dfile2 = 0;
err = stat(dfile,&statB); err = stat(dfile,&statB);
if (! err && S_ISDIR(statB.st_mode)) { // output is an existing folder if (! err && S_ISDIR(statB.st_mode)) { // output is an existing folder
pp1 = (char *) strrchr(sfile,'/'); // get source file base name pp1 = (ch *) strrchr(sfile,'/'); // get source file base name
if (pp1) pp1++; if (pp1) pp1++;
else pp1 = (char *) sfile; else pp1 = (ch *) sfile;
cc = strlen(pp1); // construct output file path: cc = strlen(pp1); // construct output file path:
dfile2 = zstrdup(dfile,"copyFile",cc+4); // output folder + base name dfile2 = zstrdup(dfile,"copyFile",cc+4); // output folder + base name
pp2 = dfile2 + strlen(dfile2); pp2 = dfile2 + strlen(dfile2);
if (pp2[-1] != '/') *pp2++ = '/'; // insure '/' after folder if (pp2[-1] != '/') *pp2++ = '/'; // insure '/' after folder
strcpy(pp2,pp1); strcpy(pp2,pp1);
dfile = dfile2; // output file full path dfile = dfile2; // output file full path
} }
else { // output is a file path else { // output is a file path
pp2 = (char *) dfile; pp2 = (ch *) dfile;
pp2 = strrchr(pp2+1,'/'); pp2 = strrchr(pp2+1,'/');
if (pp2) *pp2 = 0; if (pp2) *pp2 = 0;
err = zshell("ack","mkdir -p -m 0750 \"%s\" ",dfile); err = zshell("ack","mkdir -p -m 0750 \"%s\" ",dfile);
if (pp2) *pp2 = '/'; if (pp2) *pp2 = '/';
if (err) return errno; if (err) return errno;
} }
err = lstat(sfile,&statB); // get input file attributes err = lstat(sfile,&statB); // get input file attributes
if (err) { if (err) {
Plog(0,"%s \n %s \n",strerror(errno),sfile); Plog(0,"%s \n %s \n",strerror(errno),sfile);
skipping to change at line 2299 skipping to change at line 2300
} }
return 0; return 0;
} }
/******************************************************************************* */ /******************************************************************************* */
// copy a file using shell 'cp' command // copy a file using shell 'cp' command
// file owner, permissions, and timestamps are copied // file owner, permissions, and timestamps are copied
// returns 0 if OK, else errno // returns 0 if OK, else errno
int cp_copy(cchar *sfile, cchar *dfile) int cp_copy(ch *sfile, ch *dfile)
{ {
if (strmatch(sfile,dfile)) { if (strmatch(sfile,dfile)) {
Plog(0,"ignore copy file to self: %s \n",sfile); Plog(0,"ignore copy file to self: %s \n",sfile);
return 0; return 0;
} }
int err = zshell(0,"cp -f -p \"%s\" \"%s\" ",sfile,dfile); int err = zshell(0,"cp -f -p \"%s\" \"%s\" ",sfile,dfile);
return err; return err;
} }
/******************************************************************************* */ /******************************************************************************* */
// get the available space on disk of the given file // get the available space on disk of the given file
// returns disk space in MB (limit 2 billion MB) // returns disk space in MB (limit 2 billion MB)
int diskspace(cchar *file) int diskspace(ch *file)
{ {
char command[200], buff[200]; ch command[200], buff[200];
char *pp; ch *pp;
int avail; int avail;
FILE *fid; FILE *fid;
snprintf(command,200,"df --output=avail \"%s\" ",file); snprintf(command,200,"df --output=avail \"%s\" ",file);
pp = strchr(command,'/'); pp = strchr(command,'/');
if (! pp) return 0; if (! pp) return 0;
fid = popen(command,"r"); fid = popen(command,"r");
if (! fid) return 0; if (! fid) return 0;
pp = fgets(buff,200,fid); // "Avail" header pp = fgets(buff,200,fid); // "Avail" header
skipping to change at line 2342 skipping to change at line 2343
avail = 0.001 * atoll(pp); // MB space avail = 0.001 * atoll(pp); // MB space
return avail; return avail;
} }
/******************************************************************************* */ /******************************************************************************* */
// if a file has an incorrect .ext, return the correct .ext // if a file has an incorrect .ext, return the correct .ext
// return null if file is OK or cannot be determined // return null if file is OK or cannot be determined
// returned .ext is in a static buffer // returned .ext is in a static buffer
char * get_file_extension(cchar *file) ch * get_file_extension(ch *file)
{ {
cchar *fext1; ch *fext1;
char *extlist, *fext2, *pp; ch *extlist, *fext2, *pp;
char *buff; ch *buff;
int cc; int cc;
FILE *fid; FILE *fid;
static char fext3[20]; static ch fext3[20];
errno = 0; errno = 0;
cc = strlen(file) + 20; cc = strlen(file) + 20;
buff = (char *) zmalloc(cc,0); buff = (ch *) zmalloc(cc,0);
snprintf(buff,cc,"file --extension %s",file); // 'file' command - get correct extensions snprintf(buff,cc,"file --extension %s",file); // 'file' command - get correct extensions
fid = popen(buff,"r"); fid = popen(buff,"r");
if (! fid) goto ret0; if (! fid) goto ret0;
extlist = fgets(buff,cc,fid); // /.../filename.ext: ext1/ext2/... extlist = fgets(buff,cc,fid); // /.../filename.ext: ext1/ext2/...
pclose(fid); pclose(fid);
if (! extlist) goto ret0; if (! extlist) goto ret0;
extlist = strrchr(extlist,':'); // extlist = : ext1/ext2/... extlist = strrchr(extlist,':'); // extlist = : ext1/ext2/...
if (! extlist) goto ret0; if (! extlist) goto ret0;
extlist += 2; // extlist = ext1/ext2/... extlist += 2; // extlist = ext1/ext2/...
skipping to change at line 2393 skipping to change at line 2394
/******************************************************************************* */ /******************************************************************************* */
// Return all the file names in a folder, sorted in alphabetic order. // Return all the file names in a folder, sorted in alphabetic order.
// Subfolders are not included. // Subfolders are not included.
// The 'files' argument is allocated and filled with pointers to file names. // The 'files' argument is allocated and filled with pointers to file names.
// (the names in the folder, not the full path names) // (the names in the folder, not the full path names)
// The number of files found is returned. // The number of files found is returned.
// -1 is returned if the folder is invalid or other error. // -1 is returned if the folder is invalid or other error.
// If 'files' is returned non-zero, it is subject to zfree() // If 'files' is returned non-zero, it is subject to zfree()
int zreaddir(cchar *folder, char **&files) int zreaddir(ch *folder, ch **&files)
{ {
struct dirent *dirent1; struct dirent *dirent1;
int Nfiles = 0, maxfiles = 100; int Nfiles = 0, maxfiles = 100;
DIR *direc; DIR *direc;
char **ufiles, **ufiles2; ch **ufiles, **ufiles2;
files = 0; // nothing returned yet files = 0; // nothing returned yet
ufiles = (char **) zmalloc(maxfiles * sizeof(char *),"zreaddir"); // starting space ufiles = (ch **) zmalloc(maxfiles * sizeof(ch *),"zreaddir"); // starting space
direc = opendir(folder); // open caller's folder direc = opendir(folder); // open caller's folder
if (! direc) return -1; if (! direc) return -1;
while (true) while (true)
{ {
if (Nfiles == maxfiles) // out of space if (Nfiles == maxfiles) // out of space
{ {
ufiles2 = (char **) zmalloc(2 * maxfiles * sizeof(char *),"zreaddir"); ufiles2 = (ch **) zmalloc(2 * maxfiles * sizeof(ch *),"zreaddir");
// allocate new space = 2x old space // allocate new space = 2x old space
memcpy(ufiles2,ufiles, maxfiles * sizeof(char *)); memcpy(ufiles2,ufiles, maxfiles * sizeof(ch *));
// copy data to new space // copy data to new space
zfree(ufiles); // free old space zfree(ufiles); // free old space
ufiles = ufiles2; // set new space ufiles = ufiles2; // set new space
maxfiles *= 2; // new capacity maxfiles *= 2; // new capacity
} }
dirent1 = readdir(direc); // get next file in folder dirent1 = readdir(direc); // get next file in folder
if (! dirent1) break; if (! dirent1) break;
if (dirent1->d_type != DT_REG) continue; // skip subfolders if (dirent1->d_type != DT_REG) continue; // skip subfolders
ufiles[Nfiles] = zstrdup(dirent1->d_name,"zreaddir"); // add to file list ufiles[Nfiles] = zstrdup(dirent1->d_name,"zreaddir"); // add to file list
Nfiles++; Nfiles++;
skipping to change at line 2437 skipping to change at line 2438
closedir(direc); closedir(direc);
if (Nfiles > 1) HeapSort(ufiles,Nfiles); // sort file list if (Nfiles > 1) HeapSort(ufiles,Nfiles); // sort file list
files = ufiles; // return allocated file list files = ufiles; // return allocated file list
return Nfiles; // return file count return Nfiles; // return file count
} }
/******************************************************************************* */ /******************************************************************************* */
// int NR = zreadfile(cchar *filename, char &**rrecs) // int NR = zreadfile(ch *filename, ch &**rrecs)
// //
// Read a text file into a list of char * strings, 1 record per string. // Read a text file into a list of ch * strings, 1 record per string.
// The strings are allocated as needed. The number of records is returned. // The strings are allocated as needed. The number of records is returned.
// Returned: -1 error (errno is set) // Returned: -1 error (errno is set)
// 0 empty file // 0 empty file
// NR records read, > 0 // NR records read, > 0
// Returned record N: rrecs[N] (char *) // Returned record N: rrecs[N] (ch *)
// Trailing blanks and '\n' characters are removed. // Trailing blanks and '\n' characters are removed.
// The maximum record length is 1000 chars, including terminating null. // The maximum record length is 1000 chars, including terminating null.
// The maximum record count is 1000 records. // The maximum record count is 1000 records.
// Null records ("" or "\n") are not included in output. // Null records ("" or "\n") are not included in output.
// rrecs[NR] (last + 1) is a null pointer. // rrecs[NR] (last + 1) is a null pointer.
int zreadfile(cchar *filename, char **&rrecs) int zreadfile(ch *filename, ch **&rrecs)
{ {
FILE *fid; FILE *fid;
char *recs[1001]; ch *recs[1001];
char buff[1001], *pp; ch buff[1001], *pp;
int cc, NR = 0; int cc, NR = 0;
rrecs = 0; // initz. no data rrecs = 0; // initz. no data
fid = fopen(filename,"r"); // open file fid = fopen(filename,"r"); // open file
if (! fid) return -1; if (! fid) return -1;
while (true) while (true)
{ {
pp = fgets(buff,1001,fid); // read record pp = fgets(buff,1001,fid); // read record
skipping to change at line 2478 skipping to change at line 2479
if (cc > 999) { if (cc > 999) {
zmessageACK(mainwin,"zreadfile() record too long %s",filename); zmessageACK(mainwin,"zreadfile() record too long %s",filename);
errno = EFBIG; errno = EFBIG;
return -1; return -1;
} }
while (cc && pp[cc-1] > 0 && pp[cc-1] <= ' ') --cc; // remove trailing \n, \r, blanks, etc. while (cc && pp[cc-1] > 0 && pp[cc-1] <= ' ') --cc; // remove trailing \n, \r, blanks, etc.
pp[cc] = 0; // terminating null pp[cc] = 0; // terminating null
if (cc == 0) continue; // discard null recs if (cc == 0) continue; // discard null recs
recs[NR] = (char *) zmalloc(cc+1,"zreadfile"); // allocate memory recs[NR] = (ch *) zmalloc(cc+1,"zreadfile"); // allocate memory
memcpy(recs[NR],pp,cc+1); // copy record memcpy(recs[NR],pp,cc+1); // copy record
NR++; NR++;
if (NR == 1000) { if (NR == 1000) {
zmessageACK(mainwin,"zreadfile() too many records %s",filename); zmessageACK(mainwin,"zreadfile() too many records %s",filename);
errno = EFBIG; errno = EFBIG;
return -1; return -1;
} }
} }
fclose(fid); fclose(fid);
recs[NR] = 0; // last record + 1 = null recs[NR] = 0; // last record + 1 = null
cc = (NR + 1) * sizeof(char *); cc = (NR + 1) * sizeof(ch *);
// allocate caller rrecs list // allocate caller rrecs list
rrecs = (char **) zmalloc(cc,"zreadfile"); rrecs = (ch **) zmalloc(cc,"zreadfile");
memcpy(rrecs,recs,cc); // copy record pointers + null memcpy(rrecs,recs,cc); // copy record pointers + null
return NR; return NR;
} }
// int NR = zwritefile(cchar *filename, char **rrecs) // int NR = zwritefile(ch *filename, ch **rrecs)
// write array of records to a file, each with trailing \n character. // write array of records to a file, each with trailing \n character.
// EOF is signalled with a null pointer: rrecs[last] = null // EOF is signalled with a null pointer: rrecs[last] = null
// returns no. records written (>= 0) or -1 if file error. // returns no. records written (>= 0) or -1 if file error.
int zwritefile(cchar *filename, char **rrecs) int zwritefile(ch *filename, ch **rrecs)
{ {
FILE *fid; FILE *fid;
int nr, nn; int nr, nn;
fid = fopen(filename,"w"); // open file fid = fopen(filename,"w"); // open file
if (! fid) return -1; if (! fid) return -1;
for (nr = 0; nr < 1000; nr++) for (nr = 0; nr < 1000; nr++)
{ {
if (! rrecs[nr]) break; if (! rrecs[nr]) break;
skipping to change at line 2525 skipping to change at line 2526
if (nn <= 0) break; if (nn <= 0) break;
nr++; nr++;
} }
fclose(fid); fclose(fid);
return nr; return nr;
} }
// free allocated records and their pointer list // free allocated records and their pointer list
void zreadfile_free(char **&rrecs) void zreadfile_free(ch **&rrecs)
{ {
for (int ii = 0; rrecs[ii]; ii++) // loop until null pointer for (int ii = 0; rrecs[ii]; ii++) // loop until null pointer
zfree(rrecs[ii]); zfree(rrecs[ii]);
zfree(rrecs); zfree(rrecs);
rrecs = 0; // set no data rrecs = 0; // set no data
return; return;
} }
/******************************************************************************* */ /******************************************************************************* */
// escape quote marks (") in a file name for use in shell commands // escape quote marks (") in a file name for use in shell commands
// returned file is subject for zfree() // returned file is subject for zfree()
char * zescape_quotes(cchar *file1) ch * zescape_quotes(ch *file1)
{ {
char *file2 = 0; ch *file2 = 0;
if (strchr(file1,'"') == 0) { if (strchr(file1,'"') == 0) {
file2 = zstrdup(file1,"zescape_quotes"); file2 = zstrdup(file1,"zescape_quotes");
return file2; return file2;
} }
file2 = zstrdup(file1,"zescape_quotes",20); file2 = zstrdup(file1,"zescape_quotes",20);
repl_1str(file1,file2,"\"","\\\""); repl_1str(file1,file2,"\"","\\\"");
return file2; return file2;
} }
skipping to change at line 2661 skipping to change at line 2662
} }
return faultrate; return faultrate;
} }
void * pagefaultrate_names::threadfunc(void *) void * pagefaultrate_names::threadfunc(void *)
{ {
using namespace pagefaultrate_names; using namespace pagefaultrate_names;
FILE *fid; FILE *fid;
char *pp, buff[200]; ch *pp, buff[200];
double pfs1, pfs2, fps, elaps; double pfs1, pfs2, fps, elaps;
while (true) while (true)
{ {
sleep(2); sleep(2);
time2 = get_seconds(); time2 = get_seconds();
elaps = time2 - time1; elaps = time2 - time1;
time1 = time2; time1 = time2;
skipping to change at line 2691 skipping to change at line 2692
} }
Plog(0,"pagefaultrate() failure \n"); Plog(0,"pagefaultrate() failure \n");
return 0; return 0;
} }
/******************************************************************************* * /******************************************************************************* *
substringR() substringR()
char * substringR(cchar *string, cchar *delims, int Nth) ch * substringR(ch *string, ch *delims, int Nth)
Get the Nth substring in an input string, which contains at least N Get the Nth substring in an input string, which contains at least N
substrings delimited by the character(s) in delim (e.g. blank, comma). substrings delimited by the character(s) in delim (e.g. blank, comma).
Nth >= 1. Nth >= 1.
Returns a pointer to the found substring (actually a pointer to a Returns a pointer to the found substring (actually a pointer to a
copy of the found substring, with a null terminator appended). copy of the found substring, with a null terminator appended).
The returned pointer is a subject for zfree(). The returned pointer is a subject for zfree().
If a delimiter is immediately followed by another delimiter, it is If a delimiter is immediately followed by another delimiter, it is
skipping to change at line 2732 skipping to change at line 2733
1: (null) 1: (null)
2: a 2: a
3: bb 3: bb
4: cc 4: cc
5: (one blank) 5: (one blank)
6: ddee,ffggg 6: ddee,ffggg
7: (null) last+1 substring 7: (null) last+1 substring
******************************************************************************** */ ******************************************************************************** */
char * substringR(cchar *string, cchar *delims, int Nth) ch * substringR(ch *string, ch *delims, int Nth)
{ {
char *pf1, pf2[2000]; ch *pf1, pf2[2000];
// 2000 char. limit // 2000 char. limit
cchar quote = '"'; ch quote = '"';
int nf, fcc = 0; int nf, fcc = 0;
if (! string || ! *string) return 0; // bad call if (! string || ! *string) return 0; // bad call
if (Nth < 1) return 0; if (Nth < 1) return 0;
pf1 = (char *) string - 1; // start parse pf1 = (ch *) string - 1; // start parse
nf = 0; nf = 0;
while (nf < Nth) while (nf < Nth)
{ {
pf1++; // start substring pf1++; // start substring
nf++; nf++;
fcc = 0; fcc = 0;
while (*pf1 == ' ') pf1++; // skip leading blanks while (*pf1 == ' ') pf1++; // skip leading blanks
skipping to change at line 2776 skipping to change at line 2777
if (nf < Nth) return 0; // no Nth substring if (nf < Nth) return 0; // no Nth substring
if (fcc == 0 && *pf1 == 0) return 0; // empty substring if (fcc == 0 && *pf1 == 0) return 0; // empty substring
pf2[fcc] = 0; pf2[fcc] = 0;
return zstrdup(pf2,"substringR"); // returned string (needs zfree()) return zstrdup(pf2,"substringR"); // returned string (needs zfree())
} }
// alternative with one delimiter // alternative with one delimiter
char * substringR(cchar *string, cchar delim, int Nth) ch * substringR(ch *string, ch delim, int Nth)
{ {
char delims[2] = "x"; ch delims[2] = "x";
*delims = delim; *delims = delim;
return substringR(string,delims,Nth); return substringR(string,delims,Nth);
} }
// non-thread-safe versions without zfree() requirement. // non-thread-safe versions without zfree() requirement.
char * substring(cchar *string, cchar *delims, int Nth) ch * substring(ch *string, ch *delims, int Nth)
{ {
char *s1; ch *s1;
static char s2[2000]; static ch s2[2000];
s1 = substringR(string,delims,Nth); s1 = substringR(string,delims,Nth);
if (! s1) return 0; if (! s1) return 0;
strcpy(s2,s1); strcpy(s2,s1);
zfree(s1); zfree(s1);
return s2; return s2;
} }
char * substring(cchar *string, cchar delim, int Nth) ch * substring(ch *string, ch delim, int Nth)
{ {
char delims[2] = "x"; ch delims[2] = "x";
*delims = delim; *delims = delim;
return substring(string,delims,Nth); return substring(string,delims,Nth);
} }
/******************************************************************************* * /******************************************************************************* *
stat = strParms(begin, input, pname, maxcc, pval) stat = strParms(begin, input, pname, maxcc, pval)
Parse an input string with parameter names and values: Parse an input string with parameter names and values:
"pname1=pval1 | pname2 | pname3=pval3 | pname4 ..." "pname1=pval1 | pname2 | pname3=pval3 | pname4 ..."
begin int & must be 1 to start new string, is modified begin int & must be 1 to start new string, is modified
input cchar * input string input ch * input string
pname char * output parameter name pname ch * output parameter name
maxcc int max. length for pname, including null maxcc int max. length for pname, including null
pval double & output parameter value pval double & output parameter value
stat int status: 0=OK, -1=EOL, 1=parse error stat int status: 0=OK, -1=EOL, 1=parse error
Each call returns the next pname and pval. Each call returns the next pname and pval.
A pname with no pval is assigned a value of 1 (present). A pname with no pval is assigned a value of 1 (present).
Input format: pname1 | pname2=pval2 | pname3 ... null Input format: pname1 | pname2=pval2 | pname3 ... null
Leading blanks are ignored, and pnames may have embedded blanks. Leading blanks are ignored, and pnames may have embedded blanks.
pvals must convert to double using convSD (accepts decimal point or comma) pvals must convert to double using convSD (accepts decimal point or comma)
***/ ***/
int strParms(int &begin, cchar *input, char *pname, int maxcc, double &pval) int strParms(int &begin, ch *input, ch *pname, int maxcc, double &pval)
{ {
static int ii, beginx = 3579246; static int ii, beginx = 3579246;
cchar *pnamex, *delim; ch *pnamex, *delim;
int cc, err; int cc, err;
if (begin == 1) { // start new string if (begin == 1) { // start new string
begin = ++beginx; begin = ++beginx;
ii = 0; ii = 0;
} }
if (begin != beginx) zappcrash("strParms call error"); // thread safe, not reentrant if (begin != beginx) zappcrash("strParms call error"); // thread safe, not reentrant
*pname = 0; // initz. outputs to nothing *pname = 0; // initz. outputs to nothing
skipping to change at line 2888 skipping to change at line 2889
if (*delim) ii++; // position for next call if (*delim) ii++; // position for next call
return 0; return 0;
} }
/******************************************************************************* */ /******************************************************************************* */
// Produce random value from hashed input string. // Produce random value from hashed input string.
// Output range is 0 to max-1. // Output range is 0 to max-1.
// Benchmark: 0.2 usec for 99 char. string, 3 GHz Core i5 // Benchmark: 0.2 usec for 99 char. string, 3 GHz Core i5
int strHash(cchar *string, uint max) int strHash(ch *string, uint max)
{ {
uint hash = 1357; uint hash = 1357;
uchar byte; uch byte;
while ((byte = *string++)) while ((byte = *string++))
{ {
hash = hash * (byte + 111); hash = hash * (byte + 111);
hash = hash ^ (hash >> 9); hash = hash ^ (hash >> 9);
hash = hash ^ (byte << 9); hash = hash ^ (byte << 9);
} }
hash = hash % max; hash = hash % max;
return hash; return hash;
} }
/******************************************************************************* */ /******************************************************************************* */
// Copy string with specified max. length (including null terminator). // Copy string with specified max. length (including null terminator).
// truncate if needed. null terminator is always supplied. // truncate if needed. null terminator is always supplied.
// Returns 0 if no truncation, 1 if input string was truncated to fit. // Returns 0 if no truncation, 1 if input string was truncated to fit.
int strncpy0(char *dest, cchar *source, uint cc) int strncpy0(ch *dest, ch *source, uint cc)
{ {
strncpy(dest,source,cc); strncpy(dest,source,cc);
dest[cc-1] = 0; dest[cc-1] = 0;
if (strlen(source) >= cc) return 1; // truncated if (strlen(source) >= cc) return 1; // truncated
else return 0; else return 0;
} }
/******************************************************************************* */ /******************************************************************************* */
// Copy string with blank pad to specified length. No null is added. // Copy string with blank pad to specified length. No null is added.
void strnPad(char *dest, cchar *source, int cc) void strnPad(ch *dest, ch *source, int cc)
{ {
strncpy(dest,source,cc); strncpy(dest,source,cc);
int ii = strlen(source); int ii = strlen(source);
for (int jj = ii; jj < cc; jj++) dest[jj] = ' '; for (int jj = ii; jj < cc; jj++) dest[jj] = ' ';
} }
/******************************************************************************* */ /******************************************************************************* */
// Remove trailing blanks from a string. Returns remaining length. // Remove trailing blanks from a string. Returns remaining length.
int strTrim(char *dest, cchar *source) int strTrim(ch *dest, ch *source)
{ {
if (dest != source) strcpy(dest,source); if (dest != source) strcpy(dest,source);
return strTrim(dest); return strTrim(dest);
} }
int strTrim(char *dest) int strTrim(ch *dest)
{ {
int ii = strlen(dest); int ii = strlen(dest);
while (ii && (dest[ii-1] == ' ')) dest[--ii] = 0; while (ii && (dest[ii-1] == ' ')) dest[--ii] = 0;
return ii; return ii;
} }
/******************************************************************************* */ /******************************************************************************* */
// Remove leading and trailing blanks from a string. // Remove leading and trailing blanks from a string.
// Returns remaining length, possibly zero. // Returns remaining length, possibly zero.
int strTrim2(char *dest, cchar *source) int strTrim2(ch *dest, ch *source)
{ {
cchar *pp1, *pp2; ch *pp1, *pp2;
int cc; int cc;
pp1 = source; pp1 = source;
pp2 = source + strlen(source) - 1; pp2 = source + strlen(source) - 1;
while (*pp1 == ' ') pp1++; while (*pp1 == ' ') pp1++;
if (*pp1 == 0) { if (*pp1 == 0) {
strcpy(dest,""); // null or blank input strcpy(dest,""); // null or blank input
return 0; return 0;
} }
while (*pp2 == ' ' && pp2 > pp1) pp2--; while (*pp2 == ' ' && pp2 > pp1) pp2--;
cc = pp2 - pp1 + 1; cc = pp2 - pp1 + 1;
memmove(dest,pp1,cc); memmove(dest,pp1,cc);
dest[cc] = 0; dest[cc] = 0;
return cc; return cc;
} }
int strTrim2(char *string) int strTrim2(ch *string)
{ {
return strTrim2(string,(cchar *) string); return strTrim2(string,(ch *) string);
} }
/******************************************************************************* */ /******************************************************************************* */
// Remove all blanks from a string. Returns remaining length. // Remove all blanks from a string. Returns remaining length.
int strCompress(char *dest, cchar *source) int strCompress(ch *dest, ch *source)
{ {
if (dest != source) strcpy(dest,source); if (dest != source) strcpy(dest,source);
return strCompress(dest); return strCompress(dest);
} }
int strCompress(char *string) int strCompress(ch *string)
{ {
int ii, jj; int ii, jj;
for (ii = jj = 0; string[ii]; ii++) for (ii = jj = 0; string[ii]; ii++)
{ {
if (string[ii] != ' ') if (string[ii] != ' ')
{ {
string[jj] = string[ii]; string[jj] = string[ii];
jj++; jj++;
} }
skipping to change at line 3010 skipping to change at line 3011
/******************************************************************************* */ /******************************************************************************* */
// Concatenate multiple strings, staying within a specified overall length. // Concatenate multiple strings, staying within a specified overall length.
// The destination string is also the first source string. // The destination string is also the first source string.
// Null marks the end of the source strings (omission --> crash). // Null marks the end of the source strings (omission --> crash).
// Output is truncated to fit within the specified length. // Output is truncated to fit within the specified length.
// A final null is assured and is included in the length. // A final null is assured and is included in the length.
// Returns 0 if OK, 1 if truncation was needed. // Returns 0 if OK, 1 if truncation was needed.
int strncatv(char *dest, int maxcc, cchar *source, ...) int strncatv(ch *dest, int maxcc, ch *source, ...)
{ {
cchar *ps; ch *ps;
va_list arglist; va_list arglist;
maxcc = maxcc - strlen(dest) - 1; maxcc = maxcc - strlen(dest) - 1;
if (maxcc < 0) return 1; if (maxcc < 0) return 1;
va_start(arglist,source); va_start(arglist,source);
ps = source; ps = source;
while (ps) while (ps)
{ {
strncat(dest,ps,maxcc); strncat(dest,ps,maxcc);
maxcc = maxcc - strlen(ps); maxcc = maxcc - strlen(ps);
if (maxcc < 0) break; if (maxcc < 0) break;
ps = va_arg(arglist,cchar *); ps = va_arg(arglist,ch *);
if (! ps || ps == (cchar *) 0x100000000) break; if (! ps || ps == (ch *) 0x100000000) break;
// ARM bug // ARM bug
} }
va_end(arglist); va_end(arglist);
if (maxcc < 0) return 1; if (maxcc < 0) return 1;
return 0; return 0;
} }
/******************************************************************************* */ /******************************************************************************* */
// Match 1st string to N additional strings. // Match 1st string to N additional strings.
// Return matching string number 1 to N or 0 if no match. // Return matching string number 1 to N or 0 if no match.
// Supply a null argument for end of list. // Supply a null argument for end of list.
int strmatchV(cchar *string, ...) int strmatchV(ch *string, ...)
{ {
int match = 0; int match = 0;
char *stringN; ch *stringN;
va_list arglist; va_list arglist;
va_start(arglist,string); va_start(arglist,string);
while (true) while (true)
{ {
stringN = va_arg(arglist, char *); stringN = va_arg(arglist, ch *);
if (stringN == null || stringN == (char *) 0x100000000) if (stringN == null || stringN == (ch *) 0x100000000)
// ARM bug // ARM bug
{ {
va_end(arglist); va_end(arglist);
return 0; return 0;
} }
match++; match++;
if (strmatch(string,stringN)) if (strmatch(string,stringN))
{ {
va_end(arglist); va_end(arglist);
return match; return match;
} }
} }
} }
/******************************************************************************* */ /******************************************************************************* */
// convert string to upper case // convert string to upper case
void strToUpper(char *string) void strToUpper(ch *string)
{ {
int ii; int ii;
char jj; ch jj;
const int delta = 'A' - 'a'; int delta = 'A' - 'a';
for (ii = 0; (jj = string[ii]); ii++) for (ii = 0; (jj = string[ii]); ii++)
if ((jj >= 'a') && (jj <= 'z')) string[ii] += delta; if ((jj >= 'a') && (jj <= 'z')) string[ii] += delta;
} }
void strToUpper(char *dest, cchar *source) void strToUpper(ch *dest, ch *source)
{ {
strcpy(dest,source); strcpy(dest,source);
strToUpper(dest); strToUpper(dest);
} }
/******************************************************************************* */ /******************************************************************************* */
// convert string to lower case // convert string to lower case
void strToLower(char *string) void strToLower(ch *string)
{ {
int ii; int ii;
char jj; ch jj;
const int delta = 'a' - 'A'; int delta = 'a' - 'A';
for (ii = 0; (jj = string[ii]); ii++) for (ii = 0; (jj = string[ii]); ii++)
if ((jj >= 'A') && (jj <= 'Z')) string[ii] += delta; if ((jj >= 'A') && (jj <= 'Z')) string[ii] += delta;
} }
void strToLower(char *dest, cchar *source) void strToLower(ch *dest, ch *source)
{ {
strcpy(dest,source); strcpy(dest,source);
strToLower(dest); strToLower(dest);
} }
/******************************************************************************* */ /******************************************************************************* */
// Copy string strin to strout, replacing every occurrence // Copy string strin to strout, replacing every occurrence
// of the substring ssin with the substring ssout. // of the substring ssin with the substring ssout.
// Returns the count of replacements, if any. // Returns the count of replacements, if any.
// Replacement strings may be longer or shorter or have zero length. // Replacement strings may be longer or shorter or have zero length.
int repl_1str(cchar *strin, char *strout, cchar *ssin, cchar *ssout) int repl_1str(ch *strin, ch *strout, ch *ssin, ch *ssout)
{ {
int ccc, cc1, cc2, nfound; int ccc, cc1, cc2, nfound;
cchar *ppp; ch *ppp;
cc1 = strlen(ssin); cc1 = strlen(ssin);
cc2 = strlen(ssout); cc2 = strlen(ssout);
nfound = 0; nfound = 0;
while ((ppp = strstr(strin,ssin))) while ((ppp = strstr(strin,ssin)))
{ {
nfound++; nfound++;
ccc = ppp - strin; ccc = ppp - strin;
memcpy(strout,strin,ccc); // memcpy instead of strncpy memcpy(strout,strin,ccc); // memcpy instead of strncpy
skipping to change at line 3146 skipping to change at line 3147
} }
/******************************************************************************* */ /******************************************************************************* */
// Copy string strin to strout, replacing multiple substrings with replacement strings. // Copy string strin to strout, replacing multiple substrings with replacement strings.
// Multiple pairs of string arguments follow strout, a substring and a replacem ent string. // Multiple pairs of string arguments follow strout, a substring and a replacem ent string.
// Last pair of string arguments must be followed by a null argument. // Last pair of string arguments must be followed by a null argument.
// Returns the count of replacements, if any. // Returns the count of replacements, if any.
// Replacement strings may be longer or shorter or have zero length. // Replacement strings may be longer or shorter or have zero length.
int repl_Nstrs(cchar *strin, char *strout, ...) int repl_Nstrs(ch *strin, ch *strout, ...)
{ {
va_list arglist; va_list arglist;
cchar *ssin, *ssout; ch *ssin, *ssout;
char ftemp[XFCC]; ch ftemp[XFCC];
int ftf, nfound; int ftf, nfound;
ftf = 1; ftf = 1;
nfound = 0; nfound = 0;
va_start(arglist,strout); va_start(arglist,strout);
while (true) while (true)
{ {
ssin = va_arg(arglist, char *); ssin = va_arg(arglist, ch *);
if (! ssin || ssin == (char *) 0x100000000) break; if (! ssin || ssin == (ch *) 0x100000000) break;
// ARM bug // ARM bug
ssout = va_arg(arglist, char *); ssout = va_arg(arglist, ch *);
if (ftf) { if (ftf) {
ftf = 0; ftf = 0;
nfound += repl_1str(strin,strout,ssin,ssout); nfound += repl_1str(strin,strout,ssin,ssout);
} }
else { else {
strcpy(ftemp,strout); strcpy(ftemp,strout);
nfound += repl_1str(ftemp,strout,ssin,ssout); nfound += repl_1str(ftemp,strout,ssin,ssout);
} }
skipping to change at line 3183 skipping to change at line 3184
va_end(arglist); va_end(arglist);
return nfound; return nfound;
} }
/******************************************************************************* */ /******************************************************************************* */
// Break up a long text string into lines no longer than cc2 chars. // Break up a long text string into lines no longer than cc2 chars.
// If fake newlines ("\n") are found, replace them with real newlines. // If fake newlines ("\n") are found, replace them with real newlines.
// Break unconditionally where newlines are found and remove them. // Break unconditionally where newlines are found and remove them.
// Break at last blank char between cc1 and cc2 if present. // Break at last blank ch between cc1 and cc2 if present.
// Break at last delimiter char between cc1 and cc2 if present. // Break at last delimiter ch between cc1 and cc2 if present.
// Break unconditionally at cc2 if none of the above. // Break unconditionally at cc2 if none of the above.
// Returns text lines in txout[*] with count as returned function value. // Returns text lines in txout[*] with count as returned function value.
// txout[*] are subjects for zfree(). // txout[*] are subjects for zfree().
int breakup_text(cchar *txin0, char **&txout, cchar *delims, int cc1, int cc2) int breakup_text(ch *txin0, ch **&txout, ch *delims, int cc1, int cc2)
{ {
char *txin; ch *txin;
uchar ch; uch ch1;
int p1, p2, cc3, Nout; int p1, p2, cc3, Nout;
int Np, Bp, Sp; int Np, Bp, Sp;
txin = zstrdup(txin0,"breakup_text"); txin = zstrdup(txin0,"breakup_text");
txout = (char **) zmalloc(100 * sizeof(char *),"breakup_text"); // 100 line limit txout = (ch **) zmalloc(100 * sizeof(ch *),"breakup_text"); // 100 line limit
if (strstr(txin0,"\\n")) // replace "\n" with real newline chars if (strstr(txin0,"\\n")) // replace "\n" with real newline chars
repl_1str(txin0,txin,"\\n","\n"); repl_1str(txin0,txin,"\\n","\n");
Nout = p1 = 0; Nout = p1 = 0;
while (true) while (true)
{ {
p2 = p1; // input line position p2 = p1; // input line position
cc3 = 0; // output line cc cc3 = 0; // output line cc
Np = Bp = Sp = 0; Np = Bp = Sp = 0;
while (txin[p2]) // scan further up to cc2 chars while (txin[p2]) // scan further up to cc2 chars
{ {
ch = txin[p2]; ch1 = txin[p2];
if (ch == '\n') { Np = p2; break; } if (ch1 == '\n') { Np = p2; break; }
// break out if newline found // break out if newline found
if (cc3 >= cc1) { if (cc3 >= cc1) {
if (ch == ' ') Bp = p2; if (ch1 == ' ') Bp = p2;
// remember last ' ' found after cc1 chars // remember last ' ' found after cc1 chars
if (delims && strchr(delims,ch)) Sp = p2; if (delims && strchr(delims,ch1)) Sp = p2;
// remember last delimiter found after cc1 // remember last delimiter found after cc1
} }
if (ch < 0) if (ch1 < 0)
// UTF8 wide character // UTF8 wide character
while ((ch = txin[p2+1]) < 0xC0) p2++; while ((ch1 = txin[p2+1]) < 0xC0) p2++;
p2++; p2++;
cc3++; cc3++;
if (cc3 == cc2) break; if (cc3 == cc2) break;
} }
if (! cc3 && ! Np) break; // nothing left if (! cc3 && ! Np) break; // nothing left
if (Np) cc3 = Np - p1; // newline found if (Np) cc3 = Np - p1; // newline found
else { else {
if (cc3 < cc2) Bp = Sp = 0; // line fits cc2 limit 22.18 if (cc3 < cc2) Bp = Sp = 0; // line fits cc2 limit 22.18
if (Bp) cc3 = Bp - p1 + 1; // break at previous ' ' if (Bp) cc3 = Bp - p1 + 1; // break at previous ' '
else if (Sp) cc3 = Sp - p1 + 1; // break at previous delimiter else if (Sp) cc3 = Sp - p1 + 1; // break at previous delimiter
else cc3 = p2 - p1; else cc3 = p2 - p1;
} }
if (txin[p1] == ' ' && cc3) { p1++; cc3--; } // remove leading blank if (txin[p1] == ' ' && cc3) { p1++; cc3--; } // remove leading blank
if (cc3 > 0) { // avoid blank line 22.18 if (cc3 > 0) { // avoid blank line 22.18
txout[Nout] = (char *) zmalloc(cc3+1,"breakup_text"); txout[Nout] = (ch *) zmalloc(cc3+1,"breakup_text");
strncpy0(txout[Nout],txin+p1,cc3+1); strncpy0(txout[Nout],txin+p1,cc3+1);
if (++Nout == 100) break; if (++Nout == 100) break;
} }
p2 = p1 + cc3; p2 = p1 + cc3;
if (Np) p2++; if (Np) p2++;
p1 = p2; p1 = p2;
} }
zfree(txin); zfree(txin);
return Nout; return Nout;
} }
/******************************************************************************* */ /******************************************************************************* */
// Copy and convert string to hex string. // Copy and convert string to hex string.
// Each input character 'A' >> 3 output characters "41 " // Each input character 'A' >> 3 output characters "41 "
void strncpyx(char *out, cchar *in, int ccin) void strncpyx(ch *out, ch *in, int ccin)
{ {
int ii, jj, c1, c2; int ii, jj, c1, c2;
char cx[] = "0123456789ABCDEF"; ch cx[] = "0123456789ABCDEF";
if (! ccin) ccin = strlen(in); if (! ccin) ccin = strlen(in);
for (ii = 0, jj = 0; ii < ccin; ii++, jj += 3) for (ii = 0, jj = 0; ii < ccin; ii++, jj += 3)
{ {
c1 = (uchar) in[ii] >> 4; c1 = (uch) in[ii] >> 4;
c2 = in[ii] & 15; c2 = in[ii] & 15;
out[jj] = cx[c1]; out[jj] = cx[c1];
out[jj+1] = cx[c2]; out[jj+1] = cx[c2];
out[jj+2] = ' '; out[jj+2] = ' ';
} }
out[jj] = 0; out[jj] = 0;
return; return;
} }
/******************************************************************************* */ /******************************************************************************* */
// Strip trailing zeros from ascii floating numbers // Strip trailing zeros from ascii floating numbers
// (e.g. 1.230000e+02 --> 1.23e+02) // (e.g. 1.230000e+02 --> 1.23e+02)
void StripZeros(char *pNum) void StripZeros(ch *pNum)
{ {
int ii, cc; int ii, cc;
int pp, k1, k2; int pp, k1, k2;
char work[20]; ch work[20];
cc = strlen(pNum); cc = strlen(pNum);
if (cc >= 20) return; if (cc >= 20) return;
for (ii = 0; ii < cc; ii++) for (ii = 0; ii < cc; ii++)
{ {
if (pNum[ii] == '.') if (pNum[ii] == '.')
{ {
pp = ii; pp = ii;
k1 = k2 = 0; k1 = k2 = 0;
skipping to change at line 3332 skipping to change at line 3333
/******************************************************************************* */ /******************************************************************************* */
// test for blank/null string // test for blank/null string
// Returns status depending on input string: // Returns status depending on input string:
// 0 not a blank or null string // 0 not a blank or null string
// 1 argument string is NULL // 1 argument string is NULL
// 2 string has zero length (*string == 0) // 2 string has zero length (*string == 0)
// 3 string is all blanks // 3 string is all blanks
int blank_null(cchar *string) int blank_null(ch *string)
{ {
if (! string) return 1; // null string if (! string) return 1; // null string
if (! *string) return 2; // zero length string if (! *string) return 2; // zero length string
int cc = strlen(string); int cc = strlen(string);
for (int ii = 0; ii < cc; ii++) for (int ii = 0; ii < cc; ii++)
if (string[ii] != ' ') return 0; // non-blank string if (string[ii] != ' ') return 0; // non-blank string
return 3; // blank string return 3; // blank string
} }
/******************************************************************************* */ /******************************************************************************* */
// clean \x escape sequences and replace them with the escaped character // clean \x escape sequences and replace them with the escaped character
// \n >> newline \" >> doublequote \\ >> backslash etc. // \n >> newline \" >> doublequote \\ >> backslash etc.
// see $ man ascii for the complete list // see $ man ascii for the complete list
int clean_escapes(char *string) int clean_escapes(ch *string)
{ {
char *pp1 = string, *pp2 = string, *pp; ch *pp1 = string, *pp2 = string, *pp;
char char1; ch char1;
char escapes[] = "abtnvfr"; ch escapes[] = "abtnvfr";
int count = 0; int count = 0;
while (true) while (true)
{ {
char1 = *pp1++; char1 = *pp1++;
if (char1 == 0) { if (char1 == 0) {
*pp2 = 0; *pp2 = 0;
return count; return count;
} }
skipping to change at line 3380 skipping to change at line 3381
*pp2++ = char1; *pp2++ = char1;
} }
} }
/******************************************************************************* */ /******************************************************************************* */
// Compute the graphic character count for a UTF8 character string. // Compute the graphic character count for a UTF8 character string.
// Depends on UTF8 rules: // Depends on UTF8 rules:
// - ascii characters are positive (0x00 to 0x7F) // - ascii characters are positive (0x00 to 0x7F)
// - 1st char of multichar sequence is negative (0xC0 to 0xFD) // - 1st ch of multich sequence is negative (0xC0 to 0xFD)
// - subsequent multichars are in the range 0x80 to 0xBF // - subsequent multichars are in the range 0x80 to 0xBF
int utf8len(cchar *utf8string) int utf8len(ch *utf8string)
{ {
int ii, cc; int ii, cc;
char xlimit = 0xC0; ch xlimit = 0xC0;
for (ii = cc = 0; utf8string[ii]; ii++) for (ii = cc = 0; utf8string[ii]; ii++)
{ {
if (utf8string[ii] < 0) // multibyte character if (utf8string[ii] < 0) // multibyte character
while (utf8string[ii+1] < xlimit) ii++; // skip extra bytes while (utf8string[ii+1] < xlimit) ii++; // skip extra bytes
cc++; cc++;
} }
return cc; return cc;
} }
skipping to change at line 3408 skipping to change at line 3409
/******************************************************************************* */ /******************************************************************************* */
// Extract a UTF8 substring with a specified count of graphic characters. // Extract a UTF8 substring with a specified count of graphic characters.
// utf8in input UTF8 string // utf8in input UTF8 string
// utf8out output UTF8 string, which must be long enough // utf8out output UTF8 string, which must be long enough
// pos initial graphic character position to get (0 = first) // pos initial graphic character position to get (0 = first)
// cc max. count of graphic characters to get // cc max. count of graphic characters to get
// returns number of graphic characters extracted, <= cc // returns number of graphic characters extracted, <= cc
// Output string is null terminated after last extracted character. // Output string is null terminated after last extracted character.
int utf8substring(char *utf8out, cchar *utf8in, int pos, int cc) int utf8substring(ch *utf8out, ch *utf8in, int pos, int cc)
{ {
int ii, jj, kk, posx, ccx; int ii, jj, kk, posx, ccx;
char xlimit = 0xC0; ch xlimit = 0xC0;
for (ii = posx = 0; posx < pos && utf8in[ii]; ii++) for (ii = posx = 0; posx < pos && utf8in[ii]; ii++)
{ {
if (utf8in[ii] < 0) if (utf8in[ii] < 0)
while (utf8in[ii+1] < xlimit) ii++; while (utf8in[ii+1] < xlimit) ii++;
posx++; posx++;
} }
jj = ii; jj = ii;
skipping to change at line 3442 skipping to change at line 3443
utf8out[kk] = 0; utf8out[kk] = 0;
return ccx; return ccx;
} }
/******************************************************************************* */ /******************************************************************************* */
// check a string for valid utf8 encoding // check a string for valid utf8 encoding
// returns: 0 = OK, 1 = bad string // returns: 0 = OK, 1 = bad string
int utf8_check(cchar *string) int utf8_check(ch *string)
{ {
cchar *pp; ch *pp;
unsigned char ch1, ch2, nch; uch ch1, ch2, nch;
for (pp = string; *pp; pp++) for (pp = string; *pp; pp++)
{ {
ch1 = *pp; ch1 = *pp;
if (ch1 < 0x7F) continue; if (ch1 < 0x7F) continue;
if (ch1 > 0xBF && ch1 < 0xE0) nch = 1; if (ch1 > 0xBF && ch1 < 0xE0) nch = 1;
else if (ch1 < 0xF0) nch = 2; else if (ch1 < 0xF0) nch = 2;
else if (ch1 < 0xF8) nch = 3; else if (ch1 < 0xF8) nch = 3;
else if (ch1 < 0xFC) nch = 4; else if (ch1 < 0xFC) nch = 4;
else if (ch1 < 0xFE) nch = 5; else if (ch1 < 0xFE) nch = 5;
skipping to change at line 3476 skipping to change at line 3477
} }
/******************************************************************************* */ /******************************************************************************* */
// Find the Nth graphic character position within a UTF8 string // Find the Nth graphic character position within a UTF8 string
// utf8in input UTF8 string // utf8in input UTF8 string
// Nth graphic character position, zero based // Nth graphic character position, zero based
// returns starting character (byte) position of Nth graphic character // returns starting character (byte) position of Nth graphic character
// returns -1 if Nth is beyond the string length // returns -1 if Nth is beyond the string length
int utf8_position(cchar *utf8in, int Nth) int utf8_position(ch *utf8in, int Nth)
{ {
int ii, posx; int ii, posx;
char xlimit = 0xC0; ch xlimit = 0xC0;
for (ii = posx = 0; posx < Nth && utf8in[ii]; ii++) for (ii = posx = 0; posx < Nth && utf8in[ii]; ii++)
{ {
if (utf8in[ii] < 0) // multi-byte character if (utf8in[ii] < 0) // multi-byte character
while (utf8in[ii+1] && utf8in[ii+1] < xlimit) ii++; // traverse member bytes while (utf8in[ii+1] && utf8in[ii+1] < xlimit) ii++; // traverse member bytes
posx++; posx++;
} }
if (utf8in[ii]) return ii; if (utf8in[ii]) return ii;
return -1; return -1;
skipping to change at line 3501 skipping to change at line 3502
/******************************************************************************* */ /******************************************************************************* */
// err = zsed(file, string1, string2 ... null) // err = zsed(file, string1, string2 ... null)
// //
// replace string1/3/5... with string2/4/6... in designated file // replace string1/3/5... with string2/4/6... in designated file
// returns N lines changed // returns N lines changed
// -1 file not found // -1 file not found
// -2 other error (with message) // -2 other error (with message)
int zsed(cchar *infile ...) int zsed(ch *infile ...)
{ {
int err, ftf, nn; int err, ftf, nn;
FILE *fid1, *fid2; FILE *fid1, *fid2;
char *outfile, *pp; ch *outfile, *pp;
char buffin[1000], buffout[1000], buffxx[1000]; ch buffin[1000], buffout[1000], buffxx[1000];
cchar *stringin, *stringout; ch *stringin, *stringout;
va_list arglist; va_list arglist;
fid1 = fopen(infile,"r"); fid1 = fopen(infile,"r");
if (! fid1) return -1; if (! fid1) return -1;
outfile = zstrdup(infile,"zsed",8); outfile = zstrdup(infile,"zsed",8);
strcat(outfile,"-temp"); strcat(outfile,"-temp");
fid2 = fopen(outfile,"w"); fid2 = fopen(outfile,"w");
if (! fid2) { if (! fid2) {
Plog(0,"%d \n",strerror(errno)); Plog(0,"%d \n",strerror(errno));
skipping to change at line 3535 skipping to change at line 3536
{ {
pp = fgets(buffin,500,fid1); pp = fgets(buffin,500,fid1);
if (! pp) break; if (! pp) break;
va_start(arglist,infile); va_start(arglist,infile);
ftf = 1; ftf = 1;
while (true) while (true)
{ {
stringin = va_arg(arglist, char *); stringin = va_arg(arglist, ch *);
if (! stringin || stringin == (char *) 0x100000000) break; if (! stringin || stringin == (ch *) 0x100000000) break;
// ARM bug // ARM bug
stringout = va_arg(arglist, char *); stringout = va_arg(arglist, ch *);
if (! stringout || stringout == (char *) 0x100000000) break; if (! stringout || stringout == (ch *) 0x100000000) break;
if (ftf) { if (ftf) {
ftf = 0; ftf = 0;
nn += repl_1str(buffin,buffout,stringin,stringout); nn += repl_1str(buffin,buffout,stringin,stringout);
} }
else { else {
strcpy(buffxx,buffout); strcpy(buffxx,buffout);
nn += repl_1str(buffxx,buffout,stringin,stringout); nn += repl_1str(buffxx,buffout,stringin,stringout);
} }
} }
skipping to change at line 3574 skipping to change at line 3575
zfree(outfile); zfree(outfile);
return nn; return nn;
} }
/******************************************************************************* */ /******************************************************************************* */
// zstrstr() and zstrcasestr() work like strstr() and strcasestr() // zstrstr() and zstrcasestr() work like strstr() and strcasestr()
// but the needle string "" does NOT match any haystack string. // but the needle string "" does NOT match any haystack string.
const char * zstrstr(const char *haystack, const char *needle) ch * zstrstr(ch *haystack, ch *needle)
{ {
if (! needle || ! *needle) return 0; if (! needle || ! *needle) return 0;
return strstr(haystack,needle); return strstr(haystack,needle);
} }
const char * zstrcasestr(const char *haystack, const char *needle) ch * zstrcasestr(ch *haystack, ch *needle)
{ {
if (! needle || ! *needle) return 0; if (! needle || ! *needle) return 0;
return strcasestr(haystack,needle); return strcasestr(haystack,needle);
} }
/******************************************************************************* */ /******************************************************************************* */
// strcpy() with overlap allowed // strcpy() with overlap allowed
char * zstrcpy(char *dest, const char *source) // 22.14 ch * zstrcpy(ch *dest, ch *source) // 22.14
{ {
int cc = strlen(source); int cc = strlen(source);
memmove(dest,source,cc); memmove(dest,source,cc);
dest[cc] = 0; dest[cc] = 0;
return dest; return dest;
} }
// strncpy() with overlap allowed // strncpy() with overlap allowed
char * zstrncpy(char *dest, const char *source, int cc) // 22.14 ch * zstrncpy(ch *dest, ch *source, int cc) // 22.14
{ {
memmove(dest,source,cc); memmove(dest,source,cc);
return dest; return dest;
} }
/******************************************************************************* */ /******************************************************************************* */
// works like strcmp(), but compare is terminated by \n as well as null // works like strcmp(), but compare is terminated by \n as well as null
int zstrcmp(cchar *s1, cchar *s2) // 22.20 int zstrcmp(ch *s1, ch *s2) // 22.20
{ {
char *p1, *p2; ch *p1, *p2;
int nn; int nn;
p1 = (char *) strchr(s1,'\n'); p1 = (ch *) strchr(s1,'\n');
p2 = (char *) strchr(s2,'\n'); p2 = (ch *) strchr(s2,'\n');
if (p1) *p1 = 0; if (p1) *p1 = 0;
if (p2) *p2 = 0; if (p2) *p2 = 0;
nn = strcmp(s1,s2); nn = strcmp(s1,s2);
if (p1) *p1 = '\n'; if (p1) *p1 = '\n';
if (p2) *p2 = '\n'; if (p2) *p2 = '\n';
return nn; return nn;
} }
/*******************************************************************************
*/
// works like strcmp(), but using char *args instead of const char*
int zstrcmp2(ch *s1, ch *s2)
{
return strcmp((cch *) s1, (cch *) s2);
}
/*******************************************************************************
*/
// works like strcasecmp(), but using char *args instead of const char*
int zstrcasecmp(ch *s1, ch *s2)
{
return strcasecmp((cch *) s1, (cch *) s2);
}
/******************************************************************************* * /******************************************************************************* *
Conversion Utilities Conversion Utilities
convSI(string, inum, delim) string to int convSI(string, inum, delim) string to int
convSI(string, inum, low, high, delim) string to int with range chec k convSI(string, inum, low, high, delim) string to int with range chec k
convSD(string, dnum, delim) string to double convSD(string, dnum, delim) string to double
convSD(string, dnum, low, high, delim) string to double with range c heck convSD(string, dnum, low, high, delim) string to double with range c heck
convSF(string, fnum, delim) string to float convSF(string, fnum, delim) string to float
convSF(string, fnum, low, high, delim) string to float with range ch eck convSF(string, fnum, low, high, delim) string to float with range ch eck
convIS(inum, string, cc) int to string with returned c c convIS(inum, string, cc) int to string with returned c c
convDS(fnum, digits, string, cc) double to string with specifi ed convDS(fnum, digits, string, cc) double to string with specifi ed
digits of precision and ret urned cc digits of precision and ret urned cc
string input (cchar *) or output (char *) string input (ch *) or output (ch *)
inum input (int) or output (int &) inum input (int) or output (int &)
dnum input (double) or output (double &) dnum input (double) or output (double &)
delim optional returned delimiter (null or cchar **) delim optional returned delimiter (null or ch **)
low, high input range check (int or double) low, high input range check (int or double)
cc output string length (int &) cc output string length (int &)
digits input digits of precision (int) to be used for output string digits input digits of precision (int) to be used for output string
NOTE: decimal point may be comma or period. NOTE: decimal point may be comma or period.
1000's separators must NOT be present. 1000's separators must NOT be present.
convIS and convDS also return the length cc of the string output. convIS and convDS also return the length cc of the string output.
convDS accepts same formats as atof. Decimal point can be comma or period. convDS accepts same formats as atof. Decimal point can be comma or period.
convDS will use whatever format (f/e) gives the shortest result. convDS will use whatever format (f/e) gives the shortest result.
skipping to change at line 3671 skipping to change at line 3690
1 successful conversion, but trailing non-numeric found 1 successful conversion, but trailing non-numeric found
2 conversion OK, but outside specified limits 2 conversion OK, but outside specified limits
3 null or blank string, converted to zero (obsolete, now status 4) 3 null or blank string, converted to zero (obsolete, now status 4)
4 conversion error, invalid data in string 4 conversion error, invalid data in string
overlapping statuses have following precedence: 4 3 2 1 0 overlapping statuses have following precedence: 4 3 2 1 0
******************************************************************************** */ ******************************************************************************** */
// Convert string to integer // Convert string to integer
int convSI(cchar *string, int &inum, cchar **delim) // use glib function int convSI(ch *string, int &inum, ch **delim) // use glib function
{ {
char *ddelim = 0; ch *ddelim = 0;
int err; int err;
inum = strtol(string,&ddelim,10); // convert next characters inum = strtol(string,&ddelim,10); // convert next characters
if (delim) *delim = ddelim; if (delim) *delim = ddelim;
if (ddelim == string) err = 4; // no valid digits if (ddelim == string) err = 4; // no valid digits
else if (*ddelim == '\0') err = 0; // null delimiter else if (*ddelim == '\0') err = 0; // null delimiter
else if (*ddelim == ' ') err = 0; // blank delimiter else if (*ddelim == ' ') err = 0; // blank delimiter
else err = 1; // other delimiter else err = 1; // other delimiter
return err; return err;
} }
int convSI(cchar *string, int &inum, int lolim, int hilim, cchar **delim) int convSI(ch *string, int &inum, int lolim, int hilim, ch **delim)
{ {
int stat = convSI(string,inum,delim); int stat = convSI(string,inum,delim);
if (stat > 2) return stat; // invalid or null/blank if (stat > 2) return stat; // invalid or null/blank
if (inum < lolim) return 2; // return 2 if out of limits if (inum < lolim) return 2; // return 2 if out of limits
if (inum > hilim) return 2; // (has precedence over status 1) if (inum > hilim) return 2; // (has precedence over status 1)
return stat; // limits OK, return 0 or 1 return stat; // limits OK, return 0 or 1
} }
// Convert string to double *** status 3 --> status 4 *** // Convert string to double *** status 3 --> status 4 ***
int convSD(cchar *string, double &dnum, cchar **delim) // use glib function int convSD(ch *string, double &dnum, ch **delim) // use glib function
{ {
char *ddelim = 0; ch *ddelim = 0;
int err; int err;
dnum = strtod(string,&ddelim); dnum = strtod(string,&ddelim);
if (delim) *delim = ddelim; if (delim) *delim = ddelim;
if (ddelim == string) err = 4; // no valid digits if (ddelim == string) err = 4; // no valid digits
else if (*ddelim == '\0') err = 0; // OK, null delimiter else if (*ddelim == '\0') err = 0; // OK, null delimiter
else if (*ddelim == ' ') err = 0; // OK, blank delimiter else if (*ddelim == ' ') err = 0; // OK, blank delimiter
else err = 1; // OK, other delimiter else err = 1; // OK, other delimiter
return err; return err;
} }
int convSD(cchar *string, double &dnum, double lolim, double hilim, cchar **deli m) int convSD(ch *string, double &dnum, double lolim, double hilim, ch **delim)
{ {
int stat = convSD(string,dnum,delim); int stat = convSD(string,dnum,delim);
if (stat > 2) return stat; // invalid or null/blank if (stat > 2) return stat; // invalid or null/blank
if (dnum < lolim) return 2; // return 2 if out of limits if (dnum < lolim) return 2; // return 2 if out of limits
if (dnum > hilim) return 2; // (has precedence over status 1) if (dnum > hilim) return 2; // (has precedence over status 1)
return stat; // limits OK, return 0 or 1 return stat; // limits OK, return 0 or 1
} }
int convSF(cchar *string, float &fnum, cchar **delim) int convSF(ch *string, float &fnum, ch **delim)
{ {
double dnum; double dnum;
int err; int err;
err = convSD(string,dnum,delim); err = convSD(string,dnum,delim);
fnum = dnum; fnum = dnum;
return err; return err;
} }
int convSF(cchar *string, float &fnum, float lolim, float hilim, cchar **delim) int convSF(ch *string, float &fnum, float lolim, float hilim, ch **delim)
{ {
double dnum, dlolim = lolim, dhilim = hilim; double dnum, dlolim = lolim, dhilim = hilim;
int err; int err;
err = convSD(string,dnum,dlolim,dhilim,delim); err = convSD(string,dnum,dlolim,dhilim,delim);
fnum = dnum; fnum = dnum;
return err; return err;
} }
// Convert int to string with returned length. // Convert int to string with returned length.
// (will never exceed 12 characters) // (will never exceed 12 characters)
int convIS(int inum, char *string, int *cc) int convIS(int inum, ch *string, int *cc)
{ {
int ccc; int ccc;
ccc = snprintf(string,12,"%d",inum); ccc = snprintf(string,12,"%d",inum);
if (cc) *cc = ccc; if (cc) *cc = ccc;
return 0; return 0;
} }
// Convert double to string with specified digits of precision. // Convert double to string with specified digits of precision.
// Shortest length format (f/e) will be used. // Shortest length format (f/e) will be used.
// Output length is returned in optional argument cc. // Output length is returned in optional argument cc.
// (will never exceed 20 characters) // (will never exceed 20 characters)
int convDS(double dnum, int digits, char *string, int *cc) // bugfix: use memmove not strcpy 22.14 int convDS(double dnum, int digits, ch *string, int *cc) // bugfix: use memmove not strcpy 22.14
{ {
char *pstr; ch *pstr;
snprintf(string,20,"%.*g",digits,dnum); snprintf(string,20,"%.*g",digits,dnum);
pstr = strstr(string,"e+"); // 1.23e+12 > 1.23e12 pstr = strstr(string,"e+"); // 1.23e+12 > 1.23e12
if (pstr) memmove(pstr+1,pstr+2,strlen(pstr+2)+1); if (pstr) memmove(pstr+1,pstr+2,strlen(pstr+2)+1);
pstr = strstr(string,"e0"); // 1.23e02 > 1.23e2 pstr = strstr(string,"e0"); // 1.23e02 > 1.23e2
if (pstr) memmove(pstr+1,pstr+2,strlen(pstr+2)+1); if (pstr) memmove(pstr+1,pstr+2,strlen(pstr+2)+1);
pstr = strstr(string,"e0"); pstr = strstr(string,"e0");
skipping to change at line 3785 skipping to change at line 3804
if (pstr) memmove(pstr+2,pstr+3,strlen(pstr+3)+1); if (pstr) memmove(pstr+2,pstr+3,strlen(pstr+3)+1);
if (cc) *cc = strlen(string); if (cc) *cc = strlen(string);
return 0; return 0;
} }
// convert string to double, accepting either '.' or ',' decimal points. // convert string to double, accepting either '.' or ',' decimal points.
// if there is an error, zero is returned. // if there is an error, zero is returned.
double atofz(cchar *string) double atofz(ch *string)
{ {
char string2[20], *pp; ch string2[20], *pp;
strncpy(string2,string,20); strncpy(string2,string,20);
string2[19] = 0; string2[19] = 0;
pp = strchr(string2,','); pp = strchr(string2,',');
if (pp) *pp = '.'; if (pp) *pp = '.';
return atof(string2); return atof(string2);
} }
// format a number as "123 B" or "12.3 KB" or "1.23 MB" etc. // format a number as "123 B" or "12.3 KB" or "1.23 MB" etc.
// prec is the desired digits of precision to output. // prec is the desired digits of precision to output.
// WARNING: only the last 100 conversions remain available in memory. // WARNING: only the last 100 conversions remain available in memory.
// Example formats for 3 digits of precision: // Example formats for 3 digits of precision:
// 123 B, 999 B, 1.23 KB, 98.7 KB, 456 KB, 2.34 MB, 45.6 GB, 1.23 GB // 123 B, 999 B, 1.23 KB, 98.7 KB, 456 KB, 2.34 MB, 45.6 GB, 1.23 GB
char * formatKBMB(double fnum, int prec) ch * formatKBMB(double fnum, int prec)
{ {
#define Bkilo 1024 #define Bkilo 1024
#define Bmega (Bkilo*Bkilo) #define Bmega (Bkilo*Bkilo)
#define Bgiga (Bkilo*Bkilo*Bkilo) #define Bgiga (Bkilo*Bkilo*Bkilo)
cchar *units; ch *units;
static char *output[100]; static ch *output[100];
static int ftf = 1, ii; static int ftf = 1, ii;
double gnum; double gnum;
if (ftf) { // keep last 100 conversions if (ftf) { // keep last 100 conversions
ftf = 0; ftf = 0;
for (ii = 0; ii < 100; ii++) for (ii = 0; ii < 100; ii++)
output[ii] = (char *) zmalloc(20,"formatKBMB"); output[ii] = (ch *) zmalloc(20,"formatKBMB");
} }
gnum = fabs(fnum); gnum = fabs(fnum);
if (gnum > Bgiga) { if (gnum > Bgiga) {
fnum = fnum / Bgiga; fnum = fnum / Bgiga;
units = "GB"; units = "GB";
} }
else if (gnum > Bmega) { else if (gnum > Bmega) {
fnum = fnum / Bmega; fnum = fnum / Bmega;
skipping to change at line 3861 skipping to change at line 3880
Match candidate string to wildcard string containing any number of Match candidate string to wildcard string containing any number of
'*' or '?' wildcard characters. '*' matches any number of characters, '*' or '?' wildcard characters. '*' matches any number of characters,
including zero characters. '?' matches any one character. including zero characters. '?' matches any one character.
Returns 0 if match, 1 if no match. <<---- WATCH OUT ! Returns 0 if match, 1 if no match. <<---- WATCH OUT !
Benchmark: 0.032 usec. wild = *asdf*qwer?yxc Benchmark: 0.032 usec. wild = *asdf*qwer?yxc
3.3 GHz Core i5 match = XXXasdfXXXXqwerXyxc 3.3 GHz Core i5 match = XXXasdfXXXXqwerXyxc
******************************************************************************** */ ******************************************************************************** */
int MatchWild(cchar *pWild, cchar *pString) int MatchWild(ch *pWild, ch *pString)
{ {
int ii, star; int ii, star;
new_segment: new_segment:
star = 0; star = 0;
while (pWild[0] == '*') while (pWild[0] == '*')
{ {
star = 1; star = 1;
pWild++; pWild++;
skipping to change at line 3909 skipping to change at line 3928
goto test_match; goto test_match;
} }
/******************************************************************************* * /******************************************************************************* *
Wildcard string match - ignoring case Wildcard string match - ignoring case
Works like MatchWild() above, but case is ignored. Works like MatchWild() above, but case is ignored.
***/ ***/
int MatchWildCase(cchar *pWild, cchar *pString) int MatchWildCase(ch *pWild, ch *pString)
{ {
int ii, star; int ii, star;
new_segment: new_segment:
star = 0; star = 0;
while (pWild[0] == '*') while (pWild[0] == '*')
{ {
star = 1; star = 1;
pWild++; pWild++;
skipping to change at line 3958 skipping to change at line 3977
} }
/******************************************************************************* * /******************************************************************************* *
SearchWild - wildcard file search SearchWild - wildcard file search
Find all files with total /pathname/filename matching a pattern, Find all files with total /pathname/filename matching a pattern,
which may have any number of the wildcard characters '*' and '?' which may have any number of the wildcard characters '*' and '?'
in either or both the pathname and filename. in either or both the pathname and filename.
cchar * SearchWild(cchar *wfilespec, int &flag) ch * SearchWild(ch *wfilespec, int &flag)
inputs: flag = 1 to start a new search inputs: flag = 1 to start a new search
flag = 2 abort a running search flag = 2 abort a running search
*** do not modify flag within a search *** *** do not modify flag within a search ***
wfilespec = filespec to search with optional wildcards wfilespec = filespec to search with optional wildcards
e.g. "/name1/na*me2/nam??e3/name4*.ext?" e.g. "/name1/na*me2/nam??e3/name4*.ext?"
return: a pointer to one matching file is returned per call, return: a pointer to one matching file is returned per call,
or null when there are no more matching files. or null when there are no more matching files.
skipping to change at line 4004 skipping to change at line 4023
Benchmark: search path: /usr/# file: #.html 2 strings: #per prop# Benchmark: search path: /usr/# file: #.html 2 strings: #per prop#
find 97 files from 209K files in /usr/# find 97 files from 209K files in /usr/#
first time: 4.6 sec. first time: 4.6 sec.
second time: 1.5 sec. second time: 1.5 sec.
computer: 3.6 GHz core i7 with SSD disk computer: 3.6 GHz core i7 with SSD disk
Do not use to search files in /proc/# (causes infinite loop). Do not use to search files in /proc/# (causes infinite loop).
***/ ***/
cchar * SearchWild(cchar *wpath, int &uflag) ch * SearchWild(ch *wpath, int &uflag)
{ {
static FILE *fid = 0; static FILE *fid = 0;
static char buff[XFCC]; static ch buff[XFCC];
static char wpath2[XFCC]; static ch wpath2[XFCC];
static char command[XFCC]; static ch command[XFCC];
cchar *fcomm = "find \"%s\" -type f 2>/dev/null"; ch *fcomm = "find \"%s\" -type f 2>/dev/null";
int cc, err; int cc, err;
char *pp, *pp1, *pp2; ch *pp, *pp1, *pp2;
if ((uflag == 1) || (uflag == 2)) { // first call or stop flag if ((uflag == 1) || (uflag == 2)) { // first call or stop flag
if (fid) pclose(fid); // if file open, close it if (fid) pclose(fid); // if file open, close it
fid = 0; fid = 0;
if (uflag == 2) return 0; // stop flag, done if (uflag == 2) return 0; // stop flag, done
} }
if (uflag == 1) // first call flag if (uflag == 1) // first call flag
{ {
cc = strlen(wpath); cc = strlen(wpath);
skipping to change at line 4083 skipping to change at line 4102
Works like SearchWild() above, but case of file name is ignored. Works like SearchWild() above, but case of file name is ignored.
Actually, the trailing part of the path name is also case-insensitive, Actually, the trailing part of the path name is also case-insensitive,
meaning that it is possible to get more matches than technically correct meaning that it is possible to get more matches than technically correct
if folders like this are present: if folders like this are present:
/AAA/BBB/.../filename /AAA/BBB/.../filename
/AAA/bbb/.../filename /AAA/bbb/.../filename
***/ ***/
cchar * SearchWildCase(cchar *wpath, int &uflag) ch * SearchWildCase(ch *wpath, int &uflag)
{ {
static FILE *fid = 0; static FILE *fid = 0;
static char buff[XFCC]; static ch buff[XFCC];
static char wpath2[XFCC]; static ch wpath2[XFCC];
static char command[XFCC]; static ch command[XFCC];
cchar *fcomm = "find \"%s\" -type f 2>/dev/null"; ch *fcomm = "find \"%s\" -type f 2>/dev/null";
int cc, err; int cc, err;
char *pp, *pp1, *pp2; ch *pp, *pp1, *pp2;
if ((uflag == 1) || (uflag == 2)) { // first call or stop flag if ((uflag == 1) || (uflag == 2)) { // first call or stop flag
if (fid) pclose(fid); // if file open, close it if (fid) pclose(fid); // if file open, close it
fid = 0; fid = 0;
if (uflag == 2) return 0; // stop flag, done if (uflag == 2) return 0; // stop flag, done
} }
if (uflag == 1) // first call flag if (uflag == 1) // first call flag
{ {
cc = strlen(wpath); cc = strlen(wpath);
skipping to change at line 4153 skipping to change at line 4172
if (err) continue; // no if (err) continue; // no
return pp; // return file return pp; // return file
} }
} }
/******************************************************************************* * /******************************************************************************* *
Find all files matching a given pattern (using glob() rules) Find all files matching a given pattern (using glob() rules)
int zfind(cchar *pattern, char **&flist, int &NF) int zfind(ch *pattern, ch **&flist, int &NF)
pattern pattern to match, with wildcards pattern pattern to match, with wildcards
flist list of files returned flist list of files returned
NF count of files returned NF count of files returned
Returns 0 if OK, +N if error (errno is set). Returns 0 if OK, +N if error (errno is set).
flist and flist[*] are subjects for zfree(). flist and flist[*] are subjects for zfree().
zfind() works for files containing quotes (") zfind() works for files containing quotes (")
dotfiles (/. and /..) are not included dotfiles (/. and /..) are not included
******************************************************************************** */ ******************************************************************************** */
int zfind(cchar *pattern, char **&flist, int &NF) int zfind(ch *pattern, ch **&flist, int &NF)
{ {
char **zfind_filelist = 0; // list of filespecs returned ch **zfind_filelist = 0; // list of filespecs returned
int globflags = GLOB_PERIOD; // include dotfiles int globflags = GLOB_PERIOD; // include dotfiles
int ii, jj, err, cc; int ii, jj, err, cc;
glob_t globdata; glob_t globdata;
char *pp; ch *pp;
globdata.gl_pathc = 0; // glob() setup globdata.gl_pathc = 0; // glob() setup
globdata.gl_offs = 0; globdata.gl_offs = 0;
globdata.gl_pathc = 0; globdata.gl_pathc = 0;
NF = 0; // empty output NF = 0; // empty output
flist = 0; flist = 0;
err = glob(pattern,globflags,null,&globdata); // find all matching files err = glob(pattern,globflags,null,&globdata); // find all matching files
skipping to change at line 4200 skipping to change at line 4219
globfree(&globdata); // free glob memory globfree(&globdata); // free glob memory
return err; return err;
} }
NF = globdata.gl_pathc; NF = globdata.gl_pathc;
if (! NF) { if (! NF) {
globfree(&globdata); globfree(&globdata);
return 0; return 0;
} }
cc = NF * sizeof(char *); cc = NF * sizeof(ch *);
zfind_filelist = (char **) zmalloc(cc,"zfind"); zfind_filelist = (ch **) zmalloc(cc,"zfind");
for (ii = jj = 0; ii < NF; ii++) { // loop found files for (ii = jj = 0; ii < NF; ii++) { // loop found files
pp = strrchr(globdata.gl_pathv[ii],'/'); pp = strrchr(globdata.gl_pathv[ii],'/');
if (! pp) continue; if (! pp) continue;
if (strmatch(pp,"/.")) continue; // skip dotfiles if (strmatch(pp,"/.")) continue; // skip dotfiles
if (strmatch(pp,"/..")) continue; if (strmatch(pp,"/..")) continue;
zfind_filelist[jj++] = zstrdup(globdata.gl_pathv[ii],"zfind"); // add file to output list zfind_filelist[jj++] = zstrdup(globdata.gl_pathv[ii],"zfind"); // add file to output list
} }
flist = zfind_filelist; // return file list and count flist = zfind_filelist; // return file list and count
skipping to change at line 4272 skipping to change at line 4291
} }
} }
} }
} }
// Perform a binary search on sorted set of records in memory. // Perform a binary search on sorted set of records in memory.
// Return matching record number (0 based) or -1 if not found. // Return matching record number (0 based) or -1 if not found.
// Benchmark: search 10 million sorted records of 20 chars. // Benchmark: search 10 million sorted records of 20 chars.
// 0.61 usecs. 3.3 GHz Core i5 // 0.61 usecs. 3.3 GHz Core i5
int bsearch(cchar *seekrec, cchar *allrecs, int recl, int nrecs) int bsearch(ch *seekrec, ch *allrecs, int recl, int nrecs)
{ {
int ii, jj, kk, rkk; int ii, jj, kk, rkk;
ii = nrecs / 2; // next element to search ii = nrecs / 2; // next element to search
jj = (ii + 1) / 2; // next increment jj = (ii + 1) / 2; // next increment
nrecs--; // last element nrecs--; // last element
rkk = 0; rkk = 0;
while (true) while (true)
{ {
skipping to change at line 4316 skipping to change at line 4335
{ {
if (rkk > 0) { if (kk < 0) return -1; } // if change direction, fail if (rkk > 0) { if (kk < 0) return -1; } // if change direction, fail
else if (kk > 0) return -1; else if (kk > 0) return -1;
} }
} }
} }
} }
// Perform a binary search on sorted set of pointers to records in memory. // Perform a binary search on sorted set of pointers to records in memory.
// Return matching record number (0 based) or -1 if not found. // Return matching record number (0 based) or -1 if not found.
// The pointers are sorted in the order of the records starting at char N. // The pointers are sorted in the order of the records starting at ch N.
// The records need not be sorted. // The records need not be sorted.
// The string length of seekrec is compared. // The string length of seekrec is compared.
int bsearch(cchar *seekrec, cchar **allrecs, int N, int nrecs) int bsearch(ch *seekrec, ch **allrecs, int N, int nrecs)
{ {
int ii, jj, kk, rkk; int ii, jj, kk, rkk;
ii = nrecs / 2; // next element to search ii = nrecs / 2; // next element to search
jj = (ii + 1) / 2; // next increment jj = (ii + 1) / 2; // next increment
nrecs--; // last element nrecs--; // last element
rkk = 0; rkk = 0;
while (true) while (true)
{ {
skipping to change at line 4372 skipping to change at line 4391
/******************************************************************************* * /******************************************************************************* *
heap sort functions heap sort functions
void HeapSort(int list[], int nn) void HeapSort(int list[], int nn)
void HeapSort(float flist[], int nn) void HeapSort(float flist[], int nn)
void HeapSort(double dlist[], int nn) void HeapSort(double dlist[], int nn)
------------------------------------- -------------------------------------
Sort list of nn integers, floats, or doubles. Sort list of nn integers, floats, or doubles.
Numbers are sorted in ascending order. Numbers are sorted in ascending order.
void HeapSort(char *plist[], int nn) void HeapSort(ch *plist[], int nn)
------------------------------------ ------------------------------------
Pointers are sorted in order of the strings they point to. Pointers are sorted in order of the strings they point to.
The strings are not changed. The strings are not changed.
void HeapSort(char *plist1[], char *plist2[], int nn) void HeapSort(ch *plist1[], ch *plist2[], int nn)
----------------------------------------------------- -----------------------------------------------------
Sort two lists of pointers to two sets of strings. Sort two lists of pointers to two sets of strings.
Both lists are sorted in order of the first set of strings. Both lists are sorted in order of the first set of strings.
void HeapSort(char *plist[], int nn, compfunc) void HeapSort(ch *plist[], int nn, compfunc)
void HeapSort4(char *plist[], int nn, compfunc) void HeapSort4(ch *plist[], int nn, compfunc)
----------------------------------------------- -----------------------------------------------
Sort list of pointers to strings in user-defined order. Sort list of pointers to strings in user-defined order.
Pointers are sorted, strings are not changed. Pointers are sorted, strings are not changed.
HeapSort4 uses 4 parallel threads and is 3x faster for lists > 1000. HeapSort4 uses 4 parallel threads and is 3x faster for lists > 1000.
void HeapSort(char *recs, int RL, int NR, compfunc) void HeapSort(ch *recs, int RL, int NR, compfunc)
--------------------------------------------------- ---------------------------------------------------
Sort an array of records in memory using a caller-supplied compare function. Sort an array of records in memory using a caller-supplied compare function.
recs pointer to 1st record in array recs pointer to 1st record in array
RL record length RL record length
NR no. of records NR no. of records
int compfunc(cchar *rec1, cchar *rec2) int compfunc(ch *rec1, ch *rec2)
-------------------------------------- --------------------------------------
compare rec1 to rec2, return -1 0 +1 if rec1 < = > rec2 in sort order. compare rec1 to rec2, return -1 0 +1 if rec1 < = > rec2 in sort order.
Benchmarks: (3.3 GHz Core i5) Benchmarks: (3.3 GHz Core i5)
10 million integers: 1.5 secs 10 million integers: 1.5 secs
10 million doubles: 2.4 secs 10 million doubles: 2.4 secs
10 million pointers to 100 character recs: 10 million pointers to 100 character recs:
HeapSort: 11.33 HeapSort4: 4.25 HeapSort: 11.33 HeapSort4: 4.25
******************************************************************************** */ ******************************************************************************** */
skipping to change at line 4519 skipping to change at line 4538
for (jj = nn-1; jj > 0; jj--) for (jj = nn-1; jj > 0; jj--)
{ {
SWAP(bb[1], bb[jj+1]); SWAP(bb[1], bb[jj+1]);
adjust(vv,1,jj); adjust(vv,1,jj);
} }
} }
// heapsort array of pointers to strings in ascending order of strings // heapsort array of pointers to strings in ascending order of strings
// pointers are sorted, strings are not changed. // pointers are sorted, strings are not changed.
void adjust(char *vv[], int n1, int n2) void adjust(ch *vv[], int n1, int n2)
{ {
char **bb, *temp; ch **bb, *temp;
int jj, kk; int jj, kk;
bb = vv - 1; bb = vv - 1;
jj = n1; jj = n1;
kk = n1 * 2; kk = n1 * 2;
while (kk <= n2) while (kk <= n2)
{ {
if (kk < n2 && strcmp(bb[kk],bb[kk+1]) < 0) kk++; if (kk < n2 && strcmp(bb[kk],bb[kk+1]) < 0) kk++;
if (strcmp(bb[jj],bb[kk]) < 0) SWAP(bb[jj],bb[kk]); if (strcmp(bb[jj],bb[kk]) < 0) SWAP(bb[jj],bb[kk]);
jj = kk; jj = kk;
kk *= 2; kk *= 2;
} }
} }
void HeapSort(char *vv[], int nn) void HeapSort(ch *vv[], int nn)
{ {
char **bb, *temp; ch **bb, *temp;
int jj; int jj;
for (jj = nn/2; jj > 0; jj--) adjust(vv,jj,nn); for (jj = nn/2; jj > 0; jj--) adjust(vv,jj,nn);
bb = vv; bb = vv;
for (jj = nn-1; jj > 0; jj--) for (jj = nn-1; jj > 0; jj--)
{ {
SWAP(bb[0], bb[jj]); SWAP(bb[0], bb[jj]);
adjust(vv,1,jj); adjust(vv,1,jj);
} }
} }
// Heapsort 2 lists of pointers to 2 parallel sets of strings // Heapsort 2 lists of pointers to 2 parallel sets of strings
// in ascending order of the first set of strings. // in ascending order of the first set of strings.
// Both lists of pointers are sorted together in tandem. // Both lists of pointers are sorted together in tandem.
// Pointers are sorted, strings are not changed. // Pointers are sorted, strings are not changed.
void adjust(char *vv1[], char *vv2[], int n1, int n2) void adjust(ch *vv1[], ch *vv2[], int n1, int n2)
{ {
char **bb1, **bb2, *temp; ch **bb1, **bb2, *temp;
int jj, kk; int jj, kk;
bb1 = vv1 - 1; bb1 = vv1 - 1;
bb2 = vv2 - 1; bb2 = vv2 - 1;
jj = n1; jj = n1;
kk = n1 * 2; kk = n1 * 2;
while (kk <= n2) while (kk <= n2)
{ {
if (kk < n2 && strcmp(bb1[kk],bb1[kk+1]) < 0) kk++; if (kk < n2 && strcmp(bb1[kk],bb1[kk+1]) < 0) kk++;
if (strcmp(bb1[jj],bb1[kk]) < 0) { if (strcmp(bb1[jj],bb1[kk]) < 0) {
SWAP(bb1[jj],bb1[kk]); SWAP(bb1[jj],bb1[kk]);
SWAP(bb2[jj],bb2[kk]); SWAP(bb2[jj],bb2[kk]);
} }
jj = kk; jj = kk;
kk *= 2; kk *= 2;
} }
} }
void HeapSort(char *vv1[], char *vv2[], int nn) void HeapSort(ch *vv1[], ch *vv2[], int nn)
{ {
char **bb1, **bb2, *temp; ch **bb1, **bb2, *temp;
int jj; int jj;
for (jj = nn/2; jj > 0; jj--) adjust(vv1,vv2,jj,nn); for (jj = nn/2; jj > 0; jj--) adjust(vv1,vv2,jj,nn);
bb1 = vv1; bb1 = vv1;
bb2 = vv2; bb2 = vv2;
for (jj = nn-1; jj > 0; jj--) for (jj = nn-1; jj > 0; jj--)
{ {
SWAP(bb1[0], bb1[jj]); SWAP(bb1[0], bb1[jj]);
SWAP(bb2[0], bb2[jj]); SWAP(bb2[0], bb2[jj]);
adjust(vv1,vv2,1,jj); adjust(vv1,vv2,1,jj);
} }
} }
// heapsort array of pointers to strings in user-defined order. // heapsort array of pointers to strings in user-defined order.
// pointers are sorted, strings are not changed. // pointers are sorted, strings are not changed.
void adjust(char *vv[], int n1, int n2, HeapSortUcomp fcomp) void adjust(ch *vv[], int n1, int n2, HeapSortUcomp fcomp)
{ {
char **bb, *temp; ch **bb, *temp;
int jj, kk; int jj, kk;
bb = vv - 1; bb = vv - 1;
jj = n1; jj = n1;
kk = n1 * 2; kk = n1 * 2;
while (kk <= n2) while (kk <= n2)
{ {
if (kk < n2 && fcomp(bb[kk],bb[kk+1]) < 0) kk++; if (kk < n2 && fcomp(bb[kk],bb[kk+1]) < 0) kk++;
if (fcomp(bb[jj],bb[kk]) < 0) SWAP(bb[jj],bb[kk]); if (fcomp(bb[jj],bb[kk]) < 0) SWAP(bb[jj],bb[kk]);
jj = kk; jj = kk;
kk *= 2; kk *= 2;
} }
} }
void HeapSort(char *vv[], int nn, HeapSortUcomp fcomp) void HeapSort(ch *vv[], int nn, HeapSortUcomp fcomp)
{ {
char **bb, *temp; ch **bb, *temp;
int jj; int jj;
for (jj = nn/2; jj > 0; jj--) adjust(vv,jj,nn,fcomp); for (jj = nn/2; jj > 0; jj--) adjust(vv,jj,nn,fcomp);
bb = vv; bb = vv;
for (jj = nn-1; jj > 0; jj--) for (jj = nn-1; jj > 0; jj--)
{ {
SWAP(bb[0], bb[jj]); SWAP(bb[0], bb[jj]);
adjust(vv,1,jj,fcomp); adjust(vv,1,jj,fcomp);
skipping to change at line 4643 skipping to change at line 4662
} }
// heaport array of pointers to strings in user-defined order. // heaport array of pointers to strings in user-defined order.
// pointers are sorted, strings are not changed. // pointers are sorted, strings are not changed.
// 4 parallel threads are used, each sorting 1/4 of the list, then merge. // 4 parallel threads are used, each sorting 1/4 of the list, then merge.
// speed for large arrays is roughly 3x faster. // speed for large arrays is roughly 3x faster.
namespace heapsort4 namespace heapsort4
{ {
int nn1, nn2, nn3, nn4; int nn1, nn2, nn3, nn4;
char **vv1, **vv2, **vv3, **vv4; ch **vv1, **vv2, **vv3, **vv4;
pthread_t tid1, tid2, tid3, tid4; pthread_t tid1, tid2, tid3, tid4;
int tt1 = 1, tt2 = 2, tt3 = 3, tt4 = 4; int tt1 = 1, tt2 = 2, tt3 = 3, tt4 = 4;
HeapSortUcomp *ttfcomp; HeapSortUcomp *ttfcomp;
} }
void HeapSort4(char *vv[], int nn, HeapSortUcomp fcomp) void HeapSort4(ch *vv[], int nn, HeapSortUcomp fcomp)
{ {
using namespace heapsort4; using namespace heapsort4;
void * HeapSort4thread(void *arg); void * HeapSort4thread(void *arg);
char **vv9, **next; ch **vv9, **next;
if (nn < 100 || get_nprocs() < 2) { // small list or <2 SMPs if (nn < 100 || get_nprocs() < 2) { // small list or <2 SMPs
HeapSort(vv,nn,fcomp); // use one thread HeapSort(vv,nn,fcomp); // use one thread
return; return;
} }
nn1 = nn2 = nn3 = nn / 4; // 1st/2nd/3rd sub-list counts nn1 = nn2 = nn3 = nn / 4; // 1st/2nd/3rd sub-list counts
nn4 = nn - nn1 - nn2 - nn3; // 4th sub-list count nn4 = nn - nn1 - nn2 - nn3; // 4th sub-list count
vv1 = vv; // 4 sub-list start positions vv1 = vv; // 4 sub-list start positions
skipping to change at line 4682 skipping to change at line 4701
tid1 = start_Jthread(HeapSort4thread,&tt1); // sort the 4 sub-lists, parallel tid1 = start_Jthread(HeapSort4thread,&tt1); // sort the 4 sub-lists, parallel
tid2 = start_Jthread(HeapSort4thread,&tt2); tid2 = start_Jthread(HeapSort4thread,&tt2);
tid3 = start_Jthread(HeapSort4thread,&tt3); tid3 = start_Jthread(HeapSort4thread,&tt3);
tid4 = start_Jthread(HeapSort4thread,&tt4); tid4 = start_Jthread(HeapSort4thread,&tt4);
wait_Jthread(tid1); // wait for 4 thread completions wait_Jthread(tid1); // wait for 4 thread completions
wait_Jthread(tid2); wait_Jthread(tid2);
wait_Jthread(tid3); wait_Jthread(tid3);
wait_Jthread(tid4); wait_Jthread(tid4);
vv9 = (char **) malloc(nn * sizeof(char *)); // merge list, output list vv9 = (ch **) malloc(nn * sizeof(ch *)); // merge list, output list
while (true) while (true)
{ {
next = 0; next = 0;
if (vv1) next = vv1; if (vv1) next = vv1;
if (! next && vv2) next = vv2; if (! next && vv2) next = vv2;
if (! next && vv3) next = vv3; if (! next && vv3) next = vv3;
if (! next && vv4) next = vv4; if (! next && vv4) next = vv4;
if (! next) break; if (! next) break;
skipping to change at line 4726 skipping to change at line 4745
vv4++; vv4++;
nn4--; nn4--;
if (! nn4) vv4 = 0; if (! nn4) vv4 = 0;
} }
*vv9 = *next; *vv9 = *next;
vv9++; vv9++;
} }
vv9 -= nn; vv9 -= nn;
memcpy(vv,vv9,nn * sizeof(char*)); // copy output list to input list memcpy(vv,vv9,nn * sizeof(ch *)); // copy output list to input list
free(vv9); // free output list free(vv9); // free output list
return; return;
} }
void * HeapSort4thread(void *arg) // thread function void * HeapSort4thread(void *arg) // thread function
{ {
using namespace heapsort4; using namespace heapsort4;
int tt = *((int *) arg); int tt = *((int *) arg);
skipping to change at line 4751 skipping to change at line 4770
return 0; return 0;
} }
// heapsort for array of records, // heapsort for array of records,
// using caller-supplied record compare function. // using caller-supplied record compare function.
// HeapSortUcomp returns [ -1 0 +1 ] for rec1 [ < = > ] rec2 // HeapSortUcomp returns [ -1 0 +1 ] for rec1 [ < = > ] rec2
// method: build array of pointers and sort these, then // method: build array of pointers and sort these, then
// use this sorted array to re-order the records at the end. // use this sorted array to re-order the records at the end.
void adjust(char *recs, int RL, int n1, int n2, int *vv1, HeapSortUcomp fcomp) void adjust(ch *recs, int RL, int n1, int n2, int *vv1, HeapSortUcomp fcomp)
{ {
int *bb, jj, kk, temp; int *bb, jj, kk, temp;
char *rec1, *rec2; ch *rec1, *rec2;
bb = vv1 - 1; bb = vv1 - 1;
jj = n1; jj = n1;
kk = n1 * 2; kk = n1 * 2;
while (kk <= n2) while (kk <= n2)
{ {
rec1 = recs + RL * bb[kk]; rec1 = recs + RL * bb[kk];
rec2 = recs + RL * bb[kk+1]; rec2 = recs + RL * bb[kk+1];
if (kk < n2 && fcomp(rec1,rec2) < 0) kk++; if (kk < n2 && fcomp(rec1,rec2) < 0) kk++;
rec1 = recs + RL * bb[jj]; rec1 = recs + RL * bb[jj];
rec2 = recs + RL * bb[kk]; rec2 = recs + RL * bb[kk];
if (fcomp(rec1,rec2) < 0) SWAP(bb[jj],bb[kk]); if (fcomp(rec1,rec2) < 0) SWAP(bb[jj],bb[kk]);
jj = kk; jj = kk;
kk *= 2; kk *= 2;
} }
} }
void HeapSort(char *recs, int RL, int NR, HeapSortUcomp fcomp) void HeapSort(ch *recs, int RL, int NR, HeapSortUcomp fcomp)
{ {
int *bb, jj, kk, temp, flag; int *bb, jj, kk, temp, flag;
int *vv1, *vv2; // make reentrant 22.18 int *vv1, *vv2; // make reentrant 22.18
char *vvrec; ch *vvrec;
vv1 = (int *) malloc((NR+1) * sizeof(int)); vv1 = (int *) malloc((NR+1) * sizeof(int));
for (jj = 0; jj < NR; jj++) vv1[jj] = jj; for (jj = 0; jj < NR; jj++) vv1[jj] = jj;
for (jj = NR/2; jj > 0; jj--) adjust(recs,RL,jj,NR,vv1,fcomp); for (jj = NR/2; jj > 0; jj--) adjust(recs,RL,jj,NR,vv1,fcomp);
bb = vv1 - 1; bb = vv1 - 1;
for (jj = NR-1; jj > 0; jj--) for (jj = NR-1; jj > 0; jj--)
{ {
SWAP(bb[1], bb[jj+1]); SWAP(bb[1], bb[jj+1]);
adjust(recs,RL,1,jj,vv1,fcomp); adjust(recs,RL,1,jj,vv1,fcomp);
} }
vv2 = (int *) malloc((NR+1) * sizeof(int)); vv2 = (int *) malloc((NR+1) * sizeof(int));
for (jj = 0; jj < NR; jj++) vv2[vv1[jj]] = jj; for (jj = 0; jj < NR; jj++) vv2[vv1[jj]] = jj;
vvrec = (char *) malloc(RL); vvrec = (ch *) malloc(RL);
flag = 1; flag = 1;
while (flag) while (flag)
{ {
flag = 0; flag = 0;
for (jj = 0; jj < NR; jj++) for (jj = 0; jj < NR; jj++)
{ {
kk = vv2[jj]; kk = vv2[jj];
if (kk == jj) continue; if (kk == jj) continue;
memmove(vvrec,recs+jj*RL,RL); memmove(vvrec,recs+jj*RL,RL);
memmove(recs+jj*RL,recs+kk*RL,RL); memmove(recs+jj*RL,recs+kk*RL,RL);
skipping to change at line 4819 skipping to change at line 4838
} }
} }
free(vv1); free(vv1);
free(vv2); free(vv2);
free(vvrec); free(vvrec);
} }
/******************************************************************************* * /******************************************************************************* *
int MemSort (char *RECS, int RL, int NR, int KEYS[][3], int NK) int MemSort (ch *RECS, int RL, int NR, int KEYS[][3], int NK)
RECS is an array of records, to be sorted in-place. RECS is an array of records, to be sorted in-place.
(record length = RL, record count = NR) (record length = RL, record count = NR)
KEYS[NK][3] is an integer array defined as follows: KEYS[NK][3] is an integer array defined as follows:
[N][0] starting position of Nth key field in RECS [N][0] starting position of Nth key field in RECS
[N][1] length of Nth key field in RECS [N][1] length of Nth key field in RECS
[N][2] type of sort for Nth key: [N][2] type of sort for Nth key:
1 = char ascending 1 = ch ascending
2 = char descending 2 = ch descending
3 = int*4 ascending 3 = int*4 ascending
4 = int*4 descending 4 = int*4 descending
5 = float*4 ascending 5 = float*4 ascending
6 = float*4 descending 6 = float*4 descending
7 = float*8 ascending (double) 7 = float*8 ascending (double)
8 = float*8 descending 8 = float*8 descending
Benchmark: 2 million recs of 40 bytes with 4 sort keys: Benchmark: 2 million recs of 40 bytes with 4 sort keys:
2.5 secs (3.3 GHz Core i5). 2.5 secs (3.3 GHz Core i5).
***/ ***/
int MemSortComp(cchar *rec1, cchar *rec2); int MemSortComp(ch *rec1, ch *rec2);
int MemSortKeys[10][3], MemSortNK; int MemSortKeys[10][3], MemSortNK;
int MemSort(char *RECS, int RL, int NR, int KEYS[][3], int NK) int MemSort(ch *RECS, int RL, int NR, int KEYS[][3], int NK)
{ {
int ii; int ii;
if (NR < 2) return 1; if (NR < 2) return 1;
if (NK > 10) zappcrash("MemSort, bad NK"); if (NK > 10) zappcrash("MemSort, bad NK");
if (NK < 1) zappcrash("MemSort, bad NK"); if (NK < 1) zappcrash("MemSort, bad NK");
MemSortNK = NK; MemSortNK = NK;
skipping to change at line 4866 skipping to change at line 4885
{ {
MemSortKeys[ii][0] = KEYS[ii][0]; MemSortKeys[ii][0] = KEYS[ii][0];
MemSortKeys[ii][1] = KEYS[ii][1]; MemSortKeys[ii][1] = KEYS[ii][1];
MemSortKeys[ii][2] = KEYS[ii][2]; MemSortKeys[ii][2] = KEYS[ii][2];
} }
HeapSort(RECS,RL,NR,MemSortComp); HeapSort(RECS,RL,NR,MemSortComp);
return 1; return 1;
} }
int MemSortComp(cchar *rec1, cchar *rec2) int MemSortComp(ch *rec1, ch *rec2)
{ {
int ii, stat, kpos, ktype, kleng; int ii, stat, kpos, ktype, kleng;
int inum1, inum2; int inum1, inum2;
float rnum1, rnum2; float rnum1, rnum2;
double dnum1, dnum2; double dnum1, dnum2;
cchar *p1, *p2; ch *p1, *p2;
for (ii = 0; ii < MemSortNK; ii++) // loop each key for (ii = 0; ii < MemSortNK; ii++) // loop each key
{ {
kpos = MemSortKeys[ii][0]; // relative position kpos = MemSortKeys[ii][0]; // relative position
kleng = MemSortKeys[ii][1]; // length kleng = MemSortKeys[ii][1]; // length
ktype = MemSortKeys[ii][2]; // type ktype = MemSortKeys[ii][2]; // type
p1 = rec1 + kpos; // absolute position p1 = rec1 + kpos; // absolute position
p2 = rec2 + kpos; p2 = rec2 + kpos;
switch (ktype) switch (ktype)
{ {
case 1: // char ascending case 1: // ch ascending
stat = strncmp(p1,p2,kleng); // compare 2 key values stat = strncmp(p1,p2,kleng); // compare 2 key values
if (stat) return stat; // + if rec1 > rec2, - if < if (stat) return stat; // + if rec1 > rec2, - if <
break; // 2 keys are equal, check next key break; // 2 keys are equal, check next key
case 2: // char descending case 2: // ch descending
stat = strncmp(p1,p2,kleng); stat = strncmp(p1,p2,kleng);
if (stat) return -stat; if (stat) return -stat;
break; break;
case 3: // int ascending case 3: // int ascending
memmove(&inum1,p1,4); memmove(&inum1,p1,4);
memmove(&inum2,p2,4); memmove(&inum2,p2,4);
if (inum1 > inum2) return 1; if (inum1 > inum2) return 1;
if (inum1 < inum2) return -1; if (inum1 < inum2) return -1;
break; break;
skipping to change at line 4977 skipping to change at line 4996
va_end(arglist); va_end(arglist);
return matchval; return matchval;
} }
/******************************************************************************* * /******************************************************************************* *
Hash Table class Hash Table class
HashTab(int cc, int cap); constructor HashTab(int cc, int cap); constructor
~HashTab(); destructor ~HashTab(); destructor
int Add(cchar *string); add a new string int Add(ch *string); add a new string
int Del(cchar *string); delete a string int Del(ch *string); delete a string
int Find(cchar *string); find a string int Find(ch *string); find a string
int GetCount() { return count; } get string count int GetCount() { return count; } get string count
int GetNext(int &first, char *string); get first/next string int GetNext(int &first, ch *string); get first/next string
int Dump(); dump hash table to std. outpu t int Dump(); dump hash table to std. outpu t
constructor: cc = string length of table entries, cap = table capacity constructor: cc = string length of table entries, cap = table capacity
cap should be set 30% higher than needed to reduce collisions and improve spe ed cap should be set 30% higher than needed to reduce collisions and improve spe ed
Benchmark: 0.056 usec. to find 19 char string in a table of 100,000 Benchmark: 0.056 usec. to find 19 ch string in a table of 100,000
which is 80% full. 3.3 GHz Core i5 which is 80% full. 3.3 GHz Core i5
******************************************************************************** */ ******************************************************************************** */
// static members (robust for tables up to 60% full) // static members (robust for tables up to 60% full)
int HashTab::tries1 = 100; // Add() tries int HashTab::tries1 = 100; // Add() tries
int HashTab::tries2 = 200; // Find() tries int HashTab::tries2 = 200; // Find() tries
HashTab::HashTab(int _cc, int _cap) // constructor HashTab::HashTab(int _cc, int _cap) // constructor
{ {
cc = 4 * (_cc + 4) / 4; // + 1 + mod 4 length cc = 4 * (_cc + 4) / 4; // + 1 + mod 4 length
cap = _cap; cap = _cap;
int len = cc * cap; int len = cc * cap;
table = new char [len]; table = new ch [len];
if (! table) zappcrash("HashTab() new %d fail",len,null); if (! table) zappcrash("HashTab() new %d fail",len,null);
memset(table,0,len); memset(table,0,len);
} }
HashTab::~HashTab() // destructor HashTab::~HashTab() // destructor
{ {
delete [] table; delete [] table;
table = 0; table = 0;
} }
// Add a new string to table // Add a new string to table
int HashTab::Add(cchar *string) int HashTab::Add(ch *string)
{ {
int pos, fpos, tries; int pos, fpos, tries;
pos = strHash(string,cap); // get random position pos = strHash(string,cap); // get random position
pos = pos * cc; pos = pos * cc;
for (tries = 0, fpos = -1; tries < tries1; tries++, pos += cc) // find next free slot at/after position for (tries = 0, fpos = -1; tries < tries1; tries++, pos += cc) // find next free slot at/after position
{ {
if (pos >= cap * cc) pos = 0; // last position wraps to 1st if (pos >= cap * cc) pos = 0; // last position wraps to 1st
skipping to change at line 5048 skipping to change at line 5067
} }
if (strmatch(string,table+pos)) return -2; // string already present if (strmatch(string,table+pos)) return -2; // string already present
} }
return -3; // table full (tries1 exceeded) return -3; // table full (tries1 exceeded)
} }
// Delete a string from table // Delete a string from table
int HashTab::Del(cchar *string) int HashTab::Del(ch *string)
{ {
int pos, tries; int pos, tries;
pos = strHash(string,cap); // get random position pos = strHash(string,cap); // get random position
pos = pos * cc; pos = pos * cc;
for (tries = 0; tries < tries2; tries++, pos += cc) // search for string at/after position for (tries = 0; tries < tries2; tries++, pos += cc) // search for string at/after position
{ {
if (pos >= cap * cc) pos = 0; // last position wraps to 1st if (pos >= cap * cc) pos = 0; // last position wraps to 1st
skipping to change at line 5074 skipping to change at line 5093
return (pos/cc); // return rel. table entry return (pos/cc); // return rel. table entry
} }
} }
zappcrash("HashTab::Del() fail",null); // exceed tries2, must not happen zappcrash("HashTab::Del() fail",null); // exceed tries2, must not happen
return 0; // (table too full to function) return 0; // (table too full to function)
} }
// Find a table entry. // Find a table entry.
int HashTab::Find(cchar *string) int HashTab::Find(ch *string)
{ {
int pos, tries; int pos, tries;
pos = strHash(string,cap); // get random position pos = strHash(string,cap); // get random position
pos = pos * cc; pos = pos * cc;
for (tries = 0; tries < tries2; tries++, pos += cc) // search for string at/after position for (tries = 0; tries < tries2; tries++, pos += cc) // search for string at/after position
{ {
if (pos >= cap * cc) pos = 0; // last position wraps to 1st if (pos >= cap * cc) pos = 0; // last position wraps to 1st
if (! table[pos]) return -1; // empty slot, string not found if (! table[pos]) return -1; // empty slot, string not found
if (strmatch(string,table+pos)) return (pos/cc); // string found, return rel. entry if (strmatch(string,table+pos)) return (pos/cc); // string found, return rel. entry
} }
zappcrash("HashTab::Find() fail",null); // cannot happen zappcrash("HashTab::Find() fail",null); // cannot happen
return 0; return 0;
} }
// return first or next table entry // return first or next table entry
int HashTab::GetNext(int &ftf, char *string) int HashTab::GetNext(int &ftf, ch *string)
{ {
static int pos; static int pos;
if (ftf) // initial call if (ftf) // initial call
{ {
pos = 0; pos = 0;
ftf = 0; ftf = 0;
} }
while (pos < (cap * cc)) while (pos < (cap * cc))
skipping to change at line 5144 skipping to change at line 5163
return 1; return 1;
} }
/******************************************************************************* * /******************************************************************************* *
list processing functions // replace pvlist functions list processing functions // replace pvlist functions
typedef struct { list data type typedef struct { list data type
int count; count of member strings int count; count of member strings
char **mber; member strings, null == no membe rs ch **mber; member strings, null == no membe rs
} zlist_t; } zlist_t;
zlist_t *zlist; zlist_t *zlist;
zlist = zlist_new(N) make new zlist with N null me mbers zlist = zlist_new(N) make new zlist with N null me mbers
void zlist_delete(zlist) delete zlist, free memory void zlist_delete(zlist) delete zlist, free memory
void zlist_dump(zlist) dump zlist to stdout void zlist_dump(zlist) dump zlist to stdout
N = zlist_count(zlist) get member count N = zlist_count(zlist) get member count
string = zlist_get(zlist,Nth) get Nth member string = zlist_get(zlist,Nth) get Nth member
void zlist_put(zlist,string,Nth) put Nth member (replace) void zlist_put(zlist,string,Nth) put Nth member (replace)
skipping to change at line 5181 skipping to change at line 5200
******************************************************************************** */ ******************************************************************************** */
// create zlist with 'count' empty members // create zlist with 'count' empty members
zlist_t * zlist_new(int count) zlist_t * zlist_new(int count)
{ {
zlist_t *zlist = (zlist_t *) zmalloc(sizeof(zlist_t),"zlist"); zlist_t *zlist = (zlist_t *) zmalloc(sizeof(zlist_t),"zlist");
zlist->count = count; zlist->count = count;
if (count > 0) if (count > 0)
zlist->mber = (char **) zmalloc(count * sizeof(char *),"zlist"); zlist->mber = (ch **) zmalloc(count * sizeof(ch *),"zlist");
for (int ii = 0; ii < count; ii++) for (int ii = 0; ii < count; ii++)
zlist->mber[ii] = null; zlist->mber[ii] = null;
return zlist; return zlist;
} }
// delete a zlist // delete a zlist
void zlist_delete(zlist_t *zlist) void zlist_delete(zlist_t *zlist)
{ {
for (int ii = 0; ii < zlist->count; ii++) for (int ii = 0; ii < zlist->count; ii++)
skipping to change at line 5220 skipping to change at line 5239
// get zlist member count // get zlist member count
int zlist_count(zlist_t *zlist) int zlist_count(zlist_t *zlist)
{ {
return zlist->count; return zlist->count;
} }
// get a zlist member // get a zlist member
char * zlist_get(zlist_t *zlist, int Nth) ch * zlist_get(zlist_t *zlist, int Nth)
{ {
if (Nth < 0 || Nth >= zlist->count) if (Nth < 0 || Nth >= zlist->count)
zappcrash("zlist_get() invalid Nth: %d",Nth); zappcrash("zlist_get() invalid Nth: %d",Nth);
return zlist->mber[Nth]; return zlist->mber[Nth];
} }
// put a zlist member (replace existing) (null allowed) // put a zlist member (replace existing) (null allowed)
void zlist_put(zlist_t *zlist, cchar *string, int Nth) void zlist_put(zlist_t *zlist, ch *string, int Nth)
{ {
if (Nth < 0 || Nth >= zlist->count) if (Nth < 0 || Nth >= zlist->count)
zappcrash("zlist_put() invalid Nth: %d",Nth); zappcrash("zlist_put() invalid Nth: %d",Nth);
if (zlist->mber[Nth]) zfree(zlist->mber[Nth]); if (zlist->mber[Nth]) zfree(zlist->mber[Nth]);
if (string) zlist->mber[Nth] = zstrdup(string,"zlist"); if (string) zlist->mber[Nth] = zstrdup(string,"zlist");
else zlist->mber[Nth] = 0; else zlist->mber[Nth] = 0;
return; return;
} }
// insert new zlist member (count increases) // insert new zlist member (count increases)
// new member is Nth member, old Nth member is Nth+1 // new member is Nth member, old Nth member is Nth+1
// if Nth > last + 1, null members are added in-between // if Nth > last + 1, null members are added in-between
void zlist_insert(zlist_t *zlist, cchar *string, int Nth) void zlist_insert(zlist_t *zlist, ch *string, int Nth)
{ {
int count, newcount; int count, newcount;
int ii1, ii2, cc; int ii1, ii2, cc;
char **newmber; ch **newmber;
if (Nth < 0) zappcrash("zlist_insert() invalid Nth: %d",Nth); if (Nth < 0) zappcrash("zlist_insert() invalid Nth: %d",Nth);
count = zlist->count; count = zlist->count;
if (Nth < count) newcount = count + 1; if (Nth < count) newcount = count + 1;
else newcount = Nth + 1; else newcount = Nth + 1;
newmber = (char **) zmalloc(newcount * sizeof(char *),"zlist"); newmber = (ch **) zmalloc(newcount * sizeof(ch *),"zlist");
if (Nth > 0) { // copy 0 - Nth-1 if (Nth > 0) { // copy 0 - Nth-1
ii1 = 0; ii1 = 0;
ii2 = Nth; ii2 = Nth;
if (Nth > count) ii2 = count; if (Nth > count) ii2 = count;
cc = (ii2 - ii1) * sizeof(char *); cc = (ii2 - ii1) * sizeof(ch *);
memcpy(newmber,zlist->mber,cc); memcpy(newmber,zlist->mber,cc);
} }
newmber[Nth] = zstrdup(string,"zlist"); // insert Nth newmber[Nth] = zstrdup(string,"zlist"); // insert Nth
if (Nth < count) { // copy Nth - last if (Nth < count) { // copy Nth - last
ii1 = Nth; ii1 = Nth;
ii2 = count; ii2 = count;
cc = (ii2 - ii1) * sizeof(char *); cc = (ii2 - ii1) * sizeof(ch *);
memcpy(newmber+ii1+1,zlist->mber+ii1,cc); memcpy(newmber+ii1+1,zlist->mber+ii1,cc);
} }
if (zlist->mber) zfree(zlist->mber); if (zlist->mber) zfree(zlist->mber);
zlist->mber = newmber; zlist->mber = newmber;
zlist->count = newcount; zlist->count = newcount;
return; return;
} }
// remove a zlist member (count -= 1) // remove a zlist member (count -= 1)
void zlist_remove(zlist_t *zlist, int Nth) void zlist_remove(zlist_t *zlist, int Nth)
{ {
int newcount, cc; int newcount, cc;
char **newmber; ch **newmber;
if (Nth < 0 || Nth >= zlist->count) if (Nth < 0 || Nth >= zlist->count)
zappcrash("zlist_remove() invalid Nth: %d",Nth); zappcrash("zlist_remove() invalid Nth: %d",Nth);
newcount = zlist->count - 1; newcount = zlist->count - 1;
if (newcount) if (newcount)
newmber = (char **) zmalloc(newcount * sizeof(char *),"zlist"); newmber = (ch **) zmalloc(newcount * sizeof(ch *),"zlist");
else newmber = 0; else newmber = 0;
if (Nth > 0) { // copy 0 - Nth-1 if (Nth > 0) { // copy 0 - Nth-1
cc = Nth * sizeof(char *); cc = Nth * sizeof(ch *);
memcpy(newmber,zlist->mber,cc); memcpy(newmber,zlist->mber,cc);
} }
if (zlist->mber[Nth]) zfree(zlist->mber[Nth]); // remove Nth if (zlist->mber[Nth]) zfree(zlist->mber[Nth]); // remove Nth
if (Nth < newcount) { // copy Nth+1 - last if (Nth < newcount) { // copy Nth+1 - last
cc = (newcount - Nth) * sizeof(char *); cc = (newcount - Nth) * sizeof(ch *);
memcpy(newmber+Nth,zlist->mber+Nth+1,cc); memcpy(newmber+Nth,zlist->mber+Nth+1,cc);
} }
zfree(zlist->mber); zfree(zlist->mber);
zlist->mber = newmber; zlist->mber = newmber;
zlist->count = newcount; zlist->count = newcount;
return; return;
} }
// purge zlist of all null members // purge zlist of all null members
void zlist_purge(zlist_t *zlist) void zlist_purge(zlist_t *zlist)
{ {
int ii, jj; int ii, jj;
char **mber; ch **mber;
for (ii = jj = 0; ii < zlist->count; ii++) for (ii = jj = 0; ii < zlist->count; ii++)
if (zlist->mber[ii]) jj++; if (zlist->mber[ii]) jj++;
if (jj) mber = (char **) zmalloc(jj * sizeof(char *),"zlist"); if (jj) mber = (ch **) zmalloc(jj * sizeof(ch *),"zlist");
else mber = 0; else mber = 0;
for (ii = jj = 0; ii < zlist->count; ii++) { for (ii = jj = 0; ii < zlist->count; ii++) {
if (zlist->mber[ii]) { if (zlist->mber[ii]) {
mber[jj] = zlist->mber[ii]; mber[jj] = zlist->mber[ii];
jj++; jj++;
} }
} }
zlist->count = jj; zlist->count = jj;
zfree(zlist->mber); zfree(zlist->mber);
zlist->mber = mber; zlist->mber = mber;
return; return;
} }
// clear zlist members from Nth to end // clear zlist members from Nth to end
void zlist_clear(zlist_t *zlist, int Nth) void zlist_clear(zlist_t *zlist, int Nth)
{ {
int ii; int ii;
char **mber = 0; ch **mber = 0;
if (Nth >= zlist_count(zlist)) return; if (Nth >= zlist_count(zlist)) return;
if (Nth > 0) mber = (char **) zmalloc(Nth * sizeof(char *),"zlist"); // remaining members if (Nth > 0) mber = (ch **) zmalloc(Nth * sizeof(ch *),"zlist"); // remaining members
for (ii = 0; ii < Nth; ii++) // copy remaining members for (ii = 0; ii < Nth; ii++) // copy remaining members
mber[ii] = zlist->mber[ii]; mber[ii] = zlist->mber[ii];
for (ii = Nth; ii < zlist_count(zlist); ii++) // free deleted members for (ii = Nth; ii < zlist_count(zlist); ii++) // free deleted members
zfree(zlist->mber[ii]); zfree(zlist->mber[ii]);
zfree(zlist->mber); zfree(zlist->mber);
zlist->mber = mber; // null if empty list zlist->mber = mber; // null if empty list
zlist->count = Nth; zlist->count = Nth;
return; return;
} }
// add new member at first null position, or append (if unique) // add new member at first null position, or append (if unique)
// return 0 if OK, 1 if not unique // return 0 if OK, 1 if not unique
int zlist_add(zlist_t *zlist, cchar *string, int Funiq) int zlist_add(zlist_t *zlist, ch *string, int Funiq)
{ {
int ii; int ii;
if (Funiq && zlist_find(zlist,string,0) >= 0) return 1; if (Funiq && zlist_find(zlist,string,0) >= 0) return 1;
for (ii = 0; ii < zlist->count; ii++) for (ii = 0; ii < zlist->count; ii++)
if (! zlist->mber[ii]) break; if (! zlist->mber[ii]) break;
if (ii < zlist->count) { if (ii < zlist->count) {
zlist->mber[ii] = zstrdup(string,"zlist"); zlist->mber[ii] = zstrdup(string,"zlist");
return 0; return 0;
} }
return zlist_append(zlist,string,Funiq); return zlist_append(zlist,string,Funiq);
} }
// append new member at end (if unique) // append new member at end (if unique)
// return 0 if OK, 1 if not unique // return 0 if OK, 1 if not unique
int zlist_append(zlist_t *zlist, cchar *string, int Funiq) int zlist_append(zlist_t *zlist, ch *string, int Funiq)
{ {
if (Funiq && zlist_find(zlist,string,0) >= 0) return 1; if (Funiq && zlist_find(zlist,string,0) >= 0) return 1;
zlist_insert(zlist,string,zlist->count); zlist_insert(zlist,string,zlist->count);
return 0; return 0;
} }
// prepend new member at posn 0 (if unique) // prepend new member at posn 0 (if unique)
// return 0 if OK, 1 if not unique // return 0 if OK, 1 if not unique
int zlist_prepend(zlist_t *zlist, cchar *string, int Funiq) int zlist_prepend(zlist_t *zlist, ch *string, int Funiq)
{ {
if (Funiq && zlist_find(zlist,string,0) >= 0) return 1; if (Funiq && zlist_find(zlist,string,0) >= 0) return 1;
zlist_insert(zlist,string,0); zlist_insert(zlist,string,0);
return 0; return 0;
} }
// find next matching zlist member at/from given posn // find next matching zlist member at/from given posn
int zlist_find(zlist_t *zlist, cchar *string, int posn) int zlist_find(zlist_t *zlist, ch *string, int posn)
{ {
if (posn < 0 || posn >= zlist->count) return -1; if (posn < 0 || posn >= zlist->count) return -1;
for (int ii = posn; ii < zlist->count; ii++) { for (int ii = posn; ii < zlist->count; ii++) {
if (zlist->mber[ii]) if (zlist->mber[ii])
if (strmatch(string,zlist->mber[ii])) return ii; if (strmatch(string,zlist->mber[ii])) return ii;
} }
return -1; return -1;
} }
// find next matching zlist member at/from given posn (wildcard match) // find next matching zlist member at/from given posn (wildcard match)
int zlist_findwild(zlist_t *zlist, cchar *wstring, int posn) int zlist_findwild(zlist_t *zlist, ch *wstring, int posn)
{ {
if (posn < 0 || posn >= zlist->count) return -1; if (posn < 0 || posn >= zlist->count) return -1;
for (int ii = posn; ii < zlist->count; ii++) { for (int ii = posn; ii < zlist->count; ii++) {
if (zlist->mber[ii]) if (zlist->mber[ii])
if (MatchWild(wstring,zlist->mber[ii]) == 0) return ii; if (MatchWild(wstring,zlist->mber[ii]) == 0) return ii;
} }
return -1; return -1;
} }
// copy a zlist // copy a zlist
skipping to change at line 5488 skipping to change at line 5507
// sort zlist ascending // sort zlist ascending
void zlist_sort(zlist_t *zlist) void zlist_sort(zlist_t *zlist)
{ {
HeapSort(zlist->mber,zlist->count); HeapSort(zlist->mber,zlist->count);
return; return;
} }
// sort zlist via caller compare function // sort zlist via caller compare function
void zlist_sort(zlist_t *zlist, int ccfunc(cchar *, cchar *)) void zlist_sort(zlist_t *zlist, int ccfunc(ch *, ch *))
{ {
HeapSort(zlist->mber,zlist->count,ccfunc); HeapSort(zlist->mber,zlist->count,ccfunc);
return; return;
} }
// make file from zlist // make file from zlist
int zlist_to_file(zlist_t *zlist, cchar *filename) int zlist_to_file(zlist_t *zlist, ch *filename)
{ {
int ii, err; int ii, err;
FILE *fid = fopen(filename,"w"); FILE *fid = fopen(filename,"w");
if (! fid) return errno; if (! fid) return errno;
for (ii = 0; ii < zlist->count; ii++) for (ii = 0; ii < zlist->count; ii++)
if (zlist->mber[ii]) if (zlist->mber[ii])
fprintf(fid,"%s\n",zlist->mber[ii]); fprintf(fid,"%s\n",zlist->mber[ii]);
err = fclose(fid); err = fclose(fid);
if (err) return errno; if (err) return errno;
else return 0; else return 0;
} }
// make zlist from file // make zlist from file
// performance with SSD: over 100 MB/sec. // performance with SSD: over 100 MB/sec.
zlist_t * zlist_from_file(cchar *filename) zlist_t * zlist_from_file(ch *filename)
{ {
FILE *fid; FILE *fid;
zlist_t *zlist; zlist_t *zlist;
int ii, count = 0; int ii, count = 0;
char *pp, buff[XFCC]; ch *pp, buff[XFCC];
fid = fopen(filename,"r"); // count recs in file fid = fopen(filename,"r"); // count recs in file
if (! fid) return 0; // this adds 40% to elapsed time if (! fid) return 0; // this adds 40% to elapsed time
while (true) { while (true) {
pp = fgets(buff,XFCC,fid); pp = fgets(buff,XFCC,fid);
if (! pp) break; if (! pp) break;
count++; count++;
} }
fclose(fid); fclose(fid);
skipping to change at line 5671 skipping to change at line 5690
// create and initialize Qtext queue, empty status // create and initialize Qtext queue, empty status
void Qtext_open(Qtext *qtext, int cap) void Qtext_open(Qtext *qtext, int cap)
{ {
int cc; int cc;
qtext->qcap = cap; qtext->qcap = cap;
qtext->qnewest = -1; qtext->qnewest = -1;
qtext->qoldest = -1; qtext->qoldest = -1;
qtext->qdone = 0; qtext->qdone = 0;
cc = cap * sizeof(char *); cc = cap * sizeof(ch *);
qtext->qtext = (char **) zmalloc(cc,"qtext"); qtext->qtext = (ch **) zmalloc(cc,"qtext");
memset(qtext->qtext,0,cc); memset(qtext->qtext,0,cc);
return; return;
} }
// add new text string to Qtext queue // add new text string to Qtext queue
// if queue full, sleep until space is available // if queue full, sleep until space is available
void Qtext_put(Qtext *qtext, cchar *format, ...) void Qtext_put(Qtext *qtext, ch *format, ...)
{ {
int qnext; int qnext;
va_list arglist; va_list arglist;
char message[200]; ch message[200];
va_start(arglist,format); va_start(arglist,format);
vsnprintf(message,199,format,arglist); vsnprintf(message,199,format,arglist);
va_end(arglist); va_end(arglist);
qnext = qtext->qnewest + 1; qnext = qtext->qnewest + 1;
if (qnext == qtext->qcap) qnext = 0; if (qnext == qtext->qcap) qnext = 0;
while (qtext->qtext[qnext]) zsleep(0.01); while (qtext->qtext[qnext]) zsleep(0.01);
qtext->qtext[qnext] = zstrdup(message,"Qtext"); qtext->qtext[qnext] = zstrdup(message,"Qtext");
qtext->qnewest = qnext; qtext->qnewest = qnext;
return; return;
} }
// remove oldest text string from Qtext queue // remove oldest text string from Qtext queue
// if queue empty, return a null string // if queue empty, return a null string
// returned string is subject for zfree() // returned string is subject for zfree()
char * Qtext_get(Qtext *qtext) ch * Qtext_get(Qtext *qtext)
{ {
int qnext; int qnext;
char *text; ch *text;
if (qtext->qcap == 0) return 0; if (qtext->qcap == 0) return 0;
qnext = qtext->qoldest + 1; qnext = qtext->qoldest + 1;
if (qnext == qtext->qcap) qnext = 0; if (qnext == qtext->qcap) qnext = 0;
text = qtext->qtext[qnext]; text = qtext->qtext[qnext];
if (! text) return 0; if (! text) return 0;
qtext->qtext[qnext] = 0; qtext->qtext[qnext] = 0;
qtext->qoldest = qnext; qtext->qoldest = qnext;
return text; return text;
} }
skipping to change at line 5752 skipping to change at line 5771
returns: 1 already done returns: 1 already done
2 new desktop file created OK 2 new desktop file created OK
3 not an appimage 3 not an appimage
4 failure 4 failure
*****/ *****/
namespace appimage_install_names namespace appimage_install_names
{ {
char appimagexe1[100]; // initial executable pat ch appimagexe1[100]; // initial executable pat
h: /.../appname-NN.N-appimage h: /.../appname-NN.N-appimage
char appimagexe2[100]; // new executable path: / ch appimagexe2[100]; // new executable path: /
home/<user>/.local/bin/appname-NN.N-appimage home/<user>/.local/bin/appname-NN.N-appimage
char appname1[60]; // executable base name: ch appname1[60]; // executable base name:
appname-NN.N-appimage appname-NN.N-appimage
char appname2[40]; // application base name: ch appname2[40]; // application base name:
appname appname
} }
int appimage_install(cchar *appname) int appimage_install(ch *appname)
{ {
using namespace appimage_install_names; using namespace appimage_install_names;
STATB statB1, statB2; STATB statB1, statB2;
int err, cc; int err, cc;
int timediff = 0; int timediff = 0;
char *pp, *homedir; ch *pp, *homedir;
char Busr[300]; ch Busr[300];
char desktopfile1[100], desktopfile2[100]; ch desktopfile1[100], desktopfile2[100];
char iconfile1[100], iconfile2[100]; ch iconfile1[100], iconfile2[100];
char exectext1[100], exectext2[100]; ch exectext1[100], exectext2[100];
char icontext1[100], icontext2[100]; ch icontext1[100], icontext2[100];
homedir = getenv("HOME"); homedir = getenv("HOME");
if (strchr(homedir,' ')) { // check /home/user has no blanks if (strchr(homedir,' ')) { // check /home/user has no blanks
Plog(0,"user home \"%s\" has embedded blank",homedir); Plog(0,"user home \"%s\" has embedded blank",homedir);
return 4; return 4;
} }
pp = getenv("APPIMAGE"); // appimage executable file pp = getenv("APPIMAGE"); // appimage executable file
if (! pp) return 3; if (! pp) return 3;
if (! strstr(pp,appname)) return 3; // not my appimage if (! strstr(pp,appname)) return 3; // not my appimage
skipping to change at line 5873 skipping to change at line 5892
/******************************************************************************* */ /******************************************************************************* */
// Uninstall AppImage program, desktop and icon files // Uninstall AppImage program, desktop and icon files
// exits if program is uninstalled // exits if program is uninstalled
// returns if not (user cancels, program is not an appimage) // returns if not (user cancels, program is not an appimage)
void appimage_unstall() void appimage_unstall()
{ {
using namespace appimage_install_names; using namespace appimage_install_names;
char *homedir; ch *homedir;
char desktopfileloc[200]; ch desktopfileloc[200];
char iconfileloc[200]; ch iconfileloc[200];
if (! *appimagexe2) { if (! *appimagexe2) {
Plog(0,"not an appimage, nothing was done \n"); Plog(0,"not an appimage, nothing was done \n");
return; return;
} }
homedir = getenv("HOME"); homedir = getenv("HOME");
snprintf(desktopfileloc,200,"%s/.local/share/applications/",homedir); snprintf(desktopfileloc,200,"%s/.local/share/applications/",homedir);
snprintf(iconfileloc,200,"%s/.local/share/icons/",homedir); snprintf(iconfileloc,200,"%s/.local/share/icons/",homedir);
skipping to change at line 5925 skipping to change at line 5944
(following the 1st argument) from the install folder into the newly created (following the 1st argument) from the install folder into the newly created
user-specific folder. The assumption is that all initial data files for the user-specific folder. The assumption is that all initial data files for the
application (e.g. parameters) will be in the install data folder, and these a re application (e.g. parameters) will be in the install data folder, and these a re
copied to the user folder where the user or application can modify them. copied to the user folder where the user or application can modify them.
If the running program is not connected to a terminal device, stdout and stde rr are If the running program is not connected to a terminal device, stdout and stde rr are
redirected to the log file at /home/user/.appname/logfile redirected to the log file at /home/user/.appname/logfile
***/ ***/
cchar * get_zprefix() { return zfuncs::zprefix; } ch * get_zprefix() { return zfuncs::zprefix; }
// /usr or /home/<user> // /usr or /home/<user>
cchar * get_zhomedir() { return zfuncs::zhomedir; } ch * get_zhomedir() { return zfuncs::zhomedir; }
// /home/<user>/.appname or /root/.appname // /home/<user>/.appname or /root/.appname
cchar * get_zdatadir() { return zfuncs::zdatadir; } ch * get_zdatadir() { return zfuncs::zdatadir; }
// data files // data files
cchar * get_zdocdir() { return zfuncs::zdocdir; } ch * get_zdocdir() { return zfuncs::zdocdir; }
// documentation files // documentation files
cchar * get_zimagedir() { return zfuncs::zimagedir; } ch * get_zimagedir() { return zfuncs::zimagedir; }
// image files // image files
int zinitapp(cchar *appvers, int argc, char *argv[]) // appname-N.N int zinitapp(ch *appvers, int argc, ch *argv[]) // appname-N.N
{ {
using namespace appimage_install_names; using namespace appimage_install_names;
char logfile[200], buff[300]; ch logfile[200], buff[300];
char *homedir, LNhomedir[200]; ch *homedir, LNhomedir[200];
char cssfile[200]; ch cssfile[200];
char *pp, *ch_time; ch *pp, *ch_time;
int ii, cc, err; int ii, cc, err;
time_t startime; time_t startime;
STATB statB; STATB statB;
FILE *fid; FILE *fid;
startime = time(null); // app start time, secs. since 1970 startime = time(null); // app start time, secs. since 1970
catch_signals(); // catch signals, do backtrace catch_signals(); // catch signals, do backtrace
Plog(1,"command: "); Plog(1,"command: ");
skipping to change at line 6045 skipping to change at line 6064
Plog(1,"-------------------------------------------\n"); // log file separator Plog(1,"-------------------------------------------\n"); // log file separator
ch_time = ctime(&startime); // start time: Ddd Mmm dd hh:mm:ss.nn ch_time = ctime(&startime); // start time: Ddd Mmm dd hh:mm:ss.nn
ch_time[19] = 0; // eliminate hundredths of seconds ch_time[19] = 0; // eliminate hundredths of seconds
if (ch_time[8] == ' ') ch_time[8] = '0'; // replace ' d' with '0d' if (ch_time[8] == ' ') ch_time[8] = '0'; // replace ' d' with '0d'
Plog(1,"start %s %s \n",zappname,ch_time); Plog(1,"start %s %s \n",zappname,ch_time);
fflush(0); fflush(0);
err = stat(zdatadir,&statB); // missing files from .../appname/data err = stat(zdatadir,&statB); // missing files from .../appname/data
if (! err) zshell("log","cp -R -n %s/* %s",zdatadir,zhomedir); // --> user appname home folder if (! err) zshell("ack","cp -R -n %s/* %s",zdatadir,zhomedir); // --> user appname home folder
tid_main = pthread_self(); // thread ID of main() process tid_main = pthread_self(); // thread ID of main() process
// GTK initialization // GTK initialization
setenv("GDK_BACKEND","x11",0); // necessary for Fedora setenv("GDK_BACKEND","x11",0); // necessary for Fedora
setenv("GTK_THEME","default",0); // set theme if missing (KDE etc.) setenv("GTK_THEME","default",0); // set theme if missing (KDE etc.)
if (gtk_clutter_init(&argc,&argv) != CLUTTER_INIT_SUCCESS) // intiz. clutter and GTK if (gtk_clutter_init(&argc,&argv) != CLUTTER_INIT_SUCCESS) // intiz. clutter and GTK
if (! gtk_init_check(0,null)) zexit(1,"GTK initialization failed"); if (! gtk_init_check(0,null)) zexit(1,"GTK initialization failed");
skipping to change at line 6107 skipping to change at line 6126
/******************************************************************************* */ /******************************************************************************* */
// popup window with application 'about' information // popup window with application 'about' information
void zabout() void zabout()
{ {
using namespace appimage_install_names; using namespace appimage_install_names;
zdialog *zd; zdialog *zd;
int cc; int cc;
char installed_release[80]; ch installed_release[80];
char title[40]; ch title[40];
char *execfile; ch *execfile;
/*** /***
__________________________________________________ __________________________________________________
| About Appname | | About Appname |
| | | |
| installed release: appname-N.N Mon dd yyyy | // 'query release' removed 22.11 | installed release: appname-N.N Mon dd yyyy | // 'query release' removed 22.11
| executable: xxxxxxxxxxxxxxxxxxxxxxxxxxxxx | | executable: xxxxxxxxxxxxxxxxxxxxxxxxxxxxx |
| contact: mkornelix@gmail.com | | contact: mkornelix@gmail.com |
|__________________________________________________| |__________________________________________________|
skipping to change at line 6159 skipping to change at line 6178
return; return;
} }
/******************************************************************************* */ /******************************************************************************* */
// set a new application font via GtkSettings // set a new application font via GtkSettings
// newfont should be something like "sans 11" // newfont should be something like "sans 11"
// use generic monospace font since app font may not have a mono version // use generic monospace font since app font may not have a mono version
void zsetfont(cchar *newfont) void zsetfont(ch *newfont)
{ {
char font[40], bfont[48], mfont[48], mbfont[56]; ch font[40], bfont[48], mfont[48], mbfont[56];
char junk[40]; ch junk[40];
int nn, size; int nn, size;
if (! gtksettings) return; if (! gtksettings) return;
nn = sscanf(newfont,"%s %d",font,&size); // "sans 11" nn = sscanf(newfont,"%s %d",font,&size); // "sans 11"
if (nn != 2) { if (nn != 2) {
nn = sscanf(newfont,"%s %s %d",font,junk,&size); nn = sscanf(newfont,"%s %s %d",font,junk,&size);
if (nn != 3) goto fail; if (nn != 3) goto fail;
} }
if (size < 5 || size > 30) goto fail; if (size < 5 || size > 30) goto fail;
skipping to change at line 6230 skipping to change at line 6249
/******************************************************************************* */ /******************************************************************************* */
// Find installation file or user file. // Find installation file or user file.
// file type: doc, data, user // file type: doc, data, user
// file name: README, changelog, userguide, parameters ... // file name: README, changelog, userguide, parameters ...
// Returns complete file name, e.g. /usr/share/appname/data/userguide // Returns complete file name, e.g. /usr/share/appname/data/userguide
// Output filespec should be 200 bytes (limit for all installation files). // Output filespec should be 200 bytes (limit for all installation files).
// Returns 0 if OK, +N if not found. // Returns 0 if OK, +N if not found.
int get_zfilespec(cchar *filetype, cchar *filename, char *filespec) int get_zfilespec(ch *filetype, ch *filename, ch *filespec)
{ {
int cc, err; int cc, err;
STATB statB; STATB statB;
filespec[0] = '/'; filespec[0] = '/';
strcat(filespec,filetype); // leave /type as default strcat(filespec,filetype); // leave /type as default
if (strmatch(filetype,"doc")) strcpy(filespec,zdocdir); // /usr/share/doc/appname if (strmatch(filetype,"doc")) strcpy(filespec,zdocdir); // /usr/share/doc/appname
if (strmatch(filetype,"data")) strcpy(filespec,zdatadir); // /usr/share/appname/data if (strmatch(filetype,"data")) strcpy(filespec,zdatadir); // /usr/share/appname/data
if (strmatch(filetype,"user")) strcpy(filespec,zhomedir); // /home/<user>/.appname if (strmatch(filetype,"user")) strcpy(filespec,zhomedir); // /home/<user>/.appname
skipping to change at line 6266 skipping to change at line 6285
return 1; // not found return 1; // not found
} }
/******************************************************************************* */ /******************************************************************************* */
// display application log file in a popup window // display application log file in a popup window
// The log file is /home/<user>/.appname/logfile // The log file is /home/<user>/.appname/logfile
void showz_logfile(GtkWidget *parent) void showz_logfile(GtkWidget *parent)
{ {
char buff[200]; ch buff[200];
fflush(0); fflush(0);
snprintf(buff,199,"cat %s/logfile",zhomedir); snprintf(buff,199,"cat %s/logfile",zhomedir);
popup_command(buff,800,600,parent); popup_command(buff,800,600,parent);
return; return;
} }
// find and show a text file in /usr/share/doc/appname/ // find and show a text file in /usr/share/doc/appname/
// or /usr/share/appname/data // or /usr/share/appname/data
// the text file may also be a compressed .gz file // the text file may also be a compressed .gz file
// type is "doc" or "data" // type is "doc" or "data"
void showz_textfile(const char *type, const char *file, GtkWidget *parent) void showz_textfile(ch *type, ch *file, GtkWidget *parent)
{ {
char filex[40], filespec[200], command[200]; ch filex[40], filespec[200], command[200];
int err; int err;
strncpy0(filex,file,36); // look for gzip file first strncpy0(filex,file,36); // look for gzip file first
strcat(filex,".gz"); strcat(filex,".gz");
err = get_zfilespec(type,filex,filespec); err = get_zfilespec(type,filex,filespec);
if (! err) { if (! err) {
snprintf(command,200,"zcat \"%s\"",filespec); // use quotes around filename 23.0 snprintf(command,200,"zcat \"%s\"",filespec); // use quotes around filename 23.0
popup_command(command,700,500,parent,1); popup_command(command,700,500,parent,1);
return; return;
skipping to change at line 6321 skipping to change at line 6340
} }
zmessageACK(mainwin,"file not found: %s %s",type,file); zmessageACK(mainwin,"file not found: %s %s",type,file);
return; return;
} }
// show a local or remote html file using the user's preferred browser // show a local or remote html file using the user's preferred browser
// to show a local file starting at an internal live link location: // to show a local file starting at an internal live link location:
// url = "file://folder/.../filename-livelink // url = "file://folder/.../filename-livelink
void showz_html(cchar *url) void showz_html(ch *url)
{ {
static char prog[40]; static ch prog[40];
static int ftf = 1, err; static int ftf = 1, err;
if (ftf) { if (ftf) {
ftf = 0; ftf = 0;
*prog = 0; *prog = 0;
err = zshell(0,"which firefox"); // use xdg-open only as last resort err = zshell(0,"which firefox"); // use xdg-open only as last resort
if (! err) strcpy(prog,"firefox"); if (! err) strcpy(prog,"firefox");
else { else {
err = zshell(0,"which chromium-browser"); err = zshell(0,"which chromium-browser");
if (! err) strcpy(prog,"chromium-browser --new-window"); if (! err) strcpy(prog,"chromium-browser --new-window");
skipping to change at line 6352 skipping to change at line 6371
zmessageACK(mainwin,"html file reader not found"); zmessageACK(mainwin,"html file reader not found");
return; return;
} }
zshell("ack","%s %s &",prog,url); zshell("ack","%s %s &",prog,url);
return; return;
} }
/******************************************************************************* * /******************************************************************************* *
void showz_docfile(GtkWidget *parent, char *docfile, char *topic) void showz_docfile(GtkWidget *parent, ch *docfile, ch *topic)
Show docfile in popup scrolling text window with 'topic' at the top. Show docfile in popup scrolling text window with 'topic' at the top.
docfile is located in data folder: get_zdatadir() docfile is located in data folder: get_zdatadir()
images are located in image folder: get_zimagedir() images are located in image folder: get_zimagedir()
docfile format: docfile format:
TOPIC 1 linkable topics in col. 1 TOPIC 1 linkable topics in col. 1
text text text text text text text text text text text text topic te xt (col. 1 blank) text text text text text text text text text text text text topic te xt (col. 1 blank)
text text text text text text text text text text text text text text text text text text text text text text text text
skipping to change at line 6387 skipping to change at line 6406
******************************************************************************** */ ******************************************************************************** */
namespace showz_docfile_names namespace showz_docfile_names
{ {
#define TMAX 1000 // max. markups #define TMAX 1000 // max. markups
zdialog *zd = 0; zdialog *zd = 0;
GtkWidget *textwidget; GtkWidget *textwidget;
int ii, jj; int ii, jj;
int currline; int currline;
char *Tname[TMAX]; // all topic names (link targets) ch *Tname[TMAX]; // all topic names (link targets)
int Tline[TMAX]; // topic lines, count int Tline[TMAX]; // topic lines, count
int Uline[TMAX], Upos[TMAX], Ucc[TMAX]; // underlined texts: line, posn, cc int Uline[TMAX], Upos[TMAX], Ucc[TMAX]; // underlined texts: line, posn, cc
int Bline[TMAX], Bpos[TMAX], Bcc[TMAX]; // bold texts: line, posn, cc int Bline[TMAX], Bpos[TMAX], Bcc[TMAX]; // bold texts: line, posn, cc
int Lline[TMAX], Lpos[TMAX], Lcc[TMAX]; // link texts: line, posn, cc int Lline[TMAX], Lpos[TMAX], Lcc[TMAX]; // link texts: line, posn, cc
char *Lname[TMAX]; // link name ch *Lname[TMAX]; // link name
int Ltarg[TMAX]; // link target (line number) int Ltarg[TMAX]; // link target (line number)
int TN = 0, UN, BN, LN = 0, UF, BF, LF; // counts, flags int TN = 0, UN, BN, LN = 0, UF, BF, LF; // counts, flags
zlist_t *RTopics = 0; // recent topics list zlist_t *RTopics = 0; // recent topics list
char RTfile[200] = ""; // recent topics file ch RTfile[200] = ""; // recent topics file
int RTmax = 20; // max. recent topics int RTmax = 20; // max. recent topics
} }
void showz_docfile(GtkWidget *parent, cchar *docfile, cchar *utopic) void showz_docfile(GtkWidget *parent, ch *docfile, ch *utopic)
{ {
using namespace showz_docfile_names; using namespace showz_docfile_names;
void showz_docfile_clickfunc(GtkWidget *widget, int line, int pos, int kbkey) ; void showz_docfile_clickfunc(GtkWidget *widget, int line, int pos, int kbkey) ;
void audit_docfile(cchar *docfile); void audit_docfile(ch *docfile);
FILE *fid; FILE *fid;
char filespec[200], buff1[200], buff2[200]; ch filespec[200], buff1[200], buff2[200];
// limits: filename, rec.cc // limits: filename, rec.cc
char topic[50], image[100]; ch topic[50], image[100];
// limits: topic name, image name // limits: topic name, image name
char *pp1, *pp2; ch *pp1, *pp2;
int Fm, line, pos1, pos2, cc; int Fm, line, pos1, pos2, cc;
GdkPixbuf *pixbuf; GdkPixbuf *pixbuf;
GError *gerror; GError *gerror;
if (utopic && strmatch(utopic,"quit")) { // quit - save recent topics list if (utopic && strmatch(utopic,"quit")) { // quit - save recent topics list
if (RTopics && *RTfile) zlist_to_file(RTopics,RTfile); if (RTopics && *RTfile) zlist_to_file(RTopics,RTfile);
if (zdialog_valid2(zd)) popup_report_close(zd,0); // close open report or UG if (zdialog_valid2(zd)) popup_report_close(zd,0); // close open report or UG
return; return;
} }
skipping to change at line 6553 skipping to change at line 6572
if (buff1[pos1+1] == '>') { // \> markup, link to topic if (buff1[pos1+1] == '>') { // \> markup, link to topic
if (! LF) { if (! LF) {
LF = 1; // start link LF = 1; // start link
Lline[LN] = line; Lline[LN] = line;
Lpos[LN] = pos2; Lpos[LN] = pos2;
Lcc[LN] = 0; Lcc[LN] = 0;
} }
else { else {
LF = 0; // end link LF = 0; // end link
Lname[LN] = (char *) zmalloc(Lcc[LN]+1,"docfile"); Lname[LN] = (ch *) zmalloc(Lcc[LN]+1,"docfile");
memcpy(Lname[LN],buff2+Lpos[LN],Lcc[LN]); // get link name memcpy(Lname[LN],buff2+Lpos[LN],Lcc[LN]); // get link name
Lname[LN][Lcc[LN]] = 0; Lname[LN][Lcc[LN]] = 0;
LN++; LN++;
} }
} }
pos1 += 2; // skip over \* markup pos1 += 2; // skip over \* markup
if (UN == TMAX || BN == TMAX || LN == TMAX) // check limits if (UN == TMAX || BN == TMAX || LN == TMAX) // check limits
zexit(1,"docfile exceeds %d markups \n",TMAX); zexit(1,"docfile exceeds %d markups \n",TMAX);
skipping to change at line 6632 skipping to change at line 6651
} }
// handle clicks on document window and KB inputs // handle clicks on document window and KB inputs
void showz_docfile_clickfunc(GtkWidget *textwidget, int line, int posn, int kbke y) void showz_docfile_clickfunc(GtkWidget *textwidget, int line, int posn, int kbke y)
{ {
using namespace showz_docfile_names; using namespace showz_docfile_names;
int ii, jj, cc; int ii, jj, cc;
int vtop, vbott, page, posn8; int vtop, vbott, page, posn8;
char *text, *pp1, *pp2; ch *text, *pp1, *pp2;
cchar *topic; ch *topic;
char text2[200], weblink[200]; ch text2[200], weblink[200];
static int Btab[10], maxB = 10, Bpos = 0; // last 10 links clicked static int Btab[10], maxB = 10, Bpos = 0; // last 10 links clicked
gtk_widget_grab_focus(textwidget); // necessary for some reason gtk_widget_grab_focus(textwidget); // necessary for some reason
textwidget_get_visible_lines(textwidget,vtop,vbott); // range of lines on screen textwidget_get_visible_lines(textwidget,vtop,vbott); // range of lines on screen
if (kbkey == 'r' || kbkey == 'R') // key 'R', recent topics if (kbkey == 'r' || kbkey == 'R') // key 'R', recent topics
{ {
topic = popup_picklist(textwidget,(cchar **) RTopics->mber,0, // choose a topic topic = popup_picklist(textwidget,(ch **) RTopics->mber,0, // choose a topic
RTopics->count); RTopics->count);
if (! topic) return; if (! topic) return;
for (ii = 0; ii < TN; ii++) // search docfile topics for (ii = 0; ii < TN; ii++) // search docfile topics
if (strmatchcase(topic,Tname[ii])) break; if (strmatchcase(topic,Tname[ii])) break;
if (ii == TN) return; // not found if (ii == TN) return; // not found
currline = Tline[ii]; // get line of matching topic currline = Tline[ii]; // get line of matching topic
popup_report_scroll_top(zd,currline); // scroll to topic line popup_report_scroll_top(zd,currline); // scroll to topic line
skipping to change at line 6752 skipping to change at line 6771
if (pp1[cc-1] == '.') cc--; // remove trailing period if (pp1[cc-1] == '.') cc--; // remove trailing period
if (cc > 199) return; if (cc > 199) return;
strncpy0(weblink,pp1,cc+1); // copy clicked text string strncpy0(weblink,pp1,cc+1); // copy clicked text string
if (strmatchN(pp1,"http",4)) showz_html(weblink); // if "http..." assume a web link if (strmatchN(pp1,"http",4)) showz_html(weblink); // if "http..." assume a web link
return; return;
} }
// validate the F1_help_topic links and the internal links in a docfile // validate the F1_help_topic links and the internal links in a docfile
// (developer tool) // (developer tool)
void audit_docfile(cchar *docfile) void audit_docfile(ch *docfile)
{ {
#define LMAX 10000 // max. docfile lines/recs #define LMAX 10000 // max. docfile lines/recs
char *textlines[LMAX]; ch *textlines[LMAX];
char *Tname[TMAX]; ch *Tname[TMAX];
char filespec[200], buff[200], image[100]; ch filespec[200], buff[200], image[100];
// limits: filename, rec.cc, image name // limits: filename, rec.cc, image name
char topic[50]; ch topic[50];
char *pp1, *pp2, *pp3; ch *pp1, *pp2, *pp3;
FILE *fid; FILE *fid;
int Ntext, Ntop, Nerrs; int Ntext, Ntop, Nerrs;
int ii, cc, line; int ii, cc, line;
GdkPixbuf *pixbuf; GdkPixbuf *pixbuf;
GError *gerror; GError *gerror;
Plog(0,"\n*** audit docfile %s *** \n",docfile); Plog(0,"\n*** audit docfile %s *** \n",docfile);
Ntext = Ntop = Nerrs = 0; Ntext = Ntop = Nerrs = 0;
skipping to change at line 6992 skipping to change at line 7011
textBuff = gtk_text_view_get_buffer(GTK_TEXT_VIEW(textwidget)); textBuff = gtk_text_view_get_buffer(GTK_TEXT_VIEW(textwidget));
if (! textBuff) return 0; if (! textBuff) return 0;
nlines = gtk_text_buffer_get_line_count(textBuff); nlines = gtk_text_buffer_get_line_count(textBuff);
return nlines; return nlines;
} }
// append a new line of text to the end of existing text lines // append a new line of text to the end of existing text lines
// line should normally include trailing \n // line should normally include trailing \n
// if current last line has no \n, text is appended to this line // if current last line has no \n, text is appended to this line
void textwidget_append(GtkWidget *textwidget, int bold, cchar *format, ...) void textwidget_append(GtkWidget *textwidget, int bold, ch *format, ...)
{ {
va_list arglist; va_list arglist;
char textline[20000]; // textwidget append cc limit 22.40 ch textline[20000]; // textwidget append cc limit 22.40
GtkTextBuffer *textBuff; GtkTextBuffer *textBuff;
GtkTextIter enditer; GtkTextIter enditer;
GtkTextTag *fontag = 0; GtkTextTag *fontag = 0;
cchar *normfont = zfuncs::appmonofont; ch *normfont = zfuncs::appmonofont;
cchar *boldfont = zfuncs::appmonoboldfont; ch *boldfont = zfuncs::appmonoboldfont;
va_start(arglist,format); va_start(arglist,format);
vsnprintf(textline,19999,format,arglist); // 22.40 vsnprintf(textline,19999,format,arglist); // 22.40
va_end(arglist); va_end(arglist);
textBuff = gtk_text_view_get_buffer(GTK_TEXT_VIEW(textwidget)); textBuff = gtk_text_view_get_buffer(GTK_TEXT_VIEW(textwidget));
if (! textBuff) return; if (! textBuff) return;
gtk_text_buffer_get_end_iter(textBuff,&enditer); // end of text gtk_text_buffer_get_end_iter(textBuff,&enditer); // end of text
if (bold) fontag = gtk_text_buffer_create_tag(textBuff,0,"font",boldfont,0); // prepare bold/norm tag if (bold) fontag = gtk_text_buffer_create_tag(textBuff,0,"font",boldfont,0); // prepare bold/norm tag
else fontag = gtk_text_buffer_create_tag(textBuff,0,"font",normfont,0); else fontag = gtk_text_buffer_create_tag(textBuff,0,"font",normfont,0);
gtk_text_buffer_insert_with_tags(textBuff,&enditer,textline,-1,fontag,null); // insert line gtk_text_buffer_insert_with_tags(textBuff,&enditer,textline,-1,fontag,null); // insert line
return; return;
} }
// same as above, with scroll to last line added (slower) // same as above, with scroll to last line added (slower)
void textwidget_append2(GtkWidget *textwidget, int bold, cchar *format, ...) void textwidget_append2(GtkWidget *textwidget, int bold, ch *format, ...)
{ {
va_list arglist; va_list arglist;
char textline[20000]; // textwidget append cc limit 22.40 ch textline[20000]; // textwidget append cc limit 22.40
GtkTextBuffer *textBuff; GtkTextBuffer *textBuff;
GtkTextIter enditer; GtkTextIter enditer;
GtkTextTag *fontag = 0; GtkTextTag *fontag = 0;
cchar *normfont = zfuncs::appmonofont; ch *normfont = zfuncs::appmonofont;
cchar *boldfont = zfuncs::appmonoboldfont; ch *boldfont = zfuncs::appmonoboldfont;
GtkAdjustment *vadjust; GtkAdjustment *vadjust;
double upperlimit; double upperlimit;
va_start(arglist,format); va_start(arglist,format);
vsnprintf(textline,19999,format,arglist); // 22.40 vsnprintf(textline,19999,format,arglist); // 22.40
va_end(arglist); va_end(arglist);
textBuff = gtk_text_view_get_buffer(GTK_TEXT_VIEW(textwidget)); textBuff = gtk_text_view_get_buffer(GTK_TEXT_VIEW(textwidget));
if (! textBuff) return; if (! textBuff) return;
skipping to change at line 7057 skipping to change at line 7076
gtk_adjustment_set_value(vadjust,upperlimit); gtk_adjustment_set_value(vadjust,upperlimit);
zmainloop(); zmainloop();
return; return;
} }
// insert a new line of text after designated line // insert a new line of text after designated line
// use line -1 to insert before line 0 // use line -1 to insert before line 0
// line should normally include trailing \n // line should normally include trailing \n
void textwidget_insert(GtkWidget *textwidget, int bold, int line, cchar *format, ...) void textwidget_insert(GtkWidget *textwidget, int bold, int line, ch *format, .. .)
{ {
va_list arglist; va_list arglist;
char textline[2000]; ch textline[2000];
GtkTextBuffer *textBuff; GtkTextBuffer *textBuff;
GtkTextIter iter; GtkTextIter iter;
int nlines; int nlines;
GtkTextTag *fontag = 0; GtkTextTag *fontag = 0;
cchar *normfont = zfuncs::appmonofont; ch *normfont = zfuncs::appmonofont;
cchar *boldfont = zfuncs::appmonoboldfont; ch *boldfont = zfuncs::appmonoboldfont;
va_start(arglist,format); va_start(arglist,format);
vsnprintf(textline,1999,format,arglist); vsnprintf(textline,1999,format,arglist);
va_end(arglist); va_end(arglist);
textBuff = gtk_text_view_get_buffer(GTK_TEXT_VIEW(textwidget)); textBuff = gtk_text_view_get_buffer(GTK_TEXT_VIEW(textwidget));
if (! textBuff) return; if (! textBuff) return;
if (line < 0) gtk_text_buffer_get_start_iter(textBuff,&iter); // insert before line 0 if (line < 0) gtk_text_buffer_get_start_iter(textBuff,&iter); // insert before line 0
skipping to change at line 7095 skipping to change at line 7114
else fontag = gtk_text_buffer_create_tag(textBuff,0,"font",normfont,0); else fontag = gtk_text_buffer_create_tag(textBuff,0,"font",normfont,0);
gtk_text_buffer_insert_with_tags(textBuff,&iter,textline,-1,fontag,null); // insert line gtk_text_buffer_insert_with_tags(textBuff,&iter,textline,-1,fontag,null); // insert line
return; return;
} }
// replace a given line with a new line // replace a given line with a new line
// line = -1: replace last line. -2: replace last-1 line, etc. // line = -1: replace last line. -2: replace last-1 line, etc.
// new line should normally include trailing \n // new line should normally include trailing \n
void textwidget_replace(GtkWidget *textwidget, int bold, int line, cchar *format , ...) void textwidget_replace(GtkWidget *textwidget, int bold, int line, ch *format, . ..)
{ {
va_list arglist; va_list arglist;
char textline[2000]; ch textline[2000];
GtkTextBuffer *textBuff; GtkTextBuffer *textBuff;
GtkTextIter iter1, iter2; GtkTextIter iter1, iter2;
int nlines; int nlines;
GtkTextTag *fontag = 0; GtkTextTag *fontag = 0;
cchar *normfont = zfuncs::appmonofont; ch *normfont = zfuncs::appmonofont;
cchar *boldfont = zfuncs::appmonoboldfont; ch *boldfont = zfuncs::appmonoboldfont;
va_start(arglist,format); va_start(arglist,format);
vsnprintf(textline,1999,format,arglist); vsnprintf(textline,1999,format,arglist);
va_end(arglist); va_end(arglist);
textBuff = gtk_text_view_get_buffer(GTK_TEXT_VIEW(textwidget)); textBuff = gtk_text_view_get_buffer(GTK_TEXT_VIEW(textwidget));
if (! textBuff) return; if (! textBuff) return;
nlines = gtk_text_buffer_get_line_count(textBuff); // lines now in buffer nlines = gtk_text_buffer_get_line_count(textBuff); // lines now in buffer
if (line < 0) line = nlines + line - 1; if (line < 0) line = nlines + line - 1;
skipping to change at line 7157 skipping to change at line 7176
gtk_text_buffer_delete(textBuff,&iter1,&iter2); // delete line gtk_text_buffer_delete(textBuff,&iter1,&iter2); // delete line
return; return;
} }
// find first line of text containing characters matching input string // find first line of text containing characters matching input string
// search is from line1 to end, then from 0 to line1-1 // search is from line1 to end, then from 0 to line1-1
// returns first matching line or -1 if none // returns first matching line or -1 if none
// comparison is not case sensitive // comparison is not case sensitive
int textwidget_find(GtkWidget *textwidget, char *matchtext, int line1) int textwidget_find(GtkWidget *textwidget, ch *matchtext, int line1)
{ {
GtkTextBuffer *textBuff; GtkTextBuffer *textBuff;
GtkTextIter iter1, iter2; GtkTextIter iter1, iter2;
int line, nlines, cc; int line, nlines, cc;
char *textline = 0, *pp1, *pp2; ch *textline = 0, *pp1, *pp2;
textBuff = gtk_text_view_get_buffer(GTK_TEXT_VIEW(textwidget)); textBuff = gtk_text_view_get_buffer(GTK_TEXT_VIEW(textwidget));
if (! textBuff) return -1; if (! textBuff) return -1;
nlines = gtk_text_buffer_get_line_count(textBuff); // lines now in buffer nlines = gtk_text_buffer_get_line_count(textBuff); // lines now in buffer
if (! nlines) return -1; if (! nlines) return -1;
if (line1 < 0) line1 = 0; // starting line to search if (line1 < 0) line1 = 0; // starting line to search
if (line1 >= nlines) line1 = 0; if (line1 >= nlines) line1 = 0;
line = line1; line = line1;
skipping to change at line 7287 skipping to change at line 7306
y2 = y1 + rect.height; y2 = y1 + rect.height;
gtk_text_view_get_line_at_y(GTK_TEXT_VIEW(textwidget), &iter1, y1, 0); gtk_text_view_get_line_at_y(GTK_TEXT_VIEW(textwidget), &iter1, y1, 0);
gtk_text_view_get_line_at_y(GTK_TEXT_VIEW(textwidget), &iter2, y2, 0); gtk_text_view_get_line_at_y(GTK_TEXT_VIEW(textwidget), &iter2, y2, 0);
vtop = gtk_text_iter_get_line(&iter1); vtop = gtk_text_iter_get_line(&iter1);
vbott = gtk_text_iter_get_line(&iter2) - 1; vbott = gtk_text_iter_get_line(&iter2) - 1;
return; return;
} }
// dump the entire textwidget contents into a file // dump the entire textwidget contents into a file
void textwidget_dump(GtkWidget *widget, cchar *filename) void textwidget_dump(GtkWidget *widget, ch *filename)
{ {
FILE *fid; FILE *fid;
char *prec; ch *prec;
int line, err; int line, err;
fid = fopen(filename,"w"); // open file fid = fopen(filename,"w"); // open file
if (! fid) { if (! fid) {
zmessageACK(mainwin,"cannot open file %s",filename); zmessageACK(mainwin,"cannot open file %s",filename);
return; return;
} }
for (line = 0; ; line++) for (line = 0; ; line++)
{ {
skipping to change at line 7315 skipping to change at line 7334
err = fclose(fid); // close file err = fclose(fid); // close file
if (err) zmessageACK(mainwin,"file close error"); if (err) zmessageACK(mainwin,"file close error");
return; return;
} }
// dump the entire textwidget contents into a file, using a save-as dialog // dump the entire textwidget contents into a file, using a save-as dialog
void textwidget_save(GtkWidget *widget, GtkWindow *parent) void textwidget_save(GtkWidget *widget, GtkWindow *parent)
{ {
char *file; ch *file;
file = zgetfile("save text to file",parent,"save","noname"); file = zgetfile("save text to file",parent,"save","noname");
if (! file) return; if (! file) return;
textwidget_dump(widget,file); textwidget_dump(widget,file);
zfree(file); zfree(file);
return; return;
} }
// Get a line of text. Returned text is subject for zfree(). // Get a line of text. Returned text is subject for zfree().
// trailing \n is included if strip == 0 // trailing \n is included if strip == 0
char * textwidget_line(GtkWidget *textwidget, int line, int strip) ch * textwidget_line(GtkWidget *textwidget, int line, int strip)
{ {
GtkTextBuffer *textBuff; GtkTextBuffer *textBuff;
GtkTextIter iter1, iter2; GtkTextIter iter1, iter2;
int cc, nlines; int cc, nlines;
char *textline, *ztext; ch *textline, *ztext;
textBuff = gtk_text_view_get_buffer(GTK_TEXT_VIEW(textwidget)); textBuff = gtk_text_view_get_buffer(GTK_TEXT_VIEW(textwidget));
if (! textBuff) return 0; if (! textBuff) return 0;
nlines = gtk_text_buffer_get_line_count(textBuff); // lines now in buffer nlines = gtk_text_buffer_get_line_count(textBuff); // lines now in buffer
if (line < 0 || line >= nlines) return 0; if (line < 0 || line >= nlines) return 0;
gtk_text_buffer_get_iter_at_line(textBuff,&iter1,line); // line start gtk_text_buffer_get_iter_at_line(textBuff,&iter1,line); // line start
iter2 = iter1; iter2 = iter1;
gtk_text_iter_forward_line(&iter2); // end gtk_text_iter_forward_line(&iter2); // end
skipping to change at line 7379 skipping to change at line 7398
iter2 = iter1; iter2 = iter1;
gtk_text_iter_forward_line(&iter2); // end gtk_text_iter_forward_line(&iter2); // end
gtk_text_buffer_select_range(textBuff,&iter1,&iter2); // highlight gtk_text_buffer_select_range(textBuff,&iter1,&iter2); // highlight
return; return;
} }
// get the word at the given position within the line // get the word at the given position within the line
// words are defined by line starts and ends, and the given delimiters // words are defined by line starts and ends, and the given delimiters
// returns word and delimiter (&end) // returns word and delimiter (&end)
char * textwidget_word(GtkWidget *textwidget, int line, int posn, cchar *dlims, char &end) ch * textwidget_word(GtkWidget *textwidget, int line, int posn, ch *dlims, ch &e nd)
{ {
GtkTextBuffer *textBuff; GtkTextBuffer *textBuff;
char *txline, *pp1, *pp2, *ztext; ch *txline, *pp1, *pp2, *ztext;
int cc, nn; int cc, nn;
textBuff = gtk_text_view_get_buffer(GTK_TEXT_VIEW(textwidget)); textBuff = gtk_text_view_get_buffer(GTK_TEXT_VIEW(textwidget));
if (! textBuff) return 0; if (! textBuff) return 0;
txline = textwidget_line(textwidget,line,0); txline = textwidget_line(textwidget,line,0);
if (! txline) return 0; if (! txline) return 0;
cc = strlen(txline); cc = strlen(txline);
if (txline[cc-1] == '\n') { if (txline[cc-1] == '\n') {
skipping to change at line 7425 skipping to change at line 7444
posn += nn-1; posn += nn-1;
if (posn >= cc) return 0; if (posn >= cc) return 0;
if (pp1 >= txline+posn) return 0; if (pp1 >= txline+posn) return 0;
} }
nn = utf8_position(pp2,1); nn = utf8_position(pp2,1);
if (nn > 0) cc = pp2 - pp1 + nn; if (nn > 0) cc = pp2 - pp1 + nn;
else cc = pp2 - pp1 + strlen(pp2); else cc = pp2 - pp1 + strlen(pp2);
end = pp1[cc]; end = pp1[cc];
ztext = (char *) zmalloc(cc+1,"textwidget"); ztext = (ch *) zmalloc(cc+1,"textwidget");
strncpy0(ztext,pp1,cc+1); strncpy0(ztext,pp1,cc+1);
zfree(txline); zfree(txline);
return ztext; return ztext;
} }
// highlight text at line and positiion, length cc // highlight text at line and positiion, length cc
void textwidget_highlight_word(GtkWidget *textwidget, int line, int posn, int cc ) void textwidget_highlight_word(GtkWidget *textwidget, int line, int posn, int cc )
{ {
GtkTextBuffer *textBuff; GtkTextBuffer *textBuff;
GtkTextIter iter1, iter2; GtkTextIter iter1, iter2;
char *txline, *pp1, *pp2; ch *txline, *pp1, *pp2;
textBuff = gtk_text_view_get_buffer(GTK_TEXT_VIEW(textwidget)); textBuff = gtk_text_view_get_buffer(GTK_TEXT_VIEW(textwidget));
if (! textBuff) return; if (! textBuff) return;
txline = textwidget_line(textwidget,line,0); txline = textwidget_line(textwidget,line,0);
if (! txline) return; if (! txline) return;
pp1 = txline + posn; pp1 = txline + posn;
pp2 = pp1 + cc - 1; pp2 = pp1 + cc - 1;
gtk_text_buffer_get_iter_at_line_index(textBuff,&iter1,line,pp1-txline); gtk_text_buffer_get_iter_at_line_index(textBuff,&iter1,line,pp1-txline);
skipping to change at line 7462 skipping to change at line 7481
return; return;
} }
// convert text to bold text at line, positiion, cc // convert text to bold text at line, positiion, cc
void textwidget_bold_word(GtkWidget *textwidget, int line, int posn, int cc) void textwidget_bold_word(GtkWidget *textwidget, int line, int posn, int cc)
{ {
GtkTextBuffer *textBuff; GtkTextBuffer *textBuff;
GtkTextIter iter1, iter2; GtkTextIter iter1, iter2;
GtkTextTag *fontag = 0; GtkTextTag *fontag = 0;
cchar *boldfont = zfuncs::appmonoboldfont; ch *boldfont = zfuncs::appmonoboldfont;
char *txline, *pp1, *pp2; ch *txline, *pp1, *pp2;
textBuff = gtk_text_view_get_buffer(GTK_TEXT_VIEW(textwidget)); textBuff = gtk_text_view_get_buffer(GTK_TEXT_VIEW(textwidget));
if (! textBuff) return; if (! textBuff) return;
txline = textwidget_line(textwidget,line,0); txline = textwidget_line(textwidget,line,0);
if (! txline) return; if (! txline) return;
fontag = gtk_text_buffer_create_tag(textBuff,0,"font",boldfont,0); fontag = gtk_text_buffer_create_tag(textBuff,0,"font",boldfont,0);
/*** /***
skipping to change at line 7495 skipping to change at line 7514
return; return;
} }
// convert text to underlined text at line, positiion, cc // convert text to underlined text at line, positiion, cc
void textwidget_underline_word(GtkWidget *textwidget, int line, int posn, int cc ) void textwidget_underline_word(GtkWidget *textwidget, int line, int posn, int cc )
{ {
GtkTextBuffer *textBuff; GtkTextBuffer *textBuff;
GtkTextIter iter1, iter2; GtkTextIter iter1, iter2;
GtkTextTag *fontag = 0; GtkTextTag *fontag = 0;
char *txline, *pp1, *pp2; ch *txline, *pp1, *pp2;
textBuff = gtk_text_view_get_buffer(GTK_TEXT_VIEW(textwidget)); textBuff = gtk_text_view_get_buffer(GTK_TEXT_VIEW(textwidget));
if (! textBuff) return; if (! textBuff) return;
txline = textwidget_line(textwidget,line,0); txline = textwidget_line(textwidget,line,0);
if (! txline) return; if (! txline) return;
fontag = gtk_text_buffer_create_tag(textBuff,0,"underline",PANGO_UNDERLINE_SI NGLE,0); fontag = gtk_text_buffer_create_tag(textBuff,0,"underline",PANGO_UNDERLINE_SI NGLE,0);
pp1 = txline + posn; pp1 = txline + posn;
skipping to change at line 7668 skipping to change at line 7687
* add button to toolbar, using stock icon or custom icon * add button to toolbar, using stock icon or custom icon
* create a status bar and add to existing window * create a status bar and add to existing window
* display a message in the status bar * display a message in the status bar
argument definitions: argument definitions:
vbox GtkWidget * a vertical packing box (in a window) vbox GtkWidget * a vertical packing box (in a window)
mbar GtkWidget * reference for menu bar mbar GtkWidget * reference for menu bar
popup GtkWidget * reference for popup menu popup GtkWidget * reference for popup menu
mitem GtkWidget * reference for menu item (in a menu bar) mitem GtkWidget * reference for menu item (in a menu bar)
msub GtkWidget * reference for submenu item (in a menu) msub GtkWidget * reference for submenu item (in a menu)
label cchar * menu or toolbar name or label label ch * menu or toolbar name or label
tbar GtkWidget * reference for toolbar tbar GtkWidget * reference for toolbar
tip cchar * tool button tool tip (popup text via mouse-over tip ch * tool button tool tip (popup text via mouse-over
) )
icon cchar * stock icon name or custom icon file name (see b icon ch * stock icon name or custom icon file name (see b
elow) elow)
func see below menu or tool button response function func see below menu or tool button response function
arg cchar * argument to response function arg ch * argument to response function
stbar int reference for status bar stbar int reference for status bar
message cchar * message to display in status bar message ch * message to display in status bar
The icon argument for the function add_toolbar_button() has two forms. The icon argument for the function add_toolbar_button() has two forms.
For a GTK stock item referenced with a macro like GTK_STOCK_OPEN, use the For a GTK stock item referenced with a macro like GTK_STOCK_OPEN, use the
corresponding text name, like "gtk-open". corresponding text name, like "gtk-open".
For a custom icon, use the icon's file name like "my-icon.png". For a custom icon, use the icon's file name like "my-icon.png".
The file is expected to be in get_zdatadir()/icons. The file is expected to be in get_zdatadir()/icons.
The icon file may be any size, and is resized for use on the toolbar. The icon file may be any size, and is resized for use on the toolbar.
If the file is not found, the stock icon "gtk-missing-image" is used If the file is not found, the stock icon "gtk-missing-image" is used
(".png" and ".jpg" files both work). (".png" and ".jpg" files both work).
For a button with no icon (text label only), use 0 or null for the icon argum ent. For a button with no icon (text label only), use 0 or null for the icon argum ent.
For a menu separator, use the menu name "separator". For a menu separator, use the menu name "separator".
For a toolbar separator, use the label "separator". For a toolbar separator, use the label "separator".
For a title menu (no response function), set the response function to null. For a title menu (no response function), set the response function to null.
The response function for both menus and toolbar buttons looks like this: The response function for both menus and toolbar buttons looks like this:
void func(GtkWidget *, cchar *) void func(GtkWidget *, ch *)
The following macro is also supplied to simplify the coding of response funct ions: The following macro is also supplied to simplify the coding of response funct ions:
G_SIGNAL(window,event,func,arg) which expands to: G_SIGNAL(window,event,func,arg) which expands to:
g_signal_connect(G_OBJECT(window),event,G_CALLBACK(func),(void *) arg) g_signal_connect(G_OBJECT(window),event,G_CALLBACK(func),(void *) arg)
******************************************************************************** */ ******************************************************************************** */
// create menu bar and add to vertical packing box // create menu bar and add to vertical packing box
GtkWidget * create_menubar(GtkWidget *vbox) GtkWidget * create_menubar(GtkWidget *vbox)
{ {
GtkWidget *wmbar; GtkWidget *wmbar;
wmbar = gtk_menu_bar_new(); wmbar = gtk_menu_bar_new();
gtk_box_pack_start(GTK_BOX(vbox),wmbar,0,0,0); gtk_box_pack_start(GTK_BOX(vbox),wmbar,0,0,0);
return wmbar; return wmbar;
} }
// add menu item to menu bar, with optional response function // add menu item to menu bar, with optional response function
GtkWidget * add_menubar_item(GtkWidget *wmbar, cchar *mname, cbFunc func) GtkWidget * add_menubar_item(GtkWidget *wmbar, ch *mname, cbFunc func)
{ {
GtkWidget *wmitem; GtkWidget *wmitem;
wmitem = gtk_menu_item_new_with_label(mname); wmitem = gtk_menu_item_new_with_label(mname);
gtk_menu_shell_append(GTK_MENU_SHELL(wmbar),wmitem); gtk_menu_shell_append(GTK_MENU_SHELL(wmbar),wmitem);
if (func) G_SIGNAL(wmitem,"activate",func,mname); if (func) G_SIGNAL(wmitem,"activate",func,mname);
return wmitem; return wmitem;
} }
// add submenu item to menu item, with optional response function // add submenu item to menu item, with optional response function
GtkWidget * add_submenu_item(GtkWidget *wmitem, cchar *mlab, cbFunc func, cchar *mtip) GtkWidget * add_submenu_item(GtkWidget *wmitem, ch *mlab, cbFunc func, ch *mtip)
{ {
GtkWidget *wmsub, *wmsubitem; GtkWidget *wmsub, *wmsubitem;
wmsub = gtk_menu_item_get_submenu(GTK_MENU_ITEM(wmitem)); // add submenu if not already wmsub = gtk_menu_item_get_submenu(GTK_MENU_ITEM(wmitem)); // add submenu if not already
if (wmsub == null) { if (wmsub == null) {
wmsub = gtk_menu_new(); wmsub = gtk_menu_new();
gtk_menu_item_set_submenu(GTK_MENU_ITEM(wmitem),wmsub); gtk_menu_item_set_submenu(GTK_MENU_ITEM(wmitem),wmsub);
} }
if (strmatch(mlab,"separator")) if (strmatch(mlab,"separator"))
skipping to change at line 7768 skipping to change at line 7787
wtbar = gtk_toolbar_new(); wtbar = gtk_toolbar_new();
gtk_box_pack_start(GTK_BOX(vbox),wtbar,0,0,0); gtk_box_pack_start(GTK_BOX(vbox),wtbar,0,0,0);
tbIconSize = iconsize; tbIconSize = iconsize;
return wtbar; return wtbar;
} }
// add toolbar button with label and icon ("iconfile.png") and tool tip // add toolbar button with label and icon ("iconfile.png") and tool tip
// at least one of label and icon should be present // at least one of label and icon should be present
GtkWidget * add_toolbar_button(GtkWidget *wtbar, cchar *blab, cchar *btip, cchar *icon, cbFunc func) GtkWidget * add_toolbar_button(GtkWidget *wtbar, ch *blab, ch *btip, ch *icon, c bFunc func)
{ {
GtkToolItem *tbutton; GtkToolItem *tbutton;
GError *gerror = 0; GError *gerror = 0;
PIXBUF *pixbuf; PIXBUF *pixbuf;
GtkWidget *wicon = 0; GtkWidget *wicon = 0;
char iconpath[300], *pp; ch iconpath[300], *pp;
STATB statB; STATB statB;
int err, cc; int err, cc;
if (blab && strmatch(blab,"separator")) { if (blab && strmatch(blab,"separator")) {
tbutton = gtk_separator_tool_item_new(); tbutton = gtk_separator_tool_item_new();
gtk_toolbar_insert(GTK_TOOLBAR(wtbar),GTK_TOOL_ITEM(tbutton),-1); gtk_toolbar_insert(GTK_TOOLBAR(wtbar),GTK_TOOL_ITEM(tbutton),-1);
return (GtkWidget *) tbutton; return (GtkWidget *) tbutton;
} }
if (icon && *icon) { // get icon pixbuf if (icon && *icon) { // get icon pixbuf
skipping to change at line 7825 skipping to change at line 7844
GtkWidget *stbar; GtkWidget *stbar;
stbar = gtk_statusbar_new(); stbar = gtk_statusbar_new();
gtk_box_pack_start(GTK_BOX(pbox),stbar,0,0,0); gtk_box_pack_start(GTK_BOX(pbox),stbar,0,0,0);
gtk_widget_show(stbar); gtk_widget_show(stbar);
return stbar; return stbar;
} }
// display message in status bar // display message in status bar
int stbar_message(GtkWidget *wstbar, cchar *message) int stbar_message(GtkWidget *wstbar, ch *message)
{ {
static int ctx = -1; static int ctx = -1;
if (ctx == -1) if (ctx == -1)
ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(wstbar),"all"); ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(wstbar),"all");
gtk_statusbar_pop(GTK_STATUSBAR(wstbar),ctx); gtk_statusbar_pop(GTK_STATUSBAR(wstbar),ctx);
gtk_statusbar_push(GTK_STATUSBAR(wstbar),ctx,message); gtk_statusbar_push(GTK_STATUSBAR(wstbar),ctx,message);
return 0; return 0;
} }
/******************************************************************************* * /******************************************************************************* *
Popup Menu Popup Menu
GtkWidget *popup, *mitem GtkWidget *popup, *mitem
cchar *label, *arg, *tip ch *label, *arg, *tip
void func(GtkWidget *, cchar *arg) void func(GtkWidget *, ch *arg)
popup = create_popmenu() create a popup menu popup = create_popmenu() create a popup menu
mitem = add_popmenu_item(popup, label, func, arg, tip) add menu item to po pup menu mitem = add_popmenu_item(popup, label, func, arg, tip) add menu item to po pup menu
popup_menu(GtkWidget *parent, popup) popup the menu at m ouse position popup_menu(GtkWidget *parent, popup) popup the menu at m ouse position
Call 'create_popmenu' and then 'add_popmenu_item' for each item in the menu. Call 'create_popmenu' and then 'add_popmenu_item' for each item in the menu.
'label' is the menu name, 'func' the response function, 'arg' an argument 'label' is the menu name, 'func' the response function, 'arg' an argument
for 'func', and 'tip' is a tool-tip. 'arg' and 'tip' may be null. for 'func', and 'tip' is a tool-tip. 'arg' and 'tip' may be null.
A call to 'popup_menu' will show all menu entries at the mouse position. A call to 'popup_menu' will show all menu entries at the mouse position.
Clicking an entry will call the respective response function. Clicking an entry will call the respective response function.
Hovering on the entry will show the tool-tip. Hovering on the entry will show the tool-tip.
The response function looks like this: The response function looks like this:
void func(GtkWidget *, cchar *menu) void func(GtkWidget *, ch *menu)
***/ ***/
// create a popup menu // create a popup menu
GtkWidget * create_popmenu() GtkWidget * create_popmenu()
{ {
int popmenu_event(GtkWidget *, GdkEvent *); int popmenu_event(GtkWidget *, GdkEvent *);
GtkWidget *popmenu; GtkWidget *popmenu;
skipping to change at line 7885 skipping to change at line 7904
int popmenu_event(GtkWidget *popmenu, GdkEvent *event) int popmenu_event(GtkWidget *popmenu, GdkEvent *event)
{ {
if (((GdkEventButton *) event)->button != 1) // if not left mouse, kill menu if (((GdkEventButton *) event)->button != 1) // if not left mouse, kill menu
gtk_menu_popdown(GTK_MENU(popmenu)); gtk_menu_popdown(GTK_MENU(popmenu));
return 0; return 0;
} }
// add a menu item to a popup menu // add a menu item to a popup menu
GtkWidget * add_popmenu_item(GtkWidget *popmenu, cchar *mname, cbFunc func, ccha r *arg, cchar *mtip) GtkWidget * add_popmenu_item(GtkWidget *popmenu, ch *mname, cbFunc func, ch *arg , ch *mtip)
{ {
void popmenu_item_select(GtkWidget *, cchar *mtip); void popmenu_item_select(GtkWidget *, ch *mtip);
GtkWidget *widget; GtkWidget *widget;
widget = gtk_menu_item_new_with_label(mname); widget = gtk_menu_item_new_with_label(mname);
gtk_menu_shell_append(GTK_MENU_SHELL(popmenu),widget); gtk_menu_shell_append(GTK_MENU_SHELL(popmenu),widget);
if (func) { if (func) {
if (arg) G_SIGNAL(widget,"activate",func,arg); // call func with arg if (arg) G_SIGNAL(widget,"activate",func,arg); // call func with arg
else G_SIGNAL(widget,"activate",func,mname); // call func with menu name else G_SIGNAL(widget,"activate",func,mname); // call func with menu name
} }
skipping to change at line 7909 skipping to change at line 7928
if (mtip) { if (mtip) {
G_SIGNAL(widget,"select",popmenu_item_select,mtip); G_SIGNAL(widget,"select",popmenu_item_select,mtip);
G_SIGNAL(widget,"deselect",popmenu_item_select,0); G_SIGNAL(widget,"deselect",popmenu_item_select,0);
} }
return widget; return widget;
} }
// show popup tip for selected menu item // show popup tip for selected menu item
void popmenu_item_select(GtkWidget *wmitem, cchar *mtip) // convoluted code but it works void popmenu_item_select(GtkWidget *wmitem, ch *mtip) // convoluted code but it works
{ {
GdkWindow *window; GdkWindow *window;
int xp, yp, mx, my; int xp, yp, mx, my;
window = gtk_widget_get_window(wmitem); window = gtk_widget_get_window(wmitem);
gdk_window_get_origin(window,&xp,&yp); // menu screen origin gdk_window_get_origin(window,&xp,&yp); // menu screen origin
xp += gdk_window_get_width(window); // + width xp += gdk_window_get_width(window); // + width
gdk_device_get_position(zfuncs::mouse,0,&mx,&my); // mouse (x,y) screen position gdk_device_get_position(zfuncs::mouse,0,&mx,&my); // mouse (x,y) screen position
poptext_screen(mtip,xp,my,0,5); // popup px = menu + width, py = mouse poptext_screen(mtip,xp,my,0,5); // popup px = menu + width, py = mouse
return; return;
skipping to change at line 7939 skipping to change at line 7958
return; return;
} }
/******************************************************************************* * /******************************************************************************* *
Vertical Menu / Toolbar Vertical Menu / Toolbar
Build a custom vertical menu and/or toolbar in a vertical packing box Build a custom vertical menu and/or toolbar in a vertical packing box
Vmenu *vbm; Vmenu *vbm;
cchar *name, *icon, *desc, *arg; ch *name, *icon, *desc, *arg;
int iww, ihh; int iww, ihh;
void func(GtkWidget *, cchar *name); void func(GtkWidget *, ch *name);
void RMfunc(GtkWidget *, cchar *name); void RMfunc(GtkWidget *, ch *name);
vbm = Vmenu_new(GtkWidget *vbox, float fgRGB[3], float bgRGB[3]); // create base menu vbm = Vmenu_new(GtkWidget *vbox, float fgRGB[3], float bgRGB[3]); // create base menu
Vmenu_add(vbm, name, icon, iww, ihh, desc, func, arg); // add left-mouse menu function Vmenu_add(vbm, name, icon, iww, ihh, desc, func, arg); // add left-mouse menu function
Vmenu_add_setupfunc(vbm, me, func); // add opt. setup function Vmenu_add_setupfunc(vbm, me, func); // add opt. setup function
Vmenu_add_RMfunc(vbm, me, func); // add right-mouse menu function Vmenu_add_RMfunc(vbm, me, func); // add right-mouse menu function
Vmenu_block(int flag) 1 to block Vmenu, 0 to unblock Vmenu_block(int flag) 1 to block Vmenu, 0 to unblock
skipping to change at line 7972 skipping to change at line 7991
desc optional tool tip if mouse is hovered over displayed menu desc optional tool tip if mouse is hovered over displayed menu
When 'name/icon' is clicked, 'func' is called with 'arg'. When 'name/icon' is clicked, 'func' is called with 'arg'.
If 'arg' is null, 'name' is used instead. If 'arg' is null, 'name' is used instead.
To create a menu entry that is a popup menu with multiple entries, do as foll ows: To create a menu entry that is a popup menu with multiple entries, do as foll ows:
popup = create_popmenu(); popup = create_popmenu();
add_popup_menu_item(popup ...); see create_popmenu() add_popup_menu_item(popup ...); see create_popmenu()
add_popup_menu_item(popup ...); add_popup_menu_item(popup ...);
... ...
Vmenu_add(vbm, name, icon, ww, hh, desc, create_popmenu, (cchar *) popup ); Vmenu_add(vbm, name, icon, ww, hh, desc, create_popmenu, (ch *) popup);
i.e. use create_popmenu() as the response function and use the previously i.e. use create_popmenu() as the response function and use the previously
created menu 'popup' as the argument (cast to cchar *). created menu 'popup' as the argument (cast to ch *).
***/ ***/
namespace Vmenunames namespace Vmenunames
{ {
#define margin 5 // margins for menu text #define margin 5 // margins for menu text
PangoFontDescription *pfont1, *pfont2; PangoFontDescription *pfont1, *pfont2;
PangoAttrList *pattrlist; PangoAttrList *pattrlist;
PangoAttribute *pbackground; PangoAttribute *pbackground;
skipping to change at line 8002 skipping to change at line 8021
} }
// create Vmenu // create Vmenu
Vmenu *Vmenu_new(GtkWidget *vbox, float fgRGB[3], float bgRGB[3]) Vmenu *Vmenu_new(GtkWidget *vbox, float fgRGB[3], float bgRGB[3])
{ {
using namespace Vmenunames; using namespace Vmenunames;
int cc, ww, hh; int cc, ww, hh;
int K64 = 65536; int K64 = 65536;
char *menufont1, *menufont2; ch *menufont1, *menufont2;
PangoLayout *playout; PangoLayout *playout;
cc = sizeof(Vmenu); cc = sizeof(Vmenu);
Vmenu *vbm = (Vmenu *) zmalloc(cc,"Vmenu"); Vmenu *vbm = (Vmenu *) zmalloc(cc,"Vmenu");
memset(vbm,0,cc); memset(vbm,0,cc);
vbm->fgRGB[0] = fgRGB[0]; // background color, RGB 0-1.0 vbm->fgRGB[0] = fgRGB[0]; // background color, RGB 0-1.0
vbm->fgRGB[1] = fgRGB[1]; vbm->fgRGB[1] = fgRGB[1];
vbm->fgRGB[2] = fgRGB[2]; vbm->fgRGB[2] = fgRGB[2];
vbm->bgRGB[0] = bgRGB[0]; // background color, RGB 0-1.0 vbm->bgRGB[0] = bgRGB[0]; // background color, RGB 0-1.0
vbm->bgRGB[1] = bgRGB[1]; vbm->bgRGB[1] = bgRGB[1];
skipping to change at line 8052 skipping to change at line 8071
G_SIGNAL(vbm->layout,"button-release-event",mouse_event,vbm); G_SIGNAL(vbm->layout,"button-release-event",mouse_event,vbm);
G_SIGNAL(vbm->layout,"motion-notify-event",mouse_event,vbm); G_SIGNAL(vbm->layout,"motion-notify-event",mouse_event,vbm);
G_SIGNAL(vbm->layout,"leave-notify-event",mouse_event,vbm); G_SIGNAL(vbm->layout,"leave-notify-event",mouse_event,vbm);
G_SIGNAL(vbm->layout,"draw",wpaint,vbm); G_SIGNAL(vbm->layout,"draw",wpaint,vbm);
return vbm; return vbm;
} }
// add Vmenu entry with name, icon, description, menu function (left click) // add Vmenu entry with name, icon, description, menu function (left click)
void Vmenu_add(Vmenu *vbm, cchar *name, cchar *icon, int iconww, int iconhh, cch ar *desc, cbFunc func, cchar *arg) void Vmenu_add(Vmenu *vbm, ch *name, ch *icon, int iconww, int iconhh, ch *desc, cbFunc func, ch *arg)
{ {
using namespace Vmenunames; using namespace Vmenunames;
int me, cc, xpos, ww, hh; int me, cc, xpos, ww, hh;
char iconpath[200], *mdesc, *name__; ch iconpath[200], *mdesc, *name__;
cchar *blanks = " "; ch *blanks = " ";
// 20 blanks // 20 blanks
PIXBUF *pixbuf; PIXBUF *pixbuf;
GError *gerror = 0; GError *gerror = 0;
PangoLayout *playout; PangoLayout *playout;
PangoFontDescription *pfont; PangoFontDescription *pfont;
if (! name && ! icon) return; if (! name && ! icon) return;
me = vbm->mcount++; // track no. menu entries me = vbm->mcount++; // track no. menu entries
if (name) vbm->menu[me].name = zstrdup(name,"Vmenu"); // create new menu entry from caller data if (name) vbm->menu[me].name = zstrdup(name,"Vmenu"); // create new menu entry from caller data
if (icon) { if (icon) {
vbm->menu[me].icon = zstrdup(icon,"Vmenu"); vbm->menu[me].icon = zstrdup(icon,"Vmenu");
vbm->menu[me].iconww = iconww; vbm->menu[me].iconww = iconww;
vbm->menu[me].iconhh = iconhh; vbm->menu[me].iconhh = iconhh;
} }
if (desc) { // pad description with blanks for looks if (desc) { // pad description with blanks for looks
cc = strlen(desc); cc = strlen(desc);
mdesc = (char *) zmalloc(cc+3,"Vmenu"); mdesc = (ch *) zmalloc(cc+3,"Vmenu");
mdesc[0] = ' '; mdesc[0] = ' ';
strcpy(mdesc+1,desc); strcpy(mdesc+1,desc);
strcpy(mdesc+cc+1," "); strcpy(mdesc+cc+1," ");
vbm->menu[me].desc = mdesc; vbm->menu[me].desc = mdesc;
} }
vbm->menu[me].LMfunc = func; // left-mouse menu function vbm->menu[me].LMfunc = func; // left-mouse menu function
vbm->menu[me].arg = name; // argument is menu name or arg if avail. vbm->menu[me].arg = name; // argument is menu name or arg if avail.
if (arg) vbm->menu[me].arg = arg; if (arg) vbm->menu[me].arg = arg;
skipping to change at line 8161 skipping to change at line 8180
if (xpos + ww > vbm->xmax) vbm->xmax = xpos + ww; // keep track of max. layout width if (xpos + ww > vbm->xmax) vbm->xmax = xpos + ww; // keep track of max. layout width
} }
gtk_widget_set_size_request(vbm->layout,vbm->xmax+margin,0); // add right margin to layout width gtk_widget_set_size_request(vbm->layout,vbm->xmax+margin,0); // add right margin to layout width
return; return;
} }
// add opt. setup function to existing menu entry // add opt. setup function to existing menu entry
void Vmenu_add_setup(Vmenu *vbm, int me, cbFunc func, cchar *arg) void Vmenu_add_setup(Vmenu *vbm, int me, cbFunc func, ch *arg)
{ {
if (me > vbm->mcount-1) zappcrash("Vmenu_add_RMfunc() bad me: %d",me); if (me > vbm->mcount-1) zappcrash("Vmenu_add_RMfunc() bad me: %d",me);
vbm->menu[me].setupfunc = func; vbm->menu[me].setupfunc = func;
vbm->menu[me].setuparg = arg; vbm->menu[me].setuparg = arg;
return; return;
} }
// add alternate function for right-mouse click // add alternate function for right-mouse click
void Vmenu_add_RMfunc(Vmenu *vbm, int me, cbFunc func, cchar *arg) void Vmenu_add_RMfunc(Vmenu *vbm, int me, cbFunc func, ch *arg)
{ {
if (me > vbm->mcount-1) zappcrash("Vmenu_add_RMfunc() bad me: %d",me); if (me > vbm->mcount-1) zappcrash("Vmenu_add_RMfunc() bad me: %d",me);
vbm->menu[me].RMfunc = func; vbm->menu[me].RMfunc = func;
vbm->menu[me].RMarg = arg; vbm->menu[me].RMarg = arg;
return; return;
} }
// block or unblock menu // block or unblock menu
void Vmenu_block(int flag) void Vmenu_block(int flag)
skipping to change at line 8214 skipping to change at line 8233
// draw menu icon and text into layout // draw menu icon and text into layout
void Vmenunames::paint_menu(cairo_t *cr, Vmenu *vbm, int me, int hilite) void Vmenunames::paint_menu(cairo_t *cr, Vmenu *vbm, int me, int hilite)
{ {
using namespace Vmenunames; using namespace Vmenunames;
PIXBUF *pixbuf; PIXBUF *pixbuf;
PangoLayout *playout; PangoLayout *playout;
int xpos, ypos; int xpos, ypos;
int iconww, iconhh; int iconww, iconhh;
cchar *name; ch *name;
pixbuf = vbm->menu[me].pixbuf; // icon pixbuf = vbm->menu[me].pixbuf; // icon
if (pixbuf) { // draw menu icon at menu position if (pixbuf) { // draw menu icon at menu position
xpos = vbm->menu[me].iconx; xpos = vbm->menu[me].iconx;
ypos = vbm->menu[me].icony; ypos = vbm->menu[me].icony;
iconww = vbm->menu[me].iconww; iconww = vbm->menu[me].iconww;
iconhh = vbm->menu[me].iconhh; iconhh = vbm->menu[me].iconhh;
if (! hilite) { // erase box around icon if (! hilite) { // erase box around icon
cairo_set_source_rgb(cr,vbm->bgRGB[0],vbm->bgRGB[1],vbm->bgRGB[2]); // background cairo_set_source_rgb(cr,vbm->bgRGB[0],vbm->bgRGB[1],vbm->bgRGB[2]); // background
skipping to change at line 8262 skipping to change at line 8281
return; return;
} }
// mouse event function - capture buttons and drag movements // mouse event function - capture buttons and drag movements
void Vmenunames::mouse_event(GtkWidget *widget, GdkEventButton *event, Vmenu *vb m) void Vmenunames::mouse_event(GtkWidget *widget, GdkEventButton *event, Vmenu *vb m)
{ {
using namespace Vmenunames; using namespace Vmenunames;
GdkWindow *gdkwin; GdkWindow *gdkwin;
cchar *desc; ch *desc;
int me, mpx, mpy, button, ww, ylo, yhi; int me, mpx, mpy, button, ww, ylo, yhi;
static int me0 = -1, Fmyclick = 0, winww = 0; static int me0 = -1, Fmyclick = 0, winww = 0;
static draw_context_t context; static draw_context_t context;
static GtkWidget *pwidget = 0; static GtkWidget *pwidget = 0;
static cairo_t *cr = 0; static cairo_t *cr = 0;
if (widget != pwidget) { // widget changed if (widget != pwidget) { // widget changed
if (pwidget) draw_context_destroy(context); if (pwidget) draw_context_destroy(context);
gdkwin = gtk_layout_get_bin_window(GTK_LAYOUT(widget)); gdkwin = gtk_layout_get_bin_window(GTK_LAYOUT(widget));
skipping to change at line 8811 skipping to change at line 8830
y3 = y1 + (y2 - y1) * (x2 - x1); y3 = y1 + (y2 - y1) * (x2 - x1);
return y3; return y3;
} }
// load curve data from a file // load curve data from a file
// returns 0 if success, sd is initialized from file data // returns 0 if success, sd is initialized from file data
// returns 1 if fail (invalid file data), sd not modified // returns 1 if fail (invalid file data), sd not modified
int splcurve_load(spldat *sd, FILE *fid) int splcurve_load(spldat *sd, FILE *fid)
{ {
char *pp, buff[300]; ch *pp, buff[300];
int nn, ii, jj, err, myfid = 0; int nn, ii, jj, err, myfid = 0;
int Nspc, fact[10], vert[10], nap[10]; int Nspc, fact[10], vert[10], nap[10];
float apx[10][50], apy[10][50]; float apx[10][50], apy[10][50];
pp = fgets_trim(buff,300,fid,1); pp = fgets_trim(buff,300,fid,1);
if (! pp) goto fail; if (! pp) goto fail;
nn = sscanf(pp,"%d",&Nspc); // no. of curves nn = sscanf(pp,"%d",&Nspc); // no. of curves
if (nn != 1) goto fail; if (nn != 1) goto fail;
if (Nspc < 1 || Nspc > 10) goto fail; if (Nspc < 1 || Nspc > 10) goto fail;
if (Nspc != sd->Nspc) goto fail; if (Nspc != sd->Nspc) goto fail;
skipping to change at line 8837 skipping to change at line 8856
nn = sscanf(pp,"%d %d %d",&fact[ii],&vert[ii],&nap[ii]); // active flag, vert flag, anchors nn = sscanf(pp,"%d %d %d",&fact[ii],&vert[ii],&nap[ii]); // active flag, vert flag, anchors
if (nn != 3) goto fail; if (nn != 3) goto fail;
if (fact[ii] < 0 || fact[ii] > 1) goto fail; if (fact[ii] < 0 || fact[ii] > 1) goto fail;
if (vert[ii] < 0 || vert[ii] > 1) goto fail; if (vert[ii] < 0 || vert[ii] > 1) goto fail;
if (nap[ii] < 2 || nap[ii] > 50) goto fail; if (nap[ii] < 2 || nap[ii] > 50) goto fail;
pp = fgets_trim(buff,300,fid,1); // anchor points: nnn/nnn nnn/nnn ... pp = fgets_trim(buff,300,fid,1); // anchor points: nnn/nnn nnn/nnn ...
for (jj = 0; jj < nap[ii]; jj++) // anchor point values for (jj = 0; jj < nap[ii]; jj++) // anchor point values
{ {
pp = (char *) substring(buff,"/ ",2*jj+1); pp = (ch *) substring(buff,"/ ",2*jj+1);
if (! pp) goto fail; if (! pp) goto fail;
err = convSF(pp,apx[ii][jj],0,1); err = convSF(pp,apx[ii][jj],0,1);
if (err) goto fail; if (err) goto fail;
pp = (char *) substring(buff,"/ ",2*jj+2); pp = (ch *) substring(buff,"/ ",2*jj+2);
if (! pp) goto fail; if (! pp) goto fail;
err = convSF(pp,apy[ii][jj],0,1); err = convSF(pp,apy[ii][jj],0,1);
if (err) goto fail; if (err) goto fail;
} }
} }
if (myfid) fclose(fid); if (myfid) fclose(fid);
sd->Nspc = Nspc; // copy curve data to caller's arg sd->Nspc = Nspc; // copy curve data to caller's arg
skipping to change at line 8931 skipping to change at line 8950
// The title and parent arguments may be null. // The title and parent arguments may be null.
// optional arguments: up to zdmaxbutts button labels followed by null // optional arguments: up to zdmaxbutts button labels followed by null
// returned dialog status: +N = button N (1 to zdmaxbutts) // returned dialog status: +N = button N (1 to zdmaxbutts)
// <0 = [x] button or other GTK destroy action // <0 = [x] button or other GTK destroy action
// completion buttons are also events like other widgets // completion buttons are also events like other widgets
// all dialogs run parallel, use zdialog_wait() if needed // all dialogs run parallel, use zdialog_wait() if needed
// The status returned by zdialog_wait() corresponds to the button // The status returned by zdialog_wait() corresponds to the button
// (1-10) used to end the dialog. Status < 0 indicates the [x] button // (1-10) used to end the dialog. Status < 0 indicates the [x] button
// was used or the dialog was killed by the program itself. // was used or the dialog was killed by the program itself.
zdialog * zdialog_new(cchar *title, GtkWidget *parent, ...) // parent added zdialog * zdialog_new(ch *title, GtkWidget *parent, ...) // parent added
{ {
zdialog *zd; zdialog *zd;
GtkWidget *dialog, *hbox, *vbox, *butt, *hsep; GtkWidget *dialog, *hbox, *vbox, *butt, *hsep;
cchar *bulab[zdmaxbutts]; ch *bulab[zdmaxbutts];
int cc, ii, nbu; int cc, ii, nbu;
va_list arglist; va_list arglist;
static int uniqueID = 1; static int uniqueID = 1;
if (! main_thread()) zappcrash("zdialog_new() called from thread"); if (! main_thread()) zappcrash("zdialog_new() called from thread");
va_start(arglist,parent); va_start(arglist,parent);
for (nbu = 0; nbu < zdmaxbutts; nbu++) { // get completion buttons for (nbu = 0; nbu < zdmaxbutts; nbu++) { // get completion buttons
bulab[nbu] = va_arg(arglist, cchar *); bulab[nbu] = va_arg(arglist, ch *);
if (! bulab[nbu] || bulab[nbu] == (cchar *) 0x100000000) break; if (! bulab[nbu] || bulab[nbu] == (ch *) 0x100000000) break;
// ARM bug // ARM bug
} }
va_end(arglist); va_end(arglist);
if (! title) title = ""; if (! title) title = "";
dialog = gtk_window_new(GTK_WINDOW_TOPLEVEL); dialog = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW(dialog),title); gtk_window_set_title(GTK_WINDOW(dialog),title);
vbox = gtk_box_new(VERTICAL,0); // vertical packing box vbox = gtk_box_new(VERTICAL,0); // vertical packing box
gtk_container_add(GTK_CONTAINER(dialog),vbox); // add to main window gtk_container_add(GTK_CONTAINER(dialog),vbox); // add to main window
gtk_window_set_default_size(GTK_WINDOW(dialog),10,10); // stop auto width of 150 pixels gtk_window_set_default_size(GTK_WINDOW(dialog),10,10); // stop auto width of 150 pixels
skipping to change at line 9015 skipping to change at line 9034
zd->widget[0].pname = 0; // no parent zd->widget[0].pname = 0; // no parent
zd->widget[0].data = zstrdup(title,"zdialog"); zd->widget[0].data = zstrdup(title,"zdialog");
zd->widget[0].widget = dialog; zd->widget[0].widget = dialog;
zd->widget[1].type = 0; // eof - no contained widgets yet zd->widget[1].type = 0; // eof - no contained widgets yet
return zd; return zd;
} }
// change a zdialog title // change a zdialog title
void zdialog_set_title(zdialog *zd, cchar *title) void zdialog_set_title(zdialog *zd, ch *title)
{ {
gtk_window_set_title(GTK_WINDOW(zd->widget[0].widget),title); gtk_window_set_title(GTK_WINDOW(zd->widget[0].widget),title);
return; return;
} }
// set a zdialog to be modal // set a zdialog to be modal
void zdialog_set_modal(zdialog *zd) void zdialog_set_modal(zdialog *zd)
{ {
GtkWidget *widget = zdialog_gtkwidget(zd,"dialog"); GtkWidget *widget = zdialog_gtkwidget(zd,"dialog");
skipping to change at line 9102 skipping to change at line 9121
void zdialog_can_focus(zdialog *zd, int Fcan) void zdialog_can_focus(zdialog *zd, int Fcan)
{ {
gtk_window_set_accept_focus(GTK_WINDOW(zd->dialog),Fcan); gtk_window_set_accept_focus(GTK_WINDOW(zd->dialog),Fcan);
return; return;
} }
// set focus on dialog window or window and named widget // set focus on dialog window or window and named widget
// (widget name may be null or missing) // (widget name may be null or missing)
// see also: gtk_window_activate_focus(GtkWindow *) // see also: gtk_window_activate_focus(GtkWindow *)
void zdialog_set_focus(zdialog *zd, cchar *wname) void zdialog_set_focus(zdialog *zd, ch *wname)
{ {
GtkWindow *window; GtkWindow *window;
GtkWidget *widget; GtkWidget *widget;
window = GTK_WINDOW(zd->dialog); window = GTK_WINDOW(zd->dialog);
if (wname) widget = zdialog_gtkwidget(zd,wname); if (wname) widget = zdialog_gtkwidget(zd,wname);
else widget = 0; else widget = 0;
if (wname) gtk_window_set_focus(window,widget); if (wname) gtk_window_set_focus(window,widget);
else gtk_window_activate_focus(window); else gtk_window_activate_focus(window);
skipping to change at line 9138 skipping to change at line 9157
// wrap allow text to wrap at right margin // wrap allow text to wrap at right margin
// //
// data can be a string ("initial widget data") or a number in string form ("1 2.345") // data can be a string ("initial widget data") or a number in string form ("1 2.345")
// data for togbutt / check / radio: use "0" or "1" for OFF or ON // data for togbutt / check / radio: use "0" or "1" for OFF or ON
// data for spin / zspin / hscale / vscale: use "min|max|step|value" (default: 0 | 100 | 1 | 50) // data for spin / zspin / hscale / vscale: use "min|max|step|value" (default: 0 | 100 | 1 | 50)
// data for colorbutt: use "rrr|ggg|bbb" with values 0-255 for each RGB color. // data for colorbutt: use "rrr|ggg|bbb" with values 0-255 for each RGB color.
// This format is used to initialize the control and read back when user selec ts a color. // This format is used to initialize the control and read back when user selec ts a color.
// Multiple radio buttons with same parent are a group: pressing one turns the others OFF. // Multiple radio buttons with same parent are a group: pressing one turns the others OFF.
int zdialog_add_widget ( int zdialog_add_widget (
zdialog *zd, cchar *type, cchar *wname, cchar *pname, zdialog *zd, ch *type, ch *wname, ch *pname,
// mandatory args // mandatory args
cchar *data, int size, int homog, int expand, int space, int wrap) ch *data, int size, int homog, int expand, int space, int wrap)
// optional args (default = 0) // optional args (default = 0)
{ {
int textview_focus_in_event(GtkWidget *widget); // for popup_text insertion 22.15 int textview_focus_in_event(GtkWidget *widget); // for popup_text insertion 22.15
GtkWidget *widget = 0, *pwidget = 0, *fwidget = 0; GtkWidget *widget = 0, *pwidget = 0, *fwidget = 0;
GtkWidget *image, *vbox; GtkWidget *image, *vbox;
GtkTextBuffer *editBuff = 0; GtkTextBuffer *editBuff = 0;
PIXBUF *pixbuf = 0; PIXBUF *pixbuf = 0;
GdkRGBA gdkrgba; GdkRGBA gdkrgba;
GError *gerror = 0; GError *gerror = 0;
cchar *pp, *ptype = 0; ch *pp, *ptype = 0;
char vdata[30], iconpath[200]; ch vdata[30], iconpath[200];
double min, max, step, val; double min, max, step, val;
double f256 = 1.0 / 256.0; double f256 = 1.0 / 256.0;
int iiw, iip, kk, err; int iiw, iip, kk, err;
if (! zdialog_valid(zd)) zappcrash("zdialog invalid"); if (! zdialog_valid(zd)) zappcrash("zdialog invalid");
for (iiw = 1; zd->widget[iiw].type; iiw++); // find next avail. slot for (iiw = 1; zd->widget[iiw].type; iiw++); // find next avail. slot
if (iiw > zdmaxwidgets-2) zappcrash("too many widgets: %d",iiw); if (iiw > zdmaxwidgets-2) zappcrash("too many widgets: %d",iiw);
zd->widget[iiw].type = zstrdup(type,"zdialog"); // initz. widget struct zd->widget[iiw].type = zstrdup(type,"zdialog"); // initz. widget struct
skipping to change at line 9432 skipping to change at line 9451
data = 0; // data not further used data = 0; // data not further used
pixbuf = gdk_pixbuf_new_from_file_at_scale(iconpath,size,size,1,&gerror); pixbuf = gdk_pixbuf_new_from_file_at_scale(iconpath,size,size,1,&gerror);
if (pixbuf) { if (pixbuf) {
widget = gtk_image_new_from_pixbuf(pixbuf); widget = gtk_image_new_from_pixbuf(pixbuf);
g_object_unref(pixbuf); g_object_unref(pixbuf);
} }
else widget = gtk_image_new_from_icon_name("missing",GTK_ICON_SIZE_BUTTON) ; else widget = gtk_image_new_from_icon_name("missing",GTK_ICON_SIZE_BUTTON) ;
} }
if (strmatch(type,"image")) // image widget from pixbuf if (strmatch(type,"image")) // image widget from pixbuf
widget = gtk_image_new_from_pixbuf((GdkPixbuf *) data); // use (cchar *) pixbuf in call widget = gtk_image_new_from_pixbuf((GdkPixbuf *) data); // use (ch *) pixbuf in call
// all widget types come here // all widget types come here
zd->widget[iiw].widget = widget; // set widget in zdialog zd->widget[iiw].widget = widget; // set widget in zdialog
if (strmatchV(type,"zentry","zspin","zedit","text",0)) { // add frame around these widgets if (strmatchV(type,"zentry","zspin","zedit","text",0)) { // add frame around these widgets
if (! strmatch(ptype,"scrwin")) { // unless parent is scroll widget if (! strmatch(ptype,"scrwin")) { // unless parent is scroll widget
fwidget = gtk_frame_new(0); fwidget = gtk_frame_new(0);
gtk_frame_set_shadow_type(GTK_FRAME(fwidget),GTK_SHADOW_IN); gtk_frame_set_shadow_type(GTK_FRAME(fwidget),GTK_SHADOW_IN);
gtk_container_add(GTK_CONTAINER(fwidget),widget); gtk_container_add(GTK_CONTAINER(fwidget),widget);
skipping to change at line 9465 skipping to change at line 9484
gtk_box_pack_start(GTK_BOX(vbox),widget,expand,expand,space); gtk_box_pack_start(GTK_BOX(vbox),widget,expand,expand,space);
} }
if (data) zd->widget[iiw].data = zstrdup(data,"zdialog"); // widget memory if (data) zd->widget[iiw].data = zstrdup(data,"zdialog"); // widget memory
return 0; return 0;
} }
// add widget to existing zdialog - alternative form (clearer and easier code) // add widget to existing zdialog - alternative form (clearer and easier code)
// options: "size=nn | homog | expand | space=nn | wrap" (all optional, any or der) // options: "size=nn | homog | expand | space=nn | wrap" (all optional, any or der)
int zdialog_add_widget(zdialog *zd, cchar *type, cchar *wname, int zdialog_add_widget(zdialog *zd, ch *type, ch *wname,
cchar *parent, cchar *data, cchar *options) ch *parent, ch *data, ch *options)
{ {
int stat, size = 0, homog = 0, expand = 0, space = 0, wrap = 0, begin = 1; int stat, size = 0, homog = 0, expand = 0, space = 0, wrap = 0, begin = 1;
char pname[8]; ch pname[8];
double pval; double pval;
while (true) while (true)
{ {
stat = strParms(begin,options,pname,8,pval); stat = strParms(begin,options,pname,8,pval);
if (stat == -1) break; if (stat == -1) break;
if (stat == 1) zappcrash("bad zdialog options: %s",options); if (stat == 1) zappcrash("bad zdialog options: %s",options);
if (strmatch(pname,"size")) size = (int(pval)); if (strmatch(pname,"size")) size = (int(pval));
else if (strmatch(pname,"homog")) homog = 1; else if (strmatch(pname,"homog")) homog = 1;
else if (strmatch(pname,"expand")) expand = 1; else if (strmatch(pname,"expand")) expand = 1;
skipping to change at line 9491 skipping to change at line 9510
else if (strmatch(pname,"wrap")) wrap = 1; else if (strmatch(pname,"wrap")) wrap = 1;
else zappcrash("bad zdialog options: %s",options); else zappcrash("bad zdialog options: %s",options);
} }
stat = zdialog_add_widget(zd,type,wname,parent,data,size,homog,expand,space,w rap); stat = zdialog_add_widget(zd,type,wname,parent,data,size,homog,expand,space,w rap);
return stat; return stat;
} }
// return 1/0 if zdialog is valid/invalid // return 1/0 if zdialog is valid/invalid
int zdialog_valid(zdialog *zd, cchar *title) // title is optional int zdialog_valid(zdialog *zd, ch *title) // title is optional
{ {
int ok, ii; int ok, ii;
if (! zd) return 0; if (! zd) return 0;
for (ii = 0; ii < zdialog_count; ii++) // find in valid zdialog list for (ii = 0; ii < zdialog_count; ii++) // find in valid zdialog list
if (zd == zdialog_list[ii]) break; if (zd == zdialog_list[ii]) break;
if (ii == zdialog_count) { if (ii == zdialog_count) {
printf("*** zdialog not in valid list %s \n",title); Plog(0,"*** zdialog invalid %s \n",title); // 23.1
return 0; return 0;
} }
ok = 1; ok = 1;
if ((zd->sentinel1 & 0xFFFF0000) != zdsentinel) ok = 0; if ((zd->sentinel1 & 0xFFFF0000) != zdsentinel) ok = 0;
if (zd->sentinel2 != zd->sentinel1) ok = 0; if (zd->sentinel2 != zd->sentinel1) ok = 0;
if (! ok) { if (! ok) {
Plog(0,"zdialog sentinel invalid %s \n",title); Plog(0,"*** zdialog sentinel invalid %s \n",title);
return 0; return 0;
} }
if (title && ! strmatch(title,zd->title)) { if (title && ! strmatch(title,zd->title)) {
Plog(0,"zdialog title invalid %s \n",title); Plog(0,"*** zdialog title invalid %s \n",title);
return 0; return 0;
} }
return 1; return 1;
} }
// return 1/0 if zdialog is valid/invalid // return 1/0 if zdialog is valid/invalid
// silent version to use when zdialog is possibly destroyed // silent version to use when zdialog is possibly destroyed
int zdialog_valid2(zdialog *zd, cchar *title) int zdialog_valid2(zdialog *zd, ch *title)
{ {
int ok, ii; int ok, ii;
for (ii = 0; ii < zdialog_count; ii++) for (ii = 0; ii < zdialog_count; ii++)
if (zd == zdialog_list[ii]) break; if (zd == zdialog_list[ii]) break;
if (ii == zdialog_count) return 0; if (ii == zdialog_count) return 0;
ok = 1; ok = 1;
if ((zd->sentinel1 & 0xFFFF0000) != zdsentinel) ok = 0; if ((zd->sentinel1 & 0xFFFF0000) != zdsentinel) ok = 0;
if (zd->sentinel2 != zd->sentinel1) ok = 0; if (zd->sentinel2 != zd->sentinel1) ok = 0;
if (! ok) return 0; if (! ok) return 0;
if (title && ! strmatch(title,zd->title)) return 0; if (title && ! strmatch(title,zd->title)) return 0;
return 1; return 1;
} }
// find zdialog widget from zdialog and widget name // find zdialog widget from zdialog and widget name
int zdialog_find_widget(zdialog *zd, cchar *wname) int zdialog_find_widget(zdialog *zd, ch *wname)
{ {
if (! zdialog_valid(zd)) { if (! zdialog_valid(zd)) {
Plog(0,"invalid zdialog %p \n",zd); Plog(0,"invalid zdialog %p \n",zd);
return 0; return 0;
} }
for (int ii = 0; zd->widget[ii].type; ii++) for (int ii = 0; zd->widget[ii].type; ii++)
if (strmatch(zd->widget[ii].wname,wname)) return ii; if (strmatch(zd->widget[ii].wname,wname)) return ii;
Plog(0,"zdialog bad widget name: %s \n",wname); Plog(0,"zdialog bad widget name: %s \n",wname);
return 0; return 0;
} }
// get GTK widget from zdialog and widget name // get GTK widget from zdialog and widget name
GtkWidget * zdialog_gtkwidget(zdialog *zd, cchar *wname) GtkWidget * zdialog_gtkwidget(zdialog *zd, ch *wname)
{ {
if (strmatch(wname,"dialog")) return zd->widget[0].widget; if (strmatch(wname,"dialog")) return zd->widget[0].widget;
int ii = zdialog_find_widget(zd,wname); int ii = zdialog_find_widget(zd,wname);
if (ii) return zd->widget[ii].widget; if (ii) return zd->widget[ii].widget;
return 0; return 0;
} }
// set an "image" widget type from a GDK pixbuf // set an "image" widget type from a GDK pixbuf
// returns 0 if OK, else +N // returns 0 if OK, else +N
int zdialog_set_image(zdialog *zd, cchar *wname, GdkPixbuf *pixbuf) int zdialog_set_image(zdialog *zd, ch *wname, GdkPixbuf *pixbuf)
{ {
GtkWidget *widget; GtkWidget *widget;
int ii; int ii;
ii = zdialog_find_widget(zd,wname); ii = zdialog_find_widget(zd,wname);
if (! ii) return 2; if (! ii) return 2;
if (! strmatch(zd->widget[ii].type,"image")) return 3; if (! strmatch(zd->widget[ii].type,"image")) return 3;
widget = zd->widget[ii].widget; widget = zd->widget[ii].widget;
gtk_image_set_from_pixbuf(GTK_IMAGE(widget),pixbuf); gtk_image_set_from_pixbuf(GTK_IMAGE(widget),pixbuf);
return 0; return 0;
} }
// add a popup tool tip to a zdialog widget // add a popup tool tip to a zdialog widget
int zdialog_add_ttip(zdialog *zd, cchar *wname, cchar *ttip) int zdialog_add_ttip(zdialog *zd, ch *wname, ch *ttip)
{ {
GtkWidget *widget; GtkWidget *widget;
int ii; int ii;
if (! zdialog_valid(zd)) return 0; if (! zdialog_valid(zd)) return 0;
for (ii = 0; zd->compwidget[ii]; ii++) // search completion buttons for (ii = 0; zd->compwidget[ii]; ii++) // search completion buttons
if (strmatch(zd->compbutton[ii],wname)) { // for matching wname if (strmatch(zd->compbutton[ii],wname)) { // for matching wname
gtk_widget_set_tooltip_text(zd->compwidget[ii],ttip); gtk_widget_set_tooltip_text(zd->compwidget[ii],ttip);
return 1; return 1;
skipping to change at line 9608 skipping to change at line 9627
widget = zdialog_gtkwidget(zd,wname); // search zdialog widgets widget = zdialog_gtkwidget(zd,wname); // search zdialog widgets
if (! widget) return 0; if (! widget) return 0;
gtk_widget_set_tooltip_text(widget,ttip); gtk_widget_set_tooltip_text(widget,ttip);
return 1; return 1;
} }
// set a common group for a set of radio buttons // set a common group for a set of radio buttons
// (GTK, this does not work) // (GTK, this does not work)
int zdialog_set_group(zdialog *zd, cchar *radio1, ...) int zdialog_set_group(zdialog *zd, ch *radio1, ...)
{ {
va_list arglist; va_list arglist;
cchar *radio2; ch *radio2;
GtkWidget *gwidget, *widget; GtkWidget *gwidget, *widget;
GSList *glist; GSList *glist;
gwidget = zdialog_gtkwidget(zd,radio1); gwidget = zdialog_gtkwidget(zd,radio1);
glist = gtk_radio_button_get_group(GTK_RADIO_BUTTON(gwidget)); glist = gtk_radio_button_get_group(GTK_RADIO_BUTTON(gwidget));
if (! glist) zappcrash("no radio button group"); if (! glist) zappcrash("no radio button group");
va_start(arglist,radio1); va_start(arglist,radio1);
while (true) while (true)
{ {
radio2 = va_arg(arglist,cchar *); radio2 = va_arg(arglist,ch *);
if (! radio2 || radio2 == (cchar *) 0x100000000) break; if (! radio2 || radio2 == (ch *) 0x100000000) break;
// ARM bug // ARM bug
widget = zdialog_gtkwidget(zd,radio2); widget = zdialog_gtkwidget(zd,radio2);
gtk_radio_button_set_group(GTK_RADIO_BUTTON(widget),glist); gtk_radio_button_set_group(GTK_RADIO_BUTTON(widget),glist);
} }
va_end(arglist); va_end(arglist);
return 0; return 0;
} }
// resize dialog to a size greater than initial size // resize dialog to a size greater than initial size
skipping to change at line 9650 skipping to change at line 9669
if (! width) width = 10; // stop spurious GTK warnings if (! width) width = 10; // stop spurious GTK warnings
if (! height) height = 10; if (! height) height = 10;
GtkWidget *window = zd->widget[0].widget; GtkWidget *window = zd->widget[0].widget;
gtk_window_set_default_size(GTK_WINDOW(window),width,height); gtk_window_set_default_size(GTK_WINDOW(window),width,height);
return 1; return 1;
} }
// put data into a zdialog widget // put data into a zdialog widget
// private function // private function
int zdialog_put_data(zdialog *zd, cchar *wname, cchar *data) int zdialog_put_data(zdialog *zd, ch *wname, ch *data)
{ {
GtkWidget *widget; GtkWidget *widget;
GtkTextBuffer *textBuff; GtkTextBuffer *textBuff;
GdkRGBA gdkrgba; GdkRGBA gdkrgba;
int iiw, nn, kk, err, Nsteps; int iiw, nn, kk, err, Nsteps;
cchar *type, *pp; ch *type, *pp;
char *wdata, sdata[32]; ch *wdata, sdata[32];
double dval; double dval;
double f256 = 1.0 / 256.0; double f256 = 1.0 / 256.0;
double lval, hval, nval, F, F2; double lval, hval, nval, F, F2;
double fdata, lolim, hilim, step; // double double fdata, lolim, hilim, step; // double
iiw = zdialog_find_widget(zd,wname); iiw = zdialog_find_widget(zd,wname);
if (! iiw) return 0; if (! iiw) return 0;
type = zd->widget[iiw].type; type = zd->widget[iiw].type;
widget = zd->widget[iiw].widget; widget = zd->widget[iiw].widget;
skipping to change at line 9798 skipping to change at line 9817
} }
retx: retx:
zd->disabled--; // re-enable dialog zd->disabled--; // re-enable dialog
return iiw; return iiw;
} }
// get data from a dialog widget based on its name // get data from a dialog widget based on its name
// private function // private function
cchar * zdialog_get_data(zdialog *zd, cchar *wname) ch * zdialog_get_data(zdialog *zd, ch *wname)
{ {
int ii = zdialog_find_widget(zd,wname); int ii = zdialog_find_widget(zd,wname);
if (ii) return zd->widget[ii].data; if (ii) return zd->widget[ii].data;
return 0; return 0;
} }
// set new limits for a numeric data entry widget (spin, zspin, hscale, vscale) // set new limits for a numeric data entry widget (spin, zspin, hscale, vscale)
int zdialog_set_limits(zdialog *zd, cchar *wname, double min, double max) int zdialog_set_limits(zdialog *zd, ch *wname, double min, double max)
{ {
GtkWidget *widget; GtkWidget *widget;
cchar *type; ch *type;
int iiw; int iiw;
iiw = zdialog_find_widget(zd,wname); iiw = zdialog_find_widget(zd,wname);
if (! iiw) { if (! iiw) {
Plog(0,"zdialog_set_limits, %s not found \n",wname); Plog(0,"zdialog_set_limits, %s not found \n",wname);
return 0; return 0;
} }
widget = zd->widget[iiw].widget; widget = zd->widget[iiw].widget;
type = zd->widget[iiw].type; type = zd->widget[iiw].type;
skipping to change at line 9839 skipping to change at line 9858
zd->widget[iiw].lval = min; zd->widget[iiw].lval = min;
zd->widget[iiw].hval = max; zd->widget[iiw].hval = max;
} }
return 1; return 1;
} }
// get lower and upper limits for numeric data entry widget // get lower and upper limits for numeric data entry widget
// returns 1 if OK, 0 if not a widget with limits // returns 1 if OK, 0 if not a widget with limits
int zdialog_get_limits(zdialog *zd, cchar *wname, double &min, double &max) int zdialog_get_limits(zdialog *zd, ch *wname, double &min, double &max)
{ {
int iiw; int iiw;
min = max = 0; min = max = 0;
iiw = zdialog_find_widget(zd,wname); iiw = zdialog_find_widget(zd,wname);
if (! iiw) return 0; if (! iiw) return 0;
if (! strstr("spin zspin hscale hscale2 vscale",zd->widget[iiw].type)) if (! strstr("spin zspin hscale hscale2 vscale",zd->widget[iiw].type))
return 0; return 0;
min = zd->widget[iiw].lolim; min = zd->widget[iiw].lolim;
max = zd->widget[iiw].hilim; max = zd->widget[iiw].hilim;
return 1; return 1;
} }
// Expand a widget scale in the region around the neutral value. // Expand a widget scale in the region around the neutral value.
// Control small adjustments near the neutral value more precisely. // Control small adjustments near the neutral value more precisely.
// lval and hval: the range of values to be rescaled. // lval and hval: the range of values to be rescaled.
// nval: the neutral value where the scale will be expanded the most. // nval: the neutral value where the scale will be expanded the most.
// lval <= nval <= hval // lval <= nval <= hval
int zdialog_rescale(zdialog *zd, cchar *wname, float lval, float nval, float hva l) int zdialog_rescale(zdialog *zd, ch *wname, float lval, float nval, float hval)
{ {
int iiw; int iiw;
iiw = zdialog_find_widget(zd,wname); iiw = zdialog_find_widget(zd,wname);
if (! iiw) return 0; if (! iiw) return 0;
if (lval > nval || nval > hval) { if (lval > nval || nval > hval) {
Plog(0,"zdialog_rescale, bad data: %s \n",wname); Plog(0,"zdialog_rescale, bad data: %s \n",wname);
return 0; return 0;
} }
skipping to change at line 9882 skipping to change at line 9901
zd->widget[iiw].rescale = 1; zd->widget[iiw].rescale = 1;
zd->widget[iiw].lval = lval; zd->widget[iiw].lval = lval;
zd->widget[iiw].nval = nval; zd->widget[iiw].nval = nval;
zd->widget[iiw].hval = hval; zd->widget[iiw].hval = hval;
return 1; return 1;
} }
// run the dialog and send events to the event function // run the dialog and send events to the event function
// //
// evfunc: int func(zdialog *zd, cchar *event) // evfunc: int func(zdialog *zd, ch *event)
// If present, eventFunc is called when a dialog widget is changed or the dialo g // If present, eventFunc is called when a dialog widget is changed or the dialo g
// is completed. If a widget was changed, event is the widget name. // is completed. If a widget was changed, event is the widget name.
// Get the new widget data with zdialog_fetch(). // Get the new widget data with zdialog_fetch().
// If a completion button was pressed, event is "zstat" and zd->zstat will be // If a completion button was pressed, event is "zstat" and zd->zstat will be
// the button number 1-N. // the button number 1-N.
// If the dialog was destroyed, event is "zstat" and zd->zstat is negative. // If the dialog was destroyed, event is "zstat" and zd->zstat is negative.
// //
// posn: optional dialog box position: // posn: optional dialog box position:
// "mouse" = position at mouse // "mouse" = position at mouse
// "desktop" = center on desktop // "desktop" = center on desktop
// "parent" = center on parent window // "parent" = center on parent window
// "nn/nn" = position NW corner at relative x/y position in parent window, // "nn/nn" = position NW corner at relative x/y position in parent window,
// where nn/nn is a percent 0-100 of the parent window dimensions. // where nn/nn is a percent 0-100 of the parent window dimensions.
// "save" = save last user-set position and use this whenever the dialog // "save" = save last user-set position and use this whenever the dialog
// is repeated, also across sessions. DEFAULT. // is repeated, also across sessions. DEFAULT.
// //
// KBevent: extern void KBevent(GdkEventKey *event) // KBevent: extern void KBevent(GdkEventKey *event)
// This function must be supplied by the caller of zdialog. // This function must be supplied by the caller of zdialog.
// It is called when Ctrl|Shift|Alt|F1 is pressed. // It is called when Ctrl|Shift|Alt|F1 is pressed.
int zdialog_run(zdialog *zd, zdialog_event evfunc, cchar *posn) int zdialog_run(zdialog *zd, zdialog_event evfunc, ch *posn)
{ {
int zdialog_KB_press(GtkWidget *, GdkEventKey *event, zdialog *zd); int zdialog_KB_press(GtkWidget *, GdkEventKey *event, zdialog *zd);
int zdialog_focus_in_event(GtkWidget *, GdkEvent *event, zdialog *zd); int zdialog_focus_in_event(GtkWidget *, GdkEvent *event, zdialog *zd);
GtkWidget *dialog; GtkWidget *dialog;
if (! zdialog_valid(zd)) return 0; if (! zdialog_valid(zd)) return 0;
if (zd->zrunning) { if (zd->zrunning) {
Plog(0,"zdialog is already running \n"); Plog(0,"zdialog is already running \n");
return 0; return 0;
skipping to change at line 9950 skipping to change at line 9969
int zdialog_widget_event(GtkWidget *widget, zdialog *zd) int zdialog_widget_event(GtkWidget *widget, zdialog *zd)
{ {
zdialog_event *evfunc = 0; // dialog event callback function zdialog_event *evfunc = 0; // dialog event callback function
GtkTextView *textView = 0; GtkTextView *textView = 0;
GtkTextBuffer *textBuff = 0; GtkTextBuffer *textBuff = 0;
GtkTextIter iter1, iter2; GtkTextIter iter1, iter2;
GdkRGBA gdkrgba; GdkRGBA gdkrgba;
int ii, nn; int ii, nn;
cchar *wname, *wtype, *wdata; ch *wname, *wtype, *wdata;
char sdata[20]; ch sdata[20];
double dval; double dval;
float lval, nval, hval, F; float lval, nval, hval, F;
if (! zdialog_valid2(zd)) return 1; // zdialog gone if (! zdialog_valid2(zd)) return 1; // zdialog gone
if (zd->disabled) return 1; // events disabled if (zd->disabled) return 1; // events disabled
zd->disabled = 1; // disable nested events zd->disabled = 1; // disable nested events
for (ii = 0; ii < zdmaxbutts; ii++) { // check completion buttons for (ii = 0; ii < zdmaxbutts; ii++) { // check completion buttons
if (zd->compwidget[ii] == null) break; // EOL if (zd->compwidget[ii] == null) break; // EOL
skipping to change at line 9995 skipping to change at line 10014
found_widget: found_widget:
wname = zd->widget[ii].wname; wname = zd->widget[ii].wname;
wtype = zd->widget[ii].type; wtype = zd->widget[ii].type;
wdata = 0; wdata = 0;
Plog(2,"dialog: %s event: %s \n",zd->title,wname); // Floglevel=2 to log dialog inputs Plog(2,"dialog: %s event: %s \n",zd->title,wname); // Floglevel=2 to log dialog inputs
if (strmatch(wtype,"button")) if (strmatch(wtype,"button"))
wdata = gtk_button_get_label(GTK_BUTTON(widget)); // button label wdata = (ch *) gtk_button_get_label(GTK_BUTTON(widget)); // button label
if (strmatch(wtype,"zbutton")) { // checkbox as smaller button if (strmatch(wtype,"zbutton")) { // checkbox as smaller button
wdata = gtk_button_get_label(GTK_BUTTON(widget)); wdata = (ch *) gtk_button_get_label(GTK_BUTTON(widget));
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget),0); // reset checkmark = off gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget),0); // reset checkmark = off
} }
if (strmatch(wtype,"zedit")) { if (strmatch(wtype,"zedit")) {
gtk_text_buffer_get_bounds(textBuff,&iter1,&iter2); gtk_text_buffer_get_bounds(textBuff,&iter1,&iter2);
wdata = gtk_text_buffer_get_text(textBuff,&iter1,&iter2,0); wdata = gtk_text_buffer_get_text(textBuff,&iter1,&iter2,0);
} }
if (strmatch(wtype,"zentry")) { if (strmatch(wtype,"zentry")) {
gtk_text_buffer_get_bounds(textBuff,&iter1,&iter2); gtk_text_buffer_get_bounds(textBuff,&iter1,&iter2);
skipping to change at line 10106 skipping to change at line 10125
if (! zdialog_valid2(zd)) return 0; if (! zdialog_valid2(zd)) return 0;
if (zd->zstat) return 0; // already complete if (zd->zstat) return 0; // already complete
zdialog_focus_zd = zd; zdialog_focus_zd = zd;
zdialog_send_event(zd,"focus"); // notify dialog event function zdialog_send_event(zd,"focus"); // notify dialog event function
return 0; // must be 0 return 0; // must be 0
} }
// set KB shortcuts for common zdialog completion buttons // set KB shortcuts for common zdialog completion buttons
int Nkbshortcuts = 0; int Nkbshortcuts = 0;
cchar *kbshortcuts[10], *kbevents[10]; ch *kbshortcuts[10], *kbevents[10];
void zdialog_KB_addshortcut(cchar *shortcut, cchar *event) // e.g. ("Ctrl+D", "Done") void zdialog_KB_addshortcut(ch *shortcut, ch *event) // e.g. ("Ctrl+D", "Done")
{ {
if (Nkbshortcuts > 9) return; if (Nkbshortcuts > 9) return;
kbshortcuts[Nkbshortcuts] = zstrdup(shortcut,"zdialog"); kbshortcuts[Nkbshortcuts] = zstrdup(shortcut,"zdialog");
kbevents[Nkbshortcuts] = zstrdup(event,"zdialog"); kbevents[Nkbshortcuts] = zstrdup(event,"zdialog");
++Nkbshortcuts; ++Nkbshortcuts;
return; return;
} }
// zdialog response handler for keyboard events // zdialog response handler for keyboard events
// key symbols can be found at /usr/include/gtk-3.0/gdk/gdkkeysyms.h // key symbols can be found at /usr/include/gtk-3.0/gdk/gdkkeysyms.h
// main app must provide: extern void KBevent(GdkEventKey *event) // main app must provide: extern void KBevent(GdkEventKey *event)
// private function // private function
int zdialog_KB_press(GtkWidget *widget, GdkEventKey *kbevent, zdialog *zd) int zdialog_KB_press(GtkWidget *widget, GdkEventKey *kbevent, zdialog *zd)
{ {
void zdialog_copyfunc(GtkWidget *, GtkClipboard *); void zdialog_copyfunc(GtkWidget *, GtkClipboard *);
void zdialog_pastefunc(GtkClipboard *, cchar *, void *); void zdialog_pastefunc(GtkClipboard *, ch *, void *);
GtkWidget *focuswidget; GtkWidget *focuswidget;
int KB_Ctrl = 0, KB_Alt = 0; // track state of Ctrl and Alt keys int KB_Ctrl = 0, KB_Alt = 0; // track state of Ctrl and Alt keys
int KBkey = kbevent->keyval; int KBkey = kbevent->keyval;
cchar *type; ch *type;
int ii, cc; int ii, cc;
if (kbevent->state & GDK_CONTROL_MASK) KB_Ctrl = 1; if (kbevent->state & GDK_CONTROL_MASK) KB_Ctrl = 1;
if (kbevent->state & GDK_MOD1_MASK) KB_Alt = 1; if (kbevent->state & GDK_MOD1_MASK) KB_Alt = 1;
if (KBkey == GDK_KEY_Escape) { // escape key if (KBkey == GDK_KEY_Escape) { // escape key
Plog(1,"escape key \n"); // 22.50 Plog(1,"escape key \n"); // 22.50
if (zd->eventCB) zdialog_send_event(zd,"escape"); if (zd->eventCB) zdialog_send_event(zd,"escape");
else zd->zstat = -2; else zd->zstat = -2;
return 1; return 1;
skipping to change at line 10185 skipping to change at line 10204
int zdialog_zspin_event(GtkWidget *widget, GdkEvent *event, zdialog *zd) int zdialog_zspin_event(GtkWidget *widget, GdkEvent *event, zdialog *zd)
{ {
zdialog_event *evfunc = 0; // dialog event callback function zdialog_event *evfunc = 0; // dialog event callback function
GtkTextBuffer *textBuff; GtkTextBuffer *textBuff;
GtkTextIter iter1, iter2; GtkTextIter iter1, iter2;
int KBkey; int KBkey;
int ii, err, Nsteps, state, incr = 0; int ii, err, Nsteps, state, incr = 0;
double fdata, lolim, hilim, step; // double double fdata, lolim, hilim, step; // double
char *wdata, sdata[20]; ch *wdata, sdata[20];
int time, elaps, Fchanged; int time, elaps, Fchanged;
static int time0 = 0, time1 = 0; static int time0 = 0, time1 = 0;
if (! zdialog_valid2(zd)) return 1; // event after dialog destroyed if (! zdialog_valid2(zd)) return 1; // event after dialog destroyed
if (zd->disabled) return 1; // zdialog events disabled if (zd->disabled) return 1; // zdialog events disabled
for (ii = 1; zd->widget[ii].type; ii++) // find "zspin" (text view) widget for (ii = 1; zd->widget[ii].type; ii++) // find "zspin" (text view) widget
if (zd->widget[ii].widget == widget) break; if (zd->widget[ii].widget == widget) break;
if (! zd->widget[ii].type) return 0; // not found if (! zd->widget[ii].type) return 0; // not found
skipping to change at line 10303 skipping to change at line 10322
// process Ctrl+C (copy text from widget to clipboard) // process Ctrl+C (copy text from widget to clipboard)
// private function // private function
void zdialog_copyfunc(GtkWidget *widget, GtkClipboard *clipboard) void zdialog_copyfunc(GtkWidget *widget, GtkClipboard *clipboard)
{ {
GtkTextView *textView = 0; GtkTextView *textView = 0;
GtkTextBuffer *textBuff = 0; GtkTextBuffer *textBuff = 0;
zdialog *zd; zdialog *zd;
int ii, cc = 0; int ii, cc = 0;
cchar *wname; ch *wname;
char text[1000]; ch text[1000];
widget = gtk_window_get_focus(GTK_WINDOW(widget)); widget = gtk_window_get_focus(GTK_WINDOW(widget));
if (! widget) return; if (! widget) return;
zd = zdialog_focus_zd; zd = zdialog_focus_zd;
if (! zdialog_valid2(zd)) return; if (! zdialog_valid2(zd)) return;
for (ii = 1; zd->widget[ii].type; ii++) // find widget in zdialog for (ii = 1; zd->widget[ii].type; ii++) // find widget in zdialog
if (zd->widget[ii].widget == widget) goto found_widget; if (zd->widget[ii].widget == widget) goto found_widget;
for (ii = 1; zd->widget[ii].type; ii++) { // failed, test if buffer for (ii = 1; zd->widget[ii].type; ii++) { // failed, test if buffer
skipping to change at line 10334 skipping to change at line 10353
wname = zd->widget[ii].wname; wname = zd->widget[ii].wname;
zdialog_fetch(zd,wname,text,999); // current text in widget zdialog_fetch(zd,wname,text,999); // current text in widget
cc = strlen(text); cc = strlen(text);
gtk_clipboard_set_text(clipboard,text,cc); gtk_clipboard_set_text(clipboard,text,cc);
return; return;
} }
// process Ctrl+V (paste text from clipboard to widget with KB focus) // process Ctrl+V (paste text from clipboard to widget with KB focus)
// private function // private function
void zdialog_pastefunc(GtkClipboard *clipboard, cchar *cliptext, void *arg) void zdialog_pastefunc(GtkClipboard *clipboard, ch *cliptext, void *arg)
{ {
GtkWindow *window; GtkWindow *window;
GtkWidget *widget; GtkWidget *widget;
GtkTextView *textView = 0; GtkTextView *textView = 0;
GtkTextBuffer *textBuff = 0; GtkTextBuffer *textBuff = 0;
zdialog *zd; zdialog *zd;
int ii, cc = 0; int ii, cc = 0;
cchar *wname; ch *wname;
char text[1000]; ch text[1000];
window = (GtkWindow *) arg; window = (GtkWindow *) arg;
widget = gtk_window_get_focus(window); widget = gtk_window_get_focus(window);
if (! widget) return; // widget for pasted text if (! widget) return; // widget for pasted text
if (! cliptext || ! *cliptext) return; // clipboard text pasted if (! cliptext || ! *cliptext) return; // clipboard text pasted
zd = zdialog_focus_zd; zd = zdialog_focus_zd;
if (! zdialog_valid2(zd)) return; if (! zdialog_valid2(zd)) return;
if (zd->zstat) return; if (zd->zstat) return;
skipping to change at line 10408 skipping to change at line 10427
if (zdialog_valid2(zd)) zd->disabled = 0; // 'event' may cause zdialog_free() if (zdialog_valid2(zd)) zd->disabled = 0; // 'event' may cause zdialog_free()
} }
if (zdialog_valid2(zd)) zdialog_free(zd); // no callback, kill now if (zdialog_valid2(zd)) zdialog_free(zd); // no callback, kill now
return 0; return 0;
} }
// Send an event name to an active zdialog. // Send an event name to an active zdialog.
// The response function eventFunc() will be called with this event. // The response function eventFunc() will be called with this event.
int zdialog_send_event(zdialog *zd, cchar *event) int zdialog_send_event(zdialog *zd, ch *event)
{ {
zdialog_event * evfunc = 0; // dialog event callback function zdialog_event * evfunc = 0; // dialog event callback function
int ii; int ii;
if (! zdialog_valid2(zd)) return 0; // zdialog canceled if (! zdialog_valid2(zd)) return 0; // zdialog canceled
if (strmatch(event,"escape")) goto send_event; // escape key --> "escape" event if (strmatch(event,"escape")) goto send_event; // escape key --> "escape" event
if (zd->disabled) return 0; // zdialog busy if (zd->disabled) return 0; // zdialog busy
if (strstr(zdialog_button_shortcuts,event)) { // dialog completion buttons (zfuncs.h) if (strstr(zdialog_button_shortcuts,event)) { // dialog completion buttons (zfuncs.h)
skipping to change at line 10532 skipping to change at line 10551
zdialog_save_inputs(zd); // save user inputs for next use zdialog_save_inputs(zd); // save user inputs for next use
zdialog_destroy(zd); // destroy GTK dialog if there zdialog_destroy(zd); // destroy GTK dialog if there
zd->sentinel1 = zd->sentinel2 = 0; // mark sentinels invalid zd->sentinel1 = zd->sentinel2 = 0; // mark sentinels invalid
zfree(zd->title); // free title memory zfree(zd->title); // free title memory
zfree(zd->widget[0].data); zfree(zd->widget[0].data);
for (ii = 1; zd->widget[ii].type; ii++) // loop through widgets for (ii = 1; zd->widget[ii].type; ii++) // loop through widgets
{ {
zfree((char *) zd->widget[ii].type); zfree((ch *) zd->widget[ii].type);
// free strings // free strings
zfree((char *) zd->widget[ii].wname); zfree((ch *) zd->widget[ii].wname);
if (zd->widget[ii].pname) zfree((char *) zd->widget[ii].pname); if (zd->widget[ii].pname) zfree((ch *) zd->widget[ii].pname);
// parent widget name // parent widget name
if (zd->widget[ii].data) zfree(zd->widget[ii].data); // free data if (zd->widget[ii].data) zfree(zd->widget[ii].data); // free data
if (zd->widget[ii].zlist) zlist_delete(zd->widget[ii].zlist); // free combo box zlist if (zd->widget[ii].zlist) zlist_delete(zd->widget[ii].zlist); // free combo box zlist
} }
for (ii = 0; ii < zdialog_count; ii++) // remove from valid zdialog list for (ii = 0; ii < zdialog_count; ii++) // remove from valid zdialog list
if (zd == zdialog_list[ii]) break; if (zd == zdialog_list[ii]) break;
if (ii < zdialog_count) { if (ii < zdialog_count) {
zdialog_count--; zdialog_count--;
for (NOP; ii < zdialog_count; ii++) // pack down list for (NOP; ii < zdialog_count; ii++) // pack down list
zdialog_list[ii] = zdialog_list[ii+1]; zdialog_list[ii] = zdialog_list[ii+1];
skipping to change at line 10573 skipping to change at line 10592
{ {
zmainsleep(0.1); zmainsleep(0.1);
if (! zd) return -1; if (! zd) return -1;
if (! zdialog_valid2(zd)) return -1; if (! zdialog_valid2(zd)) return -1;
if (zd->zstat) return zd->zstat; if (zd->zstat) return zd->zstat;
} }
} }
// put cursor at named widget // put cursor at named widget
int zdialog_goto(zdialog *zd, cchar *wname) int zdialog_goto(zdialog *zd, ch *wname)
{ {
GtkWidget *widget; GtkWidget *widget;
if (! zdialog_valid(zd)) return 0; if (! zdialog_valid(zd)) return 0;
widget = zdialog_gtkwidget(zd, wname); widget = zdialog_gtkwidget(zd, wname);
if (! widget) return 0; if (! widget) return 0;
gtk_widget_grab_focus(widget); gtk_widget_grab_focus(widget);
return 1; return 1;
skipping to change at line 10603 skipping to change at line 10622
if (! zdialog_valid(zd)) return; if (! zdialog_valid(zd)) return;
dialog = zd->widget[0].widget; dialog = zd->widget[0].widget;
if (! dialog) return; if (! dialog) return;
window = gtk_widget_get_window(dialog); window = gtk_widget_get_window(dialog);
gdk_window_set_cursor(window,cursor); gdk_window_set_cursor(window,cursor);
return; return;
} }
// insert data into a zdialog widget // insert data into a zdialog widget
int zdialog_stuff(zdialog *zd, cchar *wname, cchar *data) // stuff a string int zdialog_stuff(zdialog *zd, ch *wname, ch *data) // stuff a string
{ {
if (data) zdialog_put_data(zd,wname,data); if (data) zdialog_put_data(zd,wname,data);
else zdialog_put_data(zd,wname,""); // null > "" else zdialog_put_data(zd,wname,""); // null > ""
return 1; return 1;
} }
int zdialog_stuff(zdialog *zd, cchar *wname, int idata) // stuff an integer int zdialog_stuff(zdialog *zd, ch *wname, int idata) // stuff an integer
{ {
char string[16]; ch string[16];
double min, max; double min, max;
if (zdialog_get_limits(zd,wname,min,max)) if (zdialog_get_limits(zd,wname,min,max))
if (idata < min || idata > max) return 0; // bad data, do nothing if (idata < min || idata > max) return 0; // bad data, do nothing
snprintf(string,16,"%d",idata); snprintf(string,16,"%d",idata);
zdialog_put_data(zd,wname,string); zdialog_put_data(zd,wname,string);
return 1; return 1;
} }
int zdialog_stuff(zdialog *zd, cchar *wname, double ddata) // stuff a double int zdialog_stuff(zdialog *zd, ch *wname, double ddata) // stuff a double
{ {
char string[32]; ch string[32];
double min, max; double min, max;
if (zdialog_get_limits(zd,wname,min,max)) if (zdialog_get_limits(zd,wname,min,max))
if (ddata < min || ddata > max) return 0; // bad data, do nothing if (ddata < min || ddata > max) return 0; // bad data, do nothing
snprintf(string,32,"%.7g",ddata); // increase from 6 to 7 digits snprintf(string,32,"%.7g",ddata); // increase from 6 to 7 digits
zdialog_put_data(zd,wname,string); // 'g' uses decimal or comma zdialog_put_data(zd,wname,string); // 'g' uses decimal or comma
return 1; // (per locale) return 1; // (per locale)
} }
int zdialog_stuff(zdialog *zd, cchar *wname, double ddata, cchar *format) // stuff a double, formatted int zdialog_stuff(zdialog *zd, ch *wname, double ddata, ch *format) // stuff a double, formatted
{ {
char string[32]; ch string[32];
double min, max; double min, max;
if (zdialog_get_limits(zd,wname,min,max)) if (zdialog_get_limits(zd,wname,min,max))
if (ddata < min || ddata > max) return 0; // bad data, do nothing if (ddata < min || ddata > max) return 0; // bad data, do nothing
snprintf(string,32,format,ddata); // use "%.2g" etc. for snprintf(string,32,format,ddata); // use "%.2g" etc. for
zdialog_put_data(zd,wname,string); // locale dependent point/comma zdialog_put_data(zd,wname,string); // locale dependent point/comma
return 1; return 1;
} }
int zdialog_labelfont(zdialog *zd, cchar *labl, cchar *font, cchar *txt) // stuff label text using specified font int zdialog_labelfont(zdialog *zd, ch *labl, ch *font, ch *txt) // stuff label text using specified font
{ {
GtkWidget *widget; GtkWidget *widget;
cchar *format = "<span font=\"%s\" >%s</span>"; ch *format = "<span font=\"%s\" >%s</span>";
char txt2[1000]; ch txt2[1000];
if (! font) font = zfuncs::appfont; // default font if (! font) font = zfuncs::appfont; // default font
snprintf(txt2,1000,format,font,txt); snprintf(txt2,1000,format,font,txt);
widget = zdialog_gtkwidget(zd,labl); widget = zdialog_gtkwidget(zd,labl);
gtk_label_set_markup(GTK_LABEL(widget),txt2); gtk_label_set_markup(GTK_LABEL(widget),txt2);
return 1; return 1;
} }
// get data from a zdialog widget // get data from a zdialog widget
int zdialog_fetch(zdialog *zd, cchar *wname, char *data, int maxcc) // fetch string data int zdialog_fetch(zdialog *zd, ch *wname, ch *data, int maxcc) // fetch string data
{ {
cchar *zdata; ch *zdata;
zdata = zdialog_get_data(zd,wname); zdata = zdialog_get_data(zd,wname);
if (! zdata) { if (! zdata) {
*data = 0; *data = 0;
return 0; return 0;
} }
return strncpy0(data,zdata,maxcc); // 0 = OK, 1 = truncation return strncpy0(data,zdata,maxcc); // 0 = OK, 1 = truncation
} }
int zdialog_fetch(zdialog *zd, cchar *wname, int &idata) // fetch an integer int zdialog_fetch(zdialog *zd, ch *wname, int &idata) // fetch an integer
{ {
cchar *zdata; ch *zdata;
zdata = zdialog_get_data(zd,wname); zdata = zdialog_get_data(zd,wname);
if (! zdata) { if (! zdata) {
idata = 0; idata = 0;
return 0; return 0;
} }
idata = atoi(zdata); idata = atoi(zdata);
return 1; return 1;
} }
int zdialog_fetch(zdialog *zd, cchar *wname, double &ddata) // fetch a double int zdialog_fetch(zdialog *zd, ch *wname, double &ddata) // fetch a double
{ {
int stat; int stat;
cchar *zdata; ch *zdata;
zdata = zdialog_get_data(zd,wname); zdata = zdialog_get_data(zd,wname);
if (! zdata) { if (! zdata) {
ddata = 0; ddata = 0;
return 0; return 0;
} }
stat = convSD(zdata,ddata); // period or comma decimal point OK stat = convSD(zdata,ddata); // period or comma decimal point OK
if (stat < 4) return 1; if (stat < 4) return 1;
return 0; return 0;
} }
int zdialog_fetch(zdialog *zd, cchar *wname, float &fdata) // fetch a float int zdialog_fetch(zdialog *zd, ch *wname, float &fdata) // fetch a float
{ {
int stat; int stat;
cchar *zdata; ch *zdata;
double ddata; double ddata;
zdata = zdialog_get_data(zd,wname); zdata = zdialog_get_data(zd,wname);
if (! zdata) { if (! zdata) {
fdata = 0; fdata = 0;
return 0; return 0;
} }
stat = convSD(zdata,ddata); // period or comma decimal point OK stat = convSD(zdata,ddata); // period or comma decimal point OK
fdata = ddata; fdata = ddata;
if (stat < 4) return 1; if (stat < 4) return 1;
return 0; return 0;
} }
// clear combo box entries // clear combo box entries
int zdialog_combo_clear(zdialog *zd, cchar *wname) int zdialog_combo_clear(zdialog *zd, ch *wname)
{ {
int ii; int ii;
ii = zdialog_find_widget(zd,wname); ii = zdialog_find_widget(zd,wname);
if (! ii) return 0; if (! ii) return 0;
gtk_combo_box_text_remove_all(GTK_COMBO_BOX_TEXT(zd->widget[ii].widget)); // remove all entries gtk_combo_box_text_remove_all(GTK_COMBO_BOX_TEXT(zd->widget[ii].widget)); // remove all entries
if (zd->widget[ii].zlist) zlist_clear(zd->widget[ii].zlist,0); if (zd->widget[ii].zlist) zlist_clear(zd->widget[ii].zlist,0);
return 1; return 1;
} }
// popup (open) combo box pick list // popup (open) combo box pick list
int zdialog_combo_popup(zdialog *zd, cchar *wname) int zdialog_combo_popup(zdialog *zd, ch *wname)
{ {
int ii; int ii;
ii = zdialog_find_widget(zd,wname); ii = zdialog_find_widget(zd,wname);
if (! ii) return 0; if (! ii) return 0;
gtk_combo_box_popup(GTK_COMBO_BOX(zd->widget[ii].widget)); gtk_combo_box_popup(GTK_COMBO_BOX(zd->widget[ii].widget));
return 1; return 1;
} }
/******************************************************************************* */ /******************************************************************************* */
// Load/save all function widget data from/to a file. // Load/save all function widget data from/to a file.
// dirname for data files: /home/<user>/.appname/funcname // dirname for data files: /home/<user>/.appname/funcname
// where zdialog data is saved for the respective function. // where zdialog data is saved for the respective function.
// return 0 = OK, +N = error // return 0 = OK, +N = error
int zdialog_load_widgets(zdialog *zd, spldat *sd, cchar *funcname, FILE *fid) int zdialog_load_widgets(zdialog *zd, spldat *sd, ch *funcname, FILE *fid)
{ {
using namespace zfuncs; using namespace zfuncs;
cchar *mess = "Load settings from file"; ch *mess = "Load settings from file";
int myfid = 0; int myfid = 0;
char *filename, dirname[200], buff[1000]; ch *filename, dirname[200], buff[1000];
char *wname, *wdata, wdata2[1000]; ch *wname, *wdata, wdata2[1000];
char *pp, *pp1, *pp2; ch *pp, *pp1, *pp2;
int ii, kk, err, cc1, cc2; int ii, kk, err, cc1, cc2;
if (! fid) // fid from script if (! fid) // fid from script
{ {
snprintf(dirname,200,"%s/%s",get_zhomedir(),funcname); // folder for data files snprintf(dirname,200,"%s/%s",get_zhomedir(),funcname); // folder for data files
filename = zgetfile(mess,GTK_WINDOW(mainwin),"file",dirname,0); // open data file filename = zgetfile(mess,GTK_WINDOW(mainwin),"file",dirname,0); // open data file
if (! filename) return 1; // user cancel if (! filename) return 1; // user cancel
fid = fopen(filename,"r"); fid = fopen(filename,"r");
zfree(filename); zfree(filename);
if (! fid) { if (! fid) {
skipping to change at line 10802 skipping to change at line 10821
if (! pp2) continue; // widget has no data if (! pp2) continue; // widget has no data
cc1 = pp2 - pp1; cc1 = pp2 - pp1;
if (cc1 > 100) continue; if (cc1 > 100) continue;
pp1[cc1] = 0; pp1[cc1] = 0;
wname = pp1; // widget name wname = pp1; // widget name
if (strstr("defcats deftags",wname)) continue; // fotoxx only kludge if (strstr("defcats deftags",wname)) continue; // fotoxx only kludge
pp2 += 3; pp2 += 3;
if (*pp2 == ' ') pp2++; if (*pp2 == ' ') pp2++;
wdata = pp2; // widget data wdata = pp2; // widget data
cc2 = strlen(wdata); cc2 = strlen(wdata);
if (cc2 < 1) wdata = (char *) ""; if (cc2 < 1) wdata = "";
if (cc2 > 1000) continue; if (cc2 > 1000) continue;
repl_1str(wdata,wdata2,"\\n","\n"); // replace "\n" with newline chars. repl_1str(wdata,wdata2,"\\n","\n"); // replace "\n" with newline chars.
kk = zdialog_put_data(zd,wname,wdata2); kk = zdialog_put_data(zd,wname,wdata2);
if (! kk) goto baddata; if (! kk) goto baddata;
} }
if (myfid) fclose(fid); if (myfid) fclose(fid);
return 0; return 0;
baddata: baddata:
zmessageACK(mainwin,"file data does not fit dialog"); zmessageACK(mainwin,"file data does not fit dialog");
if (myfid) fclose(fid); if (myfid) fclose(fid);
return 1; return 1;
} }
int zdialog_save_widgets(zdialog *zd, spldat *sd, cchar *funcname, FILE *fid) int zdialog_save_widgets(zdialog *zd, spldat *sd, ch *funcname, FILE *fid)
{ {
using namespace zfuncs; using namespace zfuncs;
cchar *mess = "Save settings to a file"; ch *mess = "Save settings to a file";
int myfid = 0; int myfid = 0;
char *filename, dirname[200]; ch *filename, dirname[200];
char *wtype, *wname, *wdata, wdata2[1000]; ch *wtype, *wname, *wdata, wdata2[1000];
int ii, cc; int ii, cc;
cchar *editwidgets = "entry zentry edit text togbutt check combo" // widget types to save ch *editwidgets = "entry zentry edit text togbutt check combo" // widget types to save
"radio spin zspin hscale hscale2 vscale colorbutt"; "radio spin zspin hscale hscale2 vscale colorbutt";
cchar *editwidgetsX = "defcats deftags"; // exclude list, fotoxx kludge ch *editwidgetsX = "defcats deftags"; // exclude list, fotoxx kludge
if (! fid) // fid from script if (! fid) // fid from script
{ {
snprintf(dirname,200,"%s/%s",get_zhomedir(),funcname); // folder for data files snprintf(dirname,200,"%s/%s",get_zhomedir(),funcname); // folder for data files
filename = zgetfile(mess,GTK_WINDOW(mainwin),"save",dirname,0); // open data file filename = zgetfile(mess,GTK_WINDOW(mainwin),"save",dirname,0); // open data file
if (! filename) return 1; // user cancel if (! filename) return 1; // user cancel
fid = fopen(filename,"w"); fid = fopen(filename,"w");
zfree(filename); zfree(filename);
if (! fid) { if (! fid) {
zmessageACK(mainwin,"%s \n %s",filename,strerror(errno)); zmessageACK(mainwin,"%s \n %s",filename,strerror(errno));
return 1; return 1;
} }
myfid = 1; myfid = 1;
} }
for (ii = 0; ii < zdmaxwidgets; ii++) for (ii = 0; ii < zdmaxwidgets; ii++)
{ {
wtype = (char *) zd->widget[ii].type; wtype = (ch *) zd->widget[ii].type;
if (! wtype) break; if (! wtype) break;
if (! strstr(editwidgets,wtype)) continue; if (! strstr(editwidgets,wtype)) continue;
wname = (char *) zd->widget[ii].wname; // write widget data recs: wname = (ch *) zd->widget[ii].wname; // write widget data recs:
if (strstr(editwidgetsX,wname)) continue; if (strstr(editwidgetsX,wname)) continue;
wdata = zd->widget[ii].data; // widgetname == widgetdata wdata = zd->widget[ii].data; // widgetname == widgetdata
if (! wdata) continue; if (! wdata) continue;
cc = strlen(wdata); cc = strlen(wdata);
if (cc > 900) continue; if (cc > 900) continue;
repl_1str(wdata,wdata2,"\n","\\n"); // replace newline with "\n" repl_1str(wdata,wdata2,"\n","\\n"); // replace newline with "\n"
fprintf(fid,"%s == %s \n",wname,wdata); fprintf(fid,"%s == %s \n",wname,wdata);
} }
if (sd) { if (sd) {
skipping to change at line 10875 skipping to change at line 10894
fprintf(fid,"end\n"); fprintf(fid,"end\n");
if (myfid) fclose(fid); if (myfid) fclose(fid);
return 0; return 0;
} }
// functions to support [prev] buttons in function dialogs // functions to support [prev] buttons in function dialogs
// load or save last-used widgets // load or save last-used widgets
int zdialog_load_prev_widgets(zdialog *zd, spldat *sd, cchar *funcname) int zdialog_load_prev_widgets(zdialog *zd, spldat *sd, ch *funcname)
{ {
using namespace zfuncs; using namespace zfuncs;
char filename[200]; ch filename[200];
FILE *fid; FILE *fid;
int err; int err;
snprintf(filename,200,"%s/%s/last-used",get_zhomedir(),funcname); snprintf(filename,200,"%s/%s/last-used",get_zhomedir(),funcname);
fid = fopen(filename,"r"); fid = fopen(filename,"r");
if (! fid) { if (! fid) {
zmessageACK(mainwin,"%s \n %s",filename,strerror(errno)); zmessageACK(mainwin,"%s \n %s",filename,strerror(errno));
return 1; return 1;
} }
err = zdialog_load_widgets(zd,sd,funcname,fid); err = zdialog_load_widgets(zd,sd,funcname,fid);
fclose(fid); fclose(fid);
return err; return err;
} }
int zdialog_save_last_widgets(zdialog *zd, spldat *sd, cchar *funcname) int zdialog_save_last_widgets(zdialog *zd, spldat *sd, ch *funcname)
{ {
using namespace zfuncs; using namespace zfuncs;
char filename[200], dirname[200]; ch filename[200], dirname[200];
FILE *fid; FILE *fid;
int err; int err;
snprintf(filename,200,"%s/%s/last-used",get_zhomedir(),funcname); snprintf(filename,200,"%s/%s/last-used",get_zhomedir(),funcname);
fid = fopen(filename,"w"); fid = fopen(filename,"w");
if (! fid) { if (! fid) {
snprintf(dirname,200,"%s/%s",get_zhomedir(),funcname); // create missing folder snprintf(dirname,200,"%s/%s",get_zhomedir(),funcname); // create missing folder
err = mkdir(dirname,0750); err = mkdir(dirname,0750);
if (err) { if (err) {
Plog(0,"%s \n %s \n",dirname,strerror(errno)); Plog(0,"%s \n %s \n",dirname,strerror(errno));
skipping to change at line 10932 skipping to change at line 10951
return err; return err;
} }
/******************************************************************************* */ /******************************************************************************* */
// functions to save and recall zdialog window positions // functions to save and recall zdialog window positions
namespace zdposn_names namespace zdposn_names
{ {
struct zdposn_t { struct zdposn_t {
char wintitle[64]; // window title (ID) ch wintitle[64]; // window title (ID)
float xpos, ypos; // window posn WRT parent or desktop, 0-100 float xpos, ypos; // window posn WRT parent or desktop, 0-100
int xsize, ysize; // window size, pixels int xsize, ysize; // window size, pixels
} zdposn[200]; // space to remember 200 windows } zdposn[200]; // space to remember 200 windows
int Nzdposn; // no. in use int Nzdposn; // no. in use
int Nzdpmax = 200; // table size int Nzdpmax = 200; // table size
} }
// Load zdialog positions table from its file (application startup) // Load zdialog positions table from its file (application startup)
// or save zdialog positions table to its file (application exit). // or save zdialog positions table to its file (application exit).
// Action is "load" or "save". Number of table entries is returned. // Action is "load" or "save". Number of table entries is returned.
int zdialog_geometry(cchar *action) int zdialog_geometry(ch *action)
{ {
using namespace zdposn_names; using namespace zdposn_names;
char posfile[200], buff[100], wintitle[64], *pp; ch posfile[200], buff[100], wintitle[64], *pp;
float xpos, ypos; float xpos, ypos;
int xsize, ysize; int xsize, ysize;
int ii, nn, cc; int ii, nn, cc;
FILE *fid; FILE *fid;
snprintf(posfile,199,"%s/zdialog_geometry",zhomedir); // /home/<user>/.appname/zdialog_geometry snprintf(posfile,199,"%s/zdialog_geometry",zhomedir); // /home/<user>/.appname/zdialog_geometry
if (strmatch(action,"load")) // load dialog positions table from file if (strmatch(action,"load")) // load dialog positions table from file
{ {
fid = fopen(posfile,"r"); fid = fopen(posfile,"r");
skipping to change at line 11024 skipping to change at line 11043
// Set the initial or new zdialog window position from "posn". // Set the initial or new zdialog window position from "posn".
// Called by zdialog_run(). Private function. // Called by zdialog_run(). Private function.
// null: window manager decides // null: window manager decides
// "mouse" put dialog at mouse position // "mouse" put dialog at mouse position
// "desktop" center dialog in desktop window // "desktop" center dialog in desktop window
// "parent" center dialog in parent window // "parent" center dialog in parent window
// "save" use the same position last set by the user // "save" use the same position last set by the user
// "nn/nn" put NW corner of dialog in parent window at % size // "nn/nn" put NW corner of dialog in parent window at % size
// (e.g. "50/50" puts NW corner at center of parent) // (e.g. "50/50" puts NW corner at center of parent)
void zdialog_set_position(zdialog *zd, cchar *posn) void zdialog_set_position(zdialog *zd, ch *posn)
{ {
using namespace zdposn_names; using namespace zdposn_names;
int ii, ppx, ppy, zdpx, zdpy, pww, phh; int ii, ppx, ppy, zdpx, zdpy, pww, phh;
float xpos, ypos; float xpos, ypos;
int xsize, ysize; int xsize, ysize;
char wintitle[64], *pp; ch wintitle[64], *pp;
GtkWidget *parent, *dialog; GtkWidget *parent, *dialog;
if (! zdialog_valid(zd)) return; if (! zdialog_valid(zd)) return;
parent = zd->parent; parent = zd->parent;
dialog = zd->widget[0].widget; dialog = zd->widget[0].widget;
if (strmatch(posn,"mouse")) { if (strmatch(posn,"mouse")) {
window_to_mouse(zd->dialog); window_to_mouse(zd->dialog);
return; return;
skipping to change at line 11070 skipping to change at line 11089
} }
else { else {
gtk_window_get_position(GTK_WINDOW(parent),&ppx,&ppy); // parent window NW corner gtk_window_get_position(GTK_WINDOW(parent),&ppx,&ppy); // parent window NW corner
gtk_window_get_size(GTK_WINDOW(parent),&pww,&phh); // parent window size gtk_window_get_size(GTK_WINDOW(parent),&pww,&phh); // parent window size
} }
if (strmatch(posn,"save")) // use last saved window position if (strmatch(posn,"save")) // use last saved window position
{ {
zd->saveposn = 1; // set flag for zdialog_free() zd->saveposn = 1; // set flag for zdialog_free()
pp = (char *) gtk_window_get_title(GTK_WINDOW(dialog)); // get window title, used as ID pp = (ch *) gtk_window_get_title(GTK_WINDOW(dialog)); // get window title, used as ID
if (! pp || strlen(pp) < 2) goto center_parent; // 22.31 if (! pp || strlen(pp) < 2) goto center_parent; // 22.31
strncpy0(wintitle,pp,64); // window title, < 64 chars. strncpy0(wintitle,pp,64); // window title, < 64 chars.
for (ii = 0; ii < Nzdposn; ii++) // search table for title for (ii = 0; ii < Nzdposn; ii++) // search table for title
if (strmatch(wintitle,zdposn[ii].wintitle)) break; if (strmatch(wintitle,zdposn[ii].wintitle)) break;
if (ii == Nzdposn) goto center_parent; // not found - zdialog_destroy() will add if (ii == Nzdposn) goto center_parent; // not found - zdialog_destroy() will add
zdpx = ppx + 0.01 * zdposn[ii].xpos * pww; // set position for dialog window zdpx = ppx + 0.01 * zdposn[ii].xpos * pww; // set position for dialog window
zdpy = ppy + 0.01 * zdposn[ii].ypos * phh; zdpy = ppy + 0.01 * zdposn[ii].ypos * phh;
skipping to change at line 11115 skipping to change at line 11134
// its position WRT parent or desktop for next use. // its position WRT parent or desktop for next use.
// called by zdialog_destroy(). Private function. // called by zdialog_destroy(). Private function.
void zdialog_save_position(zdialog *zd) void zdialog_save_position(zdialog *zd)
{ {
using namespace zdposn_names; using namespace zdposn_names;
int ii, ppx, ppy, pww, phh, zdpx, zdpy; int ii, ppx, ppy, pww, phh, zdpx, zdpy;
float xpos, ypos; float xpos, ypos;
int xsize, ysize; int xsize, ysize;
char wintitle[64], *pp; ch wintitle[64], *pp;
GtkWidget *parent, *dialog; GtkWidget *parent, *dialog;
if (! zdialog_valid(zd)) return; if (! zdialog_valid(zd)) return;
dialog = zd->widget[0].widget; dialog = zd->widget[0].widget;
if (! dialog) return; if (! dialog) return;
if (! gtk_widget_get_window(dialog)) return; if (! gtk_widget_get_window(dialog)) return;
gtk_window_get_position(GTK_WINDOW(dialog),&zdpx,&zdpy); // dialog window NW corner gtk_window_get_position(GTK_WINDOW(dialog),&zdpx,&zdpy); // dialog window NW corner
if (! zdpx && ! zdpy) return; // (0,0) ignore if (! zdpx && ! zdpy) return; // (0,0) ignore
skipping to change at line 11146 skipping to change at line 11165
phh = monitor_hh; phh = monitor_hh;
} }
else { else {
gtk_window_get_position(GTK_WINDOW(parent),&ppx,&ppy); // parent window NW corner gtk_window_get_position(GTK_WINDOW(parent),&ppx,&ppy); // parent window NW corner
gtk_window_get_size(GTK_WINDOW(parent),&pww,&phh); // parent window size gtk_window_get_size(GTK_WINDOW(parent),&pww,&phh); // parent window size
} }
xpos = 100.0 * (zdpx - ppx) / pww; // dialog window relative position xpos = 100.0 * (zdpx - ppx) / pww; // dialog window relative position
ypos = 100.0 * (zdpy - ppy) / phh; // (as percent of parent size) ypos = 100.0 * (zdpy - ppy) / phh; // (as percent of parent size)
pp = (char *) gtk_window_get_title(GTK_WINDOW(dialog)); pp = (ch *) gtk_window_get_title(GTK_WINDOW(dialog));
if (! pp) return; if (! pp) return;
if (strlen(pp) < 2) return; if (strlen(pp) < 2) return;
if (strstr(pp,"/tmp/.mount")) return; // volatile appimage path names if (strstr(pp,"/tmp/.mount")) return; // volatile appimage path names
strncpy0(wintitle,pp,64); // window title, < 64 chars. strncpy0(wintitle,pp,64); // window title, < 64 chars.
for (ii = 0; ii < Nzdposn; ii++) // search table for window for (ii = 0; ii < Nzdposn; ii++) // search table for window
if (strmatch(wintitle,zdposn[ii].wintitle)) break; if (strmatch(wintitle,zdposn[ii].wintitle)) break;
if (ii == Nzdposn) { // not found if (ii == Nzdposn) { // not found
if (ii == Nzdpmax) return; // table full if (ii == Nzdpmax) return; // table full
Nzdposn++; // new entry Nzdposn++; // new entry
skipping to change at line 11180 skipping to change at line 11199
// within an app session or across app sessions. // within an app session or across app sessions.
namespace zdinputs_names namespace zdinputs_names
{ {
#define Nwmax zdmaxwidgets // max. widgets in a dialog #define Nwmax zdmaxwidgets // max. widgets in a dialog
#define Nzdmax 200 // max. zdialogs #define Nzdmax 200 // max. zdialogs
#define ccmax1 100 // max. widget name length #define ccmax1 100 // max. widget name length
#define ccmax2 400 // max. widget data length #define ccmax2 400 // max. widget data length
struct zdinputs_t { struct zdinputs_t {
char *zdtitle; // zdialog title ch *zdtitle; // zdialog title
int Nw; // no. of widgets int Nw; // no. of widgets
char **wname; ch **wname;
// list of widget names // list of widget names
char **wdata; ch **wdata;
// list of widget data // list of widget data
} zdinputs[Nzdmax]; // space for Nzdmax dialogs } zdinputs[Nzdmax]; // space for Nzdmax dialogs
int Nzd = 0; // no. zdialogs in use int Nzd = 0; // no. zdialogs in use
} }
// Load zdialog input fields from its file (app startup) // Load zdialog input fields from its file (app startup)
// or save zdialog input fields to its file (app shutdown). // or save zdialog input fields to its file (app shutdown).
// Action is "load" or "save". // Action is "load" or "save".
// Number of zdialogs is returned. // Number of zdialogs is returned.
int zdialog_inputs(cchar *action) int zdialog_inputs(ch *action)
{ {
using namespace zdinputs_names; using namespace zdinputs_names;
char zdinputsfile[200], buff[ccmax2]; ch zdinputsfile[200], buff[ccmax2];
char zdtitle[ccmax1], wname[Nwmax][ccmax1], wdata[Nwmax][ccmax2]; ch zdtitle[ccmax1], wname[Nwmax][ccmax1], wdata[Nwmax][ccmax2];
char *pp, *pp1, *pp2, wdata2[ccmax2+50]; ch *pp, *pp1, *pp2, wdata2[ccmax2+50];
FILE *fid; FILE *fid;
int Nw, ii, jj, cc, cc1, cc2; int Nw, ii, jj, cc, cc1, cc2;
snprintf(zdinputsfile,200,"%s/zdialog_inputs",zhomedir); // /home/<user>/.appname/zdialog_inputs snprintf(zdinputsfile,200,"%s/zdialog_inputs",zhomedir); // /home/<user>/.appname/zdialog_inputs
if (strmatch(action,"load")) // load dialog input fields from its file if (strmatch(action,"load")) // load dialog input fields from its file
{ {
Nzd = 0; Nzd = 0;
fid = fopen(zdinputsfile,"r"); // no file fid = fopen(zdinputsfile,"r"); // no file
skipping to change at line 11242 skipping to change at line 11261
if (! pp) break; if (! pp) break;
pp1 = pp; pp1 = pp;
pp2 = strstr(pp1," =="); pp2 = strstr(pp1," ==");
if (! pp2) break; // widget has no data if (! pp2) break; // widget has no data
cc1 = pp2 - pp1; cc1 = pp2 - pp1;
pp1[cc1] = 0; pp1[cc1] = 0;
pp2 += 3; pp2 += 3;
if (*pp2 == ' ') pp2++; if (*pp2 == ' ') pp2++;
cc2 = strlen(pp2); cc2 = strlen(pp2);
if (cc1 < 1 || cc1 >= ccmax1) break; if (cc1 < 1 || cc1 >= ccmax1) break;
if (cc2 < 1) pp2 = (char *) ""; if (cc2 < 1) pp2 = "";
if (cc2 >= ccmax2) break; // do not copy large inputs if (cc2 >= ccmax2) break; // do not copy large inputs
strcpy(wname[ii],pp1); // save widget name and data strcpy(wname[ii],pp1); // save widget name and data
strcpy(wdata2,pp2); strcpy(wdata2,pp2);
repl_1str(wdata2,wdata[ii],"\\n","\n"); // replace "\n" with newline chars. repl_1str(wdata2,wdata[ii],"\\n","\n"); // replace "\n" with newline chars.
} }
if (ii < Nw) { if (ii < Nw) {
Plog(0,"zdialog_inputs() bad data: %s \n",zdtitle); Plog(0,"zdialog_inputs() bad data: %s \n",zdtitle);
continue; continue;
} }
if (Nzd == Nzdmax) { if (Nzd == Nzdmax) {
Plog(0,"zdialog_inputs() too many dialogs \n"); Plog(0,"zdialog_inputs() too many dialogs \n");
break; break;
} }
zdinputs[Nzd].zdtitle = zstrdup(zdtitle,"zdialog_inputs"); // save acculumated zdialog data zdinputs[Nzd].zdtitle = zstrdup(zdtitle,"zdialog_inputs"); // save acculumated zdialog data
zdinputs[Nzd].Nw = Nw; zdinputs[Nzd].Nw = Nw;
cc = Nw * sizeof(char *); cc = Nw * sizeof(ch *);
zdinputs[Nzd].wname = (char **) zmalloc(cc,"zdialog_inputs"); zdinputs[Nzd].wname = (ch **) zmalloc(cc,"zdialog_inputs");
zdinputs[Nzd].wdata = (char **) zmalloc(cc,"zdialog_inputs"); zdinputs[Nzd].wdata = (ch **) zmalloc(cc,"zdialog_inputs");
for (ii = 0; ii < Nw; ii++) { for (ii = 0; ii < Nw; ii++) {
zdinputs[Nzd].wname[ii] = zstrdup(wname[ii],"zdialog_inputs"); zdinputs[Nzd].wname[ii] = zstrdup(wname[ii],"zdialog_inputs");
zdinputs[Nzd].wdata[ii] = zstrdup(wdata[ii],"zdialog_inputs"); zdinputs[Nzd].wdata[ii] = zstrdup(wdata[ii],"zdialog_inputs");
} }
Nzd++; Nzd++;
} }
fclose(fid); fclose(fid);
return Nzd; return Nzd;
skipping to change at line 11313 skipping to change at line 11332
return 0; return 0;
} }
// Save dialog user input fields when a dialog is finished. // Save dialog user input fields when a dialog is finished.
// Called automatically by zdialog_free(). Private function. // Called automatically by zdialog_free(). Private function.
int zdialog_save_inputs(zdialog *zd) int zdialog_save_inputs(zdialog *zd)
{ {
using namespace zdinputs_names; using namespace zdinputs_names;
char zdtitle[ccmax1], wname[ccmax1], wdata[ccmax2]; ch zdtitle[ccmax1], wname[ccmax1], wdata[ccmax2];
char *wnamex, *type; ch *wnamex, *type;
int ii, jj, Nw, cc; int ii, jj, Nw, cc;
cchar *skipwidgets = "dialog hbox vbox hsep vsep frame scrwin" // non-input widgets to omit ch *skipwidgets = "dialog hbox vbox hsep vsep frame scrwin" // non-input widgets to omit
"label text link button zbutton"; "label text link button zbutton";
cchar *skipexceptions = "searchtags"; // fotoxx kludge ch *skipexceptions = "searchtags"; // fotoxx kludge
if (! zdialog_valid(zd)) return 0; if (! zdialog_valid(zd)) return 0;
if (! zd->saveinputs) return 0; // zdialog does not use this service if (! zd->saveinputs) return 0; // zdialog does not use this service
strncpy0(zdtitle,zd->widget[0].data,ccmax1); // zdialog title is widget[0].data strncpy0(zdtitle,zd->widget[0].data,ccmax1); // zdialog title is widget[0].data
for (ii = 0; ii < Nzd; ii++) // find zdialog in zdinputs table for (ii = 0; ii < Nzd; ii++) // find zdialog in zdinputs table
if (strmatch(zdtitle,zdinputs[ii].zdtitle)) break; if (strmatch(zdtitle,zdinputs[ii].zdtitle)) break;
if (ii < Nzd) { // found if (ii < Nzd) { // found
skipping to change at line 11350 skipping to change at line 11369
} }
if (Nzd == Nzdmax) { if (Nzd == Nzdmax) {
Plog(0,"zdialog_save_inputs, too many zdialogs \n"); Plog(0,"zdialog_save_inputs, too many zdialogs \n");
return 0; return 0;
} }
ii = Nzd; // next zdinputs table entry ii = Nzd; // next zdinputs table entry
for (Nw = 0, jj = 1; zd->widget[jj].type; jj++) { // count zdialog widgets for (Nw = 0, jj = 1; zd->widget[jj].type; jj++) { // count zdialog widgets
wnamex = (char *) zd->widget[jj].wname; wnamex = (ch *) zd->widget[jj].wname;
type = (char *) zd->widget[jj].type; type = (ch *) zd->widget[jj].type;
if (strstr(skipwidgets,type)) // skip non-input widgets if (strstr(skipwidgets,type)) // skip non-input widgets
if (! strstr(skipexceptions,wnamex)) continue; if (! strstr(skipexceptions,wnamex)) continue;
Nw++; Nw++;
} }
if (! Nw) return 0; // no input widgets if (! Nw) return 0; // no input widgets
if (Nw > Nwmax) { if (Nw > Nwmax) {
Plog(0,"zdialog_inputs() bad data: %s \n",zdtitle); Plog(0,"zdialog_inputs() bad data: %s \n",zdtitle);
return 0; return 0;
} }
zdinputs[ii].zdtitle = zstrdup(zdtitle,"zdialog_save"); // set zdialog title zdinputs[ii].zdtitle = zstrdup(zdtitle,"zdialog_save"); // set zdialog title
cc = Nw * sizeof(char *); cc = Nw * sizeof(ch *);
// allocate pointers for widgets // allocate pointers for widgets
zdinputs[ii].wname = (char **) zmalloc(cc,"zdialog_save"); zdinputs[ii].wname = (ch **) zmalloc(cc,"zdialog_save");
zdinputs[ii].wdata = (char **) zmalloc(cc,"zdialog_save"); zdinputs[ii].wdata = (ch **) zmalloc(cc,"zdialog_save");
for (Nw = 0, jj = 1; zd->widget[jj].type; jj++) { // add widget names and data for (Nw = 0, jj = 1; zd->widget[jj].type; jj++) { // add widget names and data
wnamex = (char *) zd->widget[jj].wname; wnamex = (ch *) zd->widget[jj].wname;
type = (char *) zd->widget[jj].type; type = (ch *) zd->widget[jj].type;
if (strstr(skipwidgets,type)) // skip non-input widgets if (strstr(skipwidgets,type)) // skip non-input widgets
if (! strstr(skipexceptions,wnamex)) continue; if (! strstr(skipexceptions,wnamex)) continue;
strncpy0(wname,zd->widget[jj].wname,ccmax1); strncpy0(wname,zd->widget[jj].wname,ccmax1);
if (zd->widget[jj].data) if (zd->widget[jj].data)
strncpy0(wdata,zd->widget[jj].data,ccmax2); strncpy0(wdata,zd->widget[jj].data,ccmax2);
else strcpy(wdata,""); else strcpy(wdata,"");
zdinputs[ii].wname[Nw] = zstrdup(wname,"zdialog_save"); zdinputs[ii].wname[Nw] = zstrdup(wname,"zdialog_save");
zdinputs[ii].wdata[Nw] = zstrdup(wdata,"zdialog_save"); zdinputs[ii].wdata[Nw] = zstrdup(wdata,"zdialog_save");
Nw++; Nw++;
} }
skipping to change at line 11397 skipping to change at line 11416
} }
// Restore user input fields from prior use of the same dialog. // Restore user input fields from prior use of the same dialog.
// Call this if wanted after zdialog is built and before it is run. // Call this if wanted after zdialog is built and before it is run.
// Override old user inputs with zdialog_stuff() where needed. // Override old user inputs with zdialog_stuff() where needed.
int zdialog_restore_inputs(zdialog *zd) int zdialog_restore_inputs(zdialog *zd)
{ {
using namespace zdinputs_names; using namespace zdinputs_names;
char *zdtitle, *wname, *wdata; ch *zdtitle, *wname, *wdata;
int ii, jj; int ii, jj;
zd->saveinputs = 1; // flag, save data at zdialog_free() zd->saveinputs = 1; // flag, save data at zdialog_free()
zdtitle = (char *) zd->widget[0].data; // zdialog title zdtitle = (ch *) zd->widget[0].data; // zdialog title
for (ii = 0; ii < Nzd; ii++) // find zdialog in zdinputs for (ii = 0; ii < Nzd; ii++) // find zdialog in zdinputs
if (strmatch(zdtitle,zdinputs[ii].zdtitle)) break; if (strmatch(zdtitle,zdinputs[ii].zdtitle)) break;
if (ii == Nzd) return 0; // not found if (ii == Nzd) return 0; // not found
for (jj = 0; jj < zdinputs[ii].Nw; jj++) { // stuff all saved widget data for (jj = 0; jj < zdinputs[ii].Nw; jj++) { // stuff all saved widget data
wname = zdinputs[ii].wname[jj]; wname = zdinputs[ii].wname[jj];
wdata = zdinputs[ii].wdata[jj]; wdata = zdinputs[ii].wdata[jj];
zdialog_put_data(zd,wname,wdata); zdialog_put_data(zd,wname,wdata);
} }
return 1; return 1;
} }
/******************************************************************************* */ /******************************************************************************* */
// get text input from a popup dialog - multiple lines can be entered // get text input from a popup dialog - multiple lines can be entered
// returned text is subject for zfree() // returned text is subject for zfree()
// null is returned if user presses [cancel] button. // null is returned if user presses [cancel] button.
char * zdialog_text(GtkWidget *parent, cchar *title, cchar *inittext) ch * zdialog_text(GtkWidget *parent, ch *title, ch *inittext)
{ {
zdialog *zd; zdialog *zd;
int zstat; int zstat;
char *text; ch *text;
if (! main_thread()) zappcrash("zdialog_text() called from thread"); if (! main_thread()) zappcrash("zdialog_text() called from thread");
zd = zdialog_new(title,parent,"OK","Cancel",null); zd = zdialog_new(title,parent,"OK","Cancel",null);
zdialog_add_widget(zd,"frame","fred","dialog"); zdialog_add_widget(zd,"frame","fred","dialog");
zdialog_add_widget(zd,"zedit","text","fred"); zdialog_add_widget(zd,"zedit","text","fred");
if (inittext) zdialog_stuff(zd,"text",inittext); if (inittext) zdialog_stuff(zd,"text",inittext);
zdialog_resize(zd,300,0); zdialog_resize(zd,300,0);
zdialog_set_modal(zd); zdialog_set_modal(zd);
zdialog_run(zd,0,"mouse"); zdialog_run(zd,0,"mouse");
zstat = zdialog_wait(zd); zstat = zdialog_wait(zd);
if (zstat == 1) if (zstat == 1)
text = (char *) zdialog_get_data(zd,"text"); text = (ch *) zdialog_get_data(zd,"text");
else text = 0; else text = 0;
if (text) text = zstrdup(text,"zdialog_text"); if (text) text = zstrdup(text,"zdialog_text");
zdialog_free(zd); zdialog_free(zd);
return text; return text;
} }
/******************************************************************************* */ /******************************************************************************* */
// get text input from a popup dialog - one line only // get text input from a popup dialog - one line only
// returned text is subject for zfree() // returned text is subject for zfree()
// null is returned if user presses [cancel] button. // null is returned if user presses [cancel] button.
char * zdialog_text1(GtkWidget *parent, cchar *title, cchar *inittext) ch * zdialog_text1(GtkWidget *parent, ch *title, ch *inittext)
{ {
zdialog *zd; zdialog *zd;
int zstat; int zstat;
char *text; ch *text;
if (! main_thread()) zappcrash("zdialog_text1() called from thread"); if (! main_thread()) zappcrash("zdialog_text1() called from thread");
zd = zdialog_new(title,parent,"OK","Cancel",null); zd = zdialog_new(title,parent,"OK","Cancel",null);
zdialog_add_widget(zd,"zentry","text","dialog",0); zdialog_add_widget(zd,"zentry","text","dialog",0);
if (inittext) zdialog_stuff(zd,"text",inittext); if (inittext) zdialog_stuff(zd,"text",inittext);
zdialog_resize(zd,300,0); zdialog_resize(zd,300,0);
zdialog_set_modal(zd); zdialog_set_modal(zd);
zdialog_run(zd,0,"mouse"); zdialog_run(zd,0,"mouse");
zstat = zdialog_wait(zd); zstat = zdialog_wait(zd);
if (zstat == 1) if (zstat == 1)
text = (char *) zdialog_get_data(zd,"text"); text = (ch *) zdialog_get_data(zd,"text");
else text = 0; else text = 0;
if (text) text = zstrdup(text,"zdialog_text"); if (text) text = zstrdup(text,"zdialog_text");
zdialog_free(zd); zdialog_free(zd);
return text; return text;
} }
/******************************************************************************* */ /******************************************************************************* */
// Display a dialog with a message and 1-5 choice buttons. // Display a dialog with a message and 1-5 choice buttons.
// Returns choice 1-N corresponding to button selected. // Returns choice 1-N corresponding to button selected.
// nn = zdialog_choose(parent, where, message, butt1, butt2, ... null) // nn = zdialog_choose(parent, where, message, butt1, butt2, ... null)
// 'where' is null: window manager decides // 'where' is null: window manager decides
// "mouse" put dialog at mouse position // "mouse" put dialog at mouse position
// "desktop" center dialog in desktop window // "desktop" center dialog in desktop window
// "parent" center dialog in parent window // "parent" center dialog in parent window
int zdialog_choose(GtkWidget *parent, cchar *where, cchar *message, ...) int zdialog_choose(GtkWidget *parent, ch *where, ch *message, ...)
{ {
zdialog *zd; zdialog *zd;
va_list arglist; va_list arglist;
int ii, zstat, Nbutn; int ii, zstat, Nbutn;
cchar *butn[6]; ch *butn[6];
if (! main_thread()) zappcrash("zmessage_choose() called from thread"); if (! main_thread()) zappcrash("zmessage_choose() called from thread");
va_start(arglist,message); va_start(arglist,message);
for (ii = 0; ii < 5; ii++) for (ii = 0; ii < 5; ii++)
{ {
butn[ii] = va_arg(arglist,cchar *); butn[ii] = va_arg(arglist,ch *);
if (! butn[ii] || butn[ii] == (cchar *) 0x100000000) break; if (! butn[ii] || butn[ii] == (ch *) 0x100000000) break;
// ARM bug // ARM bug
} }
Nbutn = ii; Nbutn = ii;
if (! Nbutn) zappcrash("zdialog_choose(), no buttons"); if (! Nbutn) zappcrash("zdialog_choose(), no buttons");
zd = zdialog_new("choose",parent,butn[0],butn[1],butn[2],butn[3],butn[4],null ); zd = zdialog_new("choose",parent,butn[0],butn[1],butn[2],butn[3],butn[4],null );
zdialog_add_widget(zd,"hbox","hbmess","dialog","space=3"); zdialog_add_widget(zd,"hbox","hbmess","dialog","space=3");
zdialog_add_widget(zd,"label","labmess","hbmess",message,"space=5"); zdialog_add_widget(zd,"label","labmess","hbmess",message,"space=5");
zdialog_set_modal(zd); zdialog_set_modal(zd);
zdialog_set_decorated(zd,0); zdialog_set_decorated(zd,0);
skipping to change at line 11532 skipping to change at line 11551
// Display a dialog with a message and 1-5 choice buttons. // Display a dialog with a message and 1-5 choice buttons.
// Returns choice 1-5 corresponding to button selected. // Returns choice 1-5 corresponding to button selected.
// Returns -1 if cancel button [x] is selected. // Returns -1 if cancel button [x] is selected.
// Returns the KB character 20-127 if one is pressed. // Returns the KB character 20-127 if one is pressed.
// nn = zdialog_choose2(parent, where, message, butt1, butt2, ... null) // nn = zdialog_choose2(parent, where, message, butt1, butt2, ... null)
// 'where' is null: window manager decides // 'where' is null: window manager decides
// "mouse" put dialog at mouse position // "mouse" put dialog at mouse position
// "desktop" center dialog in desktop window // "desktop" center dialog in desktop window
// "parent" center dialog in parent window // "parent" center dialog in parent window
int zdialog_choose2(GtkWidget *parent, cchar *where, cchar *message, ...) int zdialog_choose2(GtkWidget *parent, ch *where, ch *message, ...)
{ {
int zdialog_choose2_event(zdialog *zd, cchar *event); int zdialog_choose2_event(zdialog *zd, ch *event);
int zdialog_choose2_KBevent(GtkWidget *, GdkEventKey *event, zdialog *zd); int zdialog_choose2_KBevent(GtkWidget *, GdkEventKey *event, zdialog *zd);
GtkWidget *widget; GtkWidget *widget;
zdialog *zd; zdialog *zd;
va_list arglist; va_list arglist;
int ii, zstat, Nbutn; int ii, zstat, Nbutn;
cchar *butn[6]; ch *butn[6];
if (! main_thread()) zappcrash("zmessage_choose2() called from thread"); if (! main_thread()) zappcrash("zmessage_choose2() called from thread");
va_start(arglist,message); va_start(arglist,message);
for (ii = 0; ii < 5; ii++) for (ii = 0; ii < 5; ii++)
{ {
butn[ii] = va_arg(arglist,cchar *); butn[ii] = va_arg(arglist,ch *);
if (! butn[ii] || butn[ii] == (cchar *) 0x100000000) break; if (! butn[ii] || butn[ii] == (ch *) 0x100000000) break;
// ARM bug // ARM bug
} }
Nbutn = ii; Nbutn = ii;
if (! Nbutn) zappcrash("zdialog_choose(), no buttons"); if (! Nbutn) zappcrash("zdialog_choose(), no buttons");
zd = zdialog_new("choose",parent,butn[0],butn[1],butn[2],butn[3],butn[4],null ); zd = zdialog_new("choose",parent,butn[0],butn[1],butn[2],butn[3],butn[4],null );
zdialog_add_widget(zd,"hbox","hbmess","dialog","space=3"); zdialog_add_widget(zd,"hbox","hbmess","dialog","space=3");
zdialog_add_widget(zd,"label","labmess","hbmess",message,"space=5"); zdialog_add_widget(zd,"label","labmess","hbmess",message,"space=5");
zdialog_set_modal(zd); zdialog_set_modal(zd);
zdialog_resize(zd,200,0); zdialog_resize(zd,200,0);
skipping to change at line 11573 skipping to change at line 11592
G_SIGNAL(widget,"key-press-event",zdialog_choose2_KBevent,zd); G_SIGNAL(widget,"key-press-event",zdialog_choose2_KBevent,zd);
zdialog_run(zd,zdialog_choose2_event,where); zdialog_run(zd,zdialog_choose2_event,where);
zstat = zdialog_wait(zd); zstat = zdialog_wait(zd);
zdialog_free(zd); zdialog_free(zd);
return zstat; return zstat;
} }
// button events and [x] event // button events and [x] event
int zdialog_choose2_event(zdialog *zd, cchar *event) int zdialog_choose2_event(zdialog *zd, ch *event)
{ {
if (strmatch(event,"escape")) zd->zstat = -2; // escape key if (strmatch(event,"escape")) zd->zstat = -2; // escape key
if (! zd->zstat) return 1; if (! zd->zstat) return 1;
zdialog_destroy(zd); // a button was pressed zdialog_destroy(zd); // a button was pressed
return 1; return 1;
} }
// KB input events // KB input events
int zdialog_choose2_KBevent(GtkWidget *, GdkEventKey *event, zdialog *zd) int zdialog_choose2_KBevent(GtkWidget *, GdkEventKey *event, zdialog *zd)
skipping to change at line 11606 skipping to change at line 11625
} }
return 0; return 0;
} }
/******************************************************************************* */ /******************************************************************************* */
// popup a list of characters and text strings for insertion // popup a list of characters and text strings for insertion
// into the currently active GtkTextView widget // into the currently active GtkTextView widget
char popup_text_textfile[XFCC]; ch popup_text_textfile[XFCC];
void zdialog_popup_text(cchar *textfile, GtkWidget *parent) // 22.15 void zdialog_popup_text(ch *textfile, GtkWidget *parent) // 22.15
{ {
void popup_text_clickfunc(GtkWidget *poptext, int line, int posn, int kbkey); void popup_text_clickfunc(GtkWidget *poptext, int line, int posn, int kbkey);
zdialog *zd; zdialog *zd;
zlist_t *zlist; zlist_t *zlist;
char *pp; ch *pp;
int ii; int ii;
zlist = zlist_from_file(textfile); zlist = zlist_from_file(textfile);
if (! zlist) { if (! zlist) {
zmessageACK(parent,"file not found: %s",textfile); zmessageACK(parent,"file not found: %s",textfile);
return; return;
} }
strncpy0(popup_text_textfile,textfile,XFCC); strncpy0(popup_text_textfile,textfile,XFCC);
zd = popup_report_open("Popup Text",parent,400,400,0,popup_text_clickfunc,"Ed zd = popup_report_open("Popup Text",parent,400,400,0,
it","OK",0); // 22.16 popup_text_clickfunc,"Edit","OK",0);
// 22.16
for (ii = 0; ii < zlist_count(zlist); ii++) for (ii = 0; ii < zlist_count(zlist); ii++)
{ {
pp = zlist_get(zlist,ii); pp = zlist_get(zlist,ii);
if (pp) popup_report_write(zd,0,"%s \n",pp); if (pp) popup_report_write(zd,0,"%s \n",pp);
} }
return; return;
} }
// Receive clicks on text report and get selected text. // Receive clicks on text report and get selected text.
// Insert into widget: GtkTextView *curr_text_view (fotoxx.h) // Insert into widget: GtkTextView *curr_text_view (fotoxx.h)
void popup_text_clickfunc(GtkWidget *poptext, int line, int posn, int kbkey) void popup_text_clickfunc(GtkWidget *poptext, int line, int posn, int kbkey)
{ {
using namespace zfuncs; using namespace zfuncs;
char *pp, dlim; ch *pp, dlim;
int cc; int cc;
GtkWindow *window; GtkWindow *window;
GtkTextBuffer *textbuffer; GtkTextBuffer *textbuffer;
GtkWidget *widget; GtkWidget *widget;
if (kbkey == 'E') { // [Edit] 22.16 if (kbkey == 'E') { // [Edit] 22.16
zshell("ack","xdg-open %s",popup_text_textfile); zshell("ack","xdg-open %s",popup_text_textfile);
return; return;
} }
skipping to change at line 11694 skipping to change at line 11714
Fheader add optional non-scrolling header at top of report window Fheader add optional non-scrolling header at top of report window
CBfunc optional callback function: CBfunc optional callback function:
CBfunc(GtkWidget *, int line, int posn, int KBkey) CBfunc(GtkWidget *, int line, int posn, int KBkey)
... optional event buttons terminated with null: ... optional event buttons terminated with null:
[OK] [Hide] [Find] [Save] [Esc] are processed here [OK] [Hide] [Find] [Save] [Esc] are processed here
others are passed to callback function (1st character) others are passed to callback function (1st character)
zdialog->zstat = 1/2 for buttons [ OK ] / [Cancel] zdialog->zstat = 1/2 for buttons [ OK ] / [Cancel]
***/ ***/
zdialog * popup_report_open(cchar *title, GtkWidget *parent, int ww, int hh, zdialog * popup_report_open(ch *title, GtkWidget *parent, int ww, int hh,
int Fheader, textwidget_callbackfunc_t CBfunc, ...) int Fheader, textwidget_callbackfunc_t CBfunc, ...)
{ {
int popup_report_dialog_event(zdialog *zd, cchar *event); int popup_report_dialog_event(zdialog *zd, ch *event);
va_list arglist; va_list arglist;
cchar *butn[9]; ch *butn[9];
int ii, NB; int ii, NB;
zdialog *zd; zdialog *zd;
GtkWidget *mHead, *mText; GtkWidget *mHead, *mText;
va_start(arglist,CBfunc); // get button args, if any va_start(arglist,CBfunc); // get button args, if any
for (ii = 0; ii < 9; ii++) { // up to 9 buttons for (ii = 0; ii < 9; ii++) { // up to 9 buttons
butn[ii] = va_arg(arglist,cchar *); butn[ii] = va_arg(arglist,ch *);
if (! butn[ii] || butn[ii] == (cchar *) 0x100000000) break; if (! butn[ii] || butn[ii] == (ch *) 0x100000000) break;
// ARM bug // ARM bug
} }
NB = ii; // no. buttons NB = ii; // no. buttons
zd = zdialog_new(title,parent,null); zd = zdialog_new(title,parent,null);
if (Fheader) { // non-scrolling header if (Fheader) { // non-scrolling header
zdialog_add_widget(zd,"text","header","dialog"); zdialog_add_widget(zd,"text","header","dialog");
zdialog_add_widget(zd,"hsep","hsep","dialog"); zdialog_add_widget(zd,"hsep","hsep","dialog");
} }
skipping to change at line 11750 skipping to change at line 11770
gtk_widget_grab_focus(mText); gtk_widget_grab_focus(mText);
textwidget_set_eventfunc(mText,CBfunc); // set mouse/KB event function textwidget_set_eventfunc(mText,CBfunc); // set mouse/KB event function
zd->popup_report_CB = (void *) CBfunc; zd->popup_report_CB = (void *) CBfunc;
return zd; return zd;
} }
// dialog event and completion function [OK] [Hide] [Find] [Save] [Esc] // dialog event and completion function [OK] [Hide] [Find] [Save] [Esc]
int popup_report_dialog_event(zdialog *zd, cchar *event) int popup_report_dialog_event(zdialog *zd, ch *event)
{ {
textwidget_callbackfunc_t *CBfunc; textwidget_callbackfunc_t *CBfunc;
GtkWidget *mText; GtkWidget *mText;
static char findtext[40] = ""; static ch findtext[40] = "";
int linem, line1, line2; int linem, line1, line2;
zdialog *zdf; zdialog *zdf;
if (! zdialog_valid(zd)) { Plog(1,"report cancelled \n"); return 1; } if (! zdialog_valid(zd)) return 1; // report cancelled 23.1
if (strmatch(event,"focus")) return 0; if (strmatch(event,"focus")) return 0;
if (zd->zstat) { // [x] cancel or escape, kill dialog if (zd->zstat) { // [x] cancel or escape, kill dialog
zdialog_free(zd); zdialog_free(zd);
Plog(0,"report cancelled \n");
return 1; return 1;
} }
if (strmatch(event,"Hide")) { // [Hide] hide dialog 22.15 if (strmatch(event,"Hide")) { // [Hide] hide dialog 22.15
zdialog_show(zd,0); zdialog_show(zd,0);
return 1; return 1;
} }
if (strmatch(event,"OK")) { // [OK] kill dialog 22.15 if (strmatch(event,"OK")) { // [OK] kill dialog 22.15
zdialog_free(zd); zdialog_free(zd);
Plog(0,"report cancelled \n");
return 1; return 1;
} }
if (strmatch(event,"escape")) { if (strmatch(event,"escape")) {
// Escape key kill dialog 22.15 // Escape key kill dialog 23.1
zdialog_show(zd,0); zdialog_free(zd);
Plog(0,"report cancelled \n");
return 1; return 1;
} }
if (strmatch(event,"Find")) { // [Find] if (strmatch(event,"Find")) { // [Find]
zdf = zdialog_new("find text",zd->dialog,"Find","Cancel",0); // popup dialog to enter text zdf = zdialog_new("find text",zd->dialog,"Find","Cancel",0); // popup dialog to enter text
zdialog_add_widget(zdf,"zentry","text","dialog",findtext,"size=20"); zdialog_add_widget(zdf,"zentry","text","dialog",findtext,"size=20");
zdialog_run(zdf,0,"mouse"); zdialog_run(zdf,0,"mouse");
linem = -1; // no match line yet linem = -1; // no match line yet
while (true) while (true)
{ {
skipping to change at line 11822 skipping to change at line 11845
mText = zdialog_gtkwidget(zd,"text"); mText = zdialog_gtkwidget(zd,"text");
CBfunc = (textwidget_callbackfunc_t *) zd->popup_report_CB; // other event CBfunc = (textwidget_callbackfunc_t *) zd->popup_report_CB; // other event
if (CBfunc) CBfunc(mText,-1,-1,*event); // pass to callback function (1st char.) if (CBfunc) CBfunc(mText,-1,-1,*event); // pass to callback function (1st char.)
return 1; return 1;
} }
// write a non-scrolling header line // write a non-scrolling header line
void popup_report_header(zdialog *zd, int bold, cchar *format, ...) void popup_report_header(zdialog *zd, int bold, ch *format, ...)
{ {
va_list arglist; va_list arglist;
char message[1000]; ch message[1000];
GtkWidget *mHead; GtkWidget *mHead;
if (! zdialog_valid(zd)) { Plog(1,"report cancelled \n"); return; } if (! zdialog_valid(zd)) { Plog(1,"report cancelled \n"); return; }
va_start(arglist,format); va_start(arglist,format);
vsnprintf(message,999,format,arglist); vsnprintf(message,999,format,arglist);
va_end(arglist); va_end(arglist);
mHead = zdialog_gtkwidget(zd,"header"); mHead = zdialog_gtkwidget(zd,"header");
textwidget_append(mHead,bold,message); textwidget_append(mHead,bold,message);
gtk_widget_set_visible(mHead,1); gtk_widget_set_visible(mHead,1);
return; return;
} }
// write a new text line at the end // write a new text line at the end
void popup_report_write(zdialog *zd, int bold, cchar *format, ...) void popup_report_write(zdialog *zd, int bold, ch *format, ...)
{ {
va_list arglist; va_list arglist;
char message[1000]; ch message[1000];
GtkWidget *mText; GtkWidget *mText;
if (! zdialog_valid(zd)) { Plog(1,"report cancelled \n"); return; } if (! zdialog_valid(zd)) { Plog(1,"report cancelled \n"); return; }
va_start(arglist,format); va_start(arglist,format);
vsnprintf(message,999,format,arglist); vsnprintf(message,999,format,arglist);
va_end(arglist); va_end(arglist);
mText = zdialog_gtkwidget(zd,"text"); mText = zdialog_gtkwidget(zd,"text");
textwidget_append(mText,bold,"%s",message); textwidget_append(mText,bold,"%s",message);
return; return;
} }
// write a new text line at the end, scroll down to end // write a new text line at the end, scroll down to end
void popup_report_write2(zdialog *zd, int bold, cchar *format, ...) void popup_report_write2(zdialog *zd, int bold, ch *format, ...)
{ {
va_list arglist; va_list arglist;
char message[1000]; ch message[1000];
GtkWidget *mText; GtkWidget *mText;
if (! zdialog_valid(zd)) { Plog(1,"report cancelled \n"); return; } if (! zdialog_valid(zd)) { Plog(1,"report cancelled \n"); return; }
va_start(arglist,format); va_start(arglist,format);
vsnprintf(message,999,format,arglist); vsnprintf(message,999,format,arglist);
va_end(arglist); va_end(arglist);
mText = zdialog_gtkwidget(zd,"text"); mText = zdialog_gtkwidget(zd,"text");
textwidget_append2(mText,bold,"%s",message); textwidget_append2(mText,bold,"%s",message);
skipping to change at line 11917 skipping to change at line 11940
void popup_report_clear(zdialog *zd, int line) void popup_report_clear(zdialog *zd, int line)
{ {
GtkWidget *mText = zdialog_gtkwidget(zd,"text"); GtkWidget *mText = zdialog_gtkwidget(zd,"text");
textwidget_clear(mText,line); textwidget_clear(mText,line);
return; return;
} }
// insert a new line after a given line // insert a new line after a given line
void popup_report_insert(zdialog *zd, int bold, int line, cchar *format, ...) void popup_report_insert(zdialog *zd, int bold, int line, ch *format, ...)
{ {
va_list arglist; va_list arglist;
char message[1000]; ch message[1000];
GtkWidget *mText; GtkWidget *mText;
va_start(arglist,format); va_start(arglist,format);
vsnprintf(message,999,format,arglist); vsnprintf(message,999,format,arglist);
va_end(arglist); va_end(arglist);
if (! zdialog_valid(zd)) { Plog(1,"report cancelled \n"); return; } if (! zdialog_valid(zd)) { Plog(1,"report cancelled \n"); return; }
mText = zdialog_gtkwidget(zd,"text"); mText = zdialog_gtkwidget(zd,"text");
textwidget_insert(mText,bold,line,message); textwidget_insert(mText,bold,line,message);
return; return;
} }
// replace a given line // replace a given line
void popup_report_replace(zdialog *zd, int bold, int line, cchar *format, ...) void popup_report_replace(zdialog *zd, int bold, int line, ch *format, ...)
{ {
va_list arglist; va_list arglist;
char message[1000]; ch message[1000];
GtkWidget *mText; GtkWidget *mText;
va_start(arglist,format); va_start(arglist,format);
vsnprintf(message,999,format,arglist); vsnprintf(message,999,format,arglist);
va_end(arglist); va_end(arglist);
if (! zdialog_valid(zd)) { Plog(1,"report cancelled \n"); return; } if (! zdialog_valid(zd)) { Plog(1,"report cancelled \n"); return; }
mText = zdialog_gtkwidget(zd,"text"); mText = zdialog_gtkwidget(zd,"text");
textwidget_replace(mText,bold,line,message); textwidget_replace(mText,bold,line,message);
skipping to change at line 11967 skipping to change at line 11990
GtkWidget *mText = zdialog_gtkwidget(zd,"text"); GtkWidget *mText = zdialog_gtkwidget(zd,"text");
textwidget_delete(mText,line); textwidget_delete(mText,line);
return; return;
} }
// find first line of text containing characters matching input string // find first line of text containing characters matching input string
// search is from line1 to end, then from 0 to line1-1 // search is from line1 to end, then from 0 to line1-1
// returns first matching line or -1 if none // returns first matching line or -1 if none
// comparison is not case sensitive // comparison is not case sensitive
int popup_report_find(zdialog *zd, char *matchtext, int line1) int popup_report_find(zdialog *zd, ch *matchtext, int line1)
{ {
if (! zdialog_valid(zd)) { Plog(1,"report cancelled \n"); return 1; } if (! zdialog_valid(zd)) { Plog(1,"report cancelled \n"); return 1; }
GtkWidget *mText = zdialog_gtkwidget(zd,"text"); GtkWidget *mText = zdialog_gtkwidget(zd,"text");
return textwidget_find(mText,matchtext,line1); return textwidget_find(mText,matchtext,line1);
} }
// insert a pixbuf image after a given line // insert a pixbuf image after a given line
void popup_report_insert_pixbuf(zdialog *zd, int line, GdkPixbuf *pixbuf) void popup_report_insert_pixbuf(zdialog *zd, int line, GdkPixbuf *pixbuf)
{ {
skipping to change at line 12016 skipping to change at line 12039
void popup_report_get_visible_lines(zdialog *zd, int &vtop, int &vbott) void popup_report_get_visible_lines(zdialog *zd, int &vtop, int &vbott)
{ {
if (! zdialog_valid(zd)) { Plog(1,"report cancelled \n"); return; } if (! zdialog_valid(zd)) { Plog(1,"report cancelled \n"); return; }
GtkWidget *mText = zdialog_gtkwidget(zd,"text"); GtkWidget *mText = zdialog_gtkwidget(zd,"text");
textwidget_get_visible_lines(mText,vtop,vbott); textwidget_get_visible_lines(mText,vtop,vbott);
return; return;
} }
// retrieve a given line and optionally strip the trailing \n // retrieve a given line and optionally strip the trailing \n
char * popup_report_line(zdialog *zd, int line, int strip) ch * popup_report_line(zdialog *zd, int line, int strip)
{ {
if (! zdialog_valid(zd)) { Plog(1,"report cancelled \n"); return 0; } if (! zdialog_valid(zd)) { Plog(1,"report cancelled \n"); return 0; }
GtkWidget *mText = zdialog_gtkwidget(zd,"text"); GtkWidget *mText = zdialog_gtkwidget(zd,"text");
return textwidget_line(mText,line,strip); return textwidget_line(mText,line,strip);
} }
// retrieve the word starting at a given position in a given line // retrieve the word starting at a given position in a given line
char * popup_report_word(zdialog *zd, int line, int posn, cchar *dlims, char &en d) ch * popup_report_word(zdialog *zd, int line, int posn, ch *dlims, ch &end)
{ {
GtkWidget *mText = zdialog_gtkwidget(zd,"text"); GtkWidget *mText = zdialog_gtkwidget(zd,"text");
return textwidget_word(mText,line,posn,dlims,end); return textwidget_word(mText,line,posn,dlims,end);
} }
// highlight a given line of text // highlight a given line of text
void popup_report_highlight_line(zdialog *zd, int line) void popup_report_highlight_line(zdialog *zd, int line)
{ {
if (! zdialog_valid(zd)) { Plog(1,"report cancelled \n"); return; } if (! zdialog_valid(zd)) { Plog(1,"report cancelled \n"); return; }
skipping to change at line 12113 skipping to change at line 12136
if (! zdialog_valid(zd)) return; if (! zdialog_valid(zd)) return;
zdialog_free(zd); zdialog_free(zd);
return; return;
} }
/******************************************************************************* */ /******************************************************************************* */
// execute a shell command and show the output in a scrolling popup window // execute a shell command and show the output in a scrolling popup window
// returns: 0 = EOF 1 = command failure // returns: 0 = EOF 1 = command failure
int popup_command(cchar *command, int ww, int hh, GtkWidget *parent, int top) int popup_command(ch *command, int ww, int hh, GtkWidget *parent, int top)
{ {
FILE *fid; FILE *fid;
char buff[1000], *pp; ch buff[1000], *pp;
zdialog *zd; zdialog *zd;
Plog(1,"run command: %s \n",command); Plog(1,"run command: %s \n",command);
zd = popup_report_open(command,parent,ww,hh,0,0,"Find","Save","OK",0); zd = popup_report_open(command,parent,ww,hh,0,0,"Find","Save","OK",0);
fid = popen(command,"r"); fid = popen(command,"r");
if (! fid) return 1; if (! fid) return 1;
while (true) { while (true) {
pp = fgets_trim(buff,1000,fid); pp = fgets_trim(buff,1000,fid);
skipping to change at line 12142 skipping to change at line 12165
if (top) popup_report_top(zd); // back to top of window if (top) popup_report_top(zd); // back to top of window
return 0; return 0;
} }
/******************************************************************************* */ /******************************************************************************* */
// Display popup message box and wait for user acknowledgement. // Display popup message box and wait for user acknowledgement.
// May be called from a thread. // May be called from a thread.
// Messages are presented sequentially from main() and from threads. // Messages are presented sequentially from main() and from threads.
void zmessageACK(GtkWidget *parent, cchar *format, ... ) void zmessageACK(GtkWidget *parent, ch *format, ... )
{ {
va_list arglist; va_list arglist;
char message[2000]; ch message[2000];
cchar *posn; ch *posn;
zdialog *zd; zdialog *zd;
va_start(arglist,format); // format the message va_start(arglist,format); // format the message
vsnprintf(message,2000,format,arglist); vsnprintf(message,2000,format,arglist);
va_end(arglist); va_end(arglist);
Plog(1,"%s \n",message); // output to log file Plog(1,"%s \n",message); // output to log file
if (! main_thread()) { // caller is a thread if (! main_thread()) { // caller is a thread
xmessage(message); xmessage(message);
skipping to change at line 12180 skipping to change at line 12203
zdialog_wait(zd); zdialog_wait(zd);
zdialog_free(zd); zdialog_free(zd);
return; return;
} }
/******************************************************************************* */ /******************************************************************************* */
// display message box and wait for user Yes or No response // display message box and wait for user Yes or No response
// returns 1 or 0 // returns 1 or 0
int zmessageYN(GtkWidget *parent, cchar *format, ... ) int zmessageYN(GtkWidget *parent, ch *format, ... )
{ {
va_list arglist; va_list arglist;
char message[500]; ch message[500];
cchar *posn; ch *posn;
zdialog *zd; zdialog *zd;
int zstat; int zstat;
va_start(arglist,format); va_start(arglist,format);
vsnprintf(message,500,format,arglist); vsnprintf(message,500,format,arglist);
va_end(arglist); va_end(arglist);
Plog(1,"%s \n",message); // output to log file Plog(1,"%s \n",message); // output to log file
if (! main_thread()) zappcrash("zmessageYN() called from thread"); if (! main_thread()) zappcrash("zmessageYN() called from thread");
skipping to change at line 12229 skipping to change at line 12252
// "parent" = center on parent window // "parent" = center on parent window
// "nn/nn" = position NW corner at relative x/y position in parent window, // "nn/nn" = position NW corner at relative x/y position in parent window,
// where nn/nn is a percent 0-100 of the parent window dimensions. // where nn/nn is a percent 0-100 of the parent window dimensions.
// seconds: time to keep message on screen, 0 = forever until cancelled // seconds: time to keep message on screen, 0 = forever until cancelled
typedef struct { typedef struct {
zdialog *zd; zdialog *zd;
int uniqueID; int uniqueID;
} zdx_t; } zdx_t;
zdialog * zmessage_post(GtkWidget *parent, cchar *posn, int seconds, cchar *form at, ... ) zdialog * zmessage_post(GtkWidget *parent, ch *posn, int seconds, ch *format, .. . )
{ {
int zmessage_post_timeout(zdx_t *zdx); int zmessage_post_timeout(zdx_t *zdx);
va_list arglist; va_list arglist;
char message[1000]; ch message[1000];
static zdx_t zdx[100]; static zdx_t zdx[100];
static int ii = 0; static int ii = 0;
zdialog *zd; zdialog *zd;
va_start(arglist,format); va_start(arglist,format);
vsnprintf(message,1000,format,arglist); vsnprintf(message,1000,format,arglist);
va_end(arglist); va_end(arglist);
Plog(1,"%s \n",message); // output to log file Plog(1,"%s \n",message); // output to log file
skipping to change at line 12271 skipping to change at line 12294
zdx[ii].zd = zd; zdx[ii].zd = zd;
zdx[ii].uniqueID = zd->uniqueID; zdx[ii].uniqueID = zd->uniqueID;
g_timeout_add_seconds(seconds,(GSourceFunc) zmessage_post_timeout,&zdx[ii] ); g_timeout_add_seconds(seconds,(GSourceFunc) zmessage_post_timeout,&zdx[ii] );
} }
return zd; return zd;
} }
// same as above, but message is big, bold and red // same as above, but message is big, bold and red
zdialog * zmessage_post_bold(GtkWidget *parent, cchar *posn, int seconds, cchar *format, ... ) zdialog * zmessage_post_bold(GtkWidget *parent, ch *posn, int seconds, ch *forma t, ... )
{ {
int zmessage_post_timeout(zdx_t *zdx); int zmessage_post_timeout(zdx_t *zdx);
va_list arglist; va_list arglist;
char message[400], messagebold[460]; ch message[400], messagebold[460];
static zdx_t zdx[100]; static zdx_t zdx[100];
static int ii = 0; static int ii = 0;
zdialog *zd; zdialog *zd;
va_start(arglist,format); va_start(arglist,format);
vsnprintf(message,400,format,arglist); vsnprintf(message,400,format,arglist);
va_end(arglist); va_end(arglist);
Plog(1,"%s \n",message); // output to log file Plog(1,"%s \n",message); // output to log file
skipping to change at line 12324 skipping to change at line 12347
if (zd->uniqueID != zdx->uniqueID) return 0; if (zd->uniqueID != zdx->uniqueID) return 0;
zdialog_free(zd); zdialog_free(zd);
return 0; return 0;
} }
/******************************************************************************* */ /******************************************************************************* */
// functions to show popup text windows // functions to show popup text windows
namespace poptext { namespace poptext {
char *ptext = 0; ch *ptext = 0;
GtkWidget *popwin = 0; GtkWidget *popwin = 0;
char *pcurrent = 0; ch *pcurrent = 0;
#define GSFNORMAL GTK_STATE_FLAG_NORMAL #define GSFNORMAL GTK_STATE_FLAG_NORMAL
} }
// timer function to show popup window after a given time // timer function to show popup window after a given time
int poptext_show(char *current) int poptext_show(ch *current)
{ {
using namespace poptext; using namespace poptext;
if (current != pcurrent) return 0; if (current != pcurrent) return 0;
if (popwin) gtk_widget_show_all(popwin); if (popwin) gtk_widget_show_all(popwin);
return 0; return 0;
} }
// timer function to kill popup window after a given time // timer function to kill popup window after a given time
int poptext_timeout(char *current) int poptext_timeout(ch *current)
{ {
using namespace poptext; using namespace poptext;
if (current != pcurrent) return 0; if (current != pcurrent) return 0;
if (popwin) gtk_widget_destroy(popwin); if (popwin) gtk_widget_destroy(popwin);
if (ptext) zfree(ptext); if (ptext) zfree(ptext);
popwin = 0; popwin = 0;
ptext = 0; ptext = 0;
return 0; return 0;
} }
// Show a popup text message at a given absolute screen position. // Show a popup text message at a given absolute screen position.
// Any prior popup will be killed and replaced. // Any prior popup will be killed and replaced.
// If text == null, kill without replacement. // If text == null, kill without replacement.
// secs1 is time to delay before showing the popup. // secs1 is time to delay before showing the popup.
// secs2 is time to kill the popup after it is shown (0 = never). // secs2 is time to kill the popup after it is shown (0 = never).
// This function returns immediately. // This function returns immediately.
void poptext_screen(cchar *text, int px, int py, float secs1, float secs2) void poptext_screen(ch *text, int px, int py, float secs1, float secs2)
{ {
using namespace poptext; using namespace poptext;
GtkWidget *label; GtkWidget *label;
int cc, millisec1, millisec2; int cc, millisec1, millisec2;
if (! main_thread()) zappcrash("poptext_screen() called from thread"); if (! main_thread()) zappcrash("poptext_screen() called from thread");
poptext_killnow(); poptext_killnow();
pcurrent++; // make current != pcurrent pcurrent++; // make current != pcurrent
if (! text) return; if (! text) return;
cc = strlen(text) + 4; // construct popup window cc = strlen(text) + 4; // construct popup window
ptext = (char *) zmalloc(cc,"poptext"); // with caller's text ptext = (ch *) zmalloc(cc,"poptext"); // with caller's text
*ptext = 0; *ptext = 0;
strncatv(ptext,cc," ",text," ",null); // add extra spaces strncatv(ptext,cc," ",text," ",null); // add extra spaces
popwin = gtk_window_new(GTK_WINDOW_POPUP); popwin = gtk_window_new(GTK_WINDOW_POPUP);
label = gtk_label_new(ptext); label = gtk_label_new(ptext);
gtk_container_add(GTK_CONTAINER(popwin),label); gtk_container_add(GTK_CONTAINER(popwin),label);
gtk_window_move(GTK_WINDOW(popwin),px,py); gtk_window_move(GTK_WINDOW(popwin),px,py);
if (secs1 > 0) { // delayed popup display if (secs1 > 0) { // delayed popup display
millisec1 = secs1 * 1000; millisec1 = secs1 * 1000;
g_timeout_add(millisec1,(GSourceFunc) poptext_show,pcurrent); g_timeout_add(millisec1,(GSourceFunc) poptext_show,pcurrent);
skipping to change at line 12402 skipping to change at line 12425
if (secs2 > 0) { // popup kill timer if (secs2 > 0) { // popup kill timer
millisec2 = (secs1 + secs2) * 1000; millisec2 = (secs1 + secs2) * 1000;
g_timeout_add(millisec2,(GSourceFunc) poptext_timeout,pcurrent); g_timeout_add(millisec2,(GSourceFunc) poptext_timeout,pcurrent);
} }
return; return;
} }
// Show a popup text message at current mouse position + offsets. // Show a popup text message at current mouse position + offsets.
void poptext_mouse(cchar *text, int dx, int dy, float secs1, float secs2) void poptext_mouse(ch *text, int dx, int dy, float secs1, float secs2)
{ {
int mx, my; int mx, my;
if (! main_thread()) zappcrash("poptext_mouse() called from thread"); if (! main_thread()) zappcrash("poptext_mouse() called from thread");
if (! text) { if (! text) {
poptext_killnow(); poptext_killnow();
return; return;
} }
gdk_device_get_position(zfuncs::mouse,0,&mx,&my); // mouse screen position gdk_device_get_position(zfuncs::mouse,0,&mx,&my); // mouse screen position
poptext_screen(text,mx+dx,my+dy,secs1,secs2); // add displacements poptext_screen(text,mx+dx,my+dy,secs1,secs2); // add displacements
return; return;
} }
// Show a popup text message at the given window position. // Show a popup text message at the given window position.
void poptext_window(GtkWindow *win, cchar *text, int dx, int dy, float secs1, fl oat secs2) void poptext_window(GtkWindow *win, ch *text, int dx, int dy, float secs1, float secs2)
{ {
int px, py; int px, py;
if (! main_thread()) zappcrash("poptext_window() called from thread"); if (! main_thread()) zappcrash("poptext_window() called from thread");
if (! text) { if (! text) {
poptext_killnow(); poptext_killnow();
return; return;
} }
gtk_window_get_position(win,&px,&py); gtk_window_get_position(win,&px,&py);
poptext_screen(text,px+dx,py+dy,secs1,secs2); poptext_screen(text,px+dx,py+dy,secs1,secs2);
return; return;
} }
// Show a popup text message at the given widget position. // Show a popup text message at the given widget position.
void poptext_widget(GtkWidget *widget, cchar *text, int dx, int dy, float secs1, float secs2) void poptext_widget(GtkWidget *widget, ch *text, int dx, int dy, float secs1, fl oat secs2)
{ {
GdkWindow *win; GdkWindow *win;
int px, py; int px, py;
if (! main_thread()) zappcrash("poptext_widget() called from thread"); if (! main_thread()) zappcrash("poptext_widget() called from thread");
if (! text) { if (! text) {
poptext_killnow(); poptext_killnow();
return; return;
} }
skipping to change at line 12475 skipping to change at line 12498
/******************************************************************************* */ /******************************************************************************* */
// Show an image file in a popup window at mouse position. // Show an image file in a popup window at mouse position.
// Re-use most recent window or create a new one if Fnewin != 0. // Re-use most recent window or create a new one if Fnewin != 0.
// Returns 0 if OK, +N otherwise. // Returns 0 if OK, +N otherwise.
namespace popup_image_names namespace popup_image_names
{ {
GtkWidget *window[10], *drawarea[10]; // up to 10 popup windows open GtkWidget *window[10], *drawarea[10]; // up to 10 popup windows open
char *filex[10], reqfull[10], isfull[10]; ch *filex[10], reqfull[10], isfull[10];
int Nval[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; int Nval[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
float winc = 1.26, wdec = 0.80; // window upsize/downsize ratios 22.40 float winc = 1.26, wdec = 0.80; // window upsize/downsize ratios 22.40
int Nw = 0; int Nw = 0;
} }
int popup_image(cchar *file, GtkWindow *parent, int Fnewin, int size) int popup_image(ch *file, GtkWindow *parent, int Fnewin, int size)
{ {
using namespace popup_image_names; using namespace popup_image_names;
static int ftf = 1; static int ftf = 1;
cchar *pp; ch *pp;
cchar *tipmess("zoom via mouse wheel or Keys +/=/-/↑/↓"); ch *tipmess("zoom via mouse wheel or Keys +/=/-/↑/↓");
int popup_image_draw(GtkWidget *, cairo_t *, int &Nw); int popup_image_draw(GtkWidget *, cairo_t *, int &Nw);
int popup_image_scroll(GtkWidget *, GdkEvent *event, int &Nw); int popup_image_scroll(GtkWidget *, GdkEvent *event, int &Nw);
int popup_image_KBevent(GtkWidget *, GdkEventKey *event, int &Nw); int popup_image_KBevent(GtkWidget *, GdkEventKey *event, int &Nw);
int popup_image_mousebutt(GtkWidget *, GdkEvent *event, int &Nw); int popup_image_mousebutt(GtkWidget *, GdkEvent *event, int &Nw);
int popup_image_state_event(GtkWidget *, GdkEvent *, int &Nw); int popup_image_state_event(GtkWidget *, GdkEvent *, int &Nw);
if (! main_thread()) zappcrash("popup_image() called from thread"); if (! main_thread()) zappcrash("popup_image() called from thread");
if (ftf) { if (ftf) {
skipping to change at line 12560 skipping to change at line 12583<