Blame view

src/idl_misc/translate_sub_super.pro 11.8 KB
427f1205   Jean-Michel Glorian   version 4.2 merged
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
;  NOTE to future maintainers:
;   Make sure sub_sup_idl stays before translate_sub_super.  At least
;   for now, when IDL encounters a function and automatically compiles
;   it, it only compiles the functions in the file up to the named
;   function.  So even if sub_sup_idl was declared with
;   FORWARD_FUNCTION in translate_sub_super, it would not properly
;   compile. 
;
;+
; SPECIAL NOTE: 
;       The file translate_sub_super.pro contains two functions,
;       translate_sub_super, and sub_sup_idl.  The former is the
;       generic routine for processing TeX sub/superscripts, the
;       latter is used only by translate_sub_super and has no general
;       utility.  Hence it lives here.  You will see documentation for
;       translate_sub_super second if you use DOC_LIBRARY.
;-
;
;
;+
; NAME:
;       SUB_SUP_IDL
; PURPOSE:
;       Return the proper IDL font positioning command for TeX
;       sub/superscripts. 
; CATEGORY:
;       TeXtoIDL
; CALLING SEQUENCE:
;       fnt = sub_sup_idl( strn )
; INPUTS:
;       strn      -- Either '^' or '_', the TeX super/subscript       in
;                    characters
; KEYWORD PARAMETERS:
;       /FORCE_UD -- Set this to use !U/!D instead of !E/!I for
;                    sub/superscripts .
;       /HELP     -- Set to print useful message and exit.
; OUTPUTS:
;       fnt       -- Either '!U' or !E' for superscripts,             out
;                    or '!D' or '!I' for subscripts.
; COMMON BLOCKS:
; SIDE EFFECTS:
; NOTES:
;       Used only by translate_sub_super.  Should be kept in same
;       file. 
; EXAMPLE:
; MODIFICATION HISTORY:
;       $Id: translate_sub_super.pro,v 1.5 2000/06/14 19:09:22 mcraig Exp $
;       $Log: translate_sub_super.pro,v $
;       Revision 1.5  2000/06/14 19:09:22  mcraig
;       Changed name of strtok str_token to avoid conflict in IDL 5.3.
;
;       Revision 1.4  1996/06/14 20:00:27  mcraig
;       Updated Copyright info.
;
;       Revision 1.3  1996/05/09 00:22:17  mcraig
;       Changed some function calls to reflect changes in those functions, moved
;       some code out of the main loop that didn't need to be there, added
;       documentation.
;
;       Revision 1.1  1996/01/31 18:47:37  mcraig
;       Initial revision
;
; RELEASE:
;       $Name: Rel_2_1 $
; COPYRIGHT:
;  Copyright (C) 1996 The Regents of the University of California, All
;  Rights Reserved.  Written by Matthew W. Craig.
;  See the file COPYRIGHT for restrictions on distrubting this code.
;  This code comes with absolutely NO warranty; see DISCLAIMER for details.
;-
FUNCTION Sub_sup_idl, token,  FORCE_UD = force_ud

; provide help if needed.
    IF (n_params() NE 1) OR keyword_set(Help) THEN BEGIN
        offset = '   '
        print, offset+'Return the proper IDL font positioning command for TeX'
        print, offset+'sub/superscripts. '
        print, offset+'fnt = sub_sup_idl( strn )'
        print, offset+'Inputs:'
        print, offset+offset+"strn      -- Either '^' or '_', the TeX super/subscript       in"
        print, offset+offset+'             characters'
        print, offset+'Keywords:'
        print, offset+offset+'/FORCE_UD -- Set this to use !U/!D instead of !E/!I for'
        print, offset+offset+'             sub/superscripts .'
        print, offset+offset+'/HELP     -- Set to print useful message and exit.'
        print, offset+'Outputs:'
        print, offset+offset+"fnt       -- Either '!U' or !E' for superscripts,             out"
        print, offset+offset+"             or '!D' or '!I' for subscripts."
        return, -1
    ENDIF 

    IF keyword_set(force_ud) THEN BEGIN 
        IF (token EQ '^') THEN return, '!U' 
        IF (token EQ '_') THEN return, '!D'
        return, ''
    ENDIF ELSE BEGIN
        IF (token EQ '^') THEN return, '!E' 
        IF (token EQ '_') THEN return, '!I'
        return, ''
    ENDELSE
    
END

;
;+
; NAME:
;       TRANSLATE_SUB_SUPER
; PURPOSE:
;       Translate TeX sub/superscripts to IDL sub/superscripts.
; CATEGORY:
;       text/strings
; CALLING SEQUENCE:
;       new = translate_sub_super( old )
; INPUTS:
;       old       -- string to be translated from TeX to IDL.   in
; KEYWORD PARAMETERS:
;       /RECURSED -- set if this function is being called 
;                    recursively.                  
;       /HELP     -- Set to print useful message and exit.
; OUTPUTS:
;       new       -- string old converted from TeX to IDL       out
; COMMON BLOCKS:
; SIDE EFFECTS:
; NOTES:
;       - For best results, when both a sub and superscript are used,
;         place the shorter of the two first (e.g. 'N^{a}_{bbbb}' is
;         better than 'N_{bbbb}^{a}').
;       - Single character sub/super scripts do not need to be
;         protected by braces.
;       - Sub/superscripts may be nested (e.g. 'N^{N_1^N}').
; EXAMPLE:
;       out = translate_sub_super( 'N^2_{big}' )
;       Then out='N!U2!N!Dbig!N' which looks like it should on the
;       display. 
; LIBRARY FUNCTIONS CALLED:
;       str_token      -- Text/string (mcraig)
;       sub_sup_idl -- contained in this file
; MODIFICATION HISTORY:
;       $Id: translate_sub_super.pro,v 1.5 2000/06/14 19:09:22 mcraig Exp $
;       $Log: translate_sub_super.pro,v $
;       Revision 1.5  2000/06/14 19:09:22  mcraig
;       Changed name of strtok str_token to avoid conflict in IDL 5.3.
;
;       Revision 1.4  1996/06/14 20:00:27  mcraig
;       Updated Copyright info.
;
;       Revision 1.3  1996/05/09 00:22:17  mcraig
;       Changed some function calls to reflect changes in those functions, moved
;       some code out of the main loop that didn't need to be there, added
;       documentation.
;
;       Revision 1.2  1996/02/08 18:54:20  mcraig
;       Changed default sub/superscript size to be !D/!U rather than !I/!E to
;       improve readability of plat annotations.
;
;       Revision 1.1  1996/01/31 18:47:37  mcraig
;       Initial revision
;
; RELEASE:
;       $Name: Rel_2_1 $
;
; COPYRIGHT:
;  Copyright (C) 1996 The Regents of the University of California, All
;  Rights Reserved.  Written by Matthew W. Craig.
;  See the file COPYRIGHT for restrictions on distrubting this code.
;  This code comes with absolutely NO warranty; see DISCLAIMER for details.
;-
FUNCTION Translate_sub_super, InputString, $
                              RECURSED=recursed, $
                              HELP=Help

; Return to caller if error.
    On_error, 2

; Offer help if needed and/or desired
    IF (n_params() NE 1) OR keyword_set(help) THEN BEGIN
        offset = '   '
        print, offset+'Translate TeX sub/superscripts to IDL sub/superscripts.'
        print, offset+'new = translate_sub_super( old )'
        print, offset+'Inputs:'
        print, offset+offset+'old       -- string to be translated from TeX to IDL.   in'
        print, offset+'Keywords:'
        print, offset+offset+'/RECURSED -- set if this function is being called '
        print, offset+offset+'             recursively.                  '
        print, offset+offset+'/HELP     -- Set to print useful message and exit.'
        print, offset+'Outputs:'
        print, offset+offset+'new       -- string old converted from TeX to IDL       out'
        print, offset+'Notes:'
        print, offset+offset+'- For best results, when both a sub and superscript are used,'
        print, offset+offset+"  place the shorter of the two first (e.g. 'N^{a}_{bbbb}' is"
        print, offset+offset+"  better than 'N_{bbbb}^{a}')."
        print, offset+offset+'- Single character sub/super scripts do not need to be'
        print, offset+offset+'  protected by braces.'
        print, offset+offset+"- Sub/superscripts may be nested (e.g. 'N^{N_1^N}')."
        return, -1
    ENDIF 

;  To allow for nested scripts, use !E/!I instead of !U/!D for scripts
;  when called recursively.
    IF (NOT keyword_set(recursed)) THEN $
      ud = 1 $
    ELSE $
      ud = 0

;  Return to the normal level after making sub/superscript unless we
;  are recursed, which indicates we are processing a nested script.
    IF keyword_set(recursed) THEN fontRestore = '' ELSE fontRestore = '!N'

;  Initialize vars for processing scripts.
    SpcByte = (byte(' '))(0)    ;We need the BYTE value for a space below.
    strn = InputString
    pos = 0
    StorePos = ''
    RecallPos = ''
    OldToken =  ''
    LenLastScript = 0

; Grab next sub/superscript.  Token will be either '^' or '_'.
; RETURN if no scripts.
    Token = nexttok(strn,  '^_', pos = pos)
    if pos EQ -1 then return, InputString ;nothing to process.

    FntChange =  sub_sup_idl(Token)

; Our approach will be to grab the input string up to the next '^' or
; '_', then process the script we've found.
    NewString=str_token(strn,Token)

    WHILE  strlen(strn) GT  0 DO  BEGIN
;  Grab first char of sub/superscript.
        Script = strmid(strn, 0, 1)
        EndOfScript = 0         ;Position of end of this script.
        IF (Script EQ '{') THEN BEGIN   ; Scripts of more than 1 char.
            EndOfScript = matchdelim(strn)      
            Script = translate_sub_super(strmid(strn, 1, EndOfScript-1), $
                                         /recursed )
        ENDIF 
;     Grab rest of string _after_ the end of the script.        
        strn = strmid(strn, EndOfScript+1, $
                      strlen(strn)-EndOfScript-1)

;     Find the next script and prepare for processing it.
        FntChange = sub_sup_idl(Token, FORCE_UD = ud)
        OldToken = Token
        Token = nexttok(strn, '^_', POS = pos)

;     If the input is 'n^2_j', we want the '2' to be directly above
;     the 'j', rather than having the 'j' below and to the right of
;     the 2.  In other words, we want the first below, not the second.
;              2               2
;             N               N
;              J                J
;     To accomplish this, we need to save the position at which we
;     begin writing the 2 with a !S, and restore that position with a
;     !R after writing the 2.  The first section in the IF block below
;     handles the 'J' above, the thing after the first script.  We
;     don't care if there is another script following.  We also padd
;     the second script with spaces if it is shorter than the first to
;     make sure that whatever comes out after the scripts starts in
;     the proper place.  The worry is that without the spaces, the
;     input 'N^{looong}_{s} + 1' will end up with the + starting right
;     the 's' ends.
        IF (StorePos EQ '!S') THEN BEGIN
            StorePos = ''
            RecallPos = ''
;     calculate the difference in length between this script and the 
;     previous stacked one, removing font change commands (crudely by
;     guessing that the number of characters this takes is twice the
;     number of exclamation points).  The  + 1 below is a kludge.  I
;     don't know why, but I need one extra space.
            NumSpaces = LenLastScript - (strlen(script) - 2*strcnt(Script,'!'))
            NumSpaces = (NumSpaces + 1) > 0
            IF NumSpaces GT 0 THEN $
              Script = Script + string( replicate(SpcByte, NumSpaces) )
        ENDIF ELSE BEGIN
            IF (Token NE OldToken) AND (pos EQ 0) THEN BEGIN
;             The next script immediately folows this one.  Arrange to
;             save the position of the current script so that both begin
;             with the same horizontal position.
                StorePos = '!S'
                RecallPos = '!R'
                LenLastScript = strlen(Script) - 2*strcnt(Script,'!')
            ENDIF
        ENDELSE  

;  Continue building the IDL string, adding on our just processed script.
        NewString = NewString + StorePos + FntChange + Script + RecallPos $
          + FontRestore

        IF ( pos NE -1 ) THEN BEGIN     ; more left to process     
            NewString = NewString $
              + str_token(strn, Token)   
        ENDIF ELSE BEGIN                ; we are done
            NewString = NewString + strn
            strn = ''
        ENDELSE
    ENDWHILE 
    
    return, NewString
END