Kaynağa Gözat

ncd: modules: value: add value::substr()

ambrop7 14 yıl önce
ebeveyn
işleme
a32476c519
1 değiştirilmiş dosya ile 78 ekleme ve 1 silme
  1. 78 1
      ncd/modules/value.c

+ 78 - 1
ncd/modules/value.c

@@ -98,13 +98,24 @@
  *   operation on it to fail. Any other value objects which referred to the same value
  *   or parts of it will too enter deleted state. If the value was an element
  *   in a list or map, is is removed from it.
+ * 
+ * Synopsis:
+ *   value value::substr(string start [, string length])
+ * 
+ * Description:
+ *   Constructs a string value by extracting a part of a string.
+ *   'start' specifies the index of the character (from zero) where the substring to
+ *   extract starts, and must be <= the length of the string.
+ *   'length' specifies the maximum number of characters to extract, if given.
+ *   The newly constructed value is a copy of the extracted substring.
+ *   The value must be a string value.
  */
 
 #include <stdlib.h>
 #include <string.h>
 #include <stddef.h>
 #include <limits.h>
-#include <stdint.h>
+#include <inttypes.h>
 
 #include <misc/offset.h>
 #include <misc/debug.h>
@@ -1214,6 +1225,66 @@ fail0:
     NCDModuleInst_Backend_Dead(i);
 }
 
+static void func_new_substr (NCDModuleInst *i)
+{
+    NCDValue *start_arg;
+    NCDValue *length_arg = NULL;
+    if (!NCDValue_ListRead(i->args, 1, &start_arg) &&
+        !NCDValue_ListRead(i->args, 2, &start_arg, &length_arg)) {
+        ModuleLog(i, BLOG_ERROR, "wrong arity");
+        goto fail0;
+    }
+    if (!NCDValue_IsStringNoNulls(start_arg) || (length_arg && !NCDValue_IsStringNoNulls(length_arg))) {
+        ModuleLog(i, BLOG_ERROR, "wrong type");
+        goto fail0;
+    }
+    
+    uintmax_t start;
+    if (!parse_unsigned_integer(NCDValue_StringValue(start_arg), &start)) {
+        ModuleLog(i, BLOG_ERROR, "start is not a number");
+        goto fail0;
+    }
+    
+    uintmax_t length = UINTMAX_MAX;
+    if (length_arg && !parse_unsigned_integer(NCDValue_StringValue(length_arg), &length)) {
+        ModuleLog(i, BLOG_ERROR, "length is not a number");
+        goto fail0;
+    }
+    
+    struct instance *mo = ((NCDModuleInst *)i->method_user)->inst_user;
+    struct value *mov = valref_val(&mo->ref);
+    
+    if (!mov) {
+        ModuleLog(i, BLOG_ERROR, "value was deleted");
+        goto fail0;
+    }
+    
+    if (mov->type != NCDVALUE_STRING) {
+        ModuleLog(i, BLOG_ERROR, "value is not a string");
+        goto fail0;
+    }
+    
+    if (start > mov->string.length) {
+        ModuleLog(i, BLOG_ERROR, "start is out of range");
+        goto fail0;
+    }
+    
+    size_t remain = mov->string.length - start;
+    size_t amount = length < remain ? length : remain;
+    
+    struct value *v = value_init_string(i, mov->string.string + start, amount);
+    if (!v) {
+        goto fail0;
+    }
+    
+    func_new_common(i, v, NULL, NULL);
+    return;
+    
+fail0:
+    NCDModuleInst_Backend_SetError(i);
+    NCDModuleInst_Backend_Dead(i);
+}
+
 static void remove_func_new (NCDModuleInst *i)
 {
     NCDValue *where_arg;
@@ -1309,6 +1380,12 @@ static const struct NCDModule modules[] = {
     }, {
         .type = "value::delete",
         .func_new = delete_func_new
+    }, {
+        .type = "value::substr",
+        .base_type = "value",
+        .func_new = func_new_substr,
+        .func_die = func_die,
+        .func_getvar = func_getvar
     }, {
         .type = NULL
     }