@@ -668,7 +668,7 @@ static char **complete_from_variables(char *text,
668668
669669static PGresult * exec_query (const char * query );
670670
671- static char * previous_word (int point ,int skip );
671+ static void get_previous_words (int point ,char * * previous_words , int nwords );
672672
673673#ifdef NOT_USED
674674static char * quote_file_name (char * text ,int match_type ,char * quote_pointer );
@@ -710,13 +710,16 @@ psql_completion(char *text, int start, int end)
710710/* This is the variable we'll return. */
711711char * * matches = NULL ;
712712
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])
720723
721724static const char * const sql_commands []= {
722725"ABORT" ,"ALTER" ,"ANALYZE" ,"BEGIN" ,"CHECKPOINT" ,"CLOSE" ,"CLUSTER" ,
@@ -755,16 +758,11 @@ psql_completion(char *text, int start, int end)
755758completion_info_charp2 = NULL ;
756759
757760/*
758- * Scan the input line before our current position for the lastfive
761+ * Scan the input line before our current position for the lastfew
759762 * 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.
761764 */
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 ));
768766
769767/* If a backslash command was started, continue */
770768if (text [0 ]== '\\' )
@@ -782,18 +780,18 @@ psql_completion(char *text, int start, int end)
782780}
783781
784782/* If no previous word, suggest one of the basic sql commands */
785- else if (! prev_wd )
783+ else if (prev_wd [ 0 ] == '\0' )
786784COMPLETE_WITH_LIST (sql_commands );
787785
788786/* CREATE */
789787/* complete with something you can create */
790788else if (pg_strcasecmp (prev_wd ,"CREATE" )== 0 )
791789matches = completion_matches (text ,create_command_generator );
792790
793- /* DROP, butwatch out for DROP embedded in other commands */
791+ /* DROP, butnot DROP embedded in other commands */
794792/* complete with something you can drop */
795793else if (pg_strcasecmp (prev_wd ,"DROP" )== 0 &&
796- pg_strcasecmp ( prev2_wd , "DROP" ) == 0 )
794+ prev2_wd [ 0 ] == '\0' )
797795matches = completion_matches (text ,drop_command_generator );
798796
799797/* ALTER */
@@ -2918,11 +2916,12 @@ psql_completion(char *text, int start, int end)
29182916}
29192917
29202918/* 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+ }
29262925
29272926/* Return our Grand List O' Matches */
29282927return matches ;
@@ -3372,77 +3371,88 @@ exec_query(const char *query)
33723371
33733372
33743373/*
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.
33783378 */
3379- static char *
3380- previous_word (int point ,int skip )
3379+ static void
3380+ get_previous_words (int point ,char * * previous_words , int nwords )
33813381{
3382- int i ,
3383- start = 0 ,
3384- end = -1 ,
3385- inquotes = 0 ;
3386- char * s ;
33873382const char * buf = rl_line_buffer ;/* alias */
3383+ int i ;
33883384
3389- /* first we look for aspace or a parenthesis before the currentword */
3385+ /* first we look for anon-word char before the currentpoint */
33903386for (i = point - 1 ;i >=0 ;i -- )
33913387if (strchr (WORD_BREAKS ,buf [i ]))
33923388break ;
33933389point = i ;
33943390
3395- while (skip -- >= 0 )
3391+ while (nwords -- > 0 )
33963392{
3397- int parentheses = 0 ;
3393+ int start ,
3394+ end ;
3395+ char * s ;
33983396
33993397/* now find the first non-space which then constitutes the end */
3398+ end = -1 ;
34003399for (i = point ;i >=0 ;i -- )
3401- if (buf [i ]!= ' ' )
3400+ {
3401+ if (!isspace ((unsignedchar )buf [i ]))
34023402{
34033403end = i ;
34043404break ;
34053405}
3406+ }
34063407
34073408/*
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
34183411 */
3419- for (start = end ;start > 0 ;start -- )
3412+ if (end < 0 )
3413+ {
3414+ point = end ;
3415+ s = pg_strdup ("" );
3416+ }
3417+ else
34203418{
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 -- )
34243429{
3425- if (buf [start ]== ') ' )
3426- parentheses ++ ;
3427- else if (buf [ start ] == '(' )
3430+ if (buf [start ]== '" ' )
3431+ inquotes = ! inquotes ;
3432+ else if (! inquotes )
34283433{
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 ]))
34303443break ;
34313444}
3432- else if (parentheses == 0 &&
3433- strchr (WORD_BREAKS ,buf [start - 1 ]))
3434- break ;
34353445}
3436- }
34373446
3438- point = start - 1 ;
3439- }
3447+ point = start - 1 ;
34403448
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+ }
34443453
3445- return s ;
3454+ * previous_words ++ = s ;
3455+ }
34463456}
34473457
34483458#ifdef NOT_USED