1 /*****************************************************************************
2    Major portions of this software are copyrighted by the Medical College
3    of Wisconsin, 1994-2000, and are released under the Gnu General Public
4    License, Version 2.  See the file README.Copyright for details.
5 ******************************************************************************/
6 
7 #include "mrilib.h"
8                          /**************************
9                           * 3dNotes - T. Ross 8/99 *
10                           * adapted by RWCox  9/99 *
11                           **************************/
12 
13 #include <sys/utsname.h>
14 #include <sys/time.h>
15 #include <time.h>
16 #include <unistd.h>
17 #include <stdlib.h>
18 #include <ctype.h>
19 
20 /*---------------------------------------------------------------------------*/
21 /*!  Assemble a sort-of command line string from the arguments;
22      free() this when done.
23 -----------------------------------------------------------------------------*/
24 
tross_commandline(char * pname,int argc,char ** argv)25 char * tross_commandline( char *pname , int argc , char **argv )
26 {
27    char *ch ;
28    int ii , ll ;
29 
30    if( argc < 1 || argv == NULL ) return NULL ; /* ZSS, changed argc < 2 to argc < 1 */
31 
32    if( pname == NULL ) pname = argv[0] ;
33 
34    ii = strlen(pname) ; ch = AFMALL(char, ii+4) ; strcpy(ch,pname) ;
35    if (argc < 2) {  /* ZSS */
36       /* no options, get the hell outa here */
37       return ch ;
38    }
39    for( ii=1 ; ii < argc ; ii++ ){
40       if( argv[ii] == NULL || argv[ii][0] == '\0' ) continue ; /* skip */
41 
42       ll = strlen(argv[ii]) ;
43       ch = AFREALL(ch ,char, strlen(ch)+ll+4 ) ;  /* expand output array */
44 
45       if( !THD_filename_ok(argv[ii]) ){       /* bad characters? */
46          int jj ; char * aa = AFMALL(char, ll+1) ;
47 
48          strcpy(aa,argv[ii]) ;        /* edit out bad characters */
49          for( jj=0 ; jj < ll ; jj++ )
50             if( iscntrl(aa[jj]) ||
51                 isspace(aa[jj]) || (aa[jj] & 128) != 0 ) aa[jj] = ' ' ;
52 
53          strcat(ch," '") ; strcat(ch,aa) ; strcat(ch,"'") ; free(aa) ;
54 
55       } else {
56          strcat(ch," ")  ; strcat(ch,argv[ii]) ;   /* just copy it */
57       }
58    }
59 
60    return ch ;
61 }
62 
63 /*---------------------------------------------------------------------------*/
64 /*!  Get the current date/time string;  free() this when done.
65 -----------------------------------------------------------------------------*/
66 
tross_datetime(void)67 char * tross_datetime(void)
68 {
69    time_t tnow = time(NULL) ; int i ; char * qh , * ch ;
70 
71    ch=ctime(&tnow); i=strlen(ch); qh=AFMALL(char, i+2);
72    strcpy(qh,ch); qh[i-1]='\0';
73    return qh ;
74 }
75 
76 /*---------------------------------------------------------------------------*/
77 
78 #undef  NNAME
79 #define NNAME 1025
tross_hostname(void)80 char * tross_hostname(void)  /* 19 Sep 1999 */
81 {
82    char * cn = AFMALL(char, NNAME) ;
83    gethostname( cn , NNAME ) ;
84    return cn ;
85 }
86 
87 /*---------------------------------------------------------------------------*/
88 
89 #include <pwd.h>
90 
tross_username(void)91 char * tross_username(void)  /* 20 Sep 1999 */
92 {
93    uid_t uu = getuid() ;
94    struct passwd * pwd = getpwuid(uu) ;
95    char * cn = AFMALL(char, NNAME) ;
96 
97    if( pwd == NULL ) strcpy(cn,"nobody") ;
98    else              strcpy(cn,pwd->pw_name) ;
99    return cn ;
100 }
101 
102 /*---------------------------------------------------------------------------*/
103 /*!   Add a note after the last current note
104 -----------------------------------------------------------------------------*/
105 
tross_Add_Note(THD_3dim_dataset * dset,char * cn)106 void tross_Add_Note( THD_3dim_dataset *dset, char *cn )
107 {
108    ATR_int *notecount;
109    int num_notes;
110    char note_name[20], *ch ;
111 
112    if( !ISVALID_DSET(dset) || cn == NULL || cn[0] == '\0' ) return ;
113 
114    notecount = THD_find_int_atr(dset->dblk, "NOTES_COUNT");
115    if (notecount == NULL) {
116       num_notes = 1;
117       THD_set_int_atr(dset->dblk, "NOTES_COUNT", 1, &num_notes);
118    } else {
119       num_notes = notecount->in[0] + 1;
120       if( num_notes > MAX_DSET_NOTES ){
121          fprintf(stderr,"*** attempt to add too many notes to dataset!\n") ;
122          return ;
123       }
124       notecount->in[0]++;
125    }
126 
127    sprintf(note_name, "NOTE_NUMBER_%03d", num_notes);
128    ch = tross_Encode_String(cn) ; if( ch == NULL ) return ;
129    THD_set_string_atr(dset->dblk, note_name, ch);
130    free(ch) ;
131 
132    ch = tross_datetime() ;
133    sprintf(note_name, "NOTE_DATE_%03d", num_notes) ;
134    THD_set_string_atr(dset->dblk, note_name, ch);
135    free(ch);
136 
137    return ;
138 }
139 
140 /*---------------------------------------------------------------------------*/
141 /*!   Delete a particular note
142 -----------------------------------------------------------------------------*/
143 
tross_Delete_Note(THD_3dim_dataset * dset,int inote)144 void tross_Delete_Note(THD_3dim_dataset *dset, int inote)
145 {
146    ATR_int *notecount;
147    int num_notes;
148    ATR_string *note_text;
149    char note_name[20];
150 
151    if( !ISVALID_DSET(dset) || inote <= 0 || inote > MAX_DSET_NOTES ) return ;
152 
153    notecount = THD_find_int_atr(dset->dblk, "NOTES_COUNT");
154    if (notecount == NULL) return ;
155 
156    num_notes = notecount->in[0];
157    if (inote > num_notes) return ;
158 
159    sprintf(note_name, "NOTE_NUMBER_%03d", inote);
160    note_text = THD_find_string_atr(dset->dblk, note_name);
161    if( note_text == NULL ) return ;
162    THD_erase_one_atr( dset->dblk , note_name );
163 
164    sprintf(note_name, "NOTE_DATE_%03d", inote);
165    note_text = THD_find_string_atr(dset->dblk, note_name);
166    if( note_text != NULL ) THD_erase_one_atr( dset->dblk , note_name );
167 
168    notecount->in[0]-- ;  /* where the note count is reduced */
169 
170    /* Slide the higher numbered notes down */
171 
172    while (inote < num_notes) {
173       /* find the next note */
174       sprintf(note_name, "NOTE_NUMBER_%03d", inote+1);
175       note_text=THD_find_string_atr(dset->dblk, note_name);
176       if (note_text != NULL){
177          /* rename to the previous name */
178          sprintf(note_name, "NOTE_NUMBER_%03d", inote);
179          strcpy(note_text->name, note_name);
180       }
181 
182       sprintf(note_name,"NOTE_DATE_%03d",inote+1) ;
183       note_text = THD_find_string_atr(dset->dblk, note_name);
184       if (note_text != NULL){
185          /* rename to the previous name */
186          sprintf(note_name, "NOTE_DATE_%03d", inote);
187          strcpy(note_text->name, note_name);
188       }
189 
190       inote++ ;
191    }
192 
193    /* No notes left, so remove count attribute */
194    if (num_notes == 1)
195       THD_erase_one_atr( dset->dblk, "NOTES_COUNT");
196    return ;
197 }
198 
199 /*---------------------------------------------------------------------------*/
200 /*! Get the number of Notes currently attached to the dataset.
201     Doesn't include the History note.
202 -----------------------------------------------------------------------------*/
203 
tross_Get_Notecount(THD_3dim_dataset * dset)204 int tross_Get_Notecount( THD_3dim_dataset * dset )
205 {
206    ATR_int *notecount;
207 
208    if( !ISVALID_DSET(dset) ) return -1 ;
209 
210    notecount = THD_find_int_atr(dset->dblk, "NOTES_COUNT");
211    if (notecount == NULL) return 0 ;
212    return notecount->in[0];
213 }
214 
215 /*---------------------------------------------------------------------------*/
216 /*! Get the inote-th Note attached to the dataset.
217     free() this string when done with it - it is a copy
218 -----------------------------------------------------------------------------*/
219 
tross_Get_Note(THD_3dim_dataset * dset,int inote)220 char * tross_Get_Note( THD_3dim_dataset * dset , int inote )
221 {
222    ATR_int *notecount;
223    int num_notes;
224    ATR_string *note ;
225    char note_name[20], * ch ;
226 
227    if( !ISVALID_DSET(dset) || inote <= 0 || inote > MAX_DSET_NOTES ) return NULL ;
228 
229    notecount = THD_find_int_atr(dset->dblk, "NOTES_COUNT");
230    if (notecount == NULL) return NULL ;
231    num_notes = notecount->in[0];
232    if( inote > num_notes ) return NULL ;
233 
234    sprintf(note_name, "NOTE_NUMBER_%03d", inote);
235    note = THD_find_string_atr(dset->dblk, note_name);
236    if (note == NULL ) return NULL ;
237    ch = tross_Expand_String( note->ch ) ;
238    return ch ;
239 }
240 
241 /*------------------------------------------------------------------------------*/
242 
tross_Get_Notedate(THD_3dim_dataset * dset,int inote)243 char * tross_Get_Notedate( THD_3dim_dataset * dset , int inote )
244 {
245    ATR_int *notecount;
246    int num_notes;
247    ATR_string *note ;
248    char note_name[20];
249 
250    if( !ISVALID_DSET(dset) || inote <= 0 || inote > MAX_DSET_NOTES ) return NULL ;
251 
252    notecount = THD_find_int_atr(dset->dblk, "NOTES_COUNT");
253    if (notecount == NULL) return NULL ;
254    num_notes = notecount->in[0];
255    if( inote > num_notes ) return NULL ;
256 
257    sprintf(note_name, "NOTE_DATE_%03d", inote);
258    note = THD_find_string_atr(dset->dblk, note_name);
259    if (note == NULL ) return NULL ;
260    return tross_Expand_String( note->ch ) ;
261 }
262 
263 /*---------------------------------------------------------------------------*/
264 /*! Add the history from the command line to the dataset.
265 -----------------------------------------------------------------------------*/
266 
267 #ifndef AFNI_VERSION_LABEL
268 # include "AFNI_version.h"
269 #endif
270 
271 #ifndef AFNI_VERSION_PLATFORM
272 # ifdef SHOWOFF
273 #  undef  SHSH
274 #  undef  SHSHSH
275 #  define SHSH(x)   #x
276 #  define SHSHSH(x) SHSH(x)
277 #  define AFNI_VERSION_PLATFORM  SHSHSH(SHOWOFF)   /* now in "quotes" */
278 #  undef  SHSHSH
279 #  undef  SHSH
280 # else
281 #  define AFNI_VERSION_PLATFORM "unknown"
282 # endif
283 #endif
284 
tross_Make_History(char * pname,int argc,char ** argv,THD_3dim_dataset * dset)285 void tross_Make_History( char *pname, int argc, char **argv, THD_3dim_dataset *dset )
286 {
287    char *ch ;
288 
289    if( argc < 2 || argv == NULL || !ISVALID_DSET(dset) ) return ;
290 
291    ch = tross_commandline( pname , argc , argv ) ; if( ch == NULL ) return ;
292 
293    /* Prepend AFNI version information */
294 
295 #if defined(AFNI_VERSION_LABEL) && defined(AFNI_VERSION_PLATFORM)
296    { char cv[256] , *qh ;
297      sprintf(cv,"{%s:%s} ",AFNI_VERSION_LABEL,AFNI_VERSION_PLATFORM) ;
298      qh = (char *)malloc(sizeof(char)*(strlen(ch)+256)) ;
299      strcpy(qh,cv) ; strcat(qh,ch) ; free(ch) ; ch = qh ;
300    }
301 #endif
302 
303    tross_Append_History( dset , ch ) ;
304    free(ch) ; return ;
305 }
306 
307 /*---------------------------------------------------------------------------*/
308 /*!  Replace the History in new_dset with that from old_dset
309 -----------------------------------------------------------------------------*/
310 
tross_Copy_History(THD_3dim_dataset * old_dset,THD_3dim_dataset * new_dset)311 void tross_Copy_History( THD_3dim_dataset * old_dset , THD_3dim_dataset * new_dset )
312 {
313    char * ch , * cn ;
314 
315    if( !ISVALID_DSET(old_dset) || !ISVALID_DSET(new_dset) ) return ;
316 
317    ch = tross_Get_History( old_dset ) ;      if( ch == NULL ) return ;
318    cn = tross_Encode_String(ch) ; free(ch) ; if( cn == NULL ) return;
319    THD_set_string_atr(new_dset->dblk, "HISTORY_NOTE", cn);
320    free(cn) ; return ;
321 }
322 
323 /*---------------------------------------------------------------------------*/
324 /*! Add the History in old_dset to that in new_dset [27 Feb 2003]
325 -----------------------------------------------------------------------------*/
326 
tross_Addto_History(THD_3dim_dataset * old_dset,THD_3dim_dataset * new_dset)327 void tross_Addto_History( THD_3dim_dataset *old_dset , THD_3dim_dataset *new_dset )
328 {
329    char *ch ;
330 
331    if( !ISVALID_DSET(old_dset) || !ISVALID_DSET(new_dset) ) return ;
332 
333    ch = tross_Get_History( old_dset ) ; if( ch == NULL ) return ;
334    tross_Append_History( new_dset , ch ) ; free(ch) ; return ;
335 }
336 
337 /*---------------------------------------------------------------------------*/
338 /*! Erase the old History and replace it with this one.
339    09 Dec 2000 - use this wisely.
340 -----------------------------------------------------------------------------*/
341 
tross_Replace_History(THD_3dim_dataset * dset,char * ch)342 void tross_Replace_History( THD_3dim_dataset * dset , char * ch )
343 {
344    char * cn ;
345 
346    if( !ISVALID_DSET(dset) || ch == NULL ) return ;
347 
348    cn = tross_Encode_String(ch) ; if( cn == NULL ) return ;
349    THD_set_string_atr(dset->dblk, "HISTORY_NOTE", cn);
350    free(cn) ; return ;
351 }
352 
353 /*---------------------------------------------------------------------------*/
354 /*!  Append a string to the dataset history (create the history if need be).
355 -----------------------------------------------------------------------------*/
356 
tross_Append_History(THD_3dim_dataset * dset,char * cn)357 void tross_Append_History( THD_3dim_dataset *dset, char *cn )
358 {
359    ATR_string * hist ;
360    char *ch , *chold , *cdate , *cname , *cuser , *cenv ;
361    int idate , iname , iuser ;
362 
363    if( !ISVALID_DSET(dset) || cn == NULL || cn[0] == '\0' ) return ;
364 
365    hist = THD_find_string_atr(dset->dblk,"HISTORY_NOTE") ;
366 
367    /* maybe the user does not want any history      28 Jun 2013 [rickr] */
368    if( AFNI_noenv("AFNI_INCLUDE_HISTORY") ) {
369       if( hist ) THD_erase_one_atr(dset->dblk, "HISTORY_NOTE") ;
370       return ;
371    }
372 
373    cdate = tross_datetime() ; idate = strlen(cdate) ;
374 
375                       cenv = getenv("AFNI_HISTORY_NAME") ;
376    if( cenv == NULL ) cenv = getenv("AFNI_HISTORY_USERNAME") ;
377 
378    if( cenv != NULL ){                                   /* 24 Jun 2013 */
379      cuser = strdup(cenv) ; iuser = strlen(cuser) ;
380      cname = strdup("\0") ; iname = 0             ;
381    } else {
382      cname = tross_hostname() ; iname = strlen(cname) ;  /* 19 Sep 1999 */
383      cuser = tross_username() ; iuser = strlen(cuser) ;  /* 19 Sep 1999 */
384    }
385 
386    /*- add to the history -*/
387 
388    if( hist != NULL ){
389 
390       chold = tross_Expand_String(hist->ch) ; if( chold == NULL ) return ;
391       chold = AFREALL( chold, char,
392 		       strlen(chold)+idate+iuser+iname+strlen(cn)+16 ) ;
393 
394       strcat(chold,"\n") ;
395       strcat(chold,"[") ;
396          if( iuser > 0      ){ strcat(chold,cuser);                       }
397          if( iname > 0      ){ strcat(chold,"@")  ; strcat(chold,cname) ; }
398          if( *cuser != '\0' ){ strcat(chold,": ") ;                       }
399                                strcat(chold,cdate);
400       strcat(chold,"] ") ;
401       strcat(chold,cn) ;
402       ch = tross_Encode_String(chold) ; if( ch == NULL ){ free(chold); return; }
403       THD_set_string_atr(dset->dblk, "HISTORY_NOTE", ch);
404       free(ch) ; free(chold) ;
405 
406    /*- create the history -*/
407 
408    } else {
409       chold = AFMALL(char, idate+iuser+iname+strlen(cn)+12 ) ;
410       sprintf(chold,"[%s@%s: %s] %s",cuser,cname,cdate,cn) ;
411       ch = tross_Encode_String(chold) ; if( ch == NULL ){ free(chold); return; }
412       THD_set_string_atr(dset->dblk, "HISTORY_NOTE", ch);
413       free(ch) ; free(chold) ;
414    }
415 
416    free(cdate) ; free(cname) ; free(cuser) ; return ;
417 }
418 
419 /*----------------------------------------------------------------------------*/
420 /*! Append multiple strings to the History, all on one line.  Usage:
421       - tross_multi_Append_History(dset,str1,str2,str3,NULL) ;
422       - As many str variables as desired (at least 1), of type char *, can be
423         passed in.
424       - The last one must be NULL.
425 ------------------------------------------------------------------------------*/
426 
427 #include <stdarg.h>
428 
tross_multi_Append_History(THD_3dim_dataset * dset,...)429 void tross_multi_Append_History( THD_3dim_dataset *dset, ... )
430 {
431    va_list vararg_ptr ;
432    int nstr=0 , nc , first=1 , ii ;
433    char * str , * cpt ;
434 
435    va_start( vararg_ptr , dset ) ;
436 
437    str = AFMALL(char, 4) ; nstr = 0 ; str[0] = '\0' ;
438    while(1){
439       cpt = va_arg( vararg_ptr , char * ) ; if( cpt == NULL ) break ;
440       nc = strlen(cpt) ;                    if( nc  == 0    ) continue ;
441       nstr += nc ; str = AFREALL(str, char, nstr+8 ) ;
442       if( !first ) strcat(str," ; ") ;
443       strcat(str,cpt) ; first = 0 ;
444    }
445 
446    va_end( vararg_ptr ) ;
447 
448    nstr = strlen(str) ;
449    if( nstr > 0 ){
450       for( ii=0 ; ii < nstr ; ii++ )
451          if( str[ii]=='\n' || str[ii]=='\f' || str[ii]=='\r' || str[ii]=='\v' )
452             str[ii] = ' ' ;
453 
454       tross_Append_History( dset , str ) ;
455    }
456 
457    free(str) ; return ;
458 }
459 
460 /*----------------------------------------------------------------------------*/
461 /*!  Get the history string; free() this when done.  If NULL is returned,
462   there is no history (cf. Santayana).
463 ------------------------------------------------------------------------------*/
464 
tross_Get_History(THD_3dim_dataset * dset)465 char * tross_Get_History( THD_3dim_dataset *dset )
466 {
467    ATR_string * hist ;
468    char * ch ;
469 
470    if( !ISVALID_DSET(dset) ) return NULL ;
471 
472    hist = THD_find_string_atr(dset->dblk,"HISTORY_NOTE") ;
473    if( hist == NULL ) return NULL ;
474 
475    ch = tross_Expand_String(hist->ch) ; return ch ;
476 }
477 
478 /*-----------------------------------------------------------------------------*/
479 /*!  Store string at location inote;
480    if inote > number of notes now present, gets added at the end of the list;
481    otherwise, replaces existing note
482 -------------------------------------------------------------------------------*/
483 
tross_Store_Note(THD_3dim_dataset * dset,int inote,char * cn)484 void tross_Store_Note( THD_3dim_dataset * dset , int inote , char * cn )
485 {
486    ATR_int *notecount;
487    int num_notes;
488    ATR_string *note ;
489    char note_name[20], *ch ;
490 
491    if( !ISVALID_DSET(dset) || inote <= 0 || inote > MAX_DSET_NOTES ||
492                               cn == NULL || cn[0] == '\0'            ) return ;
493 
494    notecount = THD_find_int_atr(dset->dblk, "NOTES_COUNT");
495    if (notecount == NULL){ tross_Add_Note( dset , cn ) ; return ; }
496    num_notes = notecount->in[0];
497    if( inote > num_notes ){ tross_Add_Note( dset , cn ) ; return ; }
498 
499    sprintf(note_name, "NOTE_NUMBER_%03d", inote);
500    ch = tross_Encode_String(cn) ; if( ch == NULL ) return ;
501    THD_set_string_atr(dset->dblk, note_name, ch);
502    free(ch) ;
503 
504    ch = tross_datetime() ;
505    sprintf(note_name, "NOTE_DATE_%03d", inote) ;
506    THD_set_string_atr(dset->dblk, note_name, ch);
507    free(ch);
508 
509    return ;
510 }
511 
512 /*-----------------------------------------------------------------------*/
513 /*!  Break a string up into lines of length between lbot and ltop bytes;
514   free() the result when done with it.
515   NULL return means illegal input was found.
516 -------------------------------------------------------------------------*/
517 
tross_breakup_string(char * str,int lbot,int ltop)518 char * tross_breakup_string( char * str , int lbot , int ltop )
519 {
520    char * sout ;
521    int slen , ii , ibot,itop , ldif ;
522 
523    if( str == NULL || str[0] == '\0' || lbot > ltop || lbot < 4 ) return NULL ;
524 
525    slen = strlen(str) ; sout = AFMALL(char, slen+4) ;
526 
527    while( slen > lbot && isspace(str[slen-1]) ) slen-- ;  /* trim blanks off end */
528 
529    ibot = 0 ; ldif = ltop-lbot ;
530    while(1){
531       itop = ibot + ltop-1 ;    /* want to output str[ibot..itop] */
532 
533       /* if past end of str, then just output the rest and exit */
534 
535       if( itop >= slen ){
536          memcpy( sout+ibot , str+ibot , slen-ibot ) ;
537          sout[slen] = '\0' ;
538          return sout ;
539       }
540 
541       /* scan forwards to find a newline character before itop; */
542       /* if one is present, output the string up to there,     */
543       /* and continue again starting after the newline        */
544 
545       for( ii=ibot ; ii <= itop ; ii++ )
546          if( str[ii] == '\n' ) break ;
547 
548       if( ii <= itop ){  /* found it! */
549          memcpy( sout+ibot , str+ibot , ii-ibot+1 ) ;
550          ibot = ii+1 ;
551          if( ibot >= slen ){ sout[slen] = '\0'; return sout; }
552          continue ;
553       }
554 
555       /* scan backwards to find a whitespace character */
556 
557       for( ii=itop ; ii > itop-ldif ; ii-- )
558          if( isspace(str[ii]) ) break ;
559 
560       /* found one before the minimum location      */
561       /* copy up to the previous char into output, */
562       /* then put a newline in for the whitespace */
563 
564       if( ii > itop-ldif ){
565          memcpy( sout+ibot , str+ibot , ii-ibot ) ;
566          sout[ii] = '\n' ;
567          ibot = ii+1 ;
568          continue ;         /* try to do next line */
569       }
570 
571       /* scan ahead to next whitespace instead */
572 
573       for( ii=itop ; ii < slen ; ii++ )
574          if( isspace(str[ii]) ) break ;
575 
576       /* found one */
577 
578       if( ii < slen ){
579          memcpy( sout+ibot , str+ibot , ii-ibot ) ;
580          sout[ii] = '\n' ;
581          ibot = ii+1 ;
582          continue ;
583       }
584 
585       /* copy rest of input and exit */
586 
587       memcpy( sout+ibot , str+ibot , slen-ibot ) ;
588       sout[slen] = '\0' ;
589       return sout ;
590    }
591 }
592 
593 /*-----------------------------------------------------------------------*/
594 /*!  Return a printable version of a note string; free() this when done
595 -------------------------------------------------------------------------*/
596 
tross_Expand_String(char * ch)597 char * tross_Expand_String( char * ch )
598 {
599    char * cn = NULL ;
600    int i, j, num_char;
601 
602    if( ch == NULL || ch[0] == '\0' ) return NULL ;
603 
604    num_char = strlen(ch) ;
605    cn = (char *) malloc( sizeof(char) * (num_char+4) ) ;
606    for( i=j=0 ; j < num_char ; j++ ){
607       if( ch[j] != '\\' ){
608          cn[i++] = ch[j] ;
609       } else {
610          switch (ch[++j] ){
611             case 'r'  : cn[i++] = '\r' ; break;
612             case 'n'  : cn[i++] = '\n' ; break;
613             case '\\' : cn[i++] = '\\' ; break;
614             case '"'  : cn[i++] = '\"' ; break;
615             case 't'  : cn[i++] = '\t' ; break;
616             case 'a'  : cn[i++] = '\a' ; break;
617             case 'v'  : cn[i++] = '\v' ; break;
618             case 'b'  : cn[i++] = '\b' ; break;
619             default:    cn[i++] = '\\' ;         /* 13 Mar 2003 */
620                         cn[i++] = ch[j]; break;
621          }
622       }
623    }
624    cn[i] = '\0' ; return cn ;
625 }
626 
627 /*--------------------------------------------------------------------------*/
628 
629 static int Dont_Encode_Slash = 0 ;
630 
tross_Dont_Encode_Slash(int q)631 void tross_Dont_Encode_Slash( int q ){ Dont_Encode_Slash = q ; return ; }
632 
633 /*--------------------------------------------------------------------------*/
634 /*!  Reverse of tross_Expand_String
635 ----------------------------------------------------------------------------*/
636 
tross_Encode_String(char * cn)637 char * tross_Encode_String( char * cn )
638 {
639    char * ch = NULL ;
640    int i , j , num_char ;
641 
642    if( cn == NULL || cn[0] == '\0' ) return NULL ;
643 
644    num_char = strlen(cn) ;
645    ch = (char *) malloc( sizeof(char) * (2*num_char+4) ) ;
646    for( i=j=0 ; j < num_char ; j++ ){
647       switch( cn[j] ){
648          default:   ch[i++] = cn[j]                ; break ;
649          case '\r': ch[i++] = '\\' ; ch[i++] = 'r' ; break ;
650          case '\n': ch[i++] = '\\' ; ch[i++] = 'n' ; break ;
651          case '\"': ch[i++] = '\\' ; ch[i++] = '\"'; break ;
652          case '\t': ch[i++] = '\\' ; ch[i++] = 't' ; break ;
653          case '\a': ch[i++] = '\\' ; ch[i++] = 'a' ; break ;
654          case '\v': ch[i++] = '\\' ; ch[i++] = 'v' ; break ;
655          case '\b': ch[i++] = '\\' ; ch[i++] = 'b' ; break ;
656 
657          case '\\':                          ch[i++] = '\\';
658                     if( !Dont_Encode_Slash ) ch[i++] = '\\';
659          break ;
660       }
661    }
662    ch[i] = '\0' ;
663    for( i-- ; i > 0 ; i-- ) if( isspace(ch[i]) ) ch[i] = '\0' ; else break ;
664    return ch ;
665 }
666