[2/9] widl: Implement [range] attribute.

View: New views
1 Messages — Rating Filter:   Alert me  

[2/9] widl: Implement [range] attribute.

by Rob Shearman :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

---
 dlls/rpcrt4/tests/server.c   |   19 ++++++
 dlls/rpcrt4/tests/server.idl |   15 +++++
 tools/widl/parser.y          |   37 +++++++++++
 tools/widl/typegen.c         |  139 +++++++++++++++++++++++++++++++++++++----
 tools/widl/typegen.h         |    1 +
 5 files changed, 197 insertions(+), 14 deletions(-)

[68fe9fc28c6c0380344af2e58373c4612485d4ef.diff]

diff --git a/dlls/rpcrt4/tests/server.c b/dlls/rpcrt4/tests/server.c
index 63614e3..d9a9fcc 100644
--- a/dlls/rpcrt4/tests/server.c
+++ b/dlls/rpcrt4/tests/server.c
@@ -571,6 +571,16 @@ s_get_filename(void)
     return (char *)__FILE__;
 }
 
+int s_echo_ranged_int(int n)
+{
+    return n;
+}
+
+void s_get_ranged_enum(renum_t *re)
+{
+    *re = RE3;
+}
+
 void
 s_context_handle_test(void)
 {
@@ -762,6 +772,7 @@ basic_tests(void)
   wstr_struct_t ws = {wstring};
   str_t str;
   se_t se;
+  renum_t re;
 
   ok(int_return() == INT_CODE, "RPC int_return\n");
 
@@ -869,6 +880,14 @@ basic_tests(void)
   str = get_filename();
   ok(!strcmp(str, __FILE__), "get_filename() returned %s instead of %s\n", str, __FILE__);
   midl_user_free(str);
+
+  x = echo_ranged_int(0);
+  ok(x == 0, "echo_ranged_int() returned %d instead of 0\n", x);
+  x = echo_ranged_int(100);
+  ok(x == 100, "echo_ranged_int() returned %d instead of 100\n", x);
+
+  get_ranged_enum(&re);
+  ok(re == RE3, "get_ranged_enum() returned %d instead of RE3\n", re);
 }
 
 static void
diff --git a/dlls/rpcrt4/tests/server.idl b/dlls/rpcrt4/tests/server.idl
index 7885161..fe2c075 100644
--- a/dlls/rpcrt4/tests/server.idl
+++ b/dlls/rpcrt4/tests/server.idl
@@ -339,6 +339,21 @@ cpp_quote("#endif")
   void get_numbers_struct([out] numbers_struct_t **ns);
 
   str_t get_filename(void);
+
+  enum renum
+  {
+    RE0,
+    RE1,
+    RE2,
+    RE3,
+  };
+  const int RE_MIN = RE0;
+  const int RE_MAX = RE3;
+  typedef [range(RE_MIN, RE_MAX)] enum renum renum_t;
+  typedef [range(0, 100)] int rint_t;
+  rint_t echo_ranged_int([range(0, 100)] int n);
+  void get_ranged_enum([out] renum_t *re);
+
   void context_handle_test(void);
   void stop(void);
 }
diff --git a/tools/widl/parser.y b/tools/widl/parser.y
index 64f92b0..42123d3 100644
--- a/tools/widl/parser.y
+++ b/tools/widl/parser.y
@@ -1274,6 +1274,37 @@ static void type_function_add_head_arg(type_t *type, var_t *arg)
     list_add_head( type->details.function->args, &arg->entry );
 }
 
+static int is_allowed_range_type(const type_t *type)
+{
+    switch (type_get_type(type))
+    {
+    case TYPE_ENUM:
+        return TRUE;
+    case TYPE_BASIC:
+        switch (type_basic_get_type(type))
+        {
+        case TYPE_BASIC_INT8:
+        case TYPE_BASIC_INT16:
+        case TYPE_BASIC_INT32:
+        case TYPE_BASIC_INT64:
+        case TYPE_BASIC_INT:
+        case TYPE_BASIC_BYTE:
+        case TYPE_BASIC_CHAR:
+        case TYPE_BASIC_WCHAR:
+        case TYPE_BASIC_HYPER:
+            return TRUE;
+        case TYPE_BASIC_FLOAT:
+        case TYPE_BASIC_DOUBLE:
+        case TYPE_BASIC_ERROR_STATUS_T:
+        case TYPE_BASIC_HANDLE:
+            return FALSE;
+        }
+        return FALSE;
+    default:
+        return FALSE;
+    }
+}
+
 static type_t *append_ptrchain_type(type_t *ptrchain, type_t *type)
 {
   type_t *ptrchain_type;
@@ -1363,6 +1394,10 @@ static void set_type(var_t *v, decl_spec_t *decl_spec, const declarator_t *decl,
       error_loc("'%s': [v1_enum] attribute applied to non-enum type\n", v->name);
   }
 
+  if (is_attr(v->attrs, ATTR_RANGE) && !is_allowed_range_type(v->type))
+    error_loc("'%s': [range] attribute applied to non-integer type\n",
+              v->name);
+
   ptype = &v->type;
   sizeless = FALSE;
   if (arr) LIST_FOR_EACH_ENTRY_REV(dim, arr, expr_t, entry)
@@ -2339,6 +2374,7 @@ static void check_field_common(const type_t *container_type,
         case TGT_IFACE_POINTER:
         case TGT_BASIC:
         case TGT_ENUM:
+        case TGT_RANGE:
             /* nothing to do */
             break;
         }
@@ -2388,6 +2424,7 @@ static void check_remoting_args(const var_t *func)
             {
             case TGT_BASIC:
             case TGT_ENUM:
+            case TGT_RANGE:
             case TGT_STRUCT:
             case TGT_UNION:
             case TGT_CTXT_HANDLE:
diff --git a/tools/widl/typegen.c b/tools/widl/typegen.c
index 1f8e4fe..6b55d20 100644
--- a/tools/widl/typegen.c
+++ b/tools/widl/typegen.c
@@ -122,6 +122,19 @@ const char *string_of_type(unsigned char type)
     }
 }
 
+static void *get_aliaschain_attrp(const type_t *type, enum attr_type attr)
+{
+    const type_t *t = type;
+    for (;;)
+    {
+        if (is_attr(t->attrs, attr))
+            return get_attrp(t->attrs, attr);
+        else if (type_is_alias(t))
+            t = type_alias_get_aliasee(t);
+        else return 0;
+    }
+}
+
 unsigned char get_basic_fc(const type_t *type)
 {
     int sign = type_basic_get_sign(type);
@@ -200,8 +213,12 @@ enum typegen_type typegen_detect_type(const type_t *type, const attr_list_t *att
     switch (type_get_type(type))
     {
     case TYPE_BASIC:
+        if (is_attr(attrs, ATTR_RANGE) || is_aliaschain_attr(type, ATTR_RANGE))
+            return TGT_RANGE;
         return TGT_BASIC;
     case TYPE_ENUM:
+        if (is_attr(attrs, ATTR_RANGE) || is_aliaschain_attr(type, ATTR_RANGE))
+            return TGT_RANGE;
         return TGT_ENUM;
     case TYPE_POINTER:
         if (type_get_type(type_pointer_get_ref(type)) == TYPE_INTERFACE ||
@@ -337,6 +354,8 @@ unsigned char get_struct_fc(const type_t *type)
         }
         break;
     }
+    case TGT_RANGE:
+        return RPC_FC_BOGUS_STRUCT;
     case TGT_STRING:
         /* shouldn't get here because of TDT_IGNORE_STRINGS above. fall through */
     case TGT_INVALID:
@@ -425,6 +444,9 @@ unsigned char get_array_fc(const type_t *type)
         if (get_pointer_fc(elem_type, NULL, FALSE) == RPC_FC_RP || pointer_size != 4)
             fc = RPC_FC_BOGUS_ARRAY;
         break;
+    case TGT_RANGE:
+        fc = RPC_FC_BOGUS_ARRAY;
+        break;
     case TGT_BASIC:
     case TGT_CTXT_HANDLE:
     case TGT_CTXT_HANDLE_POINTER:
@@ -499,6 +521,7 @@ static int type_has_pointers(const type_t *type)
     case TGT_IFACE_POINTER:
     case TGT_BASIC:
     case TGT_ENUM:
+    case TGT_RANGE:
     case TGT_INVALID:
         break;
     }
@@ -552,6 +575,7 @@ static int type_has_full_pointer(const type_t *type, const attr_list_t *attrs,
     case TGT_IFACE_POINTER:
     case TGT_BASIC:
     case TGT_ENUM:
+    case TGT_RANGE:
     case TGT_INVALID:
         break;
     }
@@ -2677,6 +2701,33 @@ static unsigned int write_contexthandle_tfs(FILE *file, const type_t *type,
     return start_offset;
 }
 
+static unsigned int write_range_tfs(FILE *file, const attr_list_t *attrs,
+                                    type_t *type, expr_list_t *range_list,
+                                    unsigned int *typeformat_offset)
+{
+    unsigned char fc;
+    unsigned int start_offset = *typeformat_offset;
+    const expr_t *range_min = LIST_ENTRY(list_head(range_list), const expr_t, entry);
+    const expr_t *range_max = LIST_ENTRY(list_next(range_list, list_head(range_list)), const expr_t, entry);
+
+    if (type_get_type(type) == TYPE_BASIC)
+        fc = get_basic_fc(type);
+    else
+        fc = get_enum_fc(type);
+
+    /* fc must fit in lower 4-bits of 8-bit field below */
+    assert(fc <= 0xf);
+
+    print_file(file, 0, "/* %u */\n", *typeformat_offset);
+    print_file(file, 2, "0x%x,\t/* FC_RANGE */\n", RPC_FC_RANGE);
+    print_file(file, 2, "0x%x,\t/* %s */\n", fc, string_of_type(fc));
+    print_file(file, 2, "NdrFcLong(0x%lx),\t/* %lu */\n", range_min->cval, range_min->cval);
+    print_file(file, 2, "NdrFcLong(0x%lx),\t/* %lu */\n", range_max->cval, range_max->cval);
+    *typeformat_offset += 10;
+
+    return start_offset;
+}
+
 static unsigned int write_typeformatstring_var(FILE *file, int indent, const var_t *func,
                                                type_t *type, const var_t *var,
                                                int toplevel_param,
@@ -2724,6 +2775,13 @@ static unsigned int write_typeformatstring_var(FILE *file, int indent, const var
     case TGT_BASIC:
         /* nothing to do */
         return 0;
+    case TGT_RANGE:
+    {
+        expr_list_t *range_list = get_attrp(var->attrs, ATTR_RANGE);
+        if (!range_list)
+            range_list = get_aliaschain_attrp(type, ATTR_RANGE);
+        return write_range_tfs(file, var->attrs, type, range_list, typeformat_offset);
+    }
     case TGT_IFACE_POINTER:
         return write_ip_tfs(file, var->attrs, type, typeformat_offset);
     case TGT_POINTER:
@@ -2828,6 +2886,14 @@ static int write_embedded_types(FILE *file, const attr_list_t *attrs, type_t *ty
     case TGT_BASIC:
         /* nothing to do */
         break;
+    case TGT_RANGE:
+    {
+        expr_list_t *range_list = get_attrp(attrs, ATTR_RANGE);
+        if (!range_list)
+            range_list = get_aliaschain_attrp(type, ATTR_RANGE);
+        write_range_tfs(file, attrs, type, range_list, tfsoff);
+        break;
+    }
     case TGT_CTXT_HANDLE:
     case TGT_CTXT_HANDLE_POINTER:
     case TGT_INVALID:
@@ -3004,6 +3070,7 @@ static unsigned int get_required_buffer_size_type(
             {
             case TGT_BASIC:
             case TGT_ENUM:
+            case TGT_RANGE:
                 return get_required_buffer_size_type( ref, name, NULL, FALSE, alignment );
             case TGT_STRUCT:
                 if (get_struct_fc(ref) == RPC_FC_STRUCT)
@@ -3503,6 +3570,49 @@ static void write_remoting_arg(FILE *file, int indent, const var_t *func, const
             print_file(file, indent+1, "0x%02x /* %s */);\n", get_enum_fc(type), string_of_type(get_enum_fc(type)));
         }
         break;
+    case TGT_RANGE:
+        if (type_get_type(type) == TYPE_ENUM)
+        {
+            if (phase == PHASE_MARSHAL || phase == PHASE_UNMARSHAL)
+            {
+                if (phase == PHASE_MARSHAL)
+                    print_file(file, indent, "NdrSimpleTypeMarshall(\n");
+                else
+                    print_file(file, indent, "NdrSimpleTypeUnmarshall(\n");
+                print_file(file, indent+1, "&__frame->_StubMsg,\n");
+                print_file(file, indent+1, "(unsigned char *)&%s%s,\n",
+                           local_var_prefix,
+                           var->name);
+                print_file(file, indent+1, "0x%02x /* %s */);\n", get_enum_fc(type), string_of_type(get_enum_fc(type)));
+            }
+        }
+        else
+        {
+            if (phase == PHASE_MARSHAL || phase == PHASE_UNMARSHAL)
+                print_phase_basetype(file, indent, local_var_prefix, phase, pass, var, var->name);
+        }
+        /* Note: this goes beyond what MIDL does - it only supports arguments
+         * with the [range] attribute in Oicf mode */
+        if (phase == PHASE_UNMARSHAL)
+        {
+            const expr_t *range_min;
+            const expr_t *range_max;
+            expr_list_t *range_list = get_attrp(var->attrs, ATTR_RANGE);
+            if (!range_list)
+                range_list = get_aliaschain_attrp(type, ATTR_RANGE);
+            range_min = LIST_ENTRY(list_head(range_list), const expr_t, entry);
+            range_max = LIST_ENTRY(list_next(range_list, list_head(range_list)), const expr_t, entry);
+
+            print_file(file, indent, "if ((%s%s < (", local_var_prefix, var->name);
+            write_type_decl(file, var->type, NULL);
+            fprintf(file, ")0x%lx) || (%s%s > (", range_min->cval, local_var_prefix, var->name);
+            write_type_decl(file, var->type, NULL);
+            fprintf(file, ")0x%lx))\n", range_max->cval);
+            print_file(file, indent, "{\n");
+            print_file(file, indent+1, "RpcRaiseException(RPC_S_INVALID_BOUND);\n");
+            print_file(file, indent, "}\n");
+        }
+        break;
     case TGT_STRUCT:
         switch (get_struct_fc(type))
         {
@@ -3543,23 +3653,23 @@ static void write_remoting_arg(FILE *file, int indent, const var_t *func, const
     case TGT_POINTER:
     {
         const type_t *ref = type_pointer_get_ref(type);
-        if (pointer_type == RPC_FC_RP && !is_user_type(ref)) switch (type_get_type(ref))
+        if (pointer_type == RPC_FC_RP) switch (typegen_detect_type(ref, NULL, TDT_ALL_TYPES))
         {
-        case TYPE_BASIC:
+        case TGT_BASIC:
             /* base types have known sizes, so don't need a sizing pass
              * and don't have any memory to free and so don't need a
              * freeing pass */
             if (phase == PHASE_MARSHAL || phase == PHASE_UNMARSHAL)
                 print_phase_basetype(file, indent, local_var_prefix, phase, pass, var, var->name);
             break;
-        case TYPE_ENUM:
+        case TGT_ENUM:
             /* base types have known sizes, so don't need a sizing pass
              * and don't have any memory to free and so don't need a
              * freeing pass */
             if (phase == PHASE_MARSHAL || phase == PHASE_UNMARSHAL)
                 print_phase_function(file, indent, "Pointer", local_var_prefix, phase, var, start_offset);
             break;
-        case TYPE_STRUCT:
+        case TGT_STRUCT:
         {
             const char *struct_type = NULL;
             switch (get_struct_fc(ref))
@@ -3605,8 +3715,7 @@ static void write_remoting_arg(FILE *file, int indent, const var_t *func, const
             }
             break;
         }
-        case TYPE_UNION:
-        case TYPE_ENCAPSULATED_UNION:
+        case TGT_UNION:
         {
             const char *union_type = NULL;
             if (phase == PHASE_FREE)
@@ -3625,16 +3734,17 @@ static void write_remoting_arg(FILE *file, int indent, const var_t *func, const
                                  phase, var, start_offset);
             break;
         }
-        case TYPE_POINTER:
-        case TYPE_ARRAY:
+        case TGT_STRING:
+        case TGT_POINTER:
+        case TGT_ARRAY:
+        case TGT_RANGE:
+        case TGT_IFACE_POINTER:
+        case TGT_USER_TYPE:
+        case TGT_CTXT_HANDLE:
+        case TGT_CTXT_HANDLE_POINTER:
             print_phase_function(file, indent, "Pointer", local_var_prefix, phase, var, start_offset);
             break;
-        case TYPE_VOID:
-        case TYPE_ALIAS:
-        case TYPE_MODULE:
-        case TYPE_COCLASS:
-        case TYPE_FUNCTION:
-        case TYPE_INTERFACE:
+        case TGT_INVALID:
             assert(0);
             break;
         }
@@ -3858,6 +3968,7 @@ void assign_stub_out_args( FILE *file, int indent, const var_t *func, const char
                 case TGT_BASIC:
                 case TGT_ENUM:
                 case TGT_POINTER:
+                case TGT_RANGE:
                     print_file(file, indent, "%s_W%u = 0;\n", local_var_prefix, i);
                     break;
                 case TGT_STRUCT:
diff --git a/tools/widl/typegen.h b/tools/widl/typegen.h
index 8c8ba11..c414d78 100644
--- a/tools/widl/typegen.h
+++ b/tools/widl/typegen.h
@@ -56,6 +56,7 @@ enum typegen_type
     TGT_ENUM,
     TGT_STRUCT,
     TGT_UNION,
+    TGT_RANGE,
 };
 
 typedef int (*type_pred_t)(const type_t *);