@@ -3586,6 +3586,8 @@ static Token *pp_strcat(Token *tline, const char *dname)
3586
3586
break ;
3587
3587
case TOKEN_STR :
3588
3588
unquote_token (t );
3589
+ /* fall through */
3590
+ case TOKEN_INTERNAL_STR :
3589
3591
len += t -> len ;
3590
3592
break ;
3591
3593
default :
@@ -3608,6 +3610,78 @@ static Token *pp_strcat(Token *tline, const char *dname)
3608
3610
return t ;
3609
3611
}
3610
3612
3613
+ /*
3614
+ * Implement substring extraction as used by the %substr directive
3615
+ * and function.
3616
+ */
3617
+ static Token * pp_substr (Token * tline , const char * dname )
3618
+ {
3619
+ int64_t start , count ;
3620
+ const char * txt ;
3621
+ size_t len ;
3622
+ struct ppscan pps ;
3623
+ Token * t ;
3624
+ expr * evalresult ;
3625
+ struct tokenval tokval ;
3626
+
3627
+ t = skip_white (tline );
3628
+
3629
+ if (!tok_is (t , TOKEN_STR )) {
3630
+ nasm_nonfatal ("`%s' requires a string as parameter" , dname );
3631
+ return NULL ;
3632
+ }
3633
+
3634
+ pps .tptr = skip_white (t -> next );
3635
+ if (tok_is (pps .tptr , TOKEN_COMMA ))
3636
+ pps .tptr = skip_white (pps .tptr -> next );
3637
+ if (!pps .tptr ) {
3638
+ nasm_nonfatal ("`%s' requires a starting index" , dname );
3639
+ return NULL ;
3640
+ }
3641
+
3642
+ pps .ntokens = -1 ;
3643
+ tokval .t_type = TOKEN_INVALID ;
3644
+ evalresult = evaluate (ppscan , & pps , & tokval , NULL , true, NULL );
3645
+ if (!evalresult ) {
3646
+ return NULL ;
3647
+ } else if (!is_simple (evalresult )) {
3648
+ nasm_nonfatal ("non-constant value given to `%s'" , dname );
3649
+ return NULL ;
3650
+ }
3651
+ start = evalresult -> value - 1 ;
3652
+
3653
+ pps .tptr = skip_white (pps .tptr );
3654
+ if (!pps .tptr ) {
3655
+ count = 1 ; /* Backwards compatibility: one character */
3656
+ } else {
3657
+ tokval .t_type = TOKEN_INVALID ;
3658
+ evalresult = evaluate (ppscan , & pps , & tokval , NULL , true, NULL );
3659
+ if (!evalresult ) {
3660
+ return NULL ;
3661
+ } else if (!is_simple (evalresult )) {
3662
+ nasm_nonfatal ("non-constant value given to `%s'" , dname );
3663
+ return NULL ;
3664
+ }
3665
+ count = evalresult -> value ;
3666
+ }
3667
+
3668
+ unquote_token (t );
3669
+ len = t -> len ;
3670
+
3671
+ /* make start and count being in range */
3672
+ if (start < 0 )
3673
+ start = 0 ;
3674
+ if (count < 0 )
3675
+ count = len + count + 1 - start ;
3676
+ if (start + count > (int64_t )len )
3677
+ count = len - start ;
3678
+ if (!len || count < 0 || start >=(int64_t )len )
3679
+ start = -1 , count = 0 ; /* empty string */
3680
+
3681
+ txt = (start < 0 ) ? "" : tok_text (t ) + start ;
3682
+ return make_tok_qstr_len (NULL , txt , count );
3683
+ }
3684
+
3611
3685
/**
3612
3686
* find and process preprocessor directive in passed line
3613
3687
* Find out if a line contains a preprocessor directive, and deal
@@ -4666,9 +4740,7 @@ static int do_directive(Token *tline, Token **output)
4666
4740
}
4667
4741
4668
4742
/*
4669
- * Convert the string to a token stream. Note that smacros
4670
- * are stored with the token stream reversed, so we have to
4671
- * reverse the output of tokenize().
4743
+ * Convert the string to a token stream.
4672
4744
*/
4673
4745
macro_start = tokenize (unquote_token_cstr (t ));
4674
4746
@@ -4763,89 +4835,29 @@ static int do_directive(Token *tline, Token **output)
4763
4835
* zero, and a string token to use as an expansion. Create
4764
4836
* and store an SMacro.
4765
4837
*/
4766
- define_smacro (mname , casesense , macro_start , NULL );
4838
+ if (macro_start )
4839
+ define_smacro (mname , casesense , macro_start , NULL );
4767
4840
free_tlist (tline );
4768
4841
break ;
4769
4842
4770
4843
case PP_SUBSTR :
4771
- {
4772
- int64_t start , count ;
4773
- const char * txt ;
4774
- size_t len ;
4775
-
4776
4844
if (!(mname = get_id (& tline , dname )))
4777
4845
goto done ;
4778
4846
4779
4847
last = tline ;
4780
4848
tline = expand_smacro (tline -> next );
4781
4849
last -> next = NULL ;
4782
4850
4783
- t = skip_white (tline );
4784
-
4785
- /* t should now point to the string */
4786
- if (!tok_is (t , TOKEN_STR )) {
4787
- nasm_nonfatal ("`%s' requires string as second parameter" , dname );
4788
- free_tlist (tline );
4789
- goto done ;
4790
- }
4791
-
4792
- pps .tptr = t -> next ;
4793
- pps .ntokens = -1 ;
4794
- tokval .t_type = TOKEN_INVALID ;
4795
- evalresult = evaluate (ppscan , & pps , & tokval , NULL , true, NULL );
4796
- if (!evalresult ) {
4797
- free_tlist (tline );
4798
- goto done ;
4799
- } else if (!is_simple (evalresult )) {
4800
- nasm_nonfatal ("non-constant value given to `%s'" , dname );
4801
- free_tlist (tline );
4802
- goto done ;
4803
- }
4804
- start = evalresult -> value - 1 ;
4805
-
4806
- pps .tptr = skip_white (pps .tptr );
4807
- if (!pps .tptr ) {
4808
- count = 1 ; /* Backwards compatibility: one character */
4809
- } else {
4810
- tokval .t_type = TOKEN_INVALID ;
4811
- evalresult = evaluate (ppscan , & pps , & tokval , NULL , true, NULL );
4812
- if (!evalresult ) {
4813
- free_tlist (tline );
4814
- goto done ;
4815
- } else if (!is_simple (evalresult )) {
4816
- nasm_nonfatal ("non-constant value given to `%s'" , dname );
4817
- free_tlist (tline );
4818
- goto done ;
4819
- }
4820
- count = evalresult -> value ;
4821
- }
4822
-
4823
- unquote_token (t );
4824
- len = t -> len ;
4825
-
4826
- /* make start and count being in range */
4827
- if (start < 0 )
4828
- start = 0 ;
4829
- if (count < 0 )
4830
- count = len + count + 1 - start ;
4831
- if (start + count > (int64_t )len )
4832
- count = len - start ;
4833
- if (!len || count < 0 || start >=(int64_t )len )
4834
- start = -1 , count = 0 ; /* empty string */
4835
-
4836
- txt = (start < 0 ) ? "" : tok_text (t ) + start ;
4837
- len = count ;
4838
- macro_start = make_tok_qstr_len (NULL , txt , len );
4839
-
4851
+ macro_start = pp_substr (tline , dname );
4840
4852
/*
4841
4853
* We now have a macro name, an implicit parameter count of
4842
- * zero, and a numeric token to use as an expansion. Create
4854
+ * zero, and a string token to use as an expansion. Create
4843
4855
* and store an SMacro.
4844
4856
*/
4845
- define_smacro (mname , casesense , macro_start , NULL );
4857
+ if (macro_start )
4858
+ define_smacro (mname , casesense , macro_start , NULL );
4846
4859
free_tlist (tline );
4847
4860
break ;
4848
- }
4849
4861
4850
4862
case PP_ASSIGN :
4851
4863
if (!(mname = get_id (& tline , dname )))
@@ -6887,6 +6899,30 @@ stdmac_strcat(const SMacro *s, Token **params, int nparams)
6887
6899
return pp_strcat (expand_smacro_noreset (params [0 ]), s -> name );
6888
6900
}
6889
6901
6902
+ /* %substr() function */
6903
+ static Token *
6904
+ stdmac_substr (const SMacro * s , Token * * params , int nparams )
6905
+ {
6906
+ nasm_assert (nparams == 1 );
6907
+ return pp_substr (expand_smacro_noreset (params [0 ]), s -> name );
6908
+ }
6909
+
6910
+ /* %tok() function */
6911
+ static Token *
6912
+ stdmac_tok (const SMacro * s , Token * * params , int nparams )
6913
+ {
6914
+ Token * t = expand_smacro_noreset (params [0 ]);
6915
+
6916
+ (void )nparams ;
6917
+
6918
+ if (!tok_is (t , TOKEN_STR )) {
6919
+ nasm_nonfatal ("`%s' requires string as parameter" , s -> name );
6920
+ return NULL ;
6921
+ }
6922
+
6923
+ return reverse_tokens (tokenize (unquote_token_cstr (t )));
6924
+ }
6925
+
6890
6926
/* Add magic standard macros */
6891
6927
struct magic_macros {
6892
6928
const char * name ;
@@ -6905,6 +6941,8 @@ static void pp_add_magic_stdmac(void)
6905
6941
{ "%eval" , false, 1 , SPARM_EVAL |SPARM_VARADIC , stdmac_join },
6906
6942
{ "%str" , false, 1 , SPARM_GREEDY |SPARM_STR , stdmac_join },
6907
6943
{ "%strcat" , false, 1 , SPARM_GREEDY , stdmac_strcat },
6944
+ { "%substr" , false, 1 , SPARM_GREEDY , stdmac_substr },
6945
+ { "%tok" , false, 1 , 0 , stdmac_tok },
6908
6946
{ NULL , false, 0 , 0 , NULL }
6909
6947
};
6910
6948
const struct magic_macros * m ;
0 commit comments