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< |