/* code to read and manipulate the shared and private site files. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "xephem.h" extern char maincategory[]; static void read_files (void); static int sites_cmpf (const void * v1, const void * v2); static void create_sq_w (void); static void fill_list (void); static void buildNew (Widget w); static void buildDST (Widget mb_w, char *prompt, Widget *m_w, Widget *w_w, Widget *d_w, Widget *at_w); static void addButtons (Widget pd_w, char **names, int nnames); static void setMenuHistory (Widget w, int i); static void read_file (FILE *fp); static void scroll_sites (int i); static void sq_set_cb (Widget w, XtPointer client, XtPointer call); static void sq_search_cb (Widget w, XtPointer client, XtPointer call); static void sq_dblclick_cb (Widget w, XtPointer client, XtPointer call); static void sq_click_cb (Widget w, XtPointer client, XtPointer call); static void sq_help_cb (Widget w, XtPointer client, XtPointer call); static void sq_cancel_cb (Widget w, XtPointer client, XtPointer call); static void sq_create_cb (Widget w, XtPointer client, XtPointer call); static void sq_save_cb (Widget w, XtPointer client, XtPointer call); static void sq_setmain_cb (Widget w, XtPointer client, XtPointer call); static int buildNewSite (Site *sp); static char *nows (char *bp); static char *getTF (Widget w, char buf[], int bl); static int getPDmH (Widget pd); static Site *moreSites(void); static Widget sq_w; /* sites query form dialog */ static Widget sql_w; /* sites query scrolled list */ static Widget srtf_w; /* search text field */ static Widget settf_w; /* set text field */ static Widget newf_w; /* form to un/manage to show create */ static Widget nsn_w; /* new site name TF*/ static Widget nlt_w; /* new site lat TF */ static Widget nlg_w; /* new site long TF */ static Widget nel_w; /* new site elev TF */ static Widget nzn_w; /* new site tz name TF */ static Widget nzo_w; /* new site tz offset TF */ static Widget ndn_w; /* new site dst name */ static Widget ndo_w; /* new site dst offset TF */ static Widget dbm_w; /* dst beg month pulldown */ static Widget dbw_w; /* dst beg week pulldown */ static Widget dbd_w; /* dst beg day-of-week pulldown */ static Widget dbat_w; /* dst beg time TF */ static Widget dem_w; /* dst end month pulldown */ static Widget dew_w; /* dst end week pulldown */ static Widget ded_w; /* dst end day-of-week pulldown */ static Widget deat_w; /* dst end time TF */ #define MAXSITELLEN 512 /* maximum site file line length */ static Site *sites; /* malloced list of Sites */ static int nsites; /* number of entries in sites array */ static char sfn[] = "xephem_sites";/* xephem site file */ /* strings in dst begin/end pulldown * N.B. we don't use the string values, we presume to use children[] index */ static char *months[] = { "January ", "February ", "March ", "April ", "May ", "June ", "July ", "August ", "September", "October ", "November ", "December " }; static char *weeks[] = { "1", "2", "3", "4", "Last" }; static char *dow[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; static char twoam[] = " 2:00:00"; /* let user choose a site from a scrolled list */ void sites_manage() { if (!sites) read_files(); if (!sq_w) { create_sq_w(); fill_list(); } XtManageChild (sq_w); } /* give caller our list of sites, if wanted, but always return count */ int sites_get_list (Site **sipp) { if (!sites) read_files(); if (sipp) *sipp = sites; return (nsites); } /* search the sites list for one containing glob p. * start after the current selection in the list, if any. * return index into sites[] if find, else return -1. */ int sites_search (char *p) { int *poslist, poscount; int startpos; int flags; int i, n; /* read files if first time */ if (!sites) read_files(); /* decide where to start - resume if gui up, else just at front */ if (sql_w && XmListGetSelectedPos (sql_w, &poslist, &poscount)==True) { startpos = poslist[0]%nsites; /* 1-based so already +1 */ XtFree ((char *)poslist); } else startpos = 0; /* check each possible offset location starting at startpos. */ flags = 0; #if defined(FNM_CASEFOLD) /* GNU extension only */ flags |= FNM_CASEFOLD; #endif for (n = 0, i = startpos; n < nsites; n++, i = (i+1)%nsites) { Site *sip = &sites[i]; if (!fnmatch (p, sip->si_name, flags)) return (i); } return (-1); } /* fill ab[maxn] with an abbreviated version of full. * N.B. allow for full == NULL or full[0] == '\0'. */ void sites_abbrev (full, ab, maxn) char *full, ab[]; int maxn; { int fl; int n; /* check edge conditions */ if (!full || (fl = strlen(full)) == 0) return; /* just copy if it all fits ok */ if (fl < maxn-1) { (void) strcpy (ab, full); return; } /* clip off words from the right until short enough. * n is an index, not a count. */ for (n = fl-1; n >= maxn-4; ) { while (n > 0 && isalnum(full[n])) n--; while (n > 0 && (ispunct(full[n]) || isspace(full[n]))) n--; } (void) sprintf (ab, "%.*s...", n+1, full); } /* make the site selection dialog */ static void create_sq_w() { Widget w, cl_w, fr_w, add_w; Arg args[20]; int n; /* create outter form dialog */ n = 0; XtSetArg (args[n], XmNautoUnmanage, False); n++; XtSetArg (args[n], XmNverticalSpacing, 7); n++; XtSetArg (args[n], XmNhorizontalSpacing, 7); n++; XtSetArg (args[n], XmNcolormap, xe_cm); n++; XtSetArg (args[n], XmNmarginHeight, 10); n++; XtSetArg (args[n], XmNmarginWidth, 10); n++; XtSetArg (args[n], XmNdefaultPosition, False); n++; sq_w = XmCreateFormDialog(toplevel_w, "Sites", args, n); set_something (sq_w, XmNcolormap, (XtArgVal)xe_cm); XtAddCallback (sq_w, XmNhelpCallback, sq_help_cb, NULL); sr_reg (XtParent(sq_w), "XEphem*Sites.x", maincategory, 0); sr_reg (XtParent(sq_w), "XEphem*Sites.y", maincategory, 0); /* set some stuff in the parent DialogShell. * setting XmNdialogTitle in the Form didn't work.. */ n = 0; XtSetArg (args[n], XmNtitle, "xephem Site Selection"); n++; XtSetValues (XtParent(sq_w), args, n); /* make Close Add and Help across the bottom */ n = 0; XtSetArg (args[n], XmNbottomAttachment, XmATTACH_FORM); n++; XtSetArg (args[n], XmNleftAttachment, XmATTACH_POSITION); n++; XtSetArg (args[n], XmNleftPosition, 10); n++; XtSetArg (args[n], XmNrightAttachment, XmATTACH_POSITION); n++; XtSetArg (args[n], XmNrightPosition, 30); n++; cl_w = XmCreatePushButton (sq_w, "Close", args, n); wtip (cl_w, "Close this window"); XtAddCallback (cl_w, XmNactivateCallback, sq_cancel_cb, NULL); XtManageChild (cl_w); n = 0; XtSetArg (args[n], XmNbottomAttachment, XmATTACH_FORM); n++; XtSetArg (args[n], XmNleftAttachment, XmATTACH_POSITION); n++; XtSetArg (args[n], XmNleftPosition, 40); n++; XtSetArg (args[n], XmNrightAttachment, XmATTACH_POSITION); n++; XtSetArg (args[n], XmNrightPosition, 60); n++; add_w = XmCreateToggleButton (sq_w, "Create", args, n); wtip (add_w, "Build a new site definition"); wtip (add_w, "Show fields to build a new site entry"); XtAddCallback (add_w, XmNvalueChangedCallback, sq_create_cb, NULL); XtManageChild (add_w); n = 0; XtSetArg (args[n], XmNbottomAttachment, XmATTACH_FORM); n++; XtSetArg (args[n], XmNleftAttachment, XmATTACH_POSITION); n++; XtSetArg (args[n], XmNleftPosition, 70); n++; XtSetArg (args[n], XmNrightAttachment, XmATTACH_POSITION); n++; XtSetArg (args[n], XmNrightPosition, 90); n++; w = XmCreatePushButton (sq_w, "Help", args, n); wtip (w, "Get more info about this window"); XtAddCallback (w, XmNactivateCallback, sq_help_cb, NULL); XtManageChild (w); /* build new section */ n = 0; XtSetArg (args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++; XtSetArg (args[n], XmNbottomWidget, cl_w); n++; XtSetArg (args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg (args[n], XmNrightAttachment, XmATTACH_FORM); n++; fr_w = XmCreateFrame (sq_w, "New", args, n); XtManageChild (fr_w); buildNew (fr_w); /* make a PB and TF to enter the set string above that */ n = 0; XtSetArg (args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++; XtSetArg (args[n], XmNbottomWidget, fr_w); n++; XtSetArg (args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg (args[n], XmNrightAttachment, XmATTACH_POSITION); n++; XtSetArg (args[n], XmNrightPosition, 20); n++; w = XmCreatePushButton (sq_w, "Set", args, n); XtAddCallback (w, XmNactivateCallback, sq_set_cb, NULL); wtip (w, "Set Main site to string at right"); XtManageChild (w); n = 0; XtSetArg (args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++; XtSetArg (args[n], XmNbottomWidget, fr_w); n++; XtSetArg (args[n], XmNleftAttachment, XmATTACH_WIDGET); n++; XtSetArg (args[n], XmNleftWidget, w); n++; XtSetArg (args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg (args[n], XmNcolumns, 30); n++; settf_w = XmCreateTextField (sq_w, "SetTF", args, n); wtip (settf_w, "Candidate site"); XtAddCallback (settf_w, XmNactivateCallback, sq_set_cb, NULL); XtManageChild (settf_w); /* make a PB and TF to enter the search string above that */ n = 0; XtSetArg (args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++; XtSetArg (args[n], XmNbottomWidget, settf_w); n++; XtSetArg (args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg (args[n], XmNrightAttachment, XmATTACH_POSITION); n++; XtSetArg (args[n], XmNrightPosition, 20); n++; w = XmCreatePushButton (sq_w, "Search", args, n); XtAddCallback (w, XmNactivateCallback, sq_search_cb, NULL); wtip (w, "Search for next Site matching glob at right"); XtManageChild (w); n = 0; XtSetArg (args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++; XtSetArg (args[n], XmNbottomWidget, settf_w); n++; XtSetArg (args[n], XmNleftAttachment, XmATTACH_WIDGET); n++; XtSetArg (args[n], XmNleftWidget, w); n++; XtSetArg (args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg (args[n], XmNcolumns, 30); n++; srtf_w = XmCreateTextField (sq_w, "SearchTF", args, n); wtip (srtf_w, "Candidate glob pattern"); XtAddCallback (srtf_w, XmNactivateCallback, sq_search_cb, NULL); XtManageChild (srtf_w); /* make the scrolled list at the top */ n = 0; XtSetArg (args[n], XmNtopAttachment, XmATTACH_FORM); n++; XtSetArg (args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++; XtSetArg (args[n], XmNbottomWidget, srtf_w); n++; XtSetArg (args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg (args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg (args[n], XmNselectionPolicy, XmBROWSE_SELECT); n++; sql_w = XmCreateScrolledList (sq_w, "SiteSL", args, n); wtip (sql_w, "Sites.. click to copy below, double-click to Set too"); XtAddCallback (sql_w, XmNdefaultActionCallback, sq_dblclick_cb, NULL); XtAddCallback (sql_w, XmNbrowseSelectionCallback, sq_click_cb, NULL); XtManageChild (sql_w); } /* build the section that lets the user build a new entry */ static void buildNew (Widget frame_w) { typedef struct { char *prompt; /* prompt label, or NULL for gap */ char *defstr; /* default string */ Widget *wp; /* text widget */ char *tip; /* tool tip */ } NewRC; static NewRC newrc[] = { {"Latitude:", " 40:00:00", &nlt_w, "Latitude, D:M:S +N"}, {"Longitude:", " 75:00:00", &nlg_w, "Longitude, D:M:S +W"}, {"Elevation:", " 0", &nel_w, "Elevation, m above MSL"}, {NULL}, {NULL}, {"Zone name:", " EST", &nzn_w, "Local time zone name"}, {"Offset:", " 5", &nzo_w, "Local hours west of UTC"}, {"DST name:", " EDT", &ndn_w, "Time zone name when DST"}, {"Offset:", " 4", &ndo_w, "Hours west when DST"}, }; Widget rc_w, mrc_w, w; Arg args[20]; int i, n; /* master form -- managed elsewhere */ n = 0; XtSetArg (args[n], XmNverticalSpacing, 7); n++; XtSetArg (args[n], XmNmarginHeight, 10); n++; newf_w = XmCreateForm (frame_w, "NF", args, n); /* site name */ n = 0; XtSetArg (args[n], XmNtopAttachment, XmATTACH_FORM); n++; XtSetArg (args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg (args[n], XmNrightAttachment, XmATTACH_POSITION); n++; XtSetArg (args[n], XmNrightPosition, 20); n++; w = XmCreateLabel (newf_w, "SN", args, n); set_xmstring (w, XmNlabelString, "Site name:"); XtManageChild (w); n = 0; XtSetArg (args[n], XmNtopAttachment, XmATTACH_FORM); n++; XtSetArg (args[n], XmNleftAttachment, XmATTACH_WIDGET); n++; XtSetArg (args[n], XmNleftWidget, w); n++; XtSetArg (args[n], XmNrightAttachment, XmATTACH_FORM); n++; nsn_w = XmCreateTextField (newf_w, "SN", args, n); wtip (nsn_w, "Enter name for new site"); XtManageChild (nsn_w); /* next set consistent enough to use a RC */ n = 0; XtSetArg (args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg (args[n], XmNtopWidget, nsn_w); n++; XtSetArg (args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg (args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg (args[n], XmNpacking, XmPACK_COLUMN); n++; XtSetArg (args[n], XmNorientation, XmHORIZONTAL); n++; XtSetArg (args[n], XmNnumColumns, 4); n++; XtSetArg (args[n], XmNspacing, 7); n++; rc_w = XmCreateRowColumn (newf_w, "RC", args, n); XtManageChild (rc_w); /* build fields */ for (i = 0; i < XtNumber(newrc); i++) { NewRC *p = &newrc[i]; if (p->prompt) { n = 0; w = XmCreateLabel (rc_w, "NSL", args, n); set_xmstring (w, XmNlabelString, p->prompt); XtManageChild (w); n = 0; XtSetArg (args[n], XmNvalue, p->defstr); n++; XtSetArg (args[n], XmNcolumns, 10); n++; w = XmCreateTextField (rc_w, "NST", args, n); XtManageChild (w); wtip (w, p->tip); *p->wp = w; } else { n = 0; w = XmCreateLabel (rc_w, "NSG", args, n); set_xmstring (w, XmNlabelString, " "); XtManageChild (w); } } /* build DST begins and end controls */ n = 0; XtSetArg (args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg (args[n], XmNtopWidget, rc_w); n++; XtSetArg (args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg (args[n], XmNpacking, XmPACK_TIGHT); n++; XtSetArg (args[n], XmNorientation, XmHORIZONTAL); n++; mrc_w = XmCreateRowColumn (newf_w, "BMB", args, n); wtip (mrc_w, "Rules for when summer savings time begins"); XtManageChild (mrc_w); buildDST (mrc_w, "DST Beg", &dbm_w, &dbw_w, &dbd_w, &dbat_w); setMenuHistory (dbm_w, 3); setMenuHistory (dbw_w, 0); setMenuHistory (dbd_w, 0); n = 0; XtSetArg (args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg (args[n], XmNtopWidget, mrc_w); n++; XtSetArg (args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg (args[n], XmNpacking, XmPACK_TIGHT); n++; XtSetArg (args[n], XmNorientation, XmHORIZONTAL); n++; mrc_w = XmCreateRowColumn (newf_w, "BMB", args, n); wtip (mrc_w, "Rules for when summer savings time ends"); XtManageChild (mrc_w); buildDST (mrc_w, "DST End", &dem_w, &dew_w, &ded_w, &deat_w); setMenuHistory (dem_w, 9); setMenuHistory (dew_w, 4); setMenuHistory (ded_w, 0); /* Set main and Save PBs */ n = 0; XtSetArg (args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg (args[n], XmNtopWidget, mrc_w); n++; XtSetArg (args[n], XmNbottomAttachment, XmATTACH_FORM); n++; XtSetArg (args[n], XmNleftAttachment, XmATTACH_POSITION); n++; XtSetArg (args[n], XmNleftPosition, 15); n++; XtSetArg (args[n], XmNrightAttachment, XmATTACH_POSITION); n++; XtSetArg (args[n], XmNrightPosition, 40); n++; w = XmCreatePushButton (newf_w, "S", args, n); wtip (w, "Install new site definition into Main"); set_xmstring (w, XmNlabelString, "Set main"); XtAddCallback (w, XmNactivateCallback, sq_setmain_cb, NULL); XtManageChild (w); n = 0; XtSetArg (args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg (args[n], XmNtopWidget, mrc_w); n++; XtSetArg (args[n], XmNbottomAttachment, XmATTACH_FORM); n++; XtSetArg (args[n], XmNleftAttachment, XmATTACH_POSITION); n++; XtSetArg (args[n], XmNleftPosition, 60); n++; XtSetArg (args[n], XmNrightAttachment, XmATTACH_POSITION); n++; XtSetArg (args[n], XmNrightPosition, 85); n++; w = XmCreatePushButton (newf_w, "S", args, n); wtip (w, "Save new site definition to private xephem_sites file"); set_xmstring (w, XmNlabelString, "Save"); XtAddCallback (w, XmNactivateCallback, sq_save_cb, NULL); XtManageChild (w); } static void buildDST (Widget p_w, char *prompt, Widget *m_w, Widget *w_w, Widget *d_w, Widget *at_w) { Widget w, om_w; char buf[32]; Arg args[20]; int n; n = 0; w = XmCreateLabel (p_w, "DL", args, n); set_xmstring (w, XmNlabelString, prompt); XtManageChild (w); n = 0; *m_w = XmCreatePulldownMenu (p_w, "MPD", args, n); addButtons (*m_w, months, XtNumber(months)); n = 0; XtSetArg (args[n], XmNsubMenuId, *m_w); n++; XtSetArg (args[n], XmNmarginHeight, 0); n++; om_w = XmCreateOptionMenu (p_w, "MCB", args, n); XtManageChild (om_w); w = XmOptionButtonGadget (om_w); n = 0; XtSetArg (args[n], XmNmarginHeight, 0); n++; XtSetValues (w, args, n); n = 0; *w_w = XmCreatePulldownMenu (p_w, "WPD", args, n); addButtons (*w_w, weeks, XtNumber(weeks)); n = 0; XtSetArg (args[n], XmNsubMenuId, *w_w); n++; XtSetArg (args[n], XmNmarginHeight, 0); n++; om_w = XmCreateOptionMenu (p_w, "WCB", args, n); XtManageChild (om_w); w = XmOptionButtonGadget (om_w); n = 0; XtSetArg (args[n], XmNmarginHeight, 0); n++; XtSetValues (w, args, n); n = 0; *d_w = XmCreatePulldownMenu (p_w, "DPD", args, n); addButtons (*d_w, dow, XtNumber(dow)); n = 0; XtSetArg (args[n], XmNsubMenuId, *d_w); n++; XtSetArg (args[n], XmNmarginHeight, 0); n++; om_w = XmCreateOptionMenu (p_w, "DCB", args, n); XtManageChild (om_w); w = XmOptionButtonGadget (om_w); n = 0; XtSetArg (args[n], XmNmarginHeight, 0); n++; XtSetValues (w, args, n); n = 0; w = XmCreateLabel (p_w, "AT", args, n); set_xmstring (w, XmNlabelString, "at"); XtManageChild (w); n = 0; XtSetArg (args[n], XmNcolumns, 10); n++; sprintf (buf, "%10s", twoam); XtSetArg (args[n], XmNvalue, buf); n++; *at_w = XmCreateTextField (p_w, "ATT", args, n); XtManageChild (*at_w); } static void addButtons (Widget pd_w, char **names, int nnames) { Widget w; Arg args[20]; int i, n; for (i = 0; i < nnames; i++) { n = 0; w = XmCreatePushButton (pd_w, "SPB", args, n); set_xmstring (w, XmNlabelString, names[i]); XtManageChild (w); } } /* menuHistory in the given option menu to widget number i */ static void setMenuHistory (Widget w, int i) { WidgetList children; get_something (w, XmNchildren, (XtArgVal)&children); set_something (w, XmNmenuHistory, (XtArgVal)children[i]); } /* shift the scrolled list so sites[i] is selected and visible */ static void scroll_sites (i) int i; { i += 1; /* List is 1-based */ XmListSetPos (sql_w, i); /* scroll it to top */ XmListSelectPos (sql_w, i, False); /* just highlight it */ } /* reset the current sites list, read shared then merge private and sort */ static void read_files () { char fn[1024]; FILE *fp; /* reset current list */ XtFree ((char *)sites); sites = NULL; nsites = 0; /* try share then private */ sprintf (fn, "%s/auxil/%s", getShareDir(), sfn); fp = fopenh (fn, "r"); if (fp) { read_file (fp); fclose (fp); } else { xe_msg (1, "%s:\n%s", fn, syserrstr()); } sprintf (fn, "%s/%s", getPrivateDir(), sfn); fp = fopenh (fn, "r"); if (fp) { read_file (fp); fclose (fp); } else if (errno != ENOENT) { /* ok if just absent */ xe_msg (1, "%s:\n%s", fn, syserrstr()); } /* sort by name */ qsort ((void *)sites, nsites, sizeof(Site), sites_cmpf); } /* read the given sites file and append to sites list. * caller checks if nsites increased to gauge success */ static void read_file (FILE *fp) { char buf[MAXSITELLEN]; /* read each entry, building up list */ while (fgets (buf, sizeof(buf), fp) != NULL) { char name[MAXSITELLEN]; char tzdefn[128]; int latd, latm; int lngd, lngm; double lats, lngs; char latNS, lngEW; double lt, lg; double ele; Site *sp; int l; int nf; /* read line.. skip if not complete. tz is optional */ tzdefn[0] = '\0'; nf = sscanf (buf, "%[^;]; %3d %2d %lf %c ; %3d %2d %lf %c ;%lf ; %s", name, &latd, &latm, &lats, &latNS, &lngd, &lngm, &lngs, &lngEW, &ele, tzdefn); if (nf < 10) continue; /* strip trailing blanks off name */ for (l = strlen (name); --l >= 0; ) if (isspace(name[l])) name[l] = '\0'; else break; /* crack location */ lt = degrad (latd + latm/60.0 + lats/3600.0); if (latNS == 'S') lt = -lt; lg = degrad (lngd + lngm/60.0 + lngs/3600.0); if (lngEW == 'W') lg = -lg; /* extend sites array */ sp = moreSites(); /* fill a new Site record */ memset ((void *)sp, 0, sizeof(Site)); sp->si_lat = (float)lt; sp->si_lng = (float)lg; sp->si_elev = (float)ele; (void) strncpy (sp->si_tzdefn, tzdefn, sizeof(sp->si_tzdefn)-1); (void) strncpy (sp->si_name, name, sizeof(sp->si_name)-1); } } /* (re)fill the scrolled list sql_w with the set of sites. * also tell earth view to redraw. */ static void fill_list () { XmString *xms; int i; /* build array of XmStrings for fast updating of the ScrolledList */ xms = (XmString *) XtMalloc (nsites * sizeof(XmString)); for (i = 0; i < nsites; i++) xms[i] = XmStringCreateSimple (sites[i].si_name); XmListDeleteAllItems (sql_w); XmListAddItems (sql_w, xms, nsites, 0); /* finished with the XmStrings table */ for (i = 0; i < nsites; i++) XmStringFree (xms[i]); XtFree ((void *)xms); /* update earth list */ e_update (mm_get_now(), 1); } /* compare name portions of two pointers to Sites in qsort fashion. */ static int sites_cmpf (const void * v1, const void * v2) { char *name1 = ((Site *)v1)->si_name; char *name2 = ((Site *)v2)->si_name; return (strcmp (name1, name2)); } /* called when CR is hit in the Set text field /or/ from Set PB. */ /* ARGSUSED */ static void sq_set_cb (w, client, call) Widget w; XtPointer client; XtPointer call; { char *str = XmTextFieldGetString (settf_w); int i; /* if text field matches a site, use the full definition, else just * use the simple string. */ for (i = 0; i < nsites; i++) { if (!strcmp (sites[i].si_name, str)) { scroll_sites (i); mm_setsite(&sites[i], 0); break; } } if (i == nsites) mm_sitename (str); XtFree (str); } /* called when CR is hit in the search text field /or/ from Search PB */ /* ARGSUSED */ static void sq_search_cb (w, client, call) Widget w; XtPointer client; XtPointer call; { char *str; int i; str = XmTextFieldGetString (srtf_w); i = sites_search (str); if (i < 0) xe_msg (1, "No matching site found."); else { /* Set and scroll */ XmTextFieldSetString (settf_w, sites[i].si_name); scroll_sites (i); } XtFree (str); } /* called when an item in the scrolled list is double-clicked */ /* ARGSUSED */ static void sq_dblclick_cb (w, client, call) Widget w; XtPointer client; XtPointer call; { int *pos, npos; int free; /* put into Set field and install in Main, all at once */ if ((free = XmListGetSelectedPos (sql_w, &pos, &npos)) && npos == 1 && pos[0] > 0 && pos[0] <= nsites) { Site *sip = &sites[pos[0]-1]; /* pos is 1-based */ XmTextFieldSetString (settf_w, sip->si_name); mm_setsite(sip, 0); } else { xe_msg (1, "Bogus list selection"); } if (free) XtFree ((char *)pos); } /* called when an item in the scrolled list is single-clicked */ /* ARGSUSED */ static void sq_click_cb (w, client, call) Widget w; XtPointer client; XtPointer call; { int *pos, npos; int free; /* copy to set field */ if ((free = XmListGetSelectedPos (sql_w, &pos, &npos)) && npos == 1 && pos[0] > 0 && pos[0] <= nsites) { Site *sip = &sites[pos[0]-1]; /* pos is 1-based */ XmTextFieldSetString (settf_w, sip->si_name); } else { xe_msg (1, "Bogus list selection"); } if (free) XtFree ((char *)pos); } /* callback from the Help button */ /* ARGSUSED */ static void sq_help_cb (w, client, call) Widget w; XtPointer client; XtPointer call; { static char *msg[] = { "Load and select from a list of sites." }; hlp_dialog ("MainMenu_sites_dialog", msg, XtNumber(msg)); } /* called when the Cancel button is hit */ /* ARGSUSED */ static void sq_cancel_cb (w, client, call) Widget w; XtPointer client; XtPointer call; { XtUnmanageChild (sq_w); } /* called when the Add TB is hit */ /* ARGSUSED */ static void sq_create_cb (w, client, call) Widget w; XtPointer client; XtPointer call; { if (XmToggleButtonGetState (w)) XtManageChild (newf_w); else XtUnmanageChild (newf_w); } /* called when the Set main PB is hit */ /* ARGSUSED */ static void sq_setmain_cb (w, client, call) Widget w; XtPointer client; XtPointer call; { Site ns; if (buildNewSite(&ns) < 0) return; mm_setsite (&ns, 0); } /* called when the Save PB is hit */ /* ARGSUSED */ static void sq_save_cb (w, client, call) Widget w; XtPointer client; XtPointer call; { char fn[1024]; Site ns; FILE *fp; if (buildNewSite(&ns) < 0) return; /* add to display set */ memcpy (moreSites(), &ns, sizeof(ns)); qsort ((void *)sites, nsites, sizeof(Site), sites_cmpf); fill_list(); /* append to private file */ sprintf (fn, "%s/%s", getPrivateDir(), sfn); fp = fopenh (fn, "a+"); if (fp) { /* 123:45:67 */ char latbuf[32], lngbuf[32]; fs_sexa (latbuf, raddeg(fabs(ns.si_lat)), 3, 3600); fs_sexa (lngbuf, raddeg(fabs(ns.si_lng)), 3, 3600); fprintf (fp, "%-40s; %.3s %.2s %.2s %c ; %.3s %.2s %.2s %c ;%6.1f ; %s\n", ns.si_name, latbuf, latbuf+4, latbuf+7, ns.si_lat < 0 ? 'S' : 'N', lngbuf, lngbuf+4, lngbuf+7, ns.si_lng < 0 ? 'W' : 'E', ns.si_elev, ns.si_tzdefn); fclose (fp); } else { xe_msg (1, "%s:\n%s", fn, syserrstr()); } } /* gather widget settings and build a new Site. * return 0 if looks ok, else -1 */ static int buildNewSite (Site *sp) { char buf[128], *bp; int bl = sizeof(buf); double tmp; int zl; /* init */ memset (sp, 0, sizeof(*sp)); /* always gather name lat long elev */ strncpy (sp->si_name, getTF(nsn_w,buf,bl), sizeof(sp->si_name)-1); if (strlen(sp->si_name) == 0) { xe_msg (1, "Please specify a site name"); return (-1); } f_scansexa (getTF(nlt_w,buf,bl), &tmp); sp->si_lat = (float) degrad (tmp); f_scansexa (getTF(nlg_w,buf,bl), &tmp); sp->si_lng = (float) degrad (-tmp); sp->si_elev = (float) strtod (getTF(nel_w,buf,bl), NULL); zl = 0; zl += sprintf (sp->si_tzdefn+zl, "%s", nows(getTF(nzn_w,buf,bl))); f_scansexa (getTF(nzo_w,buf,bl), &tmp); if (tmp - (int)tmp != 0) fs_sexa (buf, tmp, 2, 60); zl += sprintf (sp->si_tzdefn+zl, "%s", nows(buf)); /* only do the rest if dst name is non-blank */ bp = nows(getTF(ndn_w,buf,bl)); if (strlen(bp) > 0) { zl += sprintf (sp->si_tzdefn+zl, "%s", bp); f_scansexa (getTF(ndo_w,buf,bl), &tmp); if (tmp - (int)tmp != 0) fs_sexa (buf, tmp, 2, 60); zl += sprintf (sp->si_tzdefn+zl, "%s", nows(buf)); zl += sprintf (sp->si_tzdefn+zl, ",M%d", getPDmH (dbm_w)+1); zl += sprintf (sp->si_tzdefn+zl, ".%d", getPDmH (dbw_w)+1); zl += sprintf (sp->si_tzdefn+zl, ".%d", getPDmH (dbd_w)); f_scansexa (getTF(dbat_w,buf,bl), &tmp); fs_sexa (buf, tmp, 3, 3600); if (strcmp(buf,twoam)) zl += sprintf (sp->si_tzdefn+zl, "/%s", nows(buf)); zl += sprintf (sp->si_tzdefn+zl, ",M%d", getPDmH (dem_w)+1); zl += sprintf (sp->si_tzdefn+zl, ".%d", getPDmH (dew_w)+1); zl += sprintf (sp->si_tzdefn+zl, ".%d", getPDmH (ded_w)); f_scansexa (getTF(deat_w,buf,bl), &tmp); fs_sexa (buf, tmp, 3, 3600); if (strcmp(buf,twoam)) zl += sprintf (sp->si_tzdefn+zl, "/%s", nows(buf)); } /* fprintf (stderr, "'%s' '%s'\n", sp->si_name, sp->si_tzdefn); */ return (0); } /* extract up to bl-1 chars of text from given text field widget into buf, * return buf which always includes EOS. */ static char * getTF (Widget w, char buf[], int bl) { char *txt; txt = XmTextFieldGetString (w); strncpy (buf, txt, bl); XtFree (txt); buf[bl-1] = '\0'; return (buf); } /* remove all white space from bp IN PLACE and return first non-white char */ static char * nows (char *bp) { char *start = NULL, *dest; for (dest = bp; *bp; bp++) { if (*bp != ' ') { if (!start) start = dest; *dest++ = *bp; } } *dest = '\0'; return (start ? start : bp); } /* scan the children of the given pulldown menu and return the children[] * index of the one matching menuHistory */ static int getPDmH (Widget pd) { WidgetList children; Cardinal numChildren; Widget mh; int i; get_something (pd, XmNchildren, (XtArgVal)&children); get_something (pd, XmNnumChildren, (XtArgVal)&numChildren); get_something (pd, XmNmenuHistory, (XtArgVal)&mh); for (i = 0; i < numChildren; i++) if (children[i] == mh) return (i); printf ("Bug! no menuHistory for %s\n", XtName(pd)); abort(); } /* extend sites[] by one and return pointer to new entry */ static Site * moreSites() { sites = (Site *) XtRealloc ((void *)sites, (nsites+1)*sizeof(Site)); return (&sites[nsites++]); }