aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org.ua>2014-10-28 15:40:20 +0200
committerSergey Poznyakoff <gray@gnu.org.ua>2015-12-17 15:26:28 +0200
commit56a02e741cd8d8b9dce27a79ae9bbcaf1713c4f7 (patch)
tree1153a7dd5c15ab80f1ffa7da4eb9091685222445 /src
parent8383ec3a522a944969b3fc44069a3ff056da554a (diff)
downloadgrecs-56a02e741cd8d8b9dce27a79ae9bbcaf1713c4f7.tar.gz
grecs-56a02e741cd8d8b9dce27a79ae9bbcaf1713c4f7.tar.bz2
Improve wordsplit
* src/wordsplit.c: Implement default assignment, word expansion in variable defaults, distinction between ${variable:-word} and ${variable-word}. * doc/wordsplit.3: New file. * src/wordsplit.h (wordsplit)<ws_envbuf,ws_envidx> <ws_envsiz>: New members. (WRDSF_ARGV): Remove. (WRDSF_OPTIONS): New flag. (WRDSO_ARGV): New option bit. * tests/wordsplit.at: Add new tests. * tests/wsp.c: Set WRDSF_OPTIONS flag if one of the options is requested.
Diffstat (limited to 'src')
-rw-r--r--src/wordsplit.c367
-rw-r--r--src/wordsplit.h37
2 files changed, 310 insertions, 94 deletions
diff --git a/src/wordsplit.c b/src/wordsplit.c
index 4a69725..c726239 100644
--- a/src/wordsplit.c
+++ b/src/wordsplit.c
@@ -114,11 +114,30 @@ _wsplt_subsplit (struct wordsplit *wsp, struct wordsplit *wss,
114 wss->ws_error = wsp->ws_error; 114 wss->ws_error = wsp->ws_error;
115 wss->ws_alloc_die = wsp->ws_alloc_die; 115 wss->ws_alloc_die = wsp->ws_alloc_die;
116 116
117 if (!(flags & WRDSF_NOVAR))
118 {
119 wss->ws_env = wsp->ws_env;
120 wss->ws_getvar = wsp->ws_getvar;
121 flags |= wsp->ws_flags & (WRDSF_ENV | WRDSF_ENV_KV | WRDSF_GETVAR);
122 }
123 if (!(flags & WRDSF_NOCMD))
124 {
125 wss->ws_command = wsp->ws_command;
126 }
127
128 if ((flags & (WRDSF_NOVAR|WRDSF_NOCMD)) != (WRDSF_NOVAR|WRDSF_NOCMD))
129 {
130 wss->ws_closure = wsp->ws_closure;
131 flags |= wsp->ws_flags & WRDSF_CLOSURE;
132 }
133
134 wss->ws_options = wsp->ws_options;
135
117 flags |= WRDSF_DELIM 136 flags |= WRDSF_DELIM
118 | WRDSF_ALLOC_DIE 137 | WRDSF_ALLOC_DIE
119 | WRDSF_ERROR 138 | WRDSF_ERROR
120 | WRDSF_DEBUG 139 | WRDSF_DEBUG
121 | (wsp->ws_flags & (WRDSF_SHOWDBG | WRDSF_SHOWERR)); 140 | (wsp->ws_flags & (WRDSF_SHOWDBG | WRDSF_SHOWERR | WRDSF_OPTIONS));
122 141
123 return wordsplit_run (str, len, wss, flags, wsp->ws_lvl + 1); 142 return wordsplit_run (str, len, wss, flags, wsp->ws_lvl + 1);
124} 143}
@@ -168,12 +187,11 @@ wordsplit_init (struct wordsplit *wsp, const char *input, size_t len,
168 if (!(wsp->ws_flags & WRDSF_ERROR)) 187 if (!(wsp->ws_flags & WRDSF_ERROR))
169 wsp->ws_error = _wsplt_error; 188 wsp->ws_error = _wsplt_error;
170 189
171 if (!(wsp->ws_flags & WRDSF_NOVAR) 190 if (!(wsp->ws_flags & WRDSF_NOVAR))
172 && !(wsp->ws_flags & (WRDSF_ENV | WRDSF_GETVAR)))
173 { 191 {
174 _wsplt_seterr (wsp, WRDSE_USAGE); 192 /* These will be initialized on first variable assignment */
175 errno = EINVAL; 193 wsp->ws_envidx = wsp->ws_envsiz = 0;
176 return wsp->ws_errno; 194 wsp->ws_envbuf = NULL;
177 } 195 }
178 196
179 if (!(wsp->ws_flags & WRDSF_NOCMD)) 197 if (!(wsp->ws_flags & WRDSF_NOCMD))
@@ -214,6 +232,9 @@ wordsplit_init (struct wordsplit *wsp, const char *input, size_t len,
214 if (!(wsp->ws_flags & WRDSF_CLOSURE)) 232 if (!(wsp->ws_flags & WRDSF_CLOSURE))
215 wsp->ws_closure = NULL; 233 wsp->ws_closure = NULL;
216 234
235 if (!(wsp->ws_flags & WRDSF_OPTIONS))
236 wsp->ws_options = 0;
237
217 wsp->ws_endp = 0; 238 wsp->ws_endp = 0;
218 239
219 wordsplit_init0 (wsp); 240 wordsplit_init0 (wsp);
@@ -717,13 +738,14 @@ find_closing_paren (const char *str, size_t i, size_t len, size_t *poff,
717 return 1; 738 return 1;
718} 739}
719 740
720static const char * 741static int
721wordsplit_find_env (struct wordsplit *wsp, const char *name, size_t len) 742wordsplit_find_env (struct wordsplit *wsp, const char *name, size_t len,
743 char const **ret)
722{ 744{
723 size_t i; 745 size_t i;
724 746
725 if (!(wsp->ws_flags & WRDSF_ENV)) 747 if (!(wsp->ws_flags & WRDSF_ENV))
726 return NULL; 748 return WRDSE_UNDEF;
727 749
728 if (wsp->ws_flags & WRDSF_ENV_KV) 750 if (wsp->ws_flags & WRDSF_ENV_KV)
729 { 751 {
@@ -732,14 +754,17 @@ wordsplit_find_env (struct wordsplit *wsp, const char *name, size_t len)
732 { 754 {
733 size_t elen = strlen (wsp->ws_env[i]); 755 size_t elen = strlen (wsp->ws_env[i]);
734 if (elen == len && memcmp (wsp->ws_env[i], name, elen) == 0) 756 if (elen == len && memcmp (wsp->ws_env[i], name, elen) == 0)
735 return wsp->ws_env[i + 1]; 757 {
758 *ret = wsp->ws_env[i + 1];
759 return WRDSE_OK;
760 }
736 /* Skip the value. Break the loop if it is NULL. */ 761 /* Skip the value. Break the loop if it is NULL. */
737 i++; 762 i++;
738 if (wsp->ws_env[i] == NULL) 763 if (wsp->ws_env[i] == NULL)
739 break; 764 break;
740 } 765 }
741 } 766 }
742 else 767 else if (wsp->ws_env)
743 { 768 {
744 /* Usual (A=B) environment. */ 769 /* Usual (A=B) environment. */
745 for (i = 0; wsp->ws_env[i]; i++) 770 for (i = 0; wsp->ws_env[i]; i++)
@@ -751,10 +776,117 @@ wordsplit_find_env (struct wordsplit *wsp, const char *name, size_t len)
751 if (name[j] != var[j]) 776 if (name[j] != var[j])
752 break; 777 break;
753 if (j == len && var[j] == '=') 778 if (j == len && var[j] == '=')
754 return var + j + 1; 779 {
780 *ret = var + j + 1;
781 return WRDSE_OK;
782 }
783 }
784 }
785 return WRDSE_UNDEF;
786}
787
788static int
789wsplt_assign_var (struct wordsplit *wsp, const char *name, size_t namelen,
790 char *value)
791{
792 int n = (wsp->ws_flags & WRDSF_ENV_KV) ? 2 : 1;
793 char *v;
794
795 if (wsp->ws_envidx + n >= wsp->ws_envsiz)
796 {
797 size_t sz;
798 char **newenv;
799
800 if (!wsp->ws_envbuf)
801 {
802 if (wsp->ws_flags & WRDSF_ENV)
803 {
804 size_t i = 0, j;
805
806 if (wsp->ws_env)
807 {
808 for (; wsp->ws_env[i]; i++)
809 ;
810 }
811
812 sz = i + n + 1;
813
814 newenv = calloc (sz, sizeof(newenv[0]));
815 if (!newenv)
816 return _wsplt_nomem (wsp);
817
818 for (j = 0; j < i; j++)
819 {
820 newenv[j] = strdup (wsp->ws_env[j]);
821 if (!newenv[j])
822 {
823 for (; j > 1; j--)
824 free (newenv[j-1]);
825 free (newenv[j-1]);
826 return _wsplt_nomem (wsp);
827 }
828 }
829 newenv[j] = NULL;
830
831 wsp->ws_envbuf = newenv;
832 wsp->ws_envidx = i;
833 wsp->ws_envsiz = sz;
834 wsp->ws_env = (const char**) wsp->ws_envbuf;
835 }
836 else
837 {
838 newenv = calloc (WORDSPLIT_ENV_INIT, sizeof(newenv[0]));
839 if (!newenv)
840 return _wsplt_nomem (wsp);
841 wsp->ws_envbuf = newenv;
842 wsp->ws_envidx = 0;
843 wsp->ws_envsiz = WORDSPLIT_ENV_INIT;
844 wsp->ws_env = (const char**) wsp->ws_envbuf;
845 wsp->ws_flags |= WRDSF_ENV;
846 }
847 }
848 else
849 {
850 wsp->ws_envsiz *= 2;
851 newenv = realloc (wsp->ws_envbuf,
852 wsp->ws_envsiz * sizeof (wsp->ws_envbuf[0]));
853 if (!newenv)
854 return _wsplt_nomem (wsp);
855 wsp->ws_envbuf = newenv;
856 wsp->ws_env = (const char**) wsp->ws_envbuf;
755 } 857 }
756 } 858 }
757 return NULL; 859
860 if (wsp->ws_flags & WRDSF_ENV_KV)
861 {
862 /* A key-value pair environment */
863 char *p = malloc (namelen + 1);
864 if (!p)
865 return _wsplt_nomem (wsp);
866 memcpy (p, name, namelen);
867 p[namelen] = 0;
868
869 v = strdup (value);
870 if (!v)
871 {
872 free (p);
873 return _wsplt_nomem (wsp);
874 }
875 wsp->ws_env[wsp->ws_envidx++] = p;
876 wsp->ws_env[wsp->ws_envidx++] = v;
877 }
878 else
879 {
880 v = malloc (namelen + strlen(value) + 2);
881 if (!v)
882 return _wsplt_nomem (wsp);
883 memcpy (v, name, namelen);
884 v[namelen++] = '=';
885 strcpy(v + namelen, value);
886 wsp->ws_env[wsp->ws_envidx++] = v;
887 }
888 wsp->ws_env[wsp->ws_envidx++] = NULL;
889 return WRDSE_OK;