| 1174 | } expansion_item; |
| 1175 | |
| 1176 | static LIST * expand( expansion_item * items, int const length ) |
| 1177 | { |
| 1178 | LIST * result = L0; |
| 1179 | string buf[ 1 ]; |
| 1180 | int size = 0; |
| 1181 | int i; |
| 1182 | |
| 1183 | assert( length > 0 ); |
| 1184 | for ( i = 0; i < length; ++i ) |
| 1185 | { |
| 1186 | LISTITER iter = list_begin( items[ i ].values ); |
| 1187 | LISTITER const end = list_end( items[ i ].values ); |
| 1188 | |
| 1189 | /* If any of the items has no values - the result is an empty list. */ |
| 1190 | if ( iter == end ) return L0; |
| 1191 | |
| 1192 | /* Set each item's 'current' to its first listed value. This indicates |
| 1193 | * each item's next value to be used when constructing the list of all |
| 1194 | * possible concatenated values. |
| 1195 | */ |
| 1196 | items[ i ].current = iter; |
| 1197 | |
| 1198 | /* Calculate the longest concatenated string length - to know how much |
| 1199 | * memory we need to allocate as a buffer for holding the concatenated |
| 1200 | * strings. |
| 1201 | */ |
| 1202 | { |
| 1203 | int max = 0; |
| 1204 | for ( ; iter != end; iter = list_next( iter ) ) |
| 1205 | { |
| 1206 | int const len = strlen( object_str( list_item( iter ) ) ); |
| 1207 | if ( len > max ) max = len; |
| 1208 | } |
| 1209 | size += max; |
| 1210 | } |
| 1211 | } |
| 1212 | |
| 1213 | string_new( buf ); |
| 1214 | string_reserve( buf, size ); |
| 1215 | |
| 1216 | i = 0; |
| 1217 | while ( i >= 0 ) |
| 1218 | { |
| 1219 | for ( ; i < length; ++i ) |
| 1220 | { |
| 1221 | items[ i ].size = buf->size; |
| 1222 | string_append( buf, object_str( list_item( items[ i ].current ) ) ); |
| 1223 | } |
| 1224 | result = list_push_back( result, object_new( buf->value ) ); |
| 1225 | while ( --i >= 0 ) |
| 1226 | { |
| 1227 | if ( list_next( items[ i ].current ) != list_end( items[ i ].values |
| 1228 | ) ) |
| 1229 | { |
| 1230 | items[ i ].current = list_next( items[ i ].current ); |
| 1231 | string_truncate( buf, items[ i ].size ); |
| 1232 | break; |
| 1233 | } |
no test coverage detected