@@ -668,7 +668,7 @@ static char **complete_from_variables(char *text,
668
668
669
669
static PGresult * exec_query (const char * query );
670
670
671
- static char * previous_word (int point , int skip );
671
+ static void get_previous_words (int point , char * * previous_words , int nwords );
672
672
673
673
#ifdef NOT_USED
674
674
static char * quote_file_name (char * text , int match_type , char * quote_pointer );
@@ -710,13 +710,16 @@ psql_completion(char *text, int start, int end)
710
710
/* This is the variable we'll return. */
711
711
char * * matches = NULL ;
712
712
713
- /* These are going to contain some scannage of the input line. */
714
- char * prev_wd ,
715
- * prev2_wd ,
716
- * prev3_wd ,
717
- * prev4_wd ,
718
- * prev5_wd ,
719
- * prev6_wd ;
713
+ /* This array will contain some scannage of the input line. */
714
+ char * previous_words [6 ];
715
+
716
+ /* For compactness, we use these macros to reference previous_words[]. */
717
+ #define prev_wd (previous_words[0])
718
+ #define prev2_wd (previous_words[1])
719
+ #define prev3_wd (previous_words[2])
720
+ #define prev4_wd (previous_words[3])
721
+ #define prev5_wd (previous_words[4])
722
+ #define prev6_wd (previous_words[5])
720
723
721
724
static const char * const sql_commands [] = {
722
725
"ABORT" , "ALTER" , "ANALYZE" , "BEGIN" , "CHECKPOINT" , "CLOSE" , "CLUSTER" ,
@@ -755,16 +758,11 @@ psql_completion(char *text, int start, int end)
755
758
completion_info_charp2 = NULL ;
756
759
757
760
/*
758
- * Scan the input line before our current position for the last five
761
+ * Scan the input line before our current position for the last few
759
762
* words. According to those we'll make some smart decisions on what the
760
- * user is probably intending to type. TODO: Use strtokx() to do this.
763
+ * user is probably intending to type.
761
764
*/
762
- prev_wd = previous_word (start , 0 );
763
- prev2_wd = previous_word (start , 1 );
764
- prev3_wd = previous_word (start , 2 );
765
- prev4_wd = previous_word (start , 3 );
766
- prev5_wd = previous_word (start , 4 );
767
- prev6_wd = previous_word (start , 5 );
765
+ get_previous_words (start , previous_words , lengthof (previous_words ));
768
766
769
767
/* If a backslash command was started, continue */
770
768
if (text [0 ] == '\\' )
@@ -782,18 +780,18 @@ psql_completion(char *text, int start, int end)
782
780
}
783
781
784
782
/* If no previous word, suggest one of the basic sql commands */
785
- else if (! prev_wd )
783
+ else if (prev_wd [ 0 ] == '\0' )
786
784
COMPLETE_WITH_LIST (sql_commands );
787
785
788
786
/* CREATE */
789
787
/* complete with something you can create */
790
788
else if (pg_strcasecmp (prev_wd , "CREATE" ) == 0 )
791
789
matches = completion_matches (text , create_command_generator );
792
790
793
- /* DROP, but watch out for DROP embedded in other commands */
791
+ /* DROP, but not DROP embedded in other commands */
794
792
/* complete with something you can drop */
795
793
else if (pg_strcasecmp (prev_wd , "DROP" ) == 0 &&
796
- pg_strcasecmp ( prev2_wd , "DROP" ) == 0 )
794
+ prev2_wd [ 0 ] == '\0' )
797
795
matches = completion_matches (text , drop_command_generator );
798
796
799
797
/* ALTER */
@@ -2918,11 +2916,12 @@ psql_completion(char *text, int start, int end)
2918
2916
}
2919
2917
2920
2918
/* free storage */
2921
- free (prev_wd );
2922
- free (prev2_wd );
2923
- free (prev3_wd );
2924
- free (prev4_wd );
2925
- free (prev5_wd );
2919
+ {
2920
+ int i ;
2921
+
2922
+ for (i = 0 ; i < lengthof (previous_words ); i ++ )
2923
+ free (previous_words [i ]);
2924
+ }
2926
2925
2927
2926
/* Return our Grand List O' Matches */
2928
2927
return matches ;
@@ -3372,77 +3371,88 @@ exec_query(const char *query)
3372
3371
3373
3372
3374
3373
/*
3375
- * Return the word (space delimited) before point. Set skip > 0 to
3376
- * skip that many words; e.g. skip=1 finds the word before the
3377
- * previous one. Return value is NULL or a malloc'ed string.
3374
+ * Return the nwords word(s) before point. Words are returned right to left,
3375
+ * that is, previous_words[0] gets the last word before point.
3376
+ * If we run out of words, remaining array elements are set to empty strings.
3377
+ * Each array element is filled with a malloc'd string.
3378
3378
*/
3379
- static char *
3380
- previous_word (int point , int skip )
3379
+ static void
3380
+ get_previous_words (int point , char * * previous_words , int nwords )
3381
3381
{
3382
- int i ,
3383
- start = 0 ,
3384
- end = -1 ,
3385
- inquotes = 0 ;
3386
- char * s ;
3387
3382
const char * buf = rl_line_buffer ; /* alias */
3383
+ int i ;
3388
3384
3389
- /* first we look for a space or a parenthesis before the current word */
3385
+ /* first we look for a non-word char before the current point */
3390
3386
for (i = point - 1 ; i >= 0 ; i -- )
3391
3387
if (strchr (WORD_BREAKS , buf [i ]))
3392
3388
break ;
3393
3389
point = i ;
3394
3390
3395
- while (skip -- >= 0 )
3391
+ while (nwords -- > 0 )
3396
3392
{
3397
- int parentheses = 0 ;
3393
+ int start ,
3394
+ end ;
3395
+ char * s ;
3398
3396
3399
3397
/* now find the first non-space which then constitutes the end */
3398
+ end = -1 ;
3400
3399
for (i = point ; i >= 0 ; i -- )
3401
- if (buf [i ] != ' ' )
3400
+ {
3401
+ if (!isspace ((unsigned char ) buf [i ]))
3402
3402
{
3403
3403
end = i ;
3404
3404
break ;
3405
3405
}
3406
+ }
3406
3407
3407
3408
/*
3408
- * If no end found we return null, because there is no word before the
3409
- * point
3410
- */
3411
- if (end == -1 )
3412
- return NULL ;
3413
-
3414
- /*
3415
- * Otherwise we now look for the start. The start is either the last
3416
- * character before any space going backwards from the end, or it's
3417
- * simply character 0. We also handle open quotes and parentheses.
3409
+ * If no end found we return an empty string, because there is no word
3410
+ * before the point
3418
3411
*/
3419
- for (start = end ; start > 0 ; start -- )
3412
+ if (end < 0 )
3413
+ {
3414
+ point = end ;
3415
+ s = pg_strdup ("" );
3416
+ }
3417
+ else
3420
3418
{
3421
- if (buf [start ] == '"' )
3422
- inquotes = !inquotes ;
3423
- if (inquotes == 0 )
3419
+ /*
3420
+ * Otherwise we now look for the start. The start is either the
3421
+ * last character before any word-break character going backwards
3422
+ * from the end, or it's simply character 0. We also handle open
3423
+ * quotes and parentheses.
3424
+ */
3425
+ bool inquotes = false;
3426
+ int parentheses = 0 ;
3427
+
3428
+ for (start = end ; start > 0 ; start -- )
3424
3429
{
3425
- if (buf [start ] == ') ' )
3426
- parentheses ++ ;
3427
- else if (buf [ start ] == '(' )
3430
+ if (buf [start ] == '" ' )
3431
+ inquotes = ! inquotes ;
3432
+ else if (! inquotes )
3428
3433
{
3429
- if (-- parentheses <= 0 )
3434
+ if (buf [start ] == ')' )
3435
+ parentheses ++ ;
3436
+ else if (buf [start ] == '(' )
3437
+ {
3438
+ if (-- parentheses <= 0 )
3439
+ break ;
3440
+ }
3441
+ else if (parentheses == 0 &&
3442
+ strchr (WORD_BREAKS , buf [start - 1 ]))
3430
3443
break ;
3431
3444
}
3432
- else if (parentheses == 0 &&
3433
- strchr (WORD_BREAKS , buf [start - 1 ]))
3434
- break ;
3435
3445
}
3436
- }
3437
3446
3438
- point = start - 1 ;
3439
- }
3447
+ point = start - 1 ;
3440
3448
3441
- /* make a copy */
3442
- s = pg_malloc (end - start + 2 );
3443
- strlcpy (s , & buf [start ], end - start + 2 );
3449
+ /* make a copy of chars from start to end inclusive */
3450
+ s = pg_malloc (end - start + 2 );
3451
+ strlcpy (s , & buf [start ], end - start + 2 );
3452
+ }
3444
3453
3445
- return s ;
3454
+ * previous_words ++ = s ;
3455
+ }
3446
3456
}
3447
3457
3448
3458
#ifdef NOT_USED
0 commit comments