;-------------------------------------------------------------
;+
; NAME:
;       GETWRD
; PURPOSE:
;       Return the n'th word from a text string.
; CATEGORY:
; CALLING SEQUENCE:
;       wrd = getwrd(txt, n, [m])
; INPUTS:
;       txt = text string to extract from.         in
;         txt is allowed to be an array.
;       n = word number to get (first = 0 = def).  in
;       m = optional last word number to get.      in
; KEYWORD PARAMETERS:
;       Keywords:
;         LOCATION = l.  Return word n string location.
;         DELIMITER = d. Set word delimiter (def = space & tab).
;         /LAST means n is offset from last word.  So n=0 gives
;           last word, n=-1 gives next to last, ...
;           If n=-2 and m=0 then last 3 words are returned.
;         /NOTRIM suppresses whitespace trimming on ends.
;         NWORDS=n.  Returns number of words in string.
;         /KEEP_LEADING_DEL  Keep any leading delimiter in result.
;         /KEEP_TRAILING_DEL Keep any trailing delimiter in result.
; OUTPUTS:
;       wrd = returned word or words.              out
; COMMON BLOCKS:
;       getwrd_com
; NOTES:
;       Note: If a NULL string is given (txt="") then the last string
;             given is used.  This saves finding the words again.
;             If m > n wrd will be a string of words from word n to
;             word m.  If no m is given wrd will be a single word.
;             n<0 returns text starting at word abs(n) to string end
;             If n is out of range then a null string is returned.
;             See also nwrds.
; MODIFICATION HISTORY:
;       Ray Sterner,  6 Jan, 1985.
;       R. Sterner, Fall 1989 --- converted to SUN.
;       R. Sterner, Jan 1990 --- added delimiter.
;       R. Sterner, 18 Mar, 1990 --- added /LAST.
;       R. Sterner, 31 Jan, 1991 --- added /NOTRIM.
;       R. Sterner, 20 May, 1991 --- Added common and NULL string.
;       R. Sterner, 13 Dec, 1992 --- Made tabs equivalent to spaces.
;       R. Sterner,  4 Jan, 1993 --- Added NWORDS keyword.
;       R. Sterner, 2001 Jan 15 --- Fixed to use first element if not a scalar.
;       R. Sterner, 2006 Mar 07 --- Added /KEEP_LEADING_DEL, /KEEP_TRAILING_DEL.
;       Also cleaned up some.
;       R. Sterner, 2010 Apr 29 --- Converted arrays from () to [].
;       R. Sterner, 2010 Jun 17 --- Added the /KEEP_* keywords to the help text.
;       R. Sterner, 2011 Mar 23 --- Allowed txt to be an array.
;       R. Sterner, 2011 Dec 12 --- Added /RESET keyword.
;       R. Sterner, 2013 Feb 01 --- Made loop use long int.
;       R. Sterner, 2013 Feb 06 --- Fixed a bug where mth was getting changed.
;
; Copyright (C) 1985, Johns Hopkins University/Applied Physics Laboratory
; This software may be used, copied, or redistributed as long as it is not
; sold and this copyright notice is reproduced on each copy made.  This
; routine is provided as is without any express or implied warranties
; whatsoever.  Other limitations apply as described in the file disclaimer.txt.
;-
;-------------------------------------------------------------
 
 
	FUNCTION GETWRD, TXTSTR, NTH, MTH0, help=hlp, location=ll,$
	   delimiter=delim, notrim=notrim, last=last, nwords=nwords, $
	   keep_leading_del=keep_lead, keep_trailing_del=keep_trail, $
	   reset=reset
 
	common getwrd_com, txtstr0, nwds, loc, len, ddel, pre, post
 
	if (n_params(0) lt 1) or keyword_set(hlp) then begin
	  print," Return the n'th word from a text string."
	  print,' wrd = getwrd(txt, n, [m])'
	  print,'   txt = text string to extract from.         in'
	  print,'     txt is allowed to be an array.'
	  print,'   n = word number to get (first = 0 = def).  in'
	  print,'   m = optional last word number to get.      in'
	  print,'   wrd = returned word or words.              out'
	  print,' Keywords:'
	  print,'   LOCATION = l.  Return word n string location.'
	  print,'   DELIMITER = d. Set word delimiter (def = space & tab).'
	  print,'   /LAST means n is offset from last word.  So n=0 gives'
	  print,'     last word, n=-1 gives next to last, ...'
	  print,'     If n=-2 and m=0 then last 3 words are returned.'
	  print,'   /NOTRIM suppresses whitespace trimming on ends.'
	  print,'   NWORDS=n.  Returns number of words in string.'
          print,'   /KEEP_LEADING_DEL  Keep any leading delimiter in result.'
          print,'   /KEEP_TRAILING_DEL Keep any trailing delimiter in result.'
	  print,'   /RESET Reinitialize even if a null string is given.'
	  print,'Note: If a NULL string is given (txt="") then the last string'
	  print,'      given is used.  This saves finding the words again.'
	  print,'      With /RESET a null string has no special meaning.'
	  print,'      If m > n wrd will be a string of words from word n to'
	  print,'      word m.  If no m is given wrd will be a single word.'
	  print,'      n<0 returns text starting at word abs(n) to string end'
	  print,'      If n is out of range then a null string is returned.'
	  print,'      See also nwrds.'
	  return, -1
	endif
 
	;-------------------------------------
	;  Defaults
	;-------------------------------------
	if n_params(0) lt 2 then nth = 0		; Def is first word.
	if n_params(0) lt 3 then mth0 = nth		; Def is one word.
 
	;-------------------------------------
	;  Handle input if an array
	;-------------------------------------
	n_txtstr = n_elements(txtstr)
	if n_txtstr gt 1 then begin
	  txtout = strarr(n_txtstr)
	  for i=0L,n_txtstr-1L do begin
	    txtout1 = getwrd(txtstr[i],NTH, MTH0, location=ll,$
	      delimiter=delim, notrim=notrim, last=last, nwords=nwords, $
	      keep_leading_del=keep_lead, keep_trailing_del=keep_trail)
	    txtout[i] = txtout1
	  endfor
	  return, txtout
	endif
 
	;-------------------------------------
	;  Initialize
	;-------------------------------------
	if (strlen(txtstr[0]) gt 0) or $
           keyword_set(reset) then begin		; Non-null arg.
	  ddel = ' '					; Def del is a space.
	  if n_elements(delim) ne 0 then ddel = delim	; Use given delimiter.
	  tst = (byte(ddel))[0]				; Del to byte value.
	  tb = byte(txtstr[0])				; String to bytes.
	  if ddel eq ' ' then begin		        ; Check for tabs?
	    w = where(tb eq 9B, cnt)			; Yes.
	    if cnt gt 0 then tb[w] = 32B		; Convert any to space.
	  endif
	  x = tb NE tst					; Non-delchar (=words).
	  x = [0,X,0]					; 0s at ends.
 
	  Y = (x-shift(x,1)) eq 1			; Diff=1: word start.
	  z = where(shift(y,-1) eq 1)			; Word start locations.
	  y2 = (x-shift(x,-1)) eq 1			; Diff=1: word end.
	  z2 = where(shift(y2,1) eq 1)			; Word end locations.
 
	  txtstr0 = txtstr[0]				; Move string to common.
	  nwds = LONG(total(y))				; Number of words.
	  loc = z					; Word start locations.
	  len = z2 - z - 1				; Word lengths.
	
	  ;-----  Deal with /keep_* keywords ----- 
	  pre = ''					; Prefix.
	  post = ''					; Postfix.
	  if strmid(txtstr0,0,1) eq ddel then pre=ddel	; Leading delimiter?
	  if strmid(txtstr0,strlen(txtstr0)-1,1) $	; Trailing delimiter?
	    eq ddel then post=ddel
	endif else begin
	  if n_elements(nwds) eq 0 then begin		; Check if first call.
	    print,' Error in getwrd: must give a '+$
	      'non-NULL string on the first call.'
	    return, -1					; -1 = error flag.
	  endif
	endelse
 
	nwords = nwds					; Set nwords
 
	;-------------------------------------
	;  Offset from last word
	;-------------------------------------
	if keyword_set(last) then begin			; Offset from last.
	  lst = nwds - 1
	  in = lst + nth				; Nth word.
	  im = lst + mth0				; Mth word.
	  if (in lt 0) and (im lt 0) then return, ''	; Out of range.
	  in = in > 0					; Smaller of in and im
	  im = im > 0					;  to zero.
	  if (in gt lst) and (im gt lst) then return,'' ; Out of range.
	  in = in < lst					; Larger of in and im
	  im = im < lst					;  to be last.
	  ll = loc[in]					; Nth word start.
	  out = strmid(txtstr0,ll,loc[im]-loc[in]+len[im])
	  ;-----  Deal with /keep_* keywords ----- 
	  if in gt 0 then pre2=ddel else pre2=pre	; Not at first word.
	  if im lt lst then post2=ddel else post2=post	; Not at last word.
	  if keyword_set(keep_lead) then out=pre2+out
	  if keyword_set(keep_trail) then out=out+post2
	  if keyword_set(notrim) then return, out
	  return, strtrim(out,2)
	endif
 
	;-------------------------------------
	;  Offset from first word
	;-------------------------------------
	n = abs(nth)					; Allow nth<0.
	if n gt nwds-1 then return,''			; out of range, null.
	ll = loc[n]					; N'th word position.
	mth = mth0<(nwds-1)				; Words to end.
	if nth lt 0 then begin				; Handle nth<0.
	  out = strmid(txtstr0,ll,9999)
	endif else begin				; nth=>0
	  out = strmid(txtstr0,LL,loc[mth]-loc[nth]+len[mth])
	endelse
	;-----  Deal with /keep_* keywords ----- 
	if n gt 0 then pre2=ddel else pre2=pre		; Not at first word.
	if mth lt (nwds-1) then post2=ddel else post2=post ; Not at last word.
	if keyword_set(keep_lead) then out=pre2+out
	if keyword_set(keep_trail) then out=out+post2
	if keyword_set(notrim) then return, out
	return, strtrim(out,2)
 
	end