1 /*
2  *  xvtext.c  -  text file display window routines
3  *
4  *  includes:
5  *      void CreateTextWins(geom, cmtgeom);
6  *      void OpenTextView(text, textlen, title, freeonclose);
7  *      void OpenCommentText();
8  *      void CloseCommentText();
9  *      void ChangeCommentText();
10  *      void HideTextWindows();
11  *      void UnHideTextWindows();
12  *      void RaiseTextWindows();
13  *      void SetTextCursor(Cursor);
14  *      void KillTextWindows();
15  *      int  TextCheckEvent(evt, int *retval, int *done);
16  *
17  */
18 
19 #include "copyright.h"
20 
21 #include "xv.h"
22 #ifdef TV_MULTILINGUAL
23 #include "xvml.h"
24 #endif
25 
26 #define BUTTW1 80
27 #define BUTTW2 60
28 #define BUTTW3 110
29 #define BUTTH 24
30 
31 #define TOPMARGIN 30       /* from top of window to top of text window */
32 #define BOTMARGIN (5+BUTTH+5) /* room for a row of buttons at bottom */
33 #define LRMARGINS 5        /* left and right margins */
34 
35 #define MAXTVWIN    2      /* total # of windows */
36 #define MAXTEXTWIN  1      /* # of windows for text file viewing */
37 #define CMTWIN      1      /* cmtwin is reserved for image comments */
38 
39 /* button/menu indicies */
40 #define TV_ASCII    0
41 #define TV_HEX      1
42 #define TV_CLOSE    2
43 
44 #define TV_E_NBUTTS 3
45 
46 #ifdef TV_L10N
47 #  define TV_RESCAN   3
48 #  define TV_USASCII  4
49 #  define TV_JIS      5
50 #  define TV_EUCJ     6
51 #  define TV_MSCODE   7
52 
53 #  define TV_J_NBUTTS 8
54 #endif
55 
56 #define TITLELEN 128
57 
58 #ifdef TV_MULTILINGUAL
59 struct coding_spec {
60     struct coding_system coding_system;
61     char *(*converter)PARM((char *, int, int *));
62 };
63 #endif
64 
65 /* data needed per text window */
66 typedef struct {  Window win, textW;
67 		  int    vis, wasvis;
68 		  const char  *text;       /* text to be displayed */
69 		  int    freeonclose;      /* free text when closing win */
70 		  int    textlen;          /* length of text */
71 		  char   title[TITLELEN];  /* name of file being displayed */
72 		  const char **lines;     /* ptr to array of line ptrs */
73 		  int    numlines;         /* # of lines in text */
74 		  int    hexlines;         /* # of lines in HEX mode */
75 		  int    maxwide;          /* length of longest line (ascii) */
76 		  int    wide, high;       /* size of outer window (win)   */
77 		  int    twWide, twHigh;   /* size of inner window (textW) */
78 		  int    chwide, chhigh;   /* size of textW, in chars */
79 		  int    hexmode;          /* true if disp Hex, else Ascii */
80 		  SCRL   vscrl, hscrl;
81 #ifdef TV_L10N
82 		  int    code;         /* current character code */
83 		  BUTT   but[TV_J_NBUTTS], nopBut;
84 #else
85 		  BUTT   but[TV_E_NBUTTS], nopBut;
86 #endif
87 #ifdef TV_MULTILINGUAL
88 /*		  int    codeset; */
89 		  struct coding_spec ccs;	/* current coding_spec */
90 		  BUTT   csbut;
91 		  char *cv_text;
92 		  int cv_len;
93 		  struct context *ctx;
94 		  struct ml_text *txt;
95 		  struct csinfo_t *cs;
96 #endif
97 		} TVINFO;
98 
99 
100 static TVINFO   tinfo[MAXTVWIN];
101 static int      hasBeenSized = 0;
102 static int      haveWindows  = 0;
103 static int      nbutts;		/* # of buttons */
104 static int      mfwide, mfhigh, mfascent;   /* size of chars in mono font */
105 static int     *event_retP, *event_doneP;   /* used in tvChkEvent() */
106 #ifdef TV_MULTILINGUAL
107 # define TV_PLAIN          0
108 # define TV_ISO_8859_1     1
109 # define TV_ISO_2022_JP    2
110 # define TV_EUC_JAPAN      3
111 # define TV_ISO_2022_INT_1 4
112 # define TV_ISO_2022_KR    5
113 # define TV_EUC_KOREA      6
114 # define TV_ISO_2022_SS2_8 7
115 # define TV_ISO_2022_SS2_7 8
116 # define TV_SHIFT_JIS      9
117 # define TV_NCSS          10
118 static char *codeSetNames[TV_NCSS] = {
119     "plain",
120     "iso-8859-1",
121     "iso-2022-jp",
122     "euc-japan",
123     "iso-2022-int-1",
124     "iso-2022-kr",
125     "euc-korea",
126     "iso-2022-ss2-8",
127     "iso-2022-ss2-7",
128     "Shift JIS",
129 };
130 static struct coding_spec coding_spec[TV_NCSS] = {
131     /* --- G0 ---   --- G1 ---   --- G2 ---   --- G3 ---  GL GR EOL SF LS */
132     /* plain */
133     {{{{ 1,94,'B'}, { 1,94,'B'}, { 1,94,'B'}, { 1,94,'B'}}, 0, 0,  0, 1, 1},
134      NULL},
135     /* iso-8859-1 */
136     {{{{ 1,94,'B'}, { 1,96,'A'}, {-1,94,'B'}, {-1,94,'B'}}, 0, 1,  0, 0, 0},
137      NULL},
138     /* iso-2022-jp */
139     {{{{ 1,94,'B'}, {-1,94,'B'}, {-1,94,'B'}, {-1,94,'B'}}, 0, 0,  0, 1, 0},
140      NULL},
141     /* euc-japan */
142     {{{{ 1,94,'B'}, { 2,94,'B'}, { 1,94,'J'}, { 2,94,'D'}}, 0, 1,  0, 1, 0},
143      NULL},
144     /* iso-2022-int-1 */
145     {{{{ 1,94,'B'}, { 2,94,'C'}, {-1,94,'B'}, {-1,94,'B'}}, 0, 1,  0, 1, 1},
146      NULL},
147     /* iso-2022-kr */
148     {{{{ 1,94,'B'}, { 2,94,'C'}, {-1,94,'B'}, {-1,94,'B'}}, 0, 1,  0, 0, 1},
149      NULL},
150     /* euc-korea */
151     {{{{ 1,94,'B'}, { 2,94,'C'}, {-1,94,'B'}, {-1,94,'B'}}, 0, 1,  0, 0, 0},
152      NULL},
153     /* iso-2022-ss2-8 */
154     {{{{ 1,94,'B'}, {-1,94,'C'}, { 0,94,'B'}, {-1,94,'B'}}, 0, 1,  0, 0, 0},
155      NULL},
156     /* iso-2022-ss2-7 */
157     {{{{ 1,94,'B'}, {-1,94,'C'}, { 0,94,'B'}, {-1,94,'B'}}, 0, 1,  0, 1, 0},
158      NULL},
159     /* shift jis */
160     {{{{ 1,94,'B'}, { 2,94,'B'}, { 1,94,'J'}, { 2,94,'D'}}, 0, 1,  1, 1, 0},
161      sjis_to_jis},
162 };
163 #endif
164 
165 static void closeText       PARM((TVINFO *));
166 static int  tvChkEvent      PARM((TVINFO *, XEvent *));
167 static void resizeText      PARM((TVINFO *, int, int));
168 static void computeScrlVals PARM((TVINFO *));
169 static void doCmd           PARM((TVINFO *, int));
170 static void drawTextView    PARM((TVINFO *));
171 static void drawNumLines    PARM((TVINFO *));
172 static void eraseNumLines   PARM((TVINFO *));
173 static void drawTextW       PARM((int, SCRL *));
174 static void clickText       PARM((TVINFO *, int, int));
175 static void keyText         PARM((TVINFO *, XKeyEvent *));
176 static void textKey         PARM((TVINFO *, int));
177 static void doHexAsciiCmd   PARM((TVINFO *, int));
178 static void computeText     PARM((TVINFO *));
179 #ifdef TV_L10N
180 static int  selectCodeset         PARM((TVINFO *));
181 #endif
182 #ifdef TV_MULTILINGUAL
183 static void setCodingSpec   PARM((TVINFO *, struct coding_spec *));
184 static void createCsWins    PARM((const char *));
185 static void openCsWin       PARM((TVINFO *));
186 static void closeCsWin      PARM((TVINFO *));
187 #endif
188 
189 /* HEXMODE output looks like this:
190 0x00000000: 00 11 22 33 44 55 66 77 - 88 99 aa bb cc dd ee ff  0123456789abcdef
191 0x00000010: 00 11 22 33 44 55 66 77 - 88 99 aa bb cc dd ee ff  0123456789abcdef
192 etc.
193  */
194 
195 /***************************************************************/
CreateTextWins(geom,cmtgeom)196 void CreateTextWins(geom, cmtgeom)
197      const char *geom, *cmtgeom;
198 {
199   int                   i, defwide, defhigh, cmthigh;
200   XSizeHints            hints;
201   XSetWindowAttributes  xswa;
202   TVINFO               *tv;
203 #ifdef TV_MULTILINGUAL
204   int			default_codeset;
205 #endif
206 
207 #ifdef TV_L10N
208   if (!xlocale) {
209 #endif
210       mfwide = monofinfo->max_bounds.width;
211       mfhigh = monofinfo->ascent + monofinfo->descent;
212       mfascent = monofinfo->ascent;
213 
214       nbutts = TV_E_NBUTTS;	/* # of buttons */
215 #ifdef TV_L10N
216   }
217   else {
218       mfwide = monofsetinfo->max_logical_extent.width / 2;	/* shit! */
219       mfhigh = monofsetinfo->max_logical_extent.height + 1;
220       mfascent = mfhigh;
221 
222       nbutts = TV_J_NBUTTS;	/* # of buttons */
223   }
224 #endif
225 
226 #ifdef TV_MULTILINGUAL
227   {
228     char *dc = XGetDefault(theDisp, "xv", "codeSet");
229     if (dc == NULL)
230       default_codeset = TV_DEFAULT_CODESET;
231     else {
232       for (i = 0; i < TV_NCSS; i++) {
233 	if (strcmp(dc, codeSetNames[i]) == 0)
234 	  break;
235       }
236       if (i >= TV_NCSS) {
237         if (strcmp(dc, "iso-2022") == 0)
238 	  default_codeset = TV_PLAIN;
239 	else {
240 	  SetISTR(ISTR_WARNING, "%s: unknown codeset.", dc);
241 	  default_codeset = TV_PLAIN;
242 	}
243       } else
244 	default_codeset = i;
245     }
246   }
247 #endif
248   /* compute default size of textview windows.  should be big enough to
249      hold an 80x24 text window */
250 
251   defwide = 80 * mfwide + 2*LRMARGINS + 8 + 20;   /* -ish */
252   defhigh = 24 * mfhigh + TOPMARGIN + BOTMARGIN + 8 + 20;   /* ish */
253   cmthigh = 6  * mfhigh + TOPMARGIN + BOTMARGIN + 8 + 20;   /* ish */
254 
255   /* creates *all* textview windows at once */
256 
257   for (i=0; i<MAXTVWIN; i++) tinfo[i].win = (Window) NULL;
258 
259   for (i=0; i<MAXTVWIN; i++) {
260     tv = &tinfo[i];
261 
262 #ifdef TV_MULTILINGUAL
263     tv->ctx = ml_create_context(ScreenOfDisplay(theDisp, theScreen));
264     tv->txt = NULL;
265     tv->cv_text = NULL;
266     tv->cv_len = 0;
267     ml_set_charsets(tv->ctx, &coding_spec[TV_PLAIN].coding_system);
268 #endif
269 
270     tv->win = CreateWindow((i<CMTWIN) ? "xv text viewer" : "xv image comments",
271 			   "XVtextview",
272 			   (i<CMTWIN) ? geom : cmtgeom,
273 			   defwide,
274 			   (i<CMTWIN) ? defhigh : cmthigh,
275 			   infofg, infobg, 1);
276     if (!tv->win) FatalError("can't create textview window!");
277 
278     haveWindows = 1;
279     tv->vis = tv->wasvis = 0;
280 
281     if (ctrlColor) XSetWindowBackground(theDisp, tv->win, locol);
282               else XSetWindowBackgroundPixmap(theDisp, tv->win, grayTile);
283 
284     /* note: everything is sized and positioned in resizeText() */
285 
286     tv->textW = XCreateSimpleWindow(theDisp, tv->win, 1,1, 100,100,
287 				     1,infofg,infobg);
288     if (!tv->textW) FatalError("can't create textview text window!");
289 
290     SCCreate(&(tv->vscrl), tv->win, 0,0, 1,100, 0,0,0,0,
291 	     infofg, infobg, hicol, locol, drawTextW);
292 
293     SCCreate(&(tv->hscrl), tv->win, 0,0, 0,100, 0,0,0,0,
294 	     infofg, infobg, hicol, locol, drawTextW);
295 
296     if (XGetNormalHints(theDisp, tv->win, &hints))
297       hints.flags |= PMinSize;
298     else
299       hints.flags = PMinSize;
300 
301     hints.min_width  = 380;
302     hints.min_height = 200;
303     XSetNormalHints(theDisp, tv->win, &hints);
304 
305 
306 #ifdef BACKING_STORE
307     xswa.backing_store = WhenMapped;
308     XChangeWindowAttributes(theDisp, tv->textW, CWBackingStore, &xswa);
309 #endif
310 
311     XSelectInput(theDisp, tv->textW, ExposureMask | ButtonPressMask);
312 
313 
314     BTCreate(&(tv->but[TV_ASCII]), tv->win, 0,0,BUTTW1,BUTTH,
315 	     "Ascii",infofg,infobg,hicol,locol);
316     BTCreate(&(tv->but[TV_HEX]), tv->win, 0,0,BUTTW1,BUTTH,
317 	     "Hex",infofg,infobg,hicol,locol);
318     BTCreate(&(tv->but[TV_CLOSE]), tv->win, 0,0,BUTTW1,BUTTH,
319 	     "Close",infofg,infobg,hicol,locol);
320 
321 #ifdef TV_L10N
322     if (xlocale) {
323 	BTCreate(&(tv->but[TV_RESCAN]), tv->win, 0,0,BUTTW2,BUTTH,
324 		 "RESCAN",infofg,infobg,hicol,locol);
325 	BTCreate(&(tv->but[TV_USASCII]), tv->win, 0,0,BUTTW2,BUTTH,
326 		 "ASCII",infofg,infobg,hicol,locol);
327 	BTCreate(&(tv->but[TV_JIS]), tv->win, 0,0,BUTTW2,BUTTH,
328 		 "JIS",infofg,infobg,hicol,locol);
329 	BTCreate(&(tv->but[TV_EUCJ]), tv->win, 0,0,BUTTW2,BUTTH,
330 		 "EUC-j",infofg,infobg,hicol,locol);
331 	BTCreate(&(tv->but[TV_MSCODE]), tv->win, 0,0,BUTTW2,BUTTH,
332 		 "MS Kanji",infofg,infobg,hicol,locol);
333     }
334 #endif
335 
336     BTCreate(&(tv->nopBut), tv->win, 0,0, (u_int) tv->vscrl.tsize+1,
337 	     (u_int) tv->vscrl.tsize+1, "", infofg, infobg, hicol, locol);
338     tv->nopBut.active = 0;
339 
340     XMapSubwindows(theDisp, tv->win);
341 
342 #ifdef TV_MULTILINGUAL
343     BTCreate(&tv->csbut, tv->win, 0, 0, BUTTW1, BUTTH, "Code Sets",
344 	     infofg, infobg, hicol, locol);
345 #endif
346 
347     tv->text = (char *) NULL;
348     tv->textlen = 0;
349     tv->title[0] = '\0';
350 #ifdef TV_L10N
351     tv->code = (xlocale ? LOCALE_DEFAULT : 0);
352 #endif
353 #ifdef TV_MULTILINGUAL
354     tv->ccs = coding_spec[default_codeset];
355 #endif
356   }
357 #ifdef TV_MULTILINGUAL
358   get_monofont_size(&mfwide, &mfhigh);
359   /* recalculate sizes. */
360   defwide = 80 * mfwide + 2*LRMARGINS + 8 + 20;   /* -ish */
361   defhigh = 24 * mfhigh + TOPMARGIN + BOTMARGIN + 8 + 20;   /* ish */
362   cmthigh = 6  * mfhigh + TOPMARGIN + BOTMARGIN + 8 + 20;   /* ish */
363 #endif
364 
365   for (i=0; i<MAXTVWIN; i++) {
366     resizeText(&tinfo[i], defwide, (i<CMTWIN) ? defhigh : cmthigh);
367 
368     XSelectInput(theDisp, tinfo[i].win, ExposureMask | ButtonPressMask |
369 		 KeyPressMask | StructureNotifyMask);
370   }
371 
372   hasBeenSized = 1;  /* we can now start looking at textview events */
373 
374 #ifdef TV_MULTILINGUAL
375   createCsWins("+100+100");
376 #endif
377 }
378 
379 
380 /***************************************************************/
TextView(fname)381 int TextView(fname)
382      const char *fname;
383 {
384   /* given a filename, attempts to read in the file and open a textview win */
385 
386   int   filetype;
387   long  textlen;
388   char *text, buf[512], title[128], rfname[MAXPATHLEN+1];
389   char *basefname[128];  /* just current fname, no path */
390   FILE *fp;
391   char filename[MAXPATHLEN+1];
392 
393   strncpy(filename, fname, sizeof(filename) - 1);
394 #ifdef AUTO_EXPAND
395   Mkvdir(filename);
396   Dirtovd(filename);
397 #endif
398 
399   basefname[0] = '\0';
400   strncpy(rfname, filename, sizeof(rfname) - 1);
401 
402   /* see if this file is compressed.  if it is, uncompress it, and view
403      the uncompressed version */
404 
405   filetype = ReadFileType(filename);
406   if ((filetype == RFT_COMPRESS) || (filetype == RFT_BZIP2)) {
407 #ifndef VMS
408     if (!UncompressFile(filename, rfname, filetype)) return FALSE;
409 #else
410     /* chop off trailing '.Z' from friendly displayed basefname, if any */
411     strncpy (basefname, filename, 128 - 1);
412     *rindex (basefname, '.') = '\0';
413     if (!UncompressFile(basefname, rfname, filetype)) return FALSE;
414 #endif
415   }
416 
417   fp = fopen(rfname, "r");
418   if (!fp) {
419     sprintf(buf,"Couldn't open '%s':  %s", rfname, ERRSTR(errno));
420     ErrPopUp(buf,"\nOh well");
421     return FALSE;
422   }
423 
424 
425   fseek(fp, 0L, 2);
426   textlen = ftell(fp);
427   fseek(fp, 0L, 0);
428 
429   if (!textlen) {
430     sprintf(buf, "File '%s' contains no data.  (Zero length file.)", rfname);
431     ErrPopUp(buf, "\nOk");
432     fclose(fp);
433     return FALSE;
434   }
435 
436   text = (char *) malloc((size_t) textlen + 1);
437   if (!text) {
438     sprintf(buf, "Couldn't malloc %ld bytes to read file '%s'",
439 	    textlen, rfname);
440     ErrPopUp(buf, "\nSo what!");
441     fclose(fp);
442     return FALSE;
443   }
444 
445   if (fread(text, (size_t) 1, (size_t) textlen, fp) != textlen) {
446     sprintf(buf, "Warning:  Couldn't read all of '%s'.  Possibly truncated.",
447 	    rfname);
448     ErrPopUp(buf, "\nHmm...");
449   }
450 #ifdef TV_MULTILINGUAL
451   text[textlen] = '\0';
452 #endif
453 
454   fclose(fp);
455 
456   sprintf(title, "File: '%s'", BaseName(fname));
457   OpenTextView(text, (int) textlen, title, 1);
458 
459   /* note:  text gets freed when window gets closed */
460   return TRUE;
461 }
462 
463 
464 
465 /***************************************************************/
OpenTextView(text,len,title,freeonclose)466 void OpenTextView(text, len, title, freeonclose)
467      const char *text, *title;
468      int   len, freeonclose;
469 {
470   /* opens up a textview window */
471 
472   TVINFO *tv;
473 
474   tv = &tinfo[0];
475 
476   /* kill off old text info */
477   if (tv->freeonclose && tv->text) free((void *)tv->text);
478   if (tv->lines) free(tv->lines);
479 
480   tv->text = (const char *) NULL;
481   tv->lines = (const char **) NULL;
482   tv->numlines = tv->textlen = tv->hexmode = 0;
483 
484 
485   tv->text        = text;
486   tv->textlen     = len;
487   tv->freeonclose = freeonclose;
488   strncpy(tv->title, title, (size_t) TITLELEN-1);
489   tv->title[TITLELEN-1] = '\0';
490 
491   computeText(tv);      /* compute # lines and linestarts array */
492 
493   anyTextUp = 1;
494   if (!tv->vis) XMapRaised(theDisp, tv->win);
495   else {
496     XClearArea(theDisp, tv->win, 0, 0, (u_int) tv->wide, (u_int) 30, False);
497     drawTextView(tv);
498   }
499   tv->vis = 1;
500 
501   SCSetVal(&(tv->vscrl), 0);
502   SCSetVal(&(tv->hscrl), 0);
503   computeScrlVals(tv);
504 }
505 
506 
507 
508 /***************************************************************/
OpenCommentText()509 void OpenCommentText()
510 {
511   /* opens up the reserved 'comment' textview window */
512 
513   TVINFO *tv;
514 
515   tv = &tinfo[CMTWIN];
516   commentUp = 1;
517   XMapRaised(theDisp, tv->win);
518   tv->vis = 1;
519 
520   ChangeCommentText();
521 }
522 
523 
524 /***************************************************************/
CloseCommentText()525 void CloseCommentText()
526 {
527   /* closes the reserved 'comment' textview window */
528 
529   closeText(&tinfo[CMTWIN]);
530   commentUp = 0;
531 }
532 
533 
534 /***************************************************************/
ChangeCommentText()535 void ChangeCommentText()
536 {
537   /* called when 'picComments' changes */
538 
539   TVINFO *tv;
540 
541   tv = &tinfo[CMTWIN];
542 
543   tv->text        = picComments;
544   tv->textlen     = (tv->text) ? strlen(tv->text) : 0;
545   tv->freeonclose = 0;
546 
547   if (strlen(fullfname))
548     sprintf(tv->title, "File: '%s'", BaseName(fullfname));
549   else
550     sprintf(tv->title, "<no file loaded>");
551 
552   computeText(tv);      /* compute # lines and linestarts array */
553 
554   if (tv->vis) {
555     XClearArea(theDisp, tv->win, 0, 0, (u_int) tv->wide, (u_int) 30, False);
556     drawTextView(tv);
557   }
558 
559   SCSetVal(&(tv->vscrl), 0);
560   SCSetVal(&(tv->hscrl), 0);
561 
562   computeScrlVals(tv);
563 }
564 
565 
566 /***************************************************************/
HideTextWindows()567 void HideTextWindows()
568 {
569   int i;
570 
571   for (i=0; i<MAXTVWIN; i++) {
572     if (tinfo[i].vis) {
573       XUnmapWindow(theDisp, tinfo[i].win);
574       tinfo[i].wasvis = 1;
575       tinfo[i].vis = 0;
576     }
577   }
578 }
579 
580 
581 /***************************************************************/
UnHideTextWindows()582 void UnHideTextWindows()
583 {
584   int i;
585 
586   for (i=0; i<MAXTVWIN; i++) {
587     if (tinfo[i].wasvis) {
588       XMapRaised(theDisp, tinfo[i].win);
589       tinfo[i].wasvis = 0;
590       tinfo[i].vis = 1;
591     }
592   }
593 }
594 
595 
596 /***************************************************************/
RaiseTextWindows()597 void RaiseTextWindows()
598 {
599   int i;
600 
601   for (i=0; i<MAXTEXTWIN; i++) {
602     if (tinfo[i].vis) {
603       XRaiseWindow(theDisp, tinfo[i].win);
604     }
605   }
606 }
607 
608 
609 /***************************************************************/
SetTextCursor(c)610 void SetTextCursor(c)
611      Cursor c;
612 {
613   int i;
614 
615   for (i=0; i<MAXTVWIN; i++) {
616     if (haveWindows && tinfo[i].win) XDefineCursor(theDisp, tinfo[i].win, c);
617   }
618 }
619 
620 
621 /***************************************************************/
KillTextWindows()622 void KillTextWindows()
623 {
624   int i;
625 
626   for (i=0; i<MAXTVWIN; i++) {
627     if (haveWindows && tinfo[i].win) XDestroyWindow(theDisp, tinfo[i].win);
628   }
629 }
630 
631 
632 /***************************************************************/
TextCheckEvent(xev,retP,doneP)633 int TextCheckEvent(xev, retP, doneP)
634      XEvent *xev;
635      int *retP, *doneP;
636 {
637   int i;
638 
639   event_retP  = retP;     /* so don't have to pass these all over the place */
640   event_doneP = doneP;
641 
642   for (i=0; i<MAXTVWIN; i++) {
643     if (tvChkEvent(&tinfo[i], xev)) break;
644   }
645 
646   if (i<MAXTVWIN) return 1;
647   return 0;
648 }
649 
650 
651 /***************************************************************/
TextDelWin(win)652 int TextDelWin(win)
653      Window win;
654 {
655   /* got a delete window request.  see if the window is a textview window,
656      and close accordingly.  Return 1 if event was eaten */
657 
658   int i;
659 
660   for (i=0; i<MAXTVWIN; i++) {
661     if (tinfo[i].win == win) {
662       closeText(&tinfo[i]);
663       return 1;
664     }
665   }
666 
667   return 0;
668 }
669 
670 
671 
672 
673 
674 /**************************************************************/
675 /***                    INTERNAL FUNCTIONS                  ***/
676 /**************************************************************/
677 
678 
679 
680 
681 
682 /***************************************************************/
closeText(tv)683 static void closeText(tv)
684      TVINFO *tv;
685 {
686   /* closes specified textview window */
687 
688   int i;
689 
690   XUnmapWindow(theDisp, tv->win);
691   tv->vis = 0;
692 
693   for (i=0; i<MAXTEXTWIN && !tinfo[i].vis; i++);
694   if (i==MAXTEXTWIN) anyTextUp = 0;
695 
696   /* free all info for this textview window */
697   if (tv->freeonclose && tv->text)  free((void *)tv->text);
698   if (tv->lines) free(tv->lines);
699 
700   tv->text  = (const char *) NULL;
701   tv->lines = (const char **) NULL;
702   tv->numlines = tv->textlen = tv->hexmode = 0;
703 
704 #ifdef TV_MULTILINGUAL
705   closeCsWin(tv);
706 #endif
707 }
708 
709 
710 /***************************************************************/
tvChkEvent(tv,xev)711 static int tvChkEvent(tv, xev)
712      TVINFO *tv;
713      XEvent *xev;
714 {
715   /* checks event to see if it's a text-window related thing.  If it
716      is, it eats the event and returns '1', otherwise '0'. */
717 
718   int rv;
719 
720   rv = 1;
721 
722   if (!hasBeenSized) return 0;  /* ignore evrythng until we get 1st Resize */
723 
724   if (xev->type == Expose) {
725     int x,y,w,h;
726     XExposeEvent *e = (XExposeEvent *) xev;
727     x = e->x;  y = e->y;  w = e->width;  h = e->height;
728 
729     /* throw away excess redraws for 'dumb' windows */
730     if (e->count > 0 && (e->window == tv->vscrl.win ||
731 			 e->window == tv->hscrl.win)) {}
732 
733     else if (e->window == tv->vscrl.win) SCRedraw(&(tv->vscrl));
734     else if (e->window == tv->hscrl.win) SCRedraw(&(tv->hscrl));
735 
736     else if (e->window == tv->win || e->window == tv->textW) { /* smart wins */
737       /* group individual expose rects into a single expose region */
738       int           count;
739       Region        reg;
740       XRectangle    rect;
741       XEvent        evt;
742 
743       xvbcopy((char *) e, (char *) &evt, sizeof(XEvent));
744       reg = XCreateRegion();
745       count = 0;
746 
747       do {
748 	if (DEBUG) fprintf(stderr,"   expose: %s %d,%d %dx%d\n",
749 			   (e->window == tv->win) ? "tv win" : "text win",
750 			   rect.x, rect.y, rect.width, rect.height);
751 
752 	rect.x      = evt.xexpose.x;
753 	rect.y      = evt.xexpose.y;
754 	rect.width  = evt.xexpose.width;
755 	rect.height = evt.xexpose.height;
756 	XUnionRectWithRegion(&rect, reg, reg);
757 	count++;
758       } while (XCheckWindowEvent(theDisp, evt.xexpose.window,
759 				 ExposureMask, &evt));
760 
761       XClipBox(reg, &rect);  /* bounding box of region */
762       XSetRegion(theDisp, theGC, reg);
763 
764       if (DEBUG) {
765 	fprintf(stderr,"win = %lx, tv->win = %lx, textW = %lx\n",
766 		e->window, tv->win, tv->textW);
767 	fprintf(stderr,"grouped %d expose events into %d,%d %dx%d rect\n",
768 		count, rect.x, rect.y, rect.width, rect.height);
769       }
770 
771       if      (e->window == tv->win)   drawTextView(tv);
772       else if (e->window == tv->textW) drawTextW(0, &(tv->vscrl));
773 
774       XSetClipMask(theDisp, theGC, None);
775       XDestroyRegion(reg);
776     }
777 
778     else rv = 0;
779   }
780 
781 
782   else if (xev->type == ButtonPress) {
783     XButtonEvent *e = (XButtonEvent *) xev;
784     int x,y;
785     x = e->x;  y = e->y;
786 
787     if (e->button == Button1) {
788       if      (e->window == tv->win)       clickText(tv,x,y);
789       else if (e->window == tv->vscrl.win) SCTrack(&(tv->vscrl),x,y);
790       else if (e->window == tv->hscrl.win) SCTrack(&(tv->hscrl),x,y);
791       else if (e->window == tv->textW) { }
792       else rv = 0;
793     }
794     else if (e->button == Button4) {   /* note min vs. max, + vs. - */
795       /* scroll regardless of where we are in the text window */
796       if (e->window == tv->win ||
797 	 e->window == tv->vscrl.win ||
798 	 e->window == tv->hscrl.win ||
799 	 e->window == tv->textW)
800       {
801 	SCRL *sp=&(tv->vscrl);
802 	int  halfpage=sp->page/2;
803 
804 	if (sp->val > sp->min+halfpage)
805 	  SCSetVal(sp,sp->val-halfpage);
806 	else
807 	  SCSetVal(sp,sp->min);
808       }
809       else rv = 0;
810     }
811     else if (e->button == Button5) {   /* note max vs. min, - vs. + */
812       /* scroll regardless of where we are in the text window */
813       if (e->window == tv->win ||
814 	 e->window == tv->vscrl.win ||
815 	 e->window == tv->hscrl.win ||
816 	 e->window == tv->textW)
817       {
818 	SCRL *sp=&(tv->vscrl);
819 	int  halfpage=sp->page/2;
820 
821 	if (sp->val < sp->max-halfpage)
822 	  SCSetVal(sp,sp->val+halfpage);
823 	else
824 	  SCSetVal(sp,sp->max);
825       }
826       else rv = 0;
827     }
828     else rv = 0;
829   }
830 
831 
832   else if (xev->type == KeyPress) {
833     XKeyEvent *e = (XKeyEvent *) xev;
834     if (e->window == tv->win) keyText(tv, e);
835     else rv = 0;
836   }
837 
838 
839   else if (xev->type == ConfigureNotify) {
840     XConfigureEvent *e = (XConfigureEvent *) xev;
841 
842     if (e->window == tv->win) {
843       if (DEBUG)
844 	fprintf(stderr,"textview got a configure event (%dx%d)\n",
845 		e->width, e->height);
846 
847       if (tv->wide != e->width || tv->high != e->height) {
848 	if (DEBUG) fprintf(stderr,"Forcing a redraw!  (from configure)\n");
849 	XClearArea(theDisp, tv->win, 0, 0,
850 		   (u_int) e->width, (u_int) e->height, True);
851 	resizeText(tv, e->width, e->height);
852       }
853     }
854     else rv = 0;
855   }
856   else rv = 0;
857 
858   return rv;
859 }
860 
861 
862 /***************************************************************/
resizeText(tv,w,h)863 static void resizeText(tv,w,h)
864      TVINFO *tv;
865      int     w,h;
866 {
867   int        i, maxw, maxh;
868   XSizeHints hints;
869 
870 #ifndef TV_MULTILINGUAL
871   if (tv->wide == w && tv->high == h) return;  /* no change in size */
872 #endif
873 
874   if (XGetNormalHints(theDisp, tv->win, &hints)) {
875     hints.width  = w;
876     hints.height = h;
877     hints.flags |= USSize;
878     XSetNormalHints(theDisp, tv->win, &hints);
879   }
880 
881   tv->wide = w;  tv->high = h;
882 
883   /* compute maximum size of text window */
884   maxw = tv->wide - (2*LRMARGINS) - (tv->vscrl.tsize+1) - 2;
885   maxh = tv->high - (TOPMARGIN + BOTMARGIN) - (tv->hscrl.tsize+1) - 2;
886 
887   tv->chwide = ((maxw - 6) / mfwide);
888   tv->chhigh = ((maxh - 6) / mfhigh);
889 
890   tv->twWide = tv->chwide * mfwide + 6;
891   tv->twHigh = tv->chhigh * mfhigh + 6;
892 
893   XMoveResizeWindow(theDisp, tv->textW, LRMARGINS, TOPMARGIN,
894 		    (u_int) tv->twWide, (u_int) tv->twHigh);
895 
896   for (i=0; i<TV_E_NBUTTS; i++) {
897     tv->but[i].x = tv->wide - (TV_E_NBUTTS-i) * (BUTTW1+5);
898     tv->but[i].y = tv->high - BUTTH - 5;
899   }
900 #ifdef TV_MULTILINGUAL
901   tv->csbut.x = 5;
902   tv->csbut.y = tv->high - BUTTH - 5;
903 #endif
904 
905 #ifdef TV_L10N
906   if (xlocale) {
907     for (; i<TV_J_NBUTTS; i++) {
908       tv->but[i].x = 5 + (i-TV_E_NBUTTS) * (BUTTW2+5);
909       tv->but[i].y = tv->high - BUTTH - 5;
910     }
911   }
912 #endif
913 
914   computeScrlVals(tv);
915 
916   tv->nopBut.x = LRMARGINS + tv->twWide + 1;
917   tv->nopBut.y = TOPMARGIN + tv->twHigh + 1;
918 }
919 
920 
921 
922 
923 /***************************************************************/
computeScrlVals(tv)924 static void computeScrlVals(tv)
925      TVINFO *tv;
926 {
927   int hmax, hpag, vmax, vpag;
928 
929   if (tv->hexmode) {
930     hmax = 80 - tv->chwide;
931     vmax = tv->hexlines - tv->chhigh;
932   }
933   else {   /* ASCII mode */
934     hmax = tv->maxwide - tv->chwide;
935     vmax = tv->numlines - tv->chhigh - 1;
936   }
937 
938   hpag = tv->chwide / 4;
939   vpag = tv->chhigh - 1;
940 
941 
942   SCChange(&tv->vscrl, LRMARGINS + tv->twWide+1, TOPMARGIN,
943 	   1, tv->twHigh, 0, vmax, tv->vscrl.val, vpag);
944 
945   SCChange(&tv->hscrl, LRMARGINS, TOPMARGIN + tv->twHigh + 1,
946 	   0, tv->twWide, 0, hmax, tv->hscrl.val, hpag);
947 }
948 
949 
950 
951 /***************************************************************/
doCmd(tv,cmd)952 static void doCmd(tv, cmd)
953      TVINFO *tv;
954      int     cmd;
955 {
956   switch (cmd) {
957   case TV_ASCII:   doHexAsciiCmd(tv, 0);  break;
958   case TV_HEX:     doHexAsciiCmd(tv, 1);  break;
959 
960   case TV_CLOSE:   if (tv == &tinfo[CMTWIN]) CloseCommentText();
961                    else closeText(tv);
962                    break;
963 
964 #ifdef TV_L10N
965   case TV_RESCAN:
966     tv->code = selectCodeset(tv);
967     drawTextW(0, &tv->vscrl);
968     break;
969   case TV_USASCII:
970     tv->code = LOCALE_USASCII;
971     drawTextW(0, &tv->vscrl);
972     break;
973   case TV_JIS:
974     tv->code = LOCALE_JIS;
975     drawTextW(0, &tv->vscrl);
976     break;
977   case TV_EUCJ:
978     tv->code = LOCALE_EUCJ;
979     drawTextW(0, &tv->vscrl);
980     break;
981   case TV_MSCODE:
982     tv->code = LOCALE_MSCODE;
983     drawTextW(0, &tv->vscrl);
984     break;
985 #endif	/* TV_L10N */
986   }
987 }
988 
989 
990 
991 /***************************************************************/
drawTextView(tv)992 static void drawTextView(tv)
993      TVINFO *tv;
994 {
995   /* redraw the outer window */
996 
997   int i, y;
998 
999   if (strlen(tv->title)) {    /* draw the title */
1000     y = 5;
1001 
1002     XSetForeground(theDisp, theGC, infobg);
1003     XFillRectangle(theDisp, tv->win, theGC, 5+1, y+1,
1004 		   (u_int) StringWidth(tv->title)+6, (u_int) CHIGH+4);
1005 
1006     XSetForeground(theDisp, theGC, infofg);
1007     XDrawRectangle(theDisp, tv->win, theGC, 5, y,
1008 		   (u_int) StringWidth(tv->title)+7, (u_int) CHIGH+5);
1009 
1010     Draw3dRect(tv->win, 5+1, y+1, (u_int) StringWidth(tv->title)+5,
1011 	       (u_int) CHIGH+3, R3D_IN, 2, hicol, locol, infobg);
1012 
1013     XSetForeground(theDisp, theGC, infofg);
1014     DrawString(tv->win, 5+3, y+ASCENT+3, tv->title);
1015   }
1016 
1017   drawNumLines(tv);
1018 
1019   /* draw the buttons */
1020   for (i=0; i<nbutts; i++) BTRedraw(&(tv->but[i]));
1021 #ifdef TV_MULTILINGUAL
1022   BTRedraw(&tv->csbut);
1023 #endif
1024   BTRedraw(&tv->nopBut);
1025 }
1026 
1027 
1028 /***************************************************************/
drawNumLines(tv)1029 static void drawNumLines(tv)
1030      TVINFO *tv;
1031 {
1032   int x, y, w, nl;
1033   char tmpstr[128];
1034 
1035   if (tv->hexmode) nl = tv->hexlines;
1036   else {
1037     if (tv->numlines>0 &&
1038 	tv->lines[tv->numlines-1] - tv->lines[tv->numlines-2] == 1)
1039       nl = tv->numlines - 2;      /* line after last \n has zero length */
1040     else nl = tv->numlines - 1;
1041   }
1042   if (nl<0) nl = 0;
1043 
1044   sprintf(tmpstr, "%d byte%s, %d line%s",
1045 	  tv->textlen, (tv->textlen!=1) ? "s" : "",
1046 	  nl, (nl!=1) ? "s" : "");
1047 
1048   w = StringWidth(tmpstr) + 7;  /* width of frame */
1049   x = LRMARGINS + tv->twWide + tv->vscrl.tsize+1;     /* right align point */
1050   y = 6;
1051 
1052   XSetForeground(theDisp, theGC, infobg);
1053   XFillRectangle(theDisp, tv->win, theGC, (x-w)+1, y+1,
1054 		 (u_int) (w-1), (u_int) CHIGH+4);
1055 
1056   XSetForeground(theDisp, theGC, infofg);
1057   XDrawRectangle(theDisp, tv->win, theGC, x-w, y, (u_int) w, (u_int) CHIGH+5);
1058 
1059   Draw3dRect(tv->win, (x-w)+1, y+1, (u_int) (w-2), (u_int) CHIGH+3,
1060 	     R3D_IN,2,hicol,locol,infobg);
1061 
1062   XSetForeground(theDisp, theGC, infofg);
1063   DrawString(tv->win, (x-w)+3, y+ASCENT+3, tmpstr);
1064 }
1065 
1066 
1067 /***************************************************************/
eraseNumLines(tv)1068 static void eraseNumLines(tv)
1069      TVINFO *tv;
1070 {
1071   int x, y, w, nl;
1072   char tmpstr[64];
1073 
1074   nl = (tv->hexmode) ? tv->hexlines : tv->numlines-1;
1075 
1076   sprintf(tmpstr, "%d byte%s, %d line%s",
1077 	  tv->textlen, (tv->textlen>1) ? "s" : "",
1078 	  nl, (nl>1) ? "s" : "");
1079 
1080   w = StringWidth(tmpstr) + 7;  /* width of frame */
1081   x = LRMARGINS + tv->twWide + tv->vscrl.tsize+1;     /* right align point */
1082   y = 5;
1083 
1084   XClearArea(theDisp, tv->win, x-w, y, (u_int) w+1, (u_int) CHIGH+7, False);
1085 }
1086 
1087 
1088 /***************************************************************/
drawTextW(delta,sptr)1089 static void drawTextW(delta, sptr)
1090      int   delta;
1091      SCRL *sptr;
1092 {
1093   int     i, j, lnum, hpos, vpos, cpos, lwide;
1094 #ifndef TV_MULTILINGUAL
1095   int     extrach;
1096 #endif
1097 #ifdef TV_L10N
1098   int     desig_stat;	/* for ISO 2022-JP */
1099 	      /* 0: ASCII,  1: JIS X 0208,  2: GL is JIS X 0201 kana */
1100 #endif
1101   TVINFO *tv;
1102   char    linestr[512];
1103   byte   *lp;
1104   const byte  *sp, *ep;
1105 
1106   /* figure out TVINFO pointer from SCRL pointer */
1107   for (i=0; i<MAXTVWIN && sptr != &tinfo[i].vscrl
1108        && sptr != &tinfo[i].hscrl; i++);
1109   if (i==MAXTVWIN) return;   /* didn't find one */
1110 
1111   tv = &tinfo[i];
1112 
1113   /* make sure we've been sized.  Necessary, as creating/modifying the
1114      scrollbar calls this routine directly, rather than through
1115      TextCheckEvent() */
1116 
1117   if (!hasBeenSized) return;
1118 
1119   XSetForeground(theDisp, theGC, infofg);
1120   XSetBackground(theDisp, theGC, infobg);
1121   XSetFont(theDisp, theGC, monofont);
1122 
1123   hpos = tv->hscrl.val;
1124   vpos = tv->vscrl.val;
1125   lwide = (tv->chwide < 500) ? tv->chwide : 500;
1126 
1127   /* draw text */
1128   if (!tv->hexmode) {     /* ASCII mode */
1129 #ifdef TV_MULTILINGUAL
1130     XClearArea(theDisp, tv->textW, 0, 0,
1131 	       (u_int) tv->twWide, (u_int) tv->twHigh, False);
1132     if(tv->txt == NULL)
1133       return;
1134     else {
1135 	int i;
1136 	int y;
1137 	struct ml_text *tp = tv->txt;
1138 	struct ml_line *lp2;
1139 
1140 	XSetFunction(theDisp, theGC, GXcopy);
1141 	XSetClipMask(theDisp, theGC, None);
1142 	y = 3;
1143 	for (lp2 = &tp->lines[vpos], i = tp->nlines - vpos;
1144 		i > 0; lp2++, i--) {
1145 	    XDrawText16(theDisp, tv->textW, theGC,
1146 			-mfwide * hpos + 3, y + lp2->ascent,
1147 			lp2->items, lp2->nitems);
1148 	    y += lp2->ascent + lp2->descent;
1149 	    if (y > tv->twHigh)
1150 		break;
1151 	}
1152     }
1153 #else
1154     for (i=0; i<tv->chhigh; i++) {    /* draw each line */
1155       lnum = i + vpos;
1156       if (lnum < tv->numlines-1) {
1157 
1158 	/* find start of displayed portion of line.  This is *wildly*
1159 	   complicated by the ctrl-character and tab expansion... */
1160 
1161 	sp = (byte *) tv->lines[lnum];
1162 	ep = (byte *) tv->lines[lnum+1] - 1;  /* ptr to last disp ch in line */
1163 
1164 	extrach = 0;
1165 
1166 	for (cpos=0; cpos<hpos && sp<ep; cpos++) {
1167 	  if (!extrach) {
1168 	    if (*sp == '\011') {   /* tab to next multiple of 8 */
1169 	      extrach = ((cpos+8) & (~7)) - cpos;
1170 	      extrach--;
1171 	    }
1172 	    else if (*sp == '\015') {   /* ^M not displayed */
1173 	      cpos--;  sp++;
1174 	    }
1175 	    else if (*sp < 32) extrach = 1;
1176 
1177 #ifdef TV_L10N
1178 	    else if (!tv->code && *sp > 127) extrach = 3;
1179 #else
1180 	    else if (*sp > 127) extrach = 3;
1181 #endif
1182 
1183 	    else sp++;
1184 	  }
1185 	  else {
1186 	    extrach--;
1187 	    if (!extrach) sp++;
1188 	  }
1189 	}
1190 
1191 	/* at this point, 'sp' is pointing to the first char to display.
1192 	   if sp is a 'special' character, extrach is the # of chars
1193 	   left to display of the 'expanded' version.  If sp>=ep, a blank
1194 	   line should be printed */
1195 
1196 	/* build up the linestr buffer, which is the current line, padded
1197 	   with blanks to a width of exactly tv->chwide chars */
1198 #ifdef TV_L10N
1199 	desig_stat = 0;		/* for ISO 2022-JP */
1200 	      /* 0: ASCII,  1: JIS X 0208,  2: GL is JIS X 0201 kana */
1201 #endif
1202 	for (cpos=0, lp=(byte *) linestr; cpos<lwide; cpos++, lp++) {
1203 	  if (sp>=ep) *lp = ' ';
1204 	  else {
1205 	    if (*sp == '\011') {   /* tab to next multiple of 8 */
1206 	      if (!extrach) extrach = ((cpos+hpos+8) & (~7)) - (cpos+hpos);
1207 
1208 	      if (extrach) *lp = ' ';
1209 	    }
1210 
1211 	    else if (*sp == '\015') {  /* don't show ^M */
1212 	      cpos--;  lp--;  sp++;
1213 	    }
1214 
1215 #ifdef TV_L10N
1216 	    else if (*sp < 32 && !(tv->code == LOCALE_JIS && *sp == 0x1b)) {
1217 #else
1218 	    else if (*sp < 32) {
1219 #endif
1220 	      if (!extrach) extrach = 2;
1221 	      if      (extrach == 2) *lp = '^';
1222 	      else if (extrach == 1) *lp = *sp + 64;
1223 	    }
1224 
1225 #ifdef TV_L10N
1226 	    /* convert to EUC-Japan */
1227 	    else if (tv->code == LOCALE_JIS) {
1228 	      if (*sp == 0x1b) {	/* ESC */
1229 		if (*(sp+1) == '$') {
1230 		  if (*(sp+2) == 'B' || *(sp+2) == 'A' || *(sp+2) == '@') {
1231 		    /* ESC $ B,  ESC $ A,  ESC $ @ */
1232 		    desig_stat = 1;
1233 		    sp += 3;  cpos--;  lp--;
1234 		  }
1235 		  else if (*(sp+2) == '(' && *(sp+3) == 'B') {
1236 		    /* ESC $ ( B */
1237 		    desig_stat = 1;
1238 		    sp += 4;  cpos--;  lp--;
1239 		  }
1240 		}
1241 		else if (*(sp+1) == '(') {
1242 		  if (*(sp+2) == 'B' || *(sp+2) == 'J' || *(sp+2) == 'H') {
1243 		    /* ESC ( B,  ESC ( J,  ESC ( H */
1244 		    desig_stat = 0;
1245 		    sp += 3;  cpos--;  lp--;
1246 		  }
1247 		  else if (*(sp+2) == 'I') {
1248 		    /* ESC ( I */
1249 		    desig_stat = 2;
1250 		    sp += 3;  cpos--;  lp--;
1251 		  }
1252 		}
1253 		else if (*(sp+1) == ')' && *(sp+2) == 'I') {
1254 		  /* ESC ) I */
1255 		  desig_stat = 2;
1256 		  sp += 3;  cpos--;  lp--;
1257 		}
1258 		else {	/* error */
1259 		  *lp = ' ';  sp++;
1260 		}
1261 	      }
1262 
1263 	      else {
1264 		switch (desig_stat) {
1265 		case 0:		/* ASCII */
1266 		  *lp = *sp++;
1267 		  break;
1268 		case 1:		/* JIS X 0208 */
1269 		  *lp++ = *sp++ | 0x80;
1270 		  *lp   = *sp++ | 0x80;
1271 		  cpos++;
1272 		  break;
1273 		case 2:		/* JIS X 0201 kana */
1274 #if defined(__osf__) && !defined(X_LOCALE)
1275 		  *lp   = '=';  sp++;
1276 #else
1277 		  *lp++ = 0x8e;	/* ^N | 0x80 */
1278 		  *lp   = *sp++ | 0x80;
1279 #endif
1280 		  break;
1281 		default:	/* error */
1282 		  *lp = *sp++;
1283 		  break;
1284 		}
1285 	      }
1286 	    }
1287 
1288 	    else if (tv->code == LOCALE_MSCODE) {
1289 	      if ((*sp >= 0x81 && *sp <= 0x9f)
1290 			 || (*sp >= 0xe0 && *sp <= 0xef)) {
1291 		static u_char c1, c2;
1292 
1293 /*fprintf(stderr, "(%x,%x)->", *sp, *(sp+1));*/
1294 		c1 = ((*sp - ((*sp>=0xe0) ? 0xb0 : 0x70)) << 1)
1295 			- ((*(sp+1)<=0x9e) ? 1 : 0);
1296 		c2 = *(sp+1);
1297 		if      (c2 >= 0x9f)  c2 -= 0x7e;	/* 0x9F - 0xFC */
1298 		else if (c2 >= 0x80)  c2 -= 0x20;	/* 0x80 - 0x9E */
1299 		else		      c2 -= 0x1f;	/* 0x40 - 0x7E */
1300 
1301 		*lp++ = c1 | 0x80;
1302 		*lp   = c2 | 0x80;
1303 		sp += 2;
1304 /*fprintf(stderr, "(%x %x) ", c1 | 0x80, c2 | 0x80);*/
1305 		cpos++;
1306 	      }
1307 
1308 	      else if (*sp >= 0xa1 && *sp <= 0xdf) {	/* JIS X 0201 kana */
1309 #if defined(__osf__) && !defined(X_LOCALE)
1310 		*lp   = '=';  sp++;
1311 #else
1312 		*lp++ = 0x8e;	/* ^N | 0x80 */
1313 		*lp   = *sp++;
1314 #endif
1315 	      }
1316 
1317 	      else *lp = *sp++;
1318 	    }
1319 #endif	/* TV_L10N */
1320 
1321 #ifdef TV_L10N
1322 	    else if (!tv->code && *sp > 127) {
1323 #else
1324 	    else if (*sp > 127) {
1325 #endif
1326 	      if (!extrach) extrach = 4;
1327 	      if      (extrach == 4) *lp = '\\';
1328 	      else if (extrach == 3) *lp = ((u_char)(*sp & 0700) >> 6) + '0';
1329 	      else if (extrach == 2) *lp = ((u_char)(*sp & 0070) >> 3) + '0';
1330 	      else if (extrach == 1) *lp = ((*sp & 0007)) + '0';
1331 	    }
1332 
1333 	    else *lp = *sp++;
1334 
1335 	    if (extrach) {
1336 	      extrach--;
1337 	      if (!extrach) sp++;
1338 	    }
1339 	  }
1340 	}
1341 #ifdef TV_L10N
1342 	*lp = '\0';	/* terminate linestr */
1343 #endif
1344       }
1345 
1346       else {  /* below bottom of file.  Just build a blank str */
1347 	for (cpos = 0; cpos<lwide; cpos++) linestr[cpos]=' ';
1348       }
1349 
1350       /* draw the line */
1351 #ifdef TV_L10N
1352       if (xlocale)
1353 	XmbDrawImageString(theDisp, tv->textW, monofset, theGC,
1354 		3, i*mfhigh + 1 + mfascent, linestr, strlen(linestr));
1355       else
1356 #endif
1357 	XDrawImageString(theDisp, tv->textW, theGC,
1358 		3, i*mfhigh + 3 + mfascent, linestr, lwide);
1359     }  /* for i ... */
1360 #endif /* TV_MULTILINGUAL */
1361   }  /* if hexmode */
1362 
1363 
1364   else { /* HEX MODE */
1365     for (i=0; i<tv->chhigh; i++) {    /* draw each line */
1366       lnum = i + vpos;
1367       if (lnum < tv->hexlines) {
1368 
1369 	char hexstr[80], tmpstr[16];
1370 
1371 	/* generate hex for this line */
1372 	sprintf(hexstr, "0x%08x: ", lnum * 0x10);
1373 
1374 	sp = (const byte *) tv->text + lnum * 0x10;
1375 	ep = (const byte *) tv->text + tv->textlen;      /* ptr to end of buffer */
1376 
1377 	for (j=0; j<16; j++) {
1378 	  if (sp+j < ep) sprintf(tmpstr,"%02x ", sp[j]);
1379 	            else sprintf(tmpstr,"   ");
1380 	  strcat(hexstr, tmpstr);
1381 
1382 	  if (j==7) {
1383 	    if (sp+8<ep) strcat(hexstr,"- ");
1384 	            else strcat(hexstr,"  ");
1385 	  }
1386 	}
1387 	strcat(hexstr," ");
1388 	lp = (byte *) hexstr + strlen(hexstr);
1389 
1390 	for (j=0; j<16; j++) {
1391 	  if (sp+j < ep) {
1392 #ifdef TV_L10N
1393 	    if (sp[j] >= 32 && (sp[j] <= 127 || tv->code)) *lp++ = sp[j];
1394 #else
1395 	    if (sp[j] >= 32 && sp[j] <= 127) *lp++ = sp[j];
1396 #endif
1397 	    else *lp++ = '.';
1398 	  }
1399 	  else *lp++ = ' ';
1400 	}
1401 	*lp = '\0';
1402 
1403 
1404 	/* at this point, 'hexstr' contains an 80 column hex thingy.
1405 	   now build 'linestr', which is going to have hexstr shifted
1406 	   and/or padded with blanks  (ie, the displayed portion or hexstr) */
1407 
1408 	/* skip obscured beginning of line, if any */
1409 	for (cpos=0, sp=(byte *) hexstr; cpos<hpos && *sp;  cpos++, sp++);
1410 
1411 	for (cpos=0, lp=(byte *)linestr;  cpos<lwide; cpos++, lp++) {
1412 	  if (*sp) { *lp = *sp++; }
1413 	  else *lp = ' ';
1414 	}
1415       }
1416       else {   /* below bottom of file.  just build blank str */
1417 	for (cpos=0; cpos<lwide; cpos++) linestr[cpos]=' ';
1418       }
1419 
1420       /* draw the line */
1421       XDrawImageString(theDisp, tv->textW, theGC,
1422 		       3, i*mfhigh + 3 + mfascent, linestr, lwide);
1423     }  /* for i ... */
1424   }  /* else hexmode */
1425 
1426 
1427 
1428   XSetFont(theDisp, theGC, mfont);
1429 
1430   Draw3dRect(tv->textW, 0, 0, (u_int) (tv->twWide-1), (u_int) (tv->twHigh-1),
1431 	     R3D_IN, 2, hicol, locol, infobg);
1432 }
1433 
1434 
1435 
1436 /***************************************************************/
clickText(tv,x,y)1437 static void clickText(tv, x,y)
1438      TVINFO *tv;
1439      int     x,y;
1440 {
1441   int   i;
1442   BUTT *bp;
1443 
1444   for (i=0, bp=tv->but; i<nbutts; i++, bp++) {
1445     if (PTINRECT(x,y,bp->x,bp->y,bp->w,bp->h)) break;
1446   }
1447 
1448   if (i<nbutts) {
1449     if (BTTrack(bp)) doCmd(tv, i);
1450     return;
1451   }
1452 
1453 #ifdef TV_MULTILINGUAL
1454   if (PTINRECT(x, y, tv->csbut.x, tv->csbut.y, tv->csbut.w, tv->csbut.h)) {
1455     if (BTTrack(&tv->csbut))
1456       openCsWin(tv);
1457   }
1458 #endif
1459 }
1460 
1461 
1462 
1463 
1464 /***************************************************************/
keyText(tv,kevt)1465 static void keyText(tv, kevt)
1466      TVINFO    *tv;
1467      XKeyEvent *kevt;
1468 {
1469   char buf[128];
1470   KeySym ks;
1471   int stlen, shift, dealt, ck;
1472 
1473   stlen = XLookupString(kevt, buf, 128, &ks, (XComposeStatus *) NULL);
1474   shift = kevt->state & ShiftMask;
1475   ck    = CursorKey(ks, shift, 1);
1476   dealt = 1;
1477 
1478   RemapKeyCheck(ks, buf, &stlen);
1479 
1480   /* check for arrow keys, Home, End, PgUp, PgDown, etc. */
1481   if (ck!=CK_NONE) textKey(tv,ck);
1482   else dealt = 0;
1483 
1484   if (dealt || !stlen) return;
1485 
1486   /* keyboard equivalents */
1487   switch (buf[0]) {
1488   case '\001':  case 'a':  case 'A':
1489     doCmd(tv, TV_ASCII);   break;      /* ^A = Ascii */
1490   case '\010':  case 'h':  case 'H':
1491     doCmd(tv, TV_HEX);     break;      /* ^H = Hex   */
1492 
1493   case '\021':  case 'q':  case 'Q':
1494   case '\003':  case 'c':  case 'C':
1495   case '\033':
1496     doCmd(tv, TV_CLOSE);   break;      /* ESC = Close window */
1497 
1498   default:     break;
1499   }
1500 
1501 #ifdef TV_L10N
1502   if (xlocale) {
1503     switch (buf[0]) {
1504     case '\022':  case 'r':  case 'R':
1505       doCmd(tv, TV_RESCAN);   break;
1506     case '\012':  case 'j':  case 'J':
1507       doCmd(tv, TV_JIS);      break;
1508     case '\005':  case 'e':  case 'E':
1509     case '\025':  case 'u':  case 'U':
1510       doCmd(tv, TV_EUCJ);     break;
1511     case '\015':  case 'm':  case 'M':
1512     case '\023':  case 's':  case 'S':
1513       doCmd(tv, TV_MSCODE);  break;
1514 
1515     default:  break;
1516     }
1517   }
1518 #endif	/* TV_L10N */
1519 
1520 }
1521 
1522 
1523 /***************************************************/
textKey(tv,key)1524 static void textKey(tv, key)
1525      TVINFO *tv;
1526      int     key;
1527 {
1528   if (!tv->textlen) return;
1529 
1530   /* an arrow key (or something like that) was pressed in icon window.
1531      change selection/scrollbar accordingly */
1532 
1533   if (key == CK_UP)     SCSetVal(&tv->vscrl, tv->vscrl.val - 1);
1534   if (key == CK_DOWN)   SCSetVal(&tv->vscrl, tv->vscrl.val + 1);
1535 
1536   if (key == CK_LEFT)   SCSetVal(&tv->hscrl, tv->hscrl.val - 1);
1537   if (key == CK_RIGHT)  SCSetVal(&tv->hscrl, tv->hscrl.val + 1);
1538 
1539   if (key == CK_PAGEUP)   SCSetVal(&tv->vscrl, tv->vscrl.val - tv->vscrl.page);
1540   if (key == CK_PAGEDOWN) SCSetVal(&tv->vscrl, tv->vscrl.val + tv->vscrl.page);
1541   if (key == CK_HOME)     SCSetVal(&tv->vscrl, tv->vscrl.min);
1542   if (key == CK_END)      SCSetVal(&tv->vscrl, tv->vscrl.max);
1543 }
1544 
1545 
1546 /***************************************************/
doHexAsciiCmd(tv,hexval)1547 static void doHexAsciiCmd(tv, hexval)
1548      TVINFO *tv;
1549      int hexval;
1550 {
1551   int i, oldvscrl, pos;
1552 
1553   if (hexval == tv->hexmode) return;    /* already ascii */
1554   eraseNumLines(tv);
1555   tv->hexmode = hexval;
1556   drawNumLines(tv);
1557 
1558   oldvscrl = tv->vscrl.val;
1559 
1560   /* compute vals, as width and length of text has changed */
1561   computeScrlVals(tv);
1562 
1563   /* try to show same area of file */
1564   if (hexval) {  /* switched to hex mode */
1565     if (oldvscrl < tv->numlines-1) {
1566       pos = tv->lines[oldvscrl] - tv->text;
1567 
1568       SCSetVal(&tv->vscrl, pos / 16);
1569     }
1570   }
1571   else {  /* switch to ascii mode */
1572     pos = oldvscrl * 16;
1573     for (i=0; i<tv->numlines-1; i++) {
1574       if (tv->lines[i+1] - tv->text > pos &&
1575 	  tv->lines[i]   - tv->text <= pos) break;
1576     }
1577     if (i<tv->numlines-1) SCSetVal(&tv->vscrl, i);
1578   }
1579 
1580 #ifdef TV_L10N
1581   /* redraw text */
1582   if (xlocale) {
1583     XClearArea(theDisp, tv->textW, 0, 0,
1584 	       (u_int) tv->twWide, (u_int) tv->twHigh, False);
1585 
1586     drawTextW(0, &tv->vscrl);
1587   }
1588 #endif
1589 #ifdef TV_MULTILINGUAL
1590   XClearArea(theDisp, tv->textW, 0, 0,
1591 	     (u_int) tv->twWide, (u_int) tv->twHigh, False);
1592   drawTextW(0, &tv->vscrl);
1593 #endif
1594 }
1595 
1596 
1597 /***************************************************/
computeText(tv)1598 static void computeText(tv)
1599      TVINFO *tv;
1600 {
1601   /* compute # of lines and linestarts array for given text */
1602 
1603   int   i,j,wide,maxwide,space;
1604   const byte *sp;
1605 
1606 #ifdef TV_L10N
1607   /* select code-set */
1608   if (xlocale)
1609     tv->code = selectCodeset(tv);
1610 #endif	/* TV_L10N */
1611 
1612   if (!tv->text) {
1613     tv->numlines = tv->hexlines = 0;
1614     tv->lines = (const char **) NULL;
1615 #ifdef TV_MULTILINGUAL
1616     if (tv->cv_text != NULL) {
1617 	free(tv->cv_text);
1618 	tv->cv_text = NULL;
1619     }
1620     tv->txt = NULL;
1621 #endif
1622     return;
1623   }
1624 
1625   /* count the # of newline characters in text */
1626   for (i=0, sp=(const byte *) tv->text, tv->numlines=0; i<tv->textlen; i++, sp++) {
1627     if (*sp == '\n') tv->numlines++;
1628   }
1629 
1630   /* +1 for start of line after last \n char, +1 to mark end of that line */
1631   tv->numlines += 2;
1632 
1633   /* build lines array */
1634   tv->lines = (const char **) malloc(tv->numlines * sizeof(char *));
1635   if (!tv->lines) FatalError("out of memory in computeText()");
1636 
1637   j = 0;
1638   tv->lines[j++] = tv->text;
1639   for (i=0, sp=(const byte *) tv->text; i<tv->textlen; i++, sp++) {
1640     if (*sp == '\n') tv->lines[j++] = (char *) (sp + 1);
1641   }
1642 
1643   tv->lines[tv->numlines - 1] = tv->text + tv->textlen + 1;
1644 
1645   /* each line has a trailing '\n' character, except for the last line,
1646      which has a trailing '\0' character.  In any case, all lines can
1647      be printed by printing ((lines[n+1] - lines[n]) - 1) characters,
1648      starting with lines[n].
1649 
1650      Note that there is one more lines[] entry than the actual # of lines,
1651      so as to mark the end of the last line in the same way as all the
1652      others */
1653 
1654   /* compute length of longest line, when shown in 'ascii' mode.  Takes
1655      into account the fact that non-printing chars (<32 or >127) will be
1656      shown in an 'expanded' form.  (<32 chars will be shown as '^A'
1657      (or whatever), and >127 chars will be shown as octal '\275') */
1658 
1659   maxwide = 0;
1660   for (i=0; i<tv->numlines-1; i++) {
1661     /* compute displayed width of line #i */
1662     for (sp=(const byte *) tv->lines[i], wide=0; sp<(const byte *) tv->lines[i+1]-1;
1663 	 sp++) {
1664       if (*sp == '\011') {   /* tab to next multiple of 8 */
1665 	space = ((wide+8) & (~7)) - wide;
1666 	wide += space;
1667       }
1668       else if (*sp <  32) wide += 2;
1669 #ifdef TV_L10N
1670       else if (*sp > 127 && !tv->code) wide += 4;
1671 #else
1672       else if (*sp > 127) wide += 4;
1673 #endif
1674       else wide++;
1675     }
1676     if (wide > maxwide) maxwide = wide;
1677   }
1678   tv->maxwide = maxwide;
1679 
1680 #ifdef TV_MULTILINGUAL
1681   ml_set_charsets(tv->ctx, &tv->ccs.coding_system);
1682   if (tv->cv_text != NULL) {
1683       free(tv->cv_text);
1684       tv->cv_text = NULL;
1685   }
1686   if (tv->ccs.converter == NULL) {
1687       tv->txt = ml_draw_text(tv->ctx, tv->text, tv->textlen);
1688   } else {
1689       tv->cv_text = (*tv->ccs.converter)(tv->text, tv->textlen, &tv->cv_len);
1690       tv->txt = ml_draw_text(tv->ctx, tv->cv_text, tv->cv_len);
1691   }
1692   tv->maxwide = tv->txt->width / mfwide;
1693   tv->numlines = tv->txt->height / mfhigh + 1;
1694 #endif
1695 
1696   tv->hexlines = (tv->textlen + 15) / 16;
1697 }
1698 
1699 
1700 /***************************************************/
1701 #ifdef TV_L10N
selectCodeset(tv)1702 static int selectCodeset(tv)
1703      TVINFO *tv;
1704 {
1705   const byte *sp;
1706   int i, len;
1707   int code = LOCALE_USASCII;	/* == 0 */
1708 
1709 
1710   len = tv->textlen;
1711 
1712   /* select code-set */
1713   if (xlocale) {
1714     sp = (const byte *) tv->text;  i = 0;
1715     while (i < len - 1) {
1716       if (*sp == 0x1b &&
1717 	  (*(sp+1) == '$' || *(sp+1) == '(' || *(sp+1) == ')')) {
1718 	code = LOCALE_JIS;
1719 	break;
1720       }
1721 
1722       else if (*sp >= 0xa1 && *sp <= 0xdf) {
1723 	if (*(sp+1) >= 0xf0 && *(sp+1) <= 0xfe) {
1724 	  code = LOCALE_EUCJ;
1725 	  break;
1726 	}
1727 #  if (LOCALE_DEFAULT == LOCALE_EUCJ)
1728 	else {
1729 	  sp++;  i++;
1730 	}
1731 #  endif
1732       }
1733 
1734       else if ((*sp >= 0x81 && *sp <= 0x9f) || (*sp >= 0xe0 && *sp <= 0xef)) {
1735 	if ((*(sp+1) >= 0x40 && *(sp+1) <= 0x7e) || *(sp+1) == 0x80) {
1736 	  code = LOCALE_MSCODE;
1737 	  break;
1738 	}
1739 	else if (*(sp+1) == 0xfd || *(sp+1) == 0xfe) {
1740 	  code = LOCALE_EUCJ;
1741 	  break;
1742 	}
1743 	else {
1744 	  sp++;  i++;
1745 	}
1746       }
1747 
1748       else if (*sp >= 0xf0 && *sp <= 0xfe) {
1749 	code = LOCALE_EUCJ;
1750 	break;
1751       }
1752 
1753       sp++;  i++;
1754     }
1755     if (!code)  code = LOCALE_DEFAULT;
1756   }
1757 
1758   return code;
1759 }
1760 #endif	/* TV_L10N */
1761 
1762 #ifdef TV_MULTILINGUAL
setCodingSpec(tv,cs)1763 static void setCodingSpec(tv, cs)
1764     TVINFO *tv;
1765     struct coding_spec *cs;
1766 {
1767   if (xvbcmp((char *) &tv->ccs, (char *) cs, sizeof *cs) == 0)
1768     return;
1769 
1770   tv->ccs = *cs;
1771 #if 0
1772   ml_set_charsets(tv->ctx, &tv->ccs.coding_system);
1773   if (tv->cv_text != NULL) {
1774       free(tv->cv_text);
1775       tv->cv_text = NULL;
1776   }
1777   if (tv->ccs.converter == NULL) {
1778       tv->txt = ml_draw_text(tv->ctx, tv->text, tv->textlen);
1779   } else {
1780       tv->cv_text = (*tv->ccs.converter)(tv->text, tv->textlen, &tv->cv_len);
1781       tv->txt = ml_draw_text(tv->ctx, tv->cv_text, tv->cv_len);
1782   }
1783 #else
1784   computeText(tv);
1785   computeScrlVals(tv);
1786 #endif
1787   /* drawTextW(0, &tv->vscrl); */
1788 }
1789 #endif
1790 
1791 
1792 /**********************************************************************/
1793 /* BUILT-IN TEXT FILES ************************************************/
1794 /**********************************************************************/
1795 
1796 
1797 
1798 static char license[10240];
1799 
1800 /***************************************************************/
ShowLicense()1801 void ShowLicense()
1802 {
1803   license[0] = '\0';
1804 
1805   /* build the license text */
1806 #ifdef LC
1807 #  undef LC
1808 #endif
1809 #ifdef __STDC__  /* since "x" is always a static string, this works: */
1810 #  define LC(x) (strcat(license, x "\n"))
1811 #else
1812 #  define LC(x) (strcat(license, x), strcat(license, "\n"))
1813 #endif
1814 
1815   LC("(Note: This has been changed, and hopefully clarified, from the 3.00");
1816   LC("version of this info.  Please read it.)");
1817   LC("");
1818   LC("Thank you for acquiring a copy of XV, a pretty nifty X program.");
1819   LC("I hope you enjoy using it, as I've enjoyed writing it.");
1820   LC("");
1821   LC("The latest version of XV (or at least a pointer to it) is available");
1822   LC("via anonymous ftp on ftp.cis.upenn.edu, in the directory pub/xv.  If");
1823   LC("you're not sure if you have the latest version, or you are missing the");
1824   LC("source or documentation for XV, PLEASE pick up the latest version of");
1825   LC("the xv distribution.  Do *not* send mail unless absolutely necessary");
1826   LC("(ie, you don't have ftp capability).");
1827   LC("");
1828   LC("Note:  The documentation (README.jumbo, xvdocs.ps, and/or xvdocs.pdf)");
1829 #ifdef __STDC__
1830   LC("may be installed in '" DOCDIR "'.");
1831 #else
1832   LC("may be installed in '/usr/local/share/doc/xv'.");
1833 #endif
1834   LC("");
1835   LC("If you're viewing this information via the 'About XV' command, and");
1836   LC("you'd like to print it out, a copy of this info can be found in the ");
1837   LC("README file in the top-level XV source directory.  Print that.  If you");
1838   LC("don't have it, see the previous paragraph.");
1839   LC("");
1840   LC("");
1841   LC("XV Licensing Information");
1842   LC("------------------------");
1843   LC("XV IS SHAREWARE FOR PERSONAL USE ONLY.");
1844   LC("");
1845   LC("You may use XV for your own amusement, and if you find it nifty,");
1846   LC("useful, generally cool, or of some value to you, your registration fee");
1847   LC("would be greatly appreciated.  $25 is the standard registration fee,");
1848   LC("though of course, larger amounts are quite welcome.  Folks who donate");
1849   LC("$40 or more can receive a printed, bound copy of the XV manual for no");
1850   LC("extra charge.  If you want one, just ask.  Be sure to specify the");
1851   LC("version of xv that you are using!");
1852   LC("");
1853   LC("COMMERCIAL, GOVERNMENT, AND INSTITUTIONAL USERS MUST REGISTER THEIR");
1854   LC("COPIES OF XV.");
1855   LC("");
1856   LC("This does *not* mean that you are required to register XV just because");
1857   LC("you play with it on the workstation in your office.  This falls under");
1858   LC("the heading of 'personal use'.  If you are a sysadmin, you can put XV");
1859   LC("up in a public directory for your users amusement.  Again, 'personal");
1860   LC("use', albeit plural.");
1861   LC("");
1862   LC("On the other hand, if you use XV in the course of doing your work,");
1863   LC("whatever your 'work' may happen to be, you *must* register your");
1864   LC("copy of XV.  (Note:  If you are a student, and you use XV to do");
1865   LC("classwork or research, you should get your professor/teacher/advisor");
1866   LC("to purchase an appropriate number of copies.)");
1867   LC("");
1868   LC("XV licenses are $25 each.  You should purchase one license per");
1869   LC("workstation, or one per XV user, whichever is the smaller number.  XV");
1870   LC("is *not* sold on a 'number of concurrent users' basis.  If XV was some");
1871   LC("$1000 program, yes, that would be a reasonable request, but at $25,");
1872   LC("it's not.  Also, given that XV is completely unlocked, there is no way");
1873   LC("to enforce any 'number of concurrent users' limits, so it isn't sold");
1874   LC("that way.");
1875   LC("");
1876   LC("Printed and bound copies of the 100-odd page XV manual are available");
1877   LC("for $15 each.  Note that manuals are *only* sold with, at minimum, an");
1878   LC("equal number of licenses.  (e.g.  if you purchase 5 licenses, you can");
1879   LC("also purchase *up to* 5 copies of the manual)");
1880   LC("");
1881   LC("The source code to the program can be had (as a compressed 'tar' file");
1882   LC("split over a couple 3.5\" MS-DOS formatted disks) for $15, for those");
1883   LC("who don't have ftp capabilities.");
1884   LC("");
1885   LC("Orders outside the US and Canada must add an additional $5 per manual");
1886   LC("ordered to cover the additional shipping charges.");
1887   LC("");
1888   LC("Checks, money orders, and purchase orders are accepted.  Credit cards");
1889   LC("are not.  All forms of payment must be payable in US Funds.  Checks");
1890   LC("must be payable through a US bank (or a US branch of a non-US bank).");
1891   LC("Purchase orders for less than $50, while still accepted, are not");
1892   LC("encouraged.");
1893   LC("");
1894   LC("All payments should be payable to 'John Bradley', and mailed to:");
1895   LC("        John Bradley");
1896   LC("        1053 Floyd Terrace");
1897   LC("        Bryn Mawr, PA  19010");
1898   LC("        USA");
1899   LC("");
1900   LC("");
1901   LC("Site Licenses");
1902   LC("-------------");
1903   LC("If you are planning to purchase 10 or more licenses, site licenses are");
1904   LC("available, at a substantial discount.  Site licenses let you run XV on");
1905   LC("any and all computing equipment at the site, for any purpose");
1906   LC("whatsoever.  The site license covers the current version of XV, and");
1907   LC("any versions released within one year of the licensing date.  You are");
1908   LC("also allowed to duplicate and distribute an unlimited number of copies");
1909   LC("of the XV manual, but only for use within the site.  Covered versions");
1910   LC("of the software may be run in perpetuity.");
1911   LC("");
1912   LC("Also, it should be noted that a 'site' can be defined as anything");
1913   LC("you'd like.  It can be a physical location (a room, building,");
1914   LC("location, etc.), an organizational grouping (a workgroup, department,");
1915   LC("division, etc.) or any other logical grouping (\"the seventeen");
1916   LC("technical writers scattered about our company\", etc.).");
1917   LC("");
1918   LC("The site license cost will be based on your estimate of the number of");
1919   LC("XV users or workstations at your site, whichever is the smaller");
1920   LC("number.");
1921   LC("");
1922   LC("If you are interested in obtaining a site license, please contact the");
1923   LC("author via electronic mail or FAX (see below for details).  Send");
1924   LC("information regarding your site (the name or definition of the 'site',");
1925   LC("a physical address, a fax number, and an estimate of the number of");
1926   LC("users or workstations), and we'll get a site license out to you for");
1927   LC("your examination.");
1928   LC("");
1929   LC("");
1930   LC("Copyright Notice");
1931   LC("----------------");
1932   LC("XV is Copyright 1989, 1994 by John Bradley");
1933   LC("");
1934   LC("Permission to copy and distribute XV in its entirety, for");
1935   LC("non-commercial purposes, is hereby granted without fee, provided that");
1936   LC("this license information and copyright notice appear in all copies.");
1937   LC("");
1938   LC("If you redistribute XV, the *entire* contents of this distribution");
1939   LC("must be distributed, including the README, and INSTALL files, the");
1940   LC("sources, and the complete contents of the 'docs' directory.");
1941   LC("");
1942   LC("Note that distributing XV 'bundled' in with any product is considered");
1943   LC("to be a 'commercial purpose'.");
1944   LC("");
1945   LC("Also note that any copies of XV that are distributed MUST be built");
1946   LC("and/or configured to be in their 'unregistered copy' mode, so that it");
1947   LC("is made obvious to the user that XV is shareware, and that they should");
1948   LC("consider registering, or at least reading this information.");
1949   LC("");
1950   LC("The software may be modified for your own purposes, but modified");
1951   LC("versions may not be distributed without prior consent of the author.");
1952   LC("");
1953   LC("This software is provided 'as-is', without any express or implied");
1954   LC("warranty.  In no event will the author be held liable for any damages");
1955   LC("arising from the use of this software.");
1956   LC("");
1957   LC("If you would like to do something with XV that this copyright");
1958   LC("prohibits (such as distributing it with a commercial product, using");
1959   LC("portions of the source in some other program, distributing registered");
1960   LC("copies, etc.), please contact the author (preferably via email).");
1961   LC("Arrangements can probably be worked out.");
1962   LC("");
1963   LC("");
1964   LC("The author may be contacted via:");
1965   LC("    US Mail:  John Bradley");
1966   LC("              1053 Floyd Terrace");
1967   LC("              Bryn Mawr, PA  19010");
1968   LC("");
1969   LC("    FAX:     (610) 520-2042");
1970   LC("");
1971   LC("Electronic Mail regarding XV should be sent to one of these addresses:");
1972   LC("     xv@devo.dccs.upenn.edu               - general XV questions");
1973   LC("     xvbiz@devo.dccs.upenn.edu            - all XV licensing questions");
1974   LC("     xvtech@devo.dccs.upenn.edu           - bug reports, technical questions");
1975   LC("");
1976   LC("Please do *not* send electronic mail directly to the author, as he");
1977   LC("gets more than enough as it is.");
1978   LC("");
1979 
1980 #undef LC
1981 
1982   OpenTextView(license, (int) strlen(license), "About XV", 0);
1983 }
1984 
1985 
1986 
1987 static char keyhelp[10240];
1988 
1989 /***************************************************************/
ShowKeyHelp()1990 void ShowKeyHelp()
1991 {
1992   keyhelp[0] = '\0';
1993 
1994 #undef LC
1995 #ifdef __STDC__  /* since "x" is always a static string, this works: */
1996 #  define LC(x) (strcat(keyhelp, x "\n"))
1997 #else
1998 #  define LC(x) (strcat(keyhelp, x), strcat(keyhelp, "\n"))
1999 #endif
2000 
2001   LC("XV Mouse and Keyboard Usage");
2002   LC("===========================");
2003   LC("");
2004   LC("Part 1:  Mouse Usage in the Image Window");
2005   LC("----------------------------------------");
2006   LC("                 Button1 - draws a selection rectangle");
2007   LC("                 Button2 - pixel values, measures dist., picks color");
2008   LC("                 Button3 - opens/closes the 'xv controls' window");
2009   LC("");
2010   LC("          ctrl + Button1 - zooms in");
2011   LC("          ctrl + Button2 - pans");
2012   LC("          ctrl + Button3 - zooms out");
2013   LC("");
2014   LC("  shift        + Button1 - draws a square selection rectangle");
2015   LC("  shift        + Button2 - freehand drawing tool");
2016   LC("  shift + ctrl + Button2 - draws lines");
2017   LC("  shift        + Button3 - smudging tool");
2018   LC("  ");
2019   LC("Part 1a:  Mouse Usage in Selection Rectangle");
2020   LC("--------------------------------------------");
2021   LC("                 Button1 - moves selection rectangle");
2022   LC("  shift        + Button1 - moves selection, constrains motion");
2023   LC("                 Button2 - 'drag-and-drop' cut and paste");
2024   LC("  shift        + Button2 - 'drag-and-drop' cut and paste, constrain");
2025   LC("          ctrl + Button2 - 'drag-and-drop' copy and paste");
2026   LC("  shift + ctrl + Button2 - 'drag-and-drop' copy and paste, constrain");
2027   LC("");
2028   LC("");
2029   LC("");
2030   LC("Part 2:  Normal Keyboard Equivalents");
2031   LC("------------------------------------");
2032   LC("The following keys can be used in most xv windows, including the");
2033   LC("image, controls, and color editor windows, but *not* in the Visual");
2034   LC("Schnauzer windows.");
2035   LC("");
2036   LC("  Tab or");
2037   LC("  Space         - 'Next' command");
2038   LC("");
2039   LC("  Return        - reload currently displayed image file");
2040   LC("");
2041   LC("  Del or");
2042   LC("  Backspace     - 'Prev' command");
2043   LC("");
2044   LC("  ctrl+'l'      - 'Load' command");
2045   LC("  ctrl+'s'      - 'Save' command");
2046   LC("  ctrl+'p'      - 'Print' command");
2047   LC("  ctrl+'d'      - 'Delete' command");
2048   LC("");
2049   LC("  'q' or");
2050   LC("  ctrl+'q'      - 'Quit' command");
2051   LC("");
2052   LC("  meta+'x'      - 'cut' command");
2053   LC("  meta+'c'      - 'copy' command");
2054   LC("  meta+'v'      - 'paste' command");
2055   LC("  meta+'d'      - 'clear' command");
2056   LC("");
2057   LC("  'n'           - reset image to normal (unexpanded) size");
2058   LC("  'm'           - maximum image size");
2059   LC("  'M'           - maximum image size, maintaining aspect ratio");
2060   LC("  '>'           - double image size");
2061   LC("  '<'           - half image size");
2062   LC("  '.'           - make image 10% larger");
2063   LC("  ','           - make image 10% smaller");
2064   LC("  'S'           - set image to specified size/expansion");
2065   LC("  'a'           - reset image to normal aspect ratio");
2066   LC("  '4'           - make image have a 4x3 width/height ratio");
2067   LC("  'I'           - round image size to integer expand/compres ratios");
2068   LC("");
2069   LC("  't'           - turn image 90 degrees clockwise");
2070   LC("  'T'           - turn image 90 degrees counter-clockwise");
2071   LC("  'h'           - flip image horizontally");
2072   LC("  'v'           - flip image vertically");
2073   LC("");
2074   LC("  'P'           - pad image");
2075   LC("  'A'           - image annotation");
2076   LC("  'c'           - 'Crop' command");
2077   LC("  'u'           - 'UnCrop' command");
2078   LC("  'C'           - 'AutoCrop' command");
2079   LC("");
2080   LC("  'r'           - raw mode");
2081   LC("  'd'           - dithered mode");
2082   LC("  's'           - smooth mode");
2083   LC("  meta+'8'      - toggle 8/24 bit mode");
2084   LC("");
2085   LC("  'V' or");
2086   LC("  ctrl+'v'      - Visual Schnauzer");
2087   LC("  'e'           - Color Editor");
2088   LC("  'i'           - Image Info");
2089   LC("  ctrl+'c'      - Image Comments");
2090   LC("  ctrl+'t'      - Text View");
2091   LC("");
2092   LC("  ctrl+'g'      - 'Grab' command");
2093   LC("  ctrl+'a'      - 'About XV' command");
2094   LC("");
2095   LC("  meta+'b'      - Blur algorithm");
2096   LC("  meta+'s'      - Sharpen algorithm");
2097   LC("  meta+'e'      - Edge Detection algorithm");
2098   LC("  meta+'m'      - Emboss algorithm");
2099   LC("  meta+'o'      - Oil Paint algorithm");
2100   LC("  meta+'B'      - Blend algorithm");
2101   LC("  meta+'t'      - Copy rotate algorithm");
2102   LC("  meta+'T'      - Clear rotate algorithm");
2103   LC("  meta+'p'      - Pixelize algorithm");
2104   LC("  meta+'S'      - Spread algorithm");
2105   LC("");
2106   LC("  'R' or");
2107   LC("  meta+'r' or");
2108   LC("  meta+'0'      - 'Reset' command in color editor");
2109   LC("");
2110   LC("  meta+'1'      - select preset 1 in color editor");
2111   LC("  meta+'2'      - select preset 2 in color editor");
2112   LC("  meta+'3'      - select preset 3 in color editor");
2113   LC("  meta+'4'      - select preset 4 in color editor");
2114   LC("  meta+'a'      - 'Apply' command in color editor");
2115   LC("");
2116   LC("");
2117   LC("");
2118   LC("Part 2a:  Image Window Keys");
2119   LC("---------------------------");
2120   LC("The following keys can be used *only* inside the image window.");
2121   LC("");
2122   LC("  ctrl + Up     - crops 1 pixel off the bottom of the image");
2123   LC("  ctrl + Down   - crops 1 pixel off the top of the image");
2124   LC("  ctrl + Left   - crops 1 pixel off the right side of the image");
2125   LC("  ctrl + Right  - crops 1 pixel off the left side of the image");
2126   LC("");
2127   LC("  If you're viewing a multi-page document:");
2128   LC("  'p'           -  opens a 'go to page #' dialog box");
2129   LC("");
2130   LC("  PageUp, or");
2131   LC("  Prev, or");
2132   LC("  shift+Up      - previous page");
2133   LC("");
2134   LC("  PageDown, or");
2135   LC("  Next, or");
2136   LC("  shift+Down    - next page");
2137   LC("");
2138   LC("");
2139   LC("  If a selection rectangle is active");
2140   LC("  Up            - move rectangle up 1 pixel");
2141   LC("  Down          - move rectangle down 1 pixel");
2142   LC("  Left          - move rectangle left 1 pixel");
2143   LC("  Right         - move rectangle right 1 pixel");
2144   LC("  shift+Up      - shrink rectangle vertically by 1 pixel");
2145   LC("  shift+Down    - expand rectangle vertically by 1 pixel");
2146   LC("  shift+Left    - shrink rectangle horizontally by 1 pixel");
2147   LC("  shift+Right   - expand rectangle horizontally by 1 pixel");
2148   LC("");
2149   LC("");
2150   LC("Part 2b:  Visual Schnauzer Keys");
2151   LC("-------------------------------");
2152   LC("The following keys can be used only in the Visual Schnauzer windows.");
2153   LC("");
2154   LC("  ctrl+'d'      - delete file(s)");
2155   LC("  ctrl+'n'      - create new directory");
2156   LC("  ctrl+'r'      - rename file");
2157   LC("  ctrl+'s'      - rescan directory");
2158   LC("  ctrl+'w'      - open new window");
2159   LC("  ctrl+'u'      - update icons");
2160   LC("  ctrl+'g'      - generate icons for selected files");
2161   LC("  ctrl+'a'      - select all files");
2162   LC("  ctrl+'t'      - view selected file as text");
2163   LC("  ctrl+'q'      - quit XV");
2164   LC("  ctrl+'c'      - change directory");
2165   LC("  ctrl+'f'      - select filenames");
2166   LC("  ctrl+'e'      - recursive update");
2167   LC("  Esc           - close window");
2168   LC("  Return        - load currently selected file(s)");
2169   LC("  Space         - load next file");
2170   LC("  shift+Space   - load next file, keeping previous file(s) selected");
2171   LC("  Backspace     - load previous file");
2172 
2173 #undef LC
2174   OpenTextView(keyhelp, (int) strlen(keyhelp), "XV Help", 0);
2175 }
2176 
2177 #ifdef TV_MULTILINGUAL
2178 
2179 #define TV_ML_ACCEPT TV_NCSS
2180 #define TV_ML_CLOSE  (TV_ML_ACCEPT + 1)
2181 #define TV_ML_NBUTTS (TV_ML_CLOSE + 1)
2182 
2183 #define TV_ML_RETCODE	0
2184 #	define TV_ML_RET_LF	0
2185 #	define TV_ML_RET_CRLF	1
2186 #	define TV_ML_RET_CR	2
2187 #	define TV_ML_RET_ANY	3
2188 #define TV_ML_GL	1
2189 #define TV_ML_GR	2
2190 #define TV_ML_CVTR	3
2191 #define TV_ML_NRBUTTS	4
2192 
2193 #define TV_ML_SHORT	0
2194 #define TV_ML_LOCK	1
2195 #define TV_ML_NCBUTTS	2
2196 
2197 #define TV_ML_NLISTS	4
2198 
2199 #define CSWIDE (BUTTW3 * 5 + 5 * 6)
2200 #define CSHIGH 450
2201 
2202 typedef struct csinfo_t {
2203     TVINFO *tv;
2204     RBUTT *rbt[TV_ML_NRBUTTS];
2205     CBUTT cbt[TV_ML_NCBUTTS];
2206     LIST ls[TV_ML_NLISTS];
2207     BUTT bt[TV_ML_NBUTTS];
2208     int up;
2209     Window win;
2210     struct coding_spec tcs;	/* temporary coding_spec */
2211 } CSINFO;
2212 CSINFO csinfo[MAXTVWIN];
2213 static char **regs;
2214 static int nregs;
2215 
2216 static int  csCheckEvent           PARM((CSINFO *, XEvent *));
2217 static void csReflect              PARM((CSINFO *));
2218 static void csRedraw               PARM((CSINFO *));
2219 static void csListRedraw           PARM((LIST *));
2220 static void csLsRedraw             PARM((int, SCRL *));
2221 static void create_registry_list   PARM((void));
2222 
2223 static char *(*cvtrtab[])PARM((char *, int, int *)) = {
2224     NULL,
2225     sjis_to_jis,
2226 };
2227 
createCsWins(geom)2228 static void createCsWins(geom)
2229     const char *geom;
2230 {
2231     XSetWindowAttributes xswa;
2232     int i, j;
2233 
2234     create_registry_list();
2235 
2236     xswa.backing_store = WhenMapped;
2237     for (i = 0; i < MAXTVWIN; i++) {
2238 	char nam[8];
2239 	TVINFO *tv = &tinfo[i];
2240 	CSINFO *cs = &csinfo[i];
2241 	tv->cs = cs;
2242 	cs->tv = tv;
2243 	sprintf(nam, "XVcs%d", i);
2244 	cs->win = CreateWindow("xv codeset", nam, geom,
2245 			       CSWIDE, CSHIGH, infofg, infobg, 0);
2246 	if (!cs->win) FatalError("couldn't create 'charset' window!");
2247 #ifdef BACKING_STORE
2248 	XChangeWindowAttributes(theDisp, cs->win, CWBackingStore, &xswa);
2249 #endif
2250 	XSelectInput(theDisp, cs->win, ExposureMask | ButtonPressMask);
2251 
2252 	DrawString(cs->win, 5, 5 + ASCENT, "Initial States");
2253 	for (i = 0; i < TV_ML_NLISTS; i++) {
2254 	    int x, y;
2255 	    char buf[80];
2256 
2257 	    if (i / 2 == 0)
2258 		x = 15;
2259 	    else
2260 		x = 280;
2261 	    if (i % 2 == 0)
2262 		y = 5 + LINEHIGH * 1;
2263 	    else
2264 		y = 5 + LINEHIGH * 7 + SPACING * 3;
2265 
2266 	    sprintf(buf, "Designation for G%d:", i + 1);
2267 	    DrawString(cs->win, x, y + ASCENT, buf);
2268 
2269 	    LSCreate(&cs->ls[i], cs->win, x + 15, y + LINEHIGH,
2270 			200, LINEHIGH * 5, 5,
2271 			regs, nregs + 2,
2272 			infofg, infobg, hicol, locol, csLsRedraw, 0, 0);
2273 	    cs->ls[i].selected = 0;
2274 	}
2275 
2276 	for (i = 0; i < 2; i++) {
2277 	    char *p;
2278 	    int n;
2279 	    int x, y;
2280 
2281 	    if ((p = (char *) malloc(3 * 4)) == NULL)
2282 		FatalError("out of memory in createCsWins().");
2283 	    strcpy(p, "G1 G2 G3 G4");
2284 	    p[2] = p[5] = p[8] = '\0';
2285 	    n = (i == 0 ? TV_ML_GL : TV_ML_GR);
2286 	    x = (i == 0 ? 15 : 280);
2287 	    y = 235;
2288 	    DrawString(cs->win, x, y + ASCENT, "Assignment for GL:");
2289 	    x += 15;
2290 	    y += LINEHIGH;
2291 	    cs->rbt[n] = RBCreate(NULL, cs->win,
2292 				  x, y, p, infofg, infobg, hicol, locol);
2293 	    for (j = 1; j < 4; j++) {
2294 		p += 3;
2295 		x += 50;
2296 		RBCreate(cs->rbt[n], cs->win,
2297 			 x, y, p, infofg, infobg, hicol, locol);
2298 	    }
2299 	}
2300 
2301 	DrawString(cs->win, 5, 280 + ASCENT, "Ret Code:");
2302 	cs->rbt[TV_ML_RETCODE] =
2303 	    RBCreate(NULL, cs->win, 20, 300, "LF", infofg,infobg, hicol,locol);
2304 	RBCreate(cs->rbt[TV_ML_RETCODE], cs->win, 20, 300 + 20, "CR+LF",
2305 		 infofg, infobg, hicol, locol);
2306 	RBCreate(cs->rbt[TV_ML_RETCODE], cs->win, 90, 300, "CR",
2307 		 infofg, infobg, hicol, locol);
2308 	RBCreate(cs->rbt[TV_ML_RETCODE], cs->win, 90, 300 + 20, "Any",
2309 		 infofg, infobg, hicol, locol);
2310 
2311 	DrawString(cs->win, 350, 280 + ASCENT, "Converter:");
2312 	cs->rbt[TV_ML_CVTR] =
2313 	    RBCreate(NULL, cs->win, 365, 300, "Nothing",
2314 		     infofg, infobg, hicol, locol);
2315 	RBCreate(cs->rbt[TV_ML_CVTR], cs->win, 365, 300 + 20, "Shift JIS",
2316 		 infofg, infobg, hicol, locol);
2317 
2318 	CBCreate(&cs->cbt[TV_ML_SHORT], cs->win, 200, 300, "Short Form",
2319 		 infofg, infobg, hicol, locol);
2320 	CBCreate(&cs->cbt[TV_ML_LOCK], cs->win, 200, 320, "Locking Shift",
2321 		 infofg, infobg, hicol, locol);
2322 
2323 	for (j = 0; j < TV_NCSS; j++) {
2324 	    BTCreate(&cs->bt[j], cs->win,
2325 		     5 + (BUTTW3 + 5) * (j % 5),
2326 		     350 + 5 + (BUTTH + 5) * (j / 5),
2327 		     BUTTW3, BUTTH, codeSetNames[j],
2328 		     infofg, infobg, hicol, locol);
2329 	}
2330 	BTCreate(&cs->bt[TV_ML_ACCEPT], cs->win,
2331 		 CSWIDE - 10 - BUTTW3 * 2, CSHIGH - 5 - BUTTH, BUTTW3, BUTTH,
2332 		 "Accept", infofg, infobg, hicol, locol);
2333 	BTCreate(&cs->bt[TV_ML_CLOSE], cs->win,
2334 		 CSWIDE - 5 - BUTTW3, CSHIGH - 5 - BUTTH, BUTTW3, BUTTH,
2335 		 "Close", infofg, infobg, hicol, locol);
2336 
2337 	XMapSubwindows(theDisp, cs->win);
2338 	cs->up = 0;
2339     }
2340 }
2341 
openCsWin(tv)2342 static void openCsWin(tv)
2343     TVINFO *tv;
2344 {
2345     CSINFO *cs = tv->cs;
2346     if (cs->up)
2347 	return;
2348 
2349     XMapRaised(theDisp, cs->win);
2350     cs->up = 1;
2351     cs->tcs = cs->tv->ccs;
2352     csReflect(cs);
2353 }
2354 
closeCsWin(tv)2355 static void closeCsWin(tv)
2356     TVINFO *tv;
2357 {
2358     CSINFO *cs = tv->cs;
2359     if (!cs->up)
2360 	return;
2361     cs->up = 0;
2362     XUnmapWindow(theDisp, cs->win);
2363 }
2364 
CharsetCheckEvent(xev)2365 int CharsetCheckEvent(xev)
2366     XEvent *xev;
2367 {
2368     int i;
2369     CSINFO *cs;
2370 
2371     for (cs = csinfo, i = 0; i < MAXTVWIN; cs++, i++) {
2372 	if (!cs->up)
2373 	    continue;
2374 	if (csCheckEvent(cs, xev))
2375 	    break;
2376     }
2377     if (i < MAXTVWIN)
2378 	return 1;
2379     return 0;
2380 }
2381 
csCheckEvent(cs,xev)2382 static int csCheckEvent(cs, xev)
2383     CSINFO *cs;
2384     XEvent *xev;
2385 {
2386     RBUTT **rbp;
2387     CBUTT *cbp;
2388     LIST *ls;
2389     BUTT *bp;
2390     int i, n;
2391 
2392     if (xev->type == Expose) {
2393 	int x, y, w, h;
2394 	XExposeEvent *e = (XExposeEvent *) xev;
2395 	x = e->x; y = e->y; w = e->width; h = e->height;
2396 
2397 	if (cs->win == e->window){
2398 	    csRedraw(cs);
2399 	    return 1;
2400 	} else {
2401 	    for (i = 0; i < TV_ML_NLISTS; i++) {
2402 		if (cs->ls[i].win == e->window) {
2403 		    LSRedraw(&cs->ls[i], 0);
2404 		    return 1;
2405 		}
2406 	    }
2407 	   for (i = 0; i < TV_ML_NLISTS; i++) {
2408 		if (cs->ls[i].scrl.win == e->window) {
2409 		    SCRedraw(&cs->ls[i].scrl);
2410 		    return 1;
2411 		}
2412 	   }
2413 	}
2414     } else if (xev->type == ButtonPress) {
2415 	int x, y;
2416 	XButtonEvent *e = (XButtonEvent *) xev;
2417 	x = e->x; y = e->y;
2418 	if (cs->win == e->window) {
2419 	    for (bp = cs->bt, i = 0; i < TV_ML_NBUTTS; bp++, i++) {
2420 		if (PTINRECT(x, y, bp->x, bp->y, bp->w, bp->h))
2421 		    break;
2422 	    }
2423 	    if (i < TV_ML_NBUTTS) {
2424 		if (BTTrack(bp)) {
2425 		    if (i < TV_NCSS) {
2426 			cs->tcs = coding_spec[i];
2427 			csReflect(cs);
2428 		    } else {
2429 			switch (i) {
2430 			case TV_ML_ACCEPT:
2431 			    setCodingSpec(cs->tv, &cs->tcs);
2432 			    break;
2433 			case TV_ML_CLOSE:
2434 			    closeCsWin(cs->tv);
2435 			    break;
2436 			}
2437 		    }
2438 		}
2439 		return 1;
2440 	    }
2441 	    for (cbp = cs->cbt, i = 0; i < TV_ML_NCBUTTS; cbp++, i++) {
2442 		if (CBClick(cbp, x, y) && CBTrack(cbp))
2443 		    break;
2444 	    }
2445 	    if (i < TV_ML_NCBUTTS) {
2446 		switch (i) {
2447 		case TV_ML_SHORT:
2448 		    cs->tcs.coding_system.short_form = cbp->val;
2449 		    break;
2450 		case TV_ML_LOCK:
2451 		    cs->tcs.coding_system.lock_shift = cbp->val;
2452 		    break;
2453 		}
2454 		return 1;
2455 	    }
2456 	    for (rbp = cs->rbt, i = 0; i < TV_ML_NRBUTTS; rbp++, i++) {
2457 		if ((n = RBClick(*rbp, x, y)) >= 0 && RBTrack(*rbp, n)) {
2458 		    break;
2459 		}
2460 	    }
2461 	    if (i < TV_ML_NRBUTTS) {
2462 		switch (i) {
2463 		case TV_ML_RETCODE:
2464 		    cs->tcs.coding_system.eol = n;
2465 		    break;
2466 		case TV_ML_GL:
2467 		    cs->tcs.coding_system.gl = n;
2468 		    break;
2469 		case TV_ML_GR:
2470 		    cs->tcs.coding_system.gr = n;
2471 		    break;
2472 		case TV_ML_CVTR:
2473 		    cs->tcs.converter = cvtrtab[n];
2474 		    break;
2475 		}
2476 		return 1;
2477 	    }
2478 	} else {
2479 	    for (ls = cs->ls, i = 0; i < TV_ML_NLISTS; ls++, i++) {
2480 		if (ls->win == e->window) {
2481 		    LSClick(ls, e);
2482 		    n = ls->selected;
2483 		    if (n < nregs) {
2484 			char r[32], *p = r;
2485 			int b7;
2486 			strcpy(r, regs[n]);
2487 			if ((p = strrchr(r, '/')) != NULL) {
2488 			    *p = '\0';
2489 			    b7 = (*(p + 1) == 'R' ? 1 : 0);
2490 			} else
2491 			    b7 = 0;	/* shouldn't occur */
2492 			cs->tcs.coding_system.design[i] = lookup_design(r, b7);
2493 		    } else if (n == nregs)    /* initially none is designed. */
2494 			cs->tcs.coding_system.design[i].bpc = 0;
2495 		    else
2496 			cs->tcs.coding_system.design[i].bpc = -1;
2497 		    return 1;
2498 		}
2499 	    }
2500 	    for (ls = cs->ls, i = 0; i < TV_ML_NLISTS; ls++, i++) {
2501 		if (ls->scrl.win == e->window) {
2502 		    SCTrack(&ls->scrl, x, y);
2503 		    return 1;
2504 		}
2505 	    }
2506 	}
2507     }
2508     return 0;
2509 }
2510 
csReflect(cs)2511 static void csReflect(cs)
2512     CSINFO *cs;
2513 {
2514     int i;
2515 
2516     RBSelect(cs->rbt[TV_ML_RETCODE], cs->tcs.coding_system.eol);
2517     RBSelect(cs->rbt[TV_ML_GL], cs->tcs.coding_system.gl);
2518     RBSelect(cs->rbt[TV_ML_GR], cs->tcs.coding_system.gr);
2519     for (i = 0; i < sizeof cvtrtab / sizeof cvtrtab[0]; i++) {
2520 	if (cs->tcs.converter == cvtrtab[i])
2521 	    break;
2522     }
2523     if (i >= sizeof cvtrtab / sizeof cvtrtab[0])
2524 	FatalError("program error in csReflect().");
2525     RBSelect(cs->rbt[TV_ML_CVTR], i);
2526 
2527     cs->cbt[TV_ML_SHORT].val = cs->tcs.coding_system.short_form;
2528     cs->cbt[TV_ML_LOCK].val = cs->tcs.coding_system.lock_shift;
2529     for (i = 0; i < TV_ML_NLISTS; i++) {
2530 	struct design design = cs->tcs.coding_system.design[i];
2531 	char *reg, r[32];
2532 	int b7;
2533 	int n = 0;
2534 	switch (design.bpc) {
2535 	case -1:
2536 	    n = nregs + 1;
2537 	    break;
2538 	case 0:
2539 	    n = nregs;
2540 	    break;
2541 	case 1:
2542 	case 2:
2543 	    if ((reg = lookup_registry(design, &b7)) == NULL)
2544 		FatalError("internal error in csReflect.");
2545 	    sprintf(r, "%s/%s", reg, b7 ? "Right" : "Left");
2546 	    for (n = 0; n < nregs; n++) {
2547 		if (strcmp(regs[n], r) == 0)
2548 		    break;
2549 	    }
2550 	}
2551 	cs->ls[i].selected = n;
2552 	ScrollToCurrent(&cs->ls[i]);
2553     }
2554     csRedraw(cs);
2555     for (i = 0; i < TV_ML_NLISTS; i++)
2556 	csListRedraw(&cs->ls[i]);
2557 }
2558 
csRedraw(cs)2559 static void csRedraw(cs)
2560     CSINFO *cs;
2561 {
2562     int i;
2563 
2564     XSetForeground(theDisp, theGC, infofg);
2565     DrawString(cs->win,  5,5 + ASCENT, "Initial States");
2566     for (i = 0; i < TV_ML_NLISTS; i++) {
2567 	int x, y;
2568 	char buf[80];
2569 
2570 	if (i / 2 == 0)
2571 	    x = 15;
2572 	else
2573 	    x = 280;
2574 	if (i % 2 == 0)
2575 	    y = 5 + LINEHIGH * 1;
2576 	else
2577 	    y = 5 + LINEHIGH * 7 + SPACING * 3;
2578 
2579 	sprintf(buf, "Designation for G%d:", i);
2580 	DrawString(cs->win, x, y + ASCENT, buf);
2581     }
2582 
2583     DrawString(cs->win,  15, 235 + ASCENT, "Invocation for GL:");
2584     DrawString(cs->win, 280, 235 + ASCENT, "Invocation for GR:");
2585     DrawString(cs->win,   5, 280 + ASCENT, "Ret Code:");
2586     DrawString(cs->win, 350, 280 + ASCENT, "Converter:");
2587 
2588     for (i = 0; i < TV_ML_NBUTTS; i++)
2589 	BTRedraw(&cs->bt[i]);
2590     for (i = 0; i < TV_ML_NCBUTTS; i++)
2591 	CBRedraw(&cs->cbt[i]);
2592     for (i = 0; i < TV_ML_NRBUTTS; i++)
2593 	RBRedraw(cs->rbt[i], -1);
2594 }
2595 
csListRedraw(ls)2596 static void csListRedraw(ls)
2597     LIST *ls;
2598 {
2599     int i;
2600     for (i = 0; i < TV_ML_NLISTS; i++) {
2601 	LSRedraw(ls, 0);
2602 	SCRedraw(&ls->scrl);
2603     }
2604 }
2605 
csLsRedraw(delta,sptr)2606 static void csLsRedraw(delta, sptr)
2607     int delta;
2608     SCRL *sptr;
2609 {
2610     int i, j;
2611     for (i = 0; i < MAXTVWIN; i++) {
2612 	for (j = 0; j < TV_ML_NLISTS; j++) {
2613 	    if (sptr == &csinfo[i].ls[j].scrl) {
2614 		LSRedraw(&csinfo[i].ls[j], delta);
2615 		return;
2616 	    }
2617 	}
2618     }
2619 }
2620 
CharsetDelWin(win)2621 int CharsetDelWin(win)
2622     Window win;
2623 {
2624     CSINFO *cs;
2625     int i;
2626 
2627     for (cs = csinfo, i = 0; i < TV_NCSS; cs++, i++) {
2628 	if (cs->win == win) {
2629 	    if (cs->up) {
2630 		XUnmapWindow(theDisp, cs->win);
2631 		cs->up = 0;
2632 	    }
2633 	    return 1;
2634 	}
2635     }
2636     return 0;
2637 }
2638 
2639 static int reg_comp PARM((const void *, const void *));
create_registry_list()2640 static void create_registry_list()
2641 {
2642     struct design d;
2643     char *names, *p;
2644     int i;
2645 
2646     if ((p = names = (char *) malloc(32 * 0x80 * 2 * 2)) == NULL)
2647 	FatalError("out of memory in create_name_list#1.");
2648     nregs = 0;
2649     for (d.bpc = 1; d.bpc <=2; d.bpc++) {
2650 	for (d.noc = 94; d.noc <= 96; d.noc += 2) {
2651 	    for (d.des = ' '; (unsigned char) d.des < 0x80; d.des++) {
2652 		int b7;
2653 		char *r;
2654 		if ((r = lookup_registry(d, &b7)) != NULL) {
2655 		    sprintf(p, "%s/%s", r, b7 ? "Right" : "Left");
2656 		    p += strlen(p) + 1;
2657 		    nregs++;
2658 		}
2659 	    }
2660 	}
2661     }
2662     if ((names = (char *) realloc(names, (size_t) (p - names))) == NULL)
2663 	FatalError("out of memory in create_name_list#2.");
2664     if ((regs = (char **) malloc(sizeof(char *) * (nregs + 3))) == NULL)
2665 	FatalError("out of memory in create_name_list#3.");
2666     p = names;
2667     for (i = 0; i < nregs; i++) {
2668 	regs[i] = p;
2669 	p += strlen(p) + 1;
2670     }
2671     qsort(regs, (size_t) nregs, sizeof(char *), reg_comp);
2672     regs[i++] = "nothing";
2673     regs[i++] = "unused";
2674     regs[i++] = NULL;
2675 }
reg_comp(dst,src)2676 static int reg_comp(dst, src)
2677     const void *dst, *src;
2678 {
2679     return strcmp(*(char **) dst, *(char **) src);
2680 }
2681 
2682 #endif /* TV_MULTILINGUAL */
2683