diff options
Diffstat (limited to 'lib')
162 files changed, 16280 insertions, 2873 deletions
diff --git a/lib/.gitignore b/lib/.gitignore new file mode 100644 index 0000000000..bdc850f3b7 --- /dev/null +++ b/lib/.gitignore @@ -0,0 +1,464 @@ +# megaco + +/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_prev3a.erl +/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_prev3a.hrl +/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_prev3b.erl +/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_prev3b.hrl +/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_prev3c.erl +/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_prev3c.hrl +/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_v1.erl +/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_v1.hrl +/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_v2.erl +/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_v2.hrl +/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_v3.erl +/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_v3.hrl +/megaco/src/binary/megaco_ber_bin_media_gateway_control_prev3a.erl +/megaco/src/binary/megaco_ber_bin_media_gateway_control_prev3a.hrl +/megaco/src/binary/megaco_ber_bin_media_gateway_control_prev3b.erl +/megaco/src/binary/megaco_ber_bin_media_gateway_control_prev3b.hrl +/megaco/src/binary/megaco_ber_bin_media_gateway_control_prev3c.erl +/megaco/src/binary/megaco_ber_bin_media_gateway_control_prev3c.hrl +/megaco/src/binary/megaco_ber_bin_media_gateway_control_v1.erl +/megaco/src/binary/megaco_ber_bin_media_gateway_control_v1.hrl +/megaco/src/binary/megaco_ber_bin_media_gateway_control_v2.erl +/megaco/src/binary/megaco_ber_bin_media_gateway_control_v2.hrl +/megaco/src/binary/megaco_ber_bin_media_gateway_control_v3.erl +/megaco/src/binary/megaco_ber_bin_media_gateway_control_v3.hrl +/megaco/src/binary/megaco_ber_media_gateway_control_prev3a.erl +/megaco/src/binary/megaco_ber_media_gateway_control_prev3a.hrl +/megaco/src/binary/megaco_ber_media_gateway_control_prev3b.erl +/megaco/src/binary/megaco_ber_media_gateway_control_prev3b.hrl +/megaco/src/binary/megaco_ber_media_gateway_control_prev3c.erl +/megaco/src/binary/megaco_ber_media_gateway_control_prev3c.hrl +/megaco/src/binary/megaco_ber_media_gateway_control_v1.erl +/megaco/src/binary/megaco_ber_media_gateway_control_v1.hrl +/megaco/src/binary/megaco_ber_media_gateway_control_v2.erl +/megaco/src/binary/megaco_ber_media_gateway_control_v2.hrl +/megaco/src/binary/megaco_ber_media_gateway_control_v3.erl +/megaco/src/binary/megaco_ber_media_gateway_control_v3.hrl +/megaco/src/binary/megaco_per_bin_drv_media_gateway_control_prev3a.erl +/megaco/src/binary/megaco_per_bin_drv_media_gateway_control_prev3a.hrl +/megaco/src/binary/megaco_per_bin_drv_media_gateway_control_prev3b.erl +/megaco/src/binary/megaco_per_bin_drv_media_gateway_control_prev3b.hrl +/megaco/src/binary/megaco_per_bin_drv_media_gateway_control_prev3c.erl +/megaco/src/binary/megaco_per_bin_drv_media_gateway_control_prev3c.hrl +/megaco/src/binary/megaco_per_bin_drv_media_gateway_control_v1.erl +/megaco/src/binary/megaco_per_bin_drv_media_gateway_control_v1.hrl +/megaco/src/binary/megaco_per_bin_drv_media_gateway_control_v2.erl +/megaco/src/binary/megaco_per_bin_drv_media_gateway_control_v2.hrl +/megaco/src/binary/megaco_per_bin_drv_media_gateway_control_v3.erl +/megaco/src/binary/megaco_per_bin_drv_media_gateway_control_v3.hrl +/megaco/src/binary/megaco_per_bin_media_gateway_control_prev3a.erl +/megaco/src/binary/megaco_per_bin_media_gateway_control_prev3a.hrl +/megaco/src/binary/megaco_per_bin_media_gateway_control_prev3b.erl +/megaco/src/binary/megaco_per_bin_media_gateway_control_prev3b.hrl +/megaco/src/binary/megaco_per_bin_media_gateway_control_prev3c.erl +/megaco/src/binary/megaco_per_bin_media_gateway_control_prev3c.hrl +/megaco/src/binary/megaco_per_bin_media_gateway_control_v1.erl +/megaco/src/binary/megaco_per_bin_media_gateway_control_v1.hrl +/megaco/src/binary/megaco_per_bin_media_gateway_control_v2.erl +/megaco/src/binary/megaco_per_bin_media_gateway_control_v2.hrl +/megaco/src/binary/megaco_per_bin_media_gateway_control_v3.erl +/megaco/src/binary/megaco_per_bin_media_gateway_control_v3.hrl +/megaco/src/binary/megaco_per_media_gateway_control_prev3a.erl +/megaco/src/binary/megaco_per_media_gateway_control_prev3a.hrl +/megaco/src/binary/megaco_per_media_gateway_control_prev3b.erl +/megaco/src/binary/megaco_per_media_gateway_control_prev3b.hrl +/megaco/src/binary/megaco_per_media_gateway_control_prev3c.erl +/megaco/src/binary/megaco_per_media_gateway_control_prev3c.hrl +/megaco/src/binary/megaco_per_media_gateway_control_v1.erl +/megaco/src/binary/megaco_per_media_gateway_control_v1.hrl +/megaco/src/binary/megaco_per_media_gateway_control_v2.erl +/megaco/src/binary/megaco_per_media_gateway_control_v2.hrl +/megaco/src/binary/megaco_per_media_gateway_control_v3.erl +/megaco/src/binary/megaco_per_media_gateway_control_v3.hrl +/megaco/src/binary/prebuild.skip +/megaco/src/flex/megaco_flex_scanner_drv.c +/megaco/src/flex/megaco_flex_scanner_drv.flex +/megaco/src/flex/megaco_flex_scanner_drv_mt.c +/megaco/src/flex/megaco_flex_scanner_drv_mt.flex +/megaco/src/text/megaco_text_mini_parser.erl +/megaco/src/text/megaco_text_parser_prev3a.erl +/megaco/src/text/megaco_text_parser_prev3b.erl +/megaco/src/text/megaco_text_parser_prev3c.erl +/megaco/src/text/megaco_text_parser_v1.erl +/megaco/src/text/megaco_text_parser_v2.erl +/megaco/src/text/megaco_text_parser_v3.erl + +# orber & cos* applications + +/cosEvent/include/CosEventChannelAdmin.hrl +/cosEvent/include/CosEventChannelAdmin_ConsumerAdmin.hrl +/cosEvent/include/CosEventChannelAdmin_EventChannel.hrl +/cosEvent/include/CosEventChannelAdmin_ProxyPullConsumer.hrl +/cosEvent/include/CosEventChannelAdmin_ProxyPullSupplier.hrl +/cosEvent/include/CosEventChannelAdmin_ProxyPushConsumer.hrl +/cosEvent/include/CosEventChannelAdmin_ProxyPushSupplier.hrl +/cosEvent/include/CosEventChannelAdmin_SupplierAdmin.hrl +/cosEvent/include/CosEventComm.hrl +/cosEvent/include/CosEventComm_PullConsumer.hrl +/cosEvent/include/CosEventComm_PullSupplier.hrl +/cosEvent/include/CosEventComm_PushConsumer.hrl +/cosEvent/include/CosEventComm_PushSupplier.hrl +/cosEvent/include/oe_CosEventChannelAdmin.hrl +/cosEvent/include/oe_CosEventComm.hrl +/cosEvent/src/CosEventChannelAdmin_AlreadyConnected.erl +/cosEvent/src/CosEventChannelAdmin_ConsumerAdmin.erl +/cosEvent/src/CosEventChannelAdmin_EventChannel.erl +/cosEvent/src/CosEventChannelAdmin_ProxyPullConsumer.erl +/cosEvent/src/CosEventChannelAdmin_ProxyPullSupplier.erl +/cosEvent/src/CosEventChannelAdmin_ProxyPushConsumer.erl +/cosEvent/src/CosEventChannelAdmin_ProxyPushSupplier.erl +/cosEvent/src/CosEventChannelAdmin_SupplierAdmin.erl +/cosEvent/src/CosEventChannelAdmin_TypeError.erl +/cosEvent/src/CosEventComm_Disconnected.erl +/cosEvent/src/CosEventComm_PullConsumer.erl +/cosEvent/src/CosEventComm_PullSupplier.erl +/cosEvent/src/CosEventComm_PushConsumer.erl +/cosEvent/src/CosEventComm_PushSupplier.erl +/cosEvent/src/oe_CosEventChannelAdmin.erl +/cosEvent/src/oe_CosEventComm.erl +/cosEvent/src/oe_CosEventComm_CAdmin.erl +/cosEvent/src/oe_CosEventComm_CAdmin.hrl +/cosEvent/src/oe_CosEventComm_Channel.erl +/cosEvent/src/oe_CosEventComm_Channel.hrl +/cosEvent/src/oe_CosEventComm_Event.erl +/cosEvent/src/oe_CosEventComm_Event.hrl +/cosEvent/src/oe_CosEventComm_PullerS.erl +/cosEvent/src/oe_CosEventComm_PullerS.hrl +/cosEvent/src/oe_CosEventComm_PusherS.erl +/cosEvent/src/oe_CosEventComm_PusherS.hrl +/cosEvent/src/oe_cosEventApp.erl +/cosEvent/src/oe_cosEventApp.hrl +/cosEventDomain/include/CosEventDomainAdmin.hrl +/cosEventDomain/include/CosEventDomainAdmin_EventDomain.hrl +/cosEventDomain/include/CosEventDomainAdmin_EventDomainFactory.hrl +/cosEventDomain/include/oe_CosEventDomainAdmin.hrl +/cosEventDomain/src/CosEventDomainAdmin.erl +/cosEventDomain/src/CosEventDomainAdmin_AlreadyExists.erl +/cosEventDomain/src/CosEventDomainAdmin_Connection.erl +/cosEventDomain/src/CosEventDomainAdmin_ConnectionIDSeq.erl +/cosEventDomain/src/CosEventDomainAdmin_ConnectionNotFound.erl +/cosEventDomain/src/CosEventDomainAdmin_CycleCreationForbidden.erl +/cosEventDomain/src/CosEventDomainAdmin_CycleSeq.erl +/cosEventDomain/src/CosEventDomainAdmin_DiamondCreationForbidden.erl +/cosEventDomain/src/CosEventDomainAdmin_DiamondSeq.erl +/cosEventDomain/src/CosEventDomainAdmin_DomainIDSeq.erl +/cosEventDomain/src/CosEventDomainAdmin_DomainNotFound.erl +/cosEventDomain/src/CosEventDomainAdmin_EventDomain.erl +/cosEventDomain/src/CosEventDomainAdmin_EventDomainFactory.erl +/cosEventDomain/src/CosEventDomainAdmin_MemberIDSeq.erl +/cosEventDomain/src/CosEventDomainAdmin_RouteSeq.erl +/cosEventDomain/src/oe_CosEventDomainAdmin.erl +/cosFileTransfer/include/CosFileTransfer.hrl +/cosFileTransfer/include/CosFileTransfer_Directory.hrl +/cosFileTransfer/include/CosFileTransfer_File.hrl +/cosFileTransfer/include/CosFileTransfer_FileIterator.hrl +/cosFileTransfer/include/CosFileTransfer_FileTransferSession.hrl +/cosFileTransfer/include/CosFileTransfer_VirtualFileSystem.hrl +/cosFileTransfer/include/oe_CosFileTransfer.hrl +/cosFileTransfer/src/CosFileTransfer.erl +/cosFileTransfer/src/CosFileTransfer_AccessLevel.erl +/cosFileTransfer/src/CosFileTransfer_CommandNotImplementedException.erl +/cosFileTransfer/src/CosFileTransfer_Directory.erl +/cosFileTransfer/src/CosFileTransfer_File.erl +/cosFileTransfer/src/CosFileTransfer_FileIterator.erl +/cosFileTransfer/src/CosFileTransfer_FileList.erl +/cosFileTransfer/src/CosFileTransfer_FileNameList.erl +/cosFileTransfer/src/CosFileTransfer_FileNotFoundException.erl +/cosFileTransfer/src/CosFileTransfer_FileTransferSession.erl +/cosFileTransfer/src/CosFileTransfer_FileWrapper.erl +/cosFileTransfer/src/CosFileTransfer_IllegalOperationException.erl +/cosFileTransfer/src/CosFileTransfer_ProtocolAddressList.erl +/cosFileTransfer/src/CosFileTransfer_ProtocolSupport.erl +/cosFileTransfer/src/CosFileTransfer_RequestFailureException.erl +/cosFileTransfer/src/CosFileTransfer_SessionException.erl +/cosFileTransfer/src/CosFileTransfer_SupportedProtocolAddresses.erl +/cosFileTransfer/src/CosFileTransfer_TransferException.erl +/cosFileTransfer/src/CosFileTransfer_VirtualFileSystem.erl +/cosFileTransfer/src/CosFileTransfer_VirtualFileSystem_ContentList.erl +/cosFileTransfer/src/oe_CosFileTransfer.erl +/cosNotification/include/CosNotification.hrl +/cosNotification/include/CosNotification_AdminPropertiesAdmin.hrl +/cosNotification/include/CosNotification_QoSAdmin.hrl +/cosNotification/include/CosNotifyChannelAdmin.hrl +/cosNotification/include/CosNotifyChannelAdmin_ConsumerAdmin.hrl +/cosNotification/include/CosNotifyChannelAdmin_EventChannel.hrl +/cosNotification/include/CosNotifyChannelAdmin_EventChannelFactory.hrl +/cosNotification/include/CosNotifyChannelAdmin_ProxyConsumer.hrl +/cosNotification/include/CosNotifyChannelAdmin_ProxyPullConsumer.hrl +/cosNotification/include/CosNotifyChannelAdmin_ProxyPullSupplier.hrl +/cosNotification/include/CosNotifyChannelAdmin_ProxyPushConsumer.hrl +/cosNotification/include/CosNotifyChannelAdmin_ProxyPushSupplier.hrl +/cosNotification/include/CosNotifyChannelAdmin_ProxySupplier.hrl +/cosNotification/include/CosNotifyChannelAdmin_SequenceProxyPullConsumer.hrl +/cosNotification/include/CosNotifyChannelAdmin_SequenceProxyPullSupplier.hrl +/cosNotification/include/CosNotifyChannelAdmin_SequenceProxyPushConsumer.hrl +/cosNotification/include/CosNotifyChannelAdmin_SequenceProxyPushSupplier.hrl +/cosNotification/include/CosNotifyChannelAdmin_StructuredProxyPullConsumer.hrl +/cosNotification/include/CosNotifyChannelAdmin_StructuredProxyPullSupplier.hrl +/cosNotification/include/CosNotifyChannelAdmin_StructuredProxyPushConsumer.hrl +/cosNotification/include/CosNotifyChannelAdmin_StructuredProxyPushSupplier.hrl +/cosNotification/include/CosNotifyChannelAdmin_SupplierAdmin.hrl +/cosNotification/include/CosNotifyComm.hrl +/cosNotification/include/CosNotifyComm_NotifyPublish.hrl +/cosNotification/include/CosNotifyComm_NotifySubscribe.hrl +/cosNotification/include/CosNotifyComm_PullConsumer.hrl +/cosNotification/include/CosNotifyComm_PullSupplier.hrl +/cosNotification/include/CosNotifyComm_PushConsumer.hrl +/cosNotification/include/CosNotifyComm_PushSupplier.hrl +/cosNotification/include/CosNotifyComm_SequencePullConsumer.hrl +/cosNotification/include/CosNotifyComm_SequencePullSupplier.hrl +/cosNotification/include/CosNotifyComm_SequencePushConsumer.hrl +/cosNotification/include/CosNotifyComm_SequencePushSupplier.hrl +/cosNotification/include/CosNotifyComm_StructuredPullConsumer.hrl +/cosNotification/include/CosNotifyComm_StructuredPullSupplier.hrl +/cosNotification/include/CosNotifyComm_StructuredPushConsumer.hrl +/cosNotification/include/CosNotifyComm_StructuredPushSupplier.hrl +/cosNotification/include/CosNotifyFilter.hrl +/cosNotification/include/CosNotifyFilter_Filter.hrl +/cosNotification/include/CosNotifyFilter_FilterAdmin.hrl +/cosNotification/include/CosNotifyFilter_FilterFactory.hrl +/cosNotification/include/CosNotifyFilter_MappingFilter.hrl +/cosNotification/include/oe_CosNotification.hrl +/cosNotification/include/oe_CosNotifyChannelAdmin.hrl +/cosNotification/include/oe_CosNotifyComm.hrl +/cosNotification/include/oe_CosNotifyFilter.hrl +/cosNotification/src/CosNotification.erl +/cosNotification/src/CosNotification_AdminPropertiesAdmin.erl +/cosNotification/src/CosNotification_EventBatch.erl +/cosNotification/src/CosNotification_EventHeader.erl +/cosNotification/src/CosNotification_EventType.erl +/cosNotification/src/CosNotification_EventTypeSeq.erl +/cosNotification/src/CosNotification_FixedEventHeader.erl +/cosNotification/src/CosNotification_NamedPropertyRange.erl +/cosNotification/src/CosNotification_NamedPropertyRangeSeq.erl +/cosNotification/src/CosNotification_Property.erl +/cosNotification/src/CosNotification_PropertyError.erl +/cosNotification/src/CosNotification_PropertyErrorSeq.erl +/cosNotification/src/CosNotification_PropertyRange.erl +/cosNotification/src/CosNotification_PropertySeq.erl +/cosNotification/src/CosNotification_QoSAdmin.erl +/cosNotification/src/CosNotification_StructuredEvent.erl +/cosNotification/src/CosNotification_UnsupportedAdmin.erl +/cosNotification/src/CosNotification_UnsupportedQoS.erl +/cosNotification/src/CosNotifyChannelAdmin_AdminIDSeq.erl +/cosNotification/src/CosNotifyChannelAdmin_AdminLimit.erl +/cosNotification/src/CosNotifyChannelAdmin_AdminLimitExceeded.erl +/cosNotification/src/CosNotifyChannelAdmin_AdminNotFound.erl +/cosNotification/src/CosNotifyChannelAdmin_ChannelIDSeq.erl +/cosNotification/src/CosNotifyChannelAdmin_ChannelNotFound.erl +/cosNotification/src/CosNotifyChannelAdmin_ConnectionAlreadyActive.erl +/cosNotification/src/CosNotifyChannelAdmin_ConnectionAlreadyInactive.erl +/cosNotification/src/CosNotifyChannelAdmin_ConsumerAdmin.erl +/cosNotification/src/CosNotifyChannelAdmin_EventChannel.erl +/cosNotification/src/CosNotifyChannelAdmin_EventChannelFactory.erl +/cosNotification/src/CosNotifyChannelAdmin_NotConnected.erl +/cosNotification/src/CosNotifyChannelAdmin_ProxyConsumer.erl +/cosNotification/src/CosNotifyChannelAdmin_ProxyIDSeq.erl +/cosNotification/src/CosNotifyChannelAdmin_ProxyNotFound.erl +/cosNotification/src/CosNotifyChannelAdmin_ProxyPullConsumer.erl +/cosNotification/src/CosNotifyChannelAdmin_ProxyPullSupplier.erl +/cosNotification/src/CosNotifyChannelAdmin_ProxyPushConsumer.erl +/cosNotification/src/CosNotifyChannelAdmin_ProxyPushSupplier.erl +/cosNotification/src/CosNotifyChannelAdmin_ProxySupplier.erl +/cosNotification/src/CosNotifyChannelAdmin_SequenceProxyPullConsumer.erl +/cosNotification/src/CosNotifyChannelAdmin_SequenceProxyPullSupplier.erl +/cosNotification/src/CosNotifyChannelAdmin_SequenceProxyPushConsumer.erl +/cosNotification/src/CosNotifyChannelAdmin_SequenceProxyPushSupplier.erl +/cosNotification/src/CosNotifyChannelAdmin_StructuredProxyPullConsumer.erl +/cosNotification/src/CosNotifyChannelAdmin_StructuredProxyPullSupplier.erl +/cosNotification/src/CosNotifyChannelAdmin_StructuredProxyPushConsumer.erl +/cosNotification/src/CosNotifyChannelAdmin_StructuredProxyPushSupplier.erl +/cosNotification/src/CosNotifyChannelAdmin_SupplierAdmin.erl +/cosNotification/src/CosNotifyComm_InvalidEventType.erl +/cosNotification/src/CosNotifyComm_NotifyPublish.erl +/cosNotification/src/CosNotifyComm_NotifySubscribe.erl +/cosNotification/src/CosNotifyComm_PullConsumer.erl +/cosNotification/src/CosNotifyComm_PullSupplier.erl +/cosNotification/src/CosNotifyComm_PushConsumer.erl +/cosNotification/src/CosNotifyComm_PushSupplier.erl +/cosNotification/src/CosNotifyComm_SequencePullConsumer.erl +/cosNotification/src/CosNotifyComm_SequencePullSupplier.erl +/cosNotification/src/CosNotifyComm_SequencePushConsumer.erl +/cosNotification/src/CosNotifyComm_SequencePushSupplier.erl +/cosNotification/src/CosNotifyComm_StructuredPullConsumer.erl +/cosNotification/src/CosNotifyComm_StructuredPullSupplier.erl +/cosNotification/src/CosNotifyComm_StructuredPushConsumer.erl +/cosNotification/src/CosNotifyComm_StructuredPushSupplier.erl +/cosNotification/src/CosNotifyFilter_CallbackIDSeq.erl +/cosNotification/src/CosNotifyFilter_CallbackNotFound.erl +/cosNotification/src/CosNotifyFilter_ConstraintExp.erl +/cosNotification/src/CosNotifyFilter_ConstraintExpSeq.erl +/cosNotification/src/CosNotifyFilter_ConstraintIDSeq.erl +/cosNotification/src/CosNotifyFilter_ConstraintInfo.erl +/cosNotification/src/CosNotifyFilter_ConstraintInfoSeq.erl +/cosNotification/src/CosNotifyFilter_ConstraintNotFound.erl +/cosNotification/src/CosNotifyFilter_DuplicateConstraintID.erl +/cosNotification/src/CosNotifyFilter_Filter.erl +/cosNotification/src/CosNotifyFilter_FilterAdmin.erl +/cosNotification/src/CosNotifyFilter_FilterFactory.erl +/cosNotification/src/CosNotifyFilter_FilterIDSeq.erl +/cosNotification/src/CosNotifyFilter_FilterNotFound.erl +/cosNotification/src/CosNotifyFilter_InvalidConstraint.erl +/cosNotification/src/CosNotifyFilter_InvalidGrammar.erl +/cosNotification/src/CosNotifyFilter_InvalidValue.erl +/cosNotification/src/CosNotifyFilter_MappingConstraintInfo.erl +/cosNotification/src/CosNotifyFilter_MappingConstraintInfoSeq.erl +/cosNotification/src/CosNotifyFilter_MappingConstraintPair.erl +/cosNotification/src/CosNotifyFilter_MappingConstraintPairSeq.erl +/cosNotification/src/CosNotifyFilter_MappingFilter.erl +/cosNotification/src/CosNotifyFilter_UnsupportedFilterableData.erl +/cosNotification/src/cosNotification_Grammar.erl +/cosNotification/src/oe_CosNotification.erl +/cosNotification/src/oe_CosNotificationComm.hrl +/cosNotification/src/oe_CosNotificationComm_Event.erl +/cosNotification/src/oe_CosNotificationComm_Event.hrl +/cosNotification/src/oe_CosNotifyChannelAdmin.erl +/cosNotification/src/oe_CosNotifyComm.erl +/cosNotification/src/oe_CosNotifyFilter.erl +/cosNotification/src/oe_cosNotificationAppComm.erl +/cosNotification/src/oe_cosNotificationAppComm.hrl +/cosProperty/include/CosPropertyService.hrl +/cosProperty/include/CosPropertyService_PropertiesIterator.hrl +/cosProperty/include/CosPropertyService_PropertyNamesIterator.hrl +/cosProperty/include/CosPropertyService_PropertySet.hrl +/cosProperty/include/CosPropertyService_PropertySetDef.hrl +/cosProperty/include/CosPropertyService_PropertySetDefFactory.hrl +/cosProperty/include/CosPropertyService_PropertySetFactory.hrl +/cosProperty/include/oe_CosProperty.hrl +/cosProperty/src/CosPropertyService_ConflictingProperty.erl +/cosProperty/src/CosPropertyService_ConstraintNotSupported.erl +/cosProperty/src/CosPropertyService_FixedProperty.erl +/cosProperty/src/CosPropertyService_InvalidPropertyName.erl +/cosProperty/src/CosPropertyService_MultipleExceptions.erl +/cosProperty/src/CosPropertyService_Properties.erl +/cosProperty/src/CosPropertyService_PropertiesIterator.erl +/cosProperty/src/CosPropertyService_Property.erl +/cosProperty/src/CosPropertyService_PropertyDef.erl +/cosProperty/src/CosPropertyService_PropertyDefs.erl +/cosProperty/src/CosPropertyService_PropertyException.erl +/cosProperty/src/CosPropertyService_PropertyExceptions.erl +/cosProperty/src/CosPropertyService_PropertyMode.erl +/cosProperty/src/CosPropertyService_PropertyModes.erl +/cosProperty/src/CosPropertyService_PropertyNames.erl +/cosProperty/src/CosPropertyService_PropertyNamesIterator.erl +/cosProperty/src/CosPropertyService_PropertyNotFound.erl +/cosProperty/src/CosPropertyService_PropertySet.erl +/cosProperty/src/CosPropertyService_PropertySetDef.erl +/cosProperty/src/CosPropertyService_PropertySetDefFactory.erl +/cosProperty/src/CosPropertyService_PropertySetFactory.erl +/cosProperty/src/CosPropertyService_PropertyTypes.erl +/cosProperty/src/CosPropertyService_ReadOnlyProperty.erl +/cosProperty/src/CosPropertyService_UnsupportedMode.erl +/cosProperty/src/CosPropertyService_UnsupportedProperty.erl +/cosProperty/src/CosPropertyService_UnsupportedTypeCode.erl +/cosProperty/src/oe_CosProperty.erl +/cosTime/include/CosTime.hrl +/cosTime/include/CosTime_TIO.hrl +/cosTime/include/CosTime_TimeService.hrl +/cosTime/include/CosTime_UTO.hrl +/cosTime/include/CosTimerEvent.hrl +/cosTime/include/CosTimerEvent_TimerEventHandler.hrl +/cosTime/include/CosTimerEvent_TimerEventService.hrl +/cosTime/include/TimeBase.hrl +/cosTime/include/oe_CosTime.hrl +/cosTime/include/oe_CosTimerEvent.hrl +/cosTime/include/oe_TimeBase.hrl +/cosTime/src/CosTime_TIO.erl +/cosTime/src/CosTime_TimeService.erl +/cosTime/src/CosTime_TimeUnavailable.erl +/cosTime/src/CosTime_UTO.erl +/cosTime/src/CosTimerEvent_TimerEventHandler.erl +/cosTime/src/CosTimerEvent_TimerEventService.erl +/cosTime/src/CosTimerEvent_TimerEventT.erl +/cosTime/src/TimeBase_IntervalT.erl +/cosTime/src/TimeBase_UtcT.erl +/cosTime/src/oe_CosTime.erl +/cosTime/src/oe_CosTimerEvent.erl +/cosTime/src/oe_TimeBase.erl +/cosTransactions/include/CosTransactions.hrl +/cosTransactions/include/CosTransactions_Control.hrl +/cosTransactions/include/CosTransactions_Coordinator.hrl +/cosTransactions/include/CosTransactions_RecoveryCoordinator.hrl +/cosTransactions/include/CosTransactions_Resource.hrl +/cosTransactions/include/CosTransactions_SubtransactionAwareResource.hrl +/cosTransactions/include/CosTransactions_Terminator.hrl +/cosTransactions/include/CosTransactions_TransactionFactory.hrl +/cosTransactions/include/ETraP.hrl +/cosTransactions/include/ETraP_Server.hrl +/cosTransactions/include/oe_CosTransactions.hrl +/cosTransactions/src/CosTransactions_Control.erl +/cosTransactions/src/CosTransactions_Coordinator.erl +/cosTransactions/src/CosTransactions_HeuristicCommit.erl +/cosTransactions/src/CosTransactions_HeuristicHazard.erl +/cosTransactions/src/CosTransactions_HeuristicMixed.erl +/cosTransactions/src/CosTransactions_HeuristicRollback.erl +/cosTransactions/src/CosTransactions_Inactive.erl +/cosTransactions/src/CosTransactions_InvalidControl.erl +/cosTransactions/src/CosTransactions_NoTransaction.erl +/cosTransactions/src/CosTransactions_NotPrepared.erl +/cosTransactions/src/CosTransactions_NotSubtransaction.erl +/cosTransactions/src/CosTransactions_PropagationContext.erl +/cosTransactions/src/CosTransactions_RecoveryCoordinator.erl +/cosTransactions/src/CosTransactions_Resource.erl +/cosTransactions/src/CosTransactions_SubtransactionAwareResource.erl +/cosTransactions/src/CosTransactions_SubtransactionsUnavailable.erl +/cosTransactions/src/CosTransactions_SynchronizationUnavailable.erl +/cosTransactions/src/CosTransactions_Terminator.erl +/cosTransactions/src/CosTransactions_TransIdentity.erl +/cosTransactions/src/CosTransactions_TransactionFactory.erl +/cosTransactions/src/CosTransactions_Unavailable.erl +/cosTransactions/src/CosTransactions_WrongTransaction.erl +/cosTransactions/src/CosTransactions_otid_t.erl +/cosTransactions/src/ETraP_Server.erl +/cosTransactions/src/oe_CosTransactions.erl +/orber/COSS/CosNaming/CosNaming.hrl +/orber/COSS/CosNaming/CosNaming_Binding.erl +/orber/COSS/CosNaming/CosNaming_BindingIterator.erl +/orber/COSS/CosNaming/CosNaming_BindingIterator.hrl +/orber/COSS/CosNaming/CosNaming_BindingList.erl +/orber/COSS/CosNaming/CosNaming_Name.erl +/orber/COSS/CosNaming/CosNaming_NameComponent.erl +/orber/COSS/CosNaming/CosNaming_NamingContext.erl +/orber/COSS/CosNaming/CosNaming_NamingContext.hrl +/orber/COSS/CosNaming/CosNaming_NamingContextExt.erl +/orber/COSS/CosNaming/CosNaming_NamingContextExt.hrl +/orber/COSS/CosNaming/CosNaming_NamingContextExt_AlreadyBound.erl +/orber/COSS/CosNaming/CosNaming_NamingContextExt_CannotProceed.erl +/orber/COSS/CosNaming/CosNaming_NamingContextExt_InvalidAddress.erl +/orber/COSS/CosNaming/CosNaming_NamingContextExt_InvalidName.erl +/orber/COSS/CosNaming/CosNaming_NamingContextExt_NotEmpty.erl +/orber/COSS/CosNaming/CosNaming_NamingContextExt_NotFound.erl +/orber/COSS/CosNaming/CosNaming_NamingContext_AlreadyBound.erl +/orber/COSS/CosNaming/CosNaming_NamingContext_CannotProceed.erl +/orber/COSS/CosNaming/CosNaming_NamingContext_InvalidName.erl +/orber/COSS/CosNaming/CosNaming_NamingContext_NotEmpty.erl +/orber/COSS/CosNaming/CosNaming_NamingContext_NotFound.erl +/orber/COSS/CosNaming/oe_cos_naming.erl +/orber/COSS/CosNaming/oe_cos_naming.hrl +/orber/COSS/CosNaming/oe_cos_naming_ext.erl +/orber/COSS/CosNaming/oe_cos_naming_ext.hrl +/orber/examples/Stack/StackModule.hrl +/orber/examples/Stack/StackModule_EmptyStack.erl +/orber/examples/Stack/StackModule_Stack.erl +/orber/examples/Stack/StackModule_Stack.hrl +/orber/examples/Stack/StackModule_StackFactory.erl +/orber/examples/Stack/StackModule_StackFactory.hrl +/orber/examples/Stack/oe_stack.erl +/orber/examples/Stack/oe_stack.hrl +/orber/src/CORBA.hrl +/orber/src/OrberApp.hrl +/orber/src/OrberApp_IFR.erl +/orber/src/OrberApp_IFR.hrl +/orber/src/erlang.hrl +/orber/src/erlang_binary.erl +/orber/src/erlang_pid.erl +/orber/src/erlang_port.erl +/orber/src/erlang_ref.erl +/orber/src/oe_CORBA.erl +/orber/src/oe_CORBA.hrl +/orber/src/oe_OrberIFR.erl +/orber/src/oe_OrberIFR.hrl +/orber/src/oe_erlang.erl +/orber/src/oe_erlang.hrl diff --git a/lib/asn1/doc/src/Makefile b/lib/asn1/doc/src/Makefile index be8755f0ff..d29225f6c9 100644 --- a/lib/asn1/doc/src/Makefile +++ b/lib/asn1/doc/src/Makefile @@ -51,9 +51,7 @@ XML_REF3_FILES = asn1ct.xml \ GEN_XML = \ asn1_spec.xml -XML_PART_FILES = \ - part.xml \ - part_notes.xml +XML_PART_FILES = part.xml XML_HTML_FILE = \ notes_history.xml diff --git a/lib/asn1/doc/src/note.gif b/lib/asn1/doc/src/note.gif Binary files differdeleted file mode 100644 index 6fffe30419..0000000000 --- a/lib/asn1/doc/src/note.gif +++ /dev/null diff --git a/lib/asn1/doc/src/notes_history.xml b/lib/asn1/doc/src/notes_history.xml deleted file mode 100644 index e6c423e79e..0000000000 --- a/lib/asn1/doc/src/notes_history.xml +++ /dev/null @@ -1,1782 +0,0 @@ -<?xml version="1.0" encoding="latin1" ?> -<!DOCTYPE chapter SYSTEM "chapter.dtd"> - -<chapter> - <header> - <copyright> - <year>2006</year><year>2009</year> - <holder>Ericsson AB. All Rights Reserved.</holder> - </copyright> - <legalnotice> - The contents of this file are subject to the Erlang Public License, - Version 1.1, (the "License"); you may not use this file except in - compliance with the License. You should have received a copy of the - Erlang Public License along with this software. If not, it can be - retrieved online at http://www.erlang.org/. - - Software distributed under the License is distributed on an "AS IS" - basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - the License for the specific language governing rights and limitations - under the License. - - </legalnotice> - - <title>ASN1 Release Notes</title> - <prepared>Bertil Karlsson</prepared> - <responsible></responsible> - <docno></docno> - <approved></approved> - <checked></checked> - <date>06-04-24</date> - <rev></rev> - <file>notes_history.sgml</file> - </header> - <p>This document describes the changes made to the asn1 system - from version to version. The intention of this document is to - list all incompatibilities as well as all enhancements and - bug-fixes for every release of the asn1 application. Each release of asn1 - thus constitutes one section in this document. The title of each - section is the version number of asn1.</p> - - - <section> - <title>Asn1 1.4.4.14</title> - - <section> - <title>Improvements and New Features</title> - <list type="bulleted"> - <item> - <p>Data in info/0 in generated code is moved to attribute - asn1_info, thus vsn value remains the same if compiler - options for asn1-spec differs but the generated code is - the same.</p> - <p>Own Id: OTP-6462</p> - </item> - <item> - <p>Dialyzer warnings on asn1 are removed, i.e. dead code - removed.</p> - <p>Own Id: OTP-6506</p> - </item> - </list> - </section> - </section> - - <section> - <title>Asn1 1.4.4.13</title> - - <section> - <title>Improvements and New Features</title> - <list type="bulleted"> - <item> - <p>Now it is possible to use 'asn1config' and 'inline' - options together. It is also possible to use 'inline' on - a single file like: - <c>asn1ct:compile("MyASN1spec.asn",[inline])</c>.</p> - <p>Own Id: OTP-6405</p> - </item> - </list> - </section> - </section> - - <section> - <title>Asn1 1.4.4.12</title> - - <section> - <title>Improvements and New Features</title> - <list type="bulleted"> - <item> - <p>As a complement to the option "{inline,OutputFile}" it is - now possible to use the option "inline". Then asn1 creates - an output file with the name of the source .set file.</p> - <p>Own Id: OTP-6314</p> - </item> - </list> - </section> - </section> - - <section> - <title>Asn1 1.4.4.11</title> - - <section> - <title>Fixed Bugs and Malfunctions</title> - <list type="bulleted"> - <item> - <p>When compiling an asn1 source that reference a type in - another source the compiler uses the asn1db file of the - other source to resolve the reference. It also tests - whether the other source has been updated since the - asn1db file was generated. This last test was to brutal - in that it exits compilation when no source was found, - even though a asn1db file existed. Changed behavior from - a brutal exit to a warning.</p> - <p>Own Id: OTP-6143</p> - </item> - </list> - </section> - </section> - - <section> - <title>Asn1 1.4.4.10</title> - - <section> - <title>Fixed Bugs and Malfunctions</title> - <list type="bulleted"> - <item> - <p>asn1 encoding failed on BIT STRING with constraint - <c>(SIZE (32..MAX))</c>.</p> - <p>Own Id: OTP-5932</p> - </item> - <item> - <p>Race condition removed in server for variable names for - generated code.</p> - <p>Own Id: OTP-6111</p> - </item> - </list> - </section> - </section> - - <section> - <title>Asn1 1.4.4.9</title> - - <section> - <title>Fixed Bugs and Malfunctions</title> - <list type="bulleted"> - <item> - <p>Now exists a default function clause for table lookup of - a table constraint. This causes a nice error instead of a - crash. Did also remove some obsolete funs ({Mod,Fun}) in - generated code.</p> - <p>Own Id: OTP-5783</p> - </item> - <item> - <p>ASN1-compiler failed to derive a value out of an external - reference in some certain cases, when compiling specs so - that the spec with the reference was compiled before the - spec with the defined value.</p> - <p>Own Id: OTP-5812 Aux Id: seq10133 </p> - </item> - <item> - <p>The documentation of how records of embedded types are - named is extended and made clearer by examples and rules. - The section "Naming of Records in .hrl Files" in the - User's Guide is added.</p> - <p>Own Id: OTP-5831 Aux Id: seq10133 </p> - </item> - <item> - <p>The compiler failed to give right name to record/function - of a parameterized type that was referenced through - another instance of a parameterized type in another - module. The fault occurred when modules were compiled in a - certain order. Now the compiler resolves the name - correctly.</p> - <p>Own Id: OTP-5832 Aux Id: seq10133 </p> - </item> - </list> - </section> - </section> - - <section> - <title>Asn1 1.4.4.8</title> - - <section> - <title>Fixed Bugs and Malfunctions</title> - <list type="bulleted"> - <item> - <p>The dynamic sort of SET OF values now correctly handles - values encoded in the "ber_bin, der, optimize" mode, the - value of a SET OF is a list of binaries.</p> - <p>Own Id: OTP-5687</p> - </item> - <item> - <p>Bad code was generated for an INTEGER with value-range. If - the value that was encoded had a lower bound with - negative value it caused a crash. This bug is now - removed.</p> - <p>Own Id: OTP-5688 Aux Id: seq10049 </p> - </item> - <item> - <p>Compiler now handles wrong include paths by returning an - error if a referenced module is not available.</p> - <p>Own Id: OTP-5689</p> - </item> - <item> - <p>The bug causing a runtime error when encoding a type - defined by: <c>BIT STRING {a(1),b(2)}</c> with the value - [] in <c>per_bin</c> mode is now removed.</p> - <p>Own Id: OTP-5710 Aux Id: seq10066 </p> - </item> - </list> - </section> - - <section> - <title>Improvements and New Features</title> - <list type="bulleted"> - <item> - <p>Better handling of filename paths</p> - <p>Own Id: OTP-5701</p> - </item> - </list> - </section> - </section> - - <section> - <title>Asn1 1.4.4.7</title> - - <section> - <title>Fixed Bugs and Malfunctions</title> - <list type="bulleted"> - <item> - <p>Effective constraint for <c>per</c> now corrected. For - instance <c>INTEGER (0|15..269)</c> didn't work properly.</p> - <p>Own Id: OTP-5477 Aux Id: OTP-5511 </p> - </item> - <item> - <p>Adjusted compiler so that functions in generated code - only are exported once.</p> - <p>Own Id: OTP-5509</p> - </item> - <item> - <p>Fixed the compiler failure when handling a value range - constraint with an extension mark that had the Lower - bound and/or Upper bound values as an external reference - to a defined value.</p> - <p>Own Id: OTP-5511 Aux Id: OTP-5466 </p> - </item> - <item> - <p>Removed sorting of elements for SEQUENCE OF. It shall - only be done in SET OF.</p> - <p>Own Id: OTP-5602</p> - </item> - <item> - <p>Corrected code that generated code causing badarith - warning.</p> - <p>Own Id: OTP-5616</p> - </item> - </list> - </section> - </section> - - <section> - <title>Asn1 1.4.4.6</title> - - <section> - <title>Known Bugs and Problems</title> - <list type="bulleted"> - <item> - <p>Compiler now correctly crashes when compiling bad values. - Failed for instance on INTEGER value that was a reference - to a defined value. Also solved problem with a union - constraint on an INTEGER.</p> - <p>Own Id: OTP-5457</p> - </item> - <item> - <p>Additional coverage of object set syntax.</p> - <p>Own Id: OTP-5466</p> - </item> - </list> - </section> - </section> - - <section> - <title>Asn1 1.4.4.5</title> - - <section> - <title>Fixed Bugs and Malfunctions</title> - <list type="bulleted"> - <item> - <p>A bug due to representation of open_type values is now - fixed. It could cause problem if one used the EXTERNAL - type.</p> - <p>Own Id: OTP-5302</p> - </item> - <item> - <p>Due to an internal error the same code could have been - generated more than one time. This happened for the - exclusive decode functionality.</p> - <p>Own Id: OTP-5378</p> - </item> - </list> - </section> - </section> - - <section> - <title>Asn1 1.4.4.4</title> - - <section> - <title>Fixed Bugs and Malfunctions</title> - <list type="bulleted"> - <item> - <p>Empty objects caused problems. There was trouble when an - object set referenced imported objects that in turn - referenced imported types. Lacked support of - SelectionType in object. All these have been attended.</p> - <p>Own Id: OTP-5240</p> - </item> - </list> - </section> - - <section> - <title>Improvements and New Features</title> - <list type="bulleted"> - <item> - <p>Now it is possible to inline asn1 run-time functionality - in the module generated by the asn1 compiler. Thus, it - will be only one module doing all encoding/decoding.</p> - <p>Own Id: OTP-5243</p> - </item> - </list> - </section> - </section> - - <section> - <title>Asn1 1.4.4.3</title> - - <section> - <title>Fixed errors and malfunctions</title> - <list type="bulleted"> - <item> - <p>A class that was referenced in two steps caused a - compiler failure. It is now corrected.</p> - <p>Own Id: OTP-5103</p> - </item> - </list> - </section> - - <section> - <title>Improvements and new features</title> - <list type="bulleted"> - <item> - <p>Optionally make it possible to get the un-decoded rest along with - the return value. Compile with option <em>undec_rest</em>.</p> - <p>Own Id: OTP-5104</p> - </item> - </list> - </section> - </section> - - <section> - <title>Asn1 1.4.4.2</title> - - <section> - <title>Fixed errors and malfunctions</title> - <list type="bulleted"> - <item> - <p>An error due to unchecked referenced imported type resulted - in missing tag in some table constraint cases. This error is - now corrected. Error occurred during decode in - <c>ber_bin optimized</c> version.</p> - <p>Own Id: OTP-5022</p> - </item> - </list> - </section> - </section> - - <section> - <title>Asn1 1.4.4.1</title> - - <section> - <title>Fixed errors and malfunctions</title> - <list type="bulleted"> - <item> - <p>When a referenced value in another module in turn referenced a - defined value the compilation crashed. This is due to the new - routines for compilation, that external references are resolved - during compilation, and not by the order in which modules are - compiled. This error is now corrected.</p> - <p>Own Id: OTP-4970</p> - </item> - </list> - </section> - </section> - - <section> - <title>Asn1 1.4.4</title> - - <section> - <title>Fixed errors and malfunctions</title> - <list type="bulleted"> - <item> - <p>Functionality for parameterized class is added. Parsing failures on - WithSyntax spec is corrected.</p> - <p>Own Id: OTP-4893</p> - </item> - <item> - <p>The failure due to Parameterized Type when parameter is an object - set is corrected.</p> - <p>Own Id: OTP-4894</p> - <p>Aux Id: OTP-4893</p> - </item> - <item> - <p>Object Identifier values with two components and the first was a - value reference failed due to parsing conflicts. Now it is - corrected.</p> - <p>Own Id: OTP-4895</p> - </item> - <item> - <p>The erroneous comparison of file name and asn1 module name could - cause compilation failure. The situation for this failure is rare, - it requires that other processes modifies the compiled file during - the compilation procedure. It is now fixed.</p> - <p>Own Id: OTP-4944</p> - <p>Aux Id: seq8429</p> - </item> - <item> - <p>Selective decode was ignored when exclusive decode spec in asn1 - configfile was missing. Selective decode failed when the selected - type was the top type. These bugs are now removed.</p> - <p>Own Id: OTP-4953</p> - <p>Aux Id: seq8436</p> - </item> - <item> - <p>The test interface asn1ct:test/1,2,3 and asn1ct:value/2 failed for - open type and EXTERNAL. The bug is now removed.</p> - <p>Own Id: OTP-4955</p> - <p>Aux Id: seq8438)</p> - </item> - <item> - <p>Two equal functions were generated for two components referencing - the same type when they were picked by the action "parts". The bug - is now fixed.</p> - <p>Own Id: OTP-4957</p> - <p>Aux Id: seq8434</p> - </item> - </list> - </section> - - <section> - <title>Improvements and new features</title> - <list type="bulleted"> - <item> - <p>INTEGER with named number list and ENUMERATED can now be sub - constrained with names from the names list.</p> - <p>Own Id: OTP-4917</p> - </item> - <item> - <p>Now there is support for SelectionType (X 680 section 29)</p> - <p>Own Id: OTP-4918</p> - </item> - <item> - <p>The compiler now resolves circular dependencies. When asn1 specs - IMPORTS from each other so that there are circular dependencies.</p> - <p>Own Id: OTP-4919</p> - </item> - <item> - <p>Now is the asn1 type UTF8String supported. For user instructions - see documentation.</p> - <p>Own Id: OTP-4965</p> - </item> - </list> - </section> - </section> - - <section> - <title>Asn1 1.4.3.1</title> - - <section> - <title>Fixed Bugs and Malfunctions</title> - <list type="bulleted"> - <item> - <p>The <c>{internal_error,...,{ unrecognized_type,...}}</c> - error occurring for a SET type when compiling with options - <c>[ber_bin,optimize,der]</c> is now corrected.</p> - <p>Own Id: OTP-4866</p> - </item> - <item> - <p>False encode of BIT STRING in PER (per_bin,optimize) is fixed. The error occurred when there was a type like BIT STRING (SIZE(C)) and C > 16.</p> - <p>Own Id: OTP-4869</p> - </item> - </list> - </section> - </section> - - <section> - <title>Asn1 1.4.3</title> - - <section> - <title>Fixed errors and malfunctions</title> - <list type="bulleted"> - <item> - <p>Functionality to handle parameterized object sets have been added.</p> - <p>Own Id: OTP-4832</p> - </item> - <item> - <p>Bug causing duplicated function definitions using exclusive decode is removed.</p> - <p>Own Id: OTP-4833)</p> - </item> - <item> - <p>The race condition when loading asn1 driver is solved.</p> - <p>Own Id: OTP-4835</p> - </item> - </list> - </section> - - <section> - <title>Improvements and new features</title> - <list type="bulleted"> - <item> - <p>A specialized decode, <em>selective decode</em> is now available. It decodes a chosen internal sub-type of a constructed type.</p> - <p>Own Id: OTP-4856)</p> - </item> - </list> - </section> - </section> - - <section> - <title>Asn1 1.4.2.2</title> - - <section> - <title>Fixed errors and malfunctions</title> - <list type="bulleted"> - <item> - <p>Release of Asn1 1.4.2.1 on R7B, The functionality is the same, but - the layer between the driver and the asn1 erlang code is different.</p> - </item> - </list> - </section> - </section> - - <section> - <title>Asn1 1.4.2.1</title> - - <section> - <title>Fixed errors and malfunctions</title> - <list type="bulleted"> - <item> - <p>ObjectDescriptor does now work as part of a sequence, set or choice.</p> - <p>Own Id: OTP-4773</p> - </item> - <item> - <p>When a SEQUENCE that have extension mark was decoded inside a - SEQUENCE OF it could cause decode error due to a failure in - restbytes2. It is now corrected.</p> - <p>Own Id: OTP-4791)</p> - </item> - <item> - <p>Now the bug is fixed that caused the compiler crash on an untagged - optional open type.</p> - <p>Own Id: OTP-4792</p> - </item> - <item> - <p>The earlier exit caused by bad in-data is now fixed so it will - return an {error,Reason} tuple.</p> - return an {error,Reason} tuple.</p> - <p>Own Id: OTP-4797</p> - </item> - <item> - <p>Open type encoded with indefinite length is now correct decoded.</p> - <p>Own Id: OTP-4798</p> - </item> - <item> - <p>Now is absent optional open types handled correctly.</p> - <p>Own Id: OTP-4799</p> - </item> - <item> - <p>Now is the necessary functions available for sorting in run-time of - SET and SET OF components.</p> - <p>Own Id: OTP-4809</p> - </item> - </list> - </section> - </section> - - <section> - <title>Asn1 1.4.2</title> - - <section> - <title>Fixed errors and malfunctions</title> - <list type="bulleted"> - <item> - <p>When a component in a SEQUENCE is a CHOICE (or reference to a CHOICE) - and the SEQUENCE's component and one of the alternatives in the CHOICE - have identical names, an error may occur if one doesn't use the - 'optimized' versions of the compiler. In the older versions (<c>ber, ber_bin, per, per_bin</c>) one could optionally apply a value of a - component as <c>{ComponentName,Value}</c>, and the generated code - chooses the second element of the tuple. However, a value of a CHOICE - must be applied as a tuple: <c>{AlternativeName,Value}</c>. Thus, - in the rare case described above and if the value to the SEQUENCE's - component is not in a tuple notation the - <c>{AlternativeName,Value}</c> will be peeled off in the SEQUENCE - and the value fed to the CHOICE will only be the <c>Value</c> - part of <c>{AlternativeName,Value}</c>, and the encoder crashes. - The best way to avoid this is to use the optimized version of the - compiler where the unnecessary tuple notation - <c>{ComponentName,Value}</c> no longer is allowed. Since it isn't - possible to solve this bug in the compiler.</p> - <p>Own Id: OTP-4693</p> - </item> - </list> - </section> - - <section> - <title>Improvements and new features</title> - <list type="bulleted"> - <item> - <p>Exclusive decode is enabled by a compiler option and a configuration - file. It makes it possible to leave parts of an ASN.1 encoded message - un-decoded.</p> - <p>Own Id: OTP-4744</p> - </item> - </list> - </section> - </section> - - <section> - <title>Asn1 1.4.1.1</title> - - <section> - <title>Fixed errors and malfunctions</title> - <list type="bulleted"> - <item> - <p>The documentation about how extensibility is handled is now corrected.</p> - <p>Own Id: OTP-4663</p> - </item> - <item> - <p>Function in object now calls the exported function</p> - <p>Own Id: OTP-4665</p> - </item> - <item> - <p>Now is tags for ObjectClassFieldType analyzed correctly.</p> - <p>Own Id: OTP-4666</p> - </item> - </list> - </section> - </section> - - <section> - <title>Asn1 1.4.1</title> - - <section> - <title>Fixed errors and malfunctions</title> - <list type="bulleted"> - <item> - <p>Now is the Default value for an ENUMERATED returned as the name from - the NamedList when decoding.</p> - <p>Own Id: OTP-4633</p> - </item> - <item> - <p>It was an internal failure when permitted alphabet constraint existed - together with for instance a size constraint. E.g. when a - referenced type is constrained by a size constraint and the defined - type in turn is constrained by a permitted alphabet constraint.</p> - <p>Own Id: OTP-4559</p> - </item> - <item> - <p>Record is generated in hrl file for a CHOICE with extension mark - that has an internal SEQUENCE/SET definition.</p> - <p>Own Id: OTP-4560</p> - </item> - <item> - <p>Now is the length of a SEQUENCE/SET OF correctly encoded/decoded (PER).</p> - <p>Own Id: OTP-4590</p> - </item> - <item> - <p>The problem with unordered decoded terms when a component is a - ObjectClassFieldType has been solved.</p> - <p>Own Id: OTP-4591</p> - </item> - </list> - </section> - - <section> - <title>Improvements and new features</title> - <list type="bulleted"> - <item> - <p>More complex definitions with TableConstraints where the SimpleTable - and ComponentRelation are on different levels is now fully - supported.</p> - <p>Own Id: OTP-4631</p> - </item> - </list> - </section> - </section> - - <section> - <title>Asn1 1.4</title> - - <section> - <title>Fixed errors and malfunctions</title> - </section> - - <section> - <title>Improvements and new features</title> - <list type="bulleted"> - <item> - <p>Each generated .erl file have now a function info/0 that returns - information about the used compiler version and options.</p> - <p>Own Id: OTP-4373</p> - </item> - <item> - <p>When compiling an ASN.1 module the compiler generates an Erlang module - that is compiled by the Erlang compiler. Earlier it was not possible to - add options to the final step, the Erlang compilation. By adding any - option that is not recognized as a specific ASN.1 option it will be - passed to the final step like: <c>erlc +debug_info Mymodule.asn</c> or - <c>asn1ct:compile('Mymodule',[debug_info])</c>.</p> - <p>Own Id: OTP-4491</p> - </item> - <item> - <p>Earlier one couldn't multi file compile modules that had different - tagdefault, which now is possible. Equal Type/Value names in different - modules are resolved by renaming (concatenate type name and module - name): If two types with the same name T exist in module A and module B - they will get the new names TA and TB.</p> - <p>(Own Id: OTP-4492)</p> - <p>Aux Id: OTP-3983</p> - </item> - <item> - <p>BER: Encode/decode of data have been significantly improved. By use of - the compiler options <c>ber_bin</c> and <c>optimize</c>, - optimized code will be generated and the optimized run-time module will - be used.</p> - <p>Own Id: OTP-4493</p> - </item> - </list> - </section> - </section> - - <section> - <title>Asn1 1.3.3.1</title> - - <section> - <title>Fixed errors and malfunctions</title> - <list type="bulleted"> - <item> - <p>Proper length encoding and padding implemented for a <c>BIT STRING</c> with - NamedNumberList and size constraint as value range. This functionality - didn't work in the rare occasion when the NamedNumberList is shorter - than the lower bound of the constraint.As in this example: - <c>TestS ::= BIT STRING {a (0),b (1)} (SIZE (3..8))</c></p> - <p>(Own Id: OTP-4353)</p> - </item> - <item> - <p>Bug in compiler, when an <c>OBJECT IDENTIFIER</c> value consisting of - two identifiers (Defined values or Name form identifiers) was falsely - interpreted causing a compiling error is now corrected.</p> - <p>(Own Id: OTP-4354)</p> - </item> - <item> - <p>Internal error in check phase that caused crash on - <c>ObjectClassFieldType</c> in ber_bin is corrected.</p> - <p>(Own Id: OTP-4390)</p> - </item> - <item> - <p>Tags for open types are handled according to <c>x.680 30.6c</c>, i.e. - open types shall not be tagged <c>IMPLICIT.</c></p> - <p>(Own Id: OTP-4395)</p> - <p>(Aux Id: OTP-4390)</p> - </item> - </list> - </section> - </section> - - <section> - <title>Asn1 1.3.3</title> - - <section> - <title>Fixed errors and malfunctions</title> - <list type="bulleted"> - <item> - <p>Now gives the compiler an appropriate error report when exported - undefined types are detected.</p> - <p>(Own Id: OTP-4129)</p> - </item> - <item> - <p>The type <c>ObjectDescriptor</c> is now supported, previously the - implementation of encode/decode for this rarely used type was - incomplete.</p> - <p>(Own Id: OTP-4161)</p> - <p>(Aux Id: seq7165)</p> - </item> - <item> - <p>In case of per and compact_bit_string the rightmost byte were erroneous - truncated when the rightmost bits of that byte were zeros. This is now - corrected.</p> - <p>(Own Id: OTP-4200)</p> - </item> - <item> - <p>Bad match of return-value from decode_length in skipvalue/3 has now been - fixed.</p> - <p>(Own Id: OTP-4232)</p> - </item> - <item> - <p>Now is decode of ENUMERATED handled correctly, when tagged EXPLICIT.</p> - <p>(Own Id: OTP-4234)</p> - </item> - <item> - <p>The compiler now parses and handles the ValueFromObject construct.</p> - <p>(Own Id: OTP-4242)</p> - </item> - <item> - <p>Now does the compiler handle the case when the object set in simple - table and componentrelation constraints is of a CLASS without a UNIQUE - field. In this case is the octets, which is assumed to be encoded, - encoded as an open type.</p> - <p>(Own Id: OTP-4248)</p> - <p>(Aux Id: OTP-4242)</p> - </item> - <item> - <p>Compiler handles objects in AdditionalElementSetSpec in ObjectSetSpec, - i.e. the objects that are referred to after the ellipses in an object set.</p> - <p>(Own Id: OTP-4275)</p> - </item> - <item> - <p>Now are values with a component of type CHOICE encoded with indefinite - length correctly decoded.</p> - <p>(Own Id: OTP-4358)</p> - </item> - </list> - </section> - - <section> - <title>Improvements and new features</title> - <list type="bulleted"> - <item> - <p>The language constructs (from the old 1988 standard) <c>ANY</c> - and <c>ANY DEFINED BY</c> are now implemented.</p> - <p>(Own Id: OTP-2741)</p> - <p>(Aux Id: seq 1188)</p> - </item> - <item> - <p>Now it is checked in run-time if a <c>OBJECT IDENTIFIER</c> value is invalid</p> - <p>(Own Id: OTP-4235)</p> - </item> - <item> - <p>The ASN.1 types EXTERNAL,EMBEDDED PDV and CHARACTER STRING now have full support in the compiler.</p> - <p>(Own Id: OTP-4247)</p> - </item> - <item> - <p>A driver in C does the final job (complete) of the PER encoding when - files are compiled with <c>per_bin</c> and <c>optimize</c> flags. - It gives significant faster encoding for PER.</p> - <p>(Own Id: OTP-4355)</p> - </item> - <item> - <p>Encode and decode of PER encoding has been made faster by moving - analysis done in run-time to compile-time. These optimizations are - available by compiling ASN.1 files with options <c>per_bin</c> and - <c>optimize</c>.</p> - <p>(Own Id: OTP-4381)</p> - <p>(Aux Id: OTP-4355)</p> - </item> - </list> - </section> - </section> - - <section> - <title>Asn1 1.3.2</title> - - <section> - <title>Fixed errors and malfunctions</title> - <list type="bulleted"> - <item> - <p>Now does the compiler check values (including referenced values), and - formats the value so it is suitable to use as input to encoding - functions.</p> - <p>(Own Id: OTP-3277)</p> - <p>(Aux Id: OTP-4103)</p> - </item> - <item> - <p>Unnecessary external function calls in generated code are now generated - as internal function calls.</p> - <p>(Own Id: OTP-4073)</p> - </item> - </list> - </section> - - <section> - <title>Improvements and new features</title> - <list type="bulleted"> - <item> - <p>Now is Information Objects supported in BER encoding.</p> - <p>(Own Id: OTP-3980)</p> - <p>(Aux Id: OTP-3979 OTP-3978)</p> - <p></p> - </item> - <item> - <p>PER: A new option <c>per_bin</c> is now supported. When used the - generated encode/decode functions use binaries and the bit syntax to - get better performance than the old <c>per</c> variant which used - lists. All values input to encode and returned from decode are - compatible between <c>per</c> and <c>per_bin</c> except for - open types which are represented as binaries with per_bin and octet - lists with per. We recommend that you use per_bin instead of per from - now on, the use of binaries will be the default in coming versions and - all improvements and optimizations for PER will be concentrated to that - solution.</p> - <p>(Own Id: OTP-4094)</p> - <p></p> - </item> - <item> - <p>Support for DER implemented. Used by flag +der when compiling. Include - the full BER encoding plus: sorting of SET components, sorting of - encoded elements in SET OF, full check of default values in SET and - SEQUENCE. See new documentation on DER in user_guide sections 1.3.1; - 1.4.11; 1.4.12; 1.4.14; 1.4.16 and 1.10, in the reference manual for - asn1ct.</p> - <p>(Own Id: OTP-4103)</p> - <p></p> - </item> - </list> - </section> - </section> - - <section> - <title>Asn1 1.3.1</title> - - <section> - <title>Fixed errors and malfunctions</title> - <list type="bulleted"> - <item> - <p>Do not generate record in .hrl file for SET types</p> - <p>Own Id: OTP-4025</p> - </item> - <item> - <p>Fixed internal error when using BIT STRINGs with Named Number List in combination with <c>compact_bit_string</c> and <c>ber_bin</c> options.</p> - <p>Own Id: OTP-4026</p> - <p>Aux Id: OTP-3982</p> - </item> - <item> - <p>The atom 'com' can now be used in ENUMERATED as an EnumerationItem.</p> - <p>Own Id: OTP-4037</p> - <p>Aux Id: Seq 7036</p> - </item> - <item> - <p>ber: Now it is possible (again) to encode data format "{Type,Value}" in a SEQUENCE OF RequestParameter, when RequestParameter is of type ENUMERATED. The {Type,Value} - notation is not recommended for use, it is redundant and exist only for very ancient backwards compatibility reasons. The "feature" might be removed in forthcoming versions.</p> - <p>Own Id: OTP-4057</p> - <p>Aux Id: Seq 7066</p> - </item> - <item> - <p>A bug in the parser, that caused failure on COMPONENTS OF is now removed.</p> - <p>Own Id: OTP-4058</p> - </item> - </list> - </section> - </section> - - <section> - <title>Asn1 1.3</title> - - <section> - <title>Known problems</title> - <list type="bulleted"> - <item> - <p>The compiler will now check that a value referenced by name - does exist.</p> - <p>Own Id: OTP-3277</p> - </item> - <item> - <p>BER:Decode of a type T ::= SEQUENCE OF C fails if C is encoded with indefinite length. - This is know corrected.</p> - <p>Own Id: OTP-3811</p> - <p>Aux Id: seq5040</p> - </item> - </list> - </section> - - <section> - <title>Fixed errors and malfunctions</title> - <list type="bulleted"> - <item> - <p>The new parser handles imports when one import ends with FROM, a modulename and a reference to a objectidentifier followed by imports from other modules.</p> - <p>Own Id: OTP-3463</p> - </item> - <item> - <p>The compiler did not check that a name mentioned as EXPORTED - actually is defined within the module. - This is now corrected.</p> - <p>Own Id: OTP-3659</p> - </item> - <item> - <p>Removed bug caused by use of nested indefinite length</p> - <p>Own Id: OTP-3994</p> - </item> - </list> - </section> - - <section> - <title>Improvements and new features</title> - <list type="bulleted"> - <item> - <p>Now supporting most common use of parameterization according to X.683</p> - <p>(Own Id: OTP-3978)</p> - </item> - <item> - <p>PER: Now supporting most common use of Information Objects according to X.681. A new parser has been implemented. The error messages due to syntax errors are slightly different than previous. TableConstraint part of X.682 now also supported.</p> - <p>Own Id: OTP-3979</p> - </item> - <item> - <p>New compiler option added: <c>ber_bin</c>. The compiler generates code with new bit syntax. Run time functions uses bit syntax when feasible. Higher encoding/decoding performance in most cases. Se also comments for Asn1 1.2.9.3.</p> - <p>Own Id: OTP-3981</p> - </item> - <item> - <p>A more compact format of BIT STRING in Erlang is now available by use of the compiler option <c>compact_bit_string</c>. It is much faster when large BIT STRINGs are used.</p> - <p>Own Id: OTP-3982</p> - </item> - <item> - <p>Now possible to merge many ASN.1 input files to one Erlang file by use of a configuration file that lists the ASN.1 files.</p> - <p>Own Id: OTP-3983</p> - </item> - <item> - <p>New documentation in <em>User's Guide</em> in section:</p> - <p>3.1: New compile-time functions and options are described.</p> - <p>4.6: New compact format of BIT STRING is described.</p> - <p>4.8: Additional comments on character strings.</p> - <p>7: New section describing ASN.1 Information Objects.</p> - <p>8: New section describing Parameterization.</p> - <p><em>Reference Manual/asn1ct</em> New compile options are described.</p> - <p>Own Id: OTP-3984</p> - <p>Aux Id: OTP-3978, OTP-3979, OTP-3981, OTP-3982, OTP-3983</p> - </item> - <item> - <p>Added the functionality to invoke ASN1Mod:encode (and decode).</p> - <p>Own Id: OTP-3985</p> - </item> - <item> - <p>Performance improvements by removing not necessary use of apply when calling asn1rt:encode. Also other general improvements.</p> - <p>Own Id: OTP-3988</p> - </item> - </list> - </section> - </section> - - <section> - <title>Asn1 1.2.9.6</title> - - <section> - <title>Known problems</title> - <list type="bulleted"> - <item> - <p>The compiler does not check that an exported name actually exists in the ASN.1 module.</p> - <p>Own Id: OTP-3659</p> - </item> - <item> - <p>The compiler does not check that a value referenced by name does exist.</p> - <p>Own Id: OTP-3277</p> - </item> - <item> - <p>BER: The compiler does not take the extensions into account when checking if - the tags are unique in a SEQUENCE or SET.</p> - <p>Own Id: OTP-3304</p> - </item> - </list> - </section> - - <section> - <title>Fixed errors and malfunctions</title> - <list type="bulleted"> - <item> - <p>PER: Trailing zeroes in a BIT STRING declared without named bits - should not be removed in the encodings.</p> - <p>Own Id: OTP-3830</p> - </item> - </list> - </section> - </section> - - <section> - <title>Asn1 1.2.9.5</title> - - <section> - <title>Known problems</title> - <p>Same as for 1.2.9.3.</p> - </section> - - <section> - <title>Fixed errors and malfunctions</title> - <list type="bulleted"> - <item> - <p>PER: Constraints are not propagated when types are - referring to each other. Example:</p> - <code type="none"> - - TBCD-STRING ::= OCTET STRING - - LAI ::= TBCD-STRING (SIZE(3)) </code> - <p>The size constraint is not passed on during encode,decode - resulting in wrong encoding for PER , it is - coded with a length determinant which should not be there - when the length is fixed. For BER this does not matter because the constraints does - not affect the encodings.</p> - <p>Own Id: OTP-3713</p> - </item> - <item> - <p>The generated code gets wrong if there are several ENUMERATED fields in a SEQUENCE or SET, this is now corrected.</p> - <p>Own Id: OTP-3796</p> - </item> - <item> - <p>BER:Decode of a type T ::= SEQUENCE OF C fails if C is encoded with indefinite length. - This is know corrected.</p> - <p>Own Id: OTP-3811</p> - </item> - </list> - </section> - </section> - - <section> - <title>Asn1 1.2.9.3</title> - - <section> - <title>Known problems</title> - <list type="bulleted"> - <item> - <p>The compiler does not check that an exported name actually exists in the ASN.1 module.</p> - <p>Own Id: OTP-3659</p> - </item> - <item> - <p>The compiler does not check that a value referenced by name does exist.</p> - <p>Own Id: OTP-3277</p> - </item> - <item> - <p>BER: The compiler does not take the extensions into account when checking if - the tags are unique in a SEQUENCE or SET.</p> - <p>Own Id: OTP-3304</p> - </item> - </list> - </section> - - <section> - <title>Fixed errors and malfunctions</title> - <list type="bulleted"> - <item> - <p>This version supports soft upgrade from versions 1.2.6 1.2.7.</p> - </item> - <item> - <p>In an ENUMERATED type like this:</p> - <code type="none"> -\011\011T ::= ENUMERATED { blue, green} </code> - <p>The symbols was encoded/decoded with the wrong values, i.e in - reverse order. This is now corrected.</p> - <p>Own Id: OTP-3700</p> - </item> - <item> - <p>PER: OCTET STRING with Size constrained to a single value i.e fixed size - was treated wrong during encode and decode. This is now corrected.</p> - <p>Own Id: OTP-3701</p> - </item> - </list> - </section> - - <section> - <title>Improvements and new features</title> - <list type="bulleted"> - <item> - <p>There is now a new compiler option <c>ber_bin</c> available that can be used to - generate encode/decode functions for BER that uses the new "bit-syntax" to - make the functions more efficient. The <c>ber_bin</c> option is used - as an alternative to the <c>ber</c> and <c>per</c> options.</p> - <p>The encode function then produces a - possibly nested list of binaries and integer lists. The decode function does - in this case require a single binary as input instead of a list. - The modules generated with this option require that you have an R7A or later - system, otherwise they will not compile and the runtime module asn1rt_ber_bin - can not be executed.</p> - <p>The ber_bin option is not officially supported in this version (will be - in a later version) but is provided for those who want to try it. - It should be significantly faster at decode and is slightly faster at encode. - Exactly how performance differs between this binary approach and the - list approach depends highly on the type of input. - Another thing worth noting is that both approaches still have a lot of - solutions in common which can be improved a lot to gain even better - performance.</p> - </item> - </list> - </section> - </section> - - <section> - <title>Asn1 1.2.9.2</title> - - <section> - <title>Fixed errors and malfunctions</title> - <list type="bulleted"> - <item> - <p>BER: Encode/decode of extension components did not work properly. This is now corrected.</p> - <p>Own Id: OTP-3395</p> - <p>Aux Id: </p> - <p>PER:The encode/decode of NULL as an open type has been corrected. An open type must always have a length of at least 1 byte even if the contained - value (e.g NULL) encodes to nothing.</p> - <p>Own Id: OTP-3496</p> - <p>Aux Id: </p> - </item> - <item> - <p>BER:In the current implementation extension components of a SEQUENCE are required - to be present when they are specified as mandatory. This is an error, all extension - components are "optional" even if they are not specified to have the OPTIONAL or - DEFAULT property. This is now corrected.</p> - <p>Own Id: OTP-3278</p> - </item> - </list> - </section> - - <section> - <title>Improvements and new features</title> - <list type="bulleted"> - <item> - <p>The ASN.1 language feature <c>COMPONENTS OF</c> is now implemented.</p> - <p>Own Id: OTP-2515</p> - </item> - <item> - <p>The encoding and decoding of ENUMERATED and - INTEGER with NamedNumbers is made more efficient and thus - faster in runtime.</p> - <p>Own Id: OTP-3464</p> - <p>Aux Id:</p> - </item> - <item> - <p>Added support for encode/decode of open type which is - constrained to a specific type. Previously the value of - an open type had to be a list of octets, but now the Erlang - representation of the specific type used in the constraint - is used both as input to encode and as output from decode.</p> - <p>Own Id: OTP-3569</p> - <p>Aux Id: </p> - </item> - <item> - <p>PER: GeneralString, GraphicalString etc. i.e all strings - that are not so called "known-multiplier character - string types" are now supported by the runtime - encode/decode functions.</p> - <p>Own Id: OTP-3573</p> - <p>Aux Id:</p> - </item> - </list> - </section> - </section> - - <section> - <title>Asn1 1.2.6</title> - - <section> - <title>Known problems</title> - <list type="bulleted"> - <item> - <p>The ASN.1 language feature <c>COMPONENTS OF</c> is not implemented.</p> - <p>Own Id: OTP-2515</p> - </item> - <item> - <p>The compiler does not check that a value referenced by name does exist.</p> - <p>Own Id: OTP-3277</p> - </item> - <item> - <p>BER:In the current implementation extension components of a SEQUENCE are required - to be present when they are specified as mandatory. This is an error, all extension - components are "optional" even if they are not specified to have the OPTIONAL or - DEFAULT property.</p> - <p>Own Id: OTP-3278</p> - </item> - <item> - <p>BER: The compiler does not take the extensions into account when checking if - the tags are unique in a SEQUENCE or SET.</p> - <p>Own Id: OTP-3304</p> - </item> - </list> - </section> - - <section> - <title>Fixed errors and malfunctions</title> - <list type="bulleted"> - <item> - <p>This version supports soft upgrade from versions 1.1.1, 1.1.5 and 1.1.6. - Two new runtime modules <c>asn1rt_ber_v1</c> and - <c>asn1rt_per_v1</c> are delivered together with the old ones. This makes - it possible to continue running applications with modules generated with the - previous version of the asn1 compiler while modules generated by this version - will use the new runtime modules. Note that it is only advice-able to continue - running old generates if they are working perfectly and have no need - for the corrections made in this version of the asn1 application.</p> - </item> - <item> - <p>BER: SEQUENCEs encoded with indefinite length was not correctly decoded. - This in now corrected.</p> - <p>Own Id: OTP-3352</p> - <p>Aux Id: Seq 4100</p> - </item> - </list> - </section> - </section> - - <section> - <title>Asn1 1.2.4</title> - - <section> - <title>Fixed errors and malfunctions</title> - <list type="bulleted"> - <item> - <p>The compiler now detects multiple definitions of values and types and reports this as - an error. Previously this was detected when the generated Erlang module was compiled.</p> - <p>Own Id: OTP-3105</p> - </item> - <item> - <p>BER: An error regarding encoding of <c>ENUMERATED</c> present in asn1-1.1.1 - is corrected. The new version 1.1.2 of asn1 containing this correction is - delivered as a "patch".</p> - <p>Own Id: OTP-3169</p> - </item> - <item> - <p>BER: Decoding of <c>SEQUENCE OF</c> and <c>SET OF</c> with indefinite length is corrected. - The correction was first delivered in version 1.1.2.</p> - <p>Own Id: OTP-3170</p> - </item> - <item> - <p>BER: Encoding and decoding of <c>ENUMERATED</c> - with extensionmark - "..." did not work (crashed with a runtime error). This - has now been corrected. If an unknown enumerated value is - decoded (for an extensible enumerated type) - it is returned as <c>{asn1_enum,Value}</c> where - <c>Value</c> is an integer. Enumerated values in this format - are also accepted by the encoder. - ASN.1 modules containing - <c>ENUMERATED</c> with extensionmark should be - recompiled with the corrected - version of the compiler. The BER runtime functions are also - corrected. - Note that this correction has already been delivered as a - bugfix for R4B (OTP-2951).</p> - <p>Own Id: OTP-3202</p> - <p>Aux Id: Seq3745</p> - </item> - <item> - <p>BER: The primitive/constructed bit in the tag byte of an encoding - is not correct when it comes to user defined tags. - For example in </p> - <code type="none"> - T ::= [2] SEQUENCE { a BOOLEAN} </code> - <p>the tag 2 does not get the constructed bit set which it should. - This is now corrected.</p> - <p>Own Id: OTP-3241</p> - </item> - <item> - <p>The decoder can now detect if there are unexpected bytes - remaining when all components of a sequence are decoded. - The decoder will then return <c>{error,{asn1{unexpected,Bytes}}}</c></p> - <p>Own Id: OTP-3270</p> - </item> - <item> - <p>Values of type <c>OBJECT IDENTIFIER</c> was sometimes returned as an Erlang list - (ASN.1 constants) and sometimes as a tuple (from the decode functions). This is now - changed so that <c>OBJECT IDENTIFIER</c> values always are represented as an Erlang - tuple.</p> - <p>Own Id: OTP-3280</p> - </item> - <item> - <p>PER:The encode/decode functions could not handle integers with - a range greater than 16#7ffffff. This limit is now removed.</p> - <p>Own Id: OTP-3287</p> - </item> - <item> - <p>PER: The encoding/decoding of the length for a SET OF/SEQUENCE OF - was wrong if there was a size constraint. This is now corrected.</p> - <p>Own Id: OTP-3291</p> - </item> - <item> - <p>PER: Encoding of a constrained INTEGER (range > 16 k) was wrong for - the value 0. This is now corrected.</p> - <p>Own Id: OTP-3306</p> - </item> - </list> - </section> - - <section> - <title>Improvements and new features</title> - <list type="bulleted"> - <item> - <p>The ASN.1 module name and the filename where the ASN.1 - specification resides must match each other (has always been the - case). This is now checked by the compiler. The check requires that - the names match in a case or case insensitive way depending on the - characteristics for the current system.</p> - <p>Own Id: OTP-1843</p> - </item> - <item> - <p>PER: Encode/decode of an extension value (i.e not within the root set) for - <c>ENUMERATED</c> did not work properly. This is now corrected. - If an unknown enumerated value is - decoded (for an extensible enumerated type) - it is returned as <c>{asn1_enum,Value}</c> where - <c>Value</c> is an integer. Enumerated values in this format - are also accepted by the encoder (if the value is >= the number of known - extension values).</p> - <p>Own Id: OTP-2930</p> - </item> - <item> - <p>Unnecessary printouts from the compiler are removed. - The compiler version and the compiler options are now - printed to stdout.</p> - <p>Own Id: OTP-3276</p> - </item> - <item> - <p>In order to better suite the use of ASN.1 in embedded systems only - the modules needed in runtime are now listed in the <c>.app</c> file.</p> - <p>Own Id: OTP-3279</p> - </item> - <item> - <p>The compiler now supports extensionmarker in constraint specifications. - Example:</p> - <code type="none"> -INTEGER (0..10, ...) </code> - <p>In previous version this was reported as a syntax error.</p> - <p>Own Id: OTP-3281</p> - </item> - <item> - <p>A very limited part of ITU-T recommendation X.681 - Abstract Syntax Notation One (ASN.1): Information - object specification is now implemented. Specifically \011 - TYPE IDENTIFIER is recognized by the compiler.</p> - <p>Own Id: OTP-3325</p> - </item> - <item> - <p>Parameterization of ASN.1 specifications (ITU-T X.683) is now - supported to a limited extent.</p> - <p>Own Id: OTP-3326</p> - </item> - </list> - </section> - </section> - - <section> - <title>Asn1 1.1.3.1</title> - - <section> - <title>Fixed errors and malfunctions</title> - <list type="bulleted"> - <item> - <p>BER Encoding and decoding of <c>ENUMERATED</c> - with extensionmark - "..." did not work (crashed with a runtime error). This - has now been corrected. If an unknown enumerated value is - decoded (for an extensible enumerated type) - it is returned as <c>{asn1_enum,Value}</c> where - <c>Value</c> is an integer. Enumerated values in this format - are also accepted by the encoder. - ASN.1 modules containing - <c>ENUMERATED</c> with extensionmark should be - recompiled with the corrected - version of the compiler. The BER runtime functions are also - corrected. - Note that this correction has already been delivered as a - bug-fix for R4B (OTP-2951).</p> - <p>Own Id: OTP-3202</p> - <p>Aux Id: Seq3745</p> - </item> - </list> - </section> - </section> - - <section> - <title>Asn1 1.1.1</title> - - <section> - <title>Known problems</title> - <list type="bulleted"> - <item> - <p>The syntactic construct <c>COMPONENTS OF</c> is not - implemented.</p> - <p>Own Id: OTP-2515</p> - </item> - <item> - <p><c>ANY</c> and <c>ANY DEFINED BY</c> are currently not - supported.</p> - <p>Own Id: OTP-2741</p> - <p>Aux Id: seq 1188</p> - </item> - <item> - <p>Multiple definitions of the same Type or Value is not detected - by the compiler. The error occurs when the generated Erlang - module is compiled.</p> - <p>Own Id: OTP-3105</p> - </item> - </list> - </section> - </section> - - <section> - <title>Asn1 1.1</title> - - <section> - <title>Known problems</title> - <list type="bulleted"> - <item> - <p>The primitive/constructed bit in the tag byte of an encoding - is not correct when it comes to user defined tags. - For example in</p> - <code type="none"> - T ::= [2] SEQUENCE { a BOOLEAN} </code> - <p>the tag 2 does not get the constructed bit set which it should. - This is now corrected.</p> - <p>Own Id: OTP-3241</p> - </item> - </list> - </section> - - <section> - <title>Fixed errors and malfunctions</title> - <list type="bulleted"> - <item> - <p>The BER decoder failed to decode certain nested data types - where <c>IMPLICIT</c> tags where involved. - This is now corrected.</p> - <p>Own Id: OTP-2719</p> - <p>Aux Id: seq 1148</p> - </item> - <item> - <p>The handling of types with extension marker "..." is corrected. - Earlier each SEQUENCE and SET with an extension marker got an - extra field named <c>asn1_EXT</c> in the generated record. - This was a mistake and that field is now removed (concerns - both BER and BER).</p> - <p>Own Id: OTP-2724</p> - <p>Aux Id: seq 1148, OTP-2719</p> - </item> - <item> - <p>The decoder (both BER and PER) could not handle unnamed - bits of a <c>BIT STRING</c> if the type had any - named bits declared. This is now corrected and the unnamed - bits are returned as <c>{bit,Pos}</c> where Pos is the bit - position. The <c>{bit,Pos}</c> can be used as input to the - encoder too.</p> - <p>Own Id: OTP-2725</p> - <p>Aux Id: seq 1148,OTP-2719,OTP-2724</p> - </item> - <item> - <p>The functions <c>asn1rt:decode</c> and <c>asn1ct:decode</c> - did not always return <c>{ok,Result}</c> or - <c>{error,Reason}</c> as documented. This is now corrected.</p> - <p>Own Id: OTP-2730</p> - <p>Aux Id: seq 1158</p> - </item> - <item> - <p>The compiler did not accept CHOICE types as components - of a SEQUENCE or SET when - the modules tag default was IMPLICIT. - Example:</p> - <code type="none"> -C ::= CHOICE { ......} -A ::= SEQUENCE { -a [1] C, -- This was not accepted -..... </code> - <p>This was an error - caused by a misinterpretation of the ASN.1 standard. This - is now corrected.</p> - <p>Own Id: OTP-2731</p> - <p>Aux Id: seq 1163</p> - </item> - <item> - <p>When decoding a SEQUENCE A which contains an OPTIONAL component - b which is a SEQUENCE with mandatory components, the decoder - does not detect as an error that a mandatory component of b - is missing. The same error could occur also in other cases - with nested types and optional components of SEQUENCE or SET. - This is now corrected.</p> - <p>Own Id: OTP-2738</p> - <p>Aux Id: seq 1183</p> - </item> - <item> - <p>BER Encoding and decoding of <c>ENUMERATED</c> - with extensionmark - "..." did not work (crashed with a runtime error). This - has now been corrected. If an unknown enumerated value is - decoded (for an extensible enumerated type) - it is returned as <c>{asn1_enum,Value}</c> where - <c>Value</c> is an integer. Enumerated values in this format - are also accepted by the encoder. - ASN.1 modules containing - <c>ENUMERATED</c> with extensionmark should be - recompiled with the corrected - version of the compiler. The BER runtime functions are also - corrected.</p> - <p>Own Id: OTP-2951</p> - <p>Aux Id: Seq 1446 OTP-2929</p> - </item> - <item> - <p>The compiler does now accept all valid value notations - for the OBJECT IDENTIFIER type. The generated code for - those values is also corrected.</p> - <p>Own Id: OTP-3059</p> - </item> - </list> - </section> - - <section> - <title>Improvements and new features</title> - <list type="bulleted"> - <item> - <p>The code generated for BER is significantly enhanced resulting - in less code and around 300% better performance in runtime - for the encoding of complex ASN.1 values. The performance of - decoding is unchanged.</p> - <p>Own Id: OTP-2806</p> - </item> - </list> - </section> - </section> - - <section> - <title>Asn1 1.0.3</title> - - <section> - <title>Fixed errors and malfunctions</title> - <list type="bulleted"> - <item> - <p>The <c>asn1.app</c> file is corrected.</p> - <p>Own Id: OTP-2640</p> - </item> - <item> - <p>The encoding of integers in BER did not comply with the - standard for all values. The values was not encoded - in the minimum number of octets as required. This is - now corrected in the runtime module <c>asn1rt_ber</c>.</p> - <p>Own Id: OTP-2666</p> - </item> - </list> - </section> - - <section> - <title>Improvements and new features</title> - <list type="bulleted"> - <item> - <p>The compiler now generates explicit exports directives for - all generated - functions that should be exported (instead of -compile(export_all)). - This eliminates the warnings from the Erlang compiler when - compiling the - generated file.</p> - <p>Own Id: OTP-1845</p> - </item> - </list> - </section> - </section> - - <section> - <title>R3B02 (Asn1 1.0.2)</title> - - <section> - <title>Fixed errors and malfunctions</title> - <list type="bulleted"> - <item> - <p>The decoding of a BER encoded SEQUENCE with optional component - of type SEQUENCE (also with optional components) could result - in an error or wrong result if the tags are equal.</p> - <p>Own Id: OTP-2226</p> - </item> - <item> - <p>The encoding of (PER) SEQUENCE with extensionmark was wrong. - This is now corrected.</p> - <p>Own Id: OTP-2349</p> - </item> - </list> - </section> - </section> - - <section> - <title>R3A (Asn1 0.9)</title> - - <section> - <title>Fixed errors and malfunctions</title> - <list type="bulleted"> - <item> - <p>The asn1 compiler now detects the use of an implicit tag before <c>CHOICE</c> as an error (in accordance with the standard)</p> - <p>Own Id: OTP-1844</p> - </item> - <item> - <p>An OPTIONAL CHOICE embedded in SEQUENCE when BER coding - caused an error when generating decode code. This is now - corrected.</p> - <p>Own Id: OTP-1857</p> - <p>Aux Id: OTP-1848</p> - </item> - </list> - </section> - </section> - - <section> - <title>1 ASN1 0.8.1</title> - <p>This is the first release of the ASN1 application. This version is - released for beta-testing. Some functionality will be added until the - 1.0 version is released. See the release notes for the latest version - for the exact details about new features. A list of missing features - and restrictions can be found in the chapter below.</p> - - <section> - <title>1.1 Missing features and other restrictions</title> - <p></p> - <list type="bulleted"> - <item> - <p>The encoding rules BER and PER (aligned) is supported. <em>PER (unaligned) IS NOT SUPPORTED</em>.</p> - </item> - <item> - <p>NOT SUPPORTED types <c>ANY</c> and <c>ANY DEFINED BY</c> - (is not in the standard any more).</p> - </item> - <item> - <p>NOT SUPPORTED types <c>EXTERNAL</c> and <c>EMBEDDED-PDV</c>. </p> - </item> - <item> - <p>NOT SUPPORTED type <c>REAL</c> (planned to be implemented). </p> - </item> - <item> - <p>The code generation support for value definitions in the ASN.1 notation is very limited - (planned to be enhanced).</p> - </item> - <item> - <p>The support for constraints is limited to:</p> - </item> - </list> - <list type="bulleted"> - <item> - <p>SizeConstraint SIZE(X)</p> - </item> - <item> - <p>SingleValue (1)</p> - </item> - <item> - <p>ValueRange (X..Y)</p> - </item> - <item> - <p>PermittedAlpabet FROM (but not for BMPString and UniversalString when generating PER).</p> - </item> - <item> - <p>Complex expressions in constraints is not supported (planned to be extended).</p> - </item> - <item> - <p>The current version of the compiler has very limited error checking:</p> - </item> - <item> - <p>Stops at first syntax error.</p> - </item> - <item> - <p>Does not stop when a reference to an undefined type is found , - but prints an error message. Compilation of the generated - Erlang module will then fail.</p> - </item> - <item> - <p>A whole number of other semantical controls is currently - missing. This means that the compiler will give little - or bad help to detect what's wrong with an ASN.1 - specification, but will mostly work very well when the - ASN.1 specification is correct.</p> - </item> - </list> - <list type="bulleted"> - <item> - <p>The maximum INTEGER supported in this version is a - signed 64 bit integer. This limitation is probably quite - reasonable. (Planned to be extended).</p> - </item> - <item> - <p>Only AUTOMATIC TAGS supported for PER.</p> - </item> - <item> - <p>Only EXPLICIT and IMPLICIT TAGS supported for BER.</p> - </item> - <item> - <p>The compiler supports decoding of BER-data with indefinite - length but it is not possible to produce data with indefinite - length with the encoder.</p> - </item> - </list> - </section> - </section> -</chapter> - diff --git a/lib/asn1/doc/src/part_notes.xml b/lib/asn1/doc/src/part_notes.xml deleted file mode 100644 index b0a6887aa5..0000000000 --- a/lib/asn1/doc/src/part_notes.xml +++ /dev/null @@ -1,39 +0,0 @@ -<?xml version="1.0" encoding="latin1" ?> -<!DOCTYPE part SYSTEM "part.dtd"> - -<part xmlns:xi="http://www.w3.org/2001/XInclude"> - <header> - <copyright> - <year>2004</year><year>2009</year> - <holder>Ericsson AB. All Rights Reserved.</holder> - </copyright> - <legalnotice> - The contents of this file are subject to the Erlang Public License, - Version 1.1, (the "License"); you may not use this file except in - compliance with the License. You should have received a copy of the - Erlang Public License along with this software. If not, it can be - retrieved online at http://www.erlang.org/. - - Software distributed under the License is distributed on an "AS IS" - basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - the License for the specific language governing rights and limitations - under the License. - - </legalnotice> - - <title>Asn1 Release Notes</title> - <prepared>Ingela Anderton Andin</prepared> - <docno></docno> - <date>>2004-09-07</date> - <rev></rev> - <file>part_notes.sgml</file> - </header> - <description> - <p>The <em>Asn1</em> application - contains modules with compile-time and run-time support for ASN.1.</p> - <p>There are also release notes for - <url href="notes_history.html">older versions</url>.</p> - </description> - <xi:include href="notes.xml"/> -</part> - diff --git a/lib/asn1/doc/src/warning.gif b/lib/asn1/doc/src/warning.gif Binary files differdeleted file mode 100644 index 96af52360e..0000000000 --- a/lib/asn1/doc/src/warning.gif +++ /dev/null diff --git a/lib/compiler/src/beam_asm.erl b/lib/compiler/src/beam_asm.erl index 90d25d87b2..497c4fa07b 100644 --- a/lib/compiler/src/beam_asm.erl +++ b/lib/compiler/src/beam_asm.erl @@ -150,7 +150,7 @@ build_file(Code, Attr, Dict, NumLabels, NumFuncs, Abst, SourceFile, Opts) -> %% Create IFF chunk. Chunks = case member(slim, Opts) of - true -> [Essentials,AttrChunk,CompileChunk,AbstChunk]; + true -> [Essentials,AttrChunk,AbstChunk]; false -> [Essentials,LocChunk,AttrChunk,CompileChunk,AbstChunk] end, build_form(<<"BEAM">>, Chunks). diff --git a/lib/compiler/src/beam_bool.erl b/lib/compiler/src/beam_bool.erl index d8c201a194..dcc6ad4c7c 100644 --- a/lib/compiler/src/beam_bool.erl +++ b/lib/compiler/src/beam_bool.erl @@ -123,6 +123,12 @@ bopt_block(Reg, Fail, OldIs, [{block,Bl0}|Acc0], St0) -> throw:mixed -> failed; + %% There was a reference to a boolean expression + %% from inside a protected block (try/catch), to + %% a boolean expression outside. + throw:protected_barrier -> + failed; + %% The 'xor' operator was used. We currently don't %% find it worthwile to translate 'xor' operators %% (the code would be clumsy). @@ -167,7 +173,7 @@ bopt_block(Reg, Fail, OldIs, [{block,Bl0}|Acc0], St0) -> %% whether the optimized code is guaranteed to work in the same %% way as the original code. %% -%% Throws an exception if the optmization is not safe. +%% Throw an exception if the optimization is not safe. %% ensure_opt_safe(Bl, NewCode, OldIs, Fail, PreceedingCode, St) -> %% Here are the conditions that must be true for the @@ -184,10 +190,10 @@ ensure_opt_safe(Bl, NewCode, OldIs, Fail, PreceedingCode, St) -> %% by the code that follows. %% %% 3. Any register that is assigned a value in the optimized - %% code must be UNUSED or KILLED in the following code. - %% (Possible future improvement: Registers that are known - %% to be assigned the SAME value in the original and optimized - %% code don't need to be unused in the following code.) + %% code must be UNUSED or KILLED in the following code + %% (because the register might be assigned the wrong value, + %% and even if the value is right it might no longer be + %% assigned on *all* paths leading to its use). InitInPreceeding = initialized_regs(PreceedingCode), @@ -304,6 +310,8 @@ dst_regs([{set,[D],_,{bif,_,{f,_}}}|Is], Acc) -> dst_regs(Is, [D|Acc]); dst_regs([{set,[D],_,{alloc,_,{gc_bif,_,{f,_}}}}|Is], Acc) -> dst_regs(Is, [D|Acc]); +dst_regs([{set,[D],_,move}|Is], Acc) -> + dst_regs(Is, [D|Acc]); dst_regs([_|Is], Acc) -> dst_regs(Is, Acc); dst_regs([], Acc) -> ordsets:from_list(Acc). @@ -414,11 +422,10 @@ bopt_good_args([A|As], Regs) -> bopt_good_args([], _) -> ok. bopt_good_arg({Tag,_}=X, Regs) when Tag =:= x; Tag =:= tmp -> - case gb_trees:get(X, Regs) of - any -> ok; - _Other -> - %%io:format("not any: ~p: ~p\n", [X,_Other]), - throw(mixed) + case gb_trees:lookup(X, Regs) of + {value,any} -> ok; + {value,_} -> throw(mixed); + none -> throw(protected_barrier) end; bopt_good_arg(_, _) -> ok. diff --git a/lib/compiler/test/andor_SUITE.erl b/lib/compiler/test/andor_SUITE.erl index 34609a49f2..a460d54239 100644 --- a/lib/compiler/test/andor_SUITE.erl +++ b/lib/compiler/test/andor_SUITE.erl @@ -20,13 +20,14 @@ -export([all/1, t_case/1,t_and_or/1,t_andalso/1,t_orelse/1,inside/1,overlap/1, - combined/1,in_case/1]). + combined/1,in_case/1,before_and_inside_if/1]). -include("test_server.hrl"). all(suite) -> test_lib:recompile(?MODULE), - [t_case,t_and_or,t_andalso,t_orelse,inside,overlap,combined,in_case]. + [t_case,t_and_or,t_andalso,t_orelse,inside,overlap,combined,in_case, + before_and_inside_if]. t_case(Config) when is_list(Config) -> %% We test boolean cases almost but not quite like cases @@ -380,6 +381,65 @@ in_case_1_guard(LenUp, LenDw, LenN, Rotation, Count) -> false -> loop end. +before_and_inside_if(Config) when is_list(Config) -> + ?line no = before_and_inside_if([a], [b], delete), + ?line no = before_and_inside_if([a], [b], x), + ?line no = before_and_inside_if([a], [], delete), + ?line no = before_and_inside_if([a], [], x), + ?line no = before_and_inside_if([], [], delete), + ?line yes = before_and_inside_if([], [], x), + ?line yes = before_and_inside_if([], [b], delete), + ?line yes = before_and_inside_if([], [b], x), + + ?line {ch1,ch2} = before_and_inside_if_2([a], [b], blah), + ?line {ch1,ch2} = before_and_inside_if_2([a], [b], xx), + ?line {ch1,ch2} = before_and_inside_if_2([a], [], blah), + ?line {ch1,ch2} = before_and_inside_if_2([a], [], xx), + ?line {no,no} = before_and_inside_if_2([], [b], blah), + ?line {no,no} = before_and_inside_if_2([], [b], xx), + ?line {ch1,no} = before_and_inside_if_2([], [], blah), + ?line {no,ch2} = before_and_inside_if_2([], [], xx), + ok. + +%% Thanks to Simon Cornish and Kostis Sagonas. +%% Used to crash beam_bool. +before_and_inside_if(XDo1, XDo2, Do3) -> + Do1 = (XDo1 =/= []), + Do2 = (XDo2 =/= []), + if + %% This expression occurs in a try/catch (protected) + %% block, which cannot refer to variables outside of + %% the block that are boolean expressions. + Do1 =:= true; + Do1 =:= false, Do2 =:= false, Do3 =:= delete -> + no; + true -> + yes + end. + +%% Thanks to Simon Cornish. +%% Used to generate code that would not set {y,0} on +%% all paths before its use (and therefore fail +%% validation by the beam_validator). +before_and_inside_if_2(XDo1, XDo2, Do3) -> + Do1 = (XDo1 =/= []), + Do2 = (XDo2 =/= []), + CH1 = if Do1 == true; + Do1 == false,Do2==false,Do3 == blah -> + ch1; + true -> + no + end, + CH2 = if Do1 == true; + Do1 == false,Do2==false,Do3 == xx -> + ch2; + true -> + no + end, + {CH1,CH2}. + +%% Utilities. + check(V1, V0) -> if V1 /= V0 -> io:fwrite("error: ~w.\n", [V1]), @@ -393,5 +453,3 @@ echo(X) -> X. id(I) -> I. - - diff --git a/lib/compiler/test/compilation_SUITE_data/on_load.erl b/lib/compiler/test/compilation_SUITE_data/on_load.erl index 92bcf74624..e9b5ec7f34 100644 --- a/lib/compiler/test/compilation_SUITE_data/on_load.erl +++ b/lib/compiler/test/compilation_SUITE_data/on_load.erl @@ -12,7 +12,7 @@ do_on_load() -> local_function(), - true. + ok. local_function() -> ok. diff --git a/lib/crypto/c_src/crypto_drv.c b/lib/crypto/c_src/crypto_drv.c index 241c4ec733..5b6d750dde 100644 --- a/lib/crypto/c_src/crypto_drv.c +++ b/lib/crypto/c_src/crypto_drv.c @@ -233,6 +233,11 @@ static ErlDrvEntry crypto_driver_entry = { #define DRV_BF_CFB64_ENCRYPT 59 #define DRV_BF_CFB64_DECRYPT 60 +#define DRV_BF_ECB_ENCRYPT 61 +#define DRV_BF_ECB_DECRYPT 62 +#define DRV_BF_OFB64_ENCRYPT 63 +#define DRV_BF_CBC_ENCRYPT 64 +#define DRV_BF_CBC_DECRYPT 65 /* #define DRV_CBC_IDEA_ENCRYPT 34 */ /* #define DRV_CBC_IDEA_DECRYPT 35 */ @@ -533,6 +538,79 @@ static int crypto_control(ErlDrvData drv_data, unsigned int command, char *buf, (command == DRV_CBC_DES_ENCRYPT)); return dlen; + case DRV_BF_ECB_ENCRYPT: + case DRV_BF_ECB_DECRYPT: + { + /* buf = klen[4] key data */ + int bf_direction; + const unsigned char *ukey; + const unsigned char *bf_dbuf; /* blowfish input data */ + BF_KEY bf_key; /* blowfish key 8 */ + + klen = get_int32(buf); + ukey = (unsigned char *) buf + 4; + bf_dbuf = ukey + klen; + dlen = len - 4 - klen; + if (dlen < 0) return -1; + BF_set_key(&bf_key, klen, ukey); + bin = return_binary(rbuf,rlen,dlen); + if (bin==NULL) return -1; + bf_direction = command == DRV_BF_ECB_ENCRYPT ? BF_ENCRYPT : BF_DECRYPT; + BF_ecb_encrypt(bf_dbuf, bin, &bf_key, bf_direction); + return dlen; + } + + case DRV_BF_CBC_ENCRYPT: + case DRV_BF_CBC_DECRYPT: + { + /* buf = klen[4] key ivec[8] data */ + unsigned char *ukey; + unsigned char* ivec; + unsigned char bf_tkey[8]; /* blowfish ivec */ + int bf_direction; + const unsigned char *bf_dbuf; /* blowfish input data */ + BF_KEY bf_key; /* blowfish key 8 */ + + klen = get_int32(buf); + ukey = (unsigned char *)buf + 4; + ivec = ukey + klen; + bf_dbuf = ivec + 8; + dlen = len - 4 - klen - 8; + if (dlen < 0) return -1; + BF_set_key(&bf_key, klen, ukey); + memcpy(bf_tkey, ivec, 8); + bin = return_binary(rbuf,rlen,dlen); + if (bin==NULL) return -1; + bf_direction = command == DRV_BF_CBC_ENCRYPT ? BF_ENCRYPT : BF_DECRYPT; + BF_cbc_encrypt(bf_dbuf, bin, dlen, &bf_key, bf_tkey, bf_direction); + return dlen; + } + + case DRV_BF_OFB64_ENCRYPT: + { + /* buf = klen[4] key ivec[8] data */ + unsigned char *ukey; + unsigned char* ivec; + unsigned char bf_tkey[8]; /* blowfish ivec */ + int bf_n; /* blowfish ivec pos */ + const unsigned char *bf_dbuf; /* blowfish input data */ + BF_KEY bf_key; /* blowfish key 8 */ + + klen = get_int32(buf); + ukey = (unsigned char *)buf + 4; + ivec = ukey + klen; + bf_dbuf = ivec + 8; + dlen = len - 4 - klen - 8; + if (dlen < 0) return -1; + BF_set_key(&bf_key, klen, ukey); + memcpy(bf_tkey, ivec, 8); + bin = return_binary(rbuf,rlen,dlen); + if (bin==NULL) return -1; + bf_n = 0; + BF_ofb64_encrypt(bf_dbuf, bin, dlen, &bf_key, bf_tkey, &bf_n); + return dlen; + } + case DRV_BF_CFB64_ENCRYPT: case DRV_BF_CFB64_DECRYPT: { diff --git a/lib/crypto/doc/src/crypto.xml b/lib/crypto/doc/src/crypto.xml index 42ba523c8c..cfc6996332 100644 --- a/lib/crypto/doc/src/crypto.xml +++ b/lib/crypto/doc/src/crypto.xml @@ -337,6 +337,53 @@ Mpint() = <![CDATA[<<ByteLen:32/integer-big, Bytes:ByteLen/binary>>]]> <c>Key3</c>, and <c>IVec</c> must be 64 bits (8 bytes).</p> </desc> </func> + + <func> + <name>blowfish_ecb_encrypt(Key, Text) -> Cipher</name> + <fsummary>Encrypt the first 64 bits of <c>Text</c> using Blowfish in ECB mode</fsummary> + <type> + <v>Key = Text = iolist() | binary()</v> + <v>IVec = Cipher = binary()</v> + </type> + <desc> + <p>Encrypts the first 64 bits of <c>Text</c> using Blowfish in ECB mode. <c>Key</c> is the Blowfish key. The length of <c>Text</c> must be at least 64 bits (8 bytes).</p> + </desc> + <name>blowfish_ecb_decrypt(Key, Text) -> Cipher</name> + <fsummary>Decrypt the first 64 bits of <c>Text</c> using Blowfish in ECB mode</fsummary> + <type> + <v>Key = Text = iolist() | binary()</v> + <v>IVec = Cipher = binary()</v> + </type> + <desc> + <p>Decrypts the first 64 bits of <c>Text</c> using Blowfish in ECB mode. <c>Key</c> is the Blowfish key. The length of <c>Text</c> must be at least 64 bits (8 bytes).</p> + </desc> + </func> + + <func> + <name>blowfish_cbc_encrypt(Key, Text) -> Cipher</name> + <fsummary>Encrypt <c>Text</c> using Blowfish in CBC mode</fsummary> + <type> + <v>Key = Text = iolist() | binary()</v> + <v>IVec = Cipher = binary()</v> + </type> + <desc> + <p>Encrypts <c>Text</c> using Blowfish in CBC mode. <c>Key</c> is the Blowfish key, and <c>IVec</c> is an + arbitrary initializing vector. The length of <c>IVec</c> + must be 64 bits (8 bytes). The length of <c>Text</c> must be a multiple of 64 bits (8 bytes).</p> + </desc> + <name>blowfish_cbc_decrypt(Key, Text) -> Cipher</name> + <fsummary>Decrypt <c>Text</c> using Blowfish in CBC mode</fsummary> + <type> + <v>Key = Text = iolist() | binary()</v> + <v>IVec = Cipher = binary()</v> + </type> + <desc> + <p>Decrypts <c>Text</c> using Blowfish in CBC mode. <c>Key</c> is the Blowfish key, and <c>IVec</c> is an + arbitrary initializing vector. The length of <c>IVec</c> + must be 64 bits (8 bytes). The length of <c>Text</c> must be a multiple 64 bits (8 bytes).</p> + </desc> + </func> + <func> <name>blowfish_cfb64_encrypt(Key, IVec, Text) -> Cipher</name> <fsummary>Encrypt <c>Text</c>using Blowfish in CFB mode with 64 @@ -367,6 +414,23 @@ Mpint() = <![CDATA[<<ByteLen:32/integer-big, Bytes:ByteLen/binary>>]]> must be 64 bits (8 bytes).</p> </desc> </func> + + <func> + <name>blowfish_ofb64_encrypt(Key, IVec, Text) -> Cipher</name> + <fsummary>Encrypt <c>Text</c>using Blowfish in OFB mode with 64 + bit feedback</fsummary> + <type> + <v>Key = Text = iolist() | binary()</v> + <v>IVec = Cipher = binary()</v> + </type> + <desc> + <p>Encrypts <c>Text</c> using Blowfish in OFB mode with 64 bit + feedback. <c>Key</c> is the Blowfish key, and <c>IVec</c> is an + arbitrary initializing vector. The length of <c>IVec</c> + must be 64 bits (8 bytes).</p> + </desc> + </func> + <func> <name>aes_cfb_128_encrypt(Key, IVec, Text) -> Cipher</name> <name>aes_cbc_128_encrypt(Key, IVec, Text) -> Cipher</name> diff --git a/lib/crypto/src/crypto.erl b/lib/crypto/src/crypto.erl index 5189677dd0..fa33bad2e0 100644 --- a/lib/crypto/src/crypto.erl +++ b/lib/crypto/src/crypto.erl @@ -30,7 +30,10 @@ -export([md5_mac/2, md5_mac_96/2, sha_mac/2, sha_mac_96/2]). -export([des_cbc_encrypt/3, des_cbc_decrypt/3, des_cbc_ivec/1]). -export([des3_cbc_encrypt/5, des3_cbc_decrypt/5]). --export([blowfish_cfb64_encrypt/3,blowfish_cfb64_decrypt/3]). +-export([blowfish_ecb_encrypt/2, blowfish_ecb_decrypt/2]). +-export([blowfish_cbc_encrypt/3, blowfish_cbc_decrypt/3]). +-export([blowfish_cfb64_encrypt/3, blowfish_cfb64_decrypt/3]). +-export([blowfish_ofb64_encrypt/3]). -export([des_ede3_cbc_encrypt/5, des_ede3_cbc_decrypt/5]). -export([aes_cfb_128_encrypt/3, aes_cfb_128_decrypt/3]). -export([exor/2]). @@ -115,6 +118,11 @@ -define(BF_CFB64_ENCRYPT, 59). -define(BF_CFB64_DECRYPT, 60). +-define(BF_ECB_ENCRYPT, 61). +-define(BF_ECB_DECRYPT, 62). +-define(BF_OFB64_ENCRYPT, 63). +-define(BF_CBC_ENCRYPT, 64). +-define(BF_CBC_DECRYPT, 65). %% -define(IDEA_CBC_ENCRYPT, 34). %% -define(IDEA_CBC_DECRYPT, 35). @@ -303,12 +311,27 @@ des_ede3_cbc_decrypt(Key1, Key2, Key3, IVec, Data) -> %% %% Blowfish %% +blowfish_ecb_encrypt(Key, Data) when byte_size(Data) >= 8 -> + control_bin(?BF_ECB_ENCRYPT, Key, list_to_binary([Data])). + +blowfish_ecb_decrypt(Key, Data) when byte_size(Data) >= 8 -> + control_bin(?BF_ECB_DECRYPT, Key, list_to_binary([Data])). + +blowfish_cbc_encrypt(Key, IVec, Data) when byte_size(Data) rem 8 =:= 0 -> + control_bin(?BF_CBC_ENCRYPT, Key, list_to_binary([IVec, Data])). + +blowfish_cbc_decrypt(Key, IVec, Data) when byte_size(Data) rem 8 =:= 0 -> + control_bin(?BF_CBC_DECRYPT, Key, list_to_binary([IVec, Data])). + blowfish_cfb64_encrypt(Key, IVec, Data) when byte_size(IVec) =:= 8 -> control_bin(?BF_CFB64_ENCRYPT, Key, list_to_binary([IVec, Data])). blowfish_cfb64_decrypt(Key, IVec, Data) when byte_size(IVec) =:= 8 -> control_bin(?BF_CFB64_DECRYPT, Key, list_to_binary([IVec, Data])). +blowfish_ofb64_encrypt(Key, IVec, Data) when byte_size(IVec) =:= 8 -> + control_bin(?BF_OFB64_ENCRYPT, Key, list_to_binary([IVec, Data])). + %% %% AES in cipher feedback mode (CFB) %% diff --git a/lib/crypto/test/Makefile b/lib/crypto/test/Makefile new file mode 100644 index 0000000000..e728875027 --- /dev/null +++ b/lib/crypto/test/Makefile @@ -0,0 +1,83 @@ +include $(ERL_TOP)/make/target.mk +include $(ERL_TOP)/make/$(TARGET)/otp.mk + +# ---------------------------------------------------- +# Target Specs +# ---------------------------------------------------- + +MODULES = \ + blowfish_SUITE \ + crypto_SUITE + +ERL_FILES= $(MODULES:%=%.erl) + +TARGET_FILES= $(MODULES:%=$(EBIN)/%.$(EMULATOR)) + +SOURCE = $(ERL_FILES) $(HRL_FILES) + +EMAKEFILE=Emakefile + +# ---------------------------------------------------- +# Release directory specification +# ---------------------------------------------------- +RELSYSDIR = $(RELEASE_PATH)/crypto_test + + +# ---------------------------------------------------- +# FLAGS +# ---------------------------------------------------- +ERL_MAKE_FLAGS += +ERL_COMPILE_FLAGS += -I$(ERL_TOP)/lib/test_server/include + +EBIN = . +MAKE_EMAKE = $(wildcard $(ERL_TOP)/make/make_emakefile) + + +# ---------------------------------------------------- +# Targets +# ---------------------------------------------------- + +# Backward compatibility, for R9B and earlier. + +ifeq ($(MAKE_EMAKE),) + +RELTEST_FILES = $(SOURCE) $(TARGET_FILES) +TEST_TARGET = tests + +tests debug opt: $(TARGET_FILES) + +else + +RELTEST_FILES = $(EMAKEFILE) $(SOURCE) +TEST_TARGET = make_emakefile + + +tests debug opt: make_emakefile + erl $(ERL_MAKE_FLAGS) -make + +make_emakefile: + $(ERL_TOP)/make/make_emakefile $(ERL_COMPILE_FLAGS) -o$(EBIN) \ + $(MODULES) > $(EMAKEFILE) + +endif +clean: + rm -f $(EMAKEFILE) + rm -f $(TARGET_FILES) $(GEN_FILES) + rm -f core + +docs: + +# ---------------------------------------------------- +# Release Target +# ---------------------------------------------------- +include $(ERL_TOP)/make/otp_release_targets.mk + +release_spec: + +release_tests_spec: $(TEST_TARGET) + $(INSTALL_DIR) $(RELSYSDIR) + $(INSTALL_DATA) crypto.spec $(RELTEST_FILES) $(RELSYSDIR) + chmod -f -R u+w $(RELSYSDIR) + +release_docs_spec: + diff --git a/lib/crypto/test/blowfish_SUITE.erl b/lib/crypto/test/blowfish_SUITE.erl new file mode 100644 index 0000000000..d4cc167ea9 --- /dev/null +++ b/lib/crypto/test/blowfish_SUITE.erl @@ -0,0 +1,210 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +-module(blowfish_SUITE). + +%% Note: This directive should only be used in test suites. +-compile(export_all). + +-include("test_server.hrl"). +-include("test_server_line.hrl"). + +-define(TIMEOUT, 120000). % 2 min + +-define(KEY, to_bin("0123456789ABCDEFF0E1D2C3B4A59687")). +-define(IVEC, to_bin("FEDCBA9876543210")). +%% "7654321 Now is the time for " (includes trailing '\0') +-define(DATA, to_bin("37363534333231204E6F77206973207468652074696D6520666F722000")). +-define(DATA_PADDED, to_bin("37363534333231204E6F77206973207468652074696D6520666F722000000000")). + +%% Test server callback functions +%%-------------------------------------------------------------------- +%% Function: init_per_suite(Config) -> Config +%% Config - [tuple()] +%% A list of key/value pairs, holding the test case configuration. +%% Description: Initialization before the whole suite +%% +%% Note: This function is free to add any key/value pairs to the Config +%% variable, but should NOT alter/remove any existing entries. +%%-------------------------------------------------------------------- +init_per_suite(Config) -> + crypto:start(), + Config. + +%%-------------------------------------------------------------------- +%% Function: end_per_suite(Config) -> _ +%% Config - [tuple()] +%% A list of key/value pairs, holding the test case configuration. +%% Description: Cleanup after the whole suite +%%-------------------------------------------------------------------- +end_per_suite(_Config) -> + crypto:stop(). + +%%-------------------------------------------------------------------- +%% Function: init_per_testcase(TestCase, Config) -> Config +%% Case - atom() +%% Name of the test case that is about to be run. +%% Config - [tuple()] +%% A list of key/value pairs, holding the test case configuration. +%% +%% Description: Initialization before each test case +%% +%% Note: This function is free to add any key/value pairs to the Config +%% variable, but should NOT alter/remove any existing entries. +%% Description: Initialization before each test case +%%-------------------------------------------------------------------- +init_per_testcase(_TestCase, Config0) -> + Config = lists:keydelete(watchdog, 1, Config0), + Dog = test_server:timetrap(?TIMEOUT), + [{watchdog, Dog} | Config]. + +%%-------------------------------------------------------------------- +%% Function: end_per_testcase(TestCase, Config) -> _ +%% Case - atom() +%% Name of the test case that is about to be run. +%% Config - [tuple()] +%% A list of key/value pairs, holding the test case configuration. +%% Description: Cleanup after each test case +%%-------------------------------------------------------------------- +end_per_testcase(_TestCase, Config) -> + Dog = ?config(watchdog, Config), + case Dog of + undefined -> + ok; + _ -> + test_server:timetrap_cancel(Dog) + end. + +%%-------------------------------------------------------------------- +%% Function: all(Clause) -> TestCases +%% Clause - atom() - suite | doc +%% TestCases - [Case] +%% Case - atom() +%% Name of a test case. +%% Description: Returns a list of all test cases in this test suite +%%-------------------------------------------------------------------- +all(doc) -> + ["Test Blowfish functionality"]; + +all(suite) -> + [ecb, + cbc, + cfb64, + ofb64 + ]. + +%% Test cases start here. +%%-------------------------------------------------------------------- + +ecb_test(KeyBytes, ClearBytes, CipherBytes) -> + {Key, Clear, Cipher} = + {to_bin(KeyBytes), to_bin(ClearBytes), to_bin(CipherBytes)}, + crypto:blowfish_ecb_encrypt(Key, Clear) =:= Cipher. + +ecb(doc) -> + "Test that ECB mode is OK"; +ecb(suite) -> + []; +ecb(Config) when is_list(Config) -> + true = ecb_test("0000000000000000", "0000000000000000", "4EF997456198DD78"), + true = ecb_test("FFFFFFFFFFFFFFFF", "FFFFFFFFFFFFFFFF", "51866FD5B85ECB8A"), + true = ecb_test("3000000000000000", "1000000000000001", "7D856F9A613063F2"), + true = ecb_test("1111111111111111", "1111111111111111", "2466DD878B963C9D"), + true = ecb_test("0123456789ABCDEF", "1111111111111111", "61F9C3802281B096"), + true = ecb_test("1111111111111111", "0123456789ABCDEF", "7D0CC630AFDA1EC7"), + true = ecb_test("0000000000000000", "0000000000000000", "4EF997456198DD78"), + true = ecb_test("FEDCBA9876543210", "0123456789ABCDEF", "0ACEAB0FC6A0A28D"), + true = ecb_test("7CA110454A1A6E57", "01A1D6D039776742", "59C68245EB05282B"), + true = ecb_test("0131D9619DC1376E", "5CD54CA83DEF57DA", "B1B8CC0B250F09A0"), + true = ecb_test("07A1133E4A0B2686", "0248D43806F67172", "1730E5778BEA1DA4"), + true = ecb_test("3849674C2602319E", "51454B582DDF440A", "A25E7856CF2651EB"), + true = ecb_test("04B915BA43FEB5B6", "42FD443059577FA2", "353882B109CE8F1A"), + true = ecb_test("0113B970FD34F2CE", "059B5E0851CF143A", "48F4D0884C379918"), + true = ecb_test("0170F175468FB5E6", "0756D8E0774761D2", "432193B78951FC98"), + true = ecb_test("43297FAD38E373FE", "762514B829BF486A", "13F04154D69D1AE5"), + true = ecb_test("07A7137045DA2A16", "3BDD119049372802", "2EEDDA93FFD39C79"), + true = ecb_test("04689104C2FD3B2F", "26955F6835AF609A", "D887E0393C2DA6E3"), + true = ecb_test("37D06BB516CB7546", "164D5E404F275232", "5F99D04F5B163969"), + true = ecb_test("1F08260D1AC2465E", "6B056E18759F5CCA", "4A057A3B24D3977B"), + true = ecb_test("584023641ABA6176", "004BD6EF09176062", "452031C1E4FADA8E"), + true = ecb_test("025816164629B007", "480D39006EE762F2", "7555AE39F59B87BD"), + true = ecb_test("49793EBC79B3258F", "437540C8698F3CFA", "53C55F9CB49FC019"), + true = ecb_test("4FB05E1515AB73A7", "072D43A077075292", "7A8E7BFA937E89A3"), + true = ecb_test("49E95D6D4CA229BF", "02FE55778117F12A", "CF9C5D7A4986ADB5"), + true = ecb_test("018310DC409B26D6", "1D9D5C5018F728C2", "D1ABB290658BC778"), + true = ecb_test("1C587F1C13924FEF", "305532286D6F295A", "55CB3774D13EF201"), + true = ecb_test("0101010101010101", "0123456789ABCDEF", "FA34EC4847B268B2"), + true = ecb_test("1F1F1F1F0E0E0E0E", "0123456789ABCDEF", "A790795108EA3CAE"), + true = ecb_test("E0FEE0FEF1FEF1FE", "0123456789ABCDEF", "C39E072D9FAC631D"), + true = ecb_test("0000000000000000", "FFFFFFFFFFFFFFFF", "014933E0CDAFF6E4"), + true = ecb_test("FFFFFFFFFFFFFFFF", "0000000000000000", "F21E9A77B71C49BC"), + true = ecb_test("0123456789ABCDEF", "0000000000000000", "245946885754369A"), + true = ecb_test("FEDCBA9876543210", "FFFFFFFFFFFFFFFF", "6B5C5A9C5D9E0A5A"), + ok. + +cbc(doc) -> + "Test that CBC mode is OK"; +cbc(suite) -> + []; +cbc(Config) when is_list(Config) -> + true = crypto:blowfish_cbc_encrypt(?KEY, ?IVEC, ?DATA_PADDED) =:= + to_bin("6B77B4D63006DEE605B156E27403979358DEB9E7154616D959F1652BD5FF92CC"), + ok. + +cfb64(doc) -> + "Test that CFB64 mode is OK"; +cfb64(suite) -> + []; +cfb64(Config) when is_list(Config) -> + true = crypto:blowfish_cfb64_encrypt(?KEY, ?IVEC, ?DATA) =:= + to_bin("E73214A2822139CAF26ECF6D2EB9E76E3DA3DE04D1517200519D57A6C3"), + ok. + +ofb64(doc) -> + "Test that OFB64 mode is OK"; +ofb64(suite) -> + []; +ofb64(Config) when is_list(Config) -> + true = crypto:blowfish_ofb64_encrypt(?KEY, ?IVEC, ?DATA) =:= + to_bin("E73214A2822139CA62B343CC5B65587310DD908D0C241B2263C2CF80DA"), + ok. + +%% Helper functions + +%% Convert a hexadecimal string to a binary. +-spec(to_bin(L::string()) -> binary()). +to_bin(L) -> + to_bin(L, []). + +%% @spec dehex(char()) -> integer() +%% @doc Convert a hex digit to its integer value. +-spec(dehex(char()) -> integer()). +dehex(C) when C >= $0, C =< $9 -> + C - $0; +dehex(C) when C >= $a, C =< $f -> + C - $a + 10; +dehex(C) when C >= $A, C =< $F -> + C - $A + 10. + +-spec(to_bin(L::string(), list()) -> binary()). +to_bin([], Acc) -> + iolist_to_binary(lists:reverse(Acc)); +to_bin([C1, C2 | Rest], Acc) -> + to_bin(Rest, [(dehex(C1) bsl 4) bor dehex(C2) | Acc]). diff --git a/lib/crypto/test/crypto.spec b/lib/crypto/test/crypto.spec new file mode 100644 index 0000000000..7ba5696189 --- /dev/null +++ b/lib/crypto/test/crypto.spec @@ -0,0 +1,2 @@ +{topcase, {dir, "../crypto_test"}}. + diff --git a/lib/crypto/test/crypto_SUITE.erl b/lib/crypto/test/crypto_SUITE.erl new file mode 100644 index 0000000000..290ef19160 --- /dev/null +++ b/lib/crypto/test/crypto_SUITE.erl @@ -0,0 +1,1110 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1999-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +-module(crypto_SUITE). + +-include("test_server.hrl"). +-include("test_server_line.hrl"). + +-export([all/1, + init_per_testcase/2, + fin_per_testcase/2, + info/1, + link_test/1, + md5/1, + md5_update/1, + md4/1, + md4_update/1, + sha/1, + sha_update/1, + sha256/1, + sha256_update/1, + sha512/1, + sha512_update/1, + md5_mac/1, + md5_mac_io/1, + des_cbc/1, + des_cbc_iter/1, + aes_cfb/1, + aes_cbc/1, + aes_cbc_iter/1, + mod_exp_test/1, + rand_uniform_test/1, + rsa_verify_test/1, + dsa_verify_test/1, + rsa_sign_test/1, + dsa_sign_test/1, + rsa_encrypt_decrypt/1, + dh/1, + exor_test/1, + rc4_test/1, + blowfish_cfb64/1, + smp/1, + cleanup/1]). + +-export([hexstr2bin/1]). + +all(suite) -> + [link_test, + {conf,info,[md5, + md5_update, + md4, + md4_update, + md5_mac, + md5_mac_io, + sha, + sha_update, +%% sha256, +%% sha256_update, +%% sha512, +%% sha512_update, + des_cbc, + aes_cfb, + aes_cbc, + aes_cbc_iter, + des_cbc_iter, + rand_uniform_test, + rsa_verify_test, + dsa_verify_test, + rsa_sign_test, + dsa_sign_test, + rsa_encrypt_decrypt, + dh, + exor_test, + rc4_test, + mod_exp_test, + blowfish_cfb64, + smp], + cleanup}]. + +init_per_testcase(_Name,Config) -> + io:format("init_per_testcase\n"), + ?line crypto:start(), + Config. + +fin_per_testcase(_Name,Config) -> + io:format("fin_per_testcase\n"), + ?line crypto:stop(), + Config. + +%% +%% +link_test(doc) -> + ["Test that the library is statically linked to libcrypto.a."]; +link_test(suite) -> + []; +link_test(Config) when is_list(Config) -> + ?line case os:type() of + {unix,darwin} -> {skipped,"Darwin cannot link statically"}; + {unix,_} -> link_test_1(); + _ -> {skip,"Only runs on Unix"} + end. + +link_test_1() -> + ?line CryptoPriv = code:priv_dir(crypto), + ?line Wc = filename:join([CryptoPriv,"lib","crypto_drv.*"]), + ?line case filelib:wildcard(Wc) of + [] -> {skip,"Didn't find the crypto driver"}; + [Drv] -> link_test_2(Drv) + end. + +link_test_2(Drv) -> + case ldd_program() of + none -> + {skip,"No ldd-like program found"}; + Ldd -> + Cmd = Ldd ++ " " ++ Drv, + Libs = os:cmd(Cmd), + io:format("~p\n", [Libs]), + case string:str(Libs, "libcrypto") of + 0 -> ok; + _ -> + case ?t:is_commercial() of + true -> + ?t:fail({libcrypto,not_statically_linked}); + false -> + {comment,"Not statically linked (OK for open-source platform)"} + end + end + end. + +ldd_program() -> + case os:find_executable("ldd") of + false -> + case os:type() of + {unix,darwin} -> + case os:find_executable("otool") of + false -> none; + Otool -> Otool ++ " -L" + end + end; + Ldd when is_list(Ldd) -> Ldd + end. + +%% +%% +info(doc) -> + ["Call the info function."]; +info(suite) -> + []; +info(Config) when is_list(Config) -> + case {code:lib_dir(crypto),?t:is_commercial()} of + {{error,bad_name},false} -> + {skip,"Missing crypto application"}; + {_,_} -> + ?line crypto:start(), + ?line crypto:info(), + ?line InfoLib = crypto:info_lib(), + ?line [_|_] = InfoLib, + F = fun([{Name,VerN,VerS}|T],Me) -> + ?line true = is_binary(Name), + ?line true = is_integer(VerN), + ?line true = is_binary(VerS), + Me(T,Me); + ([],_) -> + ok + end, + ?line F(InfoLib,F), + ?line crypto:stop() + end. + +cleanup(doc) -> + ["Cleanup (dummy)."]; +cleanup(suite) -> + []; +cleanup(Config) when is_list(Config) -> + Config. + +%% +%% +md5(doc) -> + ["Generate MD5 message digests and check the result. Examples are " + "from RFC-1321."]; +md5(suite) -> + []; +md5(Config) when is_list(Config) -> + ?line m(crypto:md5(""), + hexstr2bin("d41d8cd98f00b204e9800998ecf8427e")), + ?line m(crypto:md5("a"), + hexstr2bin("0cc175b9c0f1b6a831c399e269772661")), + ?line m(crypto:md5("abc"), + hexstr2bin("900150983cd24fb0d6963f7d28e17f72")), + ?line m(crypto:md5("message digest"), + hexstr2bin("f96b697d7cb7938d525a2f31aaf161d0")), + ?line m(crypto:md5("abcdefghijklmnopqrstuvwxyz"), + hexstr2bin("c3fcd3d76192e4007dfb496cca67e13b")), + ?line m(crypto:md5("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" + "0123456789"), + hexstr2bin("d174ab98d277d9f5a5611c2c9f419d9f")), + ?line m(crypto:md5("12345678901234567890123456789012345678901234567890" + "123456789012345678901234567890"), + hexstr2bin("57edf4a22be3c955ac49da2e2107b67a")). + +%% +%% +md5_update(doc) -> + ["Generate MD5 message using md5_init, md5_update, and md5_final, and" + "check the result. Examples are from RFC-1321."]; +md5_update(suite) -> + []; +md5_update(Config) when is_list(Config) -> + ?line Ctx = crypto:md5_init(), + ?line Ctx1 = crypto:md5_update(Ctx, "ABCDEFGHIJKLMNOPQRSTUVWXYZ"), + ?line Ctx2 = crypto:md5_update(Ctx1, "abcdefghijklmnopqrstuvwxyz" + "0123456789"), + ?line m(crypto:md5_final(Ctx2), + hexstr2bin("d174ab98d277d9f5a5611c2c9f419d9f")). + +%% +%% +md4(doc) -> + ["Generate MD4 message digests and check the result. Examples are " + "from RFC-1321."]; +md4(suite) -> + []; +md4(Config) when is_list(Config) -> + ?line m(crypto:md4(""), + hexstr2bin("31d6cfe0d16ae931b73c59d7e0c089c0")), + ?line m(crypto:md4("a"), + hexstr2bin("bde52cb31de33e46245e05fbdbd6fb24")), + ?line m(crypto:md4("abc"), + hexstr2bin("a448017aaf21d8525fc10ae87aa6729d")), + ?line m(crypto:md4("message digest"), + hexstr2bin("d9130a8164549fe818874806e1c7014b")), + ?line m(crypto:md4("abcdefghijklmnopqrstuvwxyz"), + hexstr2bin("d79e1c308aa5bbcdeea8ed63df412da9")), + ?line m(crypto:md4("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" + "0123456789"), + hexstr2bin("043f8582f241db351ce627e153e7f0e4")), + ?line m(crypto:md4("12345678901234567890123456789012345678901234567890" + "123456789012345678901234567890"), + hexstr2bin("e33b4ddc9c38f2199c3e7b164fcc0536")). + +%% +%% +md4_update(doc) -> + ["Generate MD5 message using md5_init, md5_update, and md5_final, and" + "check the result. Examples are from RFC-1321."]; +md4_update(suite) -> + []; +md4_update(Config) when is_list(Config) -> + ?line Ctx = crypto:md4_init(), + ?line Ctx1 = crypto:md4_update(Ctx, "ABCDEFGHIJKLMNOPQRSTUVWXYZ"), + ?line Ctx2 = crypto:md4_update(Ctx1, "abcdefghijklmnopqrstuvwxyz" + "0123456789"), + ?line m(crypto:md4_final(Ctx2), + hexstr2bin("043f8582f241db351ce627e153e7f0e4")). + +%% +%% +sha(doc) -> + ["Generate SHA message digests and check the result. Examples are " + "from FIPS-180-1."]; +sha(suite) -> + []; +sha(Config) when is_list(Config) -> + ?line m(crypto:sha("abc"), + hexstr2bin("A9993E364706816ABA3E25717850C26C9CD0D89D")), + ?line m(crypto:sha("abcdbcdecdefdefgefghfghighijhijkijkljklmklm" + "nlmnomnopnopq"), + hexstr2bin("84983E441C3BD26EBAAE4AA1F95129E5E54670F1")). + + +%% +%% +sha_update(doc) -> + ["Generate SHA message digests by using sha_init, sha_update, and" + "sha_final, and check the result. Examples are from FIPS-180-1."]; +sha_update(suite) -> + []; +sha_update(Config) when is_list(Config) -> + ?line Ctx = crypto:sha_init(), + ?line Ctx1 = crypto:sha_update(Ctx, "abcdbcdecdefdefgefghfghighi"), + ?line Ctx2 = crypto:sha_update(Ctx1, "jhijkijkljklmklmnlmnomnopnopq"), + ?line m(crypto:sha_final(Ctx2), + hexstr2bin("84983E441C3BD26EBAAE4AA1F95129E5E54670F1")). + +%% +%% +sha256(doc) -> + ["Generate SHA-256 message digests and check the result. Examples are " + "from rfc-4634."]; +sha256(suite) -> + []; +sha256(Config) when is_list(Config) -> + ?line m(crypto:sha256("abc"), + hexstr2bin("BA7816BF8F01CFEA4141" + "40DE5DAE2223B00361A396177A9CB410FF61F20015AD")), + ?line m(crypto:sha256("abcdbcdecdefdefgefghfghighijhijkijkljklmklm" + "nlmnomnopnopq"), + hexstr2bin("248D6A61D20638B8" + "E5C026930C3E6039A33CE45964FF2167F6ECEDD419DB06C1")). + +%% +%% +sha256_update(doc) -> + ["Generate SHA256 message digests by using sha256_init, sha256_update, and" + "sha256_final, and check the result. Examples are from rfc-4634."]; +sha256_update(suite) -> + []; +sha256_update(Config) when is_list(Config) -> + ?line Ctx = crypto:sha256_init(), + ?line Ctx1 = crypto:sha256_update(Ctx, "abcdbcdecdefdefgefghfghighi"), + ?line Ctx2 = crypto:sha256_update(Ctx1, "jhijkijkljklmklmnlmnomnopnopq"), + ?line m(crypto:sha256_final(Ctx2), + hexstr2bin("248D6A61D20638B8" + "E5C026930C3E6039A33CE45964FF2167F6ECEDD419DB06C1")). + + +%% +%% +sha512(doc) -> + ["Generate SHA-512 message digests and check the result. Examples are " + "from rfc-4634."]; +sha512(suite) -> + []; +sha512(Config) when is_list(Config) -> + ?line m(crypto:sha512("abc"), + hexstr2bin("DDAF35A193617ABACC417349AE20413112E6FA4E89A97EA2" + "0A9EEEE64B55D39A2192992A274FC1A836BA3C23A3FEEBBD" + "454D4423643CE80E2A9AC94FA54CA49F")), + ?line m(crypto:sha512("abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn" + "hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"), + hexstr2bin("8E959B75DAE313DA8CF4F72814FC143F8F7779C6EB9F7FA1" + "7299AEADB6889018501D289E4900F7E4331B99DEC4B5433A" + "C7D329EEB6DD26545E96E55B874BE909")). + +%% +%% +sha512_update(doc) -> + ["Generate SHA512 message digests by using sha512_init, sha512_update, and" + "sha512_final, and check the result. Examples are from rfc=4634."]; +sha512_update(suite) -> + []; +sha512_update(Config) when is_list(Config) -> + ?line Ctx = crypto:sha512_init(), + ?line Ctx1 = crypto:sha512_update(Ctx, "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn"), + ?line Ctx2 = crypto:sha512_update(Ctx1, "hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"), + ?line m(crypto:sha512_final(Ctx2), + hexstr2bin("8E959B75DAE313DA8CF4F72814FC143F8F7779C6EB9F7FA1" + "7299AEADB6889018501D289E4900F7E4331B99DEC4B5433A" + "C7D329EEB6DD26545E96E55B874BE909")). + +%% +%% +md5_mac(doc) -> + ["Generate some HMACs, using MD5, and check the result. Examples are " + "from RFC-2104."]; +md5_mac(suite) -> + []; +md5_mac(Config) when is_list(Config) -> + ?line m(crypto:md5_mac(hexstr2bin("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"), + "Hi There"), + hexstr2bin("9294727a3638bb1c13f48ef8158bfc9d")), + ?line m(crypto:md5_mac(list_to_binary("Jefe"), + "what do ya want for nothing?"), + hexstr2bin("750c783e6ab0b503eaa86e310a5db738")), + ?line m(crypto:md5_mac(hexstr2bin("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"), + hexstr2bin("DDDDDDDDDDDDDDDDDDDD" + "DDDDDDDDDDDDDDDDDDDD" + "DDDDDDDDDDDDDDDDDDDD" + "DDDDDDDDDDDDDDDDDDDD" + "DDDDDDDDDDDDDDDDDDDD")), + hexstr2bin("56be34521d144c88dbb8c733f0e8b3f6")). + +%% +%% +md5_mac_io(doc) -> + ["Generate some HMACs, using MD5, with Key an IO-list, and check the " + "result. Examples are from RFC-2104."]; +md5_mac_io(suite) -> + []; +md5_mac_io(Config) when is_list(Config) -> + ?line Key1 = hexstr2bin("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"), + ?line {B11, B12} = split_binary(Key1, 4), + ?line Key11 = [B11,binary_to_list(B12)], + ?line m(crypto:md5_mac(Key11, "Hi There"), + hexstr2bin("9294727a3638bb1c13f48ef8158bfc9d")). + +%% +%% +des_cbc(doc) -> + "Encrypt and decrypt according to CBC DES. and check the result. " + "Example are from FIPS-81."; +des_cbc(suite) -> + []; +des_cbc(Config) when is_list(Config) -> + ?line Key = hexstr2bin("0123456789abcdef"), + ?line IVec = hexstr2bin("1234567890abcdef"), + ?line Plain = "Now is the time for all ", + ?line Cipher = crypto:des_cbc_encrypt(Key, IVec, Plain), + ?line m(Cipher, hexstr2bin("e5c7cdde872bf27c43e934008c389c" + "0f683788499a7c05f6")), + ?line m(list_to_binary(Plain), + crypto:des_cbc_decrypt(Key, IVec, Cipher)), + ?line Plain2 = "7654321 Now is the time for " ++ [0, 0, 0, 0], + ?line Cipher2 = crypto:des_cbc_encrypt(Key, IVec, Plain2), + ?line m(Cipher2, hexstr2bin("b9916b8ee4c3da64b4f44e3cbefb9" + "9484521388fa59ae67d58d2e77e86062733")), + ?line m(list_to_binary(Plain2), + crypto:des_cbc_decrypt(Key, IVec, Cipher2)). + +%% +%% +des_cbc_iter(doc) -> + "Encrypt and decrypt according to CBC DES in two steps, and " + "check the result. Example are from FIPS-81."; +des_cbc_iter(suite) -> + []; +des_cbc_iter(Config) when is_list(Config) -> + ?line Key = hexstr2bin("0123456789abcdef"), + ?line IVec = hexstr2bin("1234567890abcdef"), + ?line Plain1 = "Now is the time ", + ?line Plain2 = "for all ", + ?line Cipher1 = crypto:des_cbc_encrypt(Key, IVec, Plain1), + ?line IVec2 = crypto:des_cbc_ivec(Cipher1), + ?line Cipher2 = crypto:des_cbc_encrypt(Key, IVec2, Plain2), + ?line Cipher = concat_binary([Cipher1, Cipher2]), + ?line m(Cipher, hexstr2bin("e5c7cdde872bf27c43e934008c389c" + "0f683788499a7c05f6")). + +%% +%% +aes_cfb(doc) -> + "Encrypt and decrypt according to AES CFB 128 bit and check " + "the result. Example are from NIST SP 800-38A."; + +aes_cfb(suite) -> + []; +aes_cfb(Config) when is_list(Config) -> + +%% Sample data from NIST Spec.Publ. 800-38A +%% F.3.13 CFB128-AES128.Encrypt +%% Key 2b7e151628aed2a6abf7158809cf4f3c +%% IV 000102030405060708090a0b0c0d0e0f +%% Segment #1 +%% Input Block 000102030405060708090a0b0c0d0e0f +%% Output Block 50fe67cc996d32b6da0937e99bafec60 +%% Plaintext 6bc1bee22e409f96e93d7e117393172a +%% Ciphertext 3b3fd92eb72dad20333449f8e83cfb4a +%% Segment #2 +%% Input Block 3b3fd92eb72dad20333449f8e83cfb4a +%% Output Block 668bcf60beb005a35354a201dab36bda +%% Plaintext ae2d8a571e03ac9c9eb76fac45af8e51 +%% Ciphertext c8a64537a0b3a93fcde3cdad9f1ce58b +%% Segment #3 +%% Input Block c8a64537a0b3a93fcde3cdad9f1ce58b +%% Output Block 16bd032100975551547b4de89daea630 +%% Plaintext 30c81c46a35ce411e5fbc1191a0a52ef +%% Ciphertext 26751f67a3cbb140b1808cf187a4f4df +%% Segment #4 +%% Input Block 26751f67a3cbb140b1808cf187a4f4df +%% Output Block 36d42170a312871947ef8714799bc5f6 +%% Plaintext f69f2445df4f9b17ad2b417be66c3710 +%% Ciphertext c04b05357c5d1c0eeac4c66f9ff7f2e6 + + ?line Key = hexstr2bin("2b7e151628aed2a6abf7158809cf4f3c"), + ?line IVec = hexstr2bin("000102030405060708090a0b0c0d0e0f"), + ?line Plain = hexstr2bin("6bc1bee22e409f96e93d7e117393172a"), + ?line Cipher = crypto:aes_cfb_128_encrypt(Key, IVec, Plain), + ?line m(Cipher, hexstr2bin("3b3fd92eb72dad20333449f8e83cfb4a")), + ?line m(Plain, + crypto:aes_cfb_128_decrypt(Key, IVec, Cipher)). + +%% +%% +aes_cbc(doc) -> + "Encrypt and decrypt according to AES CBC 128 bit. and check the result. " + "Example are from NIST SP 800-38A."; + +aes_cbc(suite) -> + []; +aes_cbc(Config) when is_list(Config) -> + +%% Sample data from NIST Spec.Publ. 800-38A +%% F.2.1 CBC-AES128.Encrypt +%% Key 2b7e151628aed2a6abf7158809cf4f3c +%% IV 000102030405060708090a0b0c0d0e0f +%% Block #1 +%% Plaintext 6bc1bee22e409f96e93d7e117393172a +%% Input Block 6bc0bce12a459991e134741a7f9e1925 +%% Output Block 7649abac8119b246cee98e9b12e9197d +%% Ciphertext 7649abac8119b246cee98e9b12e9197d +%% Block #2 +%% Plaintext ae2d8a571e03ac9c9eb76fac45af8e51 +%% Input Block d86421fb9f1a1eda505ee1375746972c +%% Output Block 5086cb9b507219ee95db113a917678b2 +%% Ciphertext 5086cb9b507219ee95db113a917678b2 +%% Block #3 +%% Plaintext 30c81c46a35ce411e5fbc1191a0a52ef +%% Input Block 604ed7ddf32efdff7020d0238b7c2a5d +%% Output Block 73bed6b8e3c1743b7116e69e22229516 +%% Ciphertext 73bed6b8e3c1743b7116e69e22229516 +%% Block #4 +%% Plaintext f69f2445df4f9b17ad2b417be66c3710 +%% Input Block 8521f2fd3c8eef2cdc3da7e5c44ea206 +%% Output Block 3ff1caa1681fac09120eca307586e1a7 +%% Ciphertext 3ff1caa1681fac09120eca307586e1a7 +%% +%% F.2.2 CBC-AES128.Decrypt +%% Key 2b7e151628aed2a6abf7158809cf4f3c +%% IV 000102030405060708090a0b0c0d0e0f + %% Block #1 +%% Ciphertext 7649abac8119b246cee98e9b12e9197d +%% Input Block 7649abac8119b246cee98e9b12e9197d +%% Output Block 6bc0bce12a459991e134741a7f9e1925 +%% Plaintext 6bc1bee22e409f96e93d7e117393172a +%% Block #2 +%% Ciphertext 5086cb9b507219ee95db113a917678b2 +%% Input Block 5086cb9b507219ee95db113a917678b2 +%% Output Block d86421fb9f1a1eda505ee1375746972c +%% Plaintext ae2d8a571e03ac9c9eb76fac45af8e51 +%% Block #3 +%% Ciphertext 73bed6b8e3c1743b7116e69e22229516 +%% Input Block 73bed6b8e3c1743b7116e69e22229516 +%% Output Block 604ed7ddf32efdff7020d0238b7c2a5d +%% Plaintext 30c81c46a35ce411e5fbc1191a0a52ef +%% Block #4 +%% Ciphertext 3ff1caa1681fac09120eca307586e1a7 +%% Input Block 3ff1caa1681fac09120eca307586e1a7 +%% Output Block 8521f2fd3c8eef2cdc3da7e5c44ea206 +%% Plaintext f69f2445df4f9b17ad2b417be66c3710 + + ?line Key = hexstr2bin("2b7e151628aed2a6abf7158809cf4f3c"), + ?line IVec = hexstr2bin("000102030405060708090a0b0c0d0e0f"), + ?line Plain = hexstr2bin("6bc1bee22e409f96e93d7e117393172a"), + ?line Cipher = crypto:aes_cbc_128_encrypt(Key, IVec, Plain), + ?line m(Cipher, hexstr2bin("7649abac8119b246cee98e9b12e9197d")), + ?line m(Plain, + crypto:aes_cbc_128_decrypt(Key, IVec, Cipher)). + +aes_cbc_iter(doc) -> + "Encrypt and decrypt according to CBC AES in steps"; +aes_cbc_iter(suite) -> []; +aes_cbc_iter(Config) when is_list(Config) -> + Key = list_to_binary(lists:seq(255,256-16*17,-17)), + IVec = list_to_binary(lists:seq(1,16*7,7)), + Plain = <<"One, two, three o'clock, four o'clock, rock" + "Five, six, seven o'clock, eight o'clock, rock" + "Nine, ten, eleven o'clock, twelve o'clock, rock" + "We're gonna rock around the clock tonight">>, + ?line 0 = size(Plain) rem 16, + + ?line Cipher = crypto:aes_cbc_128_encrypt(Key, IVec, Plain), + ?line Plain = crypto:aes_cbc_128_decrypt(Key, IVec, Cipher), + + ?line Cipher = aes_cbc_encrypt_iter(Key,IVec,Plain,<<>>), + ?line Plain = aes_cbc_decrypt_iter(Key,IVec,Cipher,<<>>), + ok. + +aes_cbc_encrypt_iter(_,_,<<>>, Acc) -> + Acc; +aes_cbc_encrypt_iter(Key,IVec,Data, Acc) -> + Bytes = 16 * (1 + size(Data) div (16*3)), + <<Chunk:Bytes/binary, Rest/binary>> = Data, + %%io:format("encrypt iter Chunk=~p Rest=~p\n",[Chunk,Rest]), + ?line Cipher = crypto:aes_cbc_128_encrypt(Key, IVec, Chunk), + ?line IVec2 = crypto:aes_cbc_ivec(Cipher), + aes_cbc_encrypt_iter(Key,IVec2,Rest, <<Acc/binary, Cipher/binary>>). + +aes_cbc_decrypt_iter(_,_,<<>>, Acc) -> + Acc; +aes_cbc_decrypt_iter(Key,IVec,Data, Acc) -> + Bytes = 16 * (1 + size(Data) div (16*5)), + <<Chunk:Bytes/binary, Rest/binary>> = Data, + %%io:format("decrypt iter Chunk=~p Rest=~p\n",[Chunk,Rest]), + ?line Plain = crypto:aes_cbc_128_decrypt(Key, IVec, Chunk), + ?line IVec2 = crypto:aes_cbc_ivec(Chunk), + aes_cbc_decrypt_iter(Key,IVec2,Rest, <<Acc/binary, Plain/binary>>). + + +%% +%% +mod_exp_test(doc) -> + "mod_exp testing (A ^ M % P with bignums)"; +mod_exp_test(suite) -> + []; +mod_exp_test(Config) when is_list(Config) -> + mod_exp_aux_test(2, 5, 10, 8). + +mod_exp_aux_test(_, _, _, 0) -> + ok; +mod_exp_aux_test(B, E, M, N) -> + ?line R1 = crypto:mod_exp(B, E, M), + ?line R2 = ipow(B, E, M), + ?line m(R1, R2), + ?line mod_exp_aux_test(B, E*E+1, M*M+1, N-1). + +%% +%% +rand_uniform_test(doc) -> + "rand_uniform and random_bytes testing"; +rand_uniform_test(suite) -> + []; +rand_uniform_test(Config) when is_list(Config) -> + rand_uniform_aux_test(10), + ?line 10 = size(crypto:rand_bytes(10)). + +rand_uniform_aux_test(0) -> + ok; +rand_uniform_aux_test(N) -> + ?line L = N*1000, + ?line H = N*100000+1, + ?line R1 = crypto:rand_uniform(L, H), + ?line t(R1 >= L), + ?line t(R1 < H), + ?line rand_uniform_aux_test(N-1). + +%% +%% +%% +%% +rsa_verify_test(doc) -> + "rsa_verify testing (A ^ M % P with bignums)"; +rsa_verify_test(suite) -> + []; +rsa_verify_test(Config) when is_list(Config) -> + ?line H = <<178,28,54,104,36,80,144,66,140,201,135,17,36,97,114,124, + 194,164,172,147>>, + ?line SigBlob = <<153,44,121,71,132,1,192,159,78,33,29,62,153,64,191,70, + 208,239,166,208,220,167,49,111,128,67,91,253,24,63,194,241, + 97,157,135,226,121,162,150,156,60,49,236,90,151,67,239,23, + 92,103,89,254,17,165,78,181,64,128,13,210,86,111,209,76, + 115,34,107,227,151,47,80,185,143,85,202,55,245,163,226,26, + 139,104,196,6,96,82,108,197,13,0,12,70,153,109,107,180, + 130,246,156,182,56,96,31,220,227,218,136,211,252,43,8,14, + 145,155,191,206,72,194,80,52,54,206,53,27,6,188,195,29>>, + ?line BadSigBlob = <<153,44,121,71,132,1,192,159,78,33,29,62,153,64,191,70, + 208,239,166,208,220,167,49,111,128,67,91,253,24,63,194,241, + 97,157,135,226,121,162,150,156,60,49,236,90,151,67,239,23, + 92,103,89,254,17,165,78,181,64,128,13,210,86,111,209,76, + 115,107,34,227,151,47,80,185,143,85,202,55,245,163,226,26, + 139,104,196,6,96,82,108,197,13,0,12,70,153,109,107,180, + 130,246,156,182,56,96,31,220,227,218,136,211,252,43,8,14, + 145,155,191,206,72,194,80,52,54,206,53,27,6,188,195,29>>, + ?line E = <<35>>, + ?line N = <<0,199,209,142,191,86,92,148,103,37,250,217,175,169,109,10, + 130,139,34,237,174,90,97,118,7,185,57,137,252,236,177,193, + 228,16,62,29,153,144,64,207,152,240,152,206,136,89,64,6, + 3,187,89,57,241,219,88,215,75,70,120,20,145,229,37,1, + 67,138,204,17,39,231,249,239,116,142,169,99,149,41,65,123, + 26,225,133,0,41,85,77,181,35,100,162,223,92,220,207,50, + 63,168,193,171,174,199,23,214,201,63,157,76,125,6,54,73, + 76,89,40,33,147,208,189,76,98,24,61,8,10,110,165,119,165>>, + ?line Nbad = <<0,199,209,142,191,86,92,148,103,37,250,217,175,169,109,10, + 130,139,34,237,174,90,97,118,7,185,57,137,252,236,177,193, + 228,16,62,29,153,144,64,207,152,240,152,206,136,89,64,6, + 3,187,89,57,241,219,88,215,75,70,120,20,145,229,37,1, + 67,138,204,17,39,231,249,239,116,142,169,99,149,41,65,123, + 26,225,133,0,41,85,77,181,35,100,162,223,92,220,207,50, + 63,168,193,171,174,199,23,214,201,63,157,76,125,6,54,73, + 76,89,40,33,147,189,208,76,98,24,61,8,10,110,165,119,165>>, + ?line Ebad = <<77>>, + ?line m(crypto:rsa_verify(sized_binary(H), sized_binary(SigBlob), + [sized_binary(E), sized_binary(N)]), true), + ?line m(crypto:rsa_verify(sized_binary(H), sized_binary(SigBlob), + [sized_binary(Ebad), sized_binary(N)]), false), + ?line m(crypto:rsa_verify(sized_binary(H), sized_binary(SigBlob), + [sized_binary(E), sized_binary(Nbad)]), false), + ?line m(crypto:rsa_verify(sized_binary(H), sized_binary(BadSigBlob), + [sized_binary(E), sized_binary(N)]), false). + +%% +%% +dsa_verify_test(doc) -> + "dsa_verify testing (A ^ M % P with bignums)"; +dsa_verify_test(suite) -> + []; +dsa_verify_test(Config) when is_list(Config) -> + ?line Msg = <<48,130,2,245,160,3,2,1,2,2,1,1,48,9,6,7,42,134,72,206,56,4,3,48, + 58,49,11,48,9,6,3,85,4,6,19,2,85,83,49,26,48,24,6,3,85,4,10,19,17, + 84,101,115,116,32,67,101,114,116,105,102,105,99,97,116,101,115,49, + 15,48,13,6,3,85,4,3,19,6,68,83,65,32,67,65,48,30,23,13,48,49,48, + 52,49,57,49,52,53,55,50,48,90,23,13,49,49,48,52,49,57,49,52,53,55, + 50,48,90,48,93,49,11,48,9,6,3,85,4,6,19,2,85,83,49,26,48,24,6,3, + 85,4,10,19,17,84,101,115,116,32,67,101,114,116,105,102,105,99,97, + 116,101,115,49,50,48,48,6,3,85,4,3,19,41,86,97,108,105,100,32,68, + 83,65,32,83,105,103,110,97,116,117,114,101,115,32,69,69,32,67,101, + 114,116,105,102,105,99,97,116,101,32,84,101,115,116,52,48,130,1, + 182,48,130,1,43,6,7,42,134,72,206,56,4,1,48,130,1,30,2,129,129,0, + 228,139,175,64,140,21,215,61,124,238,3,150,18,104,193,32,5,232,23, + 202,158,116,101,75,154,84,151,42,120,51,218,165,197,114,234,52, + 179,148,104,66,213,27,253,119,240,168,66,158,100,147,144,182,194, + 2,49,70,19,122,3,105,204,152,45,86,157,94,35,95,40,191,173,127,15, + 208,105,149,98,92,26,7,42,94,140,115,73,126,253,18,34,142,85,229, + 86,233,174,114,41,150,135,8,39,215,119,67,240,134,184,9,10,27,20, + 165,230,3,230,69,121,77,233,250,83,95,193,9,189,126,197,195,2,21, + 0,128,63,228,252,243,76,229,62,203,15,23,10,42,84,108,208,103,108, + 13,59,2,129,128,102,212,22,138,32,173,254,209,50,159,165,127,167, + 179,208,234,119,63,235,108,162,228,41,216,216,188,33,221,154,247, + 204,229,180,119,77,223,236,218,162,140,156,117,18,90,31,254,102, + 211,17,194,239,132,67,236,169,136,110,76,186,76,63,53,150,199,103, + 252,153,189,15,153,41,19,145,78,216,2,174,254,107,175,80,86,170, + 47,30,181,42,200,238,34,71,37,120,107,33,221,20,63,206,240,16,129, + 247,150,29,156,65,187,94,68,146,93,46,198,30,184,205,105,200,143, + 63,59,62,208,79,162,206,217,3,129,132,0,2,129,128,15,83,40,172,56, + 47,61,243,17,97,65,195,61,167,214,122,247,246,1,50,211,33,113,16, + 20,213,195,62,77,235,25,162,140,175,158,8,61,65,10,255,204,162,71, + 130,122,86,161,163,253,236,178,139,183,57,181,202,160,25,133,130, + 155,150,104,168,187,107,186,144,164,225,173,101,182,68,49,210,30, + 34,47,83,65,79,250,156,248,47,232,44,67,36,22,126,43,216,100,247, + 100,250,240,121,72,29,185,2,109,144,54,204,235,54,15,242,57,171, + 125,39,236,247,71,111,221,51,196,126,77,238,36,87,163,107,48,105, + 48,29,6,3,85,29,14,4,22,4,20,179,51,215,81,162,4,13,68,251,157,64, + 241,18,98,113,176,83,246,105,13,48,31,6,3,85,29,35,4,24,48,22,128, + 20,116,21,213,36,28,189,94,101,136,31,225,139,9,126,127,234,25,72, + 78,97,48,23,6,3,85,29,32,4,16,48,14,48,12,6,10,96,134,72,1,101,3, + 2,1,48,1,48,14,6,3,85,29,15,1,1,255,4,4,3,2,6,192>>, + + ?line SigBlob = <<48,45,2,21,0,140,167,200,210,153,212,64,155,249,33,146,104,243, + 39,38,9,115,162,89,24,2,20,76,254,31,128,187,48,128,215,216, + 112,198,78,118,160,217,157,180,246,64,234>>, + ?line P_p = 157224271412839155721795253728878055347359513988016145491388196653004661857517720927482198111104095793441029858267073789634147217022008635826863307553453131345099940951090826856271796188522037524757740796268675508118348391218066949174594918958269259937813776150149068811425194955973128428675945283593831134219, + ?line Q_p = 1181895316321540581845959276009400765315408342791, + ?line G_p = 143872196713149000950547166575757355261637863805587906227228163275557375159769599033632918292482002186641475268486598023281100659643528846513898847919251032731261718358900479488287933293278745715922865499005559197328388506945134386346185262919258658109015074718441639029135304654725637911172671711310801418648, + + ?line Key = 12603618348903387232593303690286336220738319446775939686476278478034365380027994899970214309288018488811754534229198764622077544117034174589418477472887827980332636062691833965078594576024299807057520016043084384987871640003684704483975314128362610573625803532737054022545217931847268776098203204571431581966, + + ValidKey = [crypto:mpint(P_p), + crypto:mpint(Q_p), + crypto:mpint(G_p), + crypto:mpint(Key) + ], + + ?line m(crypto:dss_verify(sized_binary(Msg), sized_binary(SigBlob), + ValidKey), true), + + BadMsg = one_bit_wrong(Msg), + ?line m(crypto:dss_verify(sized_binary(BadMsg), sized_binary(SigBlob), + ValidKey), false), + BadSig = one_bit_wrong(SigBlob), + ?line m(crypto:dss_verify(sized_binary(Msg), sized_binary(BadSig), + ValidKey), false), + SizeErr = size(SigBlob) - 13, + + BadArg = (catch crypto:dss_verify(sized_binary(Msg), <<SizeErr:32, SigBlob/binary>>, + ValidKey)), + ?line m(element(1,element(2,BadArg)), badarg), + + InValidKey = [crypto:mpint(P_p), + crypto:mpint(Q_p), + crypto:mpint(G_p), + crypto:mpint(Key+17) + ], + + ?line m(crypto:dss_verify(sized_binary(Msg), sized_binary(SigBlob), + InValidKey), false). + +one_bit_wrong(Bin) -> + Half = size(Bin) div 2, + <<First:Half/binary, Byte:8, Last/binary>> = Bin, + <<First/binary, (Byte+1):8, Last/binary>>. + + +%% +%% Sign tests + +rsa_sign_test(doc) -> + "rsa_sign testing"; +rsa_sign_test(suite) -> + []; +rsa_sign_test(Config) when is_list(Config) -> + PubEx = 65537, + PrivEx = 7531712708607620783801185371644749935066152052780368689827275932079815492940396744378735701395659435842364793962992309884847527234216715366607660219930945, + Mod = 7919488123861148172698919999061127847747888703039837999377650217570191053151807772962118671509138346758471459464133273114654252861270845708312601272799123, + Msg = <<"7896345786348756234 Hejsan Svejsan, erlang crypto debugger" + "09812312908312378623487263487623412039812 huagasd">>, + + PrivKey = [crypto:mpint(PubEx), crypto:mpint(Mod), crypto:mpint(PrivEx)], + PubKey = [crypto:mpint(PubEx), crypto:mpint(Mod)], + ?line Sig1 = crypto:rsa_sign(sized_binary(Msg), PrivKey), + ?line m(crypto:rsa_verify(sized_binary(Msg), sized_binary(Sig1),PubKey), true), + + ?line Sig2 = crypto:rsa_sign(md5, sized_binary(Msg), PrivKey), + ?line m(crypto:rsa_verify(md5, sized_binary(Msg), sized_binary(Sig2),PubKey), true), + + ?line m(Sig1 =:= Sig2, false), + ?line m(crypto:rsa_verify(md5, sized_binary(Msg), sized_binary(Sig1),PubKey), false), + ?line m(crypto:rsa_verify(sha, sized_binary(Msg), sized_binary(Sig1),PubKey), true), + + ok. + +dsa_sign_test(doc) -> + "dsa_sign testing"; +dsa_sign_test(suite) -> + []; +dsa_sign_test(Config) when is_list(Config) -> + Msg = <<"7896345786348756234 Hejsan Svejsan, erlang crypto debugger" + "09812312908312378623487263487623412039812 huagasd">>, + + PubKey = _Y = 25854665488880835237281628794585130313500176551981812527054397586638455298000483144002221850980183404910190346416063318160497344811383498859129095184158800144312512447497510551471331451396405348497845813002058423110442376886564659959543650802132345311573634832461635601376738282831340827591903548964194832978, + PrivKey = _X = 441502407453038284293378221372000880210588566361, + ParamP = 109799869232806890760655301608454668257695818999841877165019612946154359052535682480084145133201304812979481136659521529774182959764860329095546511521488413513097576425638476458000255392402120367876345280670101492199681798674053929238558140260669578407351853803102625390950534052428162468100618240968893110797, + ParamQ = 1349199015905534965792122312016505075413456283393, + ParamG = 18320614775012672475365915366944922415598782131828709277168615511695849821411624805195787607930033958243224786899641459701930253094446221381818858674389863050420226114787005820357372837321561754462061849169568607689530279303056075793886577588606958623645901271866346406773590024901668622321064384483571751669, + + Params = [crypto:mpint(ParamP), crypto:mpint(ParamQ), crypto:mpint(ParamG)], + ?line Sig1 = crypto:dss_sign(sized_binary(Msg), [Params, crypto:mpint(PrivKey)]), + + ?line m(crypto:dss_verify(sized_binary(Msg), sized_binary(Sig1), + [Params, crypto:mpint(PubKey)]), true), + + ?line m(crypto:dss_verify(sized_binary(one_bit_wrong(Msg)), sized_binary(Sig1), + [Params, crypto:mpint(PubKey)]), false), + + ?line m(crypto:dss_verify(sized_binary(Msg), sized_binary(one_bit_wrong(Sig1)), + [Params, crypto:mpint(PubKey)]), false), + + %%?line Bad = crypto:dss_sign(sized_binary(Msg), [Params, crypto:mpint(PubKey)]), + + ok. + + +rsa_encrypt_decrypt(doc) -> + ["Test rsa_public_encrypt and rsa_private_decrypt functions."]; +rsa_encrypt_decrypt(suite) -> []; +rsa_encrypt_decrypt(Config) when is_list(Config) -> + PubEx = 65537, + PrivEx = 7531712708607620783801185371644749935066152052780368689827275932079815492940396744378735701395659435842364793962992309884847527234216715366607660219930945, + Mod = 7919488123861148172698919999061127847747888703039837999377650217570191053151807772962118671509138346758471459464133273114654252861270845708312601272799123, + + PrivKey = [crypto:mpint(PubEx), crypto:mpint(Mod), crypto:mpint(PrivEx)], + PubKey = [crypto:mpint(PubEx), crypto:mpint(Mod)], + + Msg = <<"7896345786348 Asldi">>, + + ?line PKCS1 = crypto:rsa_public_encrypt(Msg, PubKey, rsa_pkcs1_padding), + ?line PKCS1Dec = crypto:rsa_private_decrypt(PKCS1, PrivKey, rsa_pkcs1_padding), + io:format("PKCS1Dec ~p~n",[PKCS1Dec]), + ?line Msg = PKCS1Dec, + + ?line OAEP = crypto:rsa_public_encrypt(Msg, PubKey, rsa_pkcs1_oaep_padding), + ?line Msg = crypto:rsa_private_decrypt(OAEP, PrivKey, rsa_pkcs1_oaep_padding), + + <<Msg2Len:32,_/binary>> = crypto:mpint(Mod), + Msg2 = list_to_binary(lists:duplicate(Msg2Len-1, $X)), + ?line NoPad = crypto:rsa_public_encrypt(Msg2, PubKey, rsa_no_padding), + ?line NoPadDec = crypto:rsa_private_decrypt(NoPad, PrivKey, rsa_no_padding), + ?line NoPadDec = Msg2, + + ShouldBeError = (catch crypto:rsa_public_encrypt(Msg, PubKey, rsa_no_padding)), + ?line {'EXIT', {encrypt_failed,_}} = ShouldBeError, + +%% ?line SSL = crypto:rsa_public_encrypt(Msg, PubKey, rsa_sslv23_padding), +%% ?line Msg = crypto:rsa_private_decrypt(SSL, PrivKey, rsa_sslv23_padding), + + ?line PKCS1_2 = crypto:rsa_private_encrypt(Msg, PrivKey, rsa_pkcs1_padding), + ?line PKCS1_2Dec = crypto:rsa_public_decrypt(PKCS1_2, PubKey, rsa_pkcs1_padding), + io:format("PKCS2Dec ~p~n",[PKCS1_2Dec]), + ?line Msg = PKCS1_2Dec, + + ?line PKCS1_3 = crypto:rsa_private_encrypt(Msg2, PrivKey, rsa_no_padding), + ?line PKCS1_3Dec = crypto:rsa_public_decrypt(PKCS1_3, PubKey, rsa_no_padding), + io:format("PKCS2Dec ~p~n",[PKCS1_3Dec]), + ?line Msg2 = PKCS1_3Dec, + + ?line {'EXIT', {encrypt_failed,_}} = + (catch crypto:rsa_private_encrypt(Msg, PrivKey, rsa_no_padding)), + + ok. + + +dh(doc) -> + ["Test dh (Diffie-Hellman) functions."]; +dh(suite) -> []; +dh(Config) when is_list(Config) -> + Self = self(), + GenP = fun() -> + %% Gen Param may take arbitrary long time to finish + %% That's not a bug in erlang crypto application. + ?line DHPs = crypto:dh_generate_parameters(512,2), + ?line ok = crypto:dh_check(DHPs), + Self ! {param, DHPs} + end, + Pid = spawn(GenP), + receive + {param, DHPs} -> + timer:sleep(100), + io:format("DHP ~p~n", [DHPs]), + ?line {Pub1,Priv1} = crypto:dh_generate_key(DHPs), + io:format("Key1:~n~p~n~p~n~n", [Pub1,Priv1]), + ?line {Pub2,Priv2} = crypto:dh_generate_key(DHPs), + io:format("Key2:~n~p~n~p~n~n", [Pub2,Priv2]), + ?line A = crypto:dh_compute_key(Pub1, Priv2, DHPs), + timer:sleep(100), %% Get another thread see if that triggers problem + ?line B = crypto:dh_compute_key(Pub2, Priv1, DHPs), + io:format("A ~p~n",[A]), + io:format("B ~p~n",[B]), + ?line A = B + after 50000 -> + io:format("Killing Param generation which took to long ~p~n",[Pid]), + exit(Pid, kill) + end. + +%% +%% +exor_test(doc) -> + ["Test the exor function."]; +exor_test(suite) -> + []; +exor_test(Config) when is_list(Config) -> + B = <<1, 2, 3, 4, 5, 6, 7, 8, 9, 10>>, + Z1 = zero_bin(B), + Z1 = crypto:exor(B, B), + B1 = crypto:rand_bytes(100), + B2 = crypto:rand_bytes(100), + Z2 = zero_bin(B1), + Z2 = crypto:exor(B1, B1), + Z2 = crypto:exor(B2, B2), + R = xor_bytes(B1, B2), + R = crypto:exor(B1, B2), + ok. + +%% +%% +rc4_test(doc) -> + ["Test rc4 encryption ."]; +rc4_test(suite) -> + []; +rc4_test(Config) when is_list(Config) -> + CT1 = <<"hej p� dig">>, + R1 = <<71,112,14,44,140,33,212,144,155,47>>, + K = "apaapa", + R1 = crypto:rc4_encrypt(K, CT1), + CT1 = crypto:rc4_encrypt(K, R1), + CT2 = lists:seq(0, 255), + R2 = crypto:rc4_encrypt(K, CT2), + CT2 = binary_to_list(crypto:rc4_encrypt(K, R2)), + ok. + +blowfish_cfb64(doc) -> ["Test Blowfish encrypt/decrypt."]; +blowfish_cfb64(suite) -> []; +blowfish_cfb64(Config) when is_list(Config) -> + Key = <<1,35,69,103,137,171,205,239,240,225,210,195,180,165,150,135>>, + + IVec = <<254,220,186,152,118,84,50,16>>, + Plain = <<"7654321 Now is the time for ">>, + Enc = <<231,50,20,162,130,33,57,202,242,110,207,109,46,185,231,110,61,163,222,4,209,81,114,0,81,157,87,166>>, + + Enc = crypto:blowfish_cfb64_encrypt(Key, IVec, Plain), + Plain = crypto:blowfish_cfb64_decrypt(Key, IVec, Enc), + + Key2 = <<"A2B4C">>, + IVec2 = <<"12345678">>, + Plain2 = <<"badger at my table....!">>, + Enc2 = <<173,76,128,155,70,81,79,228,4,162,188,92,119,53,144,89,93,236,28,164,176,16,138>>, + + Enc2 = crypto:blowfish_cfb64_encrypt(Key2, IVec2, Plain2), + Plain2 = crypto:blowfish_cfb64_decrypt(Key2, IVec2, Enc2). + + +smp(doc) -> "Check concurrent access to crypto driver"; +smp(suite) -> []; +smp(Config) -> + case erlang:system_info(smp_support) of + true -> + NumOfProcs = erlang:system_info(schedulers), + io:format("smp starting ~p workers\n",[NumOfProcs]), + Seeds = [random:uniform(9999) || _ <- lists:seq(1,NumOfProcs)], + Parent = self(), + Pids = [spawn_link(fun()-> worker(Seed,Config,Parent) end) + || Seed <- Seeds], + wait_pids(Pids); + + false -> + {skipped,"No smp support"} + end. + +worker(Seed, Config, Parent) -> + io:format("smp worker ~p, seed=~p~n",[self(),Seed]), + random:seed(Seed,Seed,Seed), + worker_loop(100, Config), + %%io:format("worker ~p done\n",[self()]), + Parent ! self(). + +worker_loop(0, _) -> + ok; +worker_loop(N, Config) -> + Funcs = { md5, md5_update, md5_mac, md5_mac_io, sha, sha_update, des_cbc, + aes_cfb, aes_cbc, des_cbc_iter, rand_uniform_test, + rsa_verify_test, exor_test, rc4_test, mod_exp_test }, + + F = element(random:uniform(size(Funcs)),Funcs), + %%io:format("worker ~p calling ~p\n",[self(),F]), + ?MODULE:F(Config), + worker_loop(N-1,Config). + +wait_pids([]) -> + ok; +wait_pids(Pids) -> + receive + Pid -> + ?line true = lists:member(Pid,Pids), + Others = lists:delete(Pid,Pids), + io:format("wait_pid got ~p, still waiting for ~p\n",[Pid,Others]), + wait_pids(Others) + end. + +%% +%% Help functions +%% + +% match +m(X, X) -> + ?line true. +t(true) -> + true. + +% hexstr2bin +hexstr2bin(S) -> + list_to_binary(hexstr2list(S)). + +hexstr2list([X,Y|T]) -> + [mkint(X)*16 + mkint(Y) | hexstr2list(T)]; +hexstr2list([]) -> + []. + +mkint(C) when $0 =< C, C =< $9 -> + C - $0; +mkint(C) when $A =< C, C =< $F -> + C - $A + 10; +mkint(C) when $a =< C, C =< $f -> + C - $a + 10. + +%% mod_exp in erlang (copied from jungerl's ssh_math.erl) +ipow(A, B, M) when M > 0, B >= 0 -> + if A == 1 -> + 1; + true -> + ipow(A, B, M, 1) + end. + +ipow(A, 1, M, Prod) -> + (A*Prod) rem M; +ipow(_A, 0, _M, Prod) -> + Prod; +ipow(A, B, M, Prod) -> + B1 = B bsr 1, + A1 = (A*A) rem M, + if B - B1 == B1 -> + ipow(A1, B1, M, Prod); + true -> + ipow(A1, B1, M, (A*Prod) rem M) + end. + +%% +%% Invert an element X mod P +%% Calculated as {1, {A,B}} = egcd(X,P), +%% 1 == P*A + X*B == X*B (mod P) i.e B is the inverse element +%% +%% X > 0, P > 0, X < P (P should be prime) +%% +%% invert(X,P) when X > 0, P > 0, X < P -> +%% I = inv(X,P,1,0), +%% if +%% I < 0 -> P + I; +%% true -> I +%% end. + +%% inv(0,_,_,Q) -> Q; +%% inv(X,P,R1,Q1) -> +%% D = P div X, +%% inv(P rem X, X, Q1 - D*R1, R1). + +sized_binary(Binary) when is_binary(Binary) -> + <<(size(Binary)):32/integer, Binary/binary>>; +sized_binary(List) -> + sized_binary(list_to_binary(List)). + +xor_bytes(Bin1, Bin2) when is_binary(Bin1), is_binary(Bin2) -> + L1 = binary_to_list(Bin1), + L2 = binary_to_list(Bin2), + list_to_binary(xor_bytes(L1, L2)); +xor_bytes(L1, L2) -> + xor_bytes(L1, L2, []). + +xor_bytes([], [], Acc) -> + lists:reverse(Acc); +xor_bytes([N1 | Tl1], [N2 | Tl2], Acc) -> + xor_bytes(Tl1, Tl2, [N1 bxor N2 | Acc]). + +zero_bin(N) when is_integer(N) -> + N8 = N * 8, + <<0:N8/integer>>; +zero_bin(B) when is_binary(B) -> + zero_bin(size(B)). diff --git a/lib/debugger/doc/src/Makefile b/lib/debugger/doc/src/Makefile index e6a1de2701..1c0bbaf9d2 100644 --- a/lib/debugger/doc/src/Makefile +++ b/lib/debugger/doc/src/Makefile @@ -39,7 +39,7 @@ RELSYSDIR = $(RELEASE_PATH)/lib/$(APPLICATION)-$(VSN) XML_APPLICATION_FILES = ref_man.xml XML_REF3_FILES = debugger.xml i.xml int.xml -XML_PART_FILES = part.xml part_notes.xml +XML_PART_FILES = part.xml XML_CHAPTER_FILES = debugger_chapter.xml notes.xml BOOK_FILES = book.xml diff --git a/lib/debugger/doc/src/part_notes.xml b/lib/debugger/doc/src/part_notes.xml deleted file mode 100644 index 60299bbb11..0000000000 --- a/lib/debugger/doc/src/part_notes.xml +++ /dev/null @@ -1,40 +0,0 @@ -<?xml version="1.0" encoding="latin1" ?> -<!DOCTYPE part SYSTEM "part.dtd"> - -<part xmlns:xi="http://www.w3.org/2001/XInclude"> - <header> - <copyright> - <year>2004</year><year>2009</year> - <holder>Ericsson AB. All Rights Reserved.</holder> - </copyright> - <legalnotice> - The contents of this file are subject to the Erlang Public License, - Version 1.1, (the "License"); you may not use this file except in - compliance with the License. You should have received a copy of the - Erlang Public License along with this software. If not, it can be - retrieved online at http://www.erlang.org/. - - Software distributed under the License is distributed on an "AS IS" - basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - the License for the specific language governing rights and limitations - under the License. - - </legalnotice> - - <title>Debugger Release Notes</title> - <prepared></prepared> - <docno></docno> - <date>2004-09-07</date> - <rev>1.0</rev> - <file>part_notes.sgml</file> - </header> - <description> - <p><em>Debugger</em> is a graphical tool which can be used for - debugging and testing of Erlang programs. For example, breakpoints - can be set, code can be single stepped and variable values can be - displayed and changed.</p> - </description> - <xi:include href="notes.xml"> -</part> - - diff --git a/lib/debugger/doc/src/warning.gif b/lib/debugger/doc/src/warning.gif Binary files differdeleted file mode 100644 index 96af52360e..0000000000 --- a/lib/debugger/doc/src/warning.gif +++ /dev/null diff --git a/lib/erl_docgen/priv/xsl/db_eix.xsl b/lib/erl_docgen/priv/xsl/db_eix.xsl new file mode 100644 index 0000000000..929272256a --- /dev/null +++ b/lib/erl_docgen/priv/xsl/db_eix.xsl @@ -0,0 +1,206 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + # + # %CopyrightBegin% + # + # Copyright Ericsson AB 2009. All Rights Reserved. + # + # The contents of this file are subject to the Erlang Public License, + # Version 1.1, (the "License"); you may not use this file except in + # compliance with the License. You should have received a copy of the + # Erlang Public License along with this software. If not, it can be + # retrieved online at http://www.erlang.org/. + # + # Software distributed under the License is distributed on an "AS IS" + # basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + # the License for the specific language governing rights and limitations + # under the License. + # + # %CopyrightEnd% + + --> + +<xsl:stylesheet version="1.0" + xmlns:xsl="http://www.w3.org/1999/XSL/Transform" + xmlns:fn="http://www.w3.org/2005/02/xpath-functions"> + + <xsl:output method="text" encoding="UTF-8" indent="no"/> + + <!-- Book --> + <xsl:template match="/book"> + <xsl:text>%% %% Search data file for </xsl:text><xsl:value-of select="$appname"/><xsl:text> </xsl:text><xsl:value-of select="$appver"/> + <xsl:text> %% generated </xsl:text><xsl:value-of select="$gendate"/><xsl:text> %% </xsl:text> + <xsl:apply-templates select="applications"/> + <xsl:text>{notused, application, ["</xsl:text><xsl:value-of select="$appname"/><xsl:text>"]}. </xsl:text> + </xsl:template> + + <!-- Applications --> + <xsl:template match="applications"> + <xsl:apply-templates name="application"/> + </xsl:template> + + <!-- Reference Manual --> + + <!-- Application --> + <xsl:template match="application"> + <xsl:apply-templates select="erlref|cref|comref|fileref|appref"/> + </xsl:template> + + <!-- Erlref --> + <xsl:template match="erlref"> + <xsl:text>{"</xsl:text><xsl:value-of select="module"/><xsl:text>.html", {function, {"</xsl:text><xsl:value-of select="$appname"/> + <xsl:text>", "</xsl:text><xsl:value-of select="module"/><xsl:text>"}}, [ </xsl:text> + <xsl:apply-templates select="funcs"> + <xsl:with-param name="mod" select="module"/> + </xsl:apply-templates> + <xsl:text>]}. </xsl:text> + <xsl:text>{"</xsl:text><xsl:value-of select="module"/><xsl:text>.html", {module, "</xsl:text> + <xsl:value-of select="$appname"/><xsl:text>"}, ["</xsl:text><xsl:value-of select="module"/><xsl:text>"]}. </xsl:text> + </xsl:template> + + <!-- Cref --> + <xsl:template match="cref"> + <xsl:text>{"</xsl:text><xsl:value-of select="lib"/><xsl:text>.html", {function, {"</xsl:text><xsl:value-of select="$appname"/> + <xsl:text>", "</xsl:text><xsl:value-of select="lib"/><xsl:text>"}}, [ </xsl:text> + <xsl:apply-templates select="funcs"> + <xsl:with-param name="mod" select="lib"/> + </xsl:apply-templates> + <xsl:text>]}. </xsl:text> + <xsl:text>{"</xsl:text><xsl:value-of select="lib"/><xsl:text>.html", {clib, "</xsl:text> + <xsl:value-of select="$appname"/><xsl:text>"}, ["</xsl:text><xsl:value-of select="lib"/><xsl:text>"]}. </xsl:text> + </xsl:template> + + <!-- Comref --> + <xsl:template match="comref"> + <xsl:text>{"</xsl:text><xsl:value-of select="com"/><xsl:text>.html", {command, "</xsl:text> + <xsl:value-of select="$appname"/><xsl:text>"}, ["</xsl:text><xsl:value-of select="com"/><xsl:text>"]}. </xsl:text> + </xsl:template> + + <!-- Fileref --> + <xsl:template match="fileref"> + <xsl:text>{"</xsl:text><xsl:value-of select="file"/><xsl:text>.html", {file, "</xsl:text> + <xsl:value-of select="$appname"/><xsl:text>"}, ["</xsl:text><xsl:value-of select="file"/><xsl:text>"]}. </xsl:text> + </xsl:template> + + <!-- Appref --> + <xsl:template match="appref"> + <xsl:text>{"</xsl:text><xsl:value-of select="app"/><xsl:text>_app.html", {app, "</xsl:text> + <xsl:value-of select="$appname"/><xsl:text>"}, ["</xsl:text><xsl:value-of select="app"/><xsl:text>"]}. </xsl:text> + </xsl:template> + + + <!-- Funcs --> + <xsl:template match="funcs"> + <xsl:param name="mod"/> + <xsl:variable name="lastfuncsblock"> + <xsl:value-of select="position() = last()"/> + </xsl:variable> + <xsl:apply-templates select="func/name"> + <xsl:with-param name="mod" select="$mod"/> + <xsl:with-param name="lastfuncsblock" select="$lastfuncsblock"/> + </xsl:apply-templates> + </xsl:template> + + + + + <xsl:template match="name"> + <xsl:param name="mod"/> + <xsl:param name="lastfuncsblock"/> + + <xsl:variable name="tmpstring"> + <xsl:value-of select="substring-before(substring-after(., '('), '->')"/> + </xsl:variable> + <xsl:variable name="ustring"> + <xsl:choose> + <xsl:when test="string-length($tmpstring) > 0"> + <xsl:call-template name="remove-paren"> + <xsl:with-param name="string" select="$tmpstring"/> + </xsl:call-template> + </xsl:when> + <xsl:otherwise> + <xsl:call-template name="remove-paren"> + <xsl:with-param name="string" select="substring-after(., '(')"/> + </xsl:call-template> + </xsl:otherwise> + </xsl:choose> + </xsl:variable> + <xsl:variable name="arity"> + <xsl:call-template name="calc-arity"> + <xsl:with-param name="string" select="substring-before($ustring, ')')"/> + <xsl:with-param name="no-of-pars" select="0"/> + </xsl:call-template> + </xsl:variable> + <xsl:variable name="fname"> + <xsl:choose> + <xsl:when test="ancestor::cref"> + <xsl:value-of select="substring-before(nametext, '(')"/> + </xsl:when> + <xsl:when test="ancestor::erlref"> + <xsl:value-of select="substring-before(., '(')"/> + </xsl:when> + </xsl:choose> + </xsl:variable> + <xsl:text> {"</xsl:text><xsl:value-of select="$fname"/> + <xsl:text>", "</xsl:text><xsl:value-of select="$fname"/> + <xsl:text>(</xsl:text><xsl:value-of select="normalize-space($tmpstring)"/> + <xsl:text>", "</xsl:text><xsl:value-of select="$fname"/> + <xsl:text>-</xsl:text><xsl:value-of select="$arity"/><xsl:text>"}</xsl:text> + + <xsl:choose> + <xsl:when test="($lastfuncsblock = 'true') and (position() = last())"> + <xsl:text> </xsl:text> + </xsl:when> + <xsl:otherwise> + <xsl:text>, </xsl:text> + </xsl:otherwise> + </xsl:choose> + </xsl:template> + + <!-- Special templates to calculate the arity of functions --> + <xsl:template name="calc-arity"> + <xsl:param name="string"/> + <xsl:param name="no-of-pars"/> + <xsl:variable name="length"> + <xsl:value-of select="string-length($string)"/> + </xsl:variable> + <xsl:choose> + <xsl:when test="$length > 0"> + <xsl:call-template name="calc-arity"> + <xsl:with-param name="string" select="substring-after($string, ',')"/> + <xsl:with-param name="no-of-pars" select="$no-of-pars+1"/> + </xsl:call-template> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="$no-of-pars"/> + </xsl:otherwise> + </xsl:choose> + </xsl:template> + + <xsl:template name="remove-paren"> + <xsl:param name="string"/> + <xsl:variable name="bstring"> + <xsl:value-of select="substring-before($string, '(')"/> + </xsl:variable> + <xsl:choose> + <xsl:when test="string-length($bstring) > 0"> + <xsl:variable name="astring"> + <xsl:value-of select="substring-after($string, ')')"/> + </xsl:variable> + <xsl:variable name="retstring"> + <xsl:call-template name="remove-paren"> + <xsl:with-param name="string" select="$astring"/> + </xsl:call-template> + </xsl:variable> + <xsl:value-of select="concat($bstring, $retstring)"/> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="$string"/> + </xsl:otherwise> + </xsl:choose> + </xsl:template> + + <!-- default content handling --> + <xsl:template match="text()"/> + +</xsl:stylesheet> diff --git a/lib/erl_docgen/priv/xsl/db_html.xsl b/lib/erl_docgen/priv/xsl/db_html.xsl index 3e6f762870..984655fc26 100644 --- a/lib/erl_docgen/priv/xsl/db_html.xsl +++ b/lib/erl_docgen/priv/xsl/db_html.xsl @@ -61,7 +61,7 @@ <xsl:value-of select="$copyright"/> <xsl:value-of select="/book/header/copyright/year[1]"/> <xsl:text>-</xsl:text> - <xsl:value-of select="substring-after(substring-after($gendate, ' '), ' ')"/> + <xsl:value-of select="substring-after(normalize-space(substring-after($gendate, ' ')), ' ')"/> <xsl:text> </xsl:text> <xsl:value-of select="/book/header/copyright/holder"/> </p> diff --git a/lib/erl_interface/configure.in b/lib/erl_interface/configure.in index 80b229c1c3..2f5b5673bb 100644 --- a/lib/erl_interface/configure.in +++ b/lib/erl_interface/configure.in @@ -100,11 +100,11 @@ if test "x$LD" = "x"; then fi AC_SUBST(LD) -AC_CHECK_SIZEOF(short, $erl_xcomp_short) -AC_CHECK_SIZEOF(int, $erl_xcomp_int) -AC_CHECK_SIZEOF(long, $erl_xcomp_long) -AC_CHECK_SIZEOF(void *, $erl_xcomp_void_p) -AC_CHECK_SIZEOF(long long, $erl_xcomp_long_long) +AC_CHECK_SIZEOF(short) +AC_CHECK_SIZEOF(int) +AC_CHECK_SIZEOF(long) +AC_CHECK_SIZEOF(void *) +AC_CHECK_SIZEOF(long long) if test $ac_cv_sizeof_void_p = 8; then CFLAGS="$CFLAGS -DEI_64BIT" diff --git a/lib/erl_interface/doc/src/ei_connect.xml b/lib/erl_interface/doc/src/ei_connect.xml index 08e7b122c6..abf705f9e2 100644 --- a/lib/erl_interface/doc/src/ei_connect.xml +++ b/lib/erl_interface/doc/src/ei_connect.xml @@ -619,6 +619,16 @@ typedef struct { <p>These are convenience functions for some common name lookup functions.</p> </desc> </func> + <func> + <name><ret>int</ret><nametext>ei_get_tracelevel(void)</nametext></name> + <name><ret>void</ret><nametext>ei_set_tracelevel(int level)</nametext></name> + <fsummary>Get and set functions for tracing.</fsummary> + <desc> + <p>These functions are used to set tracing on the distribution. The levels are different verbosity levels. A higher level means more information. + See also Debug Information and <c><![CDATA[EI_TRACELEVEL]]></c> below. </p> + <p> <c><![CDATA[ei_set_tracelevel]]></c> and <c><![CDATA[ei_get_tracelevel]]></c> are not thread safe. </p> + </desc> + </func> </funcs> <section> @@ -634,6 +644,17 @@ typedef struct { <item>the environment variable <c><![CDATA[ERL_EPMD_PORT]]></c> is set correctly.</item> </list> + <p>The connection attempt can be traced by setting a tracelevel by either using + <c><![CDATA[ei_set_tracelevel]]></c> or by setting the environment variable <c><![CDATA[EI_TRACELEVEL]]></c>. + The different tracelevels has the following messages:</p> + <list> + <item>1: Verbose error messages</item> + <item>2: Above messages and verbose warning messages </item> + <item>3: Above messages and progress reports for connection handling</item> + <item>4: Above messages and progress reports for communication</item> + <item>5: Above messages and progress reports for data conversion</item> + </list> </section> + </cref> diff --git a/lib/erl_interface/doc/src/erl_eterm.xml b/lib/erl_interface/doc/src/erl_eterm.xml index ce14549672..f403618c59 100644 --- a/lib/erl_interface/doc/src/erl_eterm.xml +++ b/lib/erl_interface/doc/src/erl_eterm.xml @@ -248,7 +248,7 @@ iohead ::= Binary <v>ETERM *list;</v> </type> <desc> - <p>This function converts an IO list to a '\\0' terminated C + <p>This function converts an IO list to a '\0' terminated C string. </p> <p><c><![CDATA[list]]></c> is an Erlang term containing an IO list. The IO list must not contain the integer 0, since C strings may not diff --git a/lib/erl_interface/doc/src/notes.xml b/lib/erl_interface/doc/src/notes.xml index f2519fda0b..21f12f616a 100644 --- a/lib/erl_interface/doc/src/notes.xml +++ b/lib/erl_interface/doc/src/notes.xml @@ -336,7 +336,7 @@ from 0 to 255 as a string. If the original list contains the integer 0, this is considered terminator of the string. This is incorrect. The function has now been - modified to not look for '\\0' in a string, but always + modified to not look for '\0' in a string, but always print all characters.</p> <p>Own Id: OTP-6339 Aux Id: seq10492 </p> </item> diff --git a/lib/erl_interface/include/ei.h b/lib/erl_interface/include/ei.h index 01272244e1..d1a697615a 100644 --- a/lib/erl_interface/include/ei.h +++ b/lib/erl_interface/include/ei.h @@ -339,7 +339,13 @@ const char *ei_thisalivename(const ei_cnode* ec); erlang_pid *ei_self(ei_cnode* ec); +/* + * settings + */ + void ei_set_compat_rel(unsigned rel); +void ei_set_tracelevel(int); +int ei_get_tracelevel(void); /* * We have erl_gethost*() so we include ei versions as well. diff --git a/lib/erl_interface/src/connect/ei_connect.c b/lib/erl_interface/src/connect/ei_connect.c index 9ac5a93c5a..d2d0a7e7c1 100644 --- a/lib/erl_interface/src/connect/ei_connect.c +++ b/lib/erl_interface/src/connect/ei_connect.c @@ -249,8 +249,22 @@ ei_cnode *ei_fd_to_cnode(int fd) return &sockinfo->cnode; } + +/*************************************************************************** + * Get/Set tracelevel + ***************************************************************************/ + +void ei_set_tracelevel(int level) { + ei_tracelevel = level; +} + +int ei_get_tracelevel(void) { + return ei_tracelevel; +} + + /*************************************************************************** - * XXXX + * Distversion ***************************************************************************/ int ei_distversion(int fd) @@ -1282,8 +1296,6 @@ error: return -1; } -/* FIXME fix the signed/unsigned mess..... */ - static int send_name_or_challenge(int fd, char *nodename, int f_chall, unsigned challenge, diff --git a/lib/erl_interface/test/Makefile b/lib/erl_interface/test/Makefile new file mode 100644 index 0000000000..b7a1a4e4d8 --- /dev/null +++ b/lib/erl_interface/test/Makefile @@ -0,0 +1,78 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 1997-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +include $(ERL_TOP)/make/target.mk +include $(ERL_TOP)/make/$(TARGET)/otp.mk + +# ---------------------------------------------------- +# Target Specs +# ---------------------------------------------------- + +MODULES= \ + ei_accept_SUITE \ + ei_connect_SUITE \ + ei_decode_SUITE \ + ei_decode_encode_SUITE \ + ei_encode_SUITE \ + ei_format_SUITE \ + ei_print_SUITE \ + ei_tmo_SUITE \ + erl_connect_SUITE \ + erl_eterm_SUITE \ + erl_ext_SUITE \ + erl_format_SUITE \ + erl_match_SUITE \ + port_call_SUITE \ + runner + +SPEC_FILES = \ + erl_interface.spec \ + erl_interface.dynspec \ + erl_interface.spec.vxworks + +ERL_FILES = $(MODULES:%=%.erl) + +# ---------------------------------------------------- +# Release directory specification +# ---------------------------------------------------- +RELSYSDIR = $(RELEASE_PATH)/erl_interface_test + +# ---------------------------------------------------- +# Targets +# ---------------------------------------------------- + +tests debug opt: + +clean: + +docs: + +# ---------------------------------------------------- +# Release Target +# ---------------------------------------------------- +include $(ERL_TOP)/make/otp_release_targets.mk + +release_spec: + +release_tests_spec: opt + $(INSTALL_DIR) $(RELSYSDIR) + $(INSTALL_DATA) $(SPEC_FILES) $(ERL_FILES) $(RELSYSDIR) + chmod -f -R u+w $(RELSYSDIR) + @tar cf - *_SUITE_data | (cd $(RELSYSDIR); tar xf -) + +release_docs_spec: diff --git a/lib/erl_interface/test/Makefile.src b/lib/erl_interface/test/Makefile.src new file mode 100644 index 0000000000..9c620bb8d9 --- /dev/null +++ b/lib/erl_interface/test/Makefile.src @@ -0,0 +1,71 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 1997-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# + +include @erl_interface_mk_include@@[email protected] + +CC0 = @CC@ +CC = ..@DS@all_SUITE_data@DS@gccifier@exe@ -CC"$(CC0)" +LD = @LD@ + +LIBPATH = @erl_interface_libpath@ +LIBERL = $(LIBPATH)/@erl_interface_lib@ +LIBEI = $(LIBPATH)/@erl_interface_eilib@ +LIBFLAGS = $(LIBERL) $(LIBEI) +CFLAGS = @EI_CFLAGS@ $(THR_DEFS) -I@erl_interface_include@ -I../common + +ETERM_OBJS = eterm_test@obj@ eterm_test_decl@obj@ runner@obj@ +EXT_OBJS = ext_test@obj@ ext_test_decl@obj@ runner@obj@ +FORMAT_OBJS = format_test@obj@ format_test_decl@obj@ runner@obj@ +EI_FORMAT_OBJS = ei_format_test@obj@ ei_format_test_decl@obj@ ei_runner@obj@ +EI_PRINT_OBJS = ei_print_test@obj@ ei_print_test_decl@obj@ ei_runner@obj@ +EI_CONNECT_OBJS = ei_connect_test@obj@ ei_connect_test_decl@obj@ ei_runner@obj@ +EI_ACCEPT_OBJS = ei_accept_test@obj@ ei_accept_test_decl@obj@ ei_runner@obj@ +MATCH_OBJS = match_test@obj@ match_test_decl@obj@ runner@obj@ + +PROGS = eterm_test@exe@ format_test@exe@ print_term@exe@ match_test@exe@ ei_format_test@exe@ ei_print_test@exe@ ei_connect_test@exe@ ei_accept_test@exe@ + + +all: $(PROGS) + +eterm_test@exe@: $(ETERM_OBJS) $(LIBERL) $(LIBEI) + $(LD) @CROSSLDFLAGS@ -o eterm_test $(ETERM_OBJS) $(LIBFLAGS) + +ext_test@exe@: $(EXT_OBJS) $(LIBERL) $(LIBEI) + $(LD) @CROSSLDFLAGS@ -o ext_test $(EXT_OBJS) $(LIBFLAGS) + +format_test@exe@: $(FORMAT_OBJS) $(LIBERL) $(LIBEI) + $(LD) @CROSSLDFLAGS@ -o format_test $(FORMAT_OBJS) $(LIBFLAGS) + +ei_format_test@exe@: $(EI_FORMAT_OBJS) $(LIBERL) $(LIBEI) + $(LD) @CROSSLDFLAGS@ -o ei_format_test $(EI_FORMAT_OBJS) $(LIBFLAGS) + +ei_print_test@exe@: $(EI_PRINT_OBJS) $(LIBERL) $(LIBEI) + $(LD) @CROSSLDFLAGS@ -o ei_print_test $(EI_PRINT_OBJS) $(LIBFLAGS) + +ei_connect_test@exe@: $(EI_CONNECT_OBJS) $(LIBERL) $(LIBEI) + $(LD) @CROSSLDFLAGS@ -o ei_connect_test $(EI_CONNECT_OBJS) $(LIBFLAGS) + +ei_accept_test@exe@: $(EI_ACCEPT_OBJS) $(LIBERL) $(LIBEI) + $(LD) @CROSSLDFLAGS@ -o ei_accept_test $(EI_ACCEPT_OBJS) $(LIBFLAGS) + +match_test@exe@: $(MATCH_OBJS) $(LIBERL) $(LIBEI) + $(LD) @CROSSLDFLAGS@ -o match_test $(MATCH_OBJS) $(LIBFLGAS) + +print_term@exe@: print_term@obj@ $(LIBERL) $(LIBEI) + $(LD) @CROSSLDFLAGS@ -o print_term print_term@obj@ $(LIBFLGAS) diff --git a/lib/erl_interface/test/README b/lib/erl_interface/test/README new file mode 100644 index 0000000000..e1af025ca3 --- /dev/null +++ b/lib/erl_interface/test/README @@ -0,0 +1,28 @@ + +One way to create a new suite, copy an old one +that is similar to a new one + + % setenv SIMILAR ei_xyz + % setenv NEW ei_abc + + % ct mkdir ${NEW}_SUITE_data + % ct mkelem ${NEW}_SUITE.erl + % cp ${SIMILAR}_SUITE.erl ${NEW}_SUITE.erl + % cp ${SIMILAR}_SUITE_data/* ${NEW}_SUITE_data/ + % chmod ug+rw ${NEW}_SUITE_data/* + % mv ${NEW}_SUITE_data/${SIMILAR}_test.c ${NEW}_SUITE_data/${NEW}_test.c + % ct mkelem ${NEW}_SUITE_data/* + +Now edit "${NEW}_SUITE.erl" and the files in "${NEW}_SUITE_data/". + +To use a test suite you build it and put the result outside +ClearCase. Then you create soft links to the ClearCase elements. + + % setenv SRC /clearcase/otp/erts/lib/erl_interface/test + % setenv DST /ldisk/test + % cd $SRC + % clearmake -V release TESTROOT=$DST + % foreach f (`find . -type f`) + foreach> \rm -f /ldisk/test/erl_interface_test/$f + foreach> ln -s $SRC/$f $DST/erl_interface_test/$f + foreach> end diff --git a/lib/erl_interface/test/all_SUITE_data/Makefile.first b/lib/erl_interface/test/all_SUITE_data/Makefile.first new file mode 100644 index 0000000000..b9ce689057 --- /dev/null +++ b/lib/erl_interface/test/all_SUITE_data/Makefile.first @@ -0,0 +1,20 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2003-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +all: + erlc -W init_tc.erl diff --git a/lib/erl_interface/test/all_SUITE_data/Makefile.src b/lib/erl_interface/test/all_SUITE_data/Makefile.src new file mode 100644 index 0000000000..9be2360656 --- /dev/null +++ b/lib/erl_interface/test/all_SUITE_data/Makefile.src @@ -0,0 +1,45 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2003-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +include @erl_interface_mk_include@@[email protected] + +CC0 = @CC@ +CC = .@DS@gccifier@exe@ -CC"$(CC0)" +CFLAGS0 = @CFLAGS@ -I@erl_interface_include@ +CFLAGS = @EI_CFLAGS@ $(THR_DEFS) -I@erl_interface_include@ +EI_COMMON_OBJS = runner@obj@ ei_runner@obj@ +ALL_OBJS = gccifier@exe@ $(EI_COMMON_OBJS) + +CP=cp +CHMOD=chmod + +all: $(ALL_OBJS) + +@IFEQ@ (@erl_interface_cross_compile@, true) +gccifier@exe@: + $(CP) gccifier.sh gccifier@exe@ + $(CHMOD) a+x gccifier@exe@ +@ELSE@ +gccifier@exe@: gccifier.c + $(CC0) $(CFLAGS0) -o gccifier@exe@ gccifier.c +@ENDIF@ + +clean: + $(RM) $(EI_COMMON_OBJS) + $(RM) init_tc.beam + $(RM) gccifier@exe@ diff --git a/lib/erl_interface/test/all_SUITE_data/ei_runner.c b/lib/erl_interface/test/all_SUITE_data/ei_runner.c new file mode 100644 index 0000000000..205f911e38 --- /dev/null +++ b/lib/erl_interface/test/all_SUITE_data/ei_runner.c @@ -0,0 +1,400 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2001-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#ifndef __WIN32__ +#include <unistd.h> +#endif +#include <stdarg.h> + +#include "ei_runner.h" + +#ifndef __WIN32__ +#define _O_BINARY 0 +#define _setmode(fd, mode) +#endif + +#define HEADER_SIZE 4 + +static char* progname; /* Name of this program (from argv[0]). */ +static int fd_from_erl; /* File descriptor from Erlang. */ +static int fd_to_erl; /* File descriptor to Erlang. */ + +static int packet_loop(); +static void ensure_buf_big_enough(); +static int readn(); +static void reply(char* buf, unsigned size); +static void dump(); + +void +run_tests(char* argv0, TestCase test_cases[], unsigned number) +{ + int i; + int n; + char* packet; + + progname = argv0; + _setmode(0, _O_BINARY); + _setmode(1, _O_BINARY); + fd_from_erl = 0; + fd_to_erl = 1; + + packet = read_packet(&n); + + /* + * Dispatch to the appropriate test function. + */ + + i = packet[0] * 256 + packet[1]; + if (i >= number) { + fprintf(stderr, "%s: bad test case number %d", + progname, i); + free(packet); + exit(1); + } else { + (*test_cases[i])(); + free(packet); + } +} + + +/*********************************************************************** + * + * R e a d i n g p a c k e t s + * + ************************************************************************/ + +/* + * Reads an Erlang term. + * + * Only accepts 't' (term) or 'e' (end of test), + * exits program on error + * returns 1 on 'e', 0 on 't' + */ +int get_bin_term(ei_x_buff* x, ei_term* term) +{ + int len, version; + + ei_x_free(x); + x->buff = read_packet(&len); + x->buffsz = len; + x->index = 0; + switch (x->buff[x->index++]) { + case 'e': + return 1; + case 't': + if (ei_decode_version(x->buff, &x->index, &version) < 0 + || ei_decode_ei_term(x->buff, &x->index, term) < 0) { + fail("Failed to decode term"); + exit(0); + } + return 0; + default: + fprintf(stderr, "Garbage received: "); + dump(x->buff, len, 16); + putc('\n', stderr); + fail("C program received garbage"); + exit(1); + } +} + + +/* + * Reads a packet from Erlang. The packet must be a standard {packet, 2} + * packet. This function aborts if any error is detected (including EOF). + * + * Returns: The number of bytes in the packet. + */ + +char *read_packet(int *len) +{ + + unsigned char* io_buf = NULL; /* Buffer for file i/o. */ + int i; + unsigned char header[HEADER_SIZE]; + unsigned packet_length; /* Length of current packet. */ + int bytes_read; + + /* + * Read the packet header. + */ + + bytes_read = readn(fd_from_erl, header, HEADER_SIZE); + + if (bytes_read == 0) { + fprintf(stderr, "%s: Unexpected end of file\n", progname); + exit(1); + } + if (bytes_read != HEADER_SIZE) { + fprintf(stderr, "%s: Failed to read packet header\n", progname); + exit(1); + } + + /* + * Get the length of this packet. + */ + + packet_length = 0; + + for (i = 0; i < HEADER_SIZE; i++) + packet_length = (packet_length << 8) | header[i]; + + if (len) *len=packet_length; /* report length only if caller requested it */ + + if ((io_buf = (char *) malloc(packet_length)) == NULL) { + fprintf(stderr, "%s: insufficient memory for i/o buffer of size %d\n", + progname, packet_length); + exit(1); + } + + /* + * Read the packet itself. + */ + + bytes_read = readn(fd_from_erl, io_buf, packet_length); + if (bytes_read != packet_length) { + fprintf(stderr, "%s: couldn't read packet of length %d\r\n", + progname, packet_length); + free(io_buf); + exit(1); + } + + return io_buf; +} + + +/*********************************************************************** + * S e n d i n g r e p l i e s + * + * The functions below send various types of replies back to Erlang. + * Each reply start with a letter indicating the type of reply. + * + * Reply Translated to on Erlang side + * ----- ---------------------------- + * [$b|Bytes] {bytes, Bytes} + * [$e] eot + * [$f] test_server:fail() + * [$f|Reason] test_server:fail(Reason) + * [$t|EncodedTerm] {term, Term} + * [$N] 'NULL' + * [$m|Message] io:format("~s", [Message]) (otherwise ignored) + * + ***********************************************************************/ + +/* + * This function reports the outcome of a test fail. It is useful if + * you implement a test case entirely in C code. + * + * If the ok argument is zero, a [$f] reply will be sent to the + * Erlang side (causing test_server:fail() to be called); otherwise, + * the atom 'eot' will be sent to Erlang. + * + * If you need to provide more details on a failure, use the fail() function. + */ + +void +do_report(file, line, ok) + char* file; + int line; + int ok; /* Zero if failed; non-zero otherwise. */ +{ + char reason; + /*unsigned long ab; + unsigned long fb;*/ + + reason = ok ? 'e' : 'f'; + + if (!ok) { + do_fail(file, line, "Generic failure"); + } else { + /* release all unallocated blocks */ + /*erl_eterm_release();*/ + /* check mem usage stats */ + /*erl_eterm_statistics(&ab, &fb);*/ + /*if ((ab == 0) && (fb == 0) ) {*/ + reply(&reason, 1); + /*} + else { + char sbuf[128]; + + sprintf(sbuf, "still %lu terms allocated," + " %lu on freelist at end of test", ab, fb); + do_fail(file, line, sbuf); + }*/ + } +} + + +/* + * This function causes a call to test_server:fail(Reason) on the + * Erlang side. + */ + +void do_fail(char* file, int line, char* reason) +{ + char sbuf[2048]; + + sbuf[0] = 'f'; + sprintf(sbuf+1, "%s, line %d: %s", file, line, reason); + reply(sbuf, 1+strlen(sbuf+1)); +} + +/* + * This function sends a message to the Erlang side. + * The message will be written to the test servers log file, + * but will otherwise be completly ignored. + */ + +void message(char* format, ...) +{ + va_list ap; + char sbuf[1024]; + + sbuf[0] = 'm'; + va_start(ap, format); + vsprintf(sbuf+1, format, ap); + va_end(ap); + + reply(sbuf, 1+strlen(sbuf+1)); +} + +/* + * This function sends the given binary term to the Erlang side, + * where it will be received as {term, Term} (prefix 't'). + */ +void send_bin_term(ei_x_buff* x) +{ + ei_x_buff x2; + ei_x_new(&x2); + x2.buff[x2.index++] = 't'; + ei_x_append(&x2, x); + reply(x2.buff, x2.index); + ei_x_free(&x2); +} + +/* + * This function sends a raw buffer of data to the + * Erlang side, where it will be received as {bytes, Bytes} (prefix 'b'). + */ +void send_buffer(char* buf, int size) +{ + char* send_buf; + + send_buf = (char *) malloc(size+1); + send_buf[0] = 'b'; + memcpy(send_buf+1, buf, size); + reply(send_buf, size+1); + free(send_buf); +} + +/*********************************************************************** + * + * P r i v a t e h e l p e r s + * + ***********************************************************************/ + +/* + * Sends a packet back to Erlang. + */ +static void reply(char* reply_buf, unsigned size) +{ + int n; /* Temporary to hold size. */ + int i; /* Loop counter. */ + char* buf; + + + buf = (char *) malloc(size+HEADER_SIZE); + memcpy(buf+HEADER_SIZE, reply_buf, size); + + /* + * Fill the header starting with the least significant byte. + */ + n = size; + for (i = HEADER_SIZE-1; i >= 0; i--) { + buf[i] = (char) n; /* Store least significant byte. */ + n = n >> 8; + } + + size += HEADER_SIZE; + write(fd_to_erl, buf, size); + free(buf); +} + + +/* + * Reads len number of bytes. + */ + +static int +readn(fd, buf, len) + int fd; /* File descriptor to read from. */ + unsigned char *buf; /* Store in this buffer. */ + int len; /* Number of bytes to read. */ +{ + int n; /* Byte count in last read call. */ + int sofar = 0; /* Bytes read so far. */ + + do { + if ((n = read(fd, buf+sofar, len-sofar)) <= 0) + /* error or EOF in read */ + return(n); + sofar += n; + } while (sofar < len); + return sofar; +} + +void +dump(buf, sz, max) + unsigned char* buf; + int sz; + int max; +{ + int i, imax; + char comma[5] = ","; + + if (!sz) + return; + if (sz > max) + imax = max; + else + imax = sz; + + for (i=0; i<imax; i++) { + if (i == imax-1) { + if (sz > max) + strcpy(comma, ",..."); + else + comma[0] = 0; + } + if (isdigit(buf[i])) + fprintf(stderr, "%u%s", (int)(buf[i]), comma); + else { + if (isalpha(buf[i])) { + fprintf(stderr, "%c%s", buf[i], comma); + } + else + fprintf(stderr, "%u%s", (int)(buf[i]), comma); + } + } +} + diff --git a/lib/erl_interface/test/all_SUITE_data/ei_runner.h b/lib/erl_interface/test/all_SUITE_data/ei_runner.h new file mode 100644 index 0000000000..96d6a1cbf7 --- /dev/null +++ b/lib/erl_interface/test/all_SUITE_data/ei_runner.h @@ -0,0 +1,61 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2001-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ + +#include "ei.h" + +typedef void (*TestCase)(void); + +#define TESTCASE(name) void name(void) +#define ASIZE(a) (sizeof(a)/sizeof(a[0])) + +void run_tests(char* argv0, TestCase cases[], unsigned number); + +#ifndef _MSC_VER +# define ll(val) (val##LL) +#else /* assume gcc or C99 */ +# define ll(val) (val##i64) +#endif + +#ifndef _MSC_VER +# define ull(val) (val##LL) +#else /* assume gcc or C99 */ +# define ull(val) (val##i64) +#endif + +/* + * Reading. + */ + +int get_bin_term(ei_x_buff* x, ei_term* term); +char *read_packet(int *len); + +/* + * Sending replies. + */ + +#define fail(reason) do_fail(__FILE__, __LINE__, reason) +#define report(ok) do_report(__FILE__, __LINE__, ok) + +void do_report(char* file, int line, int ok); +void do_fail(char* file, int line, char* reason); +void send_buffer(char* buf, int size); +void message(char* format, ...); + +void send_bin_term(ei_x_buff* x); + diff --git a/lib/erl_interface/test/all_SUITE_data/gccifier.c b/lib/erl_interface/test/all_SUITE_data/gccifier.c new file mode 100644 index 0000000000..9f556fc4ed --- /dev/null +++ b/lib/erl_interface/test/all_SUITE_data/gccifier.c @@ -0,0 +1,317 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2005-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + + */ + +/* + * A compiler wrapper that translate (some) gcc command line arguments + * to the Visual C++ compiler and (of course) the gcc compiler. It also + * makes some changes in the command line arguments when debug compiling. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <stdarg.h> + + +#if !defined(__WIN32__) +#define USE_EXEC +#include <unistd.h> +#endif + + +#ifdef __WIN32__ +#define EOL "\r\n" +#else +#define EOL "\n" +#endif + +#define ARGS_INCR 20 + +static char *prog; + +typedef struct { + char **vec; + int no; + int ix; + int chars; +} args_t; + +static void +enomem(void) +{ + fprintf(stderr, "%s: Out of memory%s", prog, EOL); + exit(1); +} + +static void +save_arg(args_t *args, char *arg1, ...) +{ + char *carg; + va_list argp; + + va_start(argp, arg1); + carg = arg1; + while (carg) { + if (args->no <= args->ix) { + args->vec = (char **) (args->no + ? realloc((void *) args->vec, + (sizeof(char *) + *(args->no + ARGS_INCR + 1))) + : malloc((sizeof(char *) + *(args->no + ARGS_INCR + 1)))); + if (!args->vec) + enomem(); + args->no += ARGS_INCR; + } + args->vec[args->ix++] = carg; + args->chars += strlen(carg); + carg = va_arg(argp, char *); + } + args->vec[args->ix++] = " "; + args->chars++; + va_end(argp); +} + +static int +is_prefix(char *prfx, char **str) +{ + int i; + for (i = 0; prfx[i] && (*str)[i]; i++) { + if (prfx[i] != (*str)[i]) + return 0; + } + if (!prfx[i]) { + *str = &(*str)[i]; + return 1; + } + return 0; +} + +static void +cpy(char **dst, char *src) +{ + int i; + for (i = 0; src[i]; i++) + (*dst)[i] = src[i]; + *dst = &(*dst)[i]; +} + +typedef enum { + STDLIB_NONE, + STDLIB_MD, + STDLIB_ML, + STDLIB_MT +} stdlib_t; + +int +main(int argc, char *argv[]) +{ + int res; + int i; + size_t cmd_len; + char *cmd; + char *cmd_end; + char *cc = NULL; + args_t args = {0}; + int is_debug = 0; + int is_purify = 0; + int is_quantify = 0; + int is_purecov = 0; +#ifdef __WIN32__ + int is_shared = 0; + stdlib_t stdlib = STDLIB_NONE; + char *shared_flag = ""; + char *stdlib_flag = ""; + int have_link_args = 0; + args_t link_args = {0}; + +#define CHECK_FIRST_LINK_ARG \ + if (!have_link_args) { \ + save_arg(&link_args, "-link", NULL); \ + have_link_args = 1; \ + } +#else /* #ifdef __WIN32__ */ +#define CHECK_FIRST_LINK_ARG +#endif /* #ifdef __WIN32__ */ + + prog = argv[0]; + + + for (i = 1; i < argc; i++) { + char *arg = argv[i]; + if (is_prefix("-CC", &arg)) { + cc = arg; + } + else if (is_prefix("-O", &arg)) { + if (!is_debug) + save_arg(&args, argv[i], NULL); + } + else if (strcmp("-DDEBUG", arg) == 0) { + save_arg(&args, arg, NULL); +#ifdef __WIN32__ + set_debug: +#endif + if (!is_debug) { + int j; + is_debug = 1; +#ifdef __WIN32__ + save_arg(&args, "-Z7", NULL); + CHECK_FIRST_LINK_ARG; + save_arg(&link_args, "-debug", NULL); + save_arg(&link_args, "-pdb:none", NULL); +#endif + for (j = 0; j < args.ix; j++) { + char *tmp_arg = args.vec[j]; + if (is_prefix("-O", &tmp_arg)) + args.vec[j] = ""; + } + } + } + else if (strcmp("-DPURIFY", arg) == 0) { + save_arg(&args, arg, NULL); + is_purify = 1; + } + else if (strcmp("-DQUANTIFY", arg) == 0) { + save_arg(&args, arg, NULL); + is_quantify = 1; + } + else if (strcmp("-DPURECOV", arg) == 0) { + save_arg(&args, arg, NULL); + is_purecov = 1; + } +#ifdef __WIN32__ + else if (strcmp("-g", arg) == 0) { + goto set_debug; + } + else if (strcmp("-MD", arg) == 0) + stdlib = STDLIB_MD; + else if (strcmp("-MDd", arg) == 0) { + stdlib = STDLIB_MD; + goto set_debug; + } + else if (strcmp("-ML", arg) == 0) + stdlib = STDLIB_ML; + else if (strcmp("-MLd", arg) == 0) { + stdlib = STDLIB_ML; + goto set_debug; + } + else if (strcmp("-MT", arg) == 0) + stdlib = STDLIB_MT; + else if (strcmp("-MTd", arg) == 0) { + stdlib = STDLIB_MT; + goto set_debug; + } + else if (strcmp("-shared", arg) == 0 || strcmp("-LD", arg) == 0) + is_shared = 1; + else if (strcmp("-LDd", arg) == 0) { + is_shared = 1; + goto set_debug; + } + else if (strcmp("-Wall", arg) == 0) { + save_arg(&args, "-W3", NULL); + } + else if (is_prefix("-L", &arg)) { + CHECK_FIRST_LINK_ARG; + save_arg(&link_args, "-libpath:", arg, NULL); + } +#endif /* #ifdef __WIN32__ */ + else if (is_prefix("-l", &arg)) { + CHECK_FIRST_LINK_ARG; + if (is_debug && strcmp("ethread", arg) == 0) + arg = "ethread.debug"; + else if (is_purify && strcmp("ethread", arg) == 0) + arg = "ethread.purify"; + else if (is_quantify && strcmp("ethread", arg) == 0) + arg = "ethread.quantify"; + else if (is_purecov && strcmp("ethread", arg) == 0) + arg = "ethread.purecov"; +#ifdef __WIN32__ + else if (strcmp("socket", arg) == 0) + arg = "ws2_32"; + save_arg(&link_args, arg, ".lib", NULL); +#else + save_arg(&args, "-l", arg, NULL); +#endif + } + else + save_arg(&args, argv[i], NULL); + } + + if (!cc || !cc[0]) { + fprintf(stderr, "%s: Missing compulsory -CC flag%s", prog, EOL); + exit(1); + } + + cmd_len = strlen(cc) + 1 + args.chars + 1; + +#ifdef __WIN32__ + if (is_shared) + shared_flag = is_debug ? "-LDd " : "-LD "; + switch (stdlib) { + case STDLIB_MD: stdlib_flag = is_debug ? "-MDd " : "-MD "; break; + case STDLIB_ML: stdlib_flag = is_debug ? "-MLd " : "-ML "; break; + case STDLIB_MT: stdlib_flag = is_debug ? "-MTd " : "-MT "; break; + case STDLIB_NONE: break; + } + + cmd_len += strlen(shared_flag) + strlen(stdlib_flag) + link_args.chars; +#endif + + cmd = (char *) malloc(sizeof(char) * cmd_len); + + if (!cmd) + enomem(); + cmd_end = cmd; + cpy(&cmd_end, cc); + cpy(&cmd_end, " "); +#ifdef __WIN32__ + cpy(&cmd_end, stdlib_flag); + cpy(&cmd_end, shared_flag); +#endif + for (i = 0; i < args.ix; i++) + cpy(&cmd_end, args.vec[i]); +#ifdef __WIN32__ + for (i = 0; i < link_args.ix; i++) + cpy(&cmd_end, link_args.vec[i]); +#endif + *cmd_end = '\0'; + + printf("==> %s%s", cmd, EOL); + fflush(stdout); + +#ifdef USE_EXEC + (void) execl("/bin/sh", "sh", "-c", cmd, (char *) NULL); + perror(NULL); + res = 1; +#else + res = system(cmd); +#endif + + free((void *) args.vec); +#ifdef __WIN32__ + free((void *) link_args.vec); +#endif + free((void *) cmd); + + if (res < 0) + res = 1; + return res; +} diff --git a/lib/erl_interface/test/all_SUITE_data/gccifier.sh b/lib/erl_interface/test/all_SUITE_data/gccifier.sh new file mode 100755 index 0000000000..42253213b1 --- /dev/null +++ b/lib/erl_interface/test/all_SUITE_data/gccifier.sh @@ -0,0 +1,26 @@ +#!/bin/sh +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2005-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# + +CC=`echo "$1" | sed -e "s/-CC//"` +shift +echo "->" +echo "$CC $*" +$CC $* +echo "" diff --git a/lib/erl_interface/test/all_SUITE_data/init_tc.erl b/lib/erl_interface/test/all_SUITE_data/init_tc.erl new file mode 100644 index 0000000000..8157d590fc --- /dev/null +++ b/lib/erl_interface/test/all_SUITE_data/init_tc.erl @@ -0,0 +1,101 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1997-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +-module(init_tc). + +-export([run/1]). + +%% The argument should be a list of filenames (atoms), without extension +%% A .c extension is assumed. +%% + +run([Name|Rest]) -> + case catch run1(atom_to_list(Name)) of + {'EXIT', Reason} -> + io:format("Failed: ~p~n", [Reason]), + halt(1); + _Other -> + run(Rest) + end; +run([]) -> + ok. + +run1(Name) -> + CFile = Name ++ ".c", + {ok, Bin} = file:read_file(CFile), + String = binary_to_list(Bin), + + %% This ConstPart stuff is because you can't retrieve part of a match. + %% Long live Perl! + + ConstPart = "\nTESTCASE\\(", + ConstPartLen = 10, + {match, Matches} = regexp:matches(String, ConstPart++"[_a-zA-Z]*"), + Cases = get_names(Matches, ConstPartLen, Bin, []), + generate(Name, Cases). + +get_names([{Start, Length}|Rest], Skip, Bin, Result) -> + Name = binary_to_list(Bin, Start+Skip, Start+Length-1), + get_names(Rest, Skip, Bin, [Name|Result]); +get_names([], _Skip, _Bin, Result) -> + lists:reverse(Result). + +generate(TcName, Cases) -> + Hrl = TcName ++ "_cases.hrl", + {ok, HrlFile} = file:open(Hrl, write), + {ok, Dir} = file:get_cwd(), + generate_hrl(Cases, HrlFile, {filename:join(Dir, TcName), 0}), + file:close(HrlFile), + C = TcName ++ "_decl.c", + {ok, CFile} = file:open(C, write), + generate_c(Cases, CFile, TcName), + file:close(CFile). + +generate_hrl([Case|Rest], File, {Name, Number}) -> + io:format(File, "-define(~s, {\"~s\", ~w}).~n", [Case, Name, Number]), + generate_hrl(Rest, File, {Name, Number+1}); +generate_hrl([], _, _) -> + ok. + +generate_c(Cases, File, TcName) -> + E= case lists:prefix("ei_", TcName) of + true -> "ei_"; + false -> "" + end, + io:format(File, "#include \"~srunner.h\"\n", [E]), + lists:foreach( + fun(Case) -> + io:format(File, "extern void ~s(void);~n", + [Case]) end, + Cases), + io:format(File, "~nstatic TestCase test_cases[] = {~n", []), + lists:foreach(fun(Case) -> io:format(File, " ~s,~n", [Case]) end, Cases), + io:format(File, "~s", + [["};\n\n", + "#ifdef VXWORKS\n", + "int ", TcName, "(int argc, char* argv[])\n", + "#else\n", + "int main(int argc, char* argv[])\n", + "#endif\n", + "{\n", + " run_tests(argv[0], test_cases, ", + "sizeof(test_cases)/sizeof(test_cases[0]));\n", + " return 0;\n", + "}\n"]]). diff --git a/lib/erl_interface/test/all_SUITE_data/reclaim.h b/lib/erl_interface/test/all_SUITE_data/reclaim.h new file mode 100644 index 0000000000..00fdfc38dc --- /dev/null +++ b/lib/erl_interface/test/all_SUITE_data/reclaim.h @@ -0,0 +1,151 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2001-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + + */ +#ifndef _RECLAIM_H +#define _RECLAIM_H + + +/* The Erlang release for VxWorks includes a simple mechanism for + "resource reclamation" at task exit - it allows replacement of the + functions that open/close "files" and malloc/free memory with versions + that keep track, to be able to "reclaim" file descriptors and memory + when a task exits (regardless of *how* it exits). + + The interface to this mechanism is made available via this file, + with the following caveats: + + - The interface may change (or perhaps even be removed, though that + isn't likely until VxWorks itself provides similar functionality) + in future releases - i.e. you must always use the version of this + file that comes with the Erlang release you are using. + + - Disaster is guaranteed if you use the mechanism incorrectly (see + below for the correct way), e.g. allocate memory with the "tracking" + version of malloc() and free it with the "standard" version of free(). + + - The mechanism (of course) incurs some performance penalty - thus + for a simple program you may be better off with careful programming, + making sure that you do whatever close()/free()/etc calls that are + appropriate at all exit points (though if you need to guard against + taskDelete() etc, things get messy...). + + To use the mechanism, simply program your application normally, i.e. + use open()/close()/malloc()/free() etc as usual, but #include this + file before any usage of the relevant functions. NOTE: To avoid the + "disaster" mentioned above, you *must* #include it in *all* (or none) + of the files that manipulate a particular file descriptor, allocated + memory area, etc. + + Before any task that uses this utility is loaded (which includes the + erlang emulator), the reclaim.o object file has to be loaded and + the function reclaim_init() has to be called. reclaim_init should be called + only _ONCE_ in a systems lifetime and has only a primitive guard + against multiple calls (i.e. a global variable is checked). Therefore + the initialization should occur either in the start script of the system + or (even better) in the usrInit() part of system initialization. The + object file itself should be loaded only once, so linking it with the + kernel is a good idea, linking with each application is an extremely bad + dito. Make really sure that it's loaded _before_ any application that + uses it if You want to load it in the startup script. + + If You dont want to have #define's for the posix/stdio names + of the file/memory operations (i.e. no #define malloc save_malloc etc), + #define RECLAIM_NO_ALIAS in Your source before reclaim.h is included. +*/ + +#include <vxWorks.h> /* STATUS, size_t */ +#include <sockLib.h> /* struct sockaddr */ +#include <stdio.h> /* FILE */ + +#if defined(__STDC__) +#define _RECLAIM_DECL_FUN(RetType, FunName, ParamList) \ +extern RetType FunName##ParamList +#define _RECLAIM_VOID_PTR void * +#define _RECLAIM_VOID_PARAM void +#define _RECLAIM_VOID_RETURN void +#elif defined(__cplusplus) +#define _RECLAIM_DECL_FUN(RetType, FunName, ParamList) \ +extern "C" RetType FunName##ParamList +#define _RECLAIM_VOID_PTR void * +#define _RECLAIM_VOID_PARAM +#define _RECLAIM_VOID_RETURN void +#else +#define _RECLAIM_DECL_FUN(RetType, FunName, Ignore) extern RetType FunName() +#define DECLARE_FUNCTION_TYPE(RetType, Type, PList) typedef RetType (* Type)() +#define _RECLAIM_VOID_PTR char * +#define _RECLAIM_VOID_PARAM +#define _RECLAIM_VOID_RETURN +#endif /* __STDC__ / __cplusplus */ + +/* Initialize the facility, on a per system basis. */ +_RECLAIM_DECL_FUN(STATUS, reclaim_init, (_RECLAIM_VOID_PARAM)); + +/* File descriptor operations */ +_RECLAIM_DECL_FUN(int,save_open,(char *, int, ...)); +_RECLAIM_DECL_FUN(int,save_creat,(char *, int)); +_RECLAIM_DECL_FUN(int,save_socket,(int, int, int)); +_RECLAIM_DECL_FUN(int,save_accept,(int, struct sockaddr *, int *)); +_RECLAIM_DECL_FUN(int,save_close,(int)); +/* Interface to add an fd to what's reclaimed even though it's not open with + one of the above functions */ +_RECLAIM_DECL_FUN(_RECLAIM_VOID_RETURN, save_fd, (int fd)); +#ifndef RECLAIM_NO_ALIAS +#define open save_open +#define creat save_creat +#define socket save_socket +#define accept save_accept +#define close save_close +#endif +/* Stdio file operations */ +_RECLAIM_DECL_FUN(FILE *, save_fopen, (char *, char *)); +_RECLAIM_DECL_FUN(FILE *, save_fdopen, (int, char *)); +_RECLAIM_DECL_FUN(FILE *, save_freopen, (char *, char *, FILE *)); +_RECLAIM_DECL_FUN(int, save_fclose, (FILE *)); +/* XXX Should do opendir/closedir too... */ +#ifndef RECLAIM_NO_ALIAS +#define fopen save_fopen +#define fdopen save_fdopen +#define freopen save_freopen +#define fclose save_fclose +#endif +/* Memory allocation */ +_RECLAIM_DECL_FUN(_RECLAIM_VOID_PTR, save_malloc, (size_t)); +_RECLAIM_DECL_FUN(_RECLAIM_VOID_PTR, save_calloc, (size_t, size_t)); +_RECLAIM_DECL_FUN(_RECLAIM_VOID_PTR, save_realloc, + (_RECLAIM_VOID_PTR, size_t)); +_RECLAIM_DECL_FUN(void, save_free, (_RECLAIM_VOID_PTR)); +_RECLAIM_DECL_FUN(void, save_cfree, (_RECLAIM_VOID_PTR)); +#ifndef RECLAIM_NO_ALIAS +#define malloc save_malloc +#define calloc save_calloc +#define realloc save_realloc +#define free save_free +#define cfree save_cfree +#endif +/* Generic interfaces to malloc etc... */ +_RECLAIM_DECL_FUN(_RECLAIM_VOID_PTR, plain_malloc, (size_t)); +_RECLAIM_DECL_FUN(_RECLAIM_VOID_PTR, plain_realloc, + (_RECLAIM_VOID_PTR, size_t)); +_RECLAIM_DECL_FUN(void, plain_free, (_RECLAIM_VOID_PTR)); +#endif /* _RECLAIM_H */ + + + + diff --git a/lib/erl_interface/test/all_SUITE_data/runner.c b/lib/erl_interface/test/all_SUITE_data/runner.c new file mode 100644 index 0000000000..24df0f5f40 --- /dev/null +++ b/lib/erl_interface/test/all_SUITE_data/runner.c @@ -0,0 +1,457 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1997-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ + +#include <stdio.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#ifndef __WIN32__ +#include <unistd.h> +#endif +#include <stdarg.h> + +#include "runner.h" + +#ifndef __WIN32__ +#define _O_BINARY 0 +#define _setmode(fd, mode) +#endif + +#define HEADER_SIZE 4 + +static char* progname; /* Name of this program (from argv[0]). */ +static int fd_from_erl; /* File descriptor from Erlang. */ +static int fd_to_erl; /* File descriptor to Erlang. */ + +static int packet_loop(); +static void ensure_buf_big_enough(); +static int readn(); +static void reply(char* buf, unsigned size); +static void dump(); + +void +run_tests(char* argv0, TestCase test_cases[], unsigned number) +{ + int i; + int n; + char* packet; + + progname = argv0; + _setmode(0, _O_BINARY); + _setmode(1, _O_BINARY); + fd_from_erl = 0; + fd_to_erl = 1; + + packet = read_packet(&n); + + /* + * Dispatch to the appropriate test function. + */ + + i = packet[0] * 256 + packet[1]; + if (i >= number) { + fprintf(stderr, "%s: bad test case number %d", + progname, i); + free(packet); + exit(1); + } else { + (*test_cases[i])(); + free(packet); + } +} + + +/*********************************************************************** + * + * R e a d i n g p a c k e t s + * + ************************************************************************/ + +/* + * Reads an Erlang term. + * + * Returns: A pointer to a term (an ETERM structure) if there was + * at term available, or a NULL pointer if there was an 'eot' (end-of-test) + * packet. Aborts if anything else received. + */ + +ETERM* +get_term(void) +{ + char* encoded; + ETERM* term; + int n; + + encoded = read_packet(&n); + + switch (encoded[0]) { + case 'e': + free(encoded); + return NULL; + case 't': + term = erl_decode(encoded+1); + free(encoded); + if (term == NULL) { + fail("Failed to decode term"); + exit(0); + } + return term; + default: + fprintf(stderr, "Garbage received: "); + dump(encoded, n, 16); + putc('\n', stderr); + fail("C program received garbage"); + free(encoded); + exit(1); + } +} + + +/* + * Reads a packet from Erlang. The packet must be a standard {packet, 2} + * packet. This function aborts if any error is detected (including EOF). + * + * Returns: The number of bytes in the packet. + */ + +char *read_packet(int *len) +{ + + unsigned char* io_buf = NULL; /* Buffer for file i/o. */ + int i; + unsigned char header[HEADER_SIZE]; + unsigned packet_length; /* Length of current packet. */ + int bytes_read; + + /* + * Read the packet header. + */ + + bytes_read = readn(fd_from_erl, header, HEADER_SIZE); + + if (bytes_read == 0) { + fprintf(stderr, "%s: Unexpected end of file\n", progname); + exit(1); + } + if (bytes_read != HEADER_SIZE) { + fprintf(stderr, "%s: Failed to read packet header\n", progname); + exit(1); + } + + /* + * Get the length of this packet. + */ + + packet_length = 0; + + for (i = 0; i < HEADER_SIZE; i++) + packet_length = (packet_length << 8) | header[i]; + + if (len) *len=packet_length; /* report length only if caller requested it */ + + if ((io_buf = (char *) malloc(packet_length)) == NULL) { + fprintf(stderr, "%s: insufficient memory for i/o buffer of size %d\n", + progname, packet_length); + exit(1); + } + + /* + * Read the packet itself. + */ + + bytes_read = readn(fd_from_erl, io_buf, packet_length); + if (bytes_read != packet_length) { + fprintf(stderr, "%s: couldn't read packet of length %d\r\n", + progname, packet_length); + free(io_buf); + exit(1); + } + + return io_buf; +} + + +/*********************************************************************** + * S e n d i n g r e p l i e s + * + * The functions below send various types of replies back to Erlang. + * Each reply start with a letter indicating the type of reply. + * + * Reply Translated to on Erlang side + * ----- ---------------------------- + * [$b|Bytes] {bytes, Bytes} + * [$e] eot + * [$f] test_server:fail() + * [$f|Reason] test_server:fail(Reason) + * [$t|EncodedTerm] {term, Term} + * [$N] 'NULL' + * [$m|Message] io:format("~s", [Message]) (otherwise ignored) + * + ***********************************************************************/ + +/* + * This function reports the outcome of a test fail. It is useful if + * you implement a test case entirely in C code. + * + * If the ok argument is zero, a [$f] reply will be sent to the + * Erlang side (causing test_server:fail() to be called); otherwise, + * the atom 'eot' will be sent to Erlang. + * + * If you need to provide more details on a failure, use the fail() function. + */ + +void +do_report(file, line, ok) + char* file; + int line; + int ok; /* Zero if failed; non-zero otherwise. */ +{ + char reason; + unsigned long ab; + unsigned long fb; + + reason = ok ? 'e' : 'f'; + + if (!ok) { + do_fail(file, line, "Generic failure"); + } else { + /* release all unallocated blocks */ + erl_eterm_release(); + /* check mem usage stats */ + erl_eterm_statistics(&ab, &fb); + if ((ab == 0) && (fb == 0) ) { + reply(&reason, 1); + } + else { + char sbuf[128]; + + sprintf(sbuf, "still %lu terms allocated," + " %lu on freelist at end of test", ab, fb); + do_fail(file, line, sbuf); + } + } +} + + +/* + * This function causes a call to test_server:fail(Reason) on the + * Erlang side. + */ + +void +do_fail(char* file, int line, char* reason) +{ + char sbuf[2048]; + + sbuf[0] = 'f'; + sprintf(sbuf+1, "%s, line %d: %s", file, line, reason); + reply(sbuf, 1+strlen(sbuf+1)); +} + +/* + * This function sends a message to the Erlang side. + * The message will be written to the test servers log file, + * but will otherwise be completly ignored. + */ + +void +message(char* format, ...) +{ + va_list ap; + char sbuf[1024]; + + sbuf[0] = 'm'; + va_start(ap, format); + vsprintf(sbuf+1, format, ap); + va_end(ap); + + reply(sbuf, 1+strlen(sbuf+1)); +} + +/* + * This function sends the given term to the Erlang side, + * where it will be received as {term, Term}. + * + * If the given pointer is NULL (indicating an invalid term), + * the result on the Erlang side will be the atom 'NULL'. + * + * After sending the term, this function frees the term by + * calling erl_free_term(). + */ + +void +send_term(term) + ETERM* term; /* Term to be sent to Erlang side. */ +{ + char encoded[64*1024]; + int n; + + if (term == NULL) { + encoded[0] = 'N'; + n = 1; + } else { + encoded[0] = 't'; + n = 1 + erl_encode(term, encoded+1); + erl_free_term(term); + } + reply(encoded, n); +} + +#if 0 + +/* Seriously broken!!! */ + +void +send_bin_term(x_ei_buff* x) +{ + x_ei_buff x2; + x_ei_new(&x2); + x2.buff[x2.index++] = 't'; + x_ei_append(&x2, x); + reply(x2.buff, x2.index); + free(x2.buff); +} +#endif + +/* + * This function sends a raw buffer of data to the + * Erlang side, where it will be received as {bytes, Bytes}. + */ + +void +send_buffer(buf, size) + char* buf; /* Buffer with bytes to send to Erlang. */ + int size; /* Size of data to send to Erlang. */ +{ + char* send_buf; + + send_buf = (char *) malloc(size+1); + send_buf[0] = 'b'; + memcpy(send_buf+1, buf, size); + reply(send_buf, size+1); + free(send_buf); +} + +/*********************************************************************** + * + * P r i v a t e h e l p e r s + * + ***********************************************************************/ + +/* + * Sends a packet back to Erlang. + */ + +static void +reply(reply_buf, size) + char* reply_buf; /* Buffer with reply. */ + unsigned size; /* Size of reply. */ +{ + int n; /* Temporary to hold size. */ + int i; /* Loop counter. */ + char* buf; + + + buf = (char *) malloc(size+HEADER_SIZE); + memcpy(buf+HEADER_SIZE, reply_buf, size); + + /* + * Fill the header starting with the least significant byte. + */ + + n = size; + for (i = HEADER_SIZE-1; i >= 0; i--) { + buf[i] = (char) n; /* Store least significant byte. */ + n = n >> 8; + } + + size += HEADER_SIZE; +/* + fprintf(stderr, "\r\nReply size: %u\r\n", + (unsigned)buf[0] << 8 + (unsigned)buf[1]); + + for (i = 0; i < size; i++) { + fprintf(stderr,"%u %c\r\n",buf[i],buf[i]); + } + + fprintf(stderr, "\r\n"); +*/ + write(fd_to_erl, buf, size); + free(buf); +} + + +/* + * Reads len number of bytes. + */ + +static int +readn(fd, buf, len) + int fd; /* File descriptor to read from. */ + unsigned char *buf; /* Store in this buffer. */ + int len; /* Number of bytes to read. */ +{ + int n; /* Byte count in last read call. */ + int sofar = 0; /* Bytes read so far. */ + + do { + if ((n = read(fd, buf+sofar, len-sofar)) <= 0) + /* error or EOF in read */ + return(n); + sofar += n; + } while (sofar < len); + return sofar; +} + +void +dump(buf, sz, max) + unsigned char* buf; + int sz; + int max; +{ + int i, imax; + char comma[5] = ","; + + if (!sz) + return; + if (sz > max) + imax = max; + else + imax = sz; + + for (i=0; i<imax; i++) { + if (i == imax-1) { + if (sz > max) + strcpy(comma, ",..."); + else + comma[0] = 0; + } + if (isdigit(buf[i])) + fprintf(stderr, "%u%s", (int)(buf[i]), comma); + else { + if (isalpha(buf[i])) { + fprintf(stderr, "%c%s", buf[i], comma); + } + else + fprintf(stderr, "%u%s", (int)(buf[i]), comma); + } + } +} + diff --git a/lib/erl_interface/test/all_SUITE_data/runner.h b/lib/erl_interface/test/all_SUITE_data/runner.h new file mode 100644 index 0000000000..fb29d5166d --- /dev/null +++ b/lib/erl_interface/test/all_SUITE_data/runner.h @@ -0,0 +1,50 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1997-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ + +#include "erl_interface.h" + +typedef void (*TestCase)(void); + +#define TESTCASE(name) void name(void) +#define ASIZE(a) (sizeof(a)/sizeof(a[0])) + +void run_tests(char* argv0, TestCase cases[], unsigned number); + +/* + * Reading. + */ + +ETERM* get_term(void); +char *read_packet(int *len); + +/* + * Sending replies. + */ + +#define fail(reason) do_fail(__FILE__, __LINE__, reason) +#define report(ok) do_report(__FILE__, __LINE__, ok) + +void do_report(char* file, int line, int ok); +void do_fail(char* file, int line, char* reason); +void send_term(ETERM* term); +void send_buffer(char* buf, int size); +void message(char* format, ...); + +void send_bin_term(ei_x_buff* x); + diff --git a/lib/erl_interface/test/ei_accept_SUITE.erl b/lib/erl_interface/test/ei_accept_SUITE.erl new file mode 100644 index 0000000000..bc83d6a62e --- /dev/null +++ b/lib/erl_interface/test/ei_accept_SUITE.erl @@ -0,0 +1,151 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2001-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +-module(ei_accept_SUITE). + +-include("test_server.hrl"). +-include("ei_accept_SUITE_data/ei_accept_test_cases.hrl"). + +-export([all/1, init_per_testcase/2, fin_per_testcase/2, + ei_accept/1, ei_threaded_accept/1]). + +-import(runner, [get_term/1,send_term/2]). + +all(suite) -> [ei_accept, ei_threaded_accept]. + +init_per_testcase(_Case, Config) -> + Dog = ?t:timetrap(?t:minutes(0.25)), + [{watchdog, Dog}|Config]. + +fin_per_testcase(_Case, Config) -> + Dog = ?config(watchdog, Config), + test_server:timetrap_cancel(Dog), + ok. + +ei_accept(Config) when is_list(Config) -> + ?line P = runner:start(?interpret), + ?line 0 = ei_connect_init(P, 42, erlang:get_cookie(), 0), + +% ?line AMsg={a,[message, with], " strings in it!", [-12, -23], 1.001}, + %% shouldn't this be a bif or function or something? + ?line Myname= hd(tl(string:tokens(atom_to_list(node()), "@"))), + ?line io:format("Myname ~p ~n", [Myname]), + ?line EINode= list_to_atom("c42@"++Myname), + ?line io:format("EINode ~p ~n", [EINode]), + ?line Self= self(), + ?line TermToSend= {call, Self, "Test"}, + ?line F= fun() -> + timer:sleep(500), + {any, EINode} ! TermToSend, + Self ! sent_ok, + ok + end, + + ?line spawn(F), + ?line Port = 6543, + ?line {ok, Fd, _Node} = ei_accept(P, Port), + ?line TermReceived= ei_receive(P, Fd), + ?line io:format("Sent ~p received ~p ~n", [TermToSend, TermReceived]), + ?line TermToSend= TermReceived, + ?line receive + sent_ok -> + ok; + Unknown -> + io:format("~p ~n", [Unknown]) + after 1000 -> + io:format("timeout ~n") + end, + ?line ok= ei_unpublish(P), + ok. + +ei_threaded_accept(Config) when is_list(Config) -> + ?line Einode = filename:join(?config(data_dir, Config), "eiaccnode"), + ?line N = 1, % 3, + ?line Host = atom_to_list(node()), + ?line Port = 6767, + ?line start_einode(Einode, N, Host, Port), + ?line io:format("started eiaccnode"), + %%?line spawn_link(fun() -> start_einode(Einode, N, Host, Port) end), + ?line TestServerPid = self(), + ?line [ spawn_link(fun() -> send_rec_einode(I, TestServerPid) end) + || I <- lists:seq(0, N-1) ], + ?line [ receive I -> ok end + || I <- lists:seq(0, N-1) ], + ok. + +send_rec_einode(N, TestServerPid) -> + ?line Myname= hd(tl(string:tokens(atom_to_list(node()), "@"))), + ?line EINode= list_to_atom("eiacc" ++ integer_to_list(N) ++ "@" ++ Myname), + ?line io:format("EINode ~p ~n", [EINode]), + ?line Self= self(), + ?line timer:sleep(10*1000), + ?line {any, EINode} ! Self, + ?line receive + {N,_}=X -> + ?line io:format("Received by ~s ~p~n", [EINode, X]), + ?line TestServerPid ! N, + ?line X + after 10000 -> + ?line test_server:fail(EINode) + end. + +start_einode(Einode, N, Host, Port) -> + Einodecmd = Einode ++ " " ++ atom_to_list(erlang:get_cookie()) + ++ " " ++ integer_to_list(N) ++ " " ++ Host ++ " " + ++ integer_to_list(Port) ++ " nothreads", + io:format("Einodecmd ~p ~n", [Einodecmd]), + ?line open_port({spawn, Einodecmd}, []), + ok. + + + +%%% Interface functions for ei (erl_interface) functions. + +ei_connect_init(P, Num, Cookie, Creation) -> + send_command(P, ei_connect_init, [Num,Cookie,Creation]), + case get_term(P) of + {term,Int} when is_integer(Int) -> Int + end. + +ei_accept(P, PortNo) -> + send_command(P, ei_accept, [PortNo]), + case get_term(P) of + {term,{Fd, _, Node}} when Fd >= 0 -> {ok, Fd, Node}; + {term,{_Fd, Errno, _Node}} -> {error,Errno} + end. + +ei_receive(P, Fd) -> + send_command(P, ei_receive, [Fd]), + {term, T}= get_term(P), + T. + +ei_unpublish(P) -> + send_command(P, ei_unpublish, []), + case get_term(P) of + {term,{0, _}} -> ok; + {term,{_X, Errno}} -> {error,Errno} + end. + +send_command(P, Name, Args) -> + runner:send_term(P, {Name,list_to_tuple(Args)}). + + + + diff --git a/lib/erl_interface/test/ei_accept_SUITE_data/Makefile.first b/lib/erl_interface/test/ei_accept_SUITE_data/Makefile.first new file mode 100644 index 0000000000..d7ec976cd0 --- /dev/null +++ b/lib/erl_interface/test/ei_accept_SUITE_data/Makefile.first @@ -0,0 +1,21 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2001-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# + +ei_accept_test_decl.c: ei_accept_test.c + erl -noinput -pa ../all_SUITE_data -s init_tc run ei_accept_test -s erlang halt diff --git a/lib/erl_interface/test/ei_accept_SUITE_data/Makefile.src b/lib/erl_interface/test/ei_accept_SUITE_data/Makefile.src new file mode 100644 index 0000000000..9b751d8f65 --- /dev/null +++ b/lib/erl_interface/test/ei_accept_SUITE_data/Makefile.src @@ -0,0 +1,45 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2001-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# + +include @erl_interface_mk_include@@[email protected] + +CC0 = @CC@ +CC = ..@DS@all_SUITE_data@DS@gccifier@exe@ -CC"$(CC0)" +LD = @LD@ +LIBPATH = @erl_interface_libpath@ +LIBEI = $(LIBPATH)/@erl_interface_eilib@ +LIBFLAGS = ../all_SUITE_data/ei_runner@obj@ \ + $(LIBEI) @LIBS@ @erl_interface_sock_libs@ \ + @erl_interface_threadlib@ +CFLAGS = @EI_CFLAGS@ $(THR_DEFS) -I@erl_interface_include@ -I../all_SUITE_data +EI_ACCEPT_OBJS = ei_accept_test@obj@ ei_accept_test_decl@obj@ +EIACCNODE_OBJS = eiaccnode@obj@ + +all: ei_accept_test@exe@ eiaccnode@exe@ + +clean: + $(RM) $(EI_ACCEPT_OBJS) $(EIACCNODE_OBJS) + $(RM) ei_accept_test@exe@ eiaccnode@exe@ + +ei_accept_test@exe@: $(EI_ACCEPT_OBJS) $(LIBEI) + $(LD) @CROSSLDFLAGS@ -o $@ $(EI_ACCEPT_OBJS) $(LIBFLAGS) + + +eiaccnode@exe@: $(EIACCNODE_OBJS) $(LIBEI) + $(LD) @CROSSLDFLAGS@ -o $@ $(EIACCNODE_OBJS) $(LIBFLAGS) diff --git a/lib/erl_interface/test/ei_accept_SUITE_data/ei_accept_test.c b/lib/erl_interface/test/ei_accept_SUITE_data/ei_accept_test.c new file mode 100644 index 0000000000..5f898b5944 --- /dev/null +++ b/lib/erl_interface/test/ei_accept_SUITE_data/ei_accept_test.c @@ -0,0 +1,224 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2001-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ + +/* + * Purpose: Tests the accept function in ei_connect.c. + * Author: Jakob Cederlund (taken from erl_connect by Bj�rn Gustavsson) + * + * See the ei_accept_SUITE.erl file for a "table of contents". + */ + +#include <stdio.h> +#include <string.h> +#ifdef VXWORKS +#include "reclaim.h" +#endif + +#ifdef __WIN32__ +#include <winsock2.h> +#include <windows.h> +#else +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#endif + +#include "ei_runner.h" + +static void cmd_ei_connect_init(char* buf, int len); +static void cmd_ei_accept(char* buf, int len); +static void cmd_ei_receive(char* buf, int len); +static void cmd_ei_unpublish(char* buf, int len); + +static void send_errno_result(int value); + +ei_cnode ec; + + +static struct { + char* name; + int num_args; /* Number of arguments. */ + void (*func)(char* buf, int len); +} commands[] = { + "ei_connect_init", 3, cmd_ei_connect_init, + "ei_accept", 1, cmd_ei_accept, + "ei_receive", 1, cmd_ei_receive, + "ei_unpublish", 0, cmd_ei_unpublish +}; + +/* + * Sends a list contaning all data types to the Erlang side. + */ +TESTCASE(interpret) +{ + ei_x_buff x; + int i; + ei_term term; + + ei_x_new(&x); + for (;;) { + if (get_bin_term(&x, &term)) { + report(1); + return; + } else { + char* buf = x.buff, func[MAXATOMLEN]; + int index = x.index, arity; + if (term.ei_type != ERL_SMALL_TUPLE_EXT || term.arity != 2) + fail("term should be a tuple of size 2"); + if (ei_decode_atom(buf, &index, func) < 0) + fail("function name should be an atom"); + if (ei_decode_tuple_header(buf, &index, &arity) != 0) + fail("function arguments should be a tuple"); + for (i = 0; i < sizeof(commands)/sizeof(commands[0]); i++) { + if (strcmp(func, commands[i].name) == 0) { + if (arity != commands[i].num_args) + fail("wrong number of arguments"); + commands[i].func(buf + index, x.buffsz - index); + break; + } + } + if (i >= sizeof(commands)/sizeof(commands[0])) { + message("\"%d\" \n", func); + fail("bad command"); + } + } + } +} + +static void cmd_ei_connect_init(char* buf, int len) +{ + int index = 0, r = 0; + int type, size; + long l; + char b[100]; + char cookie[MAXATOMLEN], * cp = cookie; + ei_x_buff res; + if (ei_decode_long(buf, &index, &l) < 0) + fail("expected int"); + sprintf(b, "c%d", l); + /* FIXME don't use internal and maybe use skip?! */ + ei_get_type_internal(buf, &index, &type, &size); + if (ei_decode_atom(buf, &index, cookie) < 0) + fail("expected atom (cookie)"); + if (cookie[0] == '\0') + cp = NULL; + r = ei_connect_init(&ec, b, cp, 0); + ei_x_new_with_version(&res); + ei_x_encode_long(&res, r); + send_bin_term(&res); + ei_x_free(&res); +} + +static int my_listen(int port) +{ + int listen_fd; + struct sockaddr_in addr; + const char *on = "1"; + + if ((listen_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) + return -1; + + setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, on, sizeof(on)); + + memset((void*) &addr, 0, (size_t) sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_port = htons(port); + addr.sin_addr.s_addr = htonl(INADDR_ANY); + + if (bind(listen_fd, (struct sockaddr*) &addr, sizeof(addr)) < 0) + return -1; + + listen(listen_fd, 5); + return listen_fd; +} + +static void cmd_ei_accept(char* buf, int len) +{ + int index = 0; + int listen, r; + ErlConnect conn; + long port; + ei_x_buff x; + int i; + + /* get port */ + if (ei_decode_long(buf, &index, &port) < 0) + fail("expected int (port)"); + /* Make a listen socket */ + if ((listen = my_listen(port)) <= 0) + fail("listen"); + + if ((i = ei_publish(&ec, port)) == -1) + fail("ei_publish"); +#ifdef VXWORKS + save_fd(i); +#endif + r = ei_accept(&ec, listen, &conn); +#ifdef VXWORKS + save_fd(r); +#endif + /* send result, errno and nodename */ + ei_x_new_with_version(&x); + ei_x_encode_tuple_header(&x, 3); + ei_x_encode_long(&x, r); + ei_x_encode_long(&x, erl_errno); + ei_x_encode_atom(&x, conn.nodename); /* or rather string? */ + send_bin_term(&x); + ei_x_free(&x); +} + +static void cmd_ei_receive(char* buf, int len) +{ + ei_x_buff x; + erlang_msg msg; + long l; + int fd, index = 0; + + if (ei_decode_long(buf, &index, &l) < 0) + fail("expected int (fd)"); + fd = l; + ei_x_new(&x); + for (;;) { + int got = ei_xreceive_msg(fd, &msg, &x); + if (got == ERL_TICK) + continue; + if (got == ERL_ERROR) + fail("ei_xreceive_msg"); + break; + } + index = 1; + send_bin_term(&x); + ei_x_free(&x); +} + +static void cmd_ei_unpublish(char* buf, int len) +{ + send_errno_result(ei_unpublish(&ec)); +} + +static void send_errno_result(int value) +{ + ei_x_buff x; + ei_x_new_with_version(&x); + ei_x_encode_tuple_header(&x, 2); + ei_x_encode_long(&x, value); + ei_x_encode_long(&x, erl_errno); + send_bin_term(&x); + ei_x_free(&x); +} diff --git a/lib/erl_interface/test/ei_accept_SUITE_data/eiaccnode.c b/lib/erl_interface/test/ei_accept_SUITE_data/eiaccnode.c new file mode 100644 index 0000000000..af58f75963 --- /dev/null +++ b/lib/erl_interface/test/ei_accept_SUITE_data/eiaccnode.c @@ -0,0 +1,234 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2001-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ + +/* to test multiple threads in ei */ + +#include <stdlib.h> +#include <stdio.h> + +#ifdef __WIN32__ +#include <winsock2.h> +#include <windows.h> +#include <process.h> +#else +#ifndef VXWORKS +#include <pthread.h> +#endif +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#endif + +#include "ei.h" + +#ifdef VXWORKS +#include <vxWorks.h> +#include <sockLib.h> +#include <inetLib.h> +#define MAIN cnode +#else +#define MAIN main +#endif + +static int my_listen(int port); + +/* + A small einode. + To be called from the test case ei_accept_SUITE:multi_thread + usage: eiaccnode <cookie> <n> + + - start threads 0..n-1 + - in each thread + - listen on "ei0" .. "ei<n-1>" + - wait for connection + - receive a pid + - send {i, <pid>} back + - shutdown gracefully +*/ + +static const char* cookie, * desthost; +static int port; /* actually base port */ + +#ifndef SD_SEND +#ifdef SHUTWR +#define SD_SEND SHUT_WR +#else +#define SD_SEND 1 +#endif +#endif + +#ifndef __WIN32__ +#define closesocket(fd) close(fd) +#endif + +#ifdef __WIN32__ +static DWORD WINAPI +#else +static void* +#endif + einode_thread(void* num) +{ + int n = (int)num; + ei_cnode ec; + char myname[100], destname[100]; + int r, fd, listen; + ErlConnect conn; + erlang_msg msg; +/* FILE* f;*/ + + sprintf(myname, "eiacc%d", n); + printf("thread %d (%s) listening\n", n, myname, destname); + r = ei_connect_init(&ec, myname, cookie, 0); + if ((listen = my_listen(port+n)) <= 0) { + printf("listen err\n"); + exit(7); + } + if (ei_publish(&ec, port + n) == -1) { + printf("ei_publish port %d\n", port+n); + exit(8); + } + fd = ei_accept(&ec, listen, &conn); + printf("ei_accept %d\n", fd); + if (fd >= 0) { + ei_x_buff x, xs; + int index, version; + erlang_pid pid; + + ei_x_new(&x); + for (;;) { + int got = ei_xreceive_msg(fd, &msg, &x); + if (got == ERL_TICK) + continue; + if (got == ERL_ERROR) { + printf("receive error %d\n", n); + return 0; + } + printf("received %d\n", got); + break; + } + index = 0; + if (ei_decode_version(x.buff, &index, &version) != 0) { + printf("ei_decode_version %d\n", n); + return 0; + } + if (ei_decode_pid(x.buff, &index, &pid) != 0) { + printf("ei_decode_pid %d\n", n); + return 0; + } +/* fprintf(f, "got pid from %s \n", pid.node);*/ + ei_x_new_with_version(&xs); + ei_x_encode_tuple_header(&xs, 2); + ei_x_encode_long(&xs, n); + ei_x_encode_pid(&xs, &pid); + r = ei_send(fd, &pid, xs.buff, xs.index); +/* fprintf(f, "sent %d bytes %d\n", xs.index, r);*/ + shutdown(fd, SD_SEND); + closesocket(fd); + ei_x_free(&x); + ei_x_free(&xs); + } else { + printf("coudn't connect fd %d r %d\n", fd, r); + } + printf("done thread %d\n", n); +/* fclose(f);*/ + return 0; +} + +MAIN(int argc, char *argv[]) +{ + int i, n, no_threads; +#ifndef VXWORKS +#ifdef __WIN32__ + HANDLE threads[100]; +#else + pthread_t threads[100]; +#endif +#endif + + if (argc < 3) + exit(1); + + cookie = argv[1]; + n = atoi(argv[2]); + if (n > 100) + exit(2); + desthost = argv[3]; + port = atoi(argv[4]); +#ifndef VXWORKS + no_threads = argv[5] != NULL && strcmp(argv[5], "nothreads") == 0; +#else + no_threads = 1; +#endif + for (i = 0; i < n; ++i) { + if (!no_threads) { +#ifndef VXWORKS +#ifdef __WIN32__ + unsigned tid; + threads[i] = (HANDLE)_beginthreadex(NULL, 0, einode_thread, + (void*)i, 0, &tid); +#else + pthread_create(&threads[i], NULL, einode_thread, (void*)i); +#endif +#else + ; +#endif + } else + einode_thread((void*)i); + } + + if (!no_threads) +#ifndef VXWORKS + for (i = 0; i < n; ++i) { +#ifdef __WIN32__ + if (WaitForSingleObject(threads[i], INFINITE) != WAIT_OBJECT_0) +#else + if (pthread_join(threads[i], NULL) != 0) +#endif + printf("bad wait thread %d\n", i); + } +#else + ; +#endif + printf("ok\n"); + return 0; +} + +static int my_listen(int port) +{ + int listen_fd; + struct sockaddr_in addr; + const char *on = "1"; + + if ((listen_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) + return -1; + + setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, on, sizeof(on)); + + memset((void*) &addr, 0, (size_t) sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_port = htons(port); + addr.sin_addr.s_addr = htonl(INADDR_ANY); + + if (bind(listen_fd, (struct sockaddr*) &addr, sizeof(addr)) < 0) + return -1; + + listen(listen_fd, 5); + return listen_fd; +} + diff --git a/lib/erl_interface/test/ei_connect_SUITE.erl b/lib/erl_interface/test/ei_connect_SUITE.erl new file mode 100644 index 0000000000..56f478edad --- /dev/null +++ b/lib/erl_interface/test/ei_connect_SUITE.erl @@ -0,0 +1,218 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2001-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +-module(ei_connect_SUITE). + +-include("test_server.hrl"). +-include("ei_connect_SUITE_data/ei_connect_test_cases.hrl"). + +-export([ + all/1, + init_per_testcase/2, + fin_per_testcase/2, + + ei_send/1, + ei_reg_send/1, + ei_rpc/1, + rpc_test/1, + ei_send_funs/1, + ei_threaded_send/1, + ei_set_get_tracelevel/1 + ]). + +-import(runner, [get_term/1,send_term/2]). + +all(suite) -> [ ei_send, + ei_reg_send, + ei_rpc, + ei_send_funs, + ei_threaded_send, + ei_set_get_tracelevel]. + +init_per_testcase(_Case, Config) -> + Dog = ?t:timetrap(?t:minutes(0.25)), + [{watchdog, Dog}|Config]. + +fin_per_testcase(_Case, Config) -> + Dog = ?config(watchdog, Config), + test_server:timetrap_cancel(Dog), + ok. + +ei_send(Config) when is_list(Config) -> + ?line P = runner:start(?interpret), + ?line 0 = ei_connect_init(P, 42, erlang:get_cookie(), 0), + ?line {ok,Fd} = ei_connect(P, node()), + + ?line ok = ei_send(P, Fd, self(), AMsg={a,message}), + ?line receive AMsg -> ok end, + + ?line runner:send_eot(P), + ?line runner:recv_eot(P), + ok. + +ei_send_funs(Config) when is_list(Config) -> + ?line P = runner:start(?interpret), + ?line 0 = ei_connect_init(P, 42, erlang:get_cookie(), 0), + ?line {ok,Fd} = ei_connect(P, node()), + + ?line Fun1 = fun ei_send/1, + ?line Fun2 = fun(X) -> P, X, Fd, Fun1 end, + + ?line AMsg={Fun1,Fun2}, + %%AMsg={wait_with_funs, new_dist_format}, + ?line ok = ei_send_funs(P, Fd, self(), AMsg), + ?line EIMsg = receive M -> M end, + ?line EIMsg = AMsg, + + ?line runner:send_eot(P), + ?line runner:recv_eot(P), + ok. + +ei_reg_send(Config) when is_list(Config) -> + ?line P = runner:start(?interpret), + ?line 0 = ei_connect_init(P, 42, erlang:get_cookie(), 0), + ?line {ok,Fd} = ei_connect(P, node()), + + ARegName = a_strange_registred_name, + ?line register(ARegName, self()), + ?line ok = ei_reg_send(P, Fd, ARegName, AMsg={another,[strange],message}), + ?line receive AMsg -> ok end, + + ?line runner:send_eot(P), + ?line runner:recv_eot(P), + ok. + +ei_threaded_send(Config) when is_list(Config) -> + ?line Einode = filename:join(?config(data_dir, Config), "einode"), + ?line N = 15, + ?line Host = atom_to_list(node()), + ?line spawn_link(fun() -> start_einode(Einode, N, Host) end), + ?line TestServerPid = self(), + ?line [ spawn_link(fun() -> rec_einode(I, TestServerPid) end) + || I <- lists:seq(0, N-1) ], + ?line [ receive I -> ok end + || I <- lists:seq(0, N-1) ], + ok. + +rec_einode(N, TestServerPid) -> + ?line Regname = list_to_atom("mth"++integer_to_list(N)), + ?line register(Regname, self()), + ?line io:format("~p waiting~n", [Regname]), + ?line receive + X -> + ?line io:format("Received by ~s ~p~n", [Regname, X]), + ?line TestServerPid ! N, + ?line X + after 10000 -> + ?line test_server:fail(Regname) + end. + +start_einode(Einode, N, Host) -> + Einodecmd = Einode ++ " " ++ atom_to_list(erlang:get_cookie()) + ++ " " ++ integer_to_list(N) ++ " " ++ Host, + io:format("Einodecmd ~p ~n", [Einodecmd]), + ?line open_port({spawn, Einodecmd}, []), + ok. + +ei_rpc(Config) when is_list(Config) -> + ?line P = runner:start(?interpret), + ?line 0 = ei_connect_init(P, 42, erlang:get_cookie(), 0), + ?line {ok,Fd} = ei_connect(P, node()), + + ?line S= "Hej du glade!", SRev = lists:reverse(S), + ?line X = ei_rpc(P, Fd, self(), {?MODULE, rpc_test}, [SRev]), + ?line {term, S}= X, + + ?line runner:send_eot(P), + ?line runner:recv_eot(P), + ok. + +ei_set_get_tracelevel(Config) when is_list(Config) -> + ?line P = runner:start(?interpret), + ?line 5 = ei_set_get_tracelevel(P, 5), + ?line 0 = ei_connect_init(P, 42, erlang:get_cookie(), 0), + ?line {ok,Fd} = ei_connect(P, node()), + + ?line S= "Hej du glade!", SRev = lists:reverse(S), + ?line X = ei_rpc(P, Fd, self(), {?MODULE, rpc_test}, [SRev]), + ?line {term, S}= X, + + ?line 0 = ei_set_get_tracelevel(P, 0), + + ?line runner:send_eot(P), + ?line runner:recv_eot(P), + ok. + + +%%% Interface functions for ei (erl_interface) functions. + +ei_connect_init(P, Num, Cookie, Creation) -> + send_command(P, ei_connect_init, [Num,Cookie,Creation]), + case get_term(P) of + {term,Int} when is_integer(Int) -> Int + end. + +ei_connect(P, Node) -> + send_command(P, ei_connect, [Node]), + case get_term(P) of + {term,{Fd,_}} when Fd >= 0 -> {ok,Fd}; + {term,{-1,Errno}} -> {error,Errno} + end. + +ei_set_get_tracelevel(P, Tracelevel) -> + send_command(P, ei_set_get_tracelevel, [Tracelevel]), + case get_term(P) of + {term,{tracelevel, Level}} when is_integer(Level) -> Level + end. + +ei_send(P, Fd, To, Msg) -> + send_command(P, ei_send, [Fd,To,Msg]), + get_send_result(P). + +ei_send_funs(P, Fd, To, Msg) -> + send_command(P, ei_send_funs, [Fd,To,Msg]), + get_send_result(P). + +ei_reg_send(P, Fd, To, Msg) -> + send_command(P, ei_reg_send, [Fd,To,Msg]), + get_send_result(P). + +ei_rpc(P, Fd, To, Func, Msg) -> + send_command(P, ei_rpc, [Fd, To, Func, Msg]), + get_term(P). + + +get_send_result(P) -> + case get_term(P) of + {term,{0,_}} -> ok; + {term,{1,_}} -> ok; + {term,{-1,Errno}} -> {error,Errno}; + {term,{Res,Errno}}-> + io:format("Return value: ~p\nerl_errno: ~p", [Res,Errno]), + ?t:fail(bad_return_value) + end. + +send_command(P, Name, Args) -> + runner:send_term(P, {Name,list_to_tuple(Args)}). + +%%% Test function for RPC + +rpc_test(S) -> + lists:reverse(S). diff --git a/lib/erl_interface/test/ei_connect_SUITE_data/Makefile.first b/lib/erl_interface/test/ei_connect_SUITE_data/Makefile.first new file mode 100644 index 0000000000..8bf22e366e --- /dev/null +++ b/lib/erl_interface/test/ei_connect_SUITE_data/Makefile.first @@ -0,0 +1,21 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2001-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# + +ei_connect_test_decl.c: ei_connect_test.c + erl -noinput -pa ../all_SUITE_data -s init_tc run ei_connect_test -s erlang halt diff --git a/lib/erl_interface/test/ei_connect_SUITE_data/Makefile.src b/lib/erl_interface/test/ei_connect_SUITE_data/Makefile.src new file mode 100644 index 0000000000..a6525a9138 --- /dev/null +++ b/lib/erl_interface/test/ei_connect_SUITE_data/Makefile.src @@ -0,0 +1,46 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2001-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# + +include @erl_interface_mk_include@@[email protected] + +CC0 = @CC@ +CC = ..@DS@all_SUITE_data@DS@gccifier@exe@ -CC"$(CC0)" +LD = @LD@ +LIBPATH = @erl_interface_libpath@ +LIBEI = $(LIBPATH)/@erl_interface_eilib@ +LIBFLAGS = ../all_SUITE_data/ei_runner@obj@ \ + $(LIBEI) @LIBS@ @erl_interface_sock_libs@ \ + @erl_interface_threadlib@ +CFLAGS = @EI_CFLAGS@ $(THR_DEFS) -I@erl_interface_include@ -I../all_SUITE_data +EI_CONNECT_OBJS = ei_connect_test@obj@ ei_connect_test_decl@obj@ +EINODE_OBJS = einode@obj@ + +all: ei_connect_test@exe@ einode@exe@ + +clean: + $(RM) $(EI_CONNECT_OBJS) $(EINODE_OBJS) + $(RM) ei_connect_test@exe@ einode@exe@ + +ei_connect_test@exe@: $(EI_CONNECT_OBJS) $(LIBEI) + $(LD) @CROSSLDFLAGS@ -o $@ $(EI_CONNECT_OBJS) $(LIBFLAGS) + + +einode@exe@: $(EINODE_OBJS) $(LIBEI) + $(LD) @CROSSLDFLAGS@ -o $@ $(EINODE_OBJS) $(LIBFLAGS) + diff --git a/lib/erl_interface/test/ei_connect_SUITE_data/ei_connect_test.c b/lib/erl_interface/test/ei_connect_SUITE_data/ei_connect_test.c new file mode 100644 index 0000000000..debd3e789b --- /dev/null +++ b/lib/erl_interface/test/ei_connect_SUITE_data/ei_connect_test.c @@ -0,0 +1,289 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2001-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ + +/* + * Purpose: Tests the functions in ei_connect.c. + * Author: Bjorn Gustavsson (rewritten somewhat by Jakob Cederlund) + * + * See the ei_connect_SUITE.erl file for a "table of contents". + */ + +#include <stdio.h> +#include <string.h> +#ifdef VXWORKS +#include "reclaim.h" +#endif + +#include "ei_runner.h" + +static void cmd_ei_connect_init(char* buf, int len); +static void cmd_ei_connect(char* buf, int len); +static void cmd_ei_send(char* buf, int len); +static void cmd_ei_send_funs(char* buf, int len); +static void cmd_ei_reg_send(char* buf, int len); +static void cmd_ei_rpc(char* buf, int len); +static void cmd_ei_set_get_tracelevel(char* buf, int len); + +static void send_errno_result(int value); + +ei_cnode ec; + + +static struct { + char* name; + int num_args; /* Number of arguments. */ + void (*func)(char* buf, int len); +} commands[] = { + "ei_connect_init", 3, cmd_ei_connect_init, + "ei_connect", 1, cmd_ei_connect, + "ei_send", 3, cmd_ei_send, + "ei_send_funs", 3, cmd_ei_send_funs, + "ei_reg_send", 3, cmd_ei_reg_send, + "ei_rpc", 4, cmd_ei_rpc, + "ei_set_get_tracelevel", 1, cmd_ei_set_get_tracelevel, +}; + + +/* + * Sends a list contaning all data types to the Erlang side. + */ + +TESTCASE(interpret) +{ + ei_x_buff x; + int i; + ei_term term; + + ei_x_new(&x); + for (;;) { + if (get_bin_term(&x, &term)) { + report(1); + return; + } else { + char* buf = x.buff, func[MAXATOMLEN]; + int index = x.index, arity; + if (term.ei_type != ERL_SMALL_TUPLE_EXT || term.arity != 2) + fail("term should be a tuple of size 2"); + if (ei_decode_atom(buf, &index, func) < 0) + fail("function name should be an atom"); + if (ei_decode_tuple_header(buf, &index, &arity) != 0) + fail("function arguments should be a tuple"); + for (i = 0; i < sizeof(commands)/sizeof(commands[0]); i++) { + if (strcmp(func, commands[i].name) == 0) { + if (arity != commands[i].num_args) + fail("wrong number of arguments"); + commands[i].func(buf + index, x.buffsz - index); + break; + } + } + if (i >= sizeof(commands)/sizeof(commands[0])) { + message("\"%d\" \n", func); + fail("bad command"); + } + } + } +} + + +static void cmd_ei_connect_init(char* buf, int len) +{ + int index = 0, r = 0; + int type, size; + long l; + char b[100]; + char cookie[MAXATOMLEN], * cp = cookie; + ei_x_buff res; + if (ei_decode_long(buf, &index, &l) < 0) + fail("expected int"); + sprintf(b, "c%d", l); + /* FIXME don't use internal and maybe use skip?! */ + ei_get_type_internal(buf, &index, &type, &size); + if (ei_decode_atom(buf, &index, cookie) < 0) + fail("expected atom (cookie)"); + if (cookie[0] == '\0') + cp = NULL; + r = ei_connect_init(&ec, b, cp, 0); + ei_x_new_with_version(&res); + ei_x_encode_long(&res, r); + send_bin_term(&res); + ei_x_free(&res); +} + +static void cmd_ei_connect(char* buf, int len) +{ + int index = 0; + char node[256]; + int i; + if (ei_decode_atom(buf, &index, node) < 0) + fail("expected atom"); + i=ei_connect(&ec, node); +#ifdef VXWORKS + if(i >= 0) { + save_fd(i); + } +#endif + send_errno_result(i); +} + +static void cmd_ei_set_get_tracelevel(char* buf, int len) +{ + int index = 0; + long level = 0; + long ret = 0; + ei_x_buff x; + + if (ei_decode_long(buf, &index, &level) < 0) { + fail("expected long"); + } + + ei_set_tracelevel((int)level); + + ret = (long) ei_get_tracelevel(); + + ei_x_new_with_version(&x); + ei_x_encode_tuple_header(&x, 2); + ei_x_encode_atom(&x, "tracelevel"); + ei_x_encode_long(&x, ret); + send_bin_term(&x); + ei_x_free(&x); +} + +static void cmd_ei_send(char* buf, int len) +{ + int index = 0; + long fd; + erlang_pid pid; + ei_x_buff x; + + if (ei_decode_long(buf, &index, &fd) < 0) + fail("expected long"); + if (ei_decode_pid(buf, &index, &pid) < 0) + fail("expected pid (node)"); + if (ei_x_new_with_version(&x) < 0) + fail("ei_x_new_with_version"); + if (ei_x_append_buf(&x, &buf[index], len - index) < 0) + fail("append"); + send_errno_result(ei_send(fd, &pid, x.buff, x.index)); + ei_x_free(&x); +} + +static void cmd_ei_send_funs(char* buf, int len) +{ + int index = 0, n; + long fd; + erlang_pid pid; + ei_x_buff x; + erlang_fun fun1, fun2; + + if (ei_decode_long(buf, &index, &fd) < 0) + fail("expected long"); + if (ei_decode_pid(buf, &index, &pid) < 0) + fail("expected pid (node)"); + if (ei_decode_tuple_header(buf, &index, &n) < 0) + fail("expected tuple"); + if (n != 2) + fail("expected tuple"); + if (ei_decode_fun(buf, &index, &fun1) < 0) + fail("expected Fun1"); + if (ei_decode_fun(buf, &index, &fun2) < 0) + fail("expected Fun2"); + if (ei_x_new_with_version(&x) < 0) + fail("ei_x_new_with_version"); + if (ei_x_encode_tuple_header(&x, 2) < 0) + fail("encode tuple header"); + if (ei_x_encode_fun(&x, &fun1) < 0) + fail("encode fun1"); + if (ei_x_encode_fun(&x, &fun2) < 0) + fail("encode fun2"); + free_fun(&fun1); + free_fun(&fun2); + send_errno_result(ei_send(fd, &pid, x.buff, x.index)); + ei_x_free(&x); +} + +static void cmd_ei_reg_send(char* buf, int len) +{ + int index = 0; + long fd; + char reg_name[MAXATOMLEN]; + erlang_pid pid; + ei_x_buff x; + + if (ei_decode_long(buf, &index, &fd) < 0) + fail("expected long (fd)"); + if (ei_decode_atom(buf, &index, reg_name) < 0) + fail("expected atom (reg name)"); + if (ei_x_new_with_version(&x) < 0) + fail("ei_x_new_with_version"); + if (ei_x_append_buf(&x, &buf[index], len - index) < 0) + fail("append"); + send_errno_result(ei_reg_send(&ec, fd, + reg_name, x.buff, x.index)); + ei_x_free(&x); +} + +static void cmd_ei_rpc(char* buf, int len) +{ + int index = 0, n; + long fd; + erlang_pid pid; + ei_x_buff x, rpc_x; + int r; + char mod[MAXATOMLEN], func[MAXATOMLEN]; + +#if 0 && defined(__WIN32__) + DebugBreak(); +#endif + + if (ei_decode_long(buf, &index, &fd) < 0) + fail("expected long"); + if (ei_decode_pid(buf, &index, &pid) < 0) + fail("expected pid (node)"); + if (ei_decode_tuple_header(buf, &index, &n) < 0 && n < 2) + fail("expected tuple {module, function}"); + if (ei_decode_atom(buf, &index, mod) < 0) + fail("expected atom (module)"); + if (ei_decode_atom(buf, &index, func) < 0) + fail("expected atom (function)"); + message("pid %s %d %d %d\n", pid.node, pid.num, pid.serial, pid.creation); + message("{%s, %s}\n", mod, func); + if (ei_x_new(&rpc_x) < 0) + fail("ei_x_new"); + if (ei_rpc(&ec, fd, mod, func, &buf[index], len - index, &rpc_x) < 0) + fail("ei_rpc"); + if (ei_x_new_with_version(&x) < 0) + fail("ei_x_new_with_version"); + if (ei_x_append(&x, &rpc_x) < 0) + fail("append"); + send_bin_term(&x); + /*send_errno_result(ei_send(&ec, fd, &pid, x.buff, x.index));*/ + ei_x_free(&x); + ei_x_free(&rpc_x); +} + +static void send_errno_result(int value) +{ + ei_x_buff x; + ei_x_new_with_version(&x); + ei_x_encode_tuple_header(&x, 2); + ei_x_encode_long(&x, value); + ei_x_encode_long(&x, erl_errno); + send_bin_term(&x); + ei_x_free(&x); +} diff --git a/lib/erl_interface/test/ei_connect_SUITE_data/einode.c b/lib/erl_interface/test/ei_connect_SUITE_data/einode.c new file mode 100644 index 0000000000..bafe8bd5bd --- /dev/null +++ b/lib/erl_interface/test/ei_connect_SUITE_data/einode.c @@ -0,0 +1,158 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2001-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ + +/* to test multiple threads in ei */ + +#include <stdlib.h> +#include <stdio.h> + +#ifdef __WIN32__ +#include <winsock2.h> +#include <windows.h> +#include <process.h> +#else +#ifndef VXWORKS +#include <pthread.h> +#endif +#include <sys/socket.h> +#endif + +#include "ei.h" + +#ifdef VXWORKS +#define MAIN cnode +#else +#define MAIN main +#endif + +/* + A small einode. + To be called from the test case ei_accept_SUITE:multi_thread + usage: einode <cookie> <n> <destnode> + + - start threads 0..n-1 + - in each thread + - connect to destnode + - send a message ("ei0".."ei<n-1>") to mth0..mth<n-1> on destnode + - shutdown gracefully +*/ + +static const char* cookie, * desthost; + +#ifndef SD_SEND +#ifdef SHUTWR +#define SD_SEND SHUT_WR +#else +#define SD_SEND 1 +#endif +#endif + +#ifndef __WIN32__ +#define closesocket(fd) close(fd) +#endif + +#ifdef __WIN32__ +static DWORD WINAPI +#else +static void* +#endif + einode_thread(void* num) +{ + int n = (int)num; + ei_cnode ec; + char myname[100], destname[100]; + int r, fd; + + sprintf(myname, "ei%d", n); + sprintf(destname, "mth%d", n); + printf("thread %d (%s %s) connecting\n", n, myname, destname); + r = ei_connect_init(&ec, myname, cookie, 0); + fd = ei_connect(&ec, (char*)desthost); + if (r == 0 && fd >= 0) { + ei_x_buff x; + ei_x_new_with_version(&x); + ei_x_encode_string(&x, myname); + ei_reg_send(&ec, fd, destname, x.buff, x.index); + ei_x_free(&x); + //SleepEx(100); + shutdown(fd, SD_SEND); + closesocket(fd); + } else { + printf("coudn't connect fd %d r %d\n", fd, r); // DebugBreak(); + } + printf("done thread %d\n", n); + return 0; +} + +MAIN(int argc, char *argv[]) +{ + int i, n, no_threads; +#ifndef VXWORKS +#ifdef __WIN32__ + HANDLE threads[100]; +#else + pthread_t threads[100]; +#endif +#endif + + if (argc < 3) + exit(1); + + cookie = argv[1]; + n = atoi(argv[2]); + if (n > 100) + exit(2); + desthost = argv[3]; +#ifndef VXWORKS + no_threads = argv[4] != NULL && strcmp(argv[4], "nothreads") == 0; +#else + no_threads = 1; +#endif + for (i = 0; i < n; ++i) { + if (!no_threads) { +#ifndef VXWORKS +#ifdef __WIN32__ + unsigned tid; + threads[i] = (HANDLE)_beginthreadex(NULL, 0, einode_thread, + (void*)i, 0, &tid); +#else + pthread_create(&threads[i], NULL, einode_thread, (void*)i); +#endif +#else + ; +#endif + } else + einode_thread((void*)i); + } + if (!no_threads) +#ifndef VXWORKS + for (i = 0; i < n; ++i) { +#ifdef __WIN32__ + if (WaitForSingleObject(threads[i], INFINITE) != WAIT_OBJECT_0) +#else + if (pthread_join(threads[i], NULL) != 0) +#endif + printf("bad wait thread %d\n", i); + } +#else + ; +#endif + printf("ok\n"); + return 0; +} diff --git a/lib/erl_interface/test/ei_decode_SUITE.erl b/lib/erl_interface/test/ei_decode_SUITE.erl new file mode 100644 index 0000000000..ea528728ab --- /dev/null +++ b/lib/erl_interface/test/ei_decode_SUITE.erl @@ -0,0 +1,300 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2004-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +-module(ei_decode_SUITE). + +-include("test_server.hrl"). +-include("ei_decode_SUITE_data/ei_decode_test_cases.hrl"). + +-export( + [ + all/1, + test_ei_decode_long/1, + test_ei_decode_ulong/1, + test_ei_decode_longlong/1, + test_ei_decode_ulonglong/1, + test_ei_decode_char/1, + test_ei_decode_nonoptimal/1, + test_ei_decode_misc/1 + ]). + +all(suite) -> + [ + test_ei_decode_long, + test_ei_decode_ulong, + test_ei_decode_longlong, + test_ei_decode_ulonglong, + test_ei_decode_char, + test_ei_decode_nonoptimal, + test_ei_decode_misc + ]. + +%% --------------------------------------------------------------------------- + +% NOTE: for historical reasons we don't pach as tight as we can, +% we only fill 27 bits in 32 bit INTEGER_EXT + + +%% ######################################################################## %% + +test_ei_decode_long(suite) -> []; +test_ei_decode_long(Config) when is_list(Config) -> + ?line P = runner:start(?test_ei_decode_long), + send_integers(P), + ?line runner:recv_eot(P), + ok. + + +%% ######################################################################## %% + +test_ei_decode_ulong(suite) -> []; +test_ei_decode_ulong(Config) when is_list(Config) -> + ?line P = runner:start(?test_ei_decode_ulong), + send_integers(P), + ?line runner:recv_eot(P), + ok. + + +% (*) In practical terms, other values may fit into the ext format +% i32 is signed 32 bit on C side +% u32 is unsigned 32 bit on C side + +%% ######################################################################## %% + +test_ei_decode_longlong(suite) -> []; +test_ei_decode_longlong(Config) when is_list(Config) -> + case os:type() of + vxworks -> + {skip,"Skipped on VxWorks"}; + _ -> + ?line P = runner:start(?test_ei_decode_longlong), + send_integers2(P), + ?line runner:recv_eot(P), + ok + end. + + +%% ######################################################################## %% + +test_ei_decode_ulonglong(suite) -> []; +test_ei_decode_ulonglong(Config) when is_list(Config) -> + case os:type() of + vxworks -> + {skip,"Skipped on VxWorks"}; + _ -> + ?line P = runner:start(?test_ei_decode_ulonglong), + send_integers2(P), + ?line runner:recv_eot(P), + ok + end. + + +%% ######################################################################## %% +%% A "character" for us is an 8 bit integer, alwasy positive, i.e. +%% it is unsigned. +%% FIXME maybe the API should change to use "unsigned char" to be clear?! + +test_ei_decode_char(suite) -> []; +test_ei_decode_char(Config) when is_list(Config) -> + ?line P = runner:start(?test_ei_decode_char), + + ?line send_term_as_binary(P,0), + ?line send_term_as_binary(P,16#7f), + ?line send_term_as_binary(P,16#ff), + + ?line send_term_as_binary(P, []), % illegal type + + ?line runner:recv_eot(P), + ok. + + +%% ######################################################################## %% + +test_ei_decode_nonoptimal(suite) -> []; +test_ei_decode_nonoptimal(Config) when is_list(Config) -> + ?line P = runner:start(?test_ei_decode_nonoptimal), + + send_non_optimal_pos(P), % decode_char + send_non_optimal(P), % decode_long + send_non_optimal_pos(P), % decode_ulong + case os:type() of + vxworks -> + ok; + _ -> + send_non_optimal(P), % decode_longlong + send_non_optimal_pos(P) % decode_ulonglong + end, + + ?line runner:recv_eot(P), + ok. + + +send_non_optimal(P) -> + send_non_optimal_pos(P), + send_non_optimal_neg(P). + +send_non_optimal_pos(P) -> + ?line send_raw(P, <<131,97,42>>), + ?line send_raw(P, <<131,98,42:32>>), + ?line send_raw(P, <<131,110,1,0,42>>), + ?line send_raw(P, <<131,110,2,0,42,0>>), + ?line send_raw(P, <<131,110,4,0,42,0,0,0>>), + ?line send_raw(P, <<131,111,0,0,0,1,0,42>>), + ?line send_raw(P, <<131,111,0,0,0,2,0,42,0>>), + ?line send_raw(P, <<131,111,0,0,0,3,0,42,0,0>>), + ?line send_raw(P, <<131,111,0,0,0,6,0,42,0,0,0,0,0>>), + ok. + +send_non_optimal_neg(P) -> +% ?line send_raw(P, <<131,97,-42>>), + ?line send_raw(P, <<131,98,-42:32>>), + ?line send_raw(P, <<131,110,1,1,42>>), + ?line send_raw(P, <<131,110,2,1,42,0>>), + ?line send_raw(P, <<131,110,4,1,42,0,0,0>>), + ?line send_raw(P, <<131,111,0,0,0,1,1,42>>), + ?line send_raw(P, <<131,111,0,0,0,2,1,42,0>>), + ?line send_raw(P, <<131,111,0,0,0,3,1,42,0,0>>), + ?line send_raw(P, <<131,111,0,0,0,6,1,42,0,0,0,0,0>>), + ok. + + +%% ######################################################################## %% + +test_ei_decode_misc(suite) -> []; +test_ei_decode_misc(Config) when is_list(Config) -> + ?line P = runner:start(?test_ei_decode_misc), + +% ?line <<131>> = get_binaries(P), + +% ?line {term,F} = get_term(P), +% ?line match_float(F, 0.0), +% ?line {term,F} = get_term(P), +% ?line match_float(F, 0.0), + +% ?line {term,F} = get_term(P), +% ?line true = match_float(F, -1.0), +% ?line {term,F} = get_term(P), +% ?line true = match_float(F, -1.0), + +% ?line {term,F} = get_term(P), +% ?line true = match_float(F, 1.0), +% ?line {term,F} = get_term(P), +% ?line true = match_float(F, 1.0), + + ?line send_term_as_binary(P,false), + ?line send_term_as_binary(P,true), + + ?line send_term_as_binary(P,foo), + ?line send_term_as_binary(P,''), + ?line send_term_as_binary(P,'������'), + + ?line send_term_as_binary(P,"foo"), + ?line send_term_as_binary(P,""), + ?line send_term_as_binary(P,"������"), + + ?line send_term_as_binary(P,<<"foo">>), + ?line send_term_as_binary(P,<<>>), + ?line send_term_as_binary(P,<<"������">>), + +% ?line send_term_as_binary(P,{}), +% ?line send_term_as_binary(P,[]), + + ?line runner:recv_eot(P), + ok. + + +%% ######################################################################## %% + +send_term_as_binary(Port, Term) when is_port(Port) -> + Port ! {self(), {command, term_to_binary(Term)}}. + +send_raw(Port, Bin) when is_port(Port) -> + Port ! {self(), {command, Bin}}. + + +send_integers(P) -> + ?line send_term_as_binary(P,0), % SMALL_INTEGER_EXT smallest + ?line send_term_as_binary(P,255), % SMALL_INTEGER_EXT largest + ?line send_term_as_binary(P,256), % INTEGER_EXT smallest pos (*) + ?line send_term_as_binary(P,-1), % INTEGER_EXT largest neg + + ?line send_term_as_binary(P, 16#07ffffff), % INTEGER_EXT largest (28 bits) + ?line send_term_as_binary(P,-16#08000000), % INTEGER_EXT smallest + ?line send_term_as_binary(P, 16#08000000), % SMALL_BIG_EXT smallest pos(*) + ?line send_term_as_binary(P,-16#08000001), % SMALL_BIG_EXT largest neg (*) + + ?line send_term_as_binary(P, 16#7fffffff), % SMALL_BIG_EXT largest i32 + ?line send_term_as_binary(P,-16#80000000), % SMALL_BIG_EXT smallest i32 + + case erlang:system_info(wordsize) of + 4 -> + ?line send_term_as_binary(P, 16#80000000),% SMALL_BIG_EXT u32 + ?line send_term_as_binary(P, 16#ffffffff),% SMALL_BIG_EXT largest u32 + + ?line send_term_as_binary(P, 16#7fffffffffff), % largest i48 + ?line send_term_as_binary(P,-16#800000000000), % smallest i48 + ?line send_term_as_binary(P, 16#ffffffffffff), % largest u48 + ?line send_term_as_binary(P, 16#7fffffffffffffff), % largest i64 + ?line send_term_as_binary(P,-16#8000000000000000), % smallest i64 + ?line send_term_as_binary(P, 16#ffffffffffffffff); % largest u64 + 8 -> + ?line send_term_as_binary(P, 16#8000000000000000),% SMALL_BIG_EXT u64 + % SMALL_BIG_EXT largest u64 + ?line send_term_as_binary(P, 16#ffffffffffffffff), + % largest i96 + ?line send_term_as_binary(P, 16#7fffffffffffffffffffffff), + % smallest i96 + ?line send_term_as_binary(P,-16#800000000000000000000000), + % largest u96 + ?line send_term_as_binary(P, 16#ffffffffffffffffffffffff), + % largest i128 + ?line send_term_as_binary(P, 16#7fffffffffffffffffffffffffffffff), + % smallest i128 + ?line send_term_as_binary(P,-16#80000000000000000000000000000000), + % largest u128 + ?line send_term_as_binary(P, 16#ffffffffffffffffffffffffffffffff) + end, + ?line send_term_as_binary(P, []), % illegal type + ok. + +send_integers2(P) -> + ?line send_term_as_binary(P,0), % SMALL_INTEGER_EXT smallest + ?line send_term_as_binary(P,255), % SMALL_INTEGER_EXT largest + ?line send_term_as_binary(P,256), % INTEGER_EXT smallest pos (*) + ?line send_term_as_binary(P,-1), % INTEGER_EXT largest neg + + ?line send_term_as_binary(P, 16#07ffffff), % INTEGER_EXT largest (28 bits) + ?line send_term_as_binary(P,-16#08000000), % INTEGER_EXT smallest + ?line send_term_as_binary(P, 16#08000000), % SMALL_BIG_EXT smallest pos(*) + ?line send_term_as_binary(P,-16#08000001), % SMALL_BIG_EXT largest neg (*) + + ?line send_term_as_binary(P, 16#7fffffff), % SMALL_BIG_EXT largest i32 + ?line send_term_as_binary(P,-16#80000000), % SMALL_BIG_EXT smallest i32 + ?line send_term_as_binary(P, 16#80000000),% SMALL_BIG_EXT u32 + ?line send_term_as_binary(P, 16#ffffffff),% SMALL_BIG_EXT largest u32 + + ?line send_term_as_binary(P, 16#7fffffffffff), % largest i48 + ?line send_term_as_binary(P,-16#800000000000), % smallest i48 + ?line send_term_as_binary(P, 16#ffffffffffff), % largest u48 + ?line send_term_as_binary(P, 16#7fffffffffffffff), % largest i64 + ?line send_term_as_binary(P,-16#8000000000000000), % smallest i64 + ?line send_term_as_binary(P, 16#ffffffffffffffff), % largest u64 + ?line send_term_as_binary(P, []), % illegal type + ok. diff --git a/lib/erl_interface/test/ei_decode_SUITE_data/Makefile.first b/lib/erl_interface/test/ei_decode_SUITE_data/Makefile.first new file mode 100644 index 0000000000..0791b54109 --- /dev/null +++ b/lib/erl_interface/test/ei_decode_SUITE_data/Makefile.first @@ -0,0 +1,21 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2004-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# + +ei_decode_test_decl.c: ei_decode_test.c + erl -noinput -pa ../all_SUITE_data -s init_tc run ei_decode_test -s erlang halt diff --git a/lib/erl_interface/test/ei_decode_SUITE_data/Makefile.src b/lib/erl_interface/test/ei_decode_SUITE_data/Makefile.src new file mode 100644 index 0000000000..76e55750c3 --- /dev/null +++ b/lib/erl_interface/test/ei_decode_SUITE_data/Makefile.src @@ -0,0 +1,42 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2004-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# + +include @erl_interface_mk_include@@[email protected] + +CC0 = @CC@ +CC = ..@DS@all_SUITE_data@DS@gccifier@exe@ -CC"$(CC0)" +LD = @LD@ +LIBPATH = @erl_interface_libpath@ +LIBEI = $(LIBPATH)/@erl_interface_eilib@ +LIBFLAGS = ../all_SUITE_data/ei_runner@obj@ \ + $(LIBEI) @LIBS@ @erl_interface_sock_libs@ \ + @erl_interface_threadlib@ +CFLAGS = @EI_CFLAGS@ $(THR_DEFS) -I@erl_interface_include@ -I../all_SUITE_data +EI_DECODE_OBJS = ei_decode_test@obj@ ei_decode_test_decl@obj@ + +all: ei_decode_test@exe@ + +clean: + $(RM) $(EI_DECODE_OBJS) + $(RM) ei_decode_test@exe@ + +ei_decode_test@exe@: $(EI_DECODE_OBJS) $(LIBEI) + $(LD) @CROSSLDFLAGS@ -o $@ $(EI_DECODE_OBJS) $(LIBFLAGS) + + diff --git a/lib/erl_interface/test/ei_decode_SUITE_data/ei_decode_test.c b/lib/erl_interface/test/ei_decode_SUITE_data/ei_decode_test.c new file mode 100644 index 0000000000..d81ea88437 --- /dev/null +++ b/lib/erl_interface/test/ei_decode_SUITE_data/ei_decode_test.c @@ -0,0 +1,548 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2004-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ + +#ifdef VXWORKS +#include "reclaim.h" +#endif + +#include "ei_runner.h" + +/* + * Purpose: Tests the ei_format() function. + * Author: Kent + */ + +#ifdef VXWORKS +#define MESSAGE_BACK(SIZE) \ + message("err = %d, size2 = %d, expected size = %d", \ + err, size1, SIZE); +#else +#define MESSAGE_BACK(SIZE) \ + message("err = %d, size2 = %d, expected size = %d, long long val = %lld", \ + err, size1, SIZE, (EI_LONGLONG)p); +#endif + +#define EI_DECODE_2(FUNC,SIZE,TYPE,VAL) \ + { \ + TYPE p; \ + char *buf; \ + int size1 = 0; \ + int size2 = 0; \ + int err; \ + message("ei_" #FUNC " " #TYPE " should be " #VAL); \ + buf = read_packet(NULL); \ +\ + err = ei_ ## FUNC(buf+1, &size1, NULL); \ + message("err = %d, size1 = %d, expected size = %d", \ + err, size1, SIZE); \ + if (err != 0) { \ + if (err != -1) { \ + fail("returned non zero but not -1 if NULL pointer"); \ + } else { \ + fail("returned non zero if NULL pointer"); \ + } \ + return; \ + } \ +\ + err = ei_ ## FUNC(buf+1, &size2, &p); \ + MESSAGE_BACK(SIZE) \ + if (err != 0) { \ + if (err != -1) { \ + fail("returned non zero but not -1"); \ + } else { \ + fail("returned non zero"); \ + } \ + return; \ + } \ + if (p != (TYPE)VAL) { \ + fail("value is not correct"); \ + return; \ + } \ +\ + if (size1 != size2) { \ + fail("size with and without pointer differs"); \ + return; \ + } \ +\ + if (size1 != SIZE) { \ + fail("size of encoded data is incorrect"); \ + return; \ + } \ + } \ + +#define EI_DECODE_2_FAIL(FUNC,SIZE,TYPE,VAL) \ + { \ + TYPE p, saved_p; \ + char *buf; \ + int size1 = 0; \ + int size2 = 0; \ + int err; \ + message("ei_" #FUNC " " #TYPE " should fail"); \ + memset(&p,'\0',sizeof(p)); \ + saved_p = p; \ + buf = read_packet(NULL); \ +\ + err = ei_ ## FUNC(buf+1, &size1, NULL); \ + message("err = %d, size1 = %d, expected size = %d", \ + err, size1, SIZE); \ + if (err != -1) { \ + fail("should return -1 if NULL pointer"); \ + return; \ + } \ +\ + err = ei_ ## FUNC(buf+1, &size2, &p); \ + message("err = %d, size2 = %d, expected size = %d", \ + err, size1, SIZE); \ + if (err != -1) { \ + fail("should return -1"); \ + return; \ + } \ + if (p != saved_p) { \ + fail("p argument was modified"); \ + return; \ + } \ +\ + if (size1 != 0) { \ + fail("size of encoded data should be 0 if NULL"); \ + return; \ + } \ +\ + if (size2 != 0) { \ + fail("size of encoded data should be 0"); \ + return; \ + } \ + } \ + +#define EI_DECODE_STRING(FUNC,SIZE,VAL) \ + { \ + char p[1024]; \ + char *buf; \ + int size1 = 0; \ + int size2 = 0; \ + int err; \ + message("ei_" #FUNC " should be " #VAL); \ + buf = read_packet(NULL); \ +\ + err = ei_ ## FUNC(buf+1, &size1, NULL); \ + message("err = %d, size = %d, expected size = %d\n",err,size1,SIZE); \ + if (err != 0) { \ + if (err != -1) { \ + fail("returned non zero but not -1 if NULL pointer"); \ + } else { \ + fail("returned non zero if NULL pointer"); \ + } \ + return; \ + } \ +\ + err = ei_ ## FUNC(buf+1, &size2, p); \ + message("err = %d, size = %d, expected size = %d\n",err,size2,SIZE); \ + if (err != 0) { \ + if (err != -1) { \ + fail("returned non zero but not -1"); \ + } else { \ + fail("returned non zero"); \ + } \ + return; \ + } \ +\ + if (strcmp(p,VAL) != 0) { \ + fail("value is not correct"); \ + return; \ + } \ +\ + if (size1 != size2) { \ + fail("size with and without pointer differs"); \ + return; \ + } \ +\ + if (size1 != SIZE) { \ + fail("size of encoded data is incorrect"); \ + return; \ + } \ + } \ + +#define EI_DECODE_BIN(FUNC,SIZE,VAL,LEN) \ + { \ + char p[1024]; \ + char *buf; \ + long len; \ + int size1 = 0; \ + int size2 = 0; \ + int err; \ + message("ei_" #FUNC " should be " #VAL); \ + buf = read_packet(NULL); \ + err = ei_ ## FUNC(buf+1, &size1, NULL, &len); \ + message("err = %d, size = %d, len = %d, expected size = %d, expected len = %d\n",\ + err,size1,len,SIZE,LEN); \ + if (err != 0) { \ + if (err != -1) { \ + fail("returned non zero but not -1 if NULL pointer"); \ + } else { \ + fail("returned non zero"); \ + } \ + return; \ + } \ +\ + if (len != LEN) { \ + fail("size is not correct"); \ + return; \ + } \ +\ + err = ei_ ## FUNC(buf+1, &size2, p, &len); \ + message("err = %d, size = %d, len = %d, expected size = %d, expected len = %d\n",\ + err,size2,len,SIZE,LEN); \ + if (err != 0) { \ + if (err != -1) { \ + fail("returned non zero but not -1 if NULL pointer"); \ + } else { \ + fail("returned non zero"); \ + } \ + return; \ + } \ +\ + if (len != LEN) { \ + fail("size is not correct"); \ + return; \ + } \ +\ + if (strncmp(p,VAL,LEN) != 0) { \ + fail("value is not correct"); \ + return; \ + } \ +\ + if (size1 != size2) { \ + fail("size with and without pointer differs"); \ + return; \ + } \ +\ + if (size1 != SIZE) { \ + fail("size of encoded data is incorrect"); \ + return; \ + } \ + } \ + +/* ******************************************************************** */ + +TESTCASE(test_ei_decode_long) +{ + EI_DECODE_2 (decode_long, 2, long, 0); + EI_DECODE_2 (decode_long, 2, long, 255); + EI_DECODE_2 (decode_long, 5, long, 256); + EI_DECODE_2 (decode_long, 5, long, -1); + + EI_DECODE_2 (decode_long, 5, long, 0x07ffffff); + EI_DECODE_2 (decode_long, 5, long, -0x08000000); + EI_DECODE_2 (decode_long, 7, long, 0x08000000); + EI_DECODE_2 (decode_long, 7, long, -0x08000001); + + EI_DECODE_2 (decode_long, 7, long, 0x7fffffff); + EI_DECODE_2 (decode_long, 7, long, -ll(0x80000000)); /* Strange :-( */ + + EI_DECODE_2_FAIL(decode_long, 7, long, 0x80000000); + EI_DECODE_2_FAIL(decode_long, 7, long, 0xffffffff); + + EI_DECODE_2_FAIL(decode_long, 9, long, ll(0x7fffffffffff)); + EI_DECODE_2_FAIL(decode_long, 9, long, -ll(0x800000000000)); + EI_DECODE_2_FAIL(decode_long, 9, long, ll(0xffffffffffff)); + EI_DECODE_2_FAIL(decode_long, 11, long, ll(0x7fffffffffffffff)); + EI_DECODE_2_FAIL(decode_long, 11, long, -ll(0x8000000000000000)); + EI_DECODE_2_FAIL(decode_long, 11, long, ll(0xffffffffffffffff)); + + EI_DECODE_2_FAIL(decode_long, 1, long, 0); /* Illegal type sent */ + + report(1); +} + +/* ******************************************************************** */ + +TESTCASE(test_ei_decode_ulong) +{ + EI_DECODE_2 (decode_ulong, 2, unsigned long, 0); + EI_DECODE_2 (decode_ulong, 2, unsigned long, 255); + EI_DECODE_2 (decode_ulong, 5, unsigned long, 256); + EI_DECODE_2_FAIL(decode_ulong, 5, unsigned long, -1); + + EI_DECODE_2 (decode_ulong, 5, unsigned long, 0x07ffffff); + EI_DECODE_2_FAIL(decode_ulong, 5, unsigned long, -0x08000000); + EI_DECODE_2 (decode_ulong, 7, unsigned long, 0x08000000); + EI_DECODE_2_FAIL(decode_ulong, 7, unsigned long, -0x08000001); + + EI_DECODE_2 (decode_ulong, 7, unsigned long, 0x7fffffff); + EI_DECODE_2_FAIL(decode_ulong, 7, unsigned long, -ll(0x80000000)); + + if (sizeof(long) > 4) { + EI_DECODE_2 (decode_ulong, 11, unsigned long, ll(0x8000000000000000)); + EI_DECODE_2 (decode_ulong, 11, unsigned long, ll(0xffffffffffffffff)); + } else { + EI_DECODE_2 (decode_ulong, 7, unsigned long, 0x80000000); + EI_DECODE_2 (decode_ulong, 7, unsigned long, 0xffffffff); + } + + EI_DECODE_2_FAIL(decode_ulong, 9, unsigned long, ll(0x7fffffffffff)); + EI_DECODE_2_FAIL(decode_ulong, 9, unsigned long, -ll(0x800000000000)); + EI_DECODE_2_FAIL(decode_ulong, 9, unsigned long, ll(0xffffffffffff)); + EI_DECODE_2_FAIL(decode_ulong, 11, unsigned long, ll(0x7fffffffffffffff)); + EI_DECODE_2_FAIL(decode_ulong, 11, unsigned long, -ll(0x8000000000000000)); + EI_DECODE_2_FAIL(decode_ulong, 11, unsigned long, ll(0xffffffffffffffff)); + + EI_DECODE_2_FAIL(decode_ulong, 1, unsigned long, 0); /* Illegal type */ + + report(1); +} + +/* ******************************************************************** */ + + +TESTCASE(test_ei_decode_longlong) +{ +#ifndef VXWORKS + EI_DECODE_2 (decode_longlong, 2, EI_LONGLONG, 0); + EI_DECODE_2 (decode_longlong, 2, EI_LONGLONG, 255); + EI_DECODE_2 (decode_longlong, 5, EI_LONGLONG, 256); + EI_DECODE_2 (decode_longlong, 5, EI_LONGLONG, -1); + + EI_DECODE_2 (decode_longlong, 5, EI_LONGLONG, 0x07ffffff); + EI_DECODE_2 (decode_longlong, 5, EI_LONGLONG, -0x08000000); + EI_DECODE_2 (decode_longlong, 7, EI_LONGLONG, 0x08000000); + EI_DECODE_2 (decode_longlong, 7, EI_LONGLONG, -0x08000001); + + EI_DECODE_2 (decode_longlong, 7, EI_LONGLONG, 0x7fffffff); + EI_DECODE_2 (decode_longlong, 7, EI_LONGLONG, -ll(0x80000000)); + + EI_DECODE_2 (decode_longlong, 7, EI_LONGLONG, 0x80000000); + EI_DECODE_2 (decode_longlong, 7, EI_LONGLONG, 0xffffffff); + + EI_DECODE_2 (decode_longlong, 9, EI_LONGLONG, ll(0x7fffffffffff)); + EI_DECODE_2 (decode_longlong, 9, EI_LONGLONG, -ll(0x800000000000)); + EI_DECODE_2 (decode_longlong, 9, EI_LONGLONG, ll(0xffffffffffff)); + EI_DECODE_2 (decode_longlong, 11, EI_LONGLONG, ll(0x7fffffffffffffff)); + EI_DECODE_2 (decode_longlong, 11, EI_LONGLONG, -ll(0x8000000000000000)); + EI_DECODE_2_FAIL(decode_longlong, 11, EI_LONGLONG, ll(0xffffffffffffffff)); + + EI_DECODE_2_FAIL(decode_longlong, 1, EI_LONGLONG, 0); /* Illegal type */ +#endif + report(1); +} + +/* ******************************************************************** */ + +TESTCASE(test_ei_decode_ulonglong) +{ +#ifndef VXWORKS + EI_DECODE_2 (decode_ulonglong, 2, EI_ULONGLONG, 0); + EI_DECODE_2 (decode_ulonglong, 2, EI_ULONGLONG, 255); + EI_DECODE_2 (decode_ulonglong, 5, EI_ULONGLONG, 256); + EI_DECODE_2_FAIL(decode_ulonglong, 5, EI_ULONGLONG, -1); + + EI_DECODE_2 (decode_ulonglong, 5, EI_ULONGLONG, 0x07ffffff); + EI_DECODE_2_FAIL(decode_ulonglong, 5, EI_ULONGLONG, -0x08000000); + EI_DECODE_2 (decode_ulonglong, 7, EI_ULONGLONG, 0x08000000); + EI_DECODE_2_FAIL(decode_ulonglong, 7, EI_ULONGLONG, -0x08000001); + + EI_DECODE_2 (decode_ulonglong, 7, EI_ULONGLONG, 0x7fffffff); + EI_DECODE_2_FAIL(decode_ulonglong, 7, EI_ULONGLONG, -ll(0x80000000)); + + EI_DECODE_2 (decode_ulonglong, 7, EI_ULONGLONG, 0x80000000); + EI_DECODE_2 (decode_ulonglong, 7, EI_ULONGLONG, 0xffffffff); + + EI_DECODE_2 (decode_ulonglong, 9, EI_ULONGLONG, ll(0x7fffffffffff)); + EI_DECODE_2_FAIL(decode_ulonglong, 9, EI_ULONGLONG, -ll(0x800000000000)); + EI_DECODE_2 (decode_ulonglong, 9, EI_ULONGLONG, ll(0xffffffffffff)); + EI_DECODE_2 (decode_ulonglong,11, EI_ULONGLONG, ll(0x7fffffffffffffff)); + EI_DECODE_2_FAIL(decode_ulonglong,11, EI_ULONGLONG, -ll(0x8000000000000000)); + EI_DECODE_2 (decode_ulonglong,11, EI_ULONGLONG, ll(0xffffffffffffffff)); + + EI_DECODE_2_FAIL(decode_ulonglong, 1, EI_ULONGLONG, 0); /* Illegal type */ +#endif + report(1); +} + + +/* ******************************************************************** */ + +TESTCASE(test_ei_decode_char) +{ + EI_DECODE_2(decode_char, 2, char, 0); + EI_DECODE_2(decode_char, 2, char, 0x7f); + EI_DECODE_2(decode_char, 2, char, 0xff); + + EI_DECODE_2_FAIL(decode_char, 1, char, 0); /* Illegal type */ + + report(1); +} + +/* ******************************************************************** */ + +TESTCASE(test_ei_decode_nonoptimal) +{ + EI_DECODE_2(decode_char, 2, char, 42); + EI_DECODE_2(decode_char, 5, char, 42); + EI_DECODE_2(decode_char, 4, char, 42); + EI_DECODE_2(decode_char, 5, char, 42); + EI_DECODE_2(decode_char, 7, char, 42); + EI_DECODE_2(decode_char, 7, char, 42); + EI_DECODE_2(decode_char, 8, char, 42); + EI_DECODE_2(decode_char, 9, char, 42); + EI_DECODE_2(decode_char, 12, char, 42); + +/* EI_DECODE_2(decode_char, char, -42); */ +/* EI_DECODE_2(decode_char, char, -42); */ +/* EI_DECODE_2(decode_char, char, -42); */ +/* EI_DECODE_2(decode_char, char, -42); */ +/* EI_DECODE_2(decode_char, char, -42); */ +/* EI_DECODE_2(decode_char, char, -42); */ +/* EI_DECODE_2(decode_char, char, -42); */ +/* EI_DECODE_2(decode_char, char, -42); */ +/* EI_DECODE_2(decode_char, char, -42); */ + + /* ---------------------------------------------------------------- */ + + EI_DECODE_2(decode_long, 2, long, 42); + EI_DECODE_2(decode_long, 5, long, 42); + EI_DECODE_2(decode_long, 4, long, 42); + EI_DECODE_2(decode_long, 5, long, 42); + EI_DECODE_2(decode_long, 7, long, 42); + EI_DECODE_2(decode_long, 7, long, 42); + EI_DECODE_2(decode_long, 8, long, 42); + EI_DECODE_2(decode_long, 9, long, 42); + EI_DECODE_2(decode_long, 12, long, 42); + +/* EI_DECODE_2(decode_long, 2, long, -42); */ + EI_DECODE_2(decode_long, 5, long, -42); + EI_DECODE_2(decode_long, 4, long, -42); + EI_DECODE_2(decode_long, 5, long, -42); + EI_DECODE_2(decode_long, 7, long, -42); + EI_DECODE_2(decode_long, 7, long, -42); + EI_DECODE_2(decode_long, 8, long, -42); + EI_DECODE_2(decode_long, 9, long, -42); + EI_DECODE_2(decode_long, 12, long, -42); + + /* ---------------------------------------------------------------- */ + + EI_DECODE_2(decode_ulong, 2, unsigned long, 42); + EI_DECODE_2(decode_ulong, 5, unsigned long, 42); + EI_DECODE_2(decode_ulong, 4, unsigned long, 42); + EI_DECODE_2(decode_ulong, 5, unsigned long, 42); + EI_DECODE_2(decode_ulong, 7, unsigned long, 42); + EI_DECODE_2(decode_ulong, 7, unsigned long, 42); + EI_DECODE_2(decode_ulong, 8, unsigned long, 42); + EI_DECODE_2(decode_ulong, 9, unsigned long, 42); + EI_DECODE_2(decode_ulong, 12, unsigned long, 42); + +/* EI_DECODE_2(decode_ulong, unsigned long, -42); */ +/* EI_DECODE_2(decode_ulong, unsigned long, -42); */ +/* EI_DECODE_2(decode_ulong, unsigned long, -42); */ +/* EI_DECODE_2(decode_ulong, unsigned long, -42); */ +/* EI_DECODE_2(decode_ulong, unsigned long, -42); */ +/* EI_DECODE_2(decode_ulong, unsigned long, -42); */ +/* EI_DECODE_2(decode_ulong, unsigned long, -42); */ +/* EI_DECODE_2(decode_ulong, unsigned long, -42); */ +/* EI_DECODE_2(decode_ulong, unsigned long, -42); */ + + /* ---------------------------------------------------------------- */ + +#ifndef VXWORKS + + EI_DECODE_2(decode_longlong, 2, EI_LONGLONG, 42); + EI_DECODE_2(decode_longlong, 5, EI_LONGLONG, 42); + EI_DECODE_2(decode_longlong, 4, EI_LONGLONG, 42); + EI_DECODE_2(decode_longlong, 5, EI_LONGLONG, 42); + EI_DECODE_2(decode_longlong, 7, EI_LONGLONG, 42); + EI_DECODE_2(decode_longlong, 7, EI_LONGLONG, 42); + EI_DECODE_2(decode_longlong, 8, EI_LONGLONG, 42); + EI_DECODE_2(decode_longlong, 9, EI_LONGLONG, 42); + EI_DECODE_2(decode_longlong, 12, EI_LONGLONG, 42); + +/* EI_DECODE_2(decode_longlong, 2, EI_LONGLONG, -42); */ + EI_DECODE_2(decode_longlong, 5, EI_LONGLONG, -42); + EI_DECODE_2(decode_longlong, 4, EI_LONGLONG, -42); + EI_DECODE_2(decode_longlong, 5, EI_LONGLONG, -42); + EI_DECODE_2(decode_longlong, 7, EI_LONGLONG, -42); + EI_DECODE_2(decode_longlong, 7, EI_LONGLONG, -42); + EI_DECODE_2(decode_longlong, 8, EI_LONGLONG, -42); + EI_DECODE_2(decode_longlong, 9, EI_LONGLONG, -42); + EI_DECODE_2(decode_longlong, 12, EI_LONGLONG, -42); + + /* ---------------------------------------------------------------- */ + + EI_DECODE_2(decode_ulonglong, 2, EI_ULONGLONG, 42); + EI_DECODE_2(decode_ulonglong, 5, EI_ULONGLONG, 42); + EI_DECODE_2(decode_ulonglong, 4, EI_ULONGLONG, 42); + EI_DECODE_2(decode_ulonglong, 5, EI_ULONGLONG, 42); + EI_DECODE_2(decode_ulonglong, 7, EI_ULONGLONG, 42); + EI_DECODE_2(decode_ulonglong, 7, EI_ULONGLONG, 42); + EI_DECODE_2(decode_ulonglong, 8, EI_ULONGLONG, 42); + EI_DECODE_2(decode_ulonglong, 9, EI_ULONGLONG, 42); + EI_DECODE_2(decode_ulonglong, 12, EI_ULONGLONG, 42); + +/* EI_DECODE_2(decode_ulonglong, EI_ULONGLONG, -42); */ +/* EI_DECODE_2(decode_ulonglong, EI_ULONGLONG, -42); */ +/* EI_DECODE_2(decode_ulonglong, EI_ULONGLONG, -42); */ +/* EI_DECODE_2(decode_ulonglong, EI_ULONGLONG, -42); */ +/* EI_DECODE_2(decode_ulonglong, EI_ULONGLONG, -42); */ +/* EI_DECODE_2(decode_ulonglong, EI_ULONGLONG, -42); */ +/* EI_DECODE_2(decode_ulonglong, EI_ULONGLONG, -42); */ +/* EI_DECODE_2(decode_ulonglong, EI_ULONGLONG, -42); */ +/* EI_DECODE_2(decode_ulonglong, EI_ULONGLONG, -42); */ + +#endif /* !VXWORKS */ + + /* ---------------------------------------------------------------- */ + + report(1); +} + +/* ******************************************************************** */ + +TESTCASE(test_ei_decode_misc) +{ +/* + EI_DECODE_0(decode_version); +*/ +/* + EI_DECODE_2(decode_double, 0.0); + EI_DECODE_2(decode_double, -1.0); + EI_DECODE_2(decode_double, 1.0); +*/ + EI_DECODE_2(decode_boolean, 8, int, 0); + EI_DECODE_2(decode_boolean, 7, int, 1); + + EI_DECODE_STRING(decode_atom, 6, "foo"); + EI_DECODE_STRING(decode_atom, 3, ""); + EI_DECODE_STRING(decode_atom, 9, "������"); + + EI_DECODE_STRING(decode_string, 6, "foo"); + EI_DECODE_STRING(decode_string, 1, ""); + EI_DECODE_STRING(decode_string, 9, "������"); + + EI_DECODE_BIN(decode_binary, 8, "foo", 3); + EI_DECODE_BIN(decode_binary, 5, "", 0); + EI_DECODE_BIN(decode_binary, 11, "������", 6); + + /* FIXME check \0 in strings and atoms? */ +/* + EI_ENCODE_1(decode_tuple_header, 0); + + EI_ENCODE_0(decode_empty_list); +*/ + report(1); +} + +/* ******************************************************************** */ + diff --git a/lib/erl_interface/test/ei_decode_encode_SUITE.erl b/lib/erl_interface/test/ei_decode_encode_SUITE.erl new file mode 100644 index 0000000000..c19c1d0887 --- /dev/null +++ b/lib/erl_interface/test/ei_decode_encode_SUITE.erl @@ -0,0 +1,290 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2004-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +-module(ei_decode_encode_SUITE). + +-include("test_server.hrl"). +-include("ei_decode_encode_SUITE_data/ei_decode_encode_test_cases.hrl"). + +-export( + [ + all/1, + test_ei_decode_encode/1 + ]). + +all(suite) -> + [ + test_ei_decode_encode + ]. + +%% --------------------------------------------------------------------------- + +% NOTE: these types have no meaning on the C side so we pass them +% to C and back just to see they are the same. + + +%% ######################################################################## %% + +test_ei_decode_encode(suite) -> []; +test_ei_decode_encode(Config) when is_list(Config) -> + ?line P = runner:start(?test_ei_decode_encode), + + Fun = fun (X) -> {X,true} end, + Pid = self(), + Port = case os:type() of + {win32,_} -> + open_port({spawn,"sort"},[]); + _ -> + open_port({spawn,"/bin/true"},[]) + end, + Ref = make_ref(), + Trace = {1,2,3,self(),4}, % FIXME how to construct?! + + + BigSmallA = 1696192905348584855517250509684275447603964214606878827319923580493120589769459602596313014087329389174229999430092223701630077631205171572331191216670754029016160388576759960413039261647653627052707047, + BigSmallB = 43581177444506616087519351724629421082877485633442736512567383077022781906420535744195118099822189576169114064491200598595995538299156626345938812352676950427869649947439032133573270227067833308153431095, + BigSmallC = 52751775381034251994634567029696659541685100826881826508158083211003576763074162948462801435204697796532659535818017760528684167216110865807581759669824808936751316879636014972704885388116861127856231, + + BigLargeA = 1 bsl 11111 + BigSmallA, + BigLargeB = 1 bsl 11112 + BigSmallB, + BigLargeC = BigSmallA * BigSmallB * BigSmallC * BigSmallA, + + ?line send_rec(P, Fun), + ?line send_rec(P, Pid), + ?line send_rec(P, Port), + ?line send_rec(P, Ref), + ?line send_rec(P, Trace), + + % bigs + + ?line send_rec(P, BigSmallA), + ?line send_rec(P, BigSmallB), + ?line send_rec(P, BigSmallC), + + ?line send_rec(P, BigLargeA), + ?line send_rec(P, BigLargeB), + ?line send_rec(P, BigLargeC), + + %% Test large node containers... + + ?line ThisNode = {node(), erlang:system_info(creation)}, + ?line TXPid = mk_pid(ThisNode, 32767, 8191), + ?line TXPort = mk_port(ThisNode, 268435455), + ?line TXRef = mk_ref(ThisNode, [262143, 4294967295, 4294967295]), + + ?line OtherNode = {gurka@sallad, 2}, + ?line OXPid = mk_pid(OtherNode, 32767, 8191), + ?line OXPort = mk_port(OtherNode, 268435455), + ?line OXRef = mk_ref(OtherNode, [262143, 4294967295, 4294967295]), + + ?line send_rec(P, TXPid), + ?line send_rec(P, TXPort), + ?line send_rec(P, TXRef), + ?line send_rec(P, OXPid), + ?line send_rec(P, OXPort), + ?line send_rec(P, OXRef), + + ?line runner:recv_eot(P), + ok. + + +%% ######################################################################## %% + +% We read two packets for each test, the ei_decode_encode and ei_x_decode_encode version.... + +send_rec(P, Term) when is_port(P) -> + ?t:format("Testing: ~p~n", [Term]), + P ! {self(), {command, term_to_binary(Term)}}, + {_B,Term} = get_buf_and_term(P). + + + +get_buf_and_term(P) -> + B = get_binaries(P), + case B of + <<131>> -> + io:format("(got single magic, no content)\n",[]), + {B,'$$magic$$'}; + <<131,_>> -> + T = binary_to_term(B), + io:format("~w\n~w\n(got magic)\n",[B,T]), + {B,T}; + _ -> + B1 = list_to_binary([131,B]), % No magic, add + T = binary_to_term(B1), + io:format("~w\n~w\n(got no magic)\n",[B,T]), + {B,T} + end. + + +get_binaries(P) -> + B1 = get_binary(P), + B2 = get_binary(P), + B1 = B2. + +get_binary(P) -> + case runner:get_term(P) of + {bytes,L} -> + B = list_to_binary(L), + io:format("~w\n",[L]), +% For strange reasons <<131>> show up as <>.... +% io:format("~w\n",[B]), + B; + Other -> + Other + end. + +%% + +% We use our own get_term() + +get_term(P) -> + case runner:get_term(P) of + {bytes,[131]} -> + io:format("(got single magic, no content)\n",[]), + '$$magic$$'; + {bytes,[131,L]} -> + B = list_to_binary(L), + T = binary_to_term(B), + io:format("~w\n~w\n(got magic)\n",[L,T]), + T; + {bytes,L} -> + B = list_to_binary([131,L]), + T = binary_to_term(B), + io:format("~w\n~w\n(got no magic)\n",[L,T]), + T; + Other -> + Other + end. + +%% +%% Node container constructor functions +%% + +-define(VERSION_MAGIC, 131). + +-define(ATOM_EXT, 100). +-define(REFERENCE_EXT, 101). +-define(PORT_EXT, 102). +-define(PID_EXT, 103). +-define(NEW_REFERENCE_EXT, 114). + +uint32_be(Uint) when is_integer(Uint), 0 =< Uint, Uint < 1 bsl 32 -> + [(Uint bsr 24) band 16#ff, + (Uint bsr 16) band 16#ff, + (Uint bsr 8) band 16#ff, + Uint band 16#ff]; +uint32_be(Uint) -> + exit({badarg, uint32_be, [Uint]}). + + +uint16_be(Uint) when is_integer(Uint), 0 =< Uint, Uint < 1 bsl 16 -> + [(Uint bsr 8) band 16#ff, + Uint band 16#ff]; +uint16_be(Uint) -> + exit({badarg, uint16_be, [Uint]}). + +uint8(Uint) when is_integer(Uint), 0 =< Uint, Uint < 1 bsl 8 -> + Uint band 16#ff; +uint8(Uint) -> + exit({badarg, uint8, [Uint]}). + + + +mk_pid({NodeName, Creation}, Number, Serial) when is_atom(NodeName) -> + mk_pid({atom_to_list(NodeName), Creation}, Number, Serial); +mk_pid({NodeName, Creation}, Number, Serial) -> + case catch binary_to_term(list_to_binary([?VERSION_MAGIC, + ?PID_EXT, + ?ATOM_EXT, + uint16_be(length(NodeName)), + NodeName, + uint32_be(Number), + uint32_be(Serial), + uint8(Creation)])) of + Pid when is_pid(Pid) -> + Pid; + {'EXIT', {badarg, _}} -> + exit({badarg, mk_pid, [{NodeName, Creation}, Number, Serial]}); + Other -> + exit({unexpected_binary_to_term_result, Other}) + end. + +mk_port({NodeName, Creation}, Number) when is_atom(NodeName) -> + mk_port({atom_to_list(NodeName), Creation}, Number); +mk_port({NodeName, Creation}, Number) -> + case catch binary_to_term(list_to_binary([?VERSION_MAGIC, + ?PORT_EXT, + ?ATOM_EXT, + uint16_be(length(NodeName)), + NodeName, + uint32_be(Number), + uint8(Creation)])) of + Port when is_port(Port) -> + Port; + {'EXIT', {badarg, _}} -> + exit({badarg, mk_port, [{NodeName, Creation}, Number]}); + Other -> + exit({unexpected_binary_to_term_result, Other}) + end. + +mk_ref({NodeName, Creation}, Numbers) when is_atom(NodeName), + is_integer(Creation), + is_list(Numbers) -> + mk_ref({atom_to_list(NodeName), Creation}, Numbers); +mk_ref({NodeName, Creation}, [Number]) when is_list(NodeName), + is_integer(Creation), + is_integer(Number) -> + case catch binary_to_term(list_to_binary([?VERSION_MAGIC, + ?REFERENCE_EXT, + ?ATOM_EXT, + uint16_be(length(NodeName)), + NodeName, + uint32_be(Number), + uint8(Creation)])) of + Ref when is_reference(Ref) -> + Ref; + {'EXIT', {badarg, _}} -> + exit({badarg, mk_ref, [{NodeName, Creation}, [Number]]}); + Other -> + exit({unexpected_binary_to_term_result, Other}) + end; +mk_ref({NodeName, Creation}, Numbers) when is_list(NodeName), + is_integer(Creation), + is_list(Numbers) -> + case catch binary_to_term(list_to_binary([?VERSION_MAGIC, + ?NEW_REFERENCE_EXT, + uint16_be(length(Numbers)), + ?ATOM_EXT, + uint16_be(length(NodeName)), + NodeName, + uint8(Creation), + lists:map(fun (N) -> + uint32_be(N) + end, + Numbers)])) of + Ref when is_reference(Ref) -> + Ref; + {'EXIT', {badarg, _}} -> + exit({badarg, mk_ref, [{NodeName, Creation}, Numbers]}); + Other -> + exit({unexpected_binary_to_term_result, Other}) + end. + diff --git a/lib/erl_interface/test/ei_decode_encode_SUITE_data/Makefile.first b/lib/erl_interface/test/ei_decode_encode_SUITE_data/Makefile.first new file mode 100644 index 0000000000..168a21b10e --- /dev/null +++ b/lib/erl_interface/test/ei_decode_encode_SUITE_data/Makefile.first @@ -0,0 +1,21 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2004-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# + +ei_decode_encode_test_decl.c: ei_decode_encode_test.c + erl -noinput -pa ../all_SUITE_data -s init_tc run ei_decode_encode_test -s erlang halt diff --git a/lib/erl_interface/test/ei_decode_encode_SUITE_data/Makefile.src b/lib/erl_interface/test/ei_decode_encode_SUITE_data/Makefile.src new file mode 100644 index 0000000000..d43e834558 --- /dev/null +++ b/lib/erl_interface/test/ei_decode_encode_SUITE_data/Makefile.src @@ -0,0 +1,42 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2004-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# + +include @erl_interface_mk_include@@[email protected] + +CC0 = @CC@ +CC = ..@DS@all_SUITE_data@DS@gccifier@exe@ -CC"$(CC0)" +LD = @LD@ +LIBPATH = @erl_interface_libpath@ +LIBEI = $(LIBPATH)/@erl_interface_eilib@ +LIBFLAGS = ../all_SUITE_data/ei_runner@obj@ \ + $(LIBEI) @LIBS@ @erl_interface_sock_libs@ \ + @erl_interface_threadlib@ +CFLAGS = @EI_CFLAGS@ $(THR_DEFS) -I@erl_interface_include@ -I../all_SUITE_data +EI_DECODE_ENCODE_OBJS = ei_decode_encode_test@obj@ ei_decode_encode_test_decl@obj@ + +all: ei_decode_encode_test@exe@ + +clean: + $(RM) $(EI_DECODE_ENCODE_OBJS) + $(RM) ei_decode_encode_test@exe@ + +ei_decode_encode_test@exe@: $(EI_DECODE_ENCODE_OBJS) $(LIBEI) + $(LD) @CROSSLDFLAGS@ -o $@ $(EI_DECODE_ENCODE_OBJS) $(LIBFLAGS) + + diff --git a/lib/erl_interface/test/ei_decode_encode_SUITE_data/ei_decode_encode_test.c b/lib/erl_interface/test/ei_decode_encode_SUITE_data/ei_decode_encode_test.c new file mode 100644 index 0000000000..406f02ecfb --- /dev/null +++ b/lib/erl_interface/test/ei_decode_encode_SUITE_data/ei_decode_encode_test.c @@ -0,0 +1,229 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2004-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ + +#ifdef VXWORKS +#include "reclaim.h" +#endif + +#include "ei_runner.h" + +/* + * Purpose: Read pids, funs and others without real meaning on the C side + * and pass it back to Erlang to test that it is still the same. + * Author: [email protected] + */ + +#define EI_DECODE_ENCODE(FUNC,TYPE) \ + { \ + char *buf; \ + char buf2[1024]; \ + TYPE p; \ + int size1 = 0; \ + int size2 = 0; \ + int size3 = 0; \ + int err; \ + ei_x_buff arg; \ +\ + message("ei_decode_" #FUNC ", arg is type " #TYPE); \ + buf = read_packet(NULL); \ + err = ei_decode_ ## FUNC(buf+1, &size1, &p); \ + if (err != 0) { \ + if (err != -1) { \ + fail("decode returned non zero but not -1"); \ + } else { \ + fail("decode returned non zero"); \ + } \ + return; \ + } \ + if (size1 < 1) { \ + fail("size is < 1"); \ + return; \ + } \ +\ + message("ei_encode_" #FUNC " buf is NULL, arg is type " #TYPE); \ + err = ei_encode_ ## FUNC(NULL, &size2, &p); \ + if (err != 0) { \ + if (err != -1) { \ + fail("size calculation returned non zero but not -1"); \ + return; \ + } else { \ + fail("size calculation returned non zero"); \ + return; \ + } \ + } \ + if (size1 != size2) { \ + message("size1 = %d, size2 = %d\n",size1,size2); \ + fail("decode and encode size differs when buf is NULL"); \ + return; \ + } \ + message("ei_encode_" #FUNC ", arg is type " #TYPE); \ + err = ei_encode_ ## FUNC(buf2, &size3, &p); \ + if (err != 0) { \ + if (err != -1) { \ + fail("returned non zero but not -1"); \ + } else { \ + fail("returned non zero"); \ + } \ + return; \ + } \ + if (size1 != size3) { \ + message("size1 = %d, size2 = %d\n",size1,size3); \ + fail("decode and encode size differs"); \ + return; \ + } \ + send_buffer(buf2, size1); \ +\ + message("ei_x_encode_" #FUNC ", arg is type " #TYPE); \ + ei_x_new(&arg); \ + err = ei_x_encode_ ## FUNC(&arg, &p); \ + if (err != 0) { \ + if (err != -1) { \ + fail("returned non zero but not -1"); \ + } else { \ + fail("returned non zero"); \ + } \ + ei_x_free(&arg); \ + return; \ + } \ + if (arg.index < 1) { \ + fail("size is < 1"); \ + ei_x_free(&arg); \ + return; \ + } \ + send_buffer(arg.buff, arg.index); \ + ei_x_free(&arg); \ + } + +#define EI_DECODE_ENCODE_BIG(FUNC,TYPE) \ + { \ + char *buf; \ + char buf2[2048]; \ + TYPE *p; \ + int size1 = 0; \ + int size2 = 0; \ + int size3 = 0; \ + int err, index = 0, len, type; \ + ei_x_buff arg; \ +\ + message("ei_decode_" #FUNC ", arg is type " #TYPE); \ + buf = read_packet(NULL); \ + ei_get_type(buf+1, &index, &type, &len); \ + p = ei_alloc_big(len); \ + err = ei_decode_ ## FUNC(buf+1, &size1, p); \ + if (err != 0) { \ + if (err != -1) { \ + fail("decode returned non zero but not -1"); \ + } else { \ + fail("decode returned non zero"); \ + } \ + return; \ + } \ + if (size1 < 1) { \ + fail("size is < 1"); \ + return; \ + } \ +\ + message("ei_encode_" #FUNC " buf is NULL, arg is type " #TYPE); \ + err = ei_encode_ ## FUNC(NULL, &size2, p); \ + if (err != 0) { \ + if (err != -1) { \ + fail("size calculation returned non zero but not -1"); \ + return; \ + } else { \ + fail("size calculation returned non zero"); \ + return; \ + } \ + } \ + if (size1 != size2) { \ + message("size1 = %d, size2 = %d\n",size1,size2); \ + fail("decode and encode size differs when buf is NULL"); \ + return; \ + } \ + message("ei_encode_" #FUNC ", arg is type " #TYPE); \ + err = ei_encode_ ## FUNC(buf2, &size3, p); \ + if (err != 0) { \ + if (err != -1) { \ + fail("returned non zero but not -1"); \ + } else { \ + fail("returned non zero"); \ + } \ + return; \ + } \ + if (size1 != size3) { \ + message("size1 = %d, size2 = %d\n",size1,size3); \ + fail("decode and encode size differs"); \ + return; \ + } \ + send_buffer(buf2, size1); \ +\ + message("ei_x_encode_" #FUNC ", arg is type " #TYPE); \ + ei_x_new(&arg); \ + err = ei_x_encode_ ## FUNC(&arg, p); \ + if (err != 0) { \ + if (err != -1) { \ + fail("returned non zero but not -1"); \ + } else { \ + fail("returned non zero"); \ + } \ + ei_x_free(&arg); \ + return; \ + } \ + if (arg.index < 1) { \ + fail("size is < 1"); \ + ei_x_free(&arg); \ + return; \ + } \ + send_buffer(arg.buff, arg.index); \ + ei_x_free(&arg); \ + ei_free_big(p); \ + } + + + + +/* ******************************************************************** */ + +TESTCASE(test_ei_decode_encode) +{ + EI_DECODE_ENCODE(fun , erlang_fun); + EI_DECODE_ENCODE(pid , erlang_pid); + EI_DECODE_ENCODE(port , erlang_port); + EI_DECODE_ENCODE(ref , erlang_ref); + EI_DECODE_ENCODE(trace, erlang_trace); + + EI_DECODE_ENCODE_BIG(big , erlang_big); + EI_DECODE_ENCODE_BIG(big , erlang_big); + EI_DECODE_ENCODE_BIG(big , erlang_big); + + EI_DECODE_ENCODE_BIG(big , erlang_big); + EI_DECODE_ENCODE_BIG(big , erlang_big); + EI_DECODE_ENCODE_BIG(big , erlang_big); + + /* Test large node containers... */ + EI_DECODE_ENCODE(pid , erlang_pid); + EI_DECODE_ENCODE(port , erlang_port); + EI_DECODE_ENCODE(ref , erlang_ref); + EI_DECODE_ENCODE(pid , erlang_pid); + EI_DECODE_ENCODE(port , erlang_port); + EI_DECODE_ENCODE(ref , erlang_ref); + + report(1); +} + +/* ******************************************************************** */ diff --git a/lib/erl_interface/test/ei_encode_SUITE.erl b/lib/erl_interface/test/ei_encode_SUITE.erl new file mode 100644 index 0000000000..fb790eb7c3 --- /dev/null +++ b/lib/erl_interface/test/ei_encode_SUITE.erl @@ -0,0 +1,315 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2004-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +-module(ei_encode_SUITE). + +-include("test_server.hrl"). +-include("ei_encode_SUITE_data/ei_encode_test_cases.hrl"). + +-export( + [ + all/1, + test_ei_encode_long/1, + test_ei_encode_ulong/1, + test_ei_encode_longlong/1, + test_ei_encode_ulonglong/1, + test_ei_encode_char/1, + test_ei_encode_misc/1, + test_ei_encode_fails/1 + ]). + +all(suite) -> + [ + test_ei_encode_long, + test_ei_encode_ulong, + test_ei_encode_longlong, + test_ei_encode_ulonglong, + test_ei_encode_char, + test_ei_encode_misc, + test_ei_encode_fails + ]. + +%% --------------------------------------------------------------------------- + +% NOTE: for historical reasons we don't pach as tight as we can, +% we only fill 27 bits in 32 bit INTEGER_EXT + + +%% ######################################################################## %% + +test_ei_encode_long(suite) -> []; +test_ei_encode_long(Config) when is_list(Config) -> + ?line P = runner:start(?test_ei_encode_long), + + ?line {<<97,0>> ,0} = get_buf_and_term(P), + ?line {<<97,255>> ,255} = get_buf_and_term(P), + ?line {<<98,256:32/big-signed-integer>>,256} = get_buf_and_term(P), + ?line {<<98,-1:32/big-signed-integer>> ,-1} = get_buf_and_term(P), + + ?line {<<98, 16#07ffffff:32/big-signed-integer>>, 16#07ffffff} = get_buf_and_term(P), + ?line {<<98,-16#08000000:32/big-signed-integer>>,-16#08000000} = get_buf_and_term(P), + ?line {<<110,4,0, 0,0,0,8>> , 16#08000000} = get_buf_and_term(P), + ?line {<<110,4,1, 1,0,0,8>> ,-16#08000001} = get_buf_and_term(P), + + ?line {<<110,4,0, 255,255,255,127>> , 16#7fffffff} = get_buf_and_term(P), + ?line {<<110,4,1, 0,0,0,128>> ,-16#80000000} = get_buf_and_term(P), + + ?line runner:recv_eot(P), + ok. + + +%% ######################################################################## %% + +test_ei_encode_ulong(suite) -> []; +test_ei_encode_ulong(Config) when is_list(Config) -> + ?line P = runner:start(?test_ei_encode_ulong), + + ?line {<<97,0>> ,0} = get_buf_and_term(P), + ?line {<<97,255>> ,255} = get_buf_and_term(P), + ?line {<<98,256:32/big-unsigned-integer>>,256} = get_buf_and_term(P), + + ?line {<<98, 16#07ffffff:32/big-signed-integer>>,16#07ffffff} = get_buf_and_term(P), + ?line {<<110,4,0, 0,0,0,8>> ,16#08000000} = get_buf_and_term(P), + + ?line {<<110,4,0, 255,255,255,127>> ,16#7fffffff} = get_buf_and_term(P), + ?line {<<110,4,0, 0,0,0,128>> ,16#80000000} = get_buf_and_term(P), + ?line {<<110,4,0, 255,255,255,255>> ,16#ffffffff} = get_buf_and_term(P), + + ?line runner:recv_eot(P), + ok. + + +%% ######################################################################## %% + +test_ei_encode_longlong(suite) -> []; +test_ei_encode_longlong(Config) when is_list(Config) -> + case os:type() of + vxworks -> + {skip,"Skipped on VxWorks"}; + _ -> + ?line P = runner:start(?test_ei_encode_longlong), + + ?line {<<97,0>> ,0} = get_buf_and_term(P), + ?line {<<97,255>> ,255} = get_buf_and_term(P), + ?line {<<98,256:32/big-signed-integer>>,256} = get_buf_and_term(P), + ?line {<<98,-1:32/big-signed-integer>> ,-1} = get_buf_and_term(P), + + ?line {<<98, 16#07ffffff:32/big-signed-integer>>, 16#07ffffff} = get_buf_and_term(P), + ?line {<<98,-16#08000000:32/big-signed-integer>>,-16#08000000} = get_buf_and_term(P), + ?line {<<110,4,0, 0,0,0,8>> , 16#08000000} = get_buf_and_term(P), + ?line {<<110,4,1, 1,0,0,8>> ,-16#08000001} = get_buf_and_term(P), + + ?line {<<110,4,0, 255,255,255,127>> , 16#7fffffff} = get_buf_and_term(P), + ?line {<<110,4,1, 0,0,0,128>> ,-16#80000000} = get_buf_and_term(P), + ?line {<<110,6,0, 255,255,255,255,255,127>> , 16#7fffffffffff} = get_buf_and_term(P), + ?line {<<110,6,1, 0,0,0,0,0,128>> ,-16#800000000000} = get_buf_and_term(P), + ?line {<<110,8,0, 255,255,255,255,255,255,255,127>>,16#7fffffffffffffff} = get_buf_and_term(P), + ?line {<<110,8,1, 0,0,0,0,0,0,0,128>> ,-16#8000000000000000} = get_buf_and_term(P), + + ?line runner:recv_eot(P), + ok + end. + + +%% ######################################################################## %% + +test_ei_encode_ulonglong(suite) -> []; +test_ei_encode_ulonglong(Config) when is_list(Config) -> + case os:type() of + vxworks -> + {skip,"Skipped on VxWorks"}; + _ -> + ?line P = runner:start(?test_ei_encode_ulonglong), + + ?line {<<97,0>> ,0} = get_buf_and_term(P), + ?line {<<97,255>> ,255} = get_buf_and_term(P), + ?line {<<98,256:32/big-unsigned-integer>>,256} = get_buf_and_term(P), + + ?line {<<98, 16#07ffffff:32/big-signed-integer>>,16#07ffffff} = get_buf_and_term(P), + ?line {<<110,4,0, 0,0,0,8>> ,16#08000000} = get_buf_and_term(P), + + ?line {<<110,4,0, 255,255,255,127>> ,16#7fffffff} = get_buf_and_term(P), + ?line {<<110,4,0, 0,0,0,128>> ,16#80000000} = get_buf_and_term(P), + ?line {<<110,4,0, 255,255,255,255>> ,16#ffffffff} = get_buf_and_term(P), + ?line {<<110,6,0, 255,255,255,255,255,255>>,16#ffffffffffff} = get_buf_and_term(P), + ?line {<<110,8,0, 255,255,255,255,255,255,255,255>>,16#ffffffffffffffff} = get_buf_and_term(P), + + ?line runner:recv_eot(P), + ok + end. + + +%% ######################################################################## %% +%% A "character" for us is an 8 bit integer, alwasy positive, i.e. +%% it is unsigned. +%% FIXME maybe the API should change to use "unsigned char" to be clear?! + +test_ei_encode_char(suite) -> []; +test_ei_encode_char(Config) when is_list(Config) -> + ?line P = runner:start(?test_ei_encode_char), + + ?line {<<97, 0>>,0} = get_buf_and_term(P), + ?line {<<97,127>>,16#7f} = get_buf_and_term(P), + ?line {<<97,255>>,16#ff} = get_buf_and_term(P), + + ?line runner:recv_eot(P), + ok. + + +%% ######################################################################## %% + +test_ei_encode_misc(suite) -> []; +test_ei_encode_misc(Config) when is_list(Config) -> + ?line P = runner:start(?test_ei_encode_misc), + + ?line <<131>> = get_binaries(P), + +% ?line {term,F} = get_term(P), +% ?line match_float(F, 0.0), +% ?line {term,F} = get_term(P), +% ?line match_float(F, 0.0), + +% ?line {term,F} = get_term(P), +% ?line true = match_float(F, -1.0), +% ?line {term,F} = get_term(P), +% ?line true = match_float(F, -1.0), + +% ?line {term,F} = get_term(P), +% ?line true = match_float(F, 1.0), +% ?line {term,F} = get_term(P), +% ?line true = match_float(F, 1.0), + + ?line {<<100,0,5,"false">>,false} = get_buf_and_term(P), + ?line {<<100,0,4,"true">> ,true} = get_buf_and_term(P), + ?line {<<100,0,4,"true">> ,true} = get_buf_and_term(P), + ?line {<<100,0,4,"true">> ,true} = get_buf_and_term(P), + + ?line {<<100,0,3,"foo">>,foo} = get_buf_and_term(P), + ?line {<<100,0,3,"foo">>,foo} = get_buf_and_term(P), + ?line {<<100,0,0,"">>,''} = get_buf_and_term(P), + ?line {<<100,0,0,"">>,''} = get_buf_and_term(P), + ?line {<<100,0,6,"������">>,'������'} = get_buf_and_term(P), + ?line {<<100,0,6,"������">>,'������'} = get_buf_and_term(P), + + ?line {<<107,0,3,"foo">>,"foo"} = get_buf_and_term(P), + ?line {<<107,0,3,"foo">>,"foo"} = get_buf_and_term(P), + ?line {<<106>>,""} = get_buf_and_term(P), + ?line {<<106>>,""} = get_buf_and_term(P), + ?line {<<107,0,6,"������">>,"������"} = get_buf_and_term(P), + ?line {<<107,0,6,"������">>,"������"} = get_buf_and_term(P), + + ?line {<<109,0,0,0,3,"foo">>,<<"foo">>} = get_buf_and_term(P), + ?line {<<109,0,0,0,0,"">>,<<>>} = get_buf_and_term(P), + ?line {<<109,0,0,0,6,"������">>,<<"������">>} = get_buf_and_term(P), + + ?line {<<104,0>>,{}} = get_buf_and_term(P), % Tuple header for {} + ?line {<<106>>,[]} = get_buf_and_term(P), % Empty list [] + + ?line runner:recv_eot(P), + ok. + + +%% ######################################################################## %% + +test_ei_encode_fails(suite) -> []; +test_ei_encode_fails(Config) when is_list(Config) -> + ?line P = runner:start(?test_ei_encode_fails), + + ?line XAtom = list_to_atom(lists:duplicate(255, $x)), + ?line YAtom = list_to_atom(lists:duplicate(255, $y)), + + ?line XAtom = get_term(P), + ?line XAtom = get_term(P), + ?line YAtom = get_term(P), + ?line YAtom = get_term(P), + + ?line {{{{}}}} = get_term(P), + + ?line runner:recv_eot(P), + ok. + + +%% ######################################################################## %% + +% We read two packets for each test, the ei_encode and ei_x_encode version.... + +get_buf_and_term(P) -> + B = get_binaries(P), + case B of + <<131>> -> + io:format("(got single magic, no content)\n",[]), + {B,'$$magic$$'}; + <<131,_>> -> + T = binary_to_term(B), + io:format("~w\n~w\n(got magic)\n",[B,T]), + {B,T}; + _ -> + B1 = list_to_binary([131,B]), % No magic, add + T = binary_to_term(B1), + io:format("~w\n~w\n(got no magic)\n",[B,T]), + {B,T} + end. + + +get_binaries(P) -> + B1 = get_binary(P), + B2 = get_binary(P), + B1 = B2. + +get_binary(P) -> + case runner:get_term(P) of + {bytes,L} -> + B = list_to_binary(L), + io:format("~w\n",[L]), +% For strange reasons <<131>> show up as <>.... +% io:format("~w\n",[B]), + B; + Other -> + Other + end. + +%% + +% We use our own get_term() + +get_term(P) -> + case runner:get_term(P) of + {bytes,[131]} -> + io:format("(got single magic, no content)\n",[]), + '$$magic$$'; + {bytes,[131,L]} -> + B = list_to_binary(L), + T = binary_to_term(B), + io:format("~w\n~w\n(got magic)\n",[L,T]), + T; + {bytes,L} -> + B = list_to_binary([131,L]), + T = binary_to_term(B), + io:format("~w\n~w\n(got no magic)\n",[L,T]), + T; + Other -> + Other + end. + +%% + +match_float(F, Match) when is_float(F), F > Match*0.99, F < Match*1.01 -> + true. + diff --git a/lib/erl_interface/test/ei_encode_SUITE_data/Makefile.first b/lib/erl_interface/test/ei_encode_SUITE_data/Makefile.first new file mode 100644 index 0000000000..19a6f4c0aa --- /dev/null +++ b/lib/erl_interface/test/ei_encode_SUITE_data/Makefile.first @@ -0,0 +1,21 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2004-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# + +ei_encode_test_decl.c: ei_encode_test.c + erl -noinput -pa ../all_SUITE_data -s init_tc run ei_encode_test -s erlang halt diff --git a/lib/erl_interface/test/ei_encode_SUITE_data/Makefile.src b/lib/erl_interface/test/ei_encode_SUITE_data/Makefile.src new file mode 100644 index 0000000000..f2a2c40615 --- /dev/null +++ b/lib/erl_interface/test/ei_encode_SUITE_data/Makefile.src @@ -0,0 +1,42 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2004-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# + +include @erl_interface_mk_include@@[email protected] + +CC0 = @CC@ +CC = ..@DS@all_SUITE_data@DS@gccifier@exe@ -CC"$(CC0)" +LD = @LD@ +LIBPATH = @erl_interface_libpath@ +LIBEI = $(LIBPATH)/@erl_interface_eilib@ +LIBFLAGS = ../all_SUITE_data/ei_runner@obj@ \ + $(LIBEI) @LIBS@ @erl_interface_sock_libs@ \ + @erl_interface_threadlib@ +CFLAGS = @EI_CFLAGS@ $(THR_DEFS) -I@erl_interface_include@ -I../all_SUITE_data +EI_ENCODE_OBJS = ei_encode_test@obj@ ei_encode_test_decl@obj@ + +all: ei_encode_test@exe@ + +clean: + $(RM) $(EI_ENCODE_OBJS) + $(RM) ei_encode_test@exe@ + +ei_encode_test@exe@: $(EI_ENCODE_OBJS) $(LIBEI) + $(LD) @CROSSLDFLAGS@ -o $@ $(EI_ENCODE_OBJS) $(LIBFLAGS) + + diff --git a/lib/erl_interface/test/ei_encode_SUITE_data/ei_encode_test.c b/lib/erl_interface/test/ei_encode_SUITE_data/ei_encode_test.c new file mode 100644 index 0000000000..f8de0b7878 --- /dev/null +++ b/lib/erl_interface/test/ei_encode_SUITE_data/ei_encode_test.c @@ -0,0 +1,466 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2004-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ + +#ifdef VXWORKS +#include "reclaim.h" +#endif + +#include "ei_runner.h" + +/* + * Purpose: Tests the ei_format() function. + * Author: Kent + */ + +#define EI_ENCODE_0(FUNC) \ + { \ + char buf[1024]; \ + int size1 = 0; \ + int size2 = 0; \ + int err; \ + message("ei_" #FUNC " encoded as "); \ + err = ei_ ## FUNC(NULL, &size1); \ + if (err != 0) { \ + if (err != -1) { \ + fail("size calculation returned non zero but not -1"); \ + return; \ + } else { \ + fail("size calculation returned non zero"); \ + return; \ + } \ + } \ + err = ei_ ## FUNC(buf, &size2); \ + if (err != 0) { \ + if (err != -1) { \ + fail("returned non zero but not -1"); \ + } else { \ + fail("returned non zero"); \ + } \ + return; \ + } \ + if (size1 != size2) { \ + fail("size differs when arg is NULL or buf"); \ + return; \ + } \ + if (size1 < 1) { \ + fail("size is < 1"); \ + return; \ + } \ + send_buffer(buf, size1); \ + } \ + { \ + ei_x_buff arg; \ + int err; \ + message("ei_x_" #FUNC " encoded as "); \ + ei_x_new(&arg); \ + err = ei_x_ ## FUNC(&arg); \ + if (err != 0) { \ + if (err != -1) { \ + fail("returned non zero but not -1"); \ + } else { \ + fail("returned non zero"); \ + } \ + ei_x_free(&arg); \ + return; \ + } \ + if (arg.index < 1) { \ + fail("size is < 1"); \ + ei_x_free(&arg); \ + return; \ + } \ + send_buffer(arg.buff, arg.index); \ + ei_x_free(&arg); \ + } + +#define EI_ENCODE_1(FUNC,ARG) \ + { \ + char buf[1024]; \ + int size1 = 0; \ + int size2 = 0; \ + int err; \ + message("ei_" #FUNC " " #ARG " encoded as "); \ + err = ei_ ## FUNC(NULL, &size1, ARG); \ + if (err != 0) { \ + if (err != -1) { \ + fail("size calculation returned non zero but not -1"); \ + return; \ + } else { \ + fail("size calculation returned non zero"); \ + return; \ + } \ + } \ + err = ei_ ## FUNC(buf, &size2, ARG); \ + if (err != 0) { \ + if (err != -1) { \ + fail("returned non zero but not -1"); \ + } else { \ + fail("returned non zero"); \ + } \ + return; \ + } \ + if (size1 != size2) { \ + fail("size differs when arg is NULL or buf"); \ + return; \ + } \ + if (size1 < 1) { \ + fail("size is < 1"); \ + return; \ + } \ + send_buffer(buf, size1); \ + } \ + { \ + ei_x_buff arg; \ + int err; \ + message("ei_x_" #FUNC " " #ARG " encoded as "); \ + ei_x_new(&arg); \ + err = ei_x_ ## FUNC(&arg, ARG); \ + if (err != 0) { \ + if (err != -1) { \ + fail("returned non zero but not -1"); \ + } else { \ + fail("returned non zero"); \ + } \ + ei_x_free(&arg); \ + return; \ + } \ + if (arg.index < 1) { \ + fail("size is < 1"); \ + ei_x_free(&arg); \ + return; \ + } \ + send_buffer(arg.buff, arg.index); \ + ei_x_free(&arg); \ + } + +#define EI_ENCODE_2(FUNC,ARG1,ARG2) \ + { \ + char buf[1024]; \ + int size1 = 0; \ + int size2 = 0; \ + int err; \ + message("ei_" #FUNC " " #ARG1 " " #ARG2 " encoded as "); \ + err = ei_ ## FUNC(NULL, &size1, ARG1, ARG2); \ + if (err != 0) { \ + if (err != -1) { \ + fail("size calculation returned non zero but not -1"); \ + return; \ + } else { \ + fail("size calculation returned non zero"); \ + return; \ + } \ + } \ + err = ei_ ## FUNC(buf, &size2, ARG1, ARG2); \ + if (err != 0) { \ + if (err != -1) { \ + fail("returned non zero but not -1"); \ + } else { \ + fail("returned non zero"); \ + } \ + return; \ + } \ + if (size1 != size2) { \ + fail("size differs when arg is NULL or buf"); \ + return; \ + } \ + if (size1 < 1) { \ + fail("size is < 1"); \ + return; \ + } \ + send_buffer(buf, size1); \ + } \ + { \ + ei_x_buff arg; \ + int err; \ + message("ei_x_" #FUNC " " #ARG1 " " #ARG2 " encoded as "); \ + ei_x_new(&arg); \ + err = ei_x_ ## FUNC(&arg, ARG1, ARG2); \ + if (err != 0) { \ + if (err != -1) { \ + fail("returned non zero but not -1"); \ + } else { \ + fail("returned non zero"); \ + } \ + ei_x_free(&arg); \ + return; \ + } \ + if (arg.index < 1) { \ + fail("size is < 1"); \ + ei_x_free(&arg); \ + return; \ + } \ + send_buffer(arg.buff, arg.index); \ + ei_x_free(&arg); \ + } + +/* ******************************************************************** */ + +TESTCASE(test_ei_encode_long) +{ + EI_ENCODE_1(encode_long, 0); + + EI_ENCODE_1(encode_long, 255); + + EI_ENCODE_1(encode_long, 256); + + EI_ENCODE_1(encode_long, -1); + + EI_ENCODE_1(encode_long, 0x07ffffff); + + EI_ENCODE_1(encode_long, -ll(0x08000000)); + + EI_ENCODE_1(encode_long, 0x07ffffff+1); + + EI_ENCODE_1(encode_long, -ll(0x08000000)-1); + + EI_ENCODE_1(encode_long, 0x7fffffff); + + EI_ENCODE_1(encode_long, -ll(0x80000000)); + + report(1); +} + +/* ******************************************************************** */ + +TESTCASE(test_ei_encode_ulong) +{ + EI_ENCODE_1(encode_ulong, 0); + + EI_ENCODE_1(encode_ulong, 255); + + EI_ENCODE_1(encode_ulong, 256); + + EI_ENCODE_1(encode_ulong, 0x07ffffff); + + EI_ENCODE_1(encode_ulong, 0x07ffffff+1); + + EI_ENCODE_1(encode_ulong, 0x7fffffff); + + EI_ENCODE_1(encode_ulong, 0x80000000); + + EI_ENCODE_1(encode_ulong, 0xffffffff); + + report(1); +} + +/* ******************************************************************** */ + + +TESTCASE(test_ei_encode_longlong) +{ + +#ifndef VXWORKS + + EI_ENCODE_1(encode_longlong, 0); + + EI_ENCODE_1(encode_longlong, 255); + + EI_ENCODE_1(encode_longlong, 256); + + EI_ENCODE_1(encode_longlong, -1); + + EI_ENCODE_1(encode_longlong, 0x07ffffff); + + EI_ENCODE_1(encode_longlong, -ll(0x08000000)); + + EI_ENCODE_1(encode_longlong, 0x07ffffff+1); + + EI_ENCODE_1(encode_longlong, -ll(0x08000000)-1); + + EI_ENCODE_1(encode_longlong, 0x7fffffff); + + EI_ENCODE_1(encode_longlong, -ll(0x80000000)); + + EI_ENCODE_1(encode_longlong, ll(0x7fffffffffff)); + + EI_ENCODE_1(encode_longlong, -ll(0x800000000000)); + + EI_ENCODE_1(encode_longlong, ll(0x7fffffffffffffff)); + + EI_ENCODE_1(encode_longlong, -ll(0x8000000000000000)); + +#endif /* !VXWORKS */ + + report(1); +} + +/* ******************************************************************** */ + +TESTCASE(test_ei_encode_ulonglong) +{ + +#ifndef VXWORKS + + EI_ENCODE_1(encode_ulonglong, 0); + + EI_ENCODE_1(encode_ulonglong, 255); + + EI_ENCODE_1(encode_ulonglong, 256); + + EI_ENCODE_1(encode_ulonglong, 0x07ffffff); + + EI_ENCODE_1(encode_ulonglong, 0x07ffffff+1); + + EI_ENCODE_1(encode_ulonglong, 0x7fffffff); + + EI_ENCODE_1(encode_ulonglong, 0x80000000); + + EI_ENCODE_1(encode_ulonglong, 0xffffffff); + + EI_ENCODE_1(encode_ulonglong, ll(0xffffffffffff)); + + EI_ENCODE_1(encode_ulonglong, ll(0xffffffffffffffff)); + +#endif /* !VXWORKS */ + + report(1); +} + + +/* ******************************************************************** */ + +TESTCASE(test_ei_encode_char) +{ + EI_ENCODE_1(encode_char, 0); + + EI_ENCODE_1(encode_char, 0x7f); + + EI_ENCODE_1(encode_char, 0xff); + + report(1); +} + +/* ******************************************************************** */ + +TESTCASE(test_ei_encode_misc) +{ + EI_ENCODE_0(encode_version); +/* + EI_ENCODE_1(encode_double, 0.0); + + EI_ENCODE_1(encode_double, -1.0); + + EI_ENCODE_1(encode_double, 1.0); +*/ + EI_ENCODE_1(encode_boolean, 0) /* Only case it should be false */; + + EI_ENCODE_1(encode_boolean, 1); + + EI_ENCODE_1(encode_boolean, 42); + + EI_ENCODE_1(encode_boolean, -1); + + EI_ENCODE_1(encode_atom, "foo"); + EI_ENCODE_2(encode_atom_len, "foo", 3); + + EI_ENCODE_1(encode_atom, ""); + EI_ENCODE_2(encode_atom_len, "", 0); + + EI_ENCODE_1(encode_atom, "������"); + EI_ENCODE_2(encode_atom_len, "������", 6); + + EI_ENCODE_1(encode_string, "foo"); + EI_ENCODE_2(encode_string_len, "foo", 3); + + EI_ENCODE_1(encode_string, ""); + EI_ENCODE_2(encode_string_len, "", 0); + + EI_ENCODE_1(encode_string, "������"); + EI_ENCODE_2(encode_string_len, "������", 6); + + EI_ENCODE_2(encode_binary, "foo", 3); + EI_ENCODE_2(encode_binary, "", 0); + EI_ENCODE_2(encode_binary, "������", 6); + + /* FIXME check \0 in strings and atoms */ + + EI_ENCODE_1(encode_tuple_header, 0); + + EI_ENCODE_0(encode_empty_list); + + report(1); +} + +/* ******************************************************************** */ + +TESTCASE(test_ei_encode_fails) +{ + char buf[1024]; + int index; + + /* FIXME the ei_x versions are not tested */ + + index = 0; + if (ei_encode_atom(buf, &index, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx") != 0) { + fail("could not encode atom with 255 chars"); + } + message("Encoding atom with 255 chars, encoded %d",index); + if (index != 255+3) { + fail("encoded with incorrect size"); + } + send_buffer(buf, index); + + index = 0; + if (ei_encode_atom_len(buf, &index, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", 255) != 0) { + fail("could not encode atom with 255 chars"); + } + message("Encoding atom with 255 chars, encoded %d",index); + if (index != 255+3) { + fail("encoded with incorrect size"); + } + send_buffer(buf, index); + + index = 0; + if (ei_encode_atom(buf, &index, "yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy") != 0) { + fail("could not encode atom with 256 chars, truncated to 255"); + } + message("Encoding atom with 256 chars, encoded %d",index); + if (index != 255+3) { + fail("did not truncate at 255 chars"); + } + send_buffer(buf, index); + + index = 0; + if (ei_encode_atom_len(buf, &index, "yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy", 256) != 0) { + fail("could not encode atom with 256 chars, truncated to 255"); + } + message("Encoding atom with 256 chars, encoded %d",index); + if (index != 255+3) { + fail("did not truncate at 255 chars"); + } + send_buffer(buf, index); + + /* ---------------------------------------------------------------------- */ + + index = 0; + if (ei_encode_tuple_header(buf, &index, 1) != 0) { + fail("could not create tuple header arity 1, take 1"); + } + if (ei_encode_tuple_header(buf, &index, 1) != 0) { + fail("could not create tuple header arity 1, take 2"); + } + if (ei_encode_tuple_header(buf, &index, 1) != 0) { + fail("could not create tuple header arity 1, take 3"); + } + if (ei_encode_tuple_header(buf, &index, 0) != 0) { + fail("could not create tuple header arity 0"); + } + send_buffer(buf, index); + + report(1); +} diff --git a/lib/erl_interface/test/ei_format_SUITE.erl b/lib/erl_interface/test/ei_format_SUITE.erl new file mode 100644 index 0000000000..7871f07ae9 --- /dev/null +++ b/lib/erl_interface/test/ei_format_SUITE.erl @@ -0,0 +1,161 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2001-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +-module(ei_format_SUITE). + +-include("test_server.hrl"). +-include("ei_format_SUITE_data/ei_format_test_cases.hrl"). + +-export([ + format_wo_ver/1, + all/1, + atoms/1, + tuples/1, + lists/1 + ]). + +-import(runner, [get_term/1]). + +%% This test suite test the erl_format() function. +%% It uses the port program "ei_format_test". + +all(suite) -> [ + format_wo_ver, + atoms, + tuples, + lists + ]. + +%% Tests formatting various atoms. + +atoms(suite) -> []; +atoms(Config) when is_list(Config) -> + ?line P = runner:start(?atoms), + + ?line {term, ''} = get_term(P), + ?line {term, 'a'} = get_term(P), + ?line {term, 'A'} = get_term(P), + ?line {term, 'abc'} = get_term(P), + ?line {term, 'Abc'} = get_term(P), + ?line {term, 'ab@c'} = get_term(P), + ?line {term, 'The rain in Spain stays mainly in the plains'} = + get_term(P), + + ?line {term, a} = get_term(P), + ?line {term, ab} = get_term(P), + ?line {term, abc} = get_term(P), + ?line {term, ab@c} = get_term(P), + ?line {term, abcdefghijklmnopq} = get_term(P), + + ?line {term, ''} = get_term(P), + ?line {term, 'a'} = get_term(P), + ?line {term, 'A'} = get_term(P), + ?line {term, 'abc'} = get_term(P), + ?line {term, 'Abc'} = get_term(P), + ?line {term, 'ab@c'} = get_term(P), + ?line {term, 'The rain in Spain stays mainly in the plains'} = + get_term(P), + + ?line {term, a} = get_term(P), + ?line {term, ab} = get_term(P), + ?line {term, abc} = get_term(P), + ?line {term, ab@c} = get_term(P), + ?line {term, ' abcdefghijklmnopq '} = get_term(P), + + ?line runner:recv_eot(P), + ok. + + + +%% Tests formatting various tuples + +tuples(suite) -> []; +tuples(Config) when is_list(Config) -> + ?line P = runner:start(?tuples), + + ?line {term, {}} = get_term(P), + ?line {term, {a}} = get_term(P), + ?line {term, {a, b}} = get_term(P), + ?line {term, {a, b, c}} = get_term(P), + ?line {term, {1}} = get_term(P), + ?line {term, {[]}} = get_term(P), + ?line {term, {[], []}} = get_term(P), + ?line {term, {[], a, b, c}} = get_term(P), + ?line {term, {[], a, [], b, c}} = get_term(P), + ?line {term, {[], a, '', b, c}} = get_term(P), + + ?line runner:recv_eot(P), + ok. + + + +%% Tests formatting various lists + +lists(suite) -> []; +lists(Config) when is_list(Config) -> + ?line P = runner:start(?lists), + + ?line {term, []} = get_term(P), + ?line {term, [a]} = get_term(P), + ?line {term, [a, b]} = get_term(P), + ?line {term, [a, b, c]} = get_term(P), + ?line {term, [1]} = get_term(P), + ?line {term, [[]]} = get_term(P), + ?line {term, [[], []]} = get_term(P), + ?line {term, [[], a, b, c]} = get_term(P), + ?line {term, [[], a, [], b, c]} = get_term(P), + ?line {term, [[], a, '', b, c]} = get_term(P), + ?line {term, [[x, 2], [y, 3], [z, 4]]}= get_term(P), + ?line {term, [{a,b},{c,d}]}= get_term(P), +%% ?line {term, [{name, 'Madonna'}, {age, 21}, {data, [{addr, "E-street", 42}]}]} = +%% get_term(P), + + ?line {term, [{pi, F1}, {'cos(70)', F2}]} = get_term(P), + %% don't match floats directly + true= abs(3.1415-F1) < 0.01, + true= abs(0.34202-F2) < 0.01, + + ?line {term, [[pi, F3], ['cos(70)', F4]]} = get_term(P), + true= abs(3.1415-F3) < 0.01, + true= abs(0.34202-F4) < 0.01, + + +%% ?line {term, [[pi, 3.1415], [], ["cos(70)", 0.34202]]} = get_term(P), + ?line {term, [-1]} = get_term(P), + ?line {term, "hejsan"} = get_term(P), + + + ?line Str1 = lists:duplicate(65535,$A), + ?line Str2 = lists:duplicate(65536,$A), + ?line {term,Str1} = get_term(P), + ?line {term,Str2} = get_term(P), + + ?line runner:recv_eot(P), + ok. + + +format_wo_ver(suite) -> []; +format_wo_ver(Config) when is_list(Config) -> + ?line P = runner:start(?format_wo_ver), + + ?line {term, [{a, "b"}, {c, 10}]} = get_term(P), + + ?line runner:recv_eot(P), + ok. diff --git a/lib/erl_interface/test/ei_format_SUITE_data/Makefile.first b/lib/erl_interface/test/ei_format_SUITE_data/Makefile.first new file mode 100644 index 0000000000..1247ce08c7 --- /dev/null +++ b/lib/erl_interface/test/ei_format_SUITE_data/Makefile.first @@ -0,0 +1,21 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2001-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# + +ei_format_test_decl.c: ei_format_test.c + erl -noinput -pa ../all_SUITE_data -s init_tc run ei_format_test -s erlang halt diff --git a/lib/erl_interface/test/ei_format_SUITE_data/Makefile.src b/lib/erl_interface/test/ei_format_SUITE_data/Makefile.src new file mode 100644 index 0000000000..73d51794e9 --- /dev/null +++ b/lib/erl_interface/test/ei_format_SUITE_data/Makefile.src @@ -0,0 +1,42 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2001-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# + +include @erl_interface_mk_include@@[email protected] + +CC0 = @CC@ +CC = ..@DS@all_SUITE_data@DS@gccifier@exe@ -CC"$(CC0)" +LD = @LD@ +LIBPATH = @erl_interface_libpath@ +LIBEI = $(LIBPATH)/@erl_interface_eilib@ +LIBFLAGS = ../all_SUITE_data/ei_runner@obj@ \ + $(LIBEI) @LIBS@ @erl_interface_sock_libs@ \ + @erl_interface_threadlib@ +CFLAGS = @EI_CFLAGS@ $(THR_DEFS) -I@erl_interface_include@ -I../all_SUITE_data +EI_FORMAT_OBJS = ei_format_test@obj@ ei_format_test_decl@obj@ + +all: ei_format_test@exe@ + +clean: + $(RM) $(EI_FORMAT_OBJS) + $(RM) ei_format_test@exe@ + +ei_format_test@exe@: $(EI_FORMAT_OBJS) $(LIBEI) + $(LD) @CROSSLDFLAGS@ -o $@ $(EI_FORMAT_OBJS) $(LIBFLAGS) + + diff --git a/lib/erl_interface/test/ei_format_SUITE_data/ei_format_test.c b/lib/erl_interface/test/ei_format_SUITE_data/ei_format_test.c new file mode 100644 index 0000000000..a969ded3dc --- /dev/null +++ b/lib/erl_interface/test/ei_format_SUITE_data/ei_format_test.c @@ -0,0 +1,184 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2001-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ + +#ifdef VXWORKS +#include "reclaim.h" +#endif + +#include "ei_runner.h" + +/* + * Purpose: Tests the ei_format() function. + * Author: Jakob + */ + +static void +send_format2(char* format, char* p) +{ + ei_x_buff x; + ei_x_new(&x); + ei_x_format(&x, format, p); + send_bin_term(&x); + free(x.buff); +} + +static void +send_format(char* format) +{ + send_format2(format, NULL); +} + +TESTCASE(atoms) +{ + send_format("''"); + send_format("'a'"); + send_format("'A'"); + send_format("'abc'"); + send_format("'Abc'"); + send_format("'ab@c'"); + send_format("'The rain in Spain stays mainly in the plains'"); + + send_format("a"); + send_format("ab"); + send_format("abc"); + send_format("ab@c"); + send_format(" abcdefghijklmnopq "); + + send_format2("~a", ""); + send_format2("~a", "a"); + send_format2("~a", "A"); + send_format2("~a", "abc"); + send_format2("~a", "Abc"); + send_format2("~a", "ab@c"); + send_format2("~a", "The rain in Spain stays mainly in the plains"); + + send_format2("~a", "a"); + send_format2("~a", "ab"); + send_format2("~a", "abc"); + send_format2("~a","ab@c"); + send_format2("~a", " abcdefghijklmnopq "); + + + report(1); +} + +TESTCASE(tuples) +{ + send_format("{}"); + send_format("{a}"); + send_format("{a, b}"); + send_format("{a, b, c}"); + send_format("{1}"); + send_format("{[]}"); + send_format("{[], []}"); + send_format("{[], a, b, c}"); + send_format("{[], a, [], b, c}"); + send_format("{[], a, '', b, c}"); + + report(1); +} + + + +TESTCASE(lists) +{ +/* FIXME cases to add? + ETERM* a; + ETERM* b; + ETERM* c; +*/ + ei_x_buff x; + static char str[65537]; + + send_format("[]"); + send_format("[a]"); + send_format("[a, b]"); + send_format("[a, b, c]"); + send_format("[1]"); + send_format("[[]]"); + send_format("[[], []]"); + send_format("[[], a, b, c]"); + send_format("[[], a, [], b, c]"); + send_format("[[], a, '', b, c]"); + send_format("[[x, 2], [y, 3], [z, 4]]"); + send_format("[{a,b},{c,d}]"); /* OTP-4777 */ + + ei_x_new(&x); +/* + b = erl_format("[{addr, ~s, ~i}]", "E-street", 42); + a = ei_format(x, "[{name, ~a}, {age, ~i}, {data, ~w}]", "Madonna", 21, b); + send_bin_term(a); + erl_free_term(b);*/ + ei_x_format(&x, "[{pi, ~f}, {'cos(70)', ~f}]", (float)3.1415, (float)0.34202); + send_bin_term(&x); + x.index = 0; /* otherwise it'll send the previous term again */ + ei_x_format(&x, "[[pi, ~d], ['cos(70)', ~d]]", 3.1415, 0.34202); + send_bin_term(&x); + +/* a = erl_mk_float(3.1415); + b = erl_mk_float(0.34202); + send_bin_term(ei_format("[[pi, ~w], ['cos(70)', ~w]]", a, b)); + erl_free_term(a); + erl_free_term(b); + + a = erl_mk_float(3.1415); + b = erl_mk_float(0.34202); + c = erl_mk_empty_list(); + send_bin_term(ei_format("[[~a, ~w], ~w, [~s, ~w]]", "pi", a, c, "cos(70)", b)); + erl_free_term(a); + erl_free_term(b); + erl_free_term(c); +*/ + x.index = 0; /* otherwise it'll send the previous term again */ + ei_x_format(&x, "[~i]", -1); + send_bin_term(&x); + + x.index = 0; + ei_x_format(&x, "~s","hejsan"); + send_bin_term(&x); + + memset(str,'A',65535); + str[65535] = '\0'; + str[65536] = '\0'; + x.index = 0; + ei_x_format(&x, "~s",str); + send_bin_term(&x); + str[65535] = 'A'; + x.index = 0; + ei_x_format(&x, "~s",str); + send_bin_term(&x); + + + free(x.buff); + report(1); +} + +TESTCASE(format_wo_ver) { +/* OTP-6795 + * make example with format_wo_ver + */ + ei_x_buff x; + + ei_x_new (&x); + ei_x_format(&x, "[{~a,~s},{~a,~i}]", "a", "b", "c", 10); + send_bin_term(&x); + + free(x.buff); + report(1); +} diff --git a/lib/erl_interface/test/ei_print_SUITE.erl b/lib/erl_interface/test/ei_print_SUITE.erl new file mode 100644 index 0000000000..a0f15338c6 --- /dev/null +++ b/lib/erl_interface/test/ei_print_SUITE.erl @@ -0,0 +1,142 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2001-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +-module(ei_print_SUITE). + +-include("test_server.hrl"). +-include("ei_print_SUITE_data/ei_print_test_cases.hrl"). + +-export([all/1, atoms/1, tuples/1, lists/1, strings/1]). + +-import(runner, [get_term/1]). + +%% This test suite test the ei_print() function. +%% It uses the port program "ei_format_test". + +all(suite) -> [atoms, tuples, lists, strings]. + +%% Tests formatting various atoms. + +atoms(suite) -> []; +atoms(Config) when is_list(Config) -> + ?line P = runner:start(?atoms), + + ?line {term, "''"} = get_term(P), + ?line {term, "a"} = get_term(P), + ?line {term, "'A'"} = get_term(P), + ?line {term, "abc"} = get_term(P), + ?line {term, "'Abc'"} = get_term(P), + ?line {term, "ab@c"} = get_term(P), + ?line {term, "'The rain in Spain stays mainly in the plains'"} = + get_term(P), + + ?line {term, "a"} = get_term(P), + ?line {term, "ab"} = get_term(P), + ?line {term, "abc"} = get_term(P), + ?line {term, "ab@c"} = get_term(P), + ?line {term, "abcdefghijklmnopq"} = get_term(P), + + ?line {term, "''"} = get_term(P), + ?line {term, "a"} = get_term(P), + ?line {term, "'A'"} = get_term(P), + ?line {term, "abc"} = get_term(P), + ?line {term, "'Abc'"} = get_term(P), + ?line {term, "ab@c"} = get_term(P), + ?line {term, "'The rain in Spain stays mainly in the plains'"} = + get_term(P), + + ?line {term, "a"} = get_term(P), + ?line {term, "ab"} = get_term(P), + ?line {term, "abc"} = get_term(P), + ?line {term, "ab@c"} = get_term(P), + ?line {term, "' abcdefghijklmnopq '"} = get_term(P), + + ?line runner:recv_eot(P), + ok. + + + +%% Tests formatting various tuples + +tuples(suite) -> []; +tuples(Config) when is_list(Config) -> + ?line P = runner:start(?tuples), + + ?line {term, "{}"} = get_term(P), + ?line {term, "{a}"} = get_term(P), + ?line {term, "{a, b}"} = get_term(P), + ?line {term, "{a, b, c}"} = get_term(P), + ?line {term, "{1}"} = get_term(P), + ?line {term, "{[]}"} = get_term(P), + ?line {term, "{[], []}"} = get_term(P), + ?line {term, "{[], a, b, c}"} = get_term(P), + ?line {term, "{[], a, [], b, c}"} = get_term(P), + ?line {term, "{[], a, '', b, c}"} = get_term(P), + + ?line runner:recv_eot(P), + ok. + + + +%% Tests formatting various lists + +lists(suite) -> []; +lists(Config) when is_list(Config) -> + ?line P = runner:start(?lists), + + ?line {term, "[]"} = get_term(P), + ?line {term, "[a]"} = get_term(P), + ?line {term, "[a, b]"} = get_term(P), + ?line {term, "[a, b, c]"} = get_term(P), + ?line {term, "[1]"} = get_term(P), + ?line {term, "[[]]"} = get_term(P), + ?line {term, "[[], []]"} = get_term(P), + ?line {term, "[[], a, b, c]"} = get_term(P), + ?line {term, "[[], a, [], b, c]"} = get_term(P), + ?line {term, "[[], a, '', b, c]"} = get_term(P), + ?line {term, "[[x, 2], [y, 3], [z, 4]]"}= get_term(P), + +%% ?line {term, "[{name, 'Madonna'}, {age, 21}, {data, [{addr, "E-street", 42}]}]"} = +%% get_term(P), + %% kanske regexp i st�llet? + ?line {term, "[{pi, 3.141500}, {'cos(70)', 0.342020}]"} = get_term(P), + ?line {term, "[[pi, 3.141500], ['cos(70)', 0.342020]]"} = get_term(P), + + ?line {term, "[-1]"} = get_term(P), + + ?line runner:recv_eot(P), + ok. + +strings(suite) -> []; +strings(Config) when is_list(Config) -> + ?line P = runner:start(?strings), + + ?line {term, "\"\\n\""} = get_term(P), + ?line {term, "\"\\r\\n\""} = get_term(P), + ?line {term, "\"a\""} = get_term(P), + ?line {term, "\"A\""} = get_term(P), + ?line {term, "\"0\""} = get_term(P), + ?line {term, "\"9\""} = get_term(P), + ?line {term, "\"The rain in Spain stays mainly in the plains\""} = get_term(P), + ?line {term, "\" abcdefghijklmnopq \""} = get_term(P), + + ?line runner:recv_eot(P), + ok. + diff --git a/lib/erl_interface/test/ei_print_SUITE_data/Makefile.first b/lib/erl_interface/test/ei_print_SUITE_data/Makefile.first new file mode 100644 index 0000000000..e36d4364dc --- /dev/null +++ b/lib/erl_interface/test/ei_print_SUITE_data/Makefile.first @@ -0,0 +1,21 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2001-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# + +ei_print_test_decl.c: ei_print_test.c + erl -noinput -pa ../all_SUITE_data -s init_tc run ei_print_test -s erlang halt diff --git a/lib/erl_interface/test/ei_print_SUITE_data/Makefile.src b/lib/erl_interface/test/ei_print_SUITE_data/Makefile.src new file mode 100644 index 0000000000..6eec4b1990 --- /dev/null +++ b/lib/erl_interface/test/ei_print_SUITE_data/Makefile.src @@ -0,0 +1,42 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2001-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# + +include @erl_interface_mk_include@@[email protected] + +CC0 = @CC@ +CC = ..@DS@all_SUITE_data@DS@gccifier@exe@ -CC"$(CC0)" +LD = @LD@ +LIBPATH = @erl_interface_libpath@ +LIBEI = $(LIBPATH)/@erl_interface_eilib@ +LIBFLAGS = ../all_SUITE_data/ei_runner@obj@ \ + $(LIBEI) @LIBS@ @erl_interface_sock_libs@ \ + @erl_interface_threadlib@ +CFLAGS = @EI_CFLAGS@ $(THR_DEFS) -I@erl_interface_include@ -I../all_SUITE_data +EI_PRINT_OBJS = ei_print_test@obj@ ei_print_test_decl@obj@ + +all: ei_print_test@exe@ + +clean: + $(RM) $(EI_PRINT_OBJS) + $(RM) ei_print_test@exe@ + +ei_print_test@exe@: $(EI_PRINT_OBJS) $(LIBEI) + $(LD) @CROSSLDFLAGS@ -o $@ $(EI_PRINT_OBJS) $(LIBFLAGS) + + diff --git a/lib/erl_interface/test/ei_print_SUITE_data/ei_print_test.c b/lib/erl_interface/test/ei_print_SUITE_data/ei_print_test.c new file mode 100644 index 0000000000..cc9b8048ca --- /dev/null +++ b/lib/erl_interface/test/ei_print_SUITE_data/ei_print_test.c @@ -0,0 +1,175 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2001-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ + +#include "ei_runner.h" + +/* + * Purpose: Tests the ei_print() function. + * Author: Jakob + */ + +static void +send_printed3(char* format, char* p1, char* p2, int fl) +{ + char* b = NULL; + char fn[100], * tmp = getenv("temp"); + FILE* f; + int n, index = 0, ver; + ei_x_buff x; + + ei_x_new(&x); + if (fl) { + ei_x_format(&x, format, *(float*)p1, *(float*)p2); + } else { + ei_x_format(&x, format, p1, p2); + } +#ifdef VXWORKS + tmp = "."; +#else + if (tmp == NULL) tmp = "/tmp"; +#endif + strcpy(fn, tmp); + strcat(fn, "/ei_print_test.txt"); + f = fopen(fn, "w+"); + ei_decode_version(x.buff, &index, &ver); + n = ei_print_term(f, x.buff, &index); + fseek(f, 0, SEEK_SET); + b = malloc(n+1); + fread(b, 1, n, f); + b[n] = '\0'; + fclose(f); + x.index = 0; + ei_x_format(&x, "~s", b); + send_bin_term(&x); + free(b); + ei_x_free(&x); +} + +static void +send_printed(char* format) +{ + send_printed3(format, NULL, NULL, 0); +} + +static void +send_printed2(char* format, char* p) +{ + send_printed3(format, p, NULL, 0); +} + +static void send_printed3f(char* format, float f1, float f2) +{ + send_printed3(format, (char*)&f1, (char*)&f2, 1); +} + +TESTCASE(atoms) +{ + send_printed("''"); + send_printed("'a'"); + send_printed("'A'"); + send_printed("'abc'"); + send_printed("'Abc'"); + send_printed("'ab@c'"); + send_printed("'The rain in Spain stays mainly in the plains'"); + + send_printed("a"); + send_printed("ab"); + send_printed("abc"); + send_printed("ab@c"); + send_printed(" abcdefghijklmnopq "); + + send_printed2("~a", ""); + send_printed2("~a", "a"); + send_printed2("~a", "A"); + send_printed2("~a", "abc"); + send_printed2("~a", "Abc"); + send_printed2("~a", "ab@c"); + send_printed2("~a", "The rain in Spain stays mainly in the plains"); + + send_printed2("~a", "a"); + send_printed2("~a", "ab"); + send_printed2("~a", "abc"); + send_printed2("~a","ab@c"); + send_printed2("~a", " abcdefghijklmnopq "); + + + report(1); +} + +TESTCASE(tuples) +{ + send_printed("{}"); + send_printed("{a}"); + send_printed("{a, b}"); + send_printed("{a, b, c}"); + send_printed("{1}"); + send_printed("{[]}"); + send_printed("{[], []}"); + send_printed("{[], a, b, c}"); + send_printed("{[], a, [], b, c}"); + send_printed("{[], a, '', b, c}"); + + report(1); +} + + + +TESTCASE(lists) +{ + ei_x_buff x; + + send_printed("[]"); + send_printed("[a]"); + send_printed("[a, b]"); + send_printed("[a, b, c]"); + send_printed("[1]"); + send_printed("[[]]"); + send_printed("[[], []]"); + send_printed("[[], a, b, c]"); + send_printed("[[], a, [], b, c]"); + send_printed("[[], a, '', b, c]"); + send_printed("[[x, 2], [y, 3], [z, 4]]"); + + /* more tests needed */ + send_printed3f("[{pi, ~f}, {'cos(70)', ~f}]", + (float)3.1415, (float)0.34202); + send_printed3f("[[pi, ~f], ['cos(70)', ~f]]", + (float)3.1415, (float)0.34202); + + send_printed2("[~i]", (char*)-1); + report(1); +} + +TESTCASE(strings) +{ + ei_x_buff x; + + send_printed("\"\n\""); + send_printed("\"\r\n\""); + send_printed("\"a\""); + send_printed("\"A\""); + send_printed("\"0\""); + send_printed("\"9\""); + send_printed("\"The rain in Spain stays mainly in the plains\""); + send_printed("\" abcdefghijklmnopq \""); + + report(1); +} + + diff --git a/lib/erl_interface/test/ei_tmo_SUITE.erl b/lib/erl_interface/test/ei_tmo_SUITE.erl new file mode 100644 index 0000000000..0c211aa148 --- /dev/null +++ b/lib/erl_interface/test/ei_tmo_SUITE.erl @@ -0,0 +1,666 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2003-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +-module(ei_tmo_SUITE). + +-include("test_server.hrl"). +-include_lib("kernel/include/inet.hrl"). +-include("ei_tmo_SUITE_data/ei_tmo_test_cases.hrl"). + +-define(dummy_host,test01). + +-export([all/1, init_per_testcase/2, fin_per_testcase/2, + framework_check/1, ei_accept_tmo/1, ei_connect_tmo/1, ei_send_tmo/1, + ei_recv_tmo/1]). + +all(suite) -> [framework_check,ei_accept_tmo,ei_connect_tmo, + ei_send_tmo,ei_recv_tmo]. + +init_per_testcase(_Case, Config) -> + Dog = ?t:timetrap(?t:minutes(1)), + % test if platform is vxworks_simso + ?line {_,Host} = split(node()), + Bool = case atom_to_list(Host) of + [$v,$x,$s,$i,$m | _] -> true; + _ -> false + end, + [{vxsim,Bool},{watchdog, Dog}|Config]. + +fin_per_testcase(_Case, Config) -> + Dog = ?config(watchdog, Config), + test_server:timetrap_cancel(Dog), + ok. + +framework_check(doc) -> + ["Check the framework."]; +framework_check(suite) -> + []; +framework_check(Config) when is_list(Config) -> + %%dbg:tracer(), + %%dbg:p(self()), + ?line P = runner:start(?framework_check), + ?line runner:send_term(P,{hello,world}), + ?line {term, {hello,world}} = runner:get_term(P), + ?line runner:recv_eot(P), + ok. + + +ei_recv_tmo(doc) -> + ["Check recv with timeouts."]; +ei_recv_tmo(suite) -> + []; +ei_recv_tmo(Config) when is_list(Config) -> + ?line do_one_recv(c_node_recv_tmo_1), + ?line do_one_recv_failure(c_node_recv_tmo_2), + ok. + + +do_one_recv(CNode) -> + ?line {_,Host} = split(node()), + ?line P1 = runner:start(?recv_tmo), + ?line runner:send_term(P1,{CNode, + erlang:get_cookie(), + node()}), + ?line {term, X} = runner:get_term(P1, 10000), + ?line true = is_integer(X), + ?line CNode1 = join(CNode,Host), + ?line Term1 = {hej,[hopp,{i,[lingon,"skogen"]}]}, + ?line {test,CNode1} ! Term1, + ?line {term, Term1} = runner:get_term(P1, 10000), + ?line runner:recv_eot(P1). + +do_one_recv_failure(CNode) -> + ?line P1 = runner:start(?recv_tmo), + ?line runner:send_term(P1,{CNode, + erlang:get_cookie(), + node()}), + ?line {term, X} = runner:get_term(P1, 10000), + ?line true = is_integer(X), + ?line {term, {Ret,ETimedout,ETimedout}} = runner:get_term(P1, 10000), + ?line true = (Ret < 0), + ?line runner:recv_eot(P1). + + +ei_send_tmo(doc) -> + ["Check send with timeouts."]; +ei_send_tmo(suite) -> + []; +ei_send_tmo(Config) when is_list(Config) -> + %dbg:tracer(), + %dbg:p(self()), + VxSim = ?config(vxsim, Config), + ?line register(ei_send_tmo_1,self()), + ?line do_one_send(self(),c_node_send_tmo_1), + ?line do_one_send(ei_send_tmo_1,c_node_send_tmo_2), + ?line do_one_send_failure(self(),cccc1,c_nod_send_tmo_3,VxSim), + ?line do_one_send_failure(ei_send_tmo_1,cccc2,c_nod_send_tmo_4,VxSim), + ok. + + +do_one_send(From,CNode) -> + ?line {_,Host} = split(node()), + ?line P1 = runner:start(?send_tmo), + ?line runner:send_term(P1,{CNode, + erlang:get_cookie(), + node()}), + ?line {term, X} = runner:get_term(P1, 10000), + ?line true = is_integer(X), + ?line CNode1 = join(CNode,Host), + ?line Term1 = {hej,[hopp,{i,[lingon,"skogen"]}]}, + ?line {test,CNode1} ! {From,1,Term1}, + ?line ok = receive + Term1 -> + ok + after 2000 -> + error + end, + ?line {term, 0} = runner:get_term(P1, 10000), + ?line runner:recv_eot(P1). + +do_one_send_failure(From,FakeName,CName,VxSim) -> + ?line {_,Host} = split(node()), + ?line OurName = join(FakeName,Host), + ?line Node = join(CName,Host), + ?line LSocket = case gen_tcp:listen(0, [{active, false}, {packet,2}]) of + {ok, Socket} -> + ?line Socket; + Else -> + ?line exit(Else) + end, + ?line EpmdSocket = register(OurName, LSocket, 1, 5), + ?line P3 = runner:start(?send_tmo), + ?line Cookie = kaksmula_som_ingen_bryr_sig_om, + ?line runner:send_term(P3,{CName, + Cookie, + OurName}), + ?line SocketB = case gen_tcp:accept(LSocket) of + {ok, Socket1} -> + ?line Socket1; + Else2 -> + ?line exit(Else2) + end, + ?line {hidden,Node,5} = recv_name(SocketB), % See 1) + ?line send_status(SocketB, ok), + ?line MyChallengeB = gen_challenge(), + ?line send_challenge(SocketB, OurName, MyChallengeB, 5), + ?line HisChallengeB = recv_challenge_reply( + SocketB, + MyChallengeB, + Cookie), + ?line DigestB = gen_digest(HisChallengeB,Cookie), + ?line send_challenge_ack(SocketB, DigestB), + ?line inet:setopts(SocketB, [{active, false}, + {packet, 4}]), + ?line {term, X} = runner:get_term(P3, 10000), + ?line true = is_integer(X), + ?line Message = [112,term_to_binary({6,self(),'',test}), + term_to_binary({From,10000, + {app,["lapp",{sa,["att",du,{slapp, + sitta}]}]}})], + ?line gen_tcp:send(SocketB,Message), + + %% At this point the test program starts sending messages (max 10000). Since + %% we're not receiving, eventually the send buffer fills up. Then no more + %% sending is possible and select() times out. The number of messages sent + %% before this happens is returned in Iters. The timeout value for get_term/2 + %% must be large enough so there's time for the select() to time out and + %% the test program to return the error tuple (below). + Res0 = + if VxSim == false -> + ?line {term,{Res,ETO,Iters,ETO}} = runner:get_term(P3, 20000), + Res; + true -> % relax the test for vxsim + ?line case runner:get_term(P3, 20000) of + {term,{Res,ETO,Iters,ETO}} -> + Res; + {term,{Res,_,Iters,ETO}} -> % EIO? + Res + end + end, + ?line runner:recv_eot(P3), + ?line true = ((Res0 < 0) and (Iters > 0)), + ?line gen_tcp:close(SocketB), + ?line gen_tcp:close(EpmdSocket), + ok. + + +ei_connect_tmo(doc) -> + ["Check accept with timeouts."]; +ei_connect_tmo(suite) -> + []; +ei_connect_tmo(Config) when is_list(Config) -> + %dbg:tracer(), + %dbg:p(self()), + VxSim = ?config(vxsim, Config), + DummyNode = make_and_check_dummy(), + ?line P = runner:start(?connect_tmo), + ?line runner:send_term(P,{c_nod_connect_tmo_1, + kaksmula_som_ingen_bryr_sig_om, + DummyNode}), + ETimedout = + if VxSim == false -> + ?line {term,{-3,ETO,ETO}} = runner:get_term(P, 10000), + ?line ETO; + true -> % relax the test for vxsim + ?line case runner:get_term(P, 10000) of + {term,{-3,ETO,ETO}} -> + ?line ETO; + {term,{-1,_,ETO}} -> % EHOSTUNREACH = ok + ?line ETO + end + end, + ?line runner:recv_eot(P), + ?line P2 = runner:start(?connect_tmo), + ?line runner:send_term(P2,{c_nod_connect_tmo_2, + erlang:get_cookie(), + node()}), + ?line {term, X} = runner:get_term(P2, 10000), + ?line runner:recv_eot(P2), + ?line true = is_integer(X), + %% Aborted handshake test... + ?line {_,Host} = split(node()), + ?line OurName = join(cccc,Host), + ?line Node = join(c_nod_connect_tmo_3,Host), + ?line LSocket = case gen_tcp:listen(0, [{active, false}, {packet,2}]) of + {ok, Socket} -> + ?line Socket; + Else -> + ?line exit(Else) + end, + ?line EpmdSocket = register(OurName, LSocket, 1, 5), + ?line P3 = runner:start(?connect_tmo), + ?line Cookie = kaksmula_som_ingen_bryr_sig_om, + ?line runner:send_term(P3,{c_nod_connect_tmo_3, + Cookie, + OurName}), + ?line SocketB = case gen_tcp:accept(LSocket) of + {ok, Socket1} -> + ?line Socket1; + Else2 -> + ?line exit(Else2) + end, + ?line {hidden,Node,5} = recv_name(SocketB), % See 1) + ?line send_status(SocketB, ok), + ?line MyChallengeB = gen_challenge(), + ?line send_challenge(SocketB, OurName, MyChallengeB, 5), + ?line HisChallengeB = recv_challenge_reply( + SocketB, + MyChallengeB, + Cookie), + ?line {term,{-1,ETimedout,ETimedout}} = runner:get_term(P3, 10000), + ?line runner:recv_eot(P3), + ?line gen_tcp:close(SocketB), + ?line gen_tcp:close(EpmdSocket), + ok. + + +ei_accept_tmo(doc) -> + ["Check accept with timeouts."]; +ei_accept_tmo(suite) -> + []; +ei_accept_tmo(Config) when is_list(Config) -> + %%dbg:tracer(), + %%dbg:p(self()), + ?line P = runner:start(?accept_tmo), + ?line runner:send_term(P,{c_nod_som_ingen_kontaktar_1, + kaksmula_som_ingen_bryr_sig_om}), + ?line {term,{-1,ETimedout,ETimedout}} = runner:get_term(P, 10000), + ?line runner:recv_eot(P), + ?line P2 = runner:start(?accept_tmo), + ?line runner:send_term(P2,{c_nod_som_vi_kontaktar_1, + erlang:get_cookie()}), + ?line receive after 1000 -> ok end, + ?line CNode1 = make_node(c_nod_som_vi_kontaktar_1), + ?line {ignored,CNode1} ! tjenare, + ?line {term, X} = runner:get_term(P2, 10000), + ?line runner:recv_eot(P2), + ?line true = is_integer(X), + ?line P3 = runner:start(?accept_tmo), + ?line runner:send_term(P3,{c_nod_som_vi_kontaktar_2, + erlang:get_cookie()}), + ?line receive after 1000 -> ok end, + ?line CNode2 = make_node(c_nod_som_vi_kontaktar_2), + ?line {NA,NB} = split(CNode2), + ?line {_,Host} = split(node()), + ?line OurName = join(ccc,Host), + ?line {port,PortNo,_} = erl_epmd:port_please(NA,NB), + ?line {ok, SocketA} = gen_tcp:connect(atom_to_list(NB),PortNo, + [{active,false}, + {packet,2}]), + ?line send_name(SocketA,OurName,5), + ?line ok = recv_status(SocketA), + ?line {hidden,Node,5,HisChallengeA} = recv_challenge(SocketA), % See 1) + ?line OurChallengeA = gen_challenge(), + ?line OurDigestA = gen_digest(HisChallengeA, erlang:get_cookie()), + %% Dont do the last two steps of the connection setup... + %% send_challenge_reply(SocketA, OurChallengeA, OurDigestA), + %% ok = recv_challenge_ack(SocketA, OurChallengeA, erlang:get_cookie()), + ?line {term, {-1,ETimedout,ETimedout}} = runner:get_term(P3, 10000), + ?line runner:recv_eot(P3), + ?line gen_tcp:close(SocketA), + ok. + +make_node(X) -> + list_to_atom(atom_to_list(X) ++ "@" ++ + hd(tl(string:tokens(atom_to_list(node()),"@")))). + + +make_and_check_dummy() -> + % First check that the host has an ip and is *not* reachable + ?line case gen_tcp:connect(?dummy_host,23,[{active,false}],5000) of + {error,timeout} -> ok; + {error,ehostunreach} -> ok + end, + + list_to_atom("dummy@"++atom_to_list(?dummy_host)). + +%% +%% Stolen from the erl_distribution_wb_test in kernel +%% To be able to do partial handshakes... +%% + +-define(to_port(Socket, Data), + case inet_tcp:send(Socket, Data) of + {error, closed} -> + self() ! {tcp_closed, Socket}, + {error, closed}; + R -> + R + end). + +-define(DFLAG_PUBLISHED,1). +-define(DFLAG_ATOM_CACHE,2). +-define(DFLAG_EXTENDED_REFERENCES,4). +-define(DFLAG_EXTENDED_PIDS_PORTS,16#100). +-define(DFLAG_DIST_MONITOR,8). + +%% From R9 and forward extended references is compulsory +-define(COMPULSORY_DFLAGS, (?DFLAG_EXTENDED_REFERENCES bor ?DFLAG_EXTENDED_PIDS_PORTS)). + +-define(shutdown(X), exit(X)). +-define(int16(X), [((X) bsr 8) band 16#ff, (X) band 16#ff]). + +-define(int32(X), + [((X) bsr 24) band 16#ff, ((X) bsr 16) band 16#ff, + ((X) bsr 8) band 16#ff, (X) band 16#ff]). + +-define(i16(X1,X0), + (?u16(X1,X0) - + (if (X1) > 127 -> 16#10000; true -> 0 end))). + +-define(u16(X1,X0), + (((X1) bsl 8) bor (X0))). + +-define(u32(X3,X2,X1,X0), + (((X3) bsl 24) bor ((X2) bsl 16) bor ((X1) bsl 8) bor (X0))). + +%% +%% Handshake utilities +%% + +%% +%% MD5 hashing +%% + +%% This is no proper random number, but that is not really important in +%% this test +gen_challenge() -> + {_,_,N} = erlang:now(), + N. + +%% Generate a message digest from Challenge number and Cookie +gen_digest(Challenge, Cookie) when is_integer(Challenge), is_atom(Cookie) -> + C0 = erlang:md5_init(), + C1 = erlang:md5_update(C0, atom_to_list(Cookie)), + C2 = erlang:md5_update(C1, integer_to_list(Challenge)), + binary_to_list(erlang:md5_final(C2)). + + +%% +%% The differrent stages of the MD5 handshake +%% + +send_status(Socket, Stat) -> + case gen_tcp:send(Socket, [$s | atom_to_list(Stat)]) of + {error, _} -> + ?shutdown(could_not_send_status); + _ -> + true + end. + + +recv_status(Socket) -> + case gen_tcp:recv(Socket, 0) of + {ok, [$s|StrStat]} -> + list_to_atom(StrStat); + Bad -> + exit(Bad) + end. + +send_challenge(Socket, Node, Challenge, Version) -> + send_challenge(Socket, Node, Challenge, Version, ?COMPULSORY_DFLAGS). +send_challenge(Socket, Node, Challenge, Version, Flags) -> + {ok, {{Ip1,Ip2,Ip3,Ip4}, _}} = inet:sockname(Socket), + ?to_port(Socket, [$n,?int16(Version),?int32(Flags), + ?int32(Challenge), atom_to_list(Node)]). + +recv_challenge(Socket) -> + case gen_tcp:recv(Socket, 0) of + {ok,[$n,V1,V0,Fl1,Fl2,Fl3,Fl4,CA3,CA2,CA1,CA0 | Ns]} -> + Flags = ?u32(Fl1,Fl2,Fl3,Fl4), + Type = case Flags band ?DFLAG_PUBLISHED of + 0 -> + hidden; + _ -> + normal + end, + Node =list_to_atom(Ns), + Version = ?u16(V1,V0), + Challenge = ?u32(CA3,CA2,CA1,CA0), + {Type,Node,Version,Challenge}; + _ -> + ?shutdown(no_node) + end. + +send_challenge_reply(Socket, Challenge, Digest) -> + ?to_port(Socket, [$r,?int32(Challenge),Digest]). + +recv_challenge_reply(Socket, ChallengeA, Cookie) -> + case gen_tcp:recv(Socket, 0) of + {ok,[$r,CB3,CB2,CB1,CB0 | SumB]} when length(SumB) == 16 -> + SumA = gen_digest(ChallengeA, Cookie), + ChallengeB = ?u32(CB3,CB2,CB1,CB0), + if SumB == SumA -> + ChallengeB; + true -> + ?shutdown(bad_challenge_reply) + end; + _ -> + ?shutdown(no_node) + end. + +send_challenge_ack(Socket, Digest) -> + ?to_port(Socket, [$a,Digest]). + +recv_challenge_ack(Socket, ChallengeB, CookieA) -> + case gen_tcp:recv(Socket, 0) of + {ok,[$a | SumB]} when length(SumB) == 16 -> + SumA = gen_digest(ChallengeB, CookieA), + if SumB == SumA -> + ok; + true -> + ?shutdown(bad_challenge_ack) + end; + _ -> + ?shutdown(bad_challenge_ack) + end. + +send_name(Socket, MyNode0, Version) -> + send_name(Socket, MyNode0, Version, ?COMPULSORY_DFLAGS). +send_name(Socket, MyNode0, Version, Flags) -> + MyNode = atom_to_list(MyNode0), + ?to_port(Socket, [$n,?int16(Version),?int32(Flags)] ++ + MyNode). + +%% +%% recv_name is common for both old and new handshake. +%% +recv_name(Socket) -> + case gen_tcp:recv(Socket, 0) of + {ok,Data} -> + get_name(Data); + Res -> + ?shutdown({no_node,Res}) + end. + +get_name([$m,VersionA,VersionB,_Ip1,_Ip2,_Ip3,_Ip4|OtherNode]) -> + {normal, list_to_atom(OtherNode), ?u16(VersionA,VersionB)}; +get_name([$h,VersionA,VersionB,_Ip1,_Ip2,_Ip3,_Ip4|OtherNode]) -> + {hidden, list_to_atom(OtherNode), ?u16(VersionA,VersionB)}; +get_name([$n,VersionA, VersionB, Flag1, Flag2, Flag3, Flag4 | OtherNode]) -> + Type = case ?u32(Flag1, Flag2, Flag3, Flag4) band ?DFLAG_PUBLISHED of + 0 -> + hidden; + _ -> + normal + end, + {Type, list_to_atom(OtherNode), + ?u16(VersionA,VersionB)}; +get_name(Data) -> + ?shutdown(Data). + +%% +%% tell_name is for old handshake +%% +tell_name(Socket, MyNode0, Version) -> + MyNode = atom_to_list(MyNode0), + {ok, {{Ip1,Ip2,Ip3,Ip4}, _}} = inet:sockname(Socket), + ?to_port(Socket, [$h,?int16(Version),Ip1,Ip2,Ip3,Ip4] ++ + MyNode). + +%% +%% The communication with EPMD follows +%% +do_register_node(NodeName, TcpPort, VLow, VHigh) -> + case gen_tcp:connect({127,0,0,1}, get_epmd_port(), []) of + {ok, Socket} -> + {N0,_} = split(NodeName), + Name = atom_to_list(N0), + Extra = "", + Elen = length(Extra), + Len = 1+2+1+1+2+2+2+length(Name)+2+Elen, + gen_tcp:send(Socket, [?int16(Len), $x, + ?int16(TcpPort), + $M, + 0, + ?int16(VHigh), + ?int16(VLow), + ?int16(length(Name)), + Name, + ?int16(Elen), + Extra]), + case wait_for_reg_reply(Socket, []) of + {error, epmd_close} -> + exit(epmd_broken); + Other -> + Other + end; + Error -> + Error + end. + +wait_for_reg_reply(Socket, SoFar) -> + receive + {tcp, Socket, Data0} -> + case SoFar ++ Data0 of + [$y, Result, A, B] -> + case Result of + 0 -> + {alive, Socket, ?u16(A, B)}; + _ -> + {error, duplicate_name} + end; + Data when length(Data) < 4 -> + wait_for_reg_reply(Socket, Data); + Garbage -> + {error, {garbage_from_epmd, Garbage}} + end; + {tcp_closed, Socket} -> + {error, epmd_close} + after 10000 -> + gen_tcp:close(Socket), + {error, no_reg_reply_from_epmd} + end. + + +register(NodeName, ListenSocket, VLow, VHigh) -> + {ok,{_,TcpPort}} = inet:sockname(ListenSocket), + case do_register_node(NodeName, TcpPort, VLow, VHigh) of + {alive, Socket, Creation} -> + Socket; + Other -> + exit(Other) + end. + + +%% +%% Utilities +%% + +%% Split a nodename +split([$@|T],A) -> + {lists:reverse(A),T}; +split([H|T],A) -> + split(T,[H|A]). + +split(Atom) -> + {A,B} = split(atom_to_list(Atom),[]), + {list_to_atom(A),list_to_atom(B)}. + +%% Build a simple distribution message +build_message(Cookie) -> + [$?,term_to_binary({6,self(),Cookie,rex}),term_to_binary(plupp)]. + +%% Build a distribution message that will make rex answer +build_rex_message(Cookie,OurName) -> + [$?,term_to_binary({6,self(),Cookie,rex}), + term_to_binary({'$gen_cast', + {cast, + rpc, + cast, + [OurName, hello, world, []], + self()} })]. + +%% Receive a distribution message +recv_message(Socket) -> + case gen_tcp:recv(Socket, 0) of + {ok,Data} -> + B0 = list_to_binary(Data), + {_,B1} = erlang:split_binary(B0,1), + Header = erlang:binary_to_term(B1), + Siz = size(term_to_binary(Header)), + {_,B2} = erlang:split_binary(B1,Siz), + Message = case (catch erlang:binary_to_term(B2)) of + {'EXIT', _} -> + could_not_digest_message; + Other -> + Other + end, + {Header, Message}; + Res -> + exit({no_message,Res}) + end. + +%% Build a nodename +join(Name,Host) -> + list_to_atom(atom_to_list(Name) ++ "@" ++ atom_to_list(Host)). + +%% start/stop slave. +start_node(Name, Param) -> + ?t:start_node(Name, slave, [{args, Param}]). + +stop_node(Node) -> + ?t:stop_node(Node). + + +get_nodenames(N, T) -> + get_nodenames(N, T, []). + +get_nodenames(0, _, Acc) -> + Acc; +get_nodenames(N, T, Acc) -> + {A, B, C} = now(), + get_nodenames(N-1, T, [list_to_atom(atom_to_list(?MODULE) + ++ "-" + ++ atom_to_list(T) + ++ "-" + ++ integer_to_list(A) + ++ "-" + ++ integer_to_list(B) + ++ "-" + ++ integer_to_list(C)) | Acc]). + +get_epmd_port() -> + case init:get_argument(epmd_port) of + {ok, [[PortStr|_]|_]} when is_list(PortStr) -> + list_to_integer(PortStr); + error -> + 4369 % Default epmd port + end. diff --git a/lib/erl_interface/test/ei_tmo_SUITE_data/Makefile.first b/lib/erl_interface/test/ei_tmo_SUITE_data/Makefile.first new file mode 100644 index 0000000000..6eb9f2ce71 --- /dev/null +++ b/lib/erl_interface/test/ei_tmo_SUITE_data/Makefile.first @@ -0,0 +1,21 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2003-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# + +ei_tmo_test_decl.c: ei_tmo_test.c + erl -noinput -pa ../all_SUITE_data -s init_tc run ei_tmo_test -s erlang halt diff --git a/lib/erl_interface/test/ei_tmo_SUITE_data/Makefile.src b/lib/erl_interface/test/ei_tmo_SUITE_data/Makefile.src new file mode 100644 index 0000000000..a49eeccc02 --- /dev/null +++ b/lib/erl_interface/test/ei_tmo_SUITE_data/Makefile.src @@ -0,0 +1,41 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2003-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# + +include @erl_interface_mk_include@@[email protected] + +CC0 = @CC@ +CC = ..@DS@all_SUITE_data@DS@gccifier@exe@ -CC"$(CC0)" +LD = @LD@ +LIBPATH = @erl_interface_libpath@ +LIBEI = $(LIBPATH)/@erl_interface_eilib@ +LIBFLAGS = ../all_SUITE_data/ei_runner@obj@ \ + $(LIBEI) @LIBS@ @erl_interface_sock_libs@ \ + @erl_interface_threadlib@ +CFLAGS = @EI_CFLAGS@ $(THR_DEFS) -I@erl_interface_include@ -I../all_SUITE_data +EI_TMO_OBJS = ei_tmo_test@obj@ ei_tmo_test_decl@obj@ + +all: ei_tmo_test@exe@ + +clean: + $(RM) $(EI_TMO_OBJS) + $(RM) ei_tmo_test@exe@ + +ei_tmo_test@exe@: $(EI_TMO_OBJS) $(LIBEI) + $(LD) @CROSSLDFLAGS@ -o $@ $(EI_TMO_OBJS) $(LIBFLAGS) + diff --git a/lib/erl_interface/test/ei_tmo_SUITE_data/ei_tmo_test.c b/lib/erl_interface/test/ei_tmo_SUITE_data/ei_tmo_test.c new file mode 100644 index 0000000000..2cc9af975d --- /dev/null +++ b/lib/erl_interface/test/ei_tmo_SUITE_data/ei_tmo_test.c @@ -0,0 +1,767 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2003-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ + +#include <stdio.h> +#include <string.h> +#ifdef VXWORKS +#include "reclaim.h" +#endif + +#ifdef __WIN32__ +#include <winsock2.h> +#include <windows.h> +#else +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#endif + +#include "ei_runner.h" + +#ifndef __WIN32__ +#define closesocket(X) close(X) +#endif + +#define DEBUG 1 + +#ifdef DEBUG +#include <stdarg.h> + +FILE *debugfile = NULL; +#define OPEN_DEBUGFILE(Number) debugf_open(Number) +#define CLOSE_DEBUGFILE() debugf_close() +#define DEBUGF(X) debugf X + +static void debugf(char *format, ...) +{ + va_list ap; + va_start(ap,format); + if (debugfile) { + vfprintf(debugfile,format,ap); + fflush(debugfile); + } else { + fprintf(stderr,"Attempt to write to debugfile when not open...\n"); + } + va_end(ap); +} + +static void debugf_open(int number) +{ + char filename[1024]; + sprintf(filename,"ei_tmo_test%d.debug",number); +#if !defined(VXWORKS) && !defined(__WIN32__) && !defined(_OSE_) + close(2); +#endif + debugfile = fopen(filename,"a"); + fprintf(debugfile,"===================================================\n"); +} + +static void debugf_close(void) +{ + if (debugfile) + fclose(debugfile); +} + +#else +#define OPEN_DEBUGFILE(X) /* noop */ +#define CLOSE_DEBUGFILE() /* noop */ +#define DEBUGF(X) /* noop */ +#endif + +TESTCASE(framework_check) +{ + char *ptr = NULL; + int len; + +#ifdef DEBUG + int version; + int i; +#endif + + OPEN_DEBUGFILE(1); + + DEBUGF(("B�rjar... \n")); + ptr = read_packet(&len); + if (*ptr != 't') { + DEBUGF(("Gick fel \n")); + report(1); + } else { + ei_x_buff x; + ei_x_new(&x); + ei_x_append_buf(&x, ptr+1,len-1); + DEBUGF(("Gick bra? %d\n",x.index)); +#ifdef DEBUG + for(i=0;i < x.index; ++i) + DEBUGF(("%d ",(int) ((unsigned char *) x.buff)[i])); + DEBUGF(("\n")); + len = 0; + ei_decode_version(x.buff,&len,&version); + ei_print_term(debugfile,x.buff,&len); + fflush(debugfile); +#endif + send_bin_term(&x); + ei_x_free(&x); + } + if (ptr != NULL) + free(ptr); + CLOSE_DEBUGFILE(); + report(1); +} + +int decode_request(char **nodename_p, char **cookie_p, char **peername_p) +{ + char *nodename = NULL; + char *cookie = NULL; + char *peername = NULL; + char *ptr = NULL; + ei_x_buff x; + int len; + int version; + int type; + int size; + int expected_size = (peername_p == NULL) ? 2 : 3; + int ret = -1; + + ptr = read_packet(&len); + ei_x_new(&x); + if (*ptr != 't') { + goto cleanup; + } + ei_x_append_buf(&x, ptr+1,len-1); + len = 0; + ei_decode_version(x.buff,&len,&version); +#ifdef DEBUG + { + int tlen = len; + ei_print_term(debugfile,x.buff,&tlen); + DEBUGF(("\n")); + } +#endif + if (ei_get_type(x.buff,&len,&type,&size) != 0) { + DEBUGF(("Failure at line %d\n",__LINE__)); + goto cleanup; + } + if (type != ERL_SMALL_TUPLE_EXT || size != expected_size) { + DEBUGF(("Failure at line %d, type=%d, size = %d\n",__LINE__, + type,size)); + goto cleanup; + } + if (ei_decode_tuple_header(x.buff,&len,&size) != 0 || size != expected_size) { + DEBUGF(("Failure at line %d\n",__LINE__)); + goto cleanup; + } + if (ei_get_type(x.buff,&len,&type,&size) != 0) { + DEBUGF(("Failure at line %d\n",__LINE__)); + goto cleanup; + } + if (type != ERL_ATOM_EXT) { + DEBUGF(("Failure at line %d\n",__LINE__)); + goto cleanup; + } + nodename = malloc(size+1); + ei_decode_atom(x.buff,&len,nodename); + nodename[size] = '\0'; /* needed????? */ + if (ei_get_type(x.buff,&len,&type,&size) != 0) { + DEBUGF(("Failure at line %d\n",__LINE__)); + goto cleanup; + } + if (type != ERL_ATOM_EXT) { + DEBUGF(("Failure at line %d\n",__LINE__)); + goto cleanup; + } + cookie = malloc(size + 1); + ei_decode_atom(x.buff,&len,cookie); + cookie[size] = '\0'; /* needed????? */ + if (expected_size > 2) { + if (ei_get_type(x.buff,&len,&type,&size) != 0) { + DEBUGF(("Failure at line %d\n",__LINE__)); + goto cleanup; + } + if (type != ERL_ATOM_EXT) { + DEBUGF(("Failure at line %d\n",__LINE__)); + goto cleanup; + } + peername = malloc(size + 1); + ei_decode_atom(x.buff,&len,peername); + peername[size] = '\0'; /* needed????? */ + DEBUGF(("nodename = %s, cookie = %s, peername = %s\n", + nodename, cookie, peername)); + *peername_p = peername; + peername = NULL; + } else { + DEBUGF(("nodename = %s, cookie = %s\n", + nodename, cookie)); + } + *nodename_p = nodename; + nodename = NULL; + *cookie_p = cookie; + cookie = NULL; + ret = 0; + cleanup: + ei_x_free(&x); + if (ptr != NULL) { + free(ptr); + } + if (nodename != NULL) { + free(nodename); + } + if (cookie != NULL) { + free(cookie); + } + if (peername != NULL) { + free(peername); + } + return ret; +} + +int get_message(int com_sock, ei_x_buff *buff, + char *atom_buff, erlang_pid *pid, int *iterations) +{ + ei_x_buff buffer; + int ret_val,index; + erlang_msg msg; + int res = -1; + int totlen; + int type; + int size; + int version; + long tmp; + + ei_x_new(&buffer); + + for (;;) { + /* Reset buffer index before reading */ + buffer.index = 0; + /* Receive message */ + if ((ret_val = ei_xreceive_msg(com_sock, &msg, &buffer)) == + ERL_TICK) { + /* Ticks are automatically answered, just continue */ + continue; + } else if (ret_val != ERL_MSG) { + DEBUGF(("Peer has closed, ret_val = %d (%d).\n", + ret_val,erl_errno)); + goto cleanup; + } + switch (msg.msgtype) { + case ERL_SEND: + case ERL_REG_SEND: + index = 0; + ei_decode_version(buffer.buff,&index,&version); + DEBUGF(("Peer sent the following message to me: ")); +#ifdef DEBUG + { + int ndx = index; + /*in debug log on Unix*/ + ei_print_term(debugfile, buffer.buff, &ndx); + } +#endif + DEBUGF(("\n")); + if (ei_get_type(buffer.buff,&index,&type,&size) != 0) { + DEBUGF(("Failure at line %d\n",__LINE__)); + goto cleanup; + } + if (type != ERL_SMALL_TUPLE_EXT || size != 3) { + DEBUGF(("Failure at line %d, type=%d, size = %d\n",__LINE__, + type,size)); + goto cleanup; + } + if (ei_decode_tuple_header(buffer.buff,&index,&size) != 0 || + size != 3) { + DEBUGF(("Failure at line %d\n",__LINE__)); + goto cleanup; + } + if (ei_get_type(buffer.buff,&index,&type,&size) != 0) { + DEBUGF(("Failure at line %d\n",__LINE__)); + goto cleanup; + } + if (type == ERL_ATOM_EXT) { + ei_decode_atom(buffer.buff,&index,atom_buff); + atom_buff[size] ='\0'; + res = 2; + } else if (type == ERL_PID_EXT) { + ei_decode_pid(buffer.buff,&index,pid); + res = 1; + } else { + DEBUGF(("Failure at line %d\n",__LINE__)); + goto cleanup; + } + if (ei_get_type(buffer.buff,&index,&type,&size) != 0) { + DEBUGF(("Failure at line %d\n",__LINE__)); + goto cleanup; + } + switch (type) { + case ERL_SMALL_INTEGER_EXT: + case ERL_INTEGER_EXT: + ei_decode_long(buffer.buff,&index,&tmp); + break; + default: + DEBUGF(("Failure at line %d\n",__LINE__)); + goto cleanup; + } + + *iterations = (int)tmp; + + totlen = buffer.index - index; + ei_x_append_buf(buff,buffer.buff+index,totlen); + goto cleanup; + default: + DEBUGF(("Unexpected message type from peer. Goodbye.\n")); + goto cleanup; + } + } + + cleanup: + ei_x_free(&buffer); + return res; +} +TESTCASE(recv_tmo) +{ + char *nodename = NULL; + char *cookie = NULL; + char *peername = NULL; + int com_sock = -1; + ei_cnode nodeinfo; + + + OPEN_DEBUGFILE(5); + + if (decode_request(&nodename,&cookie,&peername) != 0) { + goto cleanup; + } + if (ei_connect_init(&nodeinfo, nodename, cookie, 0) < 0) { + DEBUGF(("Failure at line %d\n",__LINE__)); + goto cleanup; + } + + if ((com_sock = ei_connect_tmo(&nodeinfo, peername, 5000)) < 0) { + ei_x_buff answer; + DEBUGF(("Got error while connecting.{%d,%d}\n",com_sock,erl_errno)); + ei_x_new(&answer); + ei_x_format(&answer,"{~i,~i,~i}",com_sock,erl_errno,ETIMEDOUT); +#ifdef DEBUG + { + int tlen = 0; + int v; + ei_decode_version(answer.buff,&tlen,&v); + ei_print_term(debugfile,answer.buff,&tlen); + DEBUGF(("\n")); + } +#endif + send_bin_term(&answer); + DEBUGF(("Binary term sent.\n")); + ei_x_free(&answer); + } else { + ei_x_buff answer; + int ret_val; + ei_x_buff buffer; + erlang_msg msg; + int index,version; + + DEBUGF(("Success when connecting.{%d,%d}\n",com_sock,erl_errno)); + ei_x_new(&answer); + ei_x_format(&answer,"~i",com_sock); + send_bin_term(&answer); + ei_x_free(&answer); + ei_x_new(&buffer); + + for (;;) { + /* Reset buffer index before reading */ + buffer.index = 0; + /* Receive message */ + if ((ret_val = ei_xreceive_msg_tmo(com_sock, &msg, &buffer,5000)) + == ERL_TICK) { + /* Ticks are automatically answered, just continue */ + continue; + } else if (ret_val != ERL_MSG) { + ei_x_new(&answer); + ei_x_format(&answer,"{~i,~i,~i}",ret_val,erl_errno,ETIMEDOUT); + send_bin_term(&answer); + ei_x_free(&answer); + ei_x_free(&buffer); + DEBUGF(("Got error receiving, sending {%d,%d} and exiting\n", + ret_val,erl_errno)); + goto cleanup; + } + switch (msg.msgtype) { + case ERL_SEND: + case ERL_REG_SEND: + index = 0; + ei_decode_version(buffer.buff,&index,&version); + DEBUGF(("Peer sent the following message to me: ")); +#ifdef DEBUG + { + int ndx = index; + /*in debug log on Unix*/ + ei_print_term(debugfile, buffer.buff, &ndx); + } +#endif + DEBUGF(("\n")); + send_bin_term(&buffer); + ei_x_free(&buffer); + goto cleanup; + default: + DEBUGF(("Unexpected message type from peer. Goodbye.\n")); + goto cleanup; + + } + } + } +cleanup: + if (com_sock >= 0) { + closesocket(com_sock); + } + + if (nodename != NULL) { + free(nodename); + } + if (cookie != NULL) { + free(cookie); + } + if (peername != NULL) { + free(peername); + } + CLOSE_DEBUGFILE(); + report(1); +} + +TESTCASE(send_tmo) +{ + char *nodename = NULL; + char *cookie = NULL; + char *peername = NULL; + int com_sock = -1; + ei_cnode nodeinfo; + + + OPEN_DEBUGFILE(4); + + if (decode_request(&nodename,&cookie,&peername) != 0) { + goto cleanup; + } + if (ei_connect_init(&nodeinfo, nodename, cookie, 0) < 0) { + DEBUGF(("Failure at line %d\n",__LINE__)); + goto cleanup; + } + + if ((com_sock = ei_connect_tmo(&nodeinfo, peername, 5000)) < 0) { + ei_x_buff answer; + DEBUGF(("Got error while connecting.{%d,%d}\n",com_sock,erl_errno)); + ei_x_new(&answer); + ei_x_format(&answer,"{~i,~i,~i}",com_sock,erl_errno,ETIMEDOUT); +#ifdef DEBUG + { + int tlen = 0; + int v; + ei_decode_version(answer.buff,&tlen,&v); + ei_print_term(debugfile,answer.buff,&tlen); + DEBUGF(("\n")); + } +#endif + send_bin_term(&answer); + DEBUGF(("Binary term sent.\n")); + ei_x_free(&answer); + } else { + ei_x_buff answer; + char atom[256]; + erlang_pid pid; + int res, iterations, i; + ei_x_buff send_buffer; + + DEBUGF(("Success when connecting.{%d,%d}\n",com_sock,erl_errno)); + ei_x_new(&answer); + ei_x_format(&answer,"~i",com_sock); + send_bin_term(&answer); + ei_x_free(&answer); + ei_x_new_with_version(&send_buffer); + if ((res = get_message(com_sock, &send_buffer, + atom ,&pid, &iterations)) < 0) { + DEBUGF(("Get_message_failure at line %d\n",__LINE__)); + ei_x_free(&send_buffer); + goto cleanup; + } + DEBUGF(("Get_message success (%d), bindata:\n",res)); +#ifdef DEBUG + { + int ndx = 0; + int v; + ei_decode_version(send_buffer.buff,&ndx,&v); + ei_print_term(debugfile, send_buffer.buff, &ndx); + } +#endif + DEBUGF(("\n")); + switch (res) { + case 1: /* Send to pid in 'pid' */ + ei_x_new(&answer); + for (i=0;i < iterations; ++i) { + res = ei_send_tmo(com_sock, &pid, send_buffer.buff, + send_buffer.index, 5000); + DEBUGF(("Sent bindata (%d):\n",res)); +#ifdef DEBUG + { + int ndx = 0; + int v; + ei_decode_version(send_buffer.buff,&ndx,&v); + ei_print_term(debugfile, send_buffer.buff, &ndx); + } +#endif + DEBUGF(("\n")); + if (res < 0) + break; + } + if (res < 0) { + DEBUGF(("ei_send_tmo failure at line %d\n",__LINE__)); + ei_x_format(&answer,"{~i,~i,~i,~i}",res,erl_errno,i,ETIMEDOUT); + } else { + ei_x_format(&answer,"~i",res); + } + send_bin_term(&answer); + ei_x_free(&answer); + ei_x_free(&send_buffer); + goto cleanup; + case 2: /* Registered name in 'atom' */ + ei_x_new(&answer); + for (i=0;i < iterations; ++i) { + res = ei_reg_send_tmo(&nodeinfo, com_sock, atom, + send_buffer.buff, + send_buffer.index,5000); + if (res < 0) + break; + } + if (res < 0) { + DEBUGF(("ei_reg_send_tmo failure at line %d\n",__LINE__)); + ei_x_format(&answer,"{~i,~i,~i,~i}",res,erl_errno,i,ETIMEDOUT); + } else { + ei_x_format(&answer,"~i",res); + } + send_bin_term(&answer); + ei_x_free(&answer); + ei_x_free(&send_buffer); + goto cleanup; + default: + DEBUGF(("unexpected request number %d at line %d\n",res,__LINE__)); + ei_x_free(&send_buffer); + goto cleanup; + } + } +cleanup: + if (com_sock >= 0) { + closesocket(com_sock); + } + + if (nodename != NULL) { + free(nodename); + } + if (cookie != NULL) { + free(cookie); + } + if (peername != NULL) { + free(peername); + } + CLOSE_DEBUGFILE(); + report(1); +} + + +TESTCASE(connect_tmo) +{ + char *nodename = NULL; + char *cookie = NULL; + char *peername = NULL; + int com_sock = -1; + ei_cnode nodeinfo; + + + + OPEN_DEBUGFILE(3); + + if (decode_request(&nodename,&cookie,&peername) != 0) { + goto cleanup; + } + if (ei_connect_init(&nodeinfo, nodename, cookie, 0) < 0) { + DEBUGF(("Failure at line %d\n",__LINE__)); + goto cleanup; + } + + if ((com_sock = ei_connect_tmo(&nodeinfo, peername, 5000)) < 0) { + ei_x_buff answer; + DEBUGF(("Got error while connecting.{%d,%d}\n",com_sock,erl_errno)); + ei_x_new(&answer); + + /* On some systems errno gets set to EHOSTUNREACH rather than + ETIMEDOUT, which is ok. Let's check for that and report timeout + if it happens. + Max OS X seems to respond EHOSTDOWN, which should be ok. + */ + + +#if defined(EHOSTUNREACH) + if (errno == EHOSTUNREACH) + ei_x_format(&answer,"{~i,~i,~i}",com_sock,ETIMEDOUT,ETIMEDOUT); + else +#endif + +#if defined(EHOSTDOWN) + if (errno == EHOSTDOWN) + ei_x_format(&answer,"{~i,~i,~i}",com_sock,ETIMEDOUT,ETIMEDOUT); + else +#endif + + ei_x_format(&answer,"{~i,~i,~i}",com_sock,erl_errno,ETIMEDOUT); + +#ifdef DEBUG + { + int tlen = 0; + int v; + ei_decode_version(answer.buff,&tlen,&v); + ei_print_term(debugfile,answer.buff,&tlen); + DEBUGF(("\n")); + } +#endif + send_bin_term(&answer); + DEBUGF(("Binary term sent.\n")); + ei_x_free(&answer); + } else { + ei_x_buff answer; + DEBUGF(("Success when connecting.{%d,%d}\n",com_sock,erl_errno)); + ei_x_new(&answer); + ei_x_format(&answer,"~i",com_sock); + send_bin_term(&answer); + ei_x_free(&answer); + } + +cleanup: + if (com_sock >= 0) { + closesocket(com_sock); + } + + if (nodename != NULL) { + free(nodename); + } + if (cookie != NULL) { + free(cookie); + } + if (peername != NULL) { + free(peername); + } + CLOSE_DEBUGFILE(); + report(1); +} + +TESTCASE(accept_tmo) +{ + char *nodename = NULL; + char *cookie = NULL; + int listen_sock = -1; + int epmd_sock = -1; + int com_sock = -1; + struct sockaddr_in sin; + int sin_siz = sizeof(sin); + ErlConnect peer; + ei_cnode nodeinfo; + + + + OPEN_DEBUGFILE(2); + + putenv("EI_TRACELEVEL=10"); + + if (decode_request(&nodename,&cookie,NULL) != 0) { + goto cleanup; + } + if (ei_connect_init(&nodeinfo, nodename, cookie, 0) < 0) { + DEBUGF(("Failure at line %d\n",__LINE__)); + goto cleanup; + } + + if ((listen_sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + DEBUGF(("Failure at line %d\n",__LINE__)); + goto cleanup; + } + memset(&sin, 0, sizeof(sin)); + sin.sin_family = AF_INET; + sin.sin_addr.s_addr = INADDR_ANY; + + if (bind(listen_sock,(struct sockaddr *) &sin, sizeof(sin)) != 0) { + DEBUGF(("Failure at line %d\n",__LINE__)); + goto cleanup; + } + if (getsockname(listen_sock, + (struct sockaddr *) &sin, &sin_siz) != 0) { + DEBUGF(("Failure at line %d\n",__LINE__)); + goto cleanup; + } + if (listen(listen_sock, 5) != 0) { + DEBUGF(("Failure at line %d\n",__LINE__)); + goto cleanup; + } + + if ((epmd_sock = ei_publish(&nodeinfo, ntohs(sin.sin_port))) < 0) { + DEBUGF(("Failure at line %d[%d,%d]\n",__LINE__,sin.sin_port,erl_errno)); + goto cleanup; + } + + if ((com_sock = ei_accept_tmo(&nodeinfo, + listen_sock, &peer, 5000)) == ERL_ERROR) { + ei_x_buff answer; + DEBUGF(("Got error while accepting.{%d,%d}\n",com_sock,erl_errno)); + ei_x_new(&answer); + ei_x_format(&answer,"{~i,~i,~i}",com_sock,erl_errno,ETIMEDOUT); +#ifdef DEBUG + { + int tlen = 0; + int v; + ei_decode_version(answer.buff,&tlen,&v); + ei_print_term(debugfile,answer.buff,&tlen); + DEBUGF(("\n")); + } +#endif + send_bin_term(&answer); + DEBUGF(("Binary term sent.\n")); + ei_x_free(&answer); + } else { + ei_x_buff answer; + DEBUGF(("Success when connecting.{%d,%d}\n",com_sock,erl_errno)); + ei_x_new(&answer); + ei_x_format(&answer,"~i",com_sock); + send_bin_term(&answer); + ei_x_free(&answer); + } + +cleanup: + + if (listen_sock >= 0) { + closesocket(listen_sock); + } + if (epmd_sock >= 0) { + closesocket(epmd_sock); + } + if (com_sock >= 0) { + closesocket(com_sock); + } + + if (nodename != NULL) { + free(nodename); + } + if (cookie != NULL) { + free(cookie); + } + CLOSE_DEBUGFILE(); + report(1); +} + diff --git a/lib/erl_interface/test/erl_connect_SUITE.erl b/lib/erl_interface/test/erl_connect_SUITE.erl new file mode 100644 index 0000000000..0d6539d98f --- /dev/null +++ b/lib/erl_interface/test/erl_connect_SUITE.erl @@ -0,0 +1,134 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2000-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +-module(erl_connect_SUITE). + +-include("test_server.hrl"). +-include("erl_connect_SUITE_data/erl_connect_test_cases.hrl"). + +-export([all/1,init_per_testcase/2,fin_per_testcase/2, + erl_send/1,erl_reg_send/1, erl_send_cookie_file/1]). + +-import(runner, [get_term/1,send_term/2]). + +all(suite) -> + [erl_send,erl_reg_send,erl_send_cookie_file]. + +init_per_testcase(_Case, Config) -> + Dog = ?t:timetrap(?t:minutes(0.25)), + [{watchdog, Dog}|Config]. + +fin_per_testcase(_Case, Config) -> + Dog = ?config(watchdog, Config), + test_server:timetrap_cancel(Dog), + ok. + +erl_send(Config) when is_list(Config) -> + ?line P = runner:start(?interpret), + ?line 1 = erl_connect_init(P, 42, erlang:get_cookie(), 0), + ?line {ok,Fd} = erl_connect(P, node()), + + ?line ok = erl_send(P, Fd, self(), AMsg={a,message}), + ?line receive AMsg -> ok end, + + ?line 0 = erl_close_connection(P,Fd), + ?line runner:send_eot(P), + ?line runner:recv_eot(P), + ok. + +erl_send_cookie_file(Config) when is_list(Config) -> + case os:type() of + vxworks -> + {skip,"Skipped on VxWorks"}; + _ -> + ?line P = runner:start(?interpret), + ?line 1 = erl_connect_init(P, 42, '', 0), + ?line {ok,Fd} = erl_connect(P, node()), + + ?line ok = erl_send(P, Fd, self(), AMsg={a,message}), + ?line receive AMsg -> ok end, + + ?line 0 = erl_close_connection(P,Fd), + ?line runner:send_eot(P), + ?line runner:recv_eot(P), + ok + end. + +erl_reg_send(Config) when is_list(Config) -> + ?line P = runner:start(?interpret), + ?line 1 = erl_connect_init(P, 42, erlang:get_cookie(), 0), + ?line {ok,Fd} = erl_connect(P, node()), + + ARegName = a_strange_registred_name, + ?line register(ARegName, self()), + ?line ok = erl_reg_send(P, Fd, ARegName, AMsg={another,[strange],message}), + ?line receive AMsg -> ok end, + + ?line 0 = erl_close_connection(P,Fd), + ?line runner:send_eot(P), + ?line runner:recv_eot(P), + ok. + + +%%% Interface functions for erl_interface functions. + +erl_connect_init(P, Num, Cookie, Creation) -> + send_command(P, erl_connect_init, [Num,Cookie,Creation]), + case get_term(P) of + {term,Int} when is_integer(Int) -> Int + end. + +erl_connect(P, Node) -> + send_command(P, erl_connect, [Node]), + case get_term(P) of + {term,{Fd,_}} when Fd >= 0 -> {ok,Fd}; + {term,{-1,Errno}} -> {error,Errno} + end. + +erl_close_connection(P, FD) -> + send_command(P, erl_close_connection, [FD]), + case get_term(P) of + {term,Int} when is_integer(Int) -> Int + end. + +erl_send(P, Fd, To, Msg) -> + send_command(P, erl_send, [Fd,To,Msg]), + get_send_result(P). + +erl_reg_send(P, Fd, To, Msg) -> + send_command(P, erl_reg_send, [Fd,To,Msg]), + get_send_result(P). + +get_send_result(P) -> + case get_term(P) of + {term,{1,_}} -> ok; + {term,{-1,Errno}} -> {error,Errno}; + {term,{Res,Errno}}-> + io:format("Return value: ~p\nerl_errno: ~p", [Res,Errno]), + ?t:fail(bad_return_value) + end. + +send_command(P, Name, Args) -> + runner:send_term(P, {Name,list_to_tuple(Args)}). + + + + + diff --git a/lib/erl_interface/test/erl_connect_SUITE_data/Makefile.first b/lib/erl_interface/test/erl_connect_SUITE_data/Makefile.first new file mode 100644 index 0000000000..09c00e7b8c --- /dev/null +++ b/lib/erl_interface/test/erl_connect_SUITE_data/Makefile.first @@ -0,0 +1,21 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2001-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# + +erl_connect_test_decl.c: erl_connect_test.c + erl -noinput -pa ../all_SUITE_data -s init_tc run erl_connect_test -s erlang halt diff --git a/lib/erl_interface/test/erl_connect_SUITE_data/Makefile.src b/lib/erl_interface/test/erl_connect_SUITE_data/Makefile.src new file mode 100644 index 0000000000..047a734ecb --- /dev/null +++ b/lib/erl_interface/test/erl_connect_SUITE_data/Makefile.src @@ -0,0 +1,41 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2000-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# + +include @erl_interface_mk_include@@[email protected] + +CC0 = @CC@ +CC = ..@DS@all_SUITE_data@DS@gccifier@exe@ -CC"$(CC0)" +LD = @LD@ +LIBPATH = @erl_interface_libpath@ +LIBERL = $(LIBPATH)/@erl_interface_lib@ +LIBEI = $(LIBPATH)/@erl_interface_eilib@ +LIBFLAGS = ../all_SUITE_data/runner@obj@ \ + $(LIBERL) $(LIBEI) @LIBS@ @erl_interface_sock_libs@ \ + @erl_interface_threadlib@ +CFLAGS = @EI_CFLAGS@ $(THR_DEFS) -I@erl_interface_include@ -I../all_SUITE_data +OBJS = erl_connect_test@obj@ erl_connect_test_decl@obj@ + +all: erl_connect_test@exe@ + +erl_connect_test@exe@: $(OBJS) $(LIBERL) $(LIBEI) + $(LD) @CROSSLDFLAGS@ -o $@ $(OBJS) $(LIBFLAGS) + +clean: + $(RM) $(OBJS) + $(RM) erl_connect_test@exe@ diff --git a/lib/erl_interface/test/erl_connect_SUITE_data/erl_connect_test.c b/lib/erl_interface/test/erl_connect_SUITE_data/erl_connect_test.c new file mode 100644 index 0000000000..02304260b8 --- /dev/null +++ b/lib/erl_interface/test/erl_connect_SUITE_data/erl_connect_test.c @@ -0,0 +1,202 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2000-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ + +/* + * Purpose: Tests the functions in erl_connect.c. + * Author: Bjorn Gustavsson + * + * See the erl_connect_SUITE.erl file for a "table of contents". + */ + +#include <stdio.h> +#include <string.h> + +#include "runner.h" + +static void cmd_erl_connect_init(ETERM* args); +static void cmd_erl_connect(ETERM* args); +static void cmd_erl_send(ETERM* args); +static void cmd_erl_reg_send(ETERM* args); +static void cmd_erl_close_connection(ETERM *args); + +static void send_errno_result(int value); + +static struct { + char* name; + int num_args; /* Number of arguments. */ + void (*func)(ETERM* args); +} commands[] = { + "erl_connect_init", 3, cmd_erl_connect_init, + "erl_connect", 1, cmd_erl_connect, + "erl_close_connection", 1, cmd_erl_close_connection, + "erl_send", 3, cmd_erl_send, + "erl_reg_send", 3, cmd_erl_reg_send, +}; + + +/* + * Sends a list contaning all data types to the Erlang side. + */ + +TESTCASE(interpret) +{ + ETERM* term; + + erl_init(NULL, 0); + + outer_loop: + + term = get_term(); + + if (term == NULL) { + report(1); + return; + } else { + ETERM* Func; + ETERM* Args; + int i; + + if (!ERL_IS_TUPLE(term) || ERL_TUPLE_SIZE(term) != 2) { + fail("term should be a tuple of size 2"); + } + + Func = erl_element(1, term); + if (!ERL_IS_ATOM(Func)) { + fail("function name should be an atom"); + } + Args = erl_element(2, term); + if (!ERL_IS_TUPLE(Args)) { + fail("function arguments should be a tuple"); + } + erl_free_term(term); + for (i = 0; i < sizeof(commands)/sizeof(commands[0]); i++) { + int n = strlen(commands[i].name); + if (ERL_ATOM_SIZE(Func) != n) { + continue; + } + if (memcmp(ERL_ATOM_PTR(Func), commands[i].name, n) == 0) { + erl_free_term(Func); + if (ERL_TUPLE_SIZE(Args) != commands[i].num_args) { + fail("wrong number of arguments"); + } + commands[i].func(Args); + erl_free_term(Args); + goto outer_loop; + } + } + fail("bad command"); + } +} + +#define VERIFY_TYPE(Test, Term) \ +if (!Test(Term)) { \ + fail("wrong type for " #Term); \ +} else { \ +} + +static void +cmd_erl_connect_init(ETERM* args) +{ + ETERM* number; + ETERM* res; + ETERM* cookie; + char cookie_buffer[256]; + + number = ERL_TUPLE_ELEMENT(args, 0); + VERIFY_TYPE(ERL_IS_INTEGER, number); + cookie = ERL_TUPLE_ELEMENT(args, 1); + VERIFY_TYPE(ERL_IS_ATOM, cookie); + if (ERL_ATOM_SIZE(cookie) == 0) { + res = erl_mk_int(erl_connect_init(ERL_INT_VALUE(number), 0, 0)); + } else { + memcpy(cookie_buffer, ERL_ATOM_PTR(cookie), ERL_ATOM_SIZE(cookie)); + cookie_buffer[ERL_ATOM_SIZE(cookie)] = '\0'; + res = erl_mk_int(erl_connect_init(ERL_INT_VALUE(number), + cookie_buffer, 0)); + } + send_term(res); + erl_free_term(res); +} + +static void +cmd_erl_connect(ETERM* args) +{ + ETERM* node; + char node_buffer[256]; + + node = ERL_TUPLE_ELEMENT(args, 0); + VERIFY_TYPE(ERL_IS_ATOM, node); + memcpy(node_buffer, ERL_ATOM_PTR(node), ERL_ATOM_SIZE(node)); + node_buffer[ERL_ATOM_SIZE(node)] = '\0'; + send_errno_result(erl_connect(node_buffer)); +} + +static void +cmd_erl_close_connection(ETERM* args) +{ + ETERM* number; + ETERM* res; + + number = ERL_TUPLE_ELEMENT(args, 0); + VERIFY_TYPE(ERL_IS_INTEGER, number); + res = erl_mk_int(erl_close_connection(ERL_INT_VALUE(number))); + send_term(res); + erl_free_term(res); +} + +static void +cmd_erl_send(ETERM* args) +{ + ETERM* fd_term = ERL_TUPLE_ELEMENT(args, 0); + ETERM* to = ERL_TUPLE_ELEMENT(args, 1); + ETERM* msg = ERL_TUPLE_ELEMENT(args, 2); + + VERIFY_TYPE(ERL_IS_INTEGER, fd_term); + send_errno_result(erl_send(ERL_INT_VALUE(fd_term), to, msg)); +} + +static void +cmd_erl_reg_send(ETERM* args) +{ + ETERM* fd_term = ERL_TUPLE_ELEMENT(args, 0); + ETERM* to = ERL_TUPLE_ELEMENT(args, 1); + ETERM* msg = ERL_TUPLE_ELEMENT(args, 2); + char reg_name[256]; + + VERIFY_TYPE(ERL_IS_INTEGER, fd_term); + VERIFY_TYPE(ERL_IS_ATOM, to); + memcpy(reg_name, ERL_ATOM_PTR(to), ERL_ATOM_SIZE(to)); + reg_name[ERL_ATOM_SIZE(to)] = '\0'; + send_errno_result(erl_reg_send(ERL_INT_VALUE(fd_term), reg_name, msg)); +} + +static void +send_errno_result(int value) +{ + ETERM* res_array[2]; + ETERM* res_tuple; + + res_array[0] = erl_mk_int(value); + res_array[1] = erl_mk_int(erl_errno); + res_tuple = erl_mk_tuple(res_array, 2); + send_term(res_tuple); + erl_free_term(res_array[0]); + erl_free_term(res_array[1]); + erl_free_term(res_tuple); +} diff --git a/lib/erl_interface/test/erl_eterm_SUITE.erl b/lib/erl_interface/test/erl_eterm_SUITE.erl new file mode 100644 index 0000000000..634e2f9aa0 --- /dev/null +++ b/lib/erl_interface/test/erl_eterm_SUITE.erl @@ -0,0 +1,1136 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1997-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +-module(erl_eterm_SUITE). + +-include("test_server.hrl"). +-include("erl_eterm_SUITE_data/eterm_test_cases.hrl"). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%% The tests are organised as follows: +%%% +%%% 1. Basic tests (encoding, decoding, memory allocation). +%%% 2. Constructing terms (the erl_mk_xxx() functions and erl_copy_term()). +%%% 3. Extracting & info functions (erl_hd(), erl_length() etc). +%%% 4. I/O list functions. +%%% 5. Miscellanous functions. +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +-export([all/1, build_terms/1, round_trip_conversion/1, + decode_terms/1, decode_float/1, + t_erl_mk_int/1, t_erl_mk_list/1, + basic_copy/1, + t_erl_cons/1, + t_erl_mk_atom/1, + t_erl_mk_binary/1, + t_erl_mk_empty_list/1, + t_erl_mk_float/1, + t_erl_mk_pid/1, + t_erl_mk_xpid/1, + t_erl_mk_port/1, + t_erl_mk_xport/1, + t_erl_mk_ref/1, + t_erl_mk_long_ref/1, + t_erl_mk_string/1, + t_erl_mk_estring/1, + t_erl_mk_tuple/1, + t_erl_mk_uint/1, + t_erl_mk_var/1, + t_erl_size/1, + t_erl_var_content/1, + t_erl_element/1, + t_erl_length/1, t_erl_hd/1, t_erl_tl/1, + type_checks/1, extractor_macros/1, + t_erl_iolist_length/1, t_erl_iolist_to_binary/1, + t_erl_iolist_to_string/1, + erl_print_term/1, print_string/1, + t_erl_free_compound/1, + high_chaparal/1, + broken_data/1, + cnode_1/1]). + +-export([start_cnode/1]). + +-import(runner, [get_term/1]). + +%% This test suite controls the running of the C language functions +%% in eterm_test.c and print_term.c. + +all(suite) -> [build_terms, round_trip_conversion, + decode_terms, decode_float, + t_erl_mk_int, t_erl_mk_list, + basic_copy, + t_erl_mk_atom, + t_erl_mk_binary, + t_erl_mk_empty_list, + t_erl_mk_float, + t_erl_mk_pid, + t_erl_mk_xpid, + t_erl_mk_port, + t_erl_mk_xport, + t_erl_mk_ref, + t_erl_mk_long_ref, + t_erl_mk_string, + t_erl_mk_estring, + t_erl_mk_tuple, + t_erl_mk_uint, + t_erl_mk_var, + t_erl_size, + t_erl_var_content, + t_erl_element, + t_erl_cons, + t_erl_length, t_erl_hd, t_erl_tl, + type_checks, extractor_macros, + t_erl_iolist_length, t_erl_iolist_to_binary, + t_erl_iolist_to_string, + erl_print_term, print_string, + t_erl_free_compound, + high_chaparal, + broken_data, + cnode_1]. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%% +%%% 1. B a s i c t e s t s +%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%% This test asks the C function to construct all data types in +%% a list and verifies that the result is as expected. + +build_terms(suite) -> []; +build_terms(Config) when is_list(Config) -> + ?line P = runner:start(?build_terms), + ?line {term, Term} = get_term(P), + ?line io:format("Received: ~p", [Term]), + ?line [ARefLN, ARef, APortLN, APort, APidLN, APid, + {element1, 42, 767}, "A string", + 1, -1, 0, 3.0, ABin, 'I am an atom'] = Term, + ?line "A binary" = binary_to_list(ABin), + ?line case ARef of + R when is_reference(R), node(R) == kalle@localhost -> ok + end, + ?line case ARefLN of + R1 when is_reference(R1), node(R1) == abcdefghijabcdefghij@localhost -> ok + end, + ?line case APort of + Port when is_port(Port), node(Port) == kalle@localhost -> ok + end, + ?line case APortLN of + Port1 when is_port(Port1), node(Port1) == abcdefghijabcdefghij@localhost -> ok + end, + ?line case APid of + Pid when is_pid(Pid), node(Pid) == kalle@localhost -> ok + end, + ?line case APidLN of + Pid1 when is_pid(Pid1), node(Pid1) == abcdefghijabcdefghij@localhost -> ok + end, + + ?line runner:recv_eot(P), + ok. + +%% This test is run entirely in C code. + +round_trip_conversion(suite) -> []; +round_trip_conversion(Config) when is_list(Config) -> + ?line runner:test(?round_trip_conversion), + ok. + +%% This test sends a list of all data types to the C code function, +%% which decodes it and verifies it. + +decode_terms(suite) -> []; +decode_terms(Config) when is_list(Config) -> + ?line Dummy1 = list_to_atom(filename:join(?config(priv_dir, Config), + dummy_file1)), + ?line Dummy2 = list_to_atom(filename:join(?config(priv_dir, Config), + dummy_file2)), + ?line Port1 = open_port(Dummy1, [out]), + ?line Port2 = open_port(Dummy2, [out]), + ?line ABinary = list_to_binary("A binary"), + ?line Terms = [make_ref(), make_ref(), + Port1, Port2, + self(), self(), + {element1, 42, 767}, "A string", + 1, -1, 0, 3.0, ABinary, 'I am an atom'], + + ?line P = runner:start(?decode_terms), + ?line runner:send_term(P, Terms), + ?line runner:recv_eot(P), + + ok. + +%% Decodes the floating point number 3.1415. + +decode_float(suite) -> []; +decode_float(Config) when is_list(Config) -> + ?line P = runner:start(?decode_float), + ?line runner:send_term(P, 3.1415), + ?line runner:recv_eot(P), + ok. + +%% Tests the erl_free_compound() function. + +t_erl_free_compound(suite) -> []; +t_erl_free_compound(Config) when is_list(Config) -> + ?line runner:test(?t_erl_free_compound), + ok. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%% +%%% 2. C o n s t r u c t i n g t e r m s +%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%% This tests the erl_mk_list() function. + +t_erl_mk_list(suite) -> []; +t_erl_mk_list(Config) when is_list(Config) -> + ?line P = runner:start(?t_erl_mk_list), + + ?line {term, []} = get_term(P), + ?line {term, [abc]} = get_term(P), + ?line {term, [abcdef, 42]} = get_term(P), + ?line {term, [0.0, 23, [], 3.1415]} = get_term(P), + + ?line runner:recv_eot(P), + ok. + + +%% This tests the erl_mk_int() function. + +t_erl_mk_int(suite) -> []; +t_erl_mk_int(Config) when is_list(Config) -> + ?line P = runner:start(?t_erl_mk_int), + + ?line {term, 0} = get_term(P), + ?line {term, 127} = get_term(P), + ?line {term, 128} = get_term(P), + ?line {term, 255} = get_term(P), + ?line {term, 256} = get_term(P), + + ?line {term, 16#FFFF} = get_term(P), + ?line {term, 16#10000} = get_term(P), + + ?line {term, 16#07FFFFFF} = get_term(P), + ?line {term, 16#0FFFFFFF} = get_term(P), + ?line {term, 16#1FFFFFFF} = get_term(P), + ?line {term, 16#3FFFFFFF} = get_term(P), + ?line {term, 16#7FFFFFFF} = get_term(P), + + ?line {term, 16#08000000} = get_term(P), + ?line {term, 16#10000000} = get_term(P), + ?line {term, 16#20000000} = get_term(P), + ?line {term, 16#40000000} = get_term(P), + + + ?line {term, -16#07FFFFFF} = get_term(P), + ?line {term, -16#0FFFFFFF} = get_term(P), + ?line {term, -16#1FFFFFFF} = get_term(P), + ?line {term, -16#3FFFFFFF} = get_term(P), + ?line {term, -16#7FFFFFFF} = get_term(P), + + ?line {term, -16#08000000} = get_term(P), + ?line {term, -16#10000000} = get_term(P), + ?line {term, -16#20000000} = get_term(P), + ?line {term, -16#40000000} = get_term(P), + + ?line {term, -16#08000001} = get_term(P), + ?line {term, -16#10000001} = get_term(P), + ?line {term, -16#20000001} = get_term(P), + ?line {term, -16#40000001} = get_term(P), + + ?line {term, -16#08000002} = get_term(P), + ?line {term, -16#10000002} = get_term(P), + ?line {term, -16#20000002} = get_term(P), + ?line {term, -16#40000002} = get_term(P), + + ?line {term, -1999999999} = get_term(P), + ?line {term, -2000000000} = get_term(P), + ?line {term, -2000000001} = get_term(P), + + ?line runner:recv_eot(P), + ok. + + +%% Basic test of erl_copy_term(). + +basic_copy(suite) -> []; +basic_copy(Config) when is_list(Config) -> + ?line runner:test(?basic_copy), + ok. + + +%% This tests the erl_mk_tuple() function. + +t_erl_mk_tuple(suite) -> []; +t_erl_mk_tuple(Config) when is_list(Config) -> + ?line P = runner:start(?t_erl_mk_tuple), + + ?line {term, {madonna, 21, 'mad donna', 12}} = get_term(P), + ?line {term, {'Madonna',21,{children,{"Isabella",2}}, + {'home page',"http://www.madonna.com/"}}} = get_term(P), + + ?line runner:recv_eot(P), + ok. + + +%% This tests the erl_mk_atom() function. + +t_erl_mk_atom(suite) -> []; +t_erl_mk_atom(Config) when is_list(Config) -> + ?line P = runner:start(?t_erl_mk_atom), + + ?line {term, madonna} = (get_term(P)), + ?line {term, 'Madonna'} = (get_term(P)), + ?line {term, 'mad donna'} = (get_term(P)), + ?line {term, '_madonna_'} = (get_term(P)), + ?line {term, '/home/madonna/tour_plan'} = (get_term(P)), + ?line {term, 'http://www.madonna.com/tour_plan'} = (get_term(P)), + ?line {term, '\'madonna\''} = (get_term(P)), + ?line {term, '\"madonna\"'} = (get_term(P)), + ?line {term, '\\madonna\\'} = (get_term(P)), + ?line {term, '{madonna,21,\'mad donna\',12}'} = (get_term(P)), + + ?line runner:recv_eot(P), + ok. + + +%% This tests the erl_mk_binary() function. + +t_erl_mk_binary(suite) -> []; +t_erl_mk_binary(Config) when is_list(Config) -> + ?line P = runner:start(?t_erl_mk_binary), + + ?line {term, Bin} = (get_term(P)), + ?line "{madonna,21,'mad donna',1234.567.890, !#$%&/()=?+-@, \" \\}" = + binary_to_list(Bin), + + ?line runner:recv_eot(P), + ok. + + +%% This tests the erl_mk_empty_list() function. + +t_erl_mk_empty_list(suite) -> []; +t_erl_mk_empty_list(Config) when is_list(Config) -> + ?line P = runner:start(?t_erl_mk_empty_list), + + ?line {term, []} = get_term(P), + + ?line runner:recv_eot(P), + ok. + + +%% This tests the erl_mk_float() function. + +t_erl_mk_float(suite) -> []; +t_erl_mk_float(Config) when is_list(Config) -> + case os:type() of + vxworks -> + {skipped, "Floating point numbers never compare equal on PPC"}; + _ -> + ?line P = runner:start(?t_erl_mk_float), + ?line {term, {3.1415, 1.999999, 2.000000, 2.000001, + 2.000002, 12345.67890}} = + get_term(P), + ?line runner:recv_eot(P), + ok + end. + + +%% This tests the erl_mk_pid() function. + +t_erl_mk_pid(suite) -> []; +t_erl_mk_pid(Config) when is_list(Config) -> + ?line P = runner:start(?t_erl_mk_pid), + + ?line {term, A_pid} = (get_term(P)), + ?line {pid, kalle@localhost, 3, 2} = nc2vinfo(A_pid), + + ?line runner:recv_eot(P), + ok. + +t_erl_mk_xpid(suite) -> []; +t_erl_mk_xpid(Config) when is_list(Config) -> + ?line P = runner:start(?t_erl_mk_xpid), + + ?line {term, A_pid} = (get_term(P)), + ?line {pid, kalle@localhost, 32767, 8191} = nc2vinfo(A_pid), + + ?line runner:recv_eot(P), + ok. + + +%% This tests the erl_mk_port() function. + +t_erl_mk_port(suite) -> []; +t_erl_mk_port(Config) when is_list(Config) -> + ?line P = runner:start(?t_erl_mk_port), + + ?line {term, A_port} = (get_term(P)), + ?line {port, kalle@localhost, 4} = nc2vinfo(A_port), + + ?line runner:recv_eot(P), + ok. + +t_erl_mk_xport(suite) -> []; +t_erl_mk_xport(Config) when is_list(Config) -> + ?line P = runner:start(?t_erl_mk_xport), + + ?line {term, A_port} = (get_term(P)), + ?line {port, kalle@localhost, 268435455} = nc2vinfo(A_port), + + ?line runner:recv_eot(P), + ok. + + +%% This tests the erl_mk_ref() function. + +t_erl_mk_ref(suite) -> []; +t_erl_mk_ref(Config) when is_list(Config) -> + ?line P = runner:start(?t_erl_mk_ref), + + ?line {term, A_ref} = (get_term(P)), + ?line {ref, kalle@localhost, _Length, [6]} = nc2vinfo(A_ref), + + ?line runner:recv_eot(P), + ok. + +t_erl_mk_long_ref(suite) -> []; +t_erl_mk_long_ref(Config) when is_list(Config) -> + ?line P = runner:start(?t_erl_mk_long_ref), + + ?line {term, A_ref} = (get_term(P)), + ?line {ref, kalle@localhost, _Length, [4294967295,4294967295,262143]} + = nc2vinfo(A_ref), + + ?line runner:recv_eot(P), + ok. + + +%% This tests the erl_mk_string() function. + +t_erl_mk_string(suite) -> []; +t_erl_mk_string(Config) when is_list(Config) -> + ?line P = runner:start(?t_erl_mk_string), + + ?line {term, "madonna"} = (get_term(P)), + ?line {term, "Madonna"} = (get_term(P)), + ?line {term, "mad donna"} = (get_term(P)), + ?line {term, "_madonna_"} = (get_term(P)), + ?line {term, "/home/madonna/tour_plan"} = (get_term(P)), + ?line {term, "http://www.madonna.com/tour_plan"} = (get_term(P)), + ?line {term, "\'madonna\'"} = (get_term(P)), + ?line {term, "\"madonna\""} = (get_term(P)), + ?line {term, "\\madonna\\"} = (get_term(P)), + ?line {term, "{madonna,21,'mad donna',12}"} = (get_term(P)), + + ?line runner:recv_eot(P), + ok. + + +%% This tests the erl_mk_estring() function. + +t_erl_mk_estring(suite) -> []; +t_erl_mk_estring(Config) when is_list(Config) -> + ?line P = runner:start(?t_erl_mk_estring), + + ?line {term, "madonna"} = (get_term(P)), + ?line {term, "Madonna"} = (get_term(P)), + ?line {term, "mad donna"} = (get_term(P)), + ?line {term, "_madonna_"} = (get_term(P)), + ?line {term, "/home/madonna/tour_plan"} = (get_term(P)), + ?line {term, "http://www.madonna.com/tour_plan"} = (get_term(P)), + ?line {term, "\'madonna\'"} = (get_term(P)), + ?line {term, "\"madonna\""} = (get_term(P)), + ?line {term, "\\madonna\\"} = (get_term(P)), + ?line {term, "{madonna,21,'mad donna',12}"} = (get_term(P)), + + ?line runner:recv_eot(P), + ok. + + +%% This tests the erl_mk_uint() function. + +t_erl_mk_uint(suite) -> []; +t_erl_mk_uint(Config) when is_list(Config) -> + ?line P = runner:start(?t_erl_mk_uint), + + ?line {term, 54321} = (get_term(P)), + ?line {term, 2147483647} = (get_term(P)), + ?line {term, 2147483648} = (get_term(P)), + ?line {term, 2147483649} = (get_term(P)), + ?line {term, 2147483650} = (get_term(P)), + ?line {term, 4294967295} = (get_term(P)), + + ?line runner:recv_eot(P), + ok. + + +%% This tests the erl_mk_var() function. + +t_erl_mk_var(suite) -> []; +t_erl_mk_var(Config) when is_list(Config) -> + ?line P = runner:start(?t_erl_mk_var), + + ?line {term, 1} = (get_term(P)), + ?line {term, 0} = (get_term(P)), + ?line {term, 1} = (get_term(P)), + ?line {term, 0} = (get_term(P)), + ?line {term, 1} = (get_term(P)), + ?line {term, 0} = (get_term(P)), + ?line {term, 1} = (get_term(P)), + + ?line runner:recv_eot(P), + ok. + + +%% This tests the erl_cons() function. + +t_erl_cons(suite) -> []; +t_erl_cons(Config) when is_list(Config) -> + ?line P = runner:start(?t_erl_cons), + + ?line {term, [madonna, 21]} = get_term(P), + + ?line runner:recv_eot(P), + ok. + + + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%% +%%% 3. E x t r a c t i n g & i n f o f u n c t i o n s +%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%% Tests the erl_length() function. + +t_erl_length(suite) -> []; +t_erl_length(Config) when is_list(Config) -> + ?line P = runner:start(?t_erl_length), + + ?line 0 = erl_length(P, []), + ?line 1 = erl_length(P, [a]), + ?line 2 = erl_length(P, [a, b]), + ?line 3 = erl_length(P, [a, b, c]), + + ?line 4 = erl_length(P, [a, [x, y], c, []]), + + ?line -1 = erl_length(P, [a|b]), + ?line -1 = erl_length(P, a), + + ?line runner:finish(P), + ok. + +%% Invokes the erl_length() function. + +erl_length(Port, List) -> + call_erl_function(Port, List). + +%% Tests the erl_hd() function. + +t_erl_hd(suite) -> []; +t_erl_hd(Config) when is_list(Config) -> + ?line P = runner:start(?t_erl_hd), + + ?line 'NULL' = erl_hd(P, 42), + ?line 'NULL' = erl_hd(P, abc), + ?line 'NULL' = erl_hd(P, []), + + ?line [] = erl_hd(P, [[], a]), + ?line a = erl_hd(P, [a]), + ?line a = erl_hd(P, [a, b]), + ?line a = erl_hd(P, [a, b, c]), + ?line a = erl_hd(P, [a|b]), + + ?line runner:send_eot(P), + ?line runner:recv_eot(P), + ok. + +%% Invokes the erl_hd() function. + +erl_hd(Port, List) -> + call_erl_function(Port, List). + +%% Tests the erl_tail() function. + +t_erl_tl(suite) -> []; +t_erl_tl(Config) when is_list(Config) -> + ?line P = runner:start(?t_erl_tl), + + ?line 'NULL' = erl_tl(P, 42), + ?line 'NULL' = erl_tl(P, abc), + ?line 'NULL' = erl_tl(P, []), + + ?line [] = erl_tl(P, [a]), + ?line [b] = erl_tl(P, [a, b]), + ?line [b, c] = erl_tl(P, [a, b, c]), + + ?line b = erl_tl(P, [a|b]), + + ?line runner:send_eot(P), + ?line runner:recv_eot(P), + ok. + +%% Invokes the erl_tail() function in erl_interface. + +erl_tl(Port, List) -> + call_erl_function(Port, List). + +%% Tests the type checking macros (done in the C program). + +type_checks(suite) -> []; +type_checks(Config) when is_list(Config) -> + ?line runner:test(?type_checks), + ok. + +%% Tests the extractor macros (done in the C program). + +extractor_macros(suite) -> []; +extractor_macros(Config) when is_list(Config) -> + ?line runner:test(?extractor_macros), + ok. + + +%% This tests the erl_size() function. + +t_erl_size(suite) -> []; +t_erl_size(Config) when is_list(Config) -> + ?line P = runner:start(?t_erl_size), + + ?line {term, 0} = (get_term(P)), + ?line {term, 4} = (get_term(P)), + + ?line {term, 0} = (get_term(P)), + ?line {term, 27} = (get_term(P)), + + ?line runner:recv_eot(P), + ok. + + +%% This tests the erl_var_content() function. + +t_erl_var_content(suite) -> []; +t_erl_var_content(Config) when is_list(Config) -> + ?line P = runner:start(?t_erl_var_content), + + ?line {term, 17} = (get_term(P)), + ?line {term, "http://www.madonna.com"} = (get_term(P)), + ?line {term, 2} = (get_term(P)), + ?line {term, "http://www.madonna.com"} = (get_term(P)), + ?line {term, 2} = (get_term(P)), + + ?line runner:recv_eot(P), + ok. + + +%% This tests the erl_element() function. + +t_erl_element(suite) -> []; +t_erl_element(Config) when is_list(Config) -> + ?line P = runner:start(?t_erl_element), + + ?line {term, madonna} = get_term(P), + ?line {term, 21} = get_term(P), + ?line {term, 'mad donna'} = get_term(P), + ?line {term, 12} = get_term(P), + + ?line {term, 'Madonna'} = get_term(P), + ?line {term, 21} = get_term(P), + ?line {term, {children,{"Isabella",2}}} = get_term(P), + ?line {term, {'home page',"http://www.madonna.com/"}} = get_term(P), + + ?line runner:recv_eot(P), + ok. + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%% +%%% 4. I / O l i s t f u n c t i o n s +%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%% Tests the erl_iolist_length() function. + +t_erl_iolist_length(suite) -> []; +t_erl_iolist_length(Config) when is_list(Config) -> + ?line P = runner:start(?t_erl_iolist_length), + + %% Flat lists. + + ?line 0 = erl_iolist_length(P, []), + ?line 1 = erl_iolist_length(P, [10]), + ?line 2 = erl_iolist_length(P, [10, 20]), + ?line 3 = erl_iolist_length(P, [10, 20, 30]), + ?line 256 = erl_iolist_length(P, lists:seq(0, 255)), + + %% Deep lists. + + ?line 0 = erl_iolist_length(P, [[]]), + ?line 1 = erl_iolist_length(P, [[], 42]), + ?line 1 = erl_iolist_length(P, [42, []]), + ?line 2 = erl_iolist_length(P, [42, [], 45]), + + ?line 3 = erl_iolist_length(P, [42, [90], 45]), + ?line 3 = erl_iolist_length(P, [[42, [90]], 45]), + ?line 3 = erl_iolist_length(P, [[42, [90]], 45]), + + %% List with binaries. + + ?line 0 = erl_iolist_length(P, [list_to_binary([])]), + ?line 0 = erl_iolist_length(P, [[], list_to_binary([])]), + ?line 1 = erl_iolist_length(P, [[1], list_to_binary([])]), + ?line 1 = erl_iolist_length(P, [[], list_to_binary([2])]), + ?line 2 = erl_iolist_length(P, [[42], list_to_binary([2])]), + ?line 4 = erl_iolist_length(P, [[42], list_to_binary([2, 3, 4])]), + + %% Binaries as tail. + + ?line 0 = erl_iolist_length(P, [[]| list_to_binary([])]), + ?line 1 = erl_iolist_length(P, [[1]| list_to_binary([])]), + ?line 1 = erl_iolist_length(P, [[]| list_to_binary([2])]), + ?line 2 = erl_iolist_length(P, [[42]| list_to_binary([2])]), + + %% Binaries only. + + ?line 0 = erl_iolist_length(P, list_to_binary("")), + ?line 1 = erl_iolist_length(P, list_to_binary([1])), + ?line 2 = erl_iolist_length(P, list_to_binary([1, 2])), + + %% Illegal cases. + + ?line -1 = erl_iolist_length(P, [42|43]), + ?line -1 = erl_iolist_length(P, a), + + ?line -1 = erl_iolist_length(P, [a]), + ?line -1 = erl_iolist_length(P, [256]), + ?line -1 = erl_iolist_length(P, [257]), + ?line -1 = erl_iolist_length(P, [-1]), + ?line -1 = erl_iolist_length(P, [-2]), + ?line -1 = erl_iolist_length(P, [-127]), + ?line -1 = erl_iolist_length(P, [-128]), + + ?line runner:finish(P), + ok. + +%% Invokes the erl_iolist_length() function. + +erl_iolist_length(Port, List) -> + call_erl_function(Port, List). + +%% Tests the erl_iolist_to_binary() function. + +t_erl_iolist_to_binary(suite) -> []; +t_erl_iolist_to_binary(Config) when is_list(Config) -> + ?line P = runner:start(?t_erl_iolist_to_binary), + + %% Flat lists. + + ?line [] = iolist_to_list(P, []), + ?line [10] = iolist_to_list(P, [10]), + ?line [10, 20] = iolist_to_list(P, [10, 20]), + ?line [10, 20, 30] = iolist_to_list(P, [10, 20, 30]), + ?line AllBytes = lists:seq(0, 255), + ?line AllBytes = iolist_to_list(P, AllBytes), + + %% Deep lists. + + ?line [] = iolist_to_list(P, [[]]), + ?line [42] = iolist_to_list(P, [[], 42]), + ?line [42] = iolist_to_list(P, [42, []]), + ?line [42, 45] = iolist_to_list(P, [42, [], 45]), + + ?line [42, 90, 45] = iolist_to_list(P, [42, [90], 45]), + ?line [42, 90, 45] = iolist_to_list(P, [[42, [90]], 45]), + ?line [42, 90, 45] = iolist_to_list(P, [[42, [90]], 45]), + + %% List with binaries. + + ?line [] = iolist_to_list(P, [list_to_binary([])]), + ?line [] = iolist_to_list(P, [[], list_to_binary([])]), + ?line [1] = iolist_to_list(P, [[1], list_to_binary([])]), + ?line [2] = iolist_to_list(P, [[], list_to_binary([2])]), + ?line [42, 2] = iolist_to_list(P, [[42], list_to_binary([2])]), + ?line [42, 2, 3, 4] = iolist_to_list(P, [[42], list_to_binary([2, 3, 4])]), + + %% Binaries as tail. + + ?line [] = iolist_to_list(P, [[]| list_to_binary([])]), + ?line [1] = iolist_to_list(P, [[1]| list_to_binary([])]), + ?line [2] = iolist_to_list(P, [[]| list_to_binary([2])]), + ?line [42, 2] = iolist_to_list(P, [[42]| list_to_binary([2])]), + + %% Binaries only. + + ?line [] = iolist_to_list(P, list_to_binary("")), + ?line [1] = iolist_to_list(P, list_to_binary([1])), + ?line [1, 2] = iolist_to_list(P, list_to_binary([1, 2])), + + %% Illegal cases. + + ?line 'NULL' = iolist_to_list(P, [42|43]), + ?line 'NULL' = iolist_to_list(P, a), + + ?line 'NULL' = iolist_to_list(P, [a]), + ?line 'NULL' = iolist_to_list(P, [256]), + ?line 'NULL' = iolist_to_list(P, [257]), + ?line 'NULL' = iolist_to_list(P, [-1]), + ?line 'NULL' = iolist_to_list(P, [-2]), + ?line 'NULL' = iolist_to_list(P, [-127]), + ?line 'NULL' = iolist_to_list(P, [-128]), + + ?line runner:finish(P), + ok. + +iolist_to_list(Port, Term) -> + case call_erl_function(Port, Term) of + 'NULL' -> + 'NULL'; + Bin when is_binary(Bin) -> + binary_to_list(Bin) + end. + +%% Tests the erl_iolist_to_string() function. + +t_erl_iolist_to_string(suite) -> []; +t_erl_iolist_to_string(Config) when is_list(Config) -> + ?line P = runner:start(?t_erl_iolist_to_string), + + %% Flat lists. + + ?line [0] = iolist_to_string(P, []), + ?line [10, 0] = iolist_to_string(P, [10]), + ?line [10, 20, 0] = iolist_to_string(P, [10, 20]), + ?line [10, 20, 30, 0] = iolist_to_string(P, [10, 20, 30]), + ?line AllBytes = lists:seq(1, 255)++[0], + ?line AllBytes = iolist_to_string(P, lists:seq(1, 255)), + + %% Deep lists. + + ?line [0] = iolist_to_string(P, [[]]), + ?line [42, 0] = iolist_to_string(P, [[], 42]), + ?line [42, 0] = iolist_to_string(P, [42, []]), + ?line [42, 45, 0] = iolist_to_string(P, [42, [], 45]), + + ?line [42, 90, 45, 0] = iolist_to_string(P, [42, [90], 45]), + ?line [42, 90, 45, 0] = iolist_to_string(P, [[42, [90]], 45]), + ?line [42, 90, 45, 0] = iolist_to_string(P, [[42, [90]], 45]), + + %% List with binaries. + + ?line [0] = iolist_to_string(P, [list_to_binary([])]), + ?line [0] = iolist_to_string(P, [[], list_to_binary([])]), + ?line [1, 0] = iolist_to_string(P, [[1], list_to_binary([])]), + ?line [2, 0] = iolist_to_string(P, [[], list_to_binary([2])]), + ?line [42, 2, 0] = iolist_to_string(P, [[42], list_to_binary([2])]), + ?line [42, 2, 3, 4, 0] = iolist_to_string(P, [[42], + list_to_binary([2, 3, 4])]), + + %% Binaries as tail. + + ?line [0] = iolist_to_string(P, [[]| list_to_binary([])]), + ?line [1, 0] = iolist_to_string(P, [[1]| list_to_binary([])]), + ?line [2, 0] = iolist_to_string(P, [[]| list_to_binary([2])]), + ?line [42, 2, 0] = iolist_to_string(P, [[42]| list_to_binary([2])]), + + %% Binaries only. + + ?line [0] = iolist_to_string(P, list_to_binary("")), + ?line [1, 0] = iolist_to_string(P, list_to_binary([1])), + ?line [1, 2, 0] = iolist_to_string(P, list_to_binary([1, 2])), + + %% Illegal cases. + + ?line 'NULL' = iolist_to_string(P, [0]), + ?line 'NULL' = iolist_to_string(P, [65, 0, 66]), + ?line 'NULL' = iolist_to_string(P, [65, 66, 67, 0]), + + ?line 'NULL' = iolist_to_string(P, [42|43]), + ?line 'NULL' = iolist_to_string(P, a), + + ?line 'NULL' = iolist_to_string(P, [a]), + ?line 'NULL' = iolist_to_string(P, [256]), + ?line 'NULL' = iolist_to_string(P, [257]), + ?line 'NULL' = iolist_to_string(P, [-1]), + ?line 'NULL' = iolist_to_string(P, [-2]), + ?line 'NULL' = iolist_to_string(P, [-127]), + ?line 'NULL' = iolist_to_string(P, [-128]), + + ?line runner:finish(P), + ok. + +%% Invokes the erl_iolist_to_string() function. + +iolist_to_string(Port, Term) -> + runner:send_term(Port, Term), + case get_term(Port) of + {bytes, Result} -> Result; + 'NULL' -> 'NULL' + end. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%% +%%% 5. M i s c e l l a n o u s T e s t s +%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +erl_print_term(suite) -> []; +erl_print_term(doc) -> "Tests the erl_print_term() function"; +erl_print_term(Config) when is_list(Config) -> + ?line PrintTerm = print_term(Config), + ?line P = open_port({spawn, PrintTerm}, [stream]), + + %% Lists. + + ?line print(P, "[]", []), + ?line print(P, "[a]", [a]), + ?line print(P, "[[a]]", [[a]]), + ?line print(P, "[[]]", [[]]), + ?line print(P, "[a,b,c]", [a,b,c]), + ?line print(P, "[a,b|c]", [a,b|c]), + ?line print(P, "[a,[],c]", [a,[],c]), + ?line print(P, "[a,[1000,1],c]", [a,[1000,1],c]), + + %% Tuples. + + ?line print(P, "{}", {}), + ?line print(P, "{ok}", {ok}), + ?line print(P, "{1,2,3}", {1, 2, 3}), + + %% Pids. + + ?line {_X, Y, Z} = split_pid(self()), + ?line PidString = lists:flatten(io_lib:format("<~s.~w.~w>", + [node(), Y, Z])), + ?line print(P, PidString, self()), + + ?line unlink(P), + ?line exit(P, die), + ok. + +split_pid(Pid) when is_pid(Pid) -> + split_pid(pid_to_list(Pid), 0, []). + +split_pid([$<|Rest], Cur, Result) -> + split_pid(Rest, Cur, Result); +split_pid([Digit|Rest], Cur, Result) when $0 =< Digit, Digit =< $9 -> + split_pid(Rest, 10*Cur+Digit-$0, Result); +split_pid([$.|Rest], Cur, Result) -> + split_pid(Rest, 0, Result++[Cur]); +split_pid([$>], Cur, Result) -> + list_to_tuple(Result++[Cur]). + +print_string(suite) -> []; +print_string(doc) -> "Test printing a string with erl_print_term()"; +print_string(Config) when is_list(Config) -> + ?line PrintTerm = print_term(Config), + ?line P = open_port({spawn, PrintTerm}, [stream]), + + %% Strings. + + ?line print(P, "\"ABC\"", "ABC"), + ?line {11, "\"\\tABC\\r\\n\""} = print(P, "\tABC\r\n"), + + %% Not strings. + + ?line print(P, "[65,66,67,0]", "ABC\000"), + + ?line unlink(P), + ?line exit(P, die), + ok. + +print(Port, TermString, Term) -> + Length = length(TermString), + {Length, TermString} = print(Port, Term). + +%% This function uses the erl_print_term() function in erl_interface +%% to print a term. +%% Returns: {NumChars, Chars} + +print(Port, Term) -> + Bin = term_to_binary(Term), + Size = size(Bin), + Port ! {self(), {command, [Size div 256, Size rem 256, Bin]}}, + collect_line(Port, []). + +collect_line(Port, Result) -> + receive + {Port, {data, Data}} -> + case lists:reverse(Data) of + [$\n|Rest] -> + collect_line1(Rest++Result, []); + Chars -> + collect_line(Port, Chars++Result) + end + after test_server:seconds(5) -> + test_server:fail("No response from C program") + end. + +collect_line1([$\r|Rest], Result) -> + {list_to_integer(Result), lists:reverse(Rest)}; +collect_line1([C|Rest], Result) -> + collect_line1(Rest, [C|Result]). + +%% Test case submitted by Per Lundgren, ERV. + +high_chaparal(suite) -> []; +high_chaparal(Config) when is_list(Config) -> + ?line P = runner:start(?high_chaparal), + ?line {term, [hello, world]} = get_term(P), + ?line runner:recv_eot(P), + ok. + +%% OTP-7448 +broken_data(suite) -> []; +broken_data(Config) when is_list(Config) -> + ?line P = runner:start(?broken_data), + ?line runner:recv_eot(P), + ok. + +%% This calls a C function with one parameter and returns the result. + +call_erl_function(Port, Term) -> + runner:send_term(Port, Term), + case get_term(Port) of + {term, Result} -> Result; + 'NULL' -> 'NULL' + end. + +print_term(Config) when is_list(Config) -> + filename:join(?config(data_dir, Config), "print_term"). + + + +%%% We receive a ref from the cnode, and expect it to be a long ref. +%%% We also send a ref we created ourselves, and expect to get it +%%% back, without having been mutated into short form. We must take +%%% care then to check the actual returned ref, and not the original +%%% one, which is equal to it. +cnode_1(suite) -> []; +cnode_1(doc) -> "Tests involving cnode: sends a long ref from a cnode to us"; +cnode_1(Config) when is_list(Config) -> + ?line Cnode = filename:join(?config(data_dir, Config), "cnode"), + ?line register(mip, self()), + ?line spawn_link(?MODULE, start_cnode, [Cnode]), + ?line Ref1 = get_ref(), + io:format("Ref1 ~p~n", [Ref1]), + ?line check_ref(Ref1), + ?line Ref2 = make_ref(), + ?line receive + Pid -> Pid + end, + ?line Fun1 = fun(X) -> {Pid, X} end, % sneak in a fun test here + %?line Fun1 = {wait_with_funs, new_dist_format}, + ?line Term = {Ref2, Fun1, {1,2,3,4,5,6,7,8,9,10}}, + %% A term which will overflow the original buffer used in 'cnode'. + ?line Pid ! Term, + ?line receive + Term2 -> + io:format("received ~p~n", [Term2]), + case Term2 of + Term -> + {Ref22,_,_} = Term2, + ?line check_ref(Ref22); + X -> + test_server:fail({receive1,X}) + end + after 5000 -> + test_server:fail(receive1) + end, + ?line receive + Pid -> + ok; + Y -> + test_server:fail({receive1,Y}) + after 5000 -> + test_server:fail(receive2) + end, + ?line io:format("ref = ~p~n", [Ref1]), + ?line check_ref(Ref1), + ok. + +check_ref(Ref) -> + case bin_ext_type(Ref) of + 101 -> + test_server:fail(oldref); + 114 -> + ok; + Type -> + test_server:fail({type, Type}) + end. + +bin_ext_type(T) -> + [131, Type | _] = binary_to_list(term_to_binary(T)), + Type. + +get_ref() -> + receive + X when is_reference(X) -> + X + after 5000 -> + test_server:fail({cnode, timeout}) + end. + +start_cnode(Cnode) -> + open_port({spawn, Cnode ++ " " ++ atom_to_list(erlang:get_cookie())}, []), + rec_cnode(). + +rec_cnode() -> + receive + X -> + io:format("from cnode: ~p~n", [X]), + rec_cnode() + end. + +nc2vinfo(Pid) when is_pid(Pid) -> + ?line [_NodeStr, NumberStr, SerialStr] + = string:tokens(pid_to_list(Pid), "<.>"), + ?line Number = list_to_integer(NumberStr), + ?line Serial = list_to_integer(SerialStr), + ?line {pid, node(Pid), Number, Serial}; +nc2vinfo(Port) when is_port(Port) -> + ?line ["#Port", _NodeStr, NumberStr] + = string:tokens(erlang:port_to_list(Port), "<.>"), + ?line Number = list_to_integer(NumberStr), + ?line {port, node(Port), Number}; +nc2vinfo(Ref) when is_reference(Ref) -> + ?line ["#Ref", _NodeStr | NumStrList] + = string:tokens(erlang:ref_to_list(Ref), "<.>"), + ?line {Len, RevNumList} = lists:foldl(fun ("0", {N, []}) -> + {N+1, []}; + (IStr, {N, Is}) -> + {N+1, + [list_to_integer(IStr)|Is]} + end, + {0, []}, + NumStrList), + ?line {ref, node(Ref), Len, lists:reverse(RevNumList)}; +nc2vinfo(Other) -> + ?line {badarg, Other}. + + diff --git a/lib/erl_interface/test/erl_eterm_SUITE_data/Makefile.first b/lib/erl_interface/test/erl_eterm_SUITE_data/Makefile.first new file mode 100644 index 0000000000..0f25fcc0a9 --- /dev/null +++ b/lib/erl_interface/test/erl_eterm_SUITE_data/Makefile.first @@ -0,0 +1,21 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2000-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# + +eterm_test_decl.c: eterm_test.c + erl -noinput -pa ../all_SUITE_data -s init_tc run eterm_test -s erlang halt diff --git a/lib/erl_interface/test/erl_eterm_SUITE_data/Makefile.src b/lib/erl_interface/test/erl_eterm_SUITE_data/Makefile.src new file mode 100644 index 0000000000..89931c7701 --- /dev/null +++ b/lib/erl_interface/test/erl_eterm_SUITE_data/Makefile.src @@ -0,0 +1,50 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 1997-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# + +include @erl_interface_mk_include@@[email protected] + +CC0 = @CC@ +CC = ..@DS@all_SUITE_data@DS@gccifier@exe@ -CC"$(CC0)" +LD = @LD@ +LIBPATH = @erl_interface_libpath@ +LIBERL = $(LIBPATH)/@erl_interface_lib@ +LIBEI = $(LIBPATH)/@erl_interface_eilib@ +LIBFLAGS = ../all_SUITE_data/runner@obj@ \ + $(LIBERL) $(LIBEI) @erl_interface_sock_libs@ @LIBS@ \ + @erl_interface_threadlib@ +CFLAGS = @EI_CFLAGS@ $(THR_DEFS) -I@erl_interface_include@ -I../all_SUITE_data +ETERM_OBJS = eterm_test@obj@ eterm_test_decl@obj@ +CNODE_OBJS = cnode@obj@ +PRINT_OBJS = print_term@obj@ +EXE_FILES = eterm_test@exe@ print_term@exe@ cnode@exe@ + +all: $(EXE_FILES) + +eterm_test@exe@: $(ETERM_OBJS) $(LIBERL) $(LIBEI) + $(LD) @CROSSLDFLAGS@ -o $@ $(ETERM_OBJS) $(LIBFLAGS) + +cnode@exe@: $(CNODE_OBJS) $(LIBERL) $(LIBEI) + $(LD) @CROSSLDFLAGS@ -o $@ $(CNODE_OBJS) $(LIBFLAGS) + +print_term@exe@: print_term@obj@ $(LIBERL) $(LIBEI) + $(LD) @CROSSLDFLAGS@ -o $@ $(PRINT_OBJS) $(LIBFLAGS) + +clean: + $(RM) $(ETERM_OBJS) $(CNODE_OBJS) $(PRINT_OBJS) + $(RM) $(EXE_FILES) diff --git a/lib/erl_interface/test/erl_eterm_SUITE_data/cnode.c b/lib/erl_interface/test/erl_eterm_SUITE_data/cnode.c new file mode 100644 index 0000000000..133f35f4bd --- /dev/null +++ b/lib/erl_interface/test/erl_eterm_SUITE_data/cnode.c @@ -0,0 +1,166 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1999-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ + +#include <stdlib.h> +#include <stdio.h> + +#include "ei.h" +#include "erl_interface.h" + +#define MSGSIZE 13 + +#define SELF(fd) erl_mk_pid(erl_thisnodename(),fd,0,erl_thiscreation()) + +#ifdef VXWORKS +#define MAIN cnode +#else +#define MAIN main +#endif + +/* FIXME uses mix och ei and erl_interface */ + +/* + A small cnode. + To be called from the test case erl_eterm_SUITE:cnode_1. + + 1) Set up connection to node 'test_server' on the same host. + All sends are done to a registered process named 'mip'. + 2) Create a long ref and send it. + 3) Create a pid for ourselves and send it. + 4) Receive a message. + 5) Send back the message part of the message. + 6) Send back the 'to' part of the message. + 7) Exit. +*/ + +MAIN(int argc, char **argv) + +{ + unsigned char *msgbufp; + int msgsize; + ErlMessage msg; + char msgbuf[MSGSIZE]; + char buf[100]; + char buf1[100]; + char buf2[100]; + int ix; + int s; + int fd; + char node[80]; + char server[80]; + char host[80]; + int number; + ETERM *ref, *ref1, *ref2; + + erl_init(NULL, 0); + + number = 1; + if (argc >= 2) { + s = erl_connect_init(number, argv[1], 0); + } else { + s = erl_connect_init(number, (char *) 0, 0); + } + gethostname(host, sizeof(host)); + sprintf(node, "c%d@%s", number, host); + + printf("s = %d\n", s); + + sprintf(server, "test_server@%s", host); + fd = erl_connect(server); + printf("fd = %d\n", fd); + +/* printf("dist = %d\n", erl_distversion(fd)); */ + +#if 1 + ref = erl_mk_long_ref(node, 4711, 113, 98, 0); +#else + ref = erl_mk_ref(node, 4711, 0); +#endif + printf("ref = %d\n", ref); + + s = erl_reg_send(fd, "mip", ref); + printf("s = %d\n", s); + + { + ETERM* emsg; + emsg = SELF(fd); + erl_reg_send(fd,"mip",emsg); + erl_free_term(emsg); + } + + msgsize = 4; + msgbufp = (unsigned char *) malloc(msgsize); + + do { +#if 0 + s = erl_receive_msg(fd, msgbuf, MSGSIZE, &msg); +#else + s = erl_xreceive_msg(fd, &msgbufp, &msgsize, &msg); +#endif + switch (s) { + case ERL_TICK: + printf("tick\n"); + break; + case ERL_ERROR: + printf("error\n"); + break; + case ERL_MSG: + printf("msg %d\n", msgsize); + break; + default: + printf("unknown result %d\n", s); + break; + } + } while (s == ERL_TICK); + + s = erl_reg_send(fd, "mip", msg.msg); + printf("s = %d\n", s); + s = erl_reg_send(fd, "mip", msg.to); + printf("s = %d\n", s); +#if 0 + /* from = NULL! */ + s = erl_reg_send(fd, "mip", msg.from); + printf("s = %d\n", s); +#endif + +#if 0 + /* Unused code which tests refs in some ways. */ + ix = 0; + s = ei_encode_term(buf, &ix, ref); + printf ("ei encode = %d, ix = %d\n", s, ix); + + /* Compare old and new ref equal */ + ref1 = erl_mk_long_ref(node, 4711, 113, 98, 0); + ref2 = erl_mk_ref(node, 4711, 0); + s = erl_encode(ref1, buf1); + printf("enc1 s = %d\n", s); + s = erl_encode(ref2, buf2); + printf("enc2 s = %d\n", s); + s = erl_compare_ext(buf1, buf2); + printf("comp s = %d\n", s); + + /* Compare, in another way */ + s = erl_match(ref1, ref2); + printf("match s = %d\n", s); +#endif + + erl_close_connection(fd); + + return 0; +} diff --git a/lib/erl_interface/test/erl_eterm_SUITE_data/eterm_test.c b/lib/erl_interface/test/erl_eterm_SUITE_data/eterm_test.c new file mode 100644 index 0000000000..6b2ec8f766 --- /dev/null +++ b/lib/erl_interface/test/erl_eterm_SUITE_data/eterm_test.c @@ -0,0 +1,1511 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1997-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ + +/* + * Purpose: Tests the functions in erl_eterm.c and erl_malloc.c. + * Author: Bjorn Gustavsson + * + * See the erl_eterm_SUITE.erl file for a "table of contents". + */ + +#include <stdio.h> +#include <string.h> + +#include "runner.h" + +/* + * Find out which version of erl_interface we are using. + */ + +#ifdef ERL_IS_STRING +#undef NEW_ERL_INTERFACE +#else +#define NEW_ERL_INTERFACE +#endif + +void dump_term (FILE *fp, ETERM *t); + +static ETERM* all_types(); + +/*********************************************************************** + * + * 1. B a s i c t e s t s + * + ***********************************************************************/ + +/* + * Sends a list contaning all data types to the Erlang side. + */ + +TESTCASE(build_terms) +{ + ETERM* t; + + erl_init(NULL, 0); + t = all_types(); + send_term(t); + report(1); +} + +/* + * Converts an Erlang term to the external term format and back again. + */ + +TESTCASE(round_trip_conversion) +{ + ETERM* original; + ETERM* new_terms; + char encoded[16*1024]; + int n; + + erl_init(NULL, 0); + original = all_types(); + if (erl_encode(original, encoded) == 0) + { + fail("failed to encode terms"); + } else if ((new_terms = erl_decode(encoded)) == NULL) + { + fail("failed to decode terms"); + } else if (!erl_match(original, new_terms)) + { + fail("decoded terms didn't match original"); + } + + erl_free_term(original); + erl_free_term(new_terms); + report(1); +} + +/* + * Decodes data from the Erlang side and verifies. + */ + +TESTCASE(decode_terms) +{ + ETERM* terms; + char* message; + + erl_init(NULL, 0); + terms = get_term(); + if (terms == NULL) { + fail("unexpected end of file"); + } else { + ETERM* all; + ETERM* p; + ETERM* t; + int i; + + all = p = all_types(); + t = terms; + + /* + * XXX For now, skip the reference, pid, and port, because + * the match will fail. Must write code here to do some other + * validating. + */ + + for (i=0; i<6; i++) { + + p = erl_tl(p); + t = erl_tl(t); + erl_free_term(p); + erl_free_term(t); + + } + + /* + * Match the tail of the lists. + */ + + if (!erl_match(p, t)) + { + fail("Received terms didn't match expected"); + } + erl_free_term(all); + erl_free_term(terms); + report(1); + } +} + +/* + * Decodes a float from the Erlang side and verifies. + */ + +TESTCASE(decode_float) +{ + ETERM* afnum; + ETERM* efnum; + int result; + + erl_init(NULL, 0); + afnum = get_term(); + efnum = erl_mk_float(3.1415); + result = erl_match(efnum, afnum); + erl_free_term(afnum); + erl_free_term(efnum); + report(result); +} + +/* + * Tests the erl_free_compound() function. + */ + +TESTCASE(t_erl_free_compound) +{ + ETERM* t; + + erl_init(NULL, 0); + + t = all_types(); + erl_free_compound(t); + report(1); +} + + +/*********************************************************************** + * + * 2. C o n s t r u c t i n g t e r m s + * + ***********************************************************************/ + +/* + * Makes various integers, and sends them to Erlang for verification. + */ + +TESTCASE(t_erl_mk_int) +{ +#define SEND_INT(i) \ + do { \ + ETERM* t = erl_mk_int(i); \ + send_term(t); \ + } while (0); + + erl_init(NULL, 0); + + SEND_INT(0); + SEND_INT(127); + SEND_INT(128); + SEND_INT(255); + SEND_INT(256); + + SEND_INT(0xFFFF); + SEND_INT(0x10000); + + SEND_INT(0x07FFFFFF); + SEND_INT(0x0FFFFFFF); + SEND_INT(0x1FFFFFFF); + SEND_INT(0x3FFFFFFF); + SEND_INT(0x7FFFFFFF); + + SEND_INT(0x08000000); + SEND_INT(0x10000000); + SEND_INT(0x20000000); + SEND_INT(0x40000000); + + SEND_INT(-0x07FFFFFF); + SEND_INT(-0x0FFFFFFF); + SEND_INT(-0x1FFFFFFF); + SEND_INT(-0x3FFFFFFF); + SEND_INT(-0x7FFFFFFF); + + SEND_INT(-0x08000000); + SEND_INT(-0x10000000); + SEND_INT(-0x20000000); + SEND_INT(-0x40000000); + + SEND_INT(-0x08000001); + SEND_INT(-0x10000001); + SEND_INT(-0x20000001); + SEND_INT(-0x40000001); + + SEND_INT(-0x08000002); + SEND_INT(-0x10000002); + SEND_INT(-0x20000002); + SEND_INT(-0x40000002); + + SEND_INT(-1999999999); + SEND_INT(-2000000000); + SEND_INT(-2000000001); + + report(1); +} + + +/* + * Makes lists of various sizes, and sends them to Erlang for verification. + */ + +TESTCASE(t_erl_mk_list) +{ + ETERM* a[4]; + + erl_init(NULL, 0); + + /* + * Empty list. + */ + + send_term(erl_mk_list(a, 0)); + + /* + * One element: [abc] + */ + + a[0] = erl_mk_atom("abc"); + send_term(erl_mk_list(a, 1)); + erl_free_term(a[0]); + + /* + * Two elements: [abcdef, 42]. + */ + + a[0] = erl_mk_atom("abcdef"); + a[1] = erl_mk_int(42); + send_term(erl_mk_list(a, 2)); + erl_free_term(a[0]); + erl_free_term(a[1]); + + /* + * Four elements. + */ + + a[0] = erl_mk_float(0.0); + a[1] = erl_mk_int(23); + a[2] = erl_mk_empty_list(); + a[3] = erl_mk_float(3.1415); + send_term(erl_mk_list(a, 4)); + erl_free_term(a[0]); + erl_free_term(a[1]); + erl_free_term(a[2]); + erl_free_term(a[3]); + + report(1); +} + +/* + * A basic test of erl_copy_term(). + */ + +TESTCASE(basic_copy) +{ + ETERM* original; + ETERM* copy; + int result; + + erl_init(NULL, 0); + original = all_types(); + copy = erl_copy_term(original); + if (copy == NULL) { + fail("erl_copy_term() failed"); + } else if (!erl_match(original, copy)) + { + fail("copy doesn't match original"); + } + + erl_free_term(original); + erl_free_term(copy); + report(1); +} + + +/* + * A basic test of erl_mk_atom(). + */ + +TESTCASE(t_erl_mk_atom) +{ + erl_init(NULL, 0); + + send_term(erl_mk_atom("madonna")); + send_term(erl_mk_atom("Madonna")); + send_term(erl_mk_atom("mad donna")); + send_term(erl_mk_atom("_madonna_")); + send_term(erl_mk_atom("/home/madonna/tour_plan")); + send_term(erl_mk_atom("http://www.madonna.com/tour_plan")); + send_term(erl_mk_atom("\'madonna\'")); + send_term(erl_mk_atom("\"madonna\"")); + send_term(erl_mk_atom("\\madonna\\")); + send_term(erl_mk_atom("{madonna,21,'mad donna',12}")); + + report(1); +} + + +/* + * A basic test of erl_mk_binary(). + */ + +TESTCASE(t_erl_mk_binary) +{ + + char* string; + erl_init(NULL, 0); + + string = "{madonna,21,'mad donna',1234.567.890, !#$%&/()=?+-@, \" \\}"; + send_term(erl_mk_binary(string,strlen(string))); + + report(1); +} + + +/* + * A basic test of erl_mk_empty_list(). + */ + +TESTCASE(t_erl_mk_empty_list) +{ + erl_init(NULL, 0); + + send_term(erl_mk_empty_list()); + report(1); +} + + +/* + * A basic test of erl_mk_float(). + */ + +TESTCASE(t_erl_mk_float) +{ + ETERM* arr[6]; + ETERM* emsg; + + erl_init(NULL, 0); + + arr[0] = erl_mk_float(3.1415); + arr[1] = erl_mk_float(1.999999); + arr[2] = erl_mk_float(2.000000); + arr[3] = erl_mk_float(2.000001); + arr[4] = erl_mk_float(2.000002); + arr[5] = erl_mk_float(12345.67890); + emsg = (erl_mk_tuple(arr,6)); + + send_term(emsg); + + erl_free_array(arr,6); + /* emsg already freed by send_term() */ + /* erl_free_term(emsg); */ + + report(1); +} + + +/* + * A basic test of erl_mk_pid(). + */ + +TESTCASE(t_erl_mk_pid) +{ + erl_init(NULL, 0); + + send_term(erl_mk_pid("kalle@localhost", 3, 2, 1)); + report(1); +} + +/* + * A basic test of erl_mk_pid(). + */ + +TESTCASE(t_erl_mk_xpid) +{ + erl_init(NULL, 0); + + send_term(erl_mk_pid("kalle@localhost", 32767, 8191, 1)); + report(1); +} + + +/* + * A basic test of erl_mk_port(). + */ + +TESTCASE(t_erl_mk_port) +{ + erl_init(NULL, 0); + + send_term(erl_mk_port("kalle@localhost", 4, 1)); + report(1); +} + +/* + * A basic test of erl_mk_port(). + */ + +TESTCASE(t_erl_mk_xport) +{ + erl_init(NULL, 0); + + send_term(erl_mk_port("kalle@localhost", 268435455, 1)); + report(1); +} + +/* + * A basic test of erl_mk_ref(). + */ + +TESTCASE(t_erl_mk_ref) +{ + erl_init(NULL, 0); + + send_term(erl_mk_ref("kalle@localhost", 6, 1)); + report(1); +} + +/* + * A basic test of erl_mk_long_ref(). + */ + + +TESTCASE(t_erl_mk_long_ref) +{ + erl_init(NULL, 0); + + send_term(erl_mk_long_ref("kalle@localhost", + 4294967295, 4294967295, 262143, + 1)); + report(1); +} + + +/* + * A basic test of erl_mk_string(). + */ + +TESTCASE(t_erl_mk_string) +{ + + erl_init(NULL, 0); + + send_term(erl_mk_string("madonna")); + send_term(erl_mk_string("Madonna")); + send_term(erl_mk_string("mad donna")); + send_term(erl_mk_string("_madonna_")); + send_term(erl_mk_string("/home/madonna/tour_plan")); + send_term(erl_mk_string("http://www.madonna.com/tour_plan")); + send_term(erl_mk_string("\'madonna\'")); + send_term(erl_mk_string("\"madonna\"")); + send_term(erl_mk_string("\\madonna\\")); + send_term(erl_mk_string("{madonna,21,'mad donna',12}")); + + report(1); +} + + +/* + * A basic test of erl_mk_estring(). + */ + +TESTCASE(t_erl_mk_estring) +{ + char* string; + erl_init(NULL, 0); + + string = "madonna"; + send_term(erl_mk_estring(string,strlen(string))); + string = "Madonna"; + send_term(erl_mk_estring(string,strlen(string))); + string = "mad donna"; + send_term(erl_mk_estring(string,strlen(string))); + string = "_madonna_"; + send_term(erl_mk_estring(string,strlen(string))); + string = "/home/madonna/tour_plan"; + send_term(erl_mk_estring(string,strlen(string))); + string = "http://www.madonna.com/tour_plan"; + send_term(erl_mk_estring(string,strlen(string))); + string = "\'madonna\'"; + send_term(erl_mk_estring(string,strlen(string))); + string = "\"madonna\""; + send_term(erl_mk_estring(string,strlen(string))); + string = "\\madonna\\"; + send_term(erl_mk_estring(string,strlen(string))); + string = "{madonna,21,'mad donna',12}"; + send_term(erl_mk_estring(string,strlen(string))); + + report(1); +} + + +/* + * A basic test of erl_mk_tuple(). + */ + +TESTCASE(t_erl_mk_tuple) +{ + ETERM* arr[4]; + ETERM* arr2[2]; + ETERM* arr3[2]; + ETERM* arr4[2]; + + erl_init(NULL, 0); + + /* {madonna,21,'mad donna',12} */ + arr[0] = erl_mk_atom("madonna"); + arr[1] = erl_mk_int(21); + arr[2] = erl_mk_atom("mad donna"); + arr[3] = erl_mk_int(12); + + send_term(erl_mk_tuple(arr,4)); + + erl_free_array(arr,4); + + + /* {'Madonna',21,{children,{"Isabella",2}},{'home page',"http://www.madonna.com/"} */ + arr4[0] = erl_mk_atom("home page"); + arr4[1] = erl_mk_string("http://www.madonna.com/"); + + arr3[0] = erl_mk_string("Isabella"); + arr3[1] = erl_mk_int(2); + + arr2[0] = erl_mk_atom("children"); + arr2[1] = erl_mk_tuple(arr3,2); + + arr[0] = erl_mk_atom("Madonna"); + arr[1] = erl_mk_int(21); + arr[2] = erl_mk_tuple(arr2,2); + arr[3] = erl_mk_tuple(arr4,2); + + send_term(erl_mk_tuple(arr,4)); + + erl_free_array(arr,4); + erl_free_array(arr2,2); + erl_free_array(arr3,2); + erl_free_array(arr4,2); + + + report(1); +} + + +/* + * A basic test of erl_mk_uint(). + */ + +TESTCASE(t_erl_mk_uint) +{ + unsigned i; + + erl_init(NULL, 0); + + send_term(erl_mk_uint(54321)); + i = 2147483647; + send_term(erl_mk_uint(i)); + send_term(erl_mk_uint(i+1)); + send_term(erl_mk_uint(i+2)); + send_term(erl_mk_uint(i+3)); + send_term(erl_mk_uint(i+i+1)); + + report(1); +} + + +/* + * A basic test of erl_mk_var(). + */ + +TESTCASE(t_erl_mk_var) +{ + ETERM* mk_var; + ETERM* term; + ETERM* term2; + ETERM* arr[4]; + ETERM* arr_term[2]; + ETERM* mk_var_tuple; + ETERM* term_tuple; + + erl_init(NULL, 0); + + + /* match unbound/bound variable against an integer */ + term = erl_mk_int(17); + term2 = erl_mk_int(2); + mk_var = erl_mk_var("New_var"); + send_term(erl_mk_int(erl_match(mk_var, term))); /* should be ok */ + send_term(erl_mk_int(erl_match(mk_var, term2))); /* should fail */ + send_term(erl_mk_int(erl_match(mk_var, term))); /* should be ok */ + send_term(erl_mk_int(erl_match(mk_var, term2))); /* should fail */ + erl_free_term(mk_var); + erl_free_term(term); + erl_free_term(term2); + + /* match unbound variable against a tuple */ + arr[0] = erl_mk_atom("madonna"); + arr[1] = erl_mk_int(21); + arr[2] = erl_mk_atom("mad donna"); + arr[3] = erl_mk_int(12); + mk_var = erl_mk_var("New_var"); + term = erl_mk_tuple(arr,4); + send_term(erl_mk_int(erl_match(mk_var, term))); /* should be ok */ + erl_free_term(mk_var); + erl_free_term(term); + erl_free_array(arr,4); + + + /* match (twice) unbound variable against an incorrect tuple */ + arr[0] = erl_mk_var("New_var"); + arr[1] = erl_mk_var("New_var"); + arr_term[0] = erl_mk_int(17); + arr_term[1] = erl_mk_int(27); + mk_var_tuple = erl_mk_tuple(arr,2); + term_tuple = erl_mk_tuple(arr_term,2); + send_term(erl_mk_int(erl_match(mk_var_tuple, term_tuple))); /* should fail */ + erl_free_array(arr,2); + erl_free_array(arr_term,2); + erl_free_term(mk_var_tuple); + erl_free_term(term_tuple); + + + /* match (twice) unbound variable against a correct tuple */ + arr[0] = erl_mk_var("New_var"); + arr[1] = erl_mk_var("New_var"); + arr_term[0] = erl_mk_int(17); + arr_term[1] = erl_mk_int(17); + mk_var_tuple = erl_mk_tuple(arr,2); + term_tuple = erl_mk_tuple(arr_term,2); + send_term(erl_mk_int(erl_match(mk_var_tuple, term_tuple))); /* should be ok */ + erl_free_array(arr,2); + erl_free_array(arr_term,2); + erl_free_term(mk_var_tuple); + erl_free_term(term_tuple); + + report(1); +} + + +/* + * A basic test of erl_size(). + */ + +TESTCASE(t_erl_size) +{ + ETERM* arr[4]; + ETERM* tuple; + ETERM* bin; + char* string; + + erl_init(NULL, 0); + + /* size of a tuple */ + tuple = erl_format("{}"); + send_term(erl_mk_int(erl_size(tuple))); + erl_free_term(tuple); + + arr[0] = erl_mk_atom("madonna"); + arr[1] = erl_mk_int(21); + arr[2] = erl_mk_atom("mad donna"); + arr[3] = erl_mk_int(12); + tuple = erl_mk_tuple(arr,4); + + send_term(erl_mk_int(erl_size(tuple))); + + erl_free_array(arr,4); + erl_free_term(tuple); + + /* size of a binary */ + string = ""; + bin = erl_mk_binary(string,strlen(string)); + send_term(erl_mk_int(erl_size(bin))); + erl_free_term(bin); + + string = "{madonna,21,'mad donna',12}"; + bin = erl_mk_binary(string,strlen(string)); + send_term(erl_mk_int(erl_size(bin))); + erl_free_term(bin); + + report(1); +} + + +/* + * A basic test of erl_var_content(). + */ + +TESTCASE(t_erl_var_content) +{ + ETERM* mk_var; + ETERM* term; + ETERM* tuple; + ETERM* list; + ETERM* a; + ETERM* b; + ETERM* arr[4]; + ETERM* arr2[2]; + ETERM* arr3[2]; + ETERM* arr4[2]; + + erl_init(NULL, 0); + + term = erl_mk_int(17); + mk_var = erl_mk_var("Var"); + + /* unbound, should return NULL */ + if (erl_var_content(mk_var,"Var") != NULL) + fail("t_erl_var_content() failed"); + + erl_match(mk_var, term); + send_term(erl_var_content(mk_var,"Var")); /* should return 17 */ + + /* integer, should return NULL */ + if (erl_var_content(term,"Var") != NULL) + fail("t_erl_var_content() failed"); + + /* unknown variable, should return NULL */ + if (erl_var_content(mk_var,"Unknown_Var") != NULL) + fail("t_erl_var_content() failed"); + + erl_free_term(mk_var); + erl_free_term(term); + + /* {'Madonna',21,{children,{"Name","Age"}},{"Home_page","Tel_no"}} */ + arr4[0] = erl_mk_var("Home_page"); + arr4[1] = erl_mk_var("Tel_no"); + a = erl_mk_string("http://www.madonna.com"); + erl_match(arr4[0], a); + + arr3[0] = erl_mk_var("Name"); + arr3[1] = erl_mk_var("Age"); + b = erl_mk_int(2); + erl_match(arr3[1], b); + + arr2[0] = erl_mk_atom("children"); + arr2[1] = erl_mk_tuple(arr3,2); + + arr[0] = erl_mk_atom("Madonna"); + arr[1] = erl_mk_int(21); + arr[2] = erl_mk_tuple(arr2,2); + arr[3] = erl_mk_tuple(arr4,2); + + tuple = erl_mk_tuple(arr,4); + + /* should return "http://www.madonna.com" */ + send_term(erl_var_content(tuple,"Home_page")); + + /* unbound, should return NULL */ + if (erl_var_content(tuple,"Tel_no") != NULL) + fail("t_erl_var_content() failed"); + + /* unbound, should return NULL */ + if (erl_var_content(tuple,"Name") != NULL) + fail("t_erl_var_content() failed"); + + /* should return 2 */ + send_term(erl_var_content(tuple,"Age")); + + erl_free_array(arr,4); + erl_free_array(arr2,2); + erl_free_array(arr3,2); + erl_free_array(arr4,2); + erl_free_term(tuple); + erl_free_term(a); + erl_free_term(b); + + + /* [] */ + list = erl_mk_empty_list(); + if (erl_var_content(list,"Tel_no") != NULL) + fail("t_erl_var_content() failed"); + erl_free_term(list); + + + /* ['Madonna',[],{children,{"Name","Age"}},{"Home_page","Tel_no"}] */ + arr4[0] = erl_mk_var("Home_page"); + arr4[1] = erl_mk_var("Tel_no"); + a = erl_mk_string("http://www.madonna.com"); + erl_match(arr4[0], a); + + arr3[0] = erl_mk_var("Name"); + arr3[1] = erl_mk_var("Age"); + b = erl_mk_int(2); + erl_match(arr3[1], b); + + arr2[0] = erl_mk_atom("children"); + arr2[1] = erl_mk_tuple(arr3,2); + + arr[0] = erl_mk_atom("Madonna"); + arr[1] = erl_mk_empty_list(); + arr[2] = erl_mk_tuple(arr2,2); + arr[3] = erl_mk_tuple(arr4,2); + + list = erl_mk_list(arr,4); + + /* should return "http://www.madonna.com" */ + send_term(erl_var_content(list,"Home_page")); + + /* unbound, should return NULL */ + if (erl_var_content(list,"Tel_no") != NULL) + fail("t_erl_var_content() failed"); + + /* unbound, should return NULL */ + if (erl_var_content(list,"Name") != NULL) + fail("t_erl_var_content() failed"); + + /* should return 2 */ + send_term(erl_var_content(list,"Age")); + + erl_free_array(arr,4); + erl_free_array(arr2,2); + erl_free_array(arr3,2); + erl_free_array(arr4,2); + erl_free_term(list); + erl_free_term(a); + erl_free_term(b); + + report(1); +} + + +/* + * A basic test of erl_element(). + */ + +TESTCASE(t_erl_element) +{ + ETERM* arr[4]; + ETERM* arr2[2]; + ETERM* arr3[2]; + ETERM* arr4[2]; + ETERM* tuple; + + erl_init(NULL, 0); + + arr[0] = erl_mk_atom("madonna"); + arr[1] = erl_mk_int(21); + arr[2] = erl_mk_atom("mad donna"); + arr[3] = erl_mk_int(12); + tuple = erl_mk_tuple(arr,4); + + send_term(erl_element(1,tuple)); + send_term(erl_element(2,tuple)); + send_term(erl_element(3,tuple)); + send_term(erl_element(4,tuple)); + + erl_free_array(arr,4); + erl_free_term(tuple); + + /* {'Madonna',21,{children,{"Isabella",2}},{'home page',"http://www.madonna.com/"} */ + arr4[0] = erl_mk_atom("home page"); + arr4[1] = erl_mk_string("http://www.madonna.com/"); + + arr3[0] = erl_mk_string("Isabella"); + arr3[1] = erl_mk_int(2); + + arr2[0] = erl_mk_atom("children"); + arr2[1] = erl_mk_tuple(arr3,2); + + arr[0] = erl_mk_atom("Madonna"); + arr[1] = erl_mk_int(21); + arr[2] = erl_mk_tuple(arr2,2); + arr[3] = erl_mk_tuple(arr4,2); + + tuple = erl_mk_tuple(arr,4); + send_term(erl_element(1,tuple)); + send_term(erl_element(2,tuple)); + send_term(erl_element(3,tuple)); + send_term(erl_element(4,tuple)); + + erl_free_term(tuple); + erl_free_array(arr,4); + erl_free_array(arr2,2); + erl_free_array(arr3,2); + erl_free_array(arr4,2); + + report(1); +} + + +/* + * A basic test of erl_cons(). + */ + +TESTCASE(t_erl_cons) +{ + ETERM* list; + ETERM* anAtom; + ETERM* anInt; + + erl_init(NULL, 0); + + anAtom = erl_mk_atom("madonna"); + anInt = erl_mk_int(21); + list = erl_mk_empty_list(); + list = erl_cons(anInt, list); + send_term(erl_cons(anAtom, list)); + + erl_free_term(anAtom); + erl_free_term(anInt); + erl_free_compound(list); + + report(1); +} + + + + +/*********************************************************************** + * + * 3. E x t r a c t i n g & i n f o f u n c t i o n s + * + ***********************************************************************/ + +/* + * Calculates the length of each list sent to it and sends back the result. + */ + +TESTCASE(t_erl_length) +{ + erl_init(NULL, 0); + + for (;;) { + ETERM* term = get_term(); + + if (term == NULL) { + report(1); + return; + } else { + ETERM* len_term; + + len_term = erl_mk_int(erl_length(term)); + erl_free_term(term); + send_term(len_term); + } + } +} + +/* + * Gets the head of each term and sends the result back. + */ + +TESTCASE(t_erl_hd) +{ + erl_init(NULL, 0); + + for (;;) { + ETERM* term = get_term(); + + if (term == NULL) { + report(1); + return; + } else { + ETERM* head; + + head = erl_hd(term); + send_term(head); + erl_free_term(term); + } + } +} + +/* + * Gets the tail of each term and sends the result back. + */ + +TESTCASE(t_erl_tl) +{ + erl_init(NULL, 0); + + for (;;) { + ETERM* term = get_term(); + + if (term == NULL) { + report(1); + return; + } else { + ETERM* tail; + + tail = erl_tl(term); + send_term(tail); + erl_free_term(term); + } + } +} + +/* + * Checks the type checking macros. + */ + +TESTCASE(type_checks) +{ + ETERM* t; + ETERM* atom; + + erl_init(NULL, 0); + atom = erl_mk_atom("an_atom"); + +#define TYPE_CHECK(macro, term) \ + { ETERM* t = term; \ + if (macro(t)) { \ + erl_free_term(t); \ + } else { \ + fail("Macro " #macro " failed on " #term); \ + } \ + } + + TYPE_CHECK(ERL_IS_INTEGER, erl_mk_int(0x7FFFFFFF)); +#ifdef NEW_ERL_INTERFACE + TYPE_CHECK(ERL_IS_UNSIGNED_INTEGER, erl_mk_uint(0x7FFFFFFF)); +#endif + TYPE_CHECK(ERL_IS_FLOAT, erl_mk_float(5.5)); + TYPE_CHECK(ERL_IS_ATOM, erl_mk_atom("another_atom")); + + TYPE_CHECK(ERL_IS_EMPTY_LIST, erl_mk_empty_list()); + TYPE_CHECK(!ERL_IS_EMPTY_LIST, erl_cons(atom, atom)); + +#ifdef NEW_ERL_INTERFACE + TYPE_CHECK(!ERL_IS_CONS, erl_mk_empty_list()); + TYPE_CHECK(ERL_IS_CONS, erl_cons(atom, atom)); +#endif + + TYPE_CHECK(ERL_IS_LIST, erl_mk_empty_list()); + TYPE_CHECK(ERL_IS_LIST, erl_cons(atom, atom)); + + TYPE_CHECK(ERL_IS_PID, erl_mk_pid("a@a", 42, 1, 1)); + TYPE_CHECK(ERL_IS_PORT, erl_mk_port("a@a", 42, 1)); + TYPE_CHECK(ERL_IS_REF, erl_mk_ref("a@a", 42, 1)); + + TYPE_CHECK(ERL_IS_BINARY, erl_mk_binary("a", 1)); + TYPE_CHECK(ERL_IS_TUPLE, erl_mk_tuple(&atom, 1)); +#undef TYPE_CHECK + + erl_free_term(atom); + + report(1); +} + +/* + * Checks the extractor macros. + */ + +TESTCASE(extractor_macros) +{ + ETERM* t; + + erl_init(NULL, 0); + +#ifdef NEW_ERL_INTERFACE +#define MATCH(a, b) ((a) == (b) ? 1 : fail("bad match: " #a)) +#define STR_MATCH(a, b) (strcmp((a), (b)) ? fail("bad match: " #a) : 0) + + { /* Integer */ + int anInt = 0x7FFFFFFF; + t = erl_mk_int(anInt); + MATCH(ERL_INT_VALUE(t), anInt); + MATCH(ERL_INT_UVALUE(t), anInt); + erl_free_term(t); + } + + { /* Float */ + double aFloat = 3.1415; + t = erl_mk_float(aFloat); + MATCH(ERL_FLOAT_VALUE(t), aFloat); + erl_free_term(t); + } + + { /* Atom. */ + char* aString = "nisse"; + t = erl_mk_atom(aString); + if (memcmp(ERL_ATOM_PTR(t), aString, strlen(aString)) != 0) + fail("bad match"); + MATCH(ERL_ATOM_SIZE(t), strlen(aString)); + erl_free_term(t); + } + + { /* Pid. */ + char* node = "arne@strider"; + int number = 42; + int serial = 5; + int creation = 1; + + t = erl_mk_pid(node, number, serial, creation); + STR_MATCH(ERL_PID_NODE(t), node); + MATCH(ERL_PID_NUMBER(t), number); + MATCH(ERL_PID_SERIAL(t), serial); + MATCH(ERL_PID_CREATION(t), creation); + erl_free_term(t); + } + + { /* Port. */ + char* node = "kalle@strider"; + int number = 45; + int creation = 1; + + t = erl_mk_port(node, number, creation); + STR_MATCH(ERL_PORT_NODE(t), node); + MATCH(ERL_PORT_NUMBER(t), number); + MATCH(ERL_PORT_CREATION(t), creation); + erl_free_term(t); + } + + { /* Reference. */ + char* node = "kalle@strider"; + int number = 48; + int creation = 1; + + t = erl_mk_ref(node, number, creation); + STR_MATCH(ERL_REF_NODE(t), node); + MATCH(ERL_REF_NUMBER(t), number); + MATCH(ERL_REF_CREATION(t), creation); + erl_free_term(t); + } + + { /* Tuple. */ + ETERM* arr[2]; + + arr[0] = erl_mk_int(51); + arr[1] = erl_mk_int(52); + t = erl_mk_tuple(arr, ASIZE(arr)); + MATCH(ERL_TUPLE_SIZE(t), ASIZE(arr)); + MATCH(ERL_TUPLE_ELEMENT(t, 0), arr[0]); + MATCH(ERL_TUPLE_ELEMENT(t, 1), arr[1]); + erl_free_array(arr, ASIZE(arr)); + erl_free_term(t); + } + + { /* Binary. */ + static char bin[] = {1, 2, 3, 0, 4, 5}; + + t = erl_mk_binary(bin, ASIZE(bin)); + MATCH(ERL_BIN_SIZE(t), ASIZE(bin)); + if (memcmp(ERL_BIN_PTR(t), bin, ASIZE(bin)) != 0) + fail("bad match"); + erl_free_term(t); + } + + { + ETERM* head = erl_mk_atom("head"); + ETERM* tail = erl_mk_atom("tail"); + + t = erl_cons(head, tail); + MATCH(ERL_CONS_HEAD(t), head); + MATCH(ERL_CONS_TAIL(t), tail); + erl_free_term(head); + erl_free_term(tail); + erl_free_term(t); + } +#undef MATCH +#undef STR_MATCH +#endif + + report(1); +} + + + +/*********************************************************************** + * + * 4. I / O l i s t f u n c t i o n s + * + ***********************************************************************/ + +/* + * Invokes erl_iolist_length() on each term and send backs the result. + */ + +TESTCASE(t_erl_iolist_length) +{ + erl_init(NULL, 0); + + for (;;) { + ETERM* term = get_term(); + + if (term == NULL) { + report(1); + return; + } else { +#ifndef NEW_ERL_INTERFACE + fail("Function not present in this version of erl_interface"); +#else + ETERM* len_term; + + len_term = erl_mk_int(erl_iolist_length(term)); + erl_free_term(term); + send_term(len_term); +#endif + } + } +} + +/* + * Invokes erl_iolist_to_binary() on each term and send backs the result. + */ + +TESTCASE(t_erl_iolist_to_binary) +{ + erl_init(NULL, 0); + + for (;;) { + ETERM* term = get_term(); + + if (term == NULL) { + report(1); + return; + } else { +#ifndef NEW_ERL_INTERFACE + fail("Function not present in this version of erl_interface"); +#else + ETERM* new_term; + + new_term = erl_iolist_to_binary(term); + + erl_free_term(term); + send_term(new_term); +#endif + } + } +} + +/* + * Invokes erl_iolist_to_string() on each term and send backs the result. + */ + +TESTCASE(t_erl_iolist_to_string) +{ + erl_init(NULL, 0); + + for (;;) { + ETERM* term = get_term(); + + if (term == NULL) { + report(1); + return; + } else { +#ifndef NEW_ERL_INTERFACE + fail("Function not present in this version of erl_interface"); +#else + char* result; + + result = erl_iolist_to_string(term); + erl_free_term(term); + if (result != NULL) { + send_buffer(result, strlen(result)+1); + erl_free(result); + } else { + send_term(NULL); + } +#endif + } + } +} + + +/*********************************************************************** + * + * 5. M i s c e l l a n o u s T e s t s + * + ***********************************************************************/ + +/* + * Test some combinations of operations to verify that the reference pointers + * are handled correctly. + * + * "Det verkar vara lite High Chaparal med minneshanteringen i erl_interface" + * Per Lundgren, ERV. + */ + +TESTCASE(high_chaparal) +{ + ETERM *L1, *A1, *L2, *A2, *L3; + + erl_init(NULL, 0); + + L1 = erl_mk_empty_list(); + A1 = erl_mk_atom("world"); + L2 = erl_cons(A1, L1); + A2 = erl_mk_atom("hello"); + L3 = erl_cons(A2, L2); + + erl_free_term(L1); + erl_free_term(A1); + erl_free_term(L2); + erl_free_term(A2); + + send_term(L3); + + /* already freed by send_term() */ + /* erl_free_term(L3);*/ + + report(1); +} + +/* + * Test erl_decode to recover from broken list data (OTP-7448) + */ +TESTCASE(broken_data) +{ + ETERM* original; + ETERM* new_terms; + char encoded[16*1024]; + int n; + + erl_init(NULL, 0); + original = all_types(); + if ((n=erl_encode(original, encoded)) == 0) + { + fail("failed to encode terms"); + } else + { + int offs = n/2; + memset(encoded+offs,0,n-offs); /* destroy */ + + if ((new_terms = erl_decode(encoded)) != NULL) + { + fail("decode accepted broken data"); + erl_free_term(new_terms); + } + } + erl_free_term(original); + report(1); +} + +/* + * Returns a list containing instances of all types. + * + * Be careful changing the contents of the list returned, because both + * the build_terms() and decode_terms() test cases depend on it. + */ + +static ETERM* +all_types(void) +{ + ETERM* t; + ETERM* terms[3]; + int i; + static char a_binary[] = "A binary"; + +#define CONS_AND_FREE(expr, tail) \ + do { \ + ETERM* term = expr; \ + ETERM* nl = erl_cons(term, tail); \ + erl_free_term(term); \ + erl_free_term(tail); \ + tail = nl; \ + } while (0) + + t = erl_mk_empty_list(); + + CONS_AND_FREE(erl_mk_atom("I am an atom"), t); + CONS_AND_FREE(erl_mk_binary("A binary", sizeof(a_binary)-1), t); + CONS_AND_FREE(erl_mk_float(3.0), t); + CONS_AND_FREE(erl_mk_int(0), t); + CONS_AND_FREE(erl_mk_int(-1), t); + CONS_AND_FREE(erl_mk_int(1), t); + + CONS_AND_FREE(erl_mk_string("A string"), t); + + terms[0] = erl_mk_atom("element1"); + terms[1] = erl_mk_int(42); + terms[2] = erl_mk_int(767); + CONS_AND_FREE(erl_mk_tuple(terms, ASIZE(terms)), t); + for (i = 0; i < ASIZE(terms); i++) { + erl_free_term(terms[i]); + } + + CONS_AND_FREE(erl_mk_pid("kalle@localhost", 3, 2, 1), t); + CONS_AND_FREE(erl_mk_pid("abcdefghijabcdefghij@localhost", 3, 2, 1), t); + CONS_AND_FREE(erl_mk_port("kalle@localhost", 4, 1), t); + CONS_AND_FREE(erl_mk_port("abcdefghijabcdefghij@localhost", 4, 1), t); + CONS_AND_FREE(erl_mk_ref("kalle@localhost", 6, 1), t); + CONS_AND_FREE(erl_mk_ref("abcdefghijabcdefghij@localhost", 6, 1), t); + return t; + +#undef CONS_AND_FREE +} + +/* + * Dump (print for debugging) a term. Useful if/when things go wrong. + */ +void +dump_term (FILE *fp, ETERM *t) +{ + if (fp == NULL) return; + + fprintf(fp, "#<%p ", t); + + if(t != NULL) + { + fprintf(fp, "count:%d, type:%d", ERL_COUNT(t), ERL_TYPE(t)); + + switch(ERL_TYPE(t)) + { + case ERL_UNDEF: + fprintf(fp, "==undef"); + break; + case ERL_INTEGER: + fprintf(fp, "==int, val:%d", ERL_INT_VALUE(t)); + break; + case ERL_U_INTEGER: + fprintf(fp, "==uint, val:%u", ERL_INT_UVALUE(t)); + break; + case ERL_FLOAT: + fprintf(fp, "==float, val:%g", ERL_FLOAT_VALUE(t)); + break; + case ERL_ATOM: + fprintf(fp, "==atom, name:%p \"%s\"", + ERL_ATOM_PTR(t), ERL_ATOM_PTR(t)); + break; + case ERL_BINARY: + fprintf(fp, "==binary, data:%p,%u", + ERL_BIN_PTR(t), ERL_BIN_SIZE(t)); + break; + case ERL_PID: + fprintf(fp, "==pid, node:%p \"%s\"", + ERL_PID_NODE(t), ERL_PID_NODE(t)); + break; + case ERL_PORT: + fprintf(fp, "==port, node:%p \"%s\"", + ERL_PORT_NODE(t), ERL_PORT_NODE(t)); + break; + case ERL_REF: + fprintf(fp, "==ref, node:%p \"%s\"", + ERL_REF_NODE(t), ERL_REF_NODE(t)); + break; + case ERL_CONS: + fprintf(fp, "==cons"); + fprintf(fp, ", car:"); + dump_term(fp, ERL_CONS_HEAD(t)); + fprintf(fp, ", cdr:"); + dump_term(fp, ERL_CONS_TAIL(t)); + break; + case ERL_NIL: + fprintf(fp, "==nil"); + break; + case ERL_TUPLE: + fprintf(fp, "==tuple, elems:%p,%u", + ERL_TUPLE_ELEMS(t), ERL_TUPLE_SIZE(t)); + { + size_t i; + for(i = 0; i < ERL_TUPLE_SIZE(t); i++) + { + fprintf(fp, "elem[%u]:", i); + dump_term(fp, ERL_TUPLE_ELEMENT(t, i)); + } + } + break; + case ERL_VARIABLE: + fprintf(fp, "==variable, name:%p \"%s\"", + ERL_VAR_NAME(t), ERL_VAR_NAME(t)); + fprintf(fp, ", value:"); + dump_term(fp, ERL_VAR_VALUE(t)); + break; + + default: + break; + } + } + fprintf(fp, ">"); +} + diff --git a/lib/erl_interface/test/erl_eterm_SUITE_data/print_term.c b/lib/erl_interface/test/erl_eterm_SUITE_data/print_term.c new file mode 100644 index 0000000000..56e2d43d2f --- /dev/null +++ b/lib/erl_interface/test/erl_eterm_SUITE_data/print_term.c @@ -0,0 +1,129 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1997-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ + +/* + * Purpose: Test the erl_print_term() function. + * Author: Bjorn Gustavsson + */ + +#include <stdio.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#ifndef __WIN32__ +#include <unistd.h> +#endif + +#include "erl_interface.h" + +#ifndef __WIN32__ +#define _O_BINARY 0 +#define _setmode(fd, mode) +#endif + +#define HEADER_SIZE 2 + +static int readn(int, unsigned char*, int); + +/* + * This program doesn't use the runner, because it needs a packet + * on input, but the result will be as a stream of bytes (since + * erl_print_term() prints directly on a file). + * + * Input is a package of with a packet header size of two bytes. + * + * +------------------------------------------------------------+ + * | length | Encoded term... | + * | (2 bytes) | (as given by "length") | + * +------------------------------------------------------------+ + * + * <------------------- length ---------------------> + * + * This program decodes the encoded terms and passes it to + * erl_print_term(). Then this program prints + * + * CR <result> LF + * + * and waits for a new package. <result> is the return value from + * erl_print_term(), formatted as an ASCII string. + */ + +#ifdef VXWORKS +int print_term() +#else +int main() +#endif +{ + _setmode(0, _O_BINARY); + _setmode(1, _O_BINARY); + + erl_init(NULL, 0); + + for (;;) { + char buf[4*1024]; + ETERM* term; + char* message; + int n; + + if (readn(0, buf, 2) <= 0) { + /* fprintf(stderr, "error reading message header\n"); */ + /* actually this is where we leave the infinite loop */ + exit(1); + } + n = buf[0] * 256 + buf[1]; + if (readn(0, buf, n) < 0) { + fprintf(stderr, "error reading message contents\n"); + exit(1); + } + + term = erl_decode(buf); + if (term == NULL) { + fprintf(stderr, "erl_decode() failed\n"); + exit(1); + } + n = erl_print_term(stdout, term); + erl_free_compound(term); + fprintf(stdout,"\r%d\n", n); + fflush(stdout); + } +} + +/* + * Reads len number of bytes. + */ + +static int +readn(fd, buf, len) + int fd; /* File descriptor to read from. */ + unsigned char *buf; /* Store in this buffer. */ + int len; /* Number of bytes to read. */ +{ + int n; /* Byte count in last read call. */ + int sofar = 0; /* Bytes read so far. */ + + do { + if ((n = read(fd, buf+sofar, len-sofar)) <= 0) + /* error or EOF in read */ + return(n); + sofar += n; + } while (sofar < len); + return sofar; +} + diff --git a/lib/erl_interface/test/erl_ext_SUITE.erl b/lib/erl_interface/test/erl_ext_SUITE.erl new file mode 100644 index 0000000000..dbafea0e39 --- /dev/null +++ b/lib/erl_interface/test/erl_ext_SUITE.erl @@ -0,0 +1,81 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2002-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +-module(erl_ext_SUITE). + +-include("test_server.hrl"). +-include("erl_ext_SUITE_data/ext_test_cases.hrl"). + +-export([ + all/1, + compare_tuple/1, + compare_list/1, + compare_string/1, + compare_list_string/1, + compare_nc_ext/1 + ]). + +-import(runner, [get_term/1]). + +all(suite) -> [ + compare_tuple, + compare_list, + compare_string, + compare_list_string, + compare_nc_ext + ]. + +compare_tuple(suite) -> []; +compare_tuple(doc) -> []; +compare_tuple(Config) when is_list(Config) -> + ?line P = runner:start(?compare_tuple), + ?line runner:recv_eot(P), + ok. + +compare_list(suite) -> []; +compare_list(doc) -> []; +compare_list(Config) when is_list(Config) -> + ?line P = runner:start(?compare_list), + ?line runner:recv_eot(P), + ok. + +compare_string(suite) -> []; +compare_string(doc) -> []; +compare_string(Config) when is_list(Config) -> + ?line P = runner:start(?compare_string), + ?line runner:recv_eot(P), + ok. + +compare_list_string(suite) -> []; +compare_list_string(doc) -> []; +compare_list_string(Config) when is_list(Config) -> + ?line P = runner:start(?compare_list_string), + ?line runner:recv_eot(P), + ok. + +compare_nc_ext(suite) -> []; +compare_nc_ext(doc) -> []; +compare_nc_ext(Config) when is_list(Config) -> + ?line P = runner:start(?compare_nc_ext), + ?line runner:recv_eot(P), + ok. + + + diff --git a/lib/erl_interface/test/erl_ext_SUITE_data/Makefile.first b/lib/erl_interface/test/erl_ext_SUITE_data/Makefile.first new file mode 100644 index 0000000000..cb7b12cc79 --- /dev/null +++ b/lib/erl_interface/test/erl_ext_SUITE_data/Makefile.first @@ -0,0 +1,21 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2002-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# + +ext_test_decl.c: ext_test.c + erl -noinput -pa ../all_SUITE_data -s init_tc run ext_test -s erlang halt diff --git a/lib/erl_interface/test/erl_ext_SUITE_data/Makefile.src b/lib/erl_interface/test/erl_ext_SUITE_data/Makefile.src new file mode 100644 index 0000000000..6f363ccd6f --- /dev/null +++ b/lib/erl_interface/test/erl_ext_SUITE_data/Makefile.src @@ -0,0 +1,41 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2002-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# + +include @erl_interface_mk_include@@[email protected] + +CC0 = @CC@ +CC = ..@DS@all_SUITE_data@DS@gccifier@exe@ -CC"$(CC0)" +LD = @LD@ +LIBPATH = @erl_interface_libpath@ +LIBERL = $(LIBPATH)/@erl_interface_lib@ +LIBEI = $(LIBPATH)/@erl_interface_eilib@ +LIBFLAGS = ../all_SUITE_data/runner@obj@ \ + $(LIBERL) $(LIBEI) @LIBS@ @erl_interface_sock_libs@ \ + @erl_interface_threadlib@ +CFLAGS = @EI_CFLAGS@ $(THR_DEFS) -I@erl_interface_include@ -I../all_SUITE_data +EXT_OBJS = ext_test@obj@ ext_test_decl@obj@ + +all: ext_test@exe@ + +clean: + $(RM) $(EXT_OBJS) + $(RM) ext_test@exe@ + +ext_test@exe@: $(EXT_OBJS) $(LIBERL) $(LIBEI) + $(LD) @CROSSLDFLAGS@ -o $@ $(EXT_OBJS) $(LIBFLAGS) diff --git a/lib/erl_interface/test/erl_ext_SUITE_data/ext_test.c b/lib/erl_interface/test/erl_ext_SUITE_data/ext_test.c new file mode 100644 index 0000000000..ba1a6c66da --- /dev/null +++ b/lib/erl_interface/test/erl_ext_SUITE_data/ext_test.c @@ -0,0 +1,485 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2002-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + + */ +/* + * Author: Rickard Green + * Modified: Bj�rn-Egil Dahlberg + * - compare_tuple + * - compare_string + * - compare_list + * - compare_list and string + */ + +#include "runner.h" +#include "erl_interface.h" +#include <stdio.h> +#include <string.h> + +typedef unsigned int uint; + +#define MAX_NC_EXT_SIZE 100 + +static unsigned char * +write_pid(unsigned char *buf, char *node, uint cre, uint ser, uint num); +static unsigned char * +write_port(unsigned char *buf, char *node, uint cre, uint id); +static unsigned char * +write_ref(unsigned char *buf, char *node, uint cre, uint id[], uint no_ids); +static void +test_compare_ext(char *test_desc, + unsigned char *ext1, + unsigned char *end_ext1, + unsigned char *ext2, + unsigned char *end_ext2, + int exp_res); + +/* + * Test erl_compare_ext with tuples + */ +TESTCASE(compare_tuple) { + // erlang:term_to_binary ({'b'}) + unsigned char term1[] = { 131, 104, 1, 100, 0, 1, 98 }; + // erlang:term_to_binary ({'a', 'a'}) + unsigned char term2[] = { 131, 104, 2, 100, 0, 1, 97, 100, 0, 1, 97 }; + unsigned char *start_a, *start_b, *end_a, *end_b; + + erl_init(NULL, 0); + start_a = term1; + start_b = term2; + end_a = term1 + 7; + end_b = term2 + 11; + + test_compare_ext("tuples", start_a, end_a, start_b, end_b, -1); + + report(1); +} + +/* + * Test erl_compare_ext with lists + */ + +TESTCASE(compare_list) { + unsigned char *start_a, *start_b, *end_a, *end_b; + // erlang:term_to_binary([a,b,[],3412]) + unsigned char term1[] = {131,108,0,0,0,4,100,0,1,97,100,0,1,98,106,98,0,0,13,84,106}; + // erlang:term_to_binary([34,{a,n},a,erlang]) + unsigned char term2[] = {131,108,0,0,0,4,97,34,104,2,100,0,1,97,100,0,1,110,100,0,1,97,100,0,6,101,114,108,97,110,103,106}; + + erl_init(NULL, 0); + start_a = term1; + start_b = term2; + end_a = term1 + 21; + end_b = term2 + 32; + + test_compare_ext("lists", start_a, end_a, start_b, end_b, 1); + + report(1); +} + +/* + * Test erl_compare_ext with strings + */ + +TESTCASE(compare_string) { + unsigned char *start_a, *start_b, *end_a, *end_b; + // erlang:term_to_binary("hej") + unsigned char term1[] = {131,107,0,3,104,101,106}; + // erlang:term_to_binary("erlang") + unsigned char term2[] = {131,107,0,6,101,114,108,97,110,103}; + + erl_init(NULL, 0); + start_a = term1; + start_b = term2; + end_a = term1 + 7; + end_b = term2 + 10; + + test_compare_ext("strings", start_a, end_a, start_b, end_b, 1); + + report(1); +} + +/* + * Test erl_compare_ext with lists and strings + */ + +TESTCASE(compare_list_string) { + unsigned char *start_a, *start_b, *end_a, *end_b; + // erlang:term_to_binary("hej") + unsigned char term1[] = {131,107,0,3,104,101,106}; + // erlang:term_to_binary([a,b,[],3412]) + unsigned char term2[] = {131,108,0,0,0,4,100,0,1,97,100,0,1,98,106,98,0,0,13,84,106}; + + erl_init(NULL, 0); + start_a = term1; + start_b = term2; + end_a = term1 + 7; + end_b = term2 + 21; + + test_compare_ext("strings", start_a, end_a, start_b, end_b, -1); + + report(1); +} + + + +/* + * Test erl_compare_ext with node containers + */ +TESTCASE(compare_nc_ext) +{ + int res; + unsigned char buf_a[MAX_NC_EXT_SIZE], buf_b[MAX_NC_EXT_SIZE]; + unsigned char *end_a, *end_b; + uint id[3]; + + erl_init(NULL, 0); + + + /* + * Test pids ---------------------------------------------------- + * + * Significance (most -> least): + * nodename, creation, serial, number, nodename, creation + * + */ + + end_a = write_pid(buf_a, "b@b", 2, 4711, 1); + + end_b = write_pid(buf_b, "a@b", 1, 4710, 2); + test_compare_ext("pid test 1", buf_a, end_a, buf_b, end_b, -1); + + end_b = write_pid(buf_b, "a@b", 1, 4712, 1); + test_compare_ext("pid test 2", buf_a, end_a, buf_b, end_b, -1); + + end_b = write_pid(buf_b, "c@b", 1, 4711, 1); + test_compare_ext("pid test 3", buf_a, end_a, buf_b, end_b, -1); + + end_b = write_pid(buf_b, "b@b", 3, 4711, 1); + test_compare_ext("pid test 4", buf_a, end_a, buf_b, end_b, -1); + + end_b = write_pid(buf_b, "b@b", 2, 4711, 1); + test_compare_ext("pid test 5", buf_a, end_a, buf_b, end_b, 0); + + + /* + * Test ports --------------------------------------------------- + * + * Significance (most -> least): + * nodename, creation, number + * + * OBS: Comparison between ports has changed in R9. This + * since it wasn't stable in R8 (and eariler releases). + * Significance used to be: dist_slot, number, + * creation. + */ + + end_a = write_port(buf_a, "b@b", 2, 4711), + + end_b = write_port(buf_b, "c@b", 1, 4710); + test_compare_ext("port test 1", buf_a, end_a, buf_b, end_b, -1); + + end_b = write_port(buf_b, "b@b", 3, 4710); + test_compare_ext("port test 2", buf_a, end_a, buf_b, end_b, -1); + + end_b = write_port(buf_b, "b@b", 2, 4712); + test_compare_ext("port test 3", buf_a, end_a, buf_b, end_b, -1); + + end_b = write_port(buf_b, "b@b", 2, 4711); + test_compare_ext("port test 4", buf_a, end_a, buf_b, end_b, 0); + + /* + * Test refs ---------------------------------------------------- + * Significance (most -> least): + * nodename, creation, (number high, number mid), number low, + * + * OBS: Comparison between refs has changed in R9. This + * since it wasn't stable in R8 (and eariler releases). + * Significance used to be: dist_slot, number, + * creation. + * + */ + + /* Long & Long */ + + id[0] = 4711; id[1] = 4711, id[2] = 4711; + end_a = write_ref(buf_a, "b@b", 2, id, 3); + + + id[0] = 4710; id[1] = 4710; id[2] = 4710; + end_b = write_ref(buf_b, "c@b", 1, id, 3); + test_compare_ext("ref test 1", buf_a, end_a, buf_b, end_b, -1); + + id[0] = 4710; id[1] = 4710; id[2] = 4710; + end_b = write_ref(buf_b, "b@b", 3, id, 3); + test_compare_ext("ref test 2", buf_a, end_a, buf_b, end_b, -1); + + id[0] = 4710; id[1] = 4710; id[2] = 4712; + end_b = write_ref(buf_b, "b@b", 2, id, 3); + test_compare_ext("ref test 3", buf_a, end_a, buf_b, end_b, -1); + + id[0] = 4710; id[1] = 4712; id[2] = 4711; + end_b = write_ref(buf_b, "b@b", 2, id, 3); + test_compare_ext("ref test 4", buf_a, end_a, buf_b, end_b, -1); + + id[0] = 4712; id[1] = 4711; id[2] = 4711; + end_b = write_ref(buf_b, "b@b", 2, id, 3); + test_compare_ext("ref test 5", buf_a, end_a, buf_b, end_b, -1); + + id[0] = 4711; id[1] = 4711; id[2] = 4711; + end_b = write_ref(buf_b, "b@b", 2, id, 3); + test_compare_ext("ref test 6", buf_a, end_a, buf_b, end_b, 0); + + /* Long & Short */ + id[0] = 4711; id[1] = 0, id[2] = 0; + end_a = write_ref(buf_a, "b@b", 2, id, 3); + + + id[0] = 4710; + end_b = write_ref(buf_b, "c@b", 1, id, 1); + test_compare_ext("ref test 7", buf_a, end_a, buf_b, end_b, -1); + + id[0] = 4710; + end_b = write_ref(buf_b, "b@b", 3, id, 1); + test_compare_ext("ref test 8", buf_a, end_a, buf_b, end_b, -1); + + id[0] = 4712; + end_b = write_ref(buf_b, "b@b", 2, id, 1); + test_compare_ext("ref test 9", buf_a, end_a, buf_b, end_b, -1); + + id[0] = 4711; + end_b = write_ref(buf_b, "b@b", 2, id, 1); + test_compare_ext("ref test 10", buf_a, end_a, buf_b, end_b, 0); + + /* Short & Long */ + id[0] = 4711; + end_a = write_ref(buf_a, "b@b", 2, id, 1); + + + id[0] = 4710; id[1] = 0, id[2] = 0; + end_b = write_ref(buf_b, "c@b", 1, id, 3); + test_compare_ext("ref test 11", buf_a, end_a, buf_b, end_b, -1); + + id[0] = 4710; id[1] = 0, id[2] = 0; + end_b = write_ref(buf_b, "b@b", 3, id, 3); + test_compare_ext("ref test 12", buf_a, end_a, buf_b, end_b, -1); + + id[0] = 4712; id[1] = 0, id[2] = 0; + end_b = write_ref(buf_b, "b@b", 2, id, 3); + test_compare_ext("ref test 13", buf_a, end_a, buf_b, end_b, -1); + + id[0] = 4711; id[1] = 0, id[2] = 0; + end_b = write_ref(buf_b, "b@b", 2, id, 3); + test_compare_ext("ref test 14", buf_a, end_a, buf_b, end_b, 0); + + /* Short & Short */ + id[0] = 4711; + end_a = write_ref(buf_a, "b@b", 2, id, 1); + + + id[0] = 4710; + end_b = write_ref(buf_b, "c@b", 1, id, 1); + test_compare_ext("ref test 15", buf_a, end_a, buf_b, end_b, -1); + + id[0] = 4710; + end_b = write_ref(buf_b, "b@b", 3, id, 1); + test_compare_ext("ref test 16", buf_a, end_a, buf_b, end_b, -1); + + id[0] = 4712; + end_b = write_ref(buf_b, "b@b", 2, id, 1); + test_compare_ext("ref test 17", buf_a, end_a, buf_b, end_b, -1); + + id[0] = 4711; + end_b = write_ref(buf_b, "b@b", 2, id, 1); + test_compare_ext("ref test 18", buf_a, end_a, buf_b, end_b, 0); + + report(1); +} + +static void +test_compare_ext(char *test_desc, + unsigned char *ext1, + unsigned char *end_ext1, + unsigned char *ext2, + unsigned char *end_ext2, + int exp_res) +{ + int er, ar; + unsigned char *e1, *e2; + int reversed_args; + char ext_str[MAX_NC_EXT_SIZE*4 + 1]; + char *es; + + message("*** %s ***", test_desc); + message(" erl_compare_ext() arguments:", test_desc); + + es = &ext_str[0]; + + e1 = ext1; + while (e1 < end_ext1) + es += sprintf(es, "%d,", *(e1++)); + *(--es) = '\0'; + message(" e1 = <<%s>>", ext_str); + + + es = &ext_str[0]; + + e2 = ext2; + while (e2 < end_ext2) + es += sprintf(es, "%d,", *(e2++)); + *(--es) = '\0'; + message(" e2 = <<%s>>", ext_str); + + message("Starting %s...", test_desc); + + + reversed_args = 0; + er = exp_res; + e1 = ext1; + e2 = ext2; + + reversed_args_start: + + ar = erl_compare_ext(e1, e2); + if (er < 0) { + if (ar > 0) + fail("expected result e1 < e2; actual result e1 > e2\n"); + else if (ar == 0) + fail("expected result e1 < e2; actual result e1 = e2\n"); + } + else if (er > 0) { + if (ar < 0) + fail("expected result e1 > e2; actual result e1 < e2\n"); + else if (ar == 0) + fail("expected result e1 > e2; actual result e1 = e2\n"); + } + else { + if (ar > 0) + fail("expected result e1 = e2; actual result e1 > e2\n"); + else if (ar < 0) + fail("expected result e1 = e2; actual result e1 < e2\n"); + } + + message("%s", "SUCCEEDED!"); + if (!reversed_args) { + message("Starting %s with reversed arguments...", test_desc); + e2 = ext1; + e1 = ext2; + if (exp_res < 0) + er = 1; + else if (exp_res > 0) + er = -1; + reversed_args = 1; + goto reversed_args_start; + } + + message("%s", ""); + +} + + +#define ATOM_EXT (100) +#define REFERENCE_EXT (101) +#define PORT_EXT (102) +#define PID_EXT (103) +#define NEW_REFERENCE_EXT (114) + + +#define PUT_UINT16(E, X) ((E)[0] = ((X) >> 8) & 0xff, \ + (E)[1] = (X) & 0xff) + +#define PUT_UINT32(E, X) ((E)[0] = ((X) >> 24) & 0xff, \ + (E)[1] = ((X) >> 16) & 0xff, \ + (E)[2] = ((X) >> 8) & 0xff, \ + (E)[3] = (X) & 0xff) + +static unsigned char * +write_atom(unsigned char *buf, char *atom) +{ + uint len; + + len = 0; + while(atom[len]) { + buf[len + 3] = atom[len]; + len++; + } + buf[0] = ATOM_EXT; + PUT_UINT16(&buf[1], len); + + return buf + 3 + len; +} + +static unsigned char * +write_pid(unsigned char *buf, char *node, uint cre, uint num, uint ser) +{ + unsigned char *e = buf; + + *(e++) = PID_EXT; + e = write_atom(e, node); + PUT_UINT32(e, num & ((1 << 15) - 1)); + e += 4; + PUT_UINT32(e, ser & ((1 << 3) - 1)); + e += 4; + *(e++) = cre & ((1 << 2) - 1); + + return e; +} + +static unsigned char * +write_port(unsigned char *buf, char *node, uint cre, uint id) +{ + unsigned char *e = buf; + + *(e++) = PORT_EXT; + e = write_atom(e, node); + PUT_UINT32(e, id & ((1 << 15) - 1)); + e += 4; + *(e++) = cre & ((1 << 2) - 1); + + return e; +} + +static unsigned char * +write_ref(unsigned char *buf, char *node, uint cre, uint id[], uint no_ids) +{ + int i; + unsigned char *e = buf; + + if (no_ids == 1) { + *(e++) = REFERENCE_EXT; + e = write_atom(e, node); + PUT_UINT32(e, id[0] & ((1 << 15) - 1)); + e += 4; + *(e++) = cre & ((1 << 2) - 1); + } + else { + *(e++) = NEW_REFERENCE_EXT; + PUT_UINT16(e, no_ids); + e += 2; + e = write_atom(e, node); + *(e++) = cre & ((1 << 2) - 1); + for (i = 0; i < no_ids; i++) { + PUT_UINT32(e, id[i]); + e += 4; + } + } + + return e; +} + diff --git a/lib/erl_interface/test/erl_format_SUITE.erl b/lib/erl_interface/test/erl_format_SUITE.erl new file mode 100644 index 0000000000..81a0bca80f --- /dev/null +++ b/lib/erl_interface/test/erl_format_SUITE.erl @@ -0,0 +1,136 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1997-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +-module(erl_format_SUITE). + +-include("test_server.hrl"). +-include("erl_format_SUITE_data/format_test_cases.hrl"). + +-export([all/1, atoms/1, tuples/1, lists/1]). + +-import(runner, [get_term/1]). + +%% This test suite test the erl_format() function. +%% It uses the port program "format_test". + +all(suite) -> [atoms, tuples, lists]. + +%% Tests formatting various atoms. + +atoms(suite) -> []; +atoms(Config) when is_list(Config) -> + ?line P = runner:start(?atoms), + + ?line {term, ''} = get_term(P), + ?line {term, 'a'} = get_term(P), + ?line {term, 'A'} = get_term(P), + ?line {term, 'abc'} = get_term(P), + ?line {term, 'Abc'} = get_term(P), + ?line {term, 'ab@c'} = get_term(P), + ?line {term, 'The rain in Spain stays mainly in the plains'} = + get_term(P), + + ?line {term, a} = get_term(P), + ?line {term, ab} = get_term(P), + ?line {term, abc} = get_term(P), + ?line {term, ab@c} = get_term(P), + ?line {term, abcdefghijklmnopq} = get_term(P), + + ?line {term, ''} = get_term(P), + ?line {term, 'a'} = get_term(P), + ?line {term, 'A'} = get_term(P), + ?line {term, 'abc'} = get_term(P), + ?line {term, 'Abc'} = get_term(P), + ?line {term, 'ab@c'} = get_term(P), + ?line {term, 'The rain in Spain stays mainly in the plains'} = + get_term(P), + + ?line {term, a} = get_term(P), + ?line {term, ab} = get_term(P), + ?line {term, abc} = get_term(P), + ?line {term, ab@c} = get_term(P), + ?line {term, ' abcdefghijklmnopq '} = get_term(P), + + ?line runner:recv_eot(P), + ok. + + + +%% Tests formatting various tuples + +tuples(suite) -> []; +tuples(Config) when is_list(Config) -> + ?line P = runner:start(?tuples), + + ?line {term, {}} = get_term(P), + ?line {term, {a}} = get_term(P), + ?line {term, {a, b}} = get_term(P), + ?line {term, {a, b, c}} = get_term(P), + ?line {term, {1}} = get_term(P), + ?line {term, {[]}} = get_term(P), + ?line {term, {[], []}} = get_term(P), + ?line {term, {[], a, b, c}} = get_term(P), + ?line {term, {[], a, [], b, c}} = get_term(P), + ?line {term, {[], a, '', b, c}} = get_term(P), + + ?line runner:recv_eot(P), + ok. + + + +%% Tests formatting various lists + +lists(suite) -> []; +lists(Config) when is_list(Config) -> + ?line P = runner:start(?lists), + + ?line {term, []} = get_term(P), + ?line {term, [a]} = get_term(P), + ?line {term, [a, b]} = get_term(P), + ?line {term, [a, b, c]} = get_term(P), + ?line {term, [1]} = get_term(P), + ?line {term, [[]]} = get_term(P), + ?line {term, [[], []]} = get_term(P), + ?line {term, [[], a, b, c]} = get_term(P), + ?line {term, [[], a, [], b, c]} = get_term(P), + ?line {term, [[], a, '', b, c]} = get_term(P), + + ?line {term, [{name, 'Madonna'}, {age, 21}, {data, [{addr, "E-street", 42}]}]} = + get_term(P), + case os:type() of + vxworks -> + ?line {term, [{pi, _}, {'cos(70)', _}]} = get_term(P), + ?line {term, [[pi, _], ['cos(70)', _]]} = get_term(P), + ?line {term, [[pi, _], [], ["cos(70)", _]]} = + get_term(P); + _ -> + ?line {term, [{pi, 3.1415}, {'cos(70)', 0.34202}]} = get_term(P), + ?line {term, [[pi, 3.1415], ['cos(70)', 0.34202]]} = get_term(P), + ?line {term, [[pi, 3.1415], [], ["cos(70)", 0.34202]]} = + get_term(P) + end, + + ?line {term, [-1]} = get_term(P), + + ?line runner:recv_eot(P), + ok. + + + diff --git a/lib/erl_interface/test/erl_format_SUITE_data/Makefile.first b/lib/erl_interface/test/erl_format_SUITE_data/Makefile.first new file mode 100644 index 0000000000..2cd313a324 --- /dev/null +++ b/lib/erl_interface/test/erl_format_SUITE_data/Makefile.first @@ -0,0 +1,21 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2000-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# + +format_test_decl.c: format_test.c + erl -noinput -pa ../all_SUITE_data -s init_tc run format_test -s erlang halt diff --git a/lib/erl_interface/test/erl_format_SUITE_data/Makefile.src b/lib/erl_interface/test/erl_format_SUITE_data/Makefile.src new file mode 100644 index 0000000000..0cd1ab512d --- /dev/null +++ b/lib/erl_interface/test/erl_format_SUITE_data/Makefile.src @@ -0,0 +1,43 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 1997-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# + +include @erl_interface_mk_include@@[email protected] + +CC0 = @CC@ +CC = ..@DS@all_SUITE_data@DS@gccifier@exe@ -CC"$(CC0)" +LD = @LD@ +LIBPATH = @erl_interface_libpath@ +LIBERL = $(LIBPATH)/@erl_interface_lib@ +LIBEI = $(LIBPATH)/@erl_interface_eilib@ +LIBFLAGS = ../all_SUITE_data/runner@obj@ \ + $(LIBERL) $(LIBEI) @LIBS@ @erl_interface_sock_libs@ \ + @erl_interface_threadlib@ +CFLAGS = @EI_CFLAGS@ $(THR_DEFS) -I@erl_interface_include@ -I../all_SUITE_data +FORMAT_OBJS = format_test@obj@ format_test_decl@obj@ + +all: format_test@exe@ + +clean: + $(RM) $(FORMAT_OBJS) + $(RM) format_test@exe@ + +format_test@exe@: $(FORMAT_OBJS) $(LIBERL) $(LIBEI) + $(LD) @CROSSLDFLAGS@ -o $@ $(FORMAT_OBJS) $(LIBFLAGS) + + diff --git a/lib/erl_interface/test/erl_format_SUITE_data/format_test.c b/lib/erl_interface/test/erl_format_SUITE_data/format_test.c new file mode 100644 index 0000000000..75e73b6df5 --- /dev/null +++ b/lib/erl_interface/test/erl_format_SUITE_data/format_test.c @@ -0,0 +1,132 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1997-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ + +#include "runner.h" + +/* + * Purpose: Tests the erl_format() function. + * Author: Bjorn Gustavsson + */ + +static void +send_format(char* format) +{ + send_term(erl_format(format)); +} + +TESTCASE(atoms) +{ + erl_init(NULL, 0); + + send_format("''"); + send_format("'a'"); + send_format("'A'"); + send_format("'abc'"); + send_format("'Abc'"); + send_format("'ab@c'"); + send_format("'The rain in Spain stays mainly in the plains'"); + + send_format("a"); + send_format("ab"); + send_format("abc"); + send_format("ab@c"); + send_format(" abcdefghijklmnopq "); + + send_term(erl_format("~a", "")); + send_term(erl_format("~a", "a")); + send_term(erl_format("~a", "A")); + send_term(erl_format("~a", "abc")); + send_term(erl_format("~a", "Abc")); + send_term(erl_format("~a", "ab@c")); + send_term(erl_format("~a", "The rain in Spain stays mainly in the plains")); + + send_term(erl_format("~a", "a")); + send_term(erl_format("~a", "ab")); + send_term(erl_format("~a", "abc")); + send_term(erl_format("~a","ab@c")); + send_term(erl_format("~a", " abcdefghijklmnopq ")); + + + report(1); +} + +TESTCASE(tuples) +{ + erl_init(NULL, 0); + + send_format("{}"); + send_format("{a}"); + send_format("{a, b}"); + send_format("{a, b, c}"); + send_format("{1}"); + send_format("{[]}"); + send_format("{[], []}"); + send_format("{[], a, b, c}"); + send_format("{[], a, [], b, c}"); + send_format("{[], a, '', b, c}"); + + report(1); +} + + + +TESTCASE(lists) +{ + ETERM* a; + ETERM* b; + ETERM* c; + + erl_init(NULL, 0); + + send_format("[]"); + send_format("[a]"); + send_format("[a, b]"); + send_format("[a, b, c]"); + send_format("[1]"); + send_format("[[]]"); + send_format("[[], []]"); + send_format("[[], a, b, c]"); + send_format("[[], a, [], b, c]"); + send_format("[[], a, '', b, c]"); + + b = erl_format("[{addr, ~s, ~i}]", "E-street", 42); + a = erl_format("[{name, ~a}, {age, ~i}, {data, ~w}]", "Madonna", 21, b); + send_term(a); + erl_free_term(b); + + send_term(erl_format("[{pi, ~f}, {'cos(70)', ~f}]", 3.1415, 0.34202)); + + a = erl_mk_float(3.1415); + b = erl_mk_float(0.34202); + send_term(erl_format("[[pi, ~w], ['cos(70)', ~w]]", a, b)); + erl_free_term(a); + erl_free_term(b); + + a = erl_mk_float(3.1415); + b = erl_mk_float(0.34202); + c = erl_mk_empty_list(); + send_term(erl_format("[[~a, ~w], ~w, [~s, ~w]]", "pi", a, c, "cos(70)", b)); + erl_free_term(a); + erl_free_term(b); + erl_free_term(c); + + send_term(erl_format("[~i]", -1)); + + report(1); +} diff --git a/lib/erl_interface/test/erl_interface.dynspec b/lib/erl_interface/test/erl_interface.dynspec new file mode 100644 index 0000000000..8af5040d97 --- /dev/null +++ b/lib/erl_interface/test/erl_interface.dynspec @@ -0,0 +1,18 @@ +%% -*- erlang -*- +%% You can test this file using this command. +%% file:script("erl_interface.dynspec", [{'TestCCompiler',{msc | gnuc, undefined}}]). + +case {TestCCompiler, erlang:system_info(c_compiler_used)} of + {{CC, _}, {CC, _}} -> + []; + {{CC1, _}, {CC2, _}} when CC1 == msc; CC2 == msc -> + Comment = + "OTP's static C libraries (compiled with " + ++ atom_to_list(CC2) ++ ") aren't compatible " + "with the C compiler (" ++ atom_to_list(CC1) + ++ ") used for testing.", + StaticLibSuites = [all_SUITE], + lists:map(fun (Suite) -> {skip,{Suite, Comment}} end, StaticLibSuites); + {{CC1, _}, {CC2, _}} -> + [] +end. diff --git a/lib/erl_interface/test/erl_interface.spec b/lib/erl_interface/test/erl_interface.spec new file mode 100644 index 0000000000..2789bd3e2c --- /dev/null +++ b/lib/erl_interface/test/erl_interface.spec @@ -0,0 +1,2 @@ +{topcase, {dir, "../erl_interface_test"}}. + diff --git a/lib/erl_interface/test/erl_interface.spec.vxworks b/lib/erl_interface/test/erl_interface.spec.vxworks new file mode 100644 index 0000000000..7089b3d447 --- /dev/null +++ b/lib/erl_interface/test/erl_interface.spec.vxworks @@ -0,0 +1,5 @@ +{topcase, {dir, "../erl_interface_test"}}. +{skip,{ei_accept_SUITE, ei_threaded_accept, + "Threaded test not yet implemented - FIXME"}}. +{skip,{ei_connect_SUITE, ei_threaded_send, + "Threaded test not yet implemented - FIXME"}}. diff --git a/lib/erl_interface/test/erl_match_SUITE.erl b/lib/erl_interface/test/erl_match_SUITE.erl new file mode 100644 index 0000000000..f506638544 --- /dev/null +++ b/lib/erl_interface/test/erl_match_SUITE.erl @@ -0,0 +1,288 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1997-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +-module(erl_match_SUITE). + +-include("test_server.hrl"). +-include("erl_match_SUITE_data/match_test_cases.hrl"). + +-export([all/1, atoms/1, lists/1, tuples/1, references/1, pids/1, ports/1, + bind/1, integers/1, floats/1, binaries/1, strings/1]). + +%% For interactive running of matcher. +-export([start_matcher/0, erl_match/3]). + +%% This test suite tests the erl_match() function. + +all(suite) -> [atoms, lists, tuples, references, pids, ports, bind, + integers, floats, binaries, strings]. + +atoms(suite) -> []; +atoms(Config) when is_list(Config) -> + ?line P = start_matcher(), + + ?line eq(P, '', ''), + ?line eq(P, a, a), + ?line ne(P, a, b), + ?line ne(P, a, aa), + ?line eq(P, kalle, kalle), + ?line ne(P, kalle, arne), + + ?line ne(P, kalle, 42), + ?line ne(P, 42, kalle), + + ?line runner:finish(P), + ok. + +lists(suite) -> []; +lists(Config) when is_list(Config) -> + ?line P = start_matcher(), + ?line eq(P, [], []), + + ?line ne(P, [], [a]), + ?line ne(P, [a], []), + + ?line eq(P, [a], [a]), + ?line ne(P, [a], [b]), + + ?line eq(P, [a|b], [a|b]), + ?line ne(P, [a|b], [a|x]), + + ?line eq(P, [a, b], [a, b]), + ?line ne(P, [a, b], [a, x]), + + ?line eq(P, [a, b, c], [a, b, c]), + ?line ne(P, [a, b|c], [a, b|x]), + ?line ne(P, [a, b, c], [a, b, x]), + ?line ne(P, [a, b|c], [a, b|x]), + ?line ne(P, [a, x|c], [a, b|c]), + ?line ne(P, [a, b, c], [a, x, c]), + + ?line runner:finish(P), + ok. + +tuples(suite) -> []; +tuples(Config) when is_list(Config) -> + ?line P = start_matcher(), + + ?line ne(P, {}, {a, b}), + ?line ne(P, {a, b}, {}), + ?line ne(P, {a}, {a, b}), + ?line ne(P, {a, b}, {a}), + + ?line eq(P, {}, {}), + + ?line eq(P, {a}, {a}), + ?line ne(P, {a}, {b}), + + ?line eq(P, {1}, {1}), + ?line ne(P, {1}, {2}), + + ?line eq(P, {a, b}, {a, b}), + ?line ne(P, {x, b}, {a, b}), + + ?line ne(P, {error, x}, {error, y}), + ?line ne(P, {error, {undefined, {subscriber, last}}}, + {error, {undefined, {subscriber, name}}}), + + ?line runner:finish(P), + ok. + + +references(suite) -> []; +references(Config) when is_list(Config) -> + ?line P = start_matcher(), + ?line Ref1 = make_ref(), + ?line Ref2 = make_ref(), + + ?line eq(P, Ref1, Ref1), + ?line eq(P, Ref2, Ref2), + ?line ne(P, Ref1, Ref2), + ?line ne(P, Ref2, Ref1), + + ?line runner:finish(P), + ok. + + +pids(suite) -> []; +pids(Config) when is_list(Config) -> + ?line P = start_matcher(), + ?line Pid1 = c:pid(0,1,2), + ?line Pid2 = c:pid(0,1,3), + + ?line eq(P, self(), self()), + ?line eq(P, Pid1, Pid1), + ?line ne(P, Pid1, self()), + ?line ne(P, Pid2, Pid1), + + ?line runner:finish(P), + ok. + + +ports(suite) -> []; +ports(Config) when is_list(Config) -> + case os:type() of + vxworks -> + {skipped,"not on vxworks, pucko"}; + _ -> + ?line P = start_matcher(), + ?line P2 = start_matcher(), + + ?line eq(P, P, P), + ?line ne(P, P, P2), + + ?line runner:finish(P), + ?line runner:finish(P2), + ok + end. + +integers(suite) -> []; +integers(Config) when is_list(Config) -> + ?line P = start_matcher(), + ?line I1 = 123, + ?line I2 = 12345, + ?line I3 = -123, + ?line I4 = 2234, + + ?line eq(P, I1, I1), + ?line eq(P, I2, I2), + ?line ne(P, I1, I2), + ?line ne(P, I1, I3), + ?line eq(P, I4, I4), + + ?line runner:finish(P), + ok. + + + +floats(suite) -> []; +floats(Config) when is_list(Config) -> + ?line P = start_matcher(), + ?line F1 = 3.1414, + ?line F2 = 3.1415, + ?line F3 = 3.1416, + + ?line S1 = "string", + ?line S2 = "string2", + + ?line eq(P, F1, F1), + ?line eq(P, F2, F2), + ?line ne(P, F1, F2), + ?line ne(P, F3, F2), + + ?line eq(P, S2, S2), + ?line ne(P, S1, S2), + + ?line runner:finish(P), + ok. + + + +binaries(suite) -> []; +binaries(Config) when is_list(Config) -> + ?line P = start_matcher(), + ?line Bin1 = term_to_binary({kalle, 146015, {kungsgatan, 23}}), + ?line Bin2 = term_to_binary(sune), + ?line Bin3 = list_to_binary("sune"), + + ?line eq(P, Bin1, Bin1), + ?line eq(P, Bin2, Bin2), + ?line eq(P, Bin3, Bin3), + ?line ne(P, Bin1, Bin2), + ?line ne(P, Bin1, Bin3), + ?line ne(P, Bin2, Bin3), + + ?line runner:finish(P), + ok. + + + +strings(suite) -> []; +strings(Config) when is_list(Config) -> + ?line P = start_matcher(), + + ?line S1 = "string", + ?line S2 = "streng", + ?line S3 = "String", + + ?line eq(P, S1, S1), + ?line ne(P, S1, S2), + ?line ne(P, S1, S3), + + ?line runner:finish(P), + ok. + + + +bind(suite) -> []; +bind(Config) when is_list(Config) -> + ?line P = start_bind(), + ?line S = "[X,Y,Z]", + ?line L1 = [301,302,302], + ?line L2 = [65,66,67], + + ?line bind_ok(P, S, L1), + ?line bind_ok(P, S, L2), + + ?line runner:finish(P), + ok. + +start_bind() -> + runner:start(?erl_match_bind). + +bind_ok(Port, Bind, Term) -> + true = erl_bind(Port, Bind, Term). + +%bind_nok(Port, Bind, Term) -> +% false = erl_bind(Port, Bind, Term). + +erl_bind(Port, Pattern, Term) -> + Port ! {self(), {command, [$b, Pattern, 0]}}, + runner:send_term(Port, Term), + case runner:get_term(Port) of + {term, 0} -> false; + {term, 1} -> true + end. + + + + + + +start_matcher() -> + runner:start(?erl_match_server). + +eq(Port, Pattern, Term) -> + true = erl_match(Port, Pattern, Term). + +ne(Port, Pattern, Term) -> + false = erl_match(Port, Pattern, Term). + + + +erl_match(Port, Pattern, Term) -> + runner:send_term(Port, Pattern), + runner:send_term(Port, Term), + case runner:get_term(Port) of + {term, 0} -> false; + {term, 1} -> true + end. + + diff --git a/lib/erl_interface/test/erl_match_SUITE_data/Makefile.first b/lib/erl_interface/test/erl_match_SUITE_data/Makefile.first new file mode 100644 index 0000000000..12141d210c --- /dev/null +++ b/lib/erl_interface/test/erl_match_SUITE_data/Makefile.first @@ -0,0 +1,21 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2000-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# + +match_test_decl.c: match_test.c + erl -noinput -pa ../all_SUITE_data -s init_tc run match_test -s erlang halt diff --git a/lib/erl_interface/test/erl_match_SUITE_data/Makefile.src b/lib/erl_interface/test/erl_match_SUITE_data/Makefile.src new file mode 100644 index 0000000000..8ce6c9c985 --- /dev/null +++ b/lib/erl_interface/test/erl_match_SUITE_data/Makefile.src @@ -0,0 +1,42 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 1997-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# + +include @erl_interface_mk_include@@[email protected] + +CC0 = @CC@ +CC = ..@DS@all_SUITE_data@DS@gccifier@exe@ -CC"$(CC0)" +LD = @LD@ +LIBPATH = @erl_interface_libpath@ +LIBERL = $(LIBPATH)/@erl_interface_lib@ +LIBEI = $(LIBPATH)/@erl_interface_eilib@ +LIBFLAGS = ../all_SUITE_data/runner@obj@ \ + $(LIBERL) $(LIBEI) @LIBS@ @erl_interface_sock_libs@ \ + @erl_interface_threadlib@ +CFLAGS = @EI_CFLAGS@ $(THR_DEFS) -I@erl_interface_include@ -I../all_SUITE_data +MATCH_OBJS = match_test@obj@ match_test_decl@obj@ + +all: match_test@exe@ + +clean: + $(RM) $(MATCH_OBJS) + $(RM) match_test@exe@ + +match_test@exe@: $(MATCH_OBJS) $(LIBERL) $(LIBEI) + $(LD) @CROSSLDFLAGS@ -o $@ $(MATCH_OBJS) $(LIBFLAGS) + diff --git a/lib/erl_interface/test/erl_match_SUITE_data/match_test.c b/lib/erl_interface/test/erl_match_SUITE_data/match_test.c new file mode 100644 index 0000000000..153a528b0b --- /dev/null +++ b/lib/erl_interface/test/erl_match_SUITE_data/match_test.c @@ -0,0 +1,113 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1997-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ + +/* + * Purpose: Tests the erl_match() function. + * Author: Bjorn Gustavsson + */ + +#include "runner.h" + +TESTCASE(erl_match_server) +{ + erl_init(NULL, 0); + + for (;;) { + ETERM* pattern; + ETERM* term; + + pattern = get_term(); + if (pattern == NULL) { + report(1); + return; + } else { + term = get_term(); + if (term == NULL) { + fail("Unexpected EOF term"); + } else { + send_term(erl_mk_int(erl_match(pattern, term))); + erl_free_term(pattern); + erl_free_term(term); + } + } + } + +} + +TESTCASE(erl_match_bind) +{ + erl_init(NULL, 0); + + for (;;) { + char* pattern; + ETERM* term; + + pattern=read_packet(NULL); + + switch (pattern[0]) { + case 'e': + free(pattern); + report(1); + return; + + case 'b': + { + ETERM* patt_term; + + /* + * Get the pattern string and convert it using erl_format(). + * + * Note that the call to get_term() below destroys the buffer + * that the pattern variable points to. Therefore, it is + * essential to call erl_format() here, before + * calling get_term(). + */ + + message("Pattern: %s", pattern+1); + patt_term = erl_format(pattern+1); + free(pattern); + + if (patt_term == NULL) { + fail("erl_format() failed"); + } + + /* + * Get the term and send back the result of the erl_match() + * call. + */ + + term = get_term(); + if (term == NULL) { + fail("Unexpected eof term"); + } + else { + send_term(erl_mk_int(erl_match(patt_term, term))); + } + erl_free_term(patt_term); + erl_free_term(term); + } + break; + + default: + free(pattern); + fail("Illegal character received"); + } + + } +} diff --git a/lib/erl_interface/test/port_call_SUITE.erl b/lib/erl_interface/test/port_call_SUITE.erl new file mode 100644 index 0000000000..895e29ad2e --- /dev/null +++ b/lib/erl_interface/test/port_call_SUITE.erl @@ -0,0 +1,106 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2001-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +-module(port_call_SUITE). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%% Checks if the dynamic driver and linker loader works. +%%% +%%% These tests can only be run installed (outside clearcase). +%%% +%%% XXX In this suite is missing test cases for reference counts +%%% and that drivers are unloaded when their processes die. +%%% (For me to add :-) +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +-export([all/1, basic/1]). +% Private exports +-include("test_server.hrl"). + + +all(suite) -> + [basic]. + +basic(suite) -> []; +basic(Config) when is_list(Config) -> + case os:type() of + {unix, sunos} -> + do_basic(Config); + {win32,_} -> + do_basic(Config); + _ -> + {skipped, "Dynamic linking and erl_interface not fully examined" + " on this platform..."} + end. + +do_basic(Config) -> + ?line Dog = test_server:timetrap(test_server:seconds(10)), + ?line Path = ?config(data_dir, Config), + + ?line erl_ddll:start(), + + %% Load the echo driver and verify that it was loaded. + {ok,L1,L2}=load_port_call_driver(Path), + + %% Verify that the driver works. + + ?line Port = open_port({spawn, port_call_drv}, [eof]), + ?line {hej, "hopp",4711,123445567436543653} = + erlang:port_call(Port,{hej, "hopp",4711,123445567436543653}), + ?line {hej, "hopp",4711,123445567436543653} = + erlang:port_call(Port,0,{hej, "hopp",4711,123445567436543653}), + ?line {[], a, [], b, c} = + erlang:port_call(Port,1,{hej, "hopp",4711,123445567436543653}), + ?line {return, {[], a, [], b, c}} = + erlang:port_call(Port,2,{[], a, [], b, c}), + ?line List = lists:duplicate(200,5), + ?line {return, List} = erlang:port_call(Port,2,List), + ?line {'EXIT',{badarg,_}} = (catch erlang:port_call(Port,4711,[])), + ?line {'EXIT',{badarg,_}} = (catch erlang:port_call(sune,2,[])), + ?line register(gunnar,Port), + ?line {return, List} = erlang:port_call(gunnar,2,List), + ?line {return, a} = erlang:port_call(gunnar,2,a), + ?line erlang:port_close(Port), + %% Unload the driver and verify that it was unloaded. + ok=unload_port_call_driver(L1,L2), + + ?line {error, {already_started, _}} = erl_ddll:start(), + ?line ok = erl_ddll:stop(), + + ?line test_server:timetrap_cancel(Dog), + ok. + +load_port_call_driver(Path) -> + ?line {ok, L1} = erl_ddll:loaded_drivers(), + ?line ok = erl_ddll:load_driver(Path, port_call_drv), + ?line {ok, L2} = erl_ddll:loaded_drivers(), + ?line ["port_call_drv"] = ordsets:to_list(ordsets:subtract(ordsets:from_list(L2), + ordsets:from_list(L1))), + {ok,L1,L2}. + +unload_port_call_driver(L1,L2) -> + ?line {ok, L2} = erl_ddll:loaded_drivers(), + ?line ok = erl_ddll:unload_driver(port_call_drv), + ?line {ok, L3} = erl_ddll:loaded_drivers(), + ?line [] = ordsets:to_list(ordsets:subtract(ordsets:from_list(L3), + ordsets:from_list(L1))), + ok. + diff --git a/lib/erl_interface/test/port_call_SUITE_data/Makefile.src b/lib/erl_interface/test/port_call_SUITE_data/Makefile.src new file mode 100644 index 0000000000..dc7385ba32 --- /dev/null +++ b/lib/erl_interface/test/port_call_SUITE_data/Makefile.src @@ -0,0 +1,39 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2001-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# + +include @erl_interface_mk_include@@[email protected] + +CC0 = @CC@ +CC = ..@DS@all_SUITE_data@DS@gccifier@exe@ -CC"$(CC0)" +LD = @LD@ +LIBPATH = @erl_interface_libpath@ +LIBERL = $(LIBPATH)/@erl_interface_lib_drv@ +LIBEI = $(LIBPATH)/@erl_interface_eilib_drv@ + +SHLIB_EXTRA_LDLIBS = $(LIBERL) $(LIBEI) +SHLIB_EXTRA_CFLAGS = -I@erl_interface_include@ -I../all_SUITE_data + + +all: port_call_drv@dll@ + +clean: + $(RM) port_call_drv@obj@ + $(RM) port_call_drv@dll@ + +@SHLIB_RULES@ diff --git a/lib/erl_interface/test/port_call_SUITE_data/port_call_drv.c b/lib/erl_interface/test/port_call_SUITE_data/port_call_drv.c new file mode 100644 index 0000000000..80811fb973 --- /dev/null +++ b/lib/erl_interface/test/port_call_SUITE_data/port_call_drv.c @@ -0,0 +1,103 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2001-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ + +#include <stdio.h> +#include "erl_interface.h" +#include "erl_driver.h" + +static ErlDrvPort my_erlang_port; +static ErlDrvData echo_start(ErlDrvPort, char *); +static void from_erlang(ErlDrvData, char*, int); +static int do_call(ErlDrvData drv_data, unsigned int command, char *buf, + int len, char **rbuf, int rlen, unsigned *ret_flags); +static ErlDrvEntry echo_driver_entry = { + NULL, /* Init */ + echo_start, + NULL, /* Stop */ + from_erlang, + NULL, /* Ready input */ + NULL, /* Ready output */ + "port_call_drv", + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + do_call +}; + +DRIVER_INIT(echo_drv) +{ + return &echo_driver_entry; +} + +static ErlDrvData +echo_start(ErlDrvPort port, char *buf) +{ + return (ErlDrvData) port; +} + +static void +from_erlang(ErlDrvData data, char *buf, int count) +{ + driver_output((ErlDrvPort) data, buf, count); +} + +static int +do_call(ErlDrvData drv_data, unsigned int command, char *buf, + int len, char **rbuf, int rlen, unsigned *ret_flags) +{ + int nlen; + ei_x_buff x; + + switch (command) { + case 0: + *rbuf = buf; + *ret_flags |= DRIVER_CALL_KEEP_BUFFER; + return len; + case 1: + ei_x_new(&x); + ei_x_format(&x, "{[], a, [], b, c}"); + nlen = x.index; + if (nlen > rlen) { + *rbuf =driver_alloc(nlen); + } + memcpy(*rbuf,x.buff,nlen); + ei_x_free(&x); + return nlen; + case 2: + ei_x_new(&x); + ei_x_encode_version(&x); + ei_x_encode_tuple_header(&x,2); + ei_x_encode_atom(&x,"return"); + ei_x_append_buf(&x,buf+1,len-1); + nlen = x.index; + if (nlen > rlen) { + *rbuf =driver_alloc(nlen); + } + memcpy(*rbuf,x.buff,nlen); + ei_x_free(&x); + return nlen; + default: + return -1; + } +} + diff --git a/lib/erl_interface/test/runner.erl b/lib/erl_interface/test/runner.erl new file mode 100644 index 0000000000..b72723c6a5 --- /dev/null +++ b/lib/erl_interface/test/runner.erl @@ -0,0 +1,130 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1997-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +-module(runner). + +-export([test/1, test/2, + start/1, send_term/2, finish/1, send_eot/1, recv_eot/1, + get_term/1, get_term/2]). + +-define(default_timeout, test_server:seconds(5)). + +%% Executes a test case in a C program. +%% +%% This function is useful for test cases written in C which requires +%% no further input, and only returns a result by calling report(). + +test(Tc) -> + test(Tc, ?default_timeout). + +test(Tc, Timeout) -> + Port = start(Tc), + + case get_term(Port, Timeout) of + eot -> + ok; + Other -> + io:format("In this test case, a success/failure result was"), + io:format("expected from the C program.\n"), + io:format("Received: ~p", [Other]), + test_server:fail() + end. + +%% Executes a test case in a C program. Returns the port. +%% +%% Use get_term/1,2. +%% +%% Returns: {ok, Port} + +start({Prog, Tc}) when is_list(Prog), is_integer(Tc) -> + Port = open_port({spawn, Prog}, [{packet, 4}]), + Command = [Tc div 256, Tc rem 256], + Port ! {self(), {command, Command}}, + Port. + +%% Finishes a test case by send an 'eot' message to the C program +%% and waiting for an 'eot'. +%% +%% If the C program doesn't require an 'eot', use recv_eot/1 instead. + +finish(Port) when is_port(Port) -> + send_eot(Port), + recv_eot(Port). + +%% Sends an Erlang term to a C program. + +send_term(Port, Term) when is_port(Port) -> + Port ! {self(), {command, [$t, term_to_binary(Term)]}}. + +%% Sends an 'eot' (end-of-test) indication to a C progrm. + +send_eot(Port) when is_port(Port) -> + Port ! {self(), {command, [$e]}}. + +%% Waits for an 'eot' indication from the C program. +%% Either returns 'ok' or invokes test_server:fail(). + +recv_eot(Port) when is_port(Port) -> + case get_term(Port) of + eot -> + ok; + Other -> + io:format("Error finishing test case. Expected eof from"), + io:format("C program, but got:"), + io:format("~p", [Other]), + test_server:fail() + end. + +%% Reads a term from the C program. +%% +%% Returns: {term, Term}|eot|'NULL' or calls test_server:fail/1,2. + +get_term(Port) -> + get_term(Port, ?default_timeout). + +get_term(Port, Timeout) -> + case get_reply(Port, Timeout) of + [$b|Bytes] -> + {bytes, Bytes}; + [$f] -> + test_server:fail(); + [$f|Reason] -> + test_server:fail(Reason); + [$t|Term] -> + {term, binary_to_term(list_to_binary(Term))}; + [$N] -> + 'NULL'; + [$e] -> + eot; + [$m|Message] -> + io:format("~s", [Message]), + get_term(Port, Timeout); + Other -> + io:format("Garbage received from C program: ~p", [Other]), + test_server:fail("Illegal response from C program") + end. + +get_reply(Port, Timeout) when is_port(Port) -> + receive + {Port, {data, Reply}} -> + Reply + after Timeout -> + test_server:fail("No response from C program") + end. diff --git a/lib/kernel/doc/src/file.xml b/lib/kernel/doc/src/file.xml index 2303617542..f9f5443f68 100644 --- a/lib/kernel/doc/src/file.xml +++ b/lib/kernel/doc/src/file.xml @@ -1368,7 +1368,7 @@ f.txt: {person, "kalle", 25}. </type> <desc> <p>Reads a line of bytes/characters from the file referenced by - <c>IoDevice</c>. Lines are defined to be delimited by the linefeed (LF, <c>\\n</c>) character, but any carriage return (CR, <c>\\r</c>) followed by a newline is also treated as a single LF character (the carriage return is silently ignored). The line is returned <em>including</em> the LF, but excluding any CR immediately followed by a LF. This behaviour is consistent with the behaviour of <seealso marker="stdlib:io#get_line/2">io:get_line/2</seealso>. If end of file is reached without any LF ending the last line, a line with no trailing LF is returned.</p> + <c>IoDevice</c>. Lines are defined to be delimited by the linefeed (LF, <c>\n</c>) character, but any carriage return (CR, <c>\r</c>) followed by a newline is also treated as a single LF character (the carriage return is silently ignored). The line is returned <em>including</em> the LF, but excluding any CR immediately followed by a LF. This behaviour is consistent with the behaviour of <seealso marker="stdlib:io#get_line/2">io:get_line/2</seealso>. If end of file is reached without any LF ending the last line, a line with no trailing LF is returned.</p> <p>The function can be used on files opened in <c>raw</c> mode. It is however inefficient to use it on <c>raw</c> files if the file is not opened with the option <c>{read_ahead, Size}</c> specified, why combining <c>raw</c> and <c>{read_ahead, Size}</c> is highly recommended when opening a text file for raw line oriented reading.</p> <p>If <c>encoding</c> is set to something else than <c>latin1</c>, the <c>read_line/1</c> call will fail if the data contains characters larger than 255, why the <seealso marker="stdlib:io">io(3)</seealso> module is to be preferred when reading such a file.</p> <p>The function returns:</p> diff --git a/lib/kernel/doc/src/inet.xml b/lib/kernel/doc/src/inet.xml index cae5fef2f8..f502b30c8d 100644 --- a/lib/kernel/doc/src/inet.xml +++ b/lib/kernel/doc/src/inet.xml @@ -49,8 +49,8 @@ might be specified in this way. An example of starting an Erlang node with all sockets using delayed send could look like this:</p> <pre> -$ <input>erl -sname test -kernel \\</input> -<input>inet_default_connect_options '[{delay_send,true}]' \\</input> +$ <input>erl -sname test -kernel \</input> +<input>inet_default_connect_options '[{delay_send,true}]' \</input> <input>inet_default_listen_options '[{delay_send,true}]'</input></pre> <p>Note that the default option <c>{active, true}</c> currently cannot be changed, for internal reasons.</p> diff --git a/lib/kernel/src/code_server.erl b/lib/kernel/src/code_server.erl index 018f7f41d2..d4e3f0bcf8 100644 --- a/lib/kernel/src/code_server.erl +++ b/lib/kernel/src/code_server.erl @@ -1479,13 +1479,12 @@ finish_on_load(Ref, OnLoadRes, #state{on_load=OnLoad0,moddb=Db}=State) -> end. finish_on_load_1(Mod, File, OnLoadRes, WaitingPids, Db) -> - Keep = if - is_boolean(OnLoadRes) -> OnLoadRes; - true -> false - end, + Keep = OnLoadRes =:= ok, erlang:finish_after_on_load(Mod, Keep), Res = case Keep of - false -> {error,on_load_failure}; + false -> + finish_on_load_report(Mod, OnLoadRes), + {error,on_load_failure}; true -> ets:insert(Db, {Mod,File}), {module,Mod} @@ -1493,6 +1492,24 @@ finish_on_load_1(Mod, File, OnLoadRes, WaitingPids, Db) -> [reply(Pid, Res) || Pid <- WaitingPids], ok. +finish_on_load_report(_Mod, Atom) when is_atom(Atom) -> + %% No error reports for atoms. + ok; +finish_on_load_report(Mod, Term) -> + %% Play it very safe here. The error_logger module and + %% modules it depend on may not be loaded yet and there + %% would be a dead-lock if we called it directly + %% from the code_server process. + spawn(fun() -> + F = "The on_load function for module " + "~s returned ~P\n", + + %% Express the call as an apply to simplify + %% the ext_mod_dep/1 test case. + E = error_logger, + E:warning_msg(F, [Mod,Term,10]) + end). + %% ------------------------------------------------------- %% Internal functions. %% ------------------------------------------------------- diff --git a/lib/kernel/test/code_SUITE.erl b/lib/kernel/test/code_SUITE.erl index 9fda66711d..38aadac202 100644 --- a/lib/kernel/test/code_SUITE.erl +++ b/lib/kernel/test/code_SUITE.erl @@ -31,12 +31,17 @@ where_is_file_cached/1, where_is_file_no_cache/1, purge_stacktrace/1, mult_lib_roots/1, bad_erl_libs/1, code_archive/1, code_archive2/1, on_load/1, - on_load_embedded/1]). + on_load_embedded/1, on_load_errors/1]). -export([init_per_testcase/2, fin_per_testcase/2, init_per_suite/1, end_per_suite/1, sticky_compiler/1]). +%% error_logger +-export([init/1, + handle_event/2, handle_call/2, handle_info/2, + terminate/2]). + all(suite) -> [set_path, get_path, add_path, add_paths, del_path, replace_path, load_file, load_abs, ensure_loaded, @@ -47,7 +52,8 @@ all(suite) -> load_cached, start_node_with_cache, add_and_rehash, where_is_file_no_cache, where_is_file_cached, purge_stacktrace, mult_lib_roots, bad_erl_libs, - code_archive, code_archive2, on_load, on_load_embedded]. + code_archive, code_archive2, on_load, on_load_embedded, + on_load_errors]. init_per_suite(Config) -> %% The compiler will no longer create a Beam file if @@ -671,6 +677,8 @@ check_funs({'$M_EXPR','$F_EXPR',2}, check_funs({'$M_EXPR','$F_EXPR',1}, [{lists,foreach,2}, {hipe_unified_loader,patch_consts,3} | _]) -> 0; +check_funs({'$M_EXPR',warning_msg,2}, + [{code_server,finish_on_load_report,2} | _]) -> 0; %% This is cheating! /raimo %% %% check_funs(This = {M,_,_}, Path) -> @@ -1229,6 +1237,81 @@ is_source_dir() -> filename:basename(code:lib_dir(kernel)) =:= "kernel" andalso filename:basename(code:lib_dir(stdlib)) =:= "stdlib". +on_load_errors(Config) when is_list(Config) -> + Master = on_load_error_test_case_process, + ?line register(Master, self()), + + ?line Data = filename:join([?config(data_dir, Config),"on_load_errors"]), + ?line ok = file:set_cwd(Data), + ?line up_to_date = make:all([{d,'MASTER',Master}]), + + ?line do_on_load_error(an_atom), + + ?line error_logger:add_report_handler(?MODULE, self()), + + ?line do_on_load_error({something,terrible,is,wrong}), + receive + Any1 -> + ?line {_, "The on_load function"++_, + [on_load_error, + {something,terrible,is,wrong},_]} = Any1 + end, + + ?line do_on_load_error(fail), %Cause exception. + receive + Any2 -> + ?line {_, "The on_load function"++_, + [on_load_error,{failed,[_|_]},_]} = Any2 + end, + + %% There should be no more messages. + receive + Unexpected -> + ?line ?t:fail({unexpected,Unexpected}) + after 10 -> + ok + end, + + ok. + +do_on_load_error(ReturnValue) -> + ?line {_,Ref} = spawn_monitor(fun() -> + exit(on_load_error:main()) + end), + receive {on_load_error,ErrorPid} -> ok end, + ?line ErrorPid ! ReturnValue, + receive + {'DOWN',Ref,process,_,Exit} -> + ?line {undef,[{on_load_error,main,[]}|_]} = Exit + end. + +%%----------------------------------------------------------------- +%% error_logger handler. +%% (Copied from stdlib/test/proc_lib_SUITE.erl.) +%%----------------------------------------------------------------- +init(Tester) -> + {ok, Tester}. + +handle_event({error, _GL, {emulator, _, _}}, Tester) -> + {ok, Tester}; +handle_event({error, _GL, Msg}, Tester) -> + Tester ! Msg, + {ok, Tester}; +handle_event(_Event, State) -> + {ok, State}. + +handle_info(_, State) -> + {ok, State}. + +handle_call(_Query, State) -> {ok, {error, bad_query}, State}. + +terminate(_Reason, State) -> + State. + +%%% +%%% Common utility functions. +%%% + start_node(Name, Param) -> ?t:start_node(Name, slave, [{args, Param}]). diff --git a/lib/kernel/test/code_SUITE_data/on_load/on_load_a.erl b/lib/kernel/test/code_SUITE_data/on_load/on_load_a.erl index 660000df46..f6bcb6570b 100644 --- a/lib/kernel/test/code_SUITE_data/on_load/on_load_a.erl +++ b/lib/kernel/test/code_SUITE_data/on_load/on_load_a.erl @@ -13,7 +13,7 @@ on_load() -> LibDir = code:lib_dir(kernel), ?MASTER ! {?MODULE,LibDir}, - true. + ok. data() -> [a|on_load_b:data()]. diff --git a/lib/kernel/test/code_SUITE_data/on_load/on_load_b.erl b/lib/kernel/test/code_SUITE_data/on_load/on_load_b.erl index 5c4d676e2d..947cbd5bcd 100644 --- a/lib/kernel/test/code_SUITE_data/on_load/on_load_b.erl +++ b/lib/kernel/test/code_SUITE_data/on_load/on_load_b.erl @@ -6,7 +6,7 @@ on_load() -> ?MASTER ! {?MODULE,start}, on_load_c:data(), ?MASTER ! {?MODULE,done}, - true. + ok. data() -> [b|on_load_c:data()]. diff --git a/lib/kernel/test/code_SUITE_data/on_load/on_load_c.erl b/lib/kernel/test/code_SUITE_data/on_load/on_load_c.erl index 4b2edbfb5a..6ab7f6402f 100644 --- a/lib/kernel/test/code_SUITE_data/on_load/on_load_c.erl +++ b/lib/kernel/test/code_SUITE_data/on_load/on_load_c.erl @@ -7,7 +7,7 @@ on_load() -> receive go -> ?MASTER ! {?MODULE,done}, - true + ok end. data() -> diff --git a/lib/kernel/test/code_SUITE_data/on_load_app-1.0/src/on_load_embedded.erl b/lib/kernel/test/code_SUITE_data/on_load_app-1.0/src/on_load_embedded.erl index bfc26864d5..a39332f81d 100644 --- a/lib/kernel/test/code_SUITE_data/on_load_app-1.0/src/on_load_embedded.erl +++ b/lib/kernel/test/code_SUITE_data/on_load_app-1.0/src/on_load_embedded.erl @@ -9,7 +9,7 @@ run_me() -> ok end end), - true. + ok. status() -> case whereis(everything_is_fine) of diff --git a/lib/kernel/test/code_SUITE_data/on_load_errors/on_load_error.erl b/lib/kernel/test/code_SUITE_data/on_load_errors/on_load_error.erl new file mode 100644 index 0000000000..0772050aeb --- /dev/null +++ b/lib/kernel/test/code_SUITE_data/on_load_errors/on_load_error.erl @@ -0,0 +1,13 @@ +-module(on_load_error). +-on_load(on_load/0). +-export([main/0]). + +on_load() -> + ?MASTER ! {?MODULE,self()}, + receive + fail -> erlang:error(failed); + Ret -> Ret + end. + +main() -> + ok. diff --git a/lib/observer/src/crashdump_viewer.erl b/lib/observer/src/crashdump_viewer.erl index b323d86ea4..978541e470 100644 --- a/lib/observer/src/crashdump_viewer.erl +++ b/lib/observer/src/crashdump_viewer.erl @@ -1272,6 +1272,9 @@ get_general_info(Fd,GenInfo) -> get_general_info(Fd,GenInfo#general_info{system_vsn=val(Fd)}); "Compiled" -> get_general_info(Fd,GenInfo#general_info{compile_time=val(Fd)}); + "Taints" -> + Val = case val(Fd) of "-1" -> "(none)"; Line -> Line end, + get_general_info(Fd,GenInfo#general_info{taints=Val}); "Atoms" -> get_general_info(Fd,GenInfo#general_info{num_atoms=val(Fd)}); "=" ++ _next_tag -> diff --git a/lib/observer/src/crashdump_viewer.hrl b/lib/observer/src/crashdump_viewer.hrl index 386d3bb423..6ce727cd3e 100644 --- a/lib/observer/src/crashdump_viewer.hrl +++ b/lib/observer/src/crashdump_viewer.hrl @@ -26,6 +26,7 @@ slogan, system_vsn, compile_time, + taints, node_name, num_atoms, num_procs, diff --git a/lib/observer/src/crashdump_viewer_html.erl b/lib/observer/src/crashdump_viewer_html.erl index 5fa829ed37..5e7bbf62a0 100644 --- a/lib/observer/src/crashdump_viewer_html.erl +++ b/lib/observer/src/crashdump_viewer_html.erl @@ -215,6 +215,8 @@ general_info_body(Heading,GenInfo) -> td(GenInfo#general_info.system_vsn)]), tr([th("ALIGN=left BGCOLOR=\"#8899AA\"","Compiled"), td(GenInfo#general_info.compile_time)]), + tr([th("ALIGN=left BGCOLOR=\"#8899AA\"","Taints"), + td(GenInfo#general_info.taints)]), case GenInfo#general_info.mem_tot of "" -> ""; MemTot -> diff --git a/lib/parsetools/doc/src/leex.xml b/lib/parsetools/doc/src/leex.xml index c113b586df..12abfd244f 100644 --- a/lib/parsetools/doc/src/leex.xml +++ b/lib/parsetools/doc/src/leex.xml @@ -281,7 +281,7 @@ NAME = VALUE</code> <Regexp> : <Erlang code>.</code> <p>The <Regexp> must occur at the start of a line and not - include any blanks; use <c>\\t</c> and <c>\\s</c> to include TAB + include any blanks; use <c>\t</c> and <c>\s</c> to include TAB and SPACE characters in the regular expression. If <Regexp> matches then the corresponding <Erlang code> is evaluated to generate a token. With the Erlang code the following predefined @@ -344,7 +344,7 @@ D = [0-9] {D}+ : {token,{integer,TokenLine,list_to_integer(TokenChars)}}. -{D}+\\.{D}+((E|e)(\\+|\\-)?{D}+)? : +{D}+\.{D}+((E|e)(\+|\-)?{D}+)? : {token,{float,TokenLine,list_to_float(TokenChars)}}.</code> <p>The Erlang code in the "Erlang code." section is written into @@ -367,7 +367,7 @@ D = [0-9] <tag><c>c</c></tag> <item><p>Matches the non-metacharacter c.</p> </item> - <tag><c>\\c</c></tag> + <tag><c>\c</c></tag> <item><p>Matches the escape sequence or literal character c.</p> </item> <tag><c>.</c></tag> @@ -410,33 +410,33 @@ D = [0-9] <p>The escape sequences allowed are the same as for Erlang strings:</p> <taglist> - <tag><c>\\b</c></tag> + <tag><c>\b</c></tag> <item><p>Backspace.</p></item> - <tag><c>\\f</c></tag> + <tag><c>\f</c></tag> <item><p>Form feed.</p></item> - <tag><c>\\n</c></tag> + <tag><c>\n</c></tag> <item><p>Newline (line feed).</p></item> - <tag><c>\\r</c></tag> + <tag><c>\r</c></tag> <item><p>Carriage return.</p></item> - <tag><c>\\t</c></tag> + <tag><c>\t</c></tag> <item><p>Tab.</p></item> - <tag><c>\\e</c></tag> + <tag><c>\e</c></tag> <item><p>Escape.</p></item> - <tag><c>\\v</c></tag> + <tag><c>\v</c></tag> <item><p>Vertical tab.</p></item> - <tag><c>\\s</c></tag> + <tag><c>\s</c></tag> <item><p>Space.</p></item> - <tag><c>\\d</c></tag> + <tag><c>\d</c></tag> <item><p>Delete.</p></item> - <tag><c>\\ddd</c></tag> + <tag><c>\ddd</c></tag> <item><p>The octal value <c>ddd</c>.</p></item> - <tag><c>\\xhh</c></tag> + <tag><c>\xhh</c></tag> <item><p>The hexadecimal value <c>hh</c>.</p></item> - <tag><c>\\x{h...}</c></tag> + <tag><c>\x{h...}</c></tag> <item><p>The hexadecimal value <c>h...</c>.</p></item> - <tag><c>\\c</c></tag> - <item><p>Any other character literally, for example <c>\\\\</c> for - backslash, <c>\\"</c> for <c>"</c>.</p> + <tag><c>\c</c></tag> + <item><p>Any other character literally, for example <c>\\</c> for + backslash, <c>\"</c> for <c>"</c>.</p> </item> </taglist> @@ -446,7 +446,7 @@ Atoms [a-z][0-9a-zA-Z_]* Variables [A-Z_][0-9a-zA-Z_]* -Floats (\\+|-)?[0-9]+\\.[0-9]+((E|e)(\\+|-)?[0-9]+)?</code> +Floats (\+|-)?[0-9]+\.[0-9]+((E|e)(\+|-)?[0-9]+)?</code> <note><p>Anchoring a regular expression with <c>^</c> and <c>$</c> is not implemented in the current version of Leex and just diff --git a/lib/percept/src/egd.erl b/lib/percept/src/egd.erl index 4becfef19b..7972fde597 100644 --- a/lib/percept/src/egd.erl +++ b/lib/percept/src/egd.erl @@ -128,13 +128,13 @@ line(Image, P1, P2, Color) -> %% @spec color( Value | Name ) -> color() %% where -%% Value = {byte(), byte(), byte()} | {byte(), byte(), byte(), byte()} -%% Name = black | silver | gray | white | maroon | red | purple | fuchia | green | lime | olive | yellow | navy | blue | teal | aqua +%% Value = {byte(), byte(), byte()} | {byte(), byte(), byte(), byte()} +%% Name = black | silver | gray | white | maroon | red | purple | fuchia | green | lime | olive | yellow | navy | blue | teal | aqua %% @doc Creates a color reference. -spec(color/1 :: ( - Value :: {byte(), byte(), byte()} | {byte(), byte(), byte(), byte()} | atom()) -> - color()). + Value :: {byte(), byte(), byte()} | {byte(), byte(), byte(), byte()} | atom()) -> + color()). color(Color) -> egd_primitives:color(Color). diff --git a/lib/percept/src/egd_font.erl b/lib/percept/src/egd_font.erl index 2b2a89a0a9..5f0d56dd90 100644 --- a/lib/percept/src/egd_font.erl +++ b/lib/percept/src/egd_font.erl @@ -131,18 +131,18 @@ parse_glyph({Code,W,H,X0,Y0,Xm,Offset}, Bitmasks) -> render_glyph(W, H, X0, Y0, Xm, Bitmask) -> render_glyph(W,{0,H},X0,Y0,Xm,Bitmask, []). render_glyph(_W, {H,H}, _X0, _Y0, _Xm, _Bitmask, Out) -> Out; -render_glyph(W, {Hi,H}, X0, Y0,Xm, Bitmask, LSs) -> +render_glyph(W, {Hi,H}, X0, Y0,Xm, Bitmask , LSs) -> N = ((W+7) div 8), O = N*Hi, <<_:O/binary, Submask/binary>> = Bitmask, - LS = render_glyph_horizontal( + LS = render_glyph_horizontal( Submask, % line glyph bitmask {down, W - 1}, % loop state W - 1, % Width []), % Linespans render_glyph(W,{Hi+1,H},X0,Y0,Xm, Bitmask, [LS|LSs]). -render_glyph_horizontal(Value, {Pr, Px}, 0, Spans) -> +render_glyph_horizontal(Value, {Pr, Px}, 0, Spans) -> Cr = bit_spin(Value, 0), case {Pr,Cr} of {up , up } -> % closure of interval since its last @@ -173,4 +173,3 @@ bit_spin(Value, Cx) -> 1 -> up; 0 -> down end. - diff --git a/lib/percept/src/egd_png.erl b/lib/percept/src/egd_png.erl index 3a0aaeef31..3a0aaeef31 100755..100644 --- a/lib/percept/src/egd_png.erl +++ b/lib/percept/src/egd_png.erl diff --git a/lib/percept/src/egd_primitives.erl b/lib/percept/src/egd_primitives.erl index 245e0d48e2..77c600279f 100644 --- a/lib/percept/src/egd_primitives.erl +++ b/lib/percept/src/egd_primitives.erl @@ -28,6 +28,7 @@ pixel/3, polygon/3, line/4, + line/5, arc/4, arc/5, rectangle/4, @@ -50,7 +51,6 @@ -include("egd.hrl"). - %% API info info(I) -> W = I#image.width, H = I#image.height, @@ -75,13 +75,22 @@ object_info(O) -> %% interface functions line(I, Sp, Ep, Color) -> - I#image{objects = [ + I#image{ objects = [ #image_object{ type = line, points = [Sp, Ep], span = span([Sp, Ep]), color = Color} | I#image.objects]}. +line(I, Sp, Ep, Stroke, Color) -> + I#image{ objects = [ + #image_object{ + type = line, + points = [Sp, Ep], + span = span([Sp, Ep]), + internals = Stroke, + color = Color } | I#image.objects]}. + arc(I, {Sx,Sy} = Sp, {Ex,Ey} = Ep, Color) -> X = Ex - Sx, Y = Ey - Sy, @@ -162,8 +171,6 @@ create(W, H) -> #image{ width = W, height = H}. -%color({crayon, Color}) -> rgba_byte2float(name_to_color({crayon, Color, 255})); -%color({crayon, Color, A}) -> rgba_byte2float(name_to_color({crayon, Color, A})); color(Color) when is_atom(Color) -> rgba_byte2float(name_to_color({Color, 255})); color({Color, A}) when is_atom(Color) -> rgba_byte2float(name_to_color({Color, A})); color({R,G,B}) -> rgba_byte2float({R,G,B, 255}); @@ -314,129 +321,6 @@ name_to_color({ slategray, A}) -> { 112, 128, 144, A}; name_to_color({ dimgray, A}) -> { 105, 105, 105, A}; name_to_color({ darkslategray, A}) -> { 47, 79, 79, A}. -%% Crayons -%name_to_color({crayon, mahogany, A}) -> { 205, 74, 74, A}; -%name_to_color({crayon, 'fuzzy wuzzy brown', A}) -> { 204, 102, 102, A}; -%name_to_color({crayon, chestnut, A}) -> { 188, 93, 88, A}; -%name_to_color({crayon, 'red orange', A}) -> { 255, 83, 73, A}; -%name_to_color({crayon, 'sunset orange', A}) -> { 253, 94, 83, A}; -%name_to_color({crayon, bittersweet, A}) -> { 253, 124, 110, A}; -%name_to_color({crayon, melon, A}) -> { 253, 188, 180, A}; -%name_to_color({crayon, 'outrageous orange', A}) -> { 255, 110, 74, A}; -%name_to_color({crayon, 'vivid tangerine', A}) -> { 255, 160, 137, A}; -%name_to_color({crayon, 'burnt sienna', A}) -> { 234, 126, 93, A}; -%name_to_color({crayon, brown, A}) -> { 180, 103, 77, A}; -%name_to_color({crayon, sepia, A}) -> { 165, 105, 79, A}; -%name_to_color({crayon, orange, A}) -> { 255, 117, 56, A}; -%name_to_color({crayon, 'burnt orange', A}) -> { 255, 127, 73, A}; -%name_to_color({crayon, copper, A}) -> { 221, 148, 117, A}; -%name_to_color({crayon, 'mango tango', A}) -> { 255, 130, 67, A}; -%name_to_color({crayon, 'atomic tangerine', A}) -> { 255, 164, 116, A}; -%name_to_color({crayon, beaver, A}) -> { 159, 129, 112, A}; -%name_to_color({crayon, 'antique brass', A}) -> { 205, 149, 117, A}; -%name_to_color({crayon, 'desert sand', A}) -> { 239, 205, 184, A}; -%name_to_color({crayon, 'raw sienna', A}) -> { 214, 138, 89, A}; -%name_to_color({crayon, tumbleweed, A}) -> { 222, 170, 136, A}; -%name_to_color({crayon, tan, A}) -> { 250, 167, 108, A}; -%name_to_color({crayon, peach, A}) -> { 255, 207, 171, A}; -%name_to_color({crayon, 'macaroni and cheese', A}) -> { 255, 189, 136, A}; -%name_to_color({crayon, apricot, A}) -> { 253, 217, 181, A}; -%name_to_color({crayon, 'neon carrot', A}) -> { 255, 163, 67, A}; -%name_to_color({crayon, almond, A}) -> { 239, 219, 197, A}; -%name_to_color({crayon, 'yellow orange', A}) -> { 255, 182, 83, A}; -%name_to_color({crayon, gold, A}) -> { 231, 198, 151, A}; -%name_to_color({crayon, shadow, A}) -> { 138, 121, 93, A}; -%name_to_color({crayon, 'banana mania', A}) -> { 250, 231, 181, A}; -%name_to_color({crayon, sunglow, A}) -> { 255, 207, 72, A}; -%name_to_color({crayon, goldenrod, A}) -> { 252, 217, 117, A}; -%name_to_color({crayon, dandelion, A}) -> { 253, 219, 109, A}; -%name_to_color({crayon, yellow, A}) -> { 252, 232, 131, A}; -%name_to_color({crayon, 'green yellow', A}) -> { 240, 232, 145, A}; -%name_to_color({crayon, 'spring green', A}) -> { 236, 234, 190, A}; -%name_to_color({crayon, 'olive green', A}) -> { 186, 184, 108, A}; -%name_to_color({crayon, 'laser lemon', A}) -> { 253, 252, 116, A}; -%name_to_color({crayon, 'unmellow yellow', A}) -> { 253, 252, 116, A}; -%name_to_color({crayon, canary, A}) -> { 255, 255, 153, A}; -%name_to_color({crayon, 'yellow green', A}) -> { 197, 227, 132, A}; -%name_to_color({crayon, 'inch worm', A}) -> { 178, 236, 93, A}; -%name_to_color({crayon, asparagus, A}) -> { 135, 169, 107, A}; -%name_to_color({crayon, 'granny smith apple', A}) -> { 168, 228, 160, A}; -%name_to_color({crayon, 'electric lime', A}) -> { 29, 249, 20, A}; -%name_to_color({crayon, 'screamin green', A}) -> { 118, 255, 122, A}; -%name_to_color({crayon, fern, A}) -> { 113, 188, 120, A}; -%name_to_color({crayon, 'forest green', A}) -> { 109, 174, 129, A}; -%name_to_color({crayon, 'sea green', A}) -> { 159, 226, 191, A}; -%name_to_color({crayon, green, A}) -> { 28, 172, 120, A}; -%name_to_color({crayon, 'mountain meadow', A}) -> { 48, 186, 143, A}; -%name_to_color({crayon, shamrock, A}) -> { 69, 206, 162, A}; -%name_to_color({crayon, 'jungle green', A}) -> { 59, 176, 143, A}; -%name_to_color({crayon, 'caribbean green', A}) -> { 28, 211, 162, A}; -%name_to_color({crayon, 'tropical rain forest', A}) -> { 23, 128, 109, A}; -%name_to_color({crayon, 'pine green', A}) -> { 21, 128, 120, A}; -%name_to_color({crayon, 'robin egg blue', A}) -> { 31, 206, 203, A}; -%name_to_color({crayon, aquamarine, A}) -> { 120, 219, 226, A}; -%name_to_color({crayon, 'turquoise blue', A}) -> { 119, 221, 231, A}; -%name_to_color({crayon, 'sky blue', A}) -> { 128, 218, 235, A}; -%name_to_color({crayon, 'outer space', A}) -> { 65, 74, 76, A}; -%name_to_color({crayon, 'blue green', A}) -> { 25, 158, 189, A}; -%name_to_color({crayon, 'pacific blue', A}) -> { 28, 169, 201, A}; -%name_to_color({crayon, cerulean, A}) -> { 29, 172, 214, A}; -%name_to_color({crayon, cornflower, A}) -> { 154, 206, 235, A}; -%name_to_color({crayon, 'midnight blue', A}) -> { 26, 72, 118, A}; -%name_to_color({crayon, 'navy blue', A}) -> { 25, 116, 210, A}; -%name_to_color({crayon, denim, A}) -> { 43, 108, 196, A}; -%name_to_color({crayon, blue, A}) -> { 31, 117, 254, A}; -%name_to_color({crayon, periwinkle, A}) -> { 197, 208, 230, A}; -%name_to_color({crayon, 'cadet blue', A}) -> { 176, 183, 198, A}; -%name_to_color({crayon, indigo, A}) -> { 93, 118, 203, A}; -%name_to_color({crayon, 'wild blue yonder', A}) -> { 162, 173, 208, A}; -%name_to_color({crayon, manatee, A}) -> { 151, 154, 170, A}; -%name_to_color({crayon, 'blue bell', A}) -> { 173, 173, 214, A}; -%name_to_color({crayon, 'blue violet', A}) -> { 115, 102, 189, A}; -%name_to_color({crayon, 'purple heart', A}) -> { 116, 66, 200, A}; -%name_to_color({crayon, 'royal purple', A}) -> { 120, 81, 169, A}; -%name_to_color({crayon, 'purple mountains majesty', A}) -> { 157, 129, 186, A}; -%name_to_color({crayon, violet, A}) -> { 146, 110, 174, A}; -%name_to_color({crayon, wisteria, A}) -> { 205, 164, 222, A}; -%name_to_color({crayon, 'vivid violet', A}) -> { 143, 80, 157, A}; -%name_to_color({crayon, fuchsia, A}) -> { 195, 100, 197, A}; -%name_to_color({crayon, 'shocking pink', A}) -> { 251, 126, 253, A}; -%name_to_color({crayon, 'pink flamingo', A}) -> { 252, 116, 253, A}; -%name_to_color({crayon, plum, A}) -> { 142, 69, 133, A}; -%name_to_color({crayon, 'hot magenta', A}) -> { 255, 29, 206, A}; -%name_to_color({crayon, 'purple pizzazz', A}) -> { 255, 29, 206, A}; -%name_to_color({crayon, 'razzle dazzle rose', A}) -> { 255, 72, 208, A}; -%name_to_color({crayon, orchid, A}) -> { 230, 168, 215, A}; -%name_to_color({crayon, 'red violet', A}) -> { 192, 68, 143, A}; -%name_to_color({crayon, eggplant, A}) -> { 110, 81, 96, A}; -%name_to_color({crayon, cerise, A}) -> { 221, 68, 146, A}; -%name_to_color({crayon, 'wild strawberry', A}) -> { 255, 67, 164, A}; -%name_to_color({crayon, magenta, A}) -> { 246, 100, 175, A}; -%name_to_color({crayon, lavender, A}) -> { 252, 180, 213, A}; -%name_to_color({crayon, 'cotton candy', A}) -> { 255, 188, 217, A}; -%name_to_color({crayon, 'violet red', A}) -> { 247, 83, 148, A}; -%name_to_color({crayon, 'carnation pink', A}) -> { 255, 170, 204, A}; -%name_to_color({crayon, razzmatazz, A}) -> { 227, 37, 107, A}; -%name_to_color({crayon, 'piggy pink', A}) -> { 253, 215, 228, A}; -%name_to_color({crayon, 'jazzberry jam', A}) -> { 202, 55, 103, A}; -%name_to_color({crayon, blush, A}) -> { 222, 93, 131, A}; -%name_to_color({crayon, 'tickle me pink', A}) -> { 252, 137, 172, A}; -%name_to_color({crayon, 'pink sherbet', A}) -> { 247, 128, 161, A}; -%name_to_color({crayon, maroon, A}) -> { 200, 56, 90, A}; -%name_to_color({crayon, red, A}) -> { 238, 32, 77, A}; -%name_to_color({crayon, 'radical red', A}) -> { 255, 73, 108, A}; -%name_to_color({crayon, mauvelous, A}) -> { 239, 152, 170, A}; -%name_to_color({crayon, 'wild watermelon', A}) -> { 252, 108, 133, A}; -%name_to_color({crayon, scarlet, A}) -> { 252, 40, 71, A}; -%name_to_color({crayon, salmon, A}) -> { 255, 155, 170, A}; -%name_to_color({crayon, 'brick red', A}) -> { 203, 65, 84, A}; -%name_to_color({crayon, white, A}) -> { 237, 237, 237, A}; -%name_to_color({crayon, timberwolf, A}) -> { 219, 215, 210, A}; -%name_to_color({crayon, silver, A}) -> { 205, 197, 194, A}; -%name_to_color({crayon, gray, A}) -> { 149, 145, 140, A}; -%name_to_color({crayon, black, A}) -> { 35, 35, 35, A}. - - text(I, {Xs,Ys} = Sp, Font, Text, Color) -> {FW,FH} = egd_font:size(Font), Length = length(Text), diff --git a/lib/percept/src/egd_render.erl b/lib/percept/src/egd_render.erl index f5e32c2a0f..cea9d2d926 100644 --- a/lib/percept/src/egd_render.erl +++ b/lib/percept/src/egd_render.erl @@ -35,7 +35,7 @@ binary(Image, Type) -> parallel_binary(precompile(Image),Type). parallel_binary(Image = #image{ height = Height },Type) -> - case lists:min([erlang:system_info(schedulers), Height]) of + case erlang:min(erlang:system_info(schedulers), Height) of 1 -> % if the height or the number of schedulers is 1 % do the scanlines in this process. @@ -120,27 +120,15 @@ receive_binaries(H, Bins) when H > 0 -> scanline(Y, Os, {_,_,Width,_}=LSB, Type) -> - OLSs = parse_objects_on_line(Y-1, Width, Os), - URLSs = resulting_line_spans([LSB|OLSs],Type), - - % FIXME: Can we keep the list sorted instead of sorting it? - % sort descending - RLSs = lists:reverse(URLSs), - - resulting_scanline(RLSs,Width). - -resulting_scanline(RLSs, Width) -> resulting_scanline(RLSs, Width, []). -resulting_scanline([], _, Scanlines) -> Scanlines; -resulting_scanline([{_,Xl, Xr, C} | RLSs], Width, Scanlines) -> - {R,G,B,_} = rgb_float2byte(C), - Scanline = lists:duplicate(trunc(Xr - Xl + 1), <<R:8,G:8,B:8>>), - resulting_scanline(RLSs, Width, [Scanline|Scanlines]). + OLSs = parse_objects_on_line(Y-1, Width, Os), + RLSs = resulting_line_spans([LSB|OLSs],Type), + [ lists:duplicate(Xr - Xl + 1, <<(trunc(R*255)):8,(trunc(G*255)):8,(trunc(B*255)):8>>) || {_,Xl, Xr, {R,G,B,_}} <- RLSs ]. resulting_line_spans(LSs,Type) -> %% Build a list of "transitions" from left to right. Trans = line_spans_to_trans(LSs), %% Convert list of "transitions" to linespans. - trans_to_line_spans(Trans,Type). + trans_to_line_spans(Trans,Type). line_spans_to_trans(LSs) -> line_spans_to_trans(LSs,[],0). @@ -194,19 +182,14 @@ color([{_,C}|_],opaque) -> C; color(Layers,alpha) -> color1({0,0,0,0},Layers). color1(Color,[]) -> Color; -color1(Color,[{_,C}|Layers]) -> color1(blend(Color,C),Layers). - -blend(C1,C2) -> alpha_blend(C1,C2). +color1(Color,[{_,C}|Layers]) -> color1(alpha_blend(Color,C),Layers). modify_layers(Layers,[]) -> Layers; -modify_layers(Layers,[{{_,Z,Op},C}|Trans]) -> - modify_layers(case Op of - start -> - add_layer(Layers,Z,C); - stop -> - remove_layer(Layers,Z,C) - end, - Trans). +modify_layers(Layers,[{{_,Z,start},C}|Trans]) -> + modify_layers(add_layer(Layers, Z, C), Trans); +modify_layers(Layers,[{{_,Z,stop },C}|Trans]) -> + modify_layers(remove_layer(Layers, Z, C), Trans). + add_layer([{Z1,_}=H|Layers],Z,C) when Z1 > Z -> [H|add_layer(Layers,Z,C)]; @@ -216,7 +199,7 @@ add_layer(Layers,Z,C) -> remove_layer(Layers,Z,C) -> Layers -- [{Z,C}]. -alpha_blend({R1,G1,B1,A1}, {R2,G2,B2,A2}) -> +alpha_blend({R1,G1,B1,A1}, {R2,G2,B2,A2}) when is_float(A1), is_float(A2)-> Beta = A2*(1.0 - A1), A = A1 + Beta, R = R1*A1 + R2*Beta, @@ -232,7 +215,7 @@ parse_objects_on_line(Y, Z, Width, [O|Os], Out) -> false -> parse_objects_on_line(Y, Z + 1, Width, Os, Out); true -> - OLs = object_line_data(Y, Z, O), + OLs = object_line_data(Y, Z, O), TOLs = trim_object_line_data(OLs, Width), parse_objects_on_line(Y, Z + 1, Width, Os, [TOLs|Out]) end. @@ -240,15 +223,13 @@ parse_objects_on_line(Y, Z, Width, [O|Os], Out) -> trim_object_line_data(OLs, Width) -> trim_object_line_data(OLs, Width, []). trim_object_line_data([], _, Out) -> Out; + +trim_object_line_data([{_, Xl, _, _}|OLs], Width, Out) when Xl > Width -> + trim_object_line_data(OLs, Width, Out); +trim_object_line_data([{_, _, Xr, _}|OLs], Width, Out) when Xr < 0 -> + trim_object_line_data(OLs, Width, Out); trim_object_line_data([{Z, Xl, Xr, C}|OLs], Width, Out) -> - if - Xl > Width -> - trim_object_line_data(OLs, Width, Out); - Xr < 0 -> - trim_object_line_data(OLs, Width, Out); - true -> - trim_object_line_data(OLs, Width, [{Z, lists:max([0,Xl]), lists:min([Xr,Width]), C}|Out]) - end. + trim_object_line_data(OLs, Width, [{Z, erlang:max(0,Xl), erlang:min(Xr,Width), C}|Out]). % object_line_data % In: @@ -264,7 +245,8 @@ trim_object_line_data([{Z, Xl, Xr, C}|OLs], Width, Out) -> % Calculate the length (start and finish index) of an objects horizontal % line given the height index. -object_line_data(Y, Z, Object) -> object_line_data(Y, Z, Object, Object#image_object.type). +object_line_data(Y, Z, Object) -> + object_line_data(Y, Z, Object, Object#image_object.type). object_line_data(Y, Z, #image_object{ span = {X0, Y0, X1, Y1}, color = C}, rectangle) -> if Y0 =:= Y ; Y1 =:= Y -> @@ -277,70 +259,43 @@ object_line_data(Y, Z, #image_object{ span = {X0, Y0, X1, Y1}, color = C}, recta object_line_data(_Y, Z, #image_object{ span = {X0, _, X1, _}, color = C}, filled_rectangle) -> [{Z, X0, X1, C}]; -object_line_data(Y, Z, #image_object{ span = {X0,Y0,X1,Y1}, color = C}, filled_ellipse) -> +object_line_data(Y, Z, #image_object{ internals={Xr,Yr,Yr2}, span = {X0,Y0,X1,Y1}, color = C}, filled_ellipse) -> if - X1 - X0 == 0 -> % if the width is exactly one pixel - [{Z, X1, X0, C}]; - X1 - X0 < 0 -> throw(bad_ellipse_width); - Y1 - Y0 == 0 -> % Height exactly one pixel, get width + X1 - X0 == 0; Y1 - Y0 == 0 -> [{Z, X0, X1, C}]; true -> - Xr = (X1 - X0)/2, - Yr = (Y1 - Y0)/2, - Yo = trunc(Y - Y0 - Yr), + Yo = trunc(Y - Y0 - Yr), Yo2 = Yo*Yo, - Yr2 = Yr*Yr, - Xo = math:sqrt((1 - Yo2/Yr2))*Xr, + Xo = math:sqrt((1 - Yo2/Yr2))*Xr, [{Z, round(X0 - Xo + Xr), round(X0 + Xo + Xr), C}] end; object_line_data(Y, Z, #image_object{ intervals = Is, color = C}, filled_triangle) -> - case lists:keysearch(Y, 1, Is) of - {value, {Y, Xl, Xr}} -> [{Z, Xl, Xr, C}]; + case lists:keyfind(Y, 1, Is) of + {Y, Xl, Xr} -> [{Z, Xl, Xr, C}]; false -> [] end; object_line_data(Y, Z, #image_object{ intervals = Is, color = C}, line) -> case dict:find(Y, Is) of - %{ok, {Xl, Xr}} -> [{Z, Xl, Xr, C}]; {ok, Ls} -> [{Z, Xl, Xr, C}||{Xl,Xr} <- Ls]; _ -> [] end; -object_line_data(Y, Z, O, polygon) -> - Is = lists:filter( - fun({Yp,_,_}) -> - if Yp == Y -> true; true -> false end - end, O#image_object.intervals), - [ {Z, Xl, Xr, O#image_object.color} || {_, Xl, Xr} <- Is]; - -object_line_data(Y, Z, #image_object{ color = C, intervals = Is }, text_horizontal) -> - % FIXME: optimize! - lists:foldl( - fun ({Yg,Xl,Xr}, Out) -> - if - Yg == Y -> - [{Z, Xl, Xr, C}|Out]; - true -> - Out - end - end, [], Is); +object_line_data(Y, Z, #image_object{ color = C, intervals = Is}, polygon) -> + [{Z, Xl, Xr, C} || {Yp, Xl, Xr} <- Is, Yp =:= Y]; + +object_line_data(Y, Z, #image_object{ color = C, intervals = Is}, text_horizontal) -> + [{Z, Xl, Xr, C} || {Yg, Xl, Xr} <- Is, Yg =:= Y]; + object_line_data(_, Z, #image_object{ span = {X0,_,X1,_}, color = C}, _) -> - % faked [{Z, X0, X1, C}]. -is_object_on_line(Y, Object) -> - is_object_bounds_on_line(Y, Object#image_object.span). +is_object_on_line(Y, #image_object{ span = Span }) -> + is_object_bounds_on_line(Y, Span). -is_object_bounds_on_line(Y, {_,Y0,_,Y1}) -> - if - Y < Y0 -> false; - Y > Y1 -> false; - true -> true - end. - -rgb_float2byte({R,G,B,A}) -> - {trunc(R*255), trunc(G*255), trunc(B*255), trunc(A*255)}. +is_object_bounds_on_line(Y, {_,Y0,_,Y1}) when Y < Y0 ; Y > Y1 -> false; +is_object_bounds_on_line(_, _) -> true. %%% primitives to line_spans @@ -360,6 +315,12 @@ precompile_objects([O = #image_object{ type = filled_triangle, points = [P0,P1,P precompile_objects([O = #image_object{ type = polygon, points = Pts } | Os], Out) -> precompile_objects(Os, [O#image_object{ intervals = polygon_ls(Pts) } | Out]); + +precompile_objects([O = #image_object{ type = filled_ellipse, span = {X0,Y0,X1,Y1} } | Os], Out) -> + Xr = (X1 - X0)/2, + Yr = (Y1 - Y0)/2, + Yr2 = Yr*Yr, + precompile_objects(Os, [ O#image_object{ internals={Xr,Yr,Yr2} } | Out]); precompile_objects([O = #image_object{ type = arc, points = [P0,P1], internals = D }| Os], Out) -> Es = egd_primitives:arc_to_edges(P0, P1, D), @@ -579,13 +540,7 @@ line_ls({Xi0, Yi0},{Xi1,Yi1}) -> true -> 1; false -> -1 end, - case Steep of - false -> - line_ls_step_not_steep({X0, X1},Y0, DX, DY, Ystep, Error, X0, []); - true -> - line_ls_step_steep({X0, X1},Y0, DX, DY, Ystep, Error, X0, []) - end. - + line_ls_step(X0, X1,Y0, DX, DY, Ystep, Error, X0, Steep, []). %% line_ls_step_(not)_steep %% In: @@ -594,27 +549,17 @@ line_ls({Xi0, Yi0},{Xi1,Yi1}) -> %% Purpose: %% Produce an line_interval for each Yi (Y index) -% Iterating the X-axis - -line_ls_step_not_steep({X,X1},Y,Dx,Dy,Ys,E, X0, LSs) when X < X1 -> - case E >= 0 of - true -> - line_ls_step_not_steep({X+1,X1},Y+Ys,Dx,Dy,Ys, E - Dx + Dy, X+1,[{Y,X0,X}|LSs]); - false -> - line_ls_step_not_steep({X+1,X1},Y,Dx,Dy,Ys, E + Dy, X0, LSs) - end; -line_ls_step_not_steep({X,_},Y,_Dx,_Dy,_Ystep,_E,X0,LSs) -> - [{Y,X0,X}|LSs]. - -% Iterating the Y-axis -line_ls_step_steep({X,X1},Y,Dx,Dy,Ystep,E, X0, LSs) when X =< X1 -> - case E >= 0 of - true -> - line_ls_step_steep({X + 1,X1},Y+Ystep,Dx,Dy,Ystep,E - Dx + Dy,X,[{X,Y,Y}|LSs]); - false -> - line_ls_step_steep({X + 1,X1},Y,Dx,Dy,Ystep,E + Dy,X0, [{X,Y,Y}|LSs]) - end; -line_ls_step_steep({_X,_},_Y,_Dx,_Dy,_Ystep,_E,_X0,LSs) -> +line_ls_step(X, X1, Y, Dx, Dy, Ys, E, X0, false = Steep, LSs) when X < X1, E >= 0 -> + line_ls_step(X+1,X1,Y+Ys,Dx,Dy,Ys, E - Dx + Dy, X+1, Steep, [{Y,X0,X}|LSs]); +line_ls_step(X, X1, Y, Dx, Dy, Ys, E, X0, false = Steep, LSs) when X < X1 -> + line_ls_step(X+1,X1,Y,Dx,Dy,Ys, E + Dy, X0, Steep, LSs); +line_ls_step(X, _X1, Y, _Dx, _Dy, _Ys, _E, X0, false, LSs) -> + [{Y,X0,X}|LSs]; +line_ls_step(X, X1, Y, Dx, Dy, Ys, E, _X0, true = Steep, LSs) when X =< X1, E >= 0 -> + line_ls_step(X+1,X1,Y+Ys,Dx,Dy,Ys, E - Dx + Dy, X, Steep, [{X,Y,Y}|LSs]); +line_ls_step(X, X1, Y, Dx, Dy, Ys, E, X0, true = Steep, LSs) when X =< X1 -> + line_ls_step(X+1,X1,Y,Dx,Dy,Ys,E + Dy, X0, Steep, [{X,Y,Y}|LSs]); +line_ls_step(_X,_,_Y,_Dx,_Dy,_Ys,_E,_X0,_,LSs) -> LSs. % Text @@ -707,3 +652,4 @@ eps_header(W,H) -> eps_footer() -> "%%EOF\n". + diff --git a/lib/percept/test/egd_SUITE.erl b/lib/percept/test/egd_SUITE.erl index 603ad628d3..a2595400dd 100644 --- a/lib/percept/test/egd_SUITE.erl +++ b/lib/percept/test/egd_SUITE.erl @@ -29,6 +29,7 @@ -export([ image_create_and_destroy/1, image_shape/1, + image_primitives/1, image_colors/1, image_font/1, image_png_compliant/1 @@ -38,8 +39,7 @@ -define(default_timeout, ?t:minutes(1)). init_per_suite(Config) when is_list(Config) -> - {A1,A2,A3} = now(), - random:seed(A1, A2, A3), + random:seed(now()), Config. end_per_suite(Config) when is_list(Config) -> @@ -59,6 +59,7 @@ all(suite) -> [ image_create_and_destroy, image_shape, + image_primitives, image_colors, image_font, image_png_compliant @@ -145,7 +146,43 @@ image_shape(Config) when is_list(Config) -> ?line ok = egd:destroy(Im), erase(image_size), ok. - + +image_primitives(suite) -> + []; +image_primitives(doc) -> + ["Image shape api test."]; +image_primitives(Config) when is_list(Config) -> + {W,H} = get_size(?config(max_size, Config)), + put(image_size, {W,H}), + + ?line Im0 = egd_primitives:create(W, H), + ?line Fgc = egd:color({25,25,255}), + ?line Bgc = egd:color({0,250,25}), + + ?line Im1 = lists:foldl(fun + ({Function, Arguments}, Im) -> + ?line erlang:apply(egd_primitives, Function, [Im|Arguments]) + end, Im0, + [{Fs, [get_point(), get_point(), Bgc]} || Fs <- [line, rectangle, filledEllipse, arc]] ++ + [{pixel, [get_point(), Bgc]}, + {filledTriangle, [get_point(), get_point(), get_point(), Bgc]}]), + + Pt1 = get_point(), + Pt2 = get_point(), + + ?line Im2 = egd_primitives:filledRectangle(Im1, Pt1, Pt2, Fgc), + + ?line Bitmap = egd_render:binary(Im2, opaque), + + ?line ok = bitmap_point_has_color(Bitmap, {W,H}, Pt2, Fgc), + ?line ok = bitmap_point_has_color(Bitmap, {W,H}, Pt1, Fgc), + + erase(image_size), + ok. + + + + image_font(suite) -> []; image_font(doc) -> diff --git a/lib/public_key/doc/src/cert_records.xml b/lib/public_key/doc/src/cert_records.xml index 8fb4ea5fd0..8cfe57f670 100644 --- a/lib/public_key/doc/src/cert_records.xml +++ b/lib/public_key/doc/src/cert_records.xml @@ -41,10 +41,18 @@ </p> <p>Use the following include directive to get access to the - records and constant macros described in the following sections.</p> + records and constant macros (OIDs) described in the following sections.</p> <code> -include_lib("public_key/include/public_key.hrl"). </code> + <p>The used specification is available in <c>OTP-PKIX.asn1</c>, + which is an amelioration of + the <c>PKIX1Explicit88.asn1</c>, <c>PKIX1Implicit88.asn1</c> + and <c>PKIX1Algorithms88.asn1</c> modules. + You find all these modules in the <c>asn1</c> subdirectory + of the application <c>public_key</c>. + </p> + <section> <title>Common Data Types</title> @@ -148,8 +156,7 @@ oid names see table below. Ex: ?'id-dsa-with-sha1'</p> }. </code> -<p><c>id_attributes() = ?oid_name_as_erlang_atom</c> -for available oid names see table below. Ex: ?'id-at-name'</p> +<p><c>id_attributes() </c></p> <table> <row> <cell align="left" valign="middle">OID name</cell> @@ -231,8 +238,7 @@ for available oid names see table below. Ex: ?'id-at-name'</p> }. </code> -<p><c> id_public_key_algorithm() = ?oid_name_as_erlang_atom</c> for available -oid names see table below. Ex: ?'id-dsa'</p> +<p><c> id_public_key_algorithm() </c></p> <table> <row> <cell align="left" valign="middle">OID name</cell> @@ -264,14 +270,11 @@ oid names see table below. Ex: ?'id-dsa'</p> }. </code> -<p><c>id_extensions() = ?oid_name_as_erlang_atom</c> for -available oid names see tables. Ex: ?'id-ce-authorityKeyIdentifier'<seealso -marker="#StdCertExt">Standard Certificate Extensions</seealso>, - <seealso - marker="#PrivIntExt">Private Internet Extensions</seealso>, <seealso - marker="#CRLCertExt">CRL Extensions</seealso> and - <seealso - marker="#CRLEntryExt">CRL Entry Extensions</seealso>. +<p><c>id_extensions()</c> + <seealso marker="#StdCertExt">Standard Certificate Extensions</seealso>, + <seealso marker="#PrivIntExt">Private Internet Extensions</seealso>, + <seealso marker="#CRLCertExt">CRL Extensions</seealso> and + <seealso marker="#CRLEntryExt">CRL Entry Extensions</seealso>. </p> </section> @@ -368,9 +371,8 @@ marker="#StdCertExt">Standard Certificate Extensions</seealso>, decipherOnly </c></p> - <p><c> id_key_purpose() = ?oid_name_as_erlang_atom</c> for available -oid names see table below. Ex: ?'id-kp-serverAuth'</p> - + <p><c> id_key_purpose()</c></p> + <table> <row> <cell align="left" valign="middle">OID name</cell> diff --git a/lib/ssl/doc/src/create_certs.xml b/lib/ssl/doc/src/create_certs.xml index 15958ee457..79cc8a0537 100644 --- a/lib/ssl/doc/src/create_certs.xml +++ b/lib/ssl/doc/src/create_certs.xml @@ -98,12 +98,12 @@ <title>Creating the Erlang root CA</title> <p>The Erlang root CA is created with the command</p> <code type="none"> -\011openssl req -new -x509 -config /some/path/req.cnf \\ -\011 -keyout /some/path/key.pem -out /some/path/cert.pem </code> + openssl req -new -x509 -config /some/path/req.cnf \\ + -keyout /some/path/key.pem -out /some/path/cert.pem </code> <p>where the option <c>-new</c> indicates that we want to create a new certificate request and the option <c>-x509</c> implies that a self-signed certificate is created. - </p> + </p> </section> <section> @@ -111,12 +111,12 @@ <p>The OTP CA is created by first creating a certificate request with the command</p> <code type="none"> -\011openssl req -new -config /some/path/req.cnf \\ -\011 -keyout /some/path/key.pem -out /some/path/req.pem </code> + openssl req -new -config /some/path/req.cnf \\ + -keyout /some/path/key.pem -out /some/path/req.pem </code> <p>and the ask the Erlang CA to sign it:</p> <code type="none"> -\011openssl ca -batch -notext -config /some/path/req.cnf \\ -\011 -extensions ca_cert -in /some/path/req.pem -out /some/path/cert.pem </code> + openssl ca -batch -notext -config /some/path/req.cnf \\ + -extensions ca_cert -in /some/path/req.pem -out /some/path/cert.pem </code> <p>where the option <c>-extensions</c> refers to a section in the configuration file saying that it should create a CA certificate, and not a plain user certificate. diff --git a/lib/ssl/doc/src/new_ssl.xml b/lib/ssl/doc/src/new_ssl.xml index f50f714fe6..a11919eb51 100644 --- a/lib/ssl/doc/src/new_ssl.xml +++ b/lib/ssl/doc/src/new_ssl.xml @@ -437,30 +437,17 @@ end </func> <func> - <name>peercert(Socket) -> </name> - <name>peercert(Socket, Opts) -> {ok, Cert} | {error, Reason}</name> + <name>peercert(Socket) -> {ok, Cert} | {error, Reason}</name> <fsummary>Return the peer certificate.</fsummary> <type> <v>Socket = sslsocket()</v> - <v>Opts = [] | [otp] | [plain] </v> - <v>Cert = term()</v> + <v>Cert = binary()</v> <v>Subject = term()</v> </type> <desc> - <p><c>peercert(Cert)</c> is equivalent to <c>peercert(Cert, [])</c>. - </p> - <p>The form of the returned certificate depends on the - options. - </p> - <p>If the options list is empty the certificate is returned as - a DER encoded binary. - </p> - <p>The option <c>otp</c> or <c>plain</c> implies that the - certificate will be returned as a parsed ASN.1 structure in the - form of an Erlang term. For detail see the public_key application. - Currently only plain is officially supported see the public_key users - guide. - </p> + <p>The peer certificate is returned as a DER encoded binary. + The certificate can be decoded with <c>public_key:pkix_decode_cert/2</c>. + </p> </desc> </func> <func> diff --git a/lib/ssl/doc/src/pkix_certs.xml b/lib/ssl/doc/src/pkix_certs.xml index 47818c1b7d..1de807cadc 100644 --- a/lib/ssl/doc/src/pkix_certs.xml +++ b/lib/ssl/doc/src/pkix_certs.xml @@ -34,219 +34,24 @@ <p>Certificates were originally defined by ITU (CCITT) and the latest definitions are described in <cite id="X.509"></cite>, but those definitions are (as always) not working. - </p> + </p> <p>Working certificate definitions for the Internet Community are found - in the the PKIX RFCs <cite id="rfc3279"></cite>and <cite id="rfc3280"></cite>. + in the the PKIX RFCs <cite id="rfc3279"></cite> and <cite id="rfc3280"></cite>. The parsing of certificates in the Erlang/OTP SSL application is based on those RFCS. - </p> + </p> <p>Certificates are defined in terms of ASN.1 (<cite id="X.680"></cite>). For an introduction to ASN.1 see <url href="http://asn1.elibel.tm.fr/">ASN.1 Information Site</url>. - </p> + </p> </section> <section> <title>PKIX Certificates</title> - <p>Here we base the PKIX certificate definitions in RFCs <cite id="rfc3279"></cite>and <cite id="rfc3280"></cite>. We however present the - definitions according to <c>SSL-PKIX.asn1</c> module, - which is an amelioration of the <c>PKIX1Explicit88.asn1</c>, - <c>PKIX1Implicit88.asn1</c>, and <c>PKIX1Algorithms88.asn1</c> - modules. You find all these modules in the <c>pkix</c> subdirectory - of SSL. - </p> - <p>The Erlang terms that are returned by the functions - <c>ssl:peercert/1/2</c>, <c>ssl_pkix:decode_cert/1/2</c>, and - <c>ssl_pkix:decode_cert_file/1/2</c> when the option <c>ssl</c> - is used in those functions, correspond the ASN.1 structures - described in the sequel. - </p> - - <section> - <title>Certificate and TBSCertificate</title> - <code type="none"> -Certificate ::= SEQUENCE { - tbsCertificate TBSCertificate, - signatureAlgorithm SignatureAlgorithm, - signature BIT STRING } - -TBSCertificate ::= SEQUENCE { - version [0] Version DEFAULT v1, - serialNumber CertificateSerialNumber, - signature SignatureAlgorithm, - issuer Name, - validity Validity, - subject Name, - subjectPublicKeyInfo SubjectPublicKeyInfo, - issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL, - -- If present, version MUST be v2 or v3 - subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL, - -- If present, version MUST be v2 or v3 - extensions [3] Extensions OPTIONAL - -- If present, version MUST be v3 -- } - -Version ::= INTEGER { v1(0), v2(1), v3(2) } - -CertificateSerialNumber ::= INTEGER - -Validity ::= SEQUENCE { - notBefore Time, - notAfter Time } - -Time ::= CHOICE { - utcTime UTCTime, - generalTime GeneralizedTime } - </code> - <p>The meaning of the fields <c>version</c>, <c>serialNumber</c>, - and <c>validity</c> are quite obvious given the type definitions - above, so we do not go further into their details. - </p> - <p>The <c>signatureAlgorithm</c> field of <c>Certificate</c> and - the <c>signature</c> field of <c>TBSCertificate</c> contain - the name and parameters of the algorithm used for signing the - certificate. The values of these two fields must be equal. - </p> - <p>The <c>signature</c> field of <c>Certificate</c> contains the - value of the signature that the issuer computed by using the - prescribed algorithm. - </p> - <p>The <c><![CDATA[issuer<c> and <c>subject]]></c> fields can contain many - different types av data, and is therefore considered in a - separate section. The same holds for the <c>extensions</c> - field. - The <c>issuerUniqueID</c> and the <c>subjectUniqueID</c> fields - are not considered further.</p> - </section> - - <section> - <title>TBSCertificate issuer and subject</title> - <p></p> - <code type="none"><![CDATA[ -Name ::= CHOICE { -- only one possibility for now -- - rdnSequence RDNSequence } - -RDNSequence ::= SEQUENCE OF RelativeDistinguishedName - -DistinguishedName ::= RDNSequence - -RelativeDistinguishedName ::= - SET SIZE (1 .. MAX) OF AttributeTypeAndValue - -AttributeTypeAndValue ::= SEQUENCE { - type ATTRIBUTE-TYPE-AND-VALUE-CLASS.&id -\011\011({SupportedAttributeTypeAndValues}), - value ATTRIBUTE-TYPE-AND-VALUE-CLASS.&Type -\011\011({SupportedAttributeTypeAndValues}{@type}) } - -SupportedAttributeTypeAndValues ATTRIBUTE-TYPE-AND-VALUE-CLASS ::= -\011{ name | surname | givenName | initials | generationQualifier | -\011 commonName | localityName | stateOrProvinceName | organizationName | -\011 organizationalUnitName | title | dnQualifier | countryName | -\011 serialNumber | pseudonym | domainComponent | emailAddress } ]]></code> - </section> - - <section> - <title>TBSCertificate extensions</title> - <p>The <c>extensions</c> field of a <c>TBScertificate</c> is a - sequence of type <c>Extension</c>, defined as follows,</p> - <code type="none"> -Extension ::= SEQUENCE { - extnID OBJECT IDENTIFIER, - critical BOOLEAN DEFAULT FALSE, - extnValue ANY } </code> - <p>Each extension has a unique object identifier. An extension - with a <c>critical</c> value set to <c>TRUE</c><em>must</em> - be recognised by the reader of a certificate, or else the - certificate must be rejected. - </p> - <p>Extensions are divided into two groups: standard extensions - and internet certificate extensions. All extensions listed in - the table that follows are standard extensions, except for - <c>authorityInfoAccess</c> and <c>subjectInfoAccess</c>, which - are internet extensions. - </p> - <p>Depending on the object identifier the <c>extnValue</c> is - parsed into an appropriate welldefined structure. - </p> - <p>The following table shows the purpose of each extension, but - does not specify the structure. To see the structure consult - the <c>PKIX1Implicit88.asn1</c> module. - </p> - <table> - <row> - <cell align="left" valign="middle">authorityKeyIdentifier</cell> - <cell align="left" valign="middle">Used by to identify a certificate signed that has multiple signing keys. </cell> - </row> - <row> - <cell align="left" valign="middle">subjectKeyIdentifier</cell> - <cell align="left" valign="middle">Used to identify certificates that contain a public key. Must appear i CA certificates.</cell> - </row> - <row> - <cell align="left" valign="middle">keyUsage </cell> - <cell align="left" valign="middle">Defines the purpose of the certificate. Can be one or several of<c>digitalSignature</c>, <c>nonRepudiation</c>,<c>keyEncipherment</c>, <c>dataEncipherment</c>,<c>keyAgreement</c>, <c>keyCertSign</c>, <c>cRLSign</c>,<c>encipherOnly</c>, <c>decipherOnly</c>.</cell> - </row> - <row> - <cell align="left" valign="middle">privateKeyUsagePeriod </cell> - <cell align="left" valign="middle">Allows certificate issuer to provide a private key usage period to be short than the certificate usage period.</cell> - </row> - <row> - <cell align="left" valign="middle">certificatePolicies</cell> - <cell align="left" valign="middle">Contains one or more policy information terms indicating the policies under which the certificate has been issued.</cell> - </row> - <row> - <cell align="left" valign="middle">policyMappings</cell> - <cell align="left" valign="middle">Used i CA certificates. </cell> - </row> - <row> - <cell align="left" valign="middle">subjectAltName</cell> - <cell align="left" valign="middle">Allows additional identities to be bound the the subject. </cell> - </row> - <row> - <cell align="left" valign="middle">issuerAltName</cell> - <cell align="left" valign="middle">Allows additional identities to be bound the the issuer.</cell> - </row> - <row> - <cell align="left" valign="middle">subjectDirectoryAttributes</cell> - <cell align="left" valign="middle">Conveys identity attributes of the subject.</cell> - </row> - <row> - <cell align="left" valign="middle">basicConstraints</cell> - <cell align="left" valign="middle">Tells if the certificate holder is a CA or not.</cell> - </row> - <row> - <cell align="left" valign="middle">nameConstraints</cell> - <cell align="left" valign="middle">Used in CA certificates.</cell> - </row> - <row> - <cell align="left" valign="middle">policyConstraints</cell> - <cell align="left" valign="middle">Used in CA certificates.</cell> - </row> - <row> - <cell align="left" valign="middle">extKeyUsage</cell> - <cell align="left" valign="middle">Indicates for which purposed the public key may be used. </cell> - </row> - <row> - <cell align="left" valign="middle">cRLDistributionPoints</cell> - <cell align="left" valign="middle">Indicates how CRL (Certificate Revokation List) information is obtained.</cell> - </row> - <row> - <cell align="left" valign="middle">inhibitAnyPolicy</cell> - <cell align="left" valign="middle">Used i CA certificates.</cell> - </row> - <row> - <cell align="left" valign="middle">freshestCRL</cell> - <cell align="left" valign="middle">For CRLs.</cell> - </row> - <row> - <cell align="left" valign="middle">authorityInfoAccess</cell> - <cell align="left" valign="middle">How to access CA information of the issuer of the certificate.</cell> - </row> - <row> - <cell align="left" valign="middle">subjectInfoAccess</cell> - <cell align="left" valign="middle">How to access CA information of the subject of the certificate.</cell> - </row> - <tcaption>PKIX Extensions</tcaption> - </table> - </section> + <p>Certificate handling is now handled by the <c>public_key</c> application.</p> + <p> + DER encoded certificates returned by <c>ssl:peercert/1</c> can for example + be decoded by the <c>public_key:pkix_decode_cert/2</c> function. + </p> </section> </chapter> diff --git a/lib/ssl/doc/src/remember.xml b/lib/ssl/doc/src/remember.xml deleted file mode 100644 index 799627a33c..0000000000 --- a/lib/ssl/doc/src/remember.xml +++ /dev/null @@ -1,83 +0,0 @@ -<?xml version="1.0" encoding="latin1" ?> -<!DOCTYPE chapter SYSTEM "chapter.dtd"> - -<chapter> - <header> - <copyright> - <year>2003</year><year>2009</year> - <holder>Ericsson AB. All Rights Reserved.</holder> - </copyright> - <legalnotice> - The contents of this file are subject to the Erlang Public License, - Version 1.1, (the "License"); you may not use this file except in - compliance with the License. You should have received a copy of the - Erlang Public License along with this software. If not, it can be - retrieved online at http://www.erlang.org/. - - Software distributed under the License is distributed on an "AS IS" - basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - the License for the specific language governing rights and limitations - under the License. - - </legalnotice> - - <title>PKIX Certificates</title> - <prepared>UAB/F/P Peter Högfeldt</prepared> - <docno></docno> - <date>2003-06-09</date> - <rev>A</rev> - <file>pkix_certs.sgml</file> - </header> - - <section> - <title>Introduction to Certificates</title> - <p><em>Outline:</em></p> - <list type="bulleted"> - <item>SSL/TLS protocol - server must have certificate - -what - the the server sends to the client - client may verify the - server - server may ask client for certificate - what the - client sends to the server - server may then verify the client - - verification - certificate chains - root certificates - - public keys - key agreement - purpose of certificate - main - contents of certificate - contents have increased as time went - by - common file formats for certificates. - </item> - <item>private keys - password protection - key generation - file - formats. - </item> - <item>ssl_pkix and alternate decodings. - </item> - <item>Attribute Certificates (not used by SSL). - </item> - <item>Certificate requests - certificate authorities - signing of - certificates - certificate revocation lists. - </item> - <item>standards: ASN.1, X.509, X.520, PKIX, PKCS, PEM. - </item> - <item>incompatibilities between standards (X.509-1997 vs old) - the - ASN.1 problem of ANY, BIT STRING and OCTET STRING - the module - ssl_pkix. - </item> - <item>test suites: NIST - </item> - <item>Warnings: *creation* of trusted certificate (OpenSSL). - </item> - <item>Erlang SSL and certificates - </item> - <item>The need for seeding the random generator. See also John - S. Denker: High-Entropy Symbol Generator - (http://www.monmouth.com/~jsd). - </item> - <item>links to standards and documents. Books (Rescorla). - </item> - <item>ASN.1 crash course. - </item> - <item>Nagel algorithm. - </item> - </list> - <p>For an introduction to ASN.1 see <url href="http://asn1.elibel.tm.fr/">ASN.1 Information Site</url>. - </p> - </section> -</chapter> - - diff --git a/lib/ssl/doc/src/ssl.xml b/lib/ssl/doc/src/ssl.xml index 9b780b14ce..217eb791d0 100644 --- a/lib/ssl/doc/src/ssl.xml +++ b/lib/ssl/doc/src/ssl.xml @@ -347,39 +347,17 @@ </desc> </func> <func> - <name>peercert(Socket) -> </name> - <name>peercert(Socket, Opts) -> {ok, Cert} | {ok, Subject} | {error, Reason}</name> + <name>peercert(Socket) -> {ok, Cert} | {error, Reason}</name> <fsummary>Return the peer certificate.</fsummary> <type> <v>Socket = sslsocket()</v> - <v>Opts = [pkix | ssl | subject]()</v> - <v>Cert = term()()</v> + <v>Cert = binary()()</v> <v>Subject = term()()</v> </type> <desc> - <p><c>peercert(Cert)</c> is equivalent to <c>peercert(Cert, [])</c>. - </p> - <p>The form of the returned certificate depends on the - options. - </p> - <p>If the options list is empty the certificate is returned as - a DER encoded binary. - </p> - <p>The options <c>pkix</c> and <c>ssl</c> implies that the - certificate is returned as a parsed ASN.1 structure in the - form of an Erlang term. - </p> - <p>The <c>ssl</c> option gives a more elaborate return - structure, with more explicit information. In particular - object identifiers are replaced by atoms. - </p> - <p>The options <c>pkix</c>, and <c>ssl</c> are mutually - exclusive. - </p> - <p>The option <c>subject</c> implies that only the subject's - distinguished name part of the peer certificate is returned. - It can only be used together with the option <c>pkix</c> or - the option <c>ssl</c>.</p> + <p>Returns the DER encoded peer certificate, the certificate can be decoded with + <c>public_key:pkix_decode_cert/2</c>. + </p> </desc> </func> <func> @@ -719,8 +697,7 @@ <section> <title>SEE ALSO</title> - <p>gen_tcp(3), inet(3) - </p> + <p>gen_tcp(3), inet(3) public_key(3) </p> </section> </erlref> diff --git a/lib/stdlib/doc/src/filename.xml b/lib/stdlib/doc/src/filename.xml index 3a6c5e0b60..0cf82fa48b 100644 --- a/lib/stdlib/doc/src/filename.xml +++ b/lib/stdlib/doc/src/filename.xml @@ -37,7 +37,7 @@ is meant all strings that can be used to denote a file. They can be short relative names like <c>foo.erl</c>, very long absolute name which include a drive designator and directory names like - <c>D:\\usr/local\\bin\\erl/lib\\tools\\foo.erl</c>, or any variations + <c>D:\usr/local\bin\erl/lib\tools\foo.erl</c>, or any variations in between.</p> <p>In Windows, all functions return file names with forward slashes only, even if the arguments contain back slashes. Use @@ -173,7 +173,7 @@ name() = string() | atom() | DeepList 14> <input>filename:dirname("kalle.erl").</input> "." -5> <input>filename:dirname("\\\\usr\\\\src/kalle.erl").</input> % Windows +5> <input>filename:dirname("\\usr\\src/kalle.erl").</input> % Windows "/usr/src"</pre> </desc> </func> @@ -228,7 +228,7 @@ name() = string() | atom() | DeepList 18> <input>filename:join(["a/b///c/"]).</input> "a/b/c" -6> <input>filename:join(["B:a\\\\b///c/"]).</input> % Windows +6> <input>filename:join(["B:a\\b///c/"]).</input> % Windows "b:a/b/c"</pre> </desc> </func> @@ -259,7 +259,7 @@ name() = string() | atom() | DeepList "/usr/local/bin" 7> <input>filename:nativename("/usr/local/bin/").</input> % Windows -"\\\\usr\\\\local\\\\bin"</pre> +"\\usr\\local\\bin"</pre> </desc> </func> <func> @@ -329,7 +329,7 @@ name() = string() | atom() | DeepList ["/","usr","local","bin"] 25> <input>filename:split("foo/bar").</input> ["foo","bar"] -26> <input>filename:split("a:\\\\msdev\\\\include").</input> +26> <input>filename:split("a:\\msdev\\include").</input> ["a:/","msdev","include"]</pre> </desc> </func> diff --git a/lib/stdlib/doc/src/gen_fsm.xml b/lib/stdlib/doc/src/gen_fsm.xml index f5d8b9bb48..739cd0bffd 100644 --- a/lib/stdlib/doc/src/gen_fsm.xml +++ b/lib/stdlib/doc/src/gen_fsm.xml @@ -729,6 +729,36 @@ gen_fsm:sync_send_all_state_event -----> Module:handle_sync_event/4 updated internal data.</p> </desc> </func> + <func> + <name>Module:format_status(normal, [PDict, StateData]) -> Status</name> + <fsummary>Optional function for providing a term describing the + current gen_fsm status.</fsummary> + <type> + <v>PDict = [{Key, Value}]</v> + <v>StateData = term()</v> + <v>Status = [term()]</v> + </type> + <desc> + <p><em>This callback is optional, so callback modules need not + export it. The gen_fsm module provides a default + implementation of this function that returns the callback + module state data.</em></p> + <p>This function is called by a gen_fsm process when one + of <seealso marker="sys#get_status/1">sys:get_status/1,2</seealso> + is invoked to get the gen_fsm status. A callback module + wishing to customise the <c>sys:get_status/1,2</c> return + value exports an instance of <c>format_status/2</c> that + returns a term describing the current status of the + gen_fsm.</p> + <p><c>PDict</c> is the current value of the gen_fsm's + process dictionary.</p> + <p><c>StateData</c> is the internal state data of the + gen_fsm.</p> + <p>The function should return <c>Status</c>, a list of one or + more terms that customise the details of the current state + and status of the gen_fsm.</p> + </desc> + </func> </funcs> <section> diff --git a/lib/stdlib/doc/src/gen_server.xml b/lib/stdlib/doc/src/gen_server.xml index 8496802259..30c04d1d52 100644 --- a/lib/stdlib/doc/src/gen_server.xml +++ b/lib/stdlib/doc/src/gen_server.xml @@ -598,6 +598,35 @@ gen_server:abcast -----> Module:handle_cast/2 <p>The function should return the updated internal state.</p> </desc> </func> + <func> + <name>Module:format_status(normal, [PDict, State]) -> Status</name> + <fsummary>Optional function for providing a term describing the + current gen_server status.</fsummary> + <type> + <v>PDict = [{Key, Value}]</v> + <v>State = term()</v> + <v>Status = [term()]</v> + </type> + <desc> + <p><em>This callback is optional, so callback modules need not + export it. The gen_server module provides a default + implementation of this function that returns the callback + module state.</em></p> + <p>This function is called by a gen_server process when one + of <seealso marker="sys#get_status/1">sys:get_status/1,2</seealso> + is invoked to get the gen_server status. A callback module + wishing to customise the <c>sys:get_status/1,2</c> return + value exports an instance of <c>format_status/2</c> that + returns a term describing the current status of the + gen_server.</p> + <p><c>PDict</c> is the current value of the gen_server's + process dictionary.</p> + <p><c>State</c> is the internal state of the gen_server.</p> + <p>The function should return <c>Status</c>, a list of one or + more terms that customise the details of the current state + and status of the gen_server.</p> + </desc> + </func> </funcs> <section> diff --git a/lib/stdlib/doc/src/io_protocol.xml b/lib/stdlib/doc/src/io_protocol.xml index 1b75114031..201787f7b5 100644 --- a/lib/stdlib/doc/src/io_protocol.xml +++ b/lib/stdlib/doc/src/io_protocol.xml @@ -546,7 +546,7 @@ request({get_chars, Encoding, _Prompt, N}, State) -> get_until(Encoding, ?MODULE, until_enough, [N], State); request({get_line, Encoding, _Prompt}, State) -> %% To simplify the code, get_line is implemented using get_until - get_until(Encoding, ?MODULE, until_newline, [$\\n], State); + get_until(Encoding, ?MODULE, until_newline, [$\n], State); </code> <p>Here we have cheated a little by more or less only implementing diff --git a/lib/stdlib/doc/src/re.xml b/lib/stdlib/doc/src/re.xml index 41dce7f2a7..e9a32a59d4 100644 --- a/lib/stdlib/doc/src/re.xml +++ b/lib/stdlib/doc/src/re.xml @@ -56,10 +56,10 @@ <note> <p>The Erlang literal syntax for strings give special - meaning to the "\\" (backslash) character. To literally write + meaning to the "\" (backslash) character. To literally write a regular expression or a replacement string containing a backslash in your code or in the shell, two backslashes have to be written: - "\\\\".</p> + "\\".</p> </note> @@ -163,9 +163,9 @@ This option makes it possible to include comments inside complicated patterns. N </taglist> </item> <tag><c>bsr_anycrlf</c></tag> - <item>Specifies specifically that \\R is to match only the cr, lf or crlf sequences, not the Unicode specific newline characters.</item> + <item>Specifies specifically that \R is to match only the cr, lf or crlf sequences, not the Unicode specific newline characters.</item> <tag><c>bsr_unicode</c></tag> - <item>Specifies specifically that \\R is to match all the Unicode newline characters (including crlf etc, the default).</item> + <item>Specifies specifically that \R is to match all the Unicode newline characters (including crlf etc, the default).</item> </taglist> </desc> </func> @@ -384,9 +384,9 @@ This option makes it possible to include comments inside complicated patterns. N </taglist> </item> <tag><c>bsr_anycrlf</c></tag> - <item>Specifies specifically that \\R is to match only the cr, lf or crlf sequences, not the Unicode specific newline characters.(overrides compilation option)</item> + <item>Specifies specifically that \R is to match only the cr, lf or crlf sequences, not the Unicode specific newline characters.(overrides compilation option)</item> <tag><c>bsr_unicode</c></tag> - <item>Specifies specifically that \\R is to match all the Unicode newline characters (including crlf etc, the default).(overrides compilation option)</item> + <item>Specifies specifically that \R is to match all the Unicode newline characters (including crlf etc, the default).(overrides compilation option)</item> <tag><c>{capture, ValueSpec}</c>/<c>{capture, ValueSpec, Type}</c></tag> <item> @@ -471,9 +471,9 @@ This option makes it possible to include comments inside complicated patterns. N <tag><c>index</c></tag> <item>Return captured substrings as pairs of byte indexes into the subject string and length of the matching string in the subject (as if the subject string was flattened with <c>iolist_to_binary/1</c> or <c>unicode:characters_to_binary/2</c> prior to matching). Note that the <c>unicode</c> option results in <em>byte-oriented</em> indexes in a (possibly imagined) <em>UTF-8 encoded</em> binary. A byte index tuple <c>{0,2}</c> might therefore represent one or two characters when <c>unicode</c> is in effect. This might seem contra-intuitive, but has been deemed the most effective and useful way to way to do it. To return lists instead might result in simpler code if that is desired. This return type is the default.</item> <tag><c>list</c></tag> - <item>Return matching substrings as lists of characters (Erlang <c>string()</c>'s). It the <c>unicode</c> option is used in combination with the \\C sequence in the regular expression, a captured subpattern can contain bytes that has is not valid UTF-8 (\\C matches bytes regardless of character encoding). In that case the <c>list</c> capturing may result in the same types of tuples that <c>unicode:characters_to_list/2</c> can return, namely three-tuples with the tag <c>incomplete</c> or <c>error</c>, the successfully converted characters and the invalid UTF-8 tail of the conversion as a binary. The best strategy is to avoid using the\\C sequence when capturing lists.</item> + <item>Return matching substrings as lists of characters (Erlang <c>string()</c>'s). It the <c>unicode</c> option is used in combination with the \C sequence in the regular expression, a captured subpattern can contain bytes that has is not valid UTF-8 (\C matches bytes regardless of character encoding). In that case the <c>list</c> capturing may result in the same types of tuples that <c>unicode:characters_to_list/2</c> can return, namely three-tuples with the tag <c>incomplete</c> or <c>error</c>, the successfully converted characters and the invalid UTF-8 tail of the conversion as a binary. The best strategy is to avoid using the \C sequence when capturing lists.</item> <tag><c>binary</c></tag> - <item>Return matching substrings as binaries. If the <c>unicode</c> option is used, these binaries is in UTF-8. If the \\C sequence is used together with <c>unicode</c> the binaries may be invalid UTF-8.</item> + <item>Return matching substrings as binaries. If the <c>unicode</c> option is used, these binaries is in UTF-8. If the \C sequence is used together with <c>unicode</c> the binaries may be invalid UTF-8.</item> </taglist> </item> </taglist> @@ -544,20 +544,20 @@ This option makes it possible to include comments inside complicated patterns. N <p>The replacement string can contain the special character <c>&</c>, which inserts the whole matching expression in the - result, and the special sequence <c>\\</c>N (where N is an + result, and the special sequence <c>\</c>N (where N is an integer > 0), resulting in the subexpression number N will be inserted in the result. If no subexpression with that number is generated by the regular expression, nothing is inserted.</p> - <p>To insert an <c>&</c> or <c>\\</c> in the result, precede it - with a <c>\\</c>. Note that Erlang already gives a special - meaning to <c>\\</c> in literal strings, why a single <c>\\</c> - has to be written as <c>"\\\\"</c> and therefore a double <c>\\</c> - as <c>"\\\\\\\\"</c>. Example:</p> + <p>To insert an <c>&</c> or <c>\</c> in the result, precede it + with a <c>\</c>. Note that Erlang already gives a special + meaning to <c>\</c> in literal strings, why a single <c>\</c> + has to be written as <c>"\\"</c> and therefore a double <c>\</c> + as <c>"\\\\"</c>. Example:</p> <code> re:replace("abcd","c","[&]",[{return,list}]).</code> <p>gives</p> <code> "ab[c]d"</code> <p>while</p> - <code> re:replace("abcd","c","[\\\&]",[{return,list}]).</code> + <code> re:replace("abcd","c","[\\&]",[{return,list}]).</code> <p>gives</p> <code> "ab[&]d"</code> <p>As with <c>re:run/3</c>, compilation errors raise the <c>badarg</c> @@ -852,19 +852,19 @@ example, the pattern:</p> <p> (*CR)a.b</p> </quote> -<p>changes the convention to CR. That pattern matches "a\\nb" because LF is no +<p>changes the convention to CR. That pattern matches "a\nb" because LF is no longer a newline. Note that these special settings, which are not Perl-compatible, are recognized only at the very start of a pattern, and that they must be in upper case. If more than one of them is present, the last one is used.</p> -<p>The newline convention does not affect what the \\R escape sequence matches. By +<p>The newline convention does not affect what the \R escape sequence matches. By default, this is any Unicode newline sequence, for Perl compatibility. However, -this can be changed; see the description of \\R in the section entitled +this can be changed; see the description of \R in the section entitled "Newline sequences" -below. A change of \\R setting can be combined with a change of newline +below. A change of \R setting can be combined with a change of newline convention.</p> </section> @@ -897,7 +897,7 @@ recognized within square brackets. Outside square brackets, the metacharacters are as follows:</p> <taglist> - <tag>\\</tag> <item>general escape character with several uses</item> + <tag>\</tag> <item>general escape character with several uses</item> <tag>^</tag> <item>assert start of string (or line, in multiline mode)</item> <tag>$</tag> <item>assert end of string (or line, in multiline mode)</item> <tag>.</tag> <item>match any character except newline (by default)</item> @@ -918,7 +918,7 @@ are as follows:</p> a character class the only metacharacters are:</p> <taglist> - <tag>\\</tag> <item>general escape character</item> + <tag>\</tag> <item>general escape character</item> <tag>^</tag> <item>negate the class, but only if the first character</item> <tag>-</tag> <item>indicates character range</item> <tag>[</tag> <item>POSIX character class (only if followed by POSIX @@ -939,11 +939,11 @@ non-alphanumeric character, it takes away any special meaning that character may have. This use of backslash as an escape character applies both inside and outside character classes.</p> -<p>For example, if you want to match a * character, you write \\* in the pattern. +<p>For example, if you want to match a * character, you write \* in the pattern. This escaping action applies whether or not the following character would otherwise be interpreted as a metacharacter, so it is always safe to precede a non-alphanumeric with backslash to specify that it stands for itself. In -particular, if you want to match a backslash, you write \\\\.</p> +particular, if you want to match a backslash, you write \\.</p> <p>If a pattern is compiled with the <c>extended</c> option, whitespace in the pattern (other than in a character class) and characters between a # outside @@ -951,18 +951,18 @@ a character class and the next newline are ignored. An escaping backslash can be used to include a whitespace or # character as part of the pattern.</p> <p>If you want to remove the special meaning from a sequence of characters, you -can do so by putting them between \\Q and \\E. This is different from Perl in -that $ and @ are handled as literals in \\Q...\\E sequences in PCRE, whereas in +can do so by putting them between \Q and \E. This is different from Perl in +that $ and @ are handled as literals in \Q...\E sequences in PCRE, whereas in Perl, $ and @ cause variable interpolation. Note the following examples:</p> <code type="none"> Pattern PCRE matches Perl matches - \\Qabc$xyz\\E abc$xyz abc followed by the contents of $xyz - \\Qabc\\$xyz\\E abc\\$xyz abc\\$xyz - \\Qabc\\E\\$\\Qxyz\\E abc$xyz abc$xyz</code> + \Qabc$xyz\E abc$xyz abc followed by the contents of $xyz + \Qabc\$xyz\E abc\$xyz abc\$xyz + \Qabc\E\$\Qxyz\E abc$xyz abc$xyz</code> -<p>The \\Q...\\E sequence is recognized both inside and outside character classes.</p> +<p>The \Q...\E sequence is recognized both inside and outside character classes.</p> <p><em>Non-printing characters</em></p> @@ -975,41 +975,41 @@ use one of the following escape sequences than the binary character it represents:</p> <taglist> - <tag>\\a</tag> <item>alarm, that is, the BEL character (hex 07)</item> - <tag>\\cx</tag> <item>"control-x", where x is any character</item> - <tag>\\e </tag> <item>escape (hex 1B)</item> - <tag>\\f</tag> <item>formfeed (hex 0C)</item> - <tag>\\n</tag> <item>linefeed (hex 0A)</item> - <tag>\\r</tag> <item>carriage return (hex 0D)</item> - <tag>\\t </tag> <item>tab (hex 09)</item> - <tag>\\ddd</tag> <item>character with octal code ddd, or backreference</item> - <tag>\\xhh </tag> <item>character with hex code hh</item> - <tag>\\x{hhh..}</tag> <item>character with hex code hhh..</item> + <tag>\a</tag> <item>alarm, that is, the BEL character (hex 07)</item> + <tag>\cx</tag> <item>"control-x", where x is any character</item> + <tag>\e </tag> <item>escape (hex 1B)</item> + <tag>\f</tag> <item>formfeed (hex 0C)</item> + <tag>\n</tag> <item>linefeed (hex 0A)</item> + <tag>\r</tag> <item>carriage return (hex 0D)</item> + <tag>\t </tag> <item>tab (hex 09)</item> + <tag>\ddd</tag> <item>character with octal code ddd, or backreference</item> + <tag>\xhh </tag> <item>character with hex code hh</item> + <tag>\x{hhh..}</tag> <item>character with hex code hhh..</item> </taglist> -<p>The precise effect of \\cx is as follows: if x is a lower case letter, it +<p>The precise effect of \cx is as follows: if x is a lower case letter, it is converted to upper case. Then bit 6 of the character (hex 40) is inverted. -Thus \\cz becomes hex 1A, but \\c{ becomes hex 3B, while \\c; becomes hex +Thus \cz becomes hex 1A, but \c{ becomes hex 3B, while \c; becomes hex 7B.</p> -<p>After \\x, from zero to two hexadecimal digits are read (letters can be in -upper or lower case). Any number of hexadecimal digits may appear between \\x{ +<p>After \x, from zero to two hexadecimal digits are read (letters can be in +upper or lower case). Any number of hexadecimal digits may appear between \x{ and }, but the value of the character code must be less than 256 in non-UTF-8 mode, and less than 2**31 in UTF-8 mode. That is, the maximum value in hexadecimal is 7FFFFFFF. Note that this is bigger than the largest Unicode code point, which is 10FFFF.</p> -<p>If characters other than hexadecimal digits appear between \\x{ and }, or if +<p>If characters other than hexadecimal digits appear between \x{ and }, or if there is no terminating }, this form of escape is not recognized. Instead, the -initial \\x will be interpreted as a basic hexadecimal escape, with no +initial \x will be interpreted as a basic hexadecimal escape, with no following digits, giving a character whose value is zero.</p> <p>Characters whose value is less than 256 can be defined by either of the two -syntaxes for \\x. There is no difference in the way they are handled. For -example, \\xdc is exactly the same as \\x{dc}.</p> +syntaxes for \x. There is no difference in the way they are handled. For +example, \xdc is exactly the same as \x{dc}.</p> -<p>After \\0 up to two further octal digits are read. If there are fewer than two -digits, just those that are present are used. Thus the sequence \\0\\x\\07 +<p>After \0 up to two further octal digits are read. If there are fewer than two +digits, just those that are present are used. Thus the sequence \0\x\07 specifies two binary zeros followed by a BEL character (code value 7). Make sure you supply two digits after the initial zero if the pattern character that follows is itself an octal digit.</p> @@ -1027,32 +1027,32 @@ have not been that many capturing subpatterns, PCRE re-reads up to three octal digits following the backslash, and uses them to generate a data character. Any subsequent digits stand for themselves. The value of a -character specified in octal must be less than \\400. +character specified in octal must be less than \400. In non-UTF-8 mode, the value of a -character specified in octal must be less than \\400. In UTF-8 mode, values up -to \\777 are permitted. +character specified in octal must be less than \400. In UTF-8 mode, values up +to \777 are permitted. For example:</p> <taglist> - <tag>\\040</tag> <item>is another way of writing a space</item> + <tag>\040</tag> <item>is another way of writing a space</item> - <tag>\\40</tag> <item>is the same, provided there are fewer than 40 + <tag>\40</tag> <item>is the same, provided there are fewer than 40 previous capturing subpatterns</item> - <tag>\\7</tag> <item>is always a back reference</item> + <tag>\7</tag> <item>is always a back reference</item> - <tag>\\11</tag> <item> might be a back reference, or another way of + <tag>\11</tag> <item> might be a back reference, or another way of writing a tab</item> - <tag>\\011</tag> <item>is always a tab</item> - <tag>\\0113</tag> <item>is a tab followed by the character "3"</item> + <tag>\011</tag> <item>is always a tab</item> + <tag>\0113</tag> <item>is a tab followed by the character "3"</item> - <tag>\\113</tag> <item>might be a back reference, otherwise the + <tag>\113</tag> <item>might be a back reference, otherwise the character with octal code 113</item> - <tag>\\377</tag> <item>might be a back reference, otherwise + <tag>\377</tag> <item>might be a back reference, otherwise the byte consisting entirely of 1 bits</item> - <tag>\\81</tag> <item>is either a back reference, or a binary zero + <tag>\81</tag> <item>is either a back reference, or a binary zero followed by the two characters "8" and "1"</item> </taglist> @@ -1062,16 +1062,16 @@ read.</p> <p>All the sequences that define a single character value can be used both inside and outside character classes. In addition, inside a -character class, the sequence \\b is interpreted as the backspace -character (hex 08), and the sequences \\R and \\X are interpreted as +character class, the sequence \b is interpreted as the backspace +character (hex 08), and the sequences \R and \X are interpreted as the characters "R" and "X", respectively. Outside a character class, these sequences have different meanings (see below).</p> <p><em>Absolute and relative back references</em></p> -<p>The sequence \\g followed by an unsigned or a negative number, +<p>The sequence \g followed by an unsigned or a negative number, optionally enclosed in braces, is an absolute or relative back -reference. A named back reference can be coded as \\g{name}. Back +reference. A named back reference can be coded as \g{name}. Back references are discussed later, following the discussion of parenthesized subpatterns.</p> @@ -1081,16 +1081,16 @@ parenthesized subpatterns.</p> following are always recognized:</p> <taglist> - <tag>\\d</tag> <item>any decimal digit</item> - <tag>\\D</tag> <item>any character that is not a decimal digit</item> - <tag>\\h</tag> <item>any horizontal whitespace character</item> - <tag>\\H</tag> <item>any character that is not a horizontal whitespace character</item> - <tag>\\s</tag> <item>any whitespace character</item> - <tag>\\S</tag> <item>any character that is not a whitespace character</item> - <tag>\\v</tag> <item>any vertical whitespace character</item> - <tag>\\V</tag> <item>any character that is not a vertical whitespace character</item> - <tag>\\w</tag> <item>any "word" character</item> - <tag>\\W</tag> <item>any "non-word" character</item> + <tag>\d</tag> <item>any decimal digit</item> + <tag>\D</tag> <item>any character that is not a decimal digit</item> + <tag>\h</tag> <item>any horizontal whitespace character</item> + <tag>\H</tag> <item>any character that is not a horizontal whitespace character</item> + <tag>\s</tag> <item>any whitespace character</item> + <tag>\S</tag> <item>any character that is not a whitespace character</item> + <tag>\v</tag> <item>any vertical whitespace character</item> + <tag>\V</tag> <item>any character that is not a vertical whitespace character</item> + <tag>\w</tag> <item>any "word" character</item> + <tag>\W</tag> <item>any "non-word" character</item> </taglist> <p>Each pair of escape sequences partitions the complete set of characters into @@ -1101,19 +1101,19 @@ classes. They each match one character of the appropriate type. If the current matching point is at the end of the subject string, all of them fail, since there is no character to match.</p> -<p>For compatibility with Perl, \\s does not match the VT character (code 11). -This makes it different from the POSIX "space" class. The \\s characters +<p>For compatibility with Perl, \s does not match the VT character (code 11). +This makes it different from the POSIX "space" class. The \s characters are HT (9), LF (10), FF (12), CR (13), and space (32). If "use locale;" is -included in a Perl script, \\s may match the VT character. In PCRE, it never +included in a Perl script, \s may match the VT character. In PCRE, it never does.</p> -<p>In UTF-8 mode, characters with values greater than 128 never match \\d, \\s, or -\\w, and always match \\D, \\S, and \\W. This is true even when Unicode +<p>In UTF-8 mode, characters with values greater than 128 never match \d, \s, or +\w, and always match \D, \S, and \W. This is true even when Unicode character property support is available. These sequences retain their original meanings from before UTF-8 support was available, mainly for efficiency reasons.</p> -<p>The sequences \\h, \\H, \\v, and \\V are Perl 5.10 features. In contrast to the +<p>The sequences \h, \H, \v, and \V are Perl 5.10 features. In contrast to the other sequences, these do match certain high-valued codepoints in UTF-8 mode. The horizontal space characters are:</p> @@ -1157,11 +1157,11 @@ low-valued character tables, which are always ISO-8859-1.</p> <p><em>Newline sequences</em></p> -<p>Outside a character class, by default, the escape sequence \\R matches any -Unicode newline sequence. This is a Perl 5.10 feature. In non-UTF-8 mode \\R is +<p>Outside a character class, by default, the escape sequence \R matches any +Unicode newline sequence. This is a Perl 5.10 feature. In non-UTF-8 mode \R is equivalent to the following:</p> -<quote><p> (?>\\r\\n|\\n|\\x0b|\\f|\\r|\\x85)</p></quote> +<quote><p> (?>\r\n|\n|\x0b|\f|\r|\x85)</p></quote> <p>This is an example of an "atomic group", details of which are given below.</p> @@ -1177,7 +1177,7 @@ Unicode character property support is not needed for these characters to be recognized.</p> -<p>It is possible to restrict \\R to match only CR, LF, or CRLF (instead of the +<p>It is possible to restrict \R to match only CR, LF, or CRLF (instead of the complete set of Unicode line endings) by setting the option <c>bsr_anycrlf</c> either at compile time or when the pattern is matched. (BSR is an abbreviation for "backslash R".) This can be made the default when PCRE is built; if this is @@ -1197,7 +1197,7 @@ newline convention, for example, a pattern can start with:</p> <p> (*ANY)(*BSR_ANYCRLF)</p> -<p>Inside a character class, \\R matches the letter "R".</p> +<p>Inside a character class, \R matches the letter "R".</p> <p><em>Unicode character properties</em></p> @@ -1208,22 +1208,22 @@ When not in UTF-8 mode, these sequences are of course limited to testing characters whose codepoints are less than 256, but they do work in this mode. The extra escape sequences are:</p> -<p> \\p{<em>xx</em>} a character with the <em>xx</em> property - \\P{<em>xx</em>} a character without the <em>xx</em> property - \\X an extended Unicode sequence</p> +<p> \p{<em>xx</em>} a character with the <em>xx</em> property + \P{<em>xx</em>} a character without the <em>xx</em> property + \X an extended Unicode sequence</p> <p>The property names represented by <em>xx</em> above are limited to the Unicode script names, the general category properties, and "Any", which matches any character (including newline). Other properties such as "InMusicalSymbols" are -not currently supported by PCRE. Note that \\P{Any} does not match any +not currently supported by PCRE. Note that \P{Any} does not match any characters, so always causes a match failure.</p> <p>Sets of Unicode characters are defined as belonging to certain scripts. A character from one of these sets can be matched using a script name. For example:</p> -<p> \\p{Greek} - \\P{Han}</p> +<p> \p{Greek} + \P{Han}</p> <p>Those that are not part of an identified script are lumped together as "Common". The current list of scripts is:</p> @@ -1300,15 +1300,15 @@ example:</p> <p>Each character has exactly one general category property, specified by a two-letter abbreviation. For compatibility with Perl, negation can be specified by including a circumflex between the opening brace and the property name. For -example, \\p{^Lu} is the same as \\P{Lu}.</p> +example, \p{^Lu} is the same as \P{Lu}.</p> -<p>If only one letter is specified with \\p or \\P, it includes all the general +<p>If only one letter is specified with \p or \P, it includes all the general category properties that start with that letter. In this case, in the absence of negation, the curly brackets in the escape sequence are optional; these two examples have the same effect:</p> -<list><item>\\p{L}</item> - <item>\\pL</item></list> +<list><item>\p{L}</item> + <item>\pL</item></list> <p>The following general category property codes are supported:</p> @@ -1382,7 +1382,7 @@ cannot be tested by PCRE, unless UTF-8 validity checking has been turned off <em>pcreapi</em> page).</p> -<p>The long synonyms for these properties that Perl supports (such as \\p{Letter}) +<p>The long synonyms for these properties that Perl supports (such as \p{Letter}) are not supported by PCRE, nor is it permitted to prefix any of these properties with "Is".</p> @@ -1391,12 +1391,12 @@ Instead, this property is assumed for any code point that is not in the Unicode table.</p> <p>Specifying caseless matching does not affect these escape sequences. For -example, \\p{Lu} always matches only upper case letters.</p> +example, \p{Lu} always matches only upper case letters.</p> -<p>The \\X escape matches any number of Unicode characters that form an extended -Unicode sequence. \\X is equivalent to</p> +<p>The \X escape matches any number of Unicode characters that form an extended +Unicode sequence. \X is equivalent to</p> -<quote><p> (?>\\PM\\pM*)</p></quote> +<quote><p> (?>\PM\pM*)</p></quote> <p>That is, it matches a character without the "mark" property, followed by zero or more characters with the "mark" property, and treats the sequence as an @@ -1404,20 +1404,20 @@ atomic group (see below). Characters with the "mark" property are typically accents that affect the preceding character. None of them have codepoints less than 256, so in -non-UTF-8 mode \\X matches any one character.</p> +non-UTF-8 mode \X matches any one character.</p> <p>Matching characters by Unicode property is not fast, because PCRE has to search a structure that contains data for over fifteen thousand characters. That is -why the traditional escape sequences such as \\d and \\w do not use Unicode +why the traditional escape sequences such as \d and \w do not use Unicode properties in PCRE.</p> <p><em>Resetting the match start</em></p> -<p>The escape sequence \\K, which is a Perl 5.10 feature, causes any previously +<p>The escape sequence \K, which is a Perl 5.10 feature, causes any previously matched characters not to be included in the final matched sequence. For example, the pattern:</p> -<quote><p> foo\\Kbar</p></quote> +<quote><p> foo\Kbar</p></quote> <p>matches "foobar", but reports that it has matched "bar". This feature is similar to a lookbehind assertion @@ -1426,12 +1426,12 @@ similar to a lookbehind assertion (described below). However, in this case, the part of the subject before the real match does not -have to be of fixed length, as lookbehind assertions do. The use of \\K does +have to be of fixed length, as lookbehind assertions do. The use of \K does not interfere with the setting of captured substrings. For example, when the pattern</p> -<quote><p> (foo)\\Kbar</p></quote> +<quote><p> (foo)\Kbar</p></quote> <p>matches "foobar", the first substring is still set to "foo".</p> @@ -1444,50 +1444,50 @@ string. The use of subpatterns for more complicated assertions is described below. The backslashed assertions are:</p> <taglist> - <tag>\\b</tag> <item>matches at a word boundary</item> - <tag>\\B</tag> <item>matches when not at a word boundary</item> - <tag>\\A</tag> <item>matches at the start of the subject</item> - <tag>\\Z</tag> <item>matches at the end of the subject + <tag>\b</tag> <item>matches at a word boundary</item> + <tag>\B</tag> <item>matches when not at a word boundary</item> + <tag>\A</tag> <item>matches at the start of the subject</item> + <tag>\Z</tag> <item>matches at the end of the subject also matches before a newline at the end of the subject</item> - <tag>\\z</tag> <item>matches only at the end of the subject</item> - <tag>\\G</tag> <item>matches at the first matching position in the + <tag>\z</tag> <item>matches only at the end of the subject</item> + <tag>\G</tag> <item>matches at the first matching position in the subject</item> </taglist> -<p>These assertions may not appear in character classes (but note that \\b has a +<p>These assertions may not appear in character classes (but note that \b has a different meaning, namely the backspace character, inside a character class).</p> <p>A word boundary is a position in the subject string where the current character -and the previous character do not both match \\w or \\W (i.e. one matches -\\w and the other matches \\W), or the start or end of the string if the -first or last character matches \\w, respectively.</p> +and the previous character do not both match \w or \W (i.e. one matches +\w and the other matches \W), or the start or end of the string if the +first or last character matches \w, respectively.</p> -<p>The \\A, \\Z, and \\z assertions differ from the traditional circumflex and +<p>The \A, \Z, and \z assertions differ from the traditional circumflex and dollar (described in the next section) in that they only ever match at the very start and end of the subject string, whatever options are set. Thus, they are independent of multiline mode. These three assertions are not affected by the <c>notbol</c> or <c>noteol</c> options, which affect only the behaviour of the circumflex and dollar metacharacters. However, if the <em>startoffset</em> argument of <c>re:run/3</c> is non-zero, indicating that matching is to start -at a point other than the beginning of the subject, \\A can never match. The -difference between \\Z and \\z is that \\Z matches before a newline at the end -of the string as well as at the very end, whereas \\z matches only at the end.</p> +at a point other than the beginning of the subject, \A can never match. The +difference between \Z and \z is that \Z matches before a newline at the end +of the string as well as at the very end, whereas \z matches only at the end.</p> -<p>The \\G assertion is true only when the current matching position is at the +<p>The \G assertion is true only when the current matching position is at the start point of the match, as specified by the <em>startoffset</em> argument of -<c>re:run/3</c>. It differs from \\A when the value of <em>startoffset</em> is +<c>re:run/3</c>. It differs from \A when the value of <em>startoffset</em> is non-zero. By calling <c>re:run/3</c> multiple times with appropriate arguments, you can mimic Perl's /g option, and it is in this kind of -implementation where \\G can be useful.</p> +implementation where \G can be useful.</p> -<p>Note, however, that PCRE's interpretation of \\G, as the start of the current +<p>Note, however, that PCRE's interpretation of \G, as the start of the current match, is subtly different from Perl's, which defines it as the end of the previous match. In Perl, these can be different when the previously matched string was empty. Because PCRE does just one match at a time, it cannot reproduce this behaviour.</p> -<p>If all the alternatives of a pattern begin with \\G, the expression is anchored +<p>If all the alternatives of a pattern begin with \G, the expression is anchored to the starting match position, and the "anchored" flag is set in the compiled regular expression.</p> @@ -1519,7 +1519,7 @@ character class.</p> <p>The meaning of dollar can be changed so that it matches only at the very end of the string, by setting the <c>dollar_endonly</c> option at -compile time. This does not affect the \\Z assertion.</p> +compile time. This does not affect the \Z assertion.</p> <p>The meanings of the circumflex and dollar characters are changed if the <c>multiline</c> option is set. When this is the case, a circumflex matches @@ -1530,16 +1530,16 @@ matches before any newlines in the string, as well as at the very end, when sequence CRLF, isolated CR and LF characters do not indicate newlines.</p> <p>For example, the pattern /^abc$/ matches the subject string -"def\\nabc" (where \\n represents a newline) in multiline mode, but +"def\nabc" (where \n represents a newline) in multiline mode, but not otherwise. Consequently, patterns that are anchored in single line mode because all branches start with ^ are not anchored in multiline mode, and a match for circumflex is possible when the <em>startoffset</em> argument of <c>re:run/3</c> is non-zero. The <c>dollar_endonly</c> option is ignored if <c>multiline</c> is set.</p> -<p>Note that the sequences \\A, \\Z, and \\z can be used to match the start and +<p>Note that the sequences \A, \Z, and \z can be used to match the start and end of the subject in both modes, and if all branches of a pattern start with -\\A it is always anchored, whether or not <c>multiline</c> is set.</p> +\A it is always anchored, whether or not <c>multiline</c> is set.</p> </section> @@ -1574,14 +1574,14 @@ involve newlines. Dot has no special meaning in a character class.</p> <section><marker id="sect6"></marker><title>Matching a single byte</title> -<p>Outside a character class, the escape sequence \\C matches any one byte, both +<p>Outside a character class, the escape sequence \C matches any one byte, both in and out of UTF-8 mode. Unlike a dot, it always matches any line-ending characters. The feature is provided in Perl in order to match individual bytes in UTF-8 mode. Because it breaks up UTF-8 characters into individual bytes, what remains in the string may be a malformed UTF-8 string. For this reason, -the \\C escape sequence is best avoided.</p> +the \C escape sequence is best avoided.</p> -<p>PCRE does not allow \\C to appear in lookbehind assertions (described below), +<p>PCRE does not allow \C to appear in lookbehind assertions (described below), because in UTF-8 mode this would make it impossible to calculate the length of the lookbehind.</p> @@ -1615,7 +1615,7 @@ string, and therefore it fails if the current pointer is at the end of the string.</p> <p>In UTF-8 mode, characters with values greater than 255 can be included in a -class as a literal string of bytes, or by using the \\x{ escaping mechanism.</p> +class as a literal string of bytes, or by using the \x{ escaping mechanism.</p> <p>When caseless matching is set, any letters in a class represent both their upper case and lower case versions, so for example, a caseless [aeiou] matches @@ -1648,32 +1648,32 @@ character of a range. A pattern such as [W-]46] is interpreted as a class of two characters ("W" and "-") followed by a literal string "46]", so it would match "W46]" or "-46]". However, if the "]" is escaped with a backslash it is interpreted as the end of range, so -[W-\\]46] is interpreted as a class containing a range followed by two +[W-\]46] is interpreted as a class containing a range followed by two other characters. The octal or hexadecimal representation of "]" can also be used to end a range.</p> <p>Ranges operate in the collating sequence of character values. They can also be -used for characters specified numerically, for example [\\000-\\037]. +used for characters specified numerically, for example [\000-\037]. In UTF-8 mode, ranges can include characters whose values are greater than 255, for -example [\\x{100}-\\x{2ff}]. +example [\x{100}-\x{2ff}]. </p> <p>If a range that includes letters is used when caseless matching is set, it matches the letters in either case. For example, [W-c] is equivalent to -[][\\\\^_`wxyzabc], matched caselessly +[][\\^_`wxyzabc], matched caselessly , and in non-UTF-8 mode, if character -tables for a French locale are in use, [\\xc8-\\xcb] matches accented E +tables for a French locale are in use, [\xc8-\xcb] matches accented E characters in both cases. In UTF-8 mode, PCRE supports the concept of case for characters with values greater than 128 only when it is compiled with Unicode property support.</p> -<p>The character types \\d, \\D, \\p, \\P, \\s, \\S, \\w, and \\W may +<p>The character types \d, \D, \p, \P, \s, \S, \w, and \W may also appear in a character class, and add the characters that they -match to the class. For example, [\\dABCDEF] matches any hexadecimal +match to the class. For example, [\dABCDEF] matches any hexadecimal digit. A circumflex can conveniently be used with the upper case character types to specify a more restricted set of characters than -the matching lower case type. For example, the class [^\\W_] matches +the matching lower case type. For example, the class [^\W_] matches any letter or digit, but not underscore.</p> <p>The only metacharacters that are recognized in character classes @@ -1702,20 +1702,20 @@ are</p> <tag>ascii</tag> <item>character codes 0 - 127</item> <tag>blank</tag> <item>space or tab only</item> <tag>cntrl</tag> <item>control characters</item> - <tag>digit</tag> <item>decimal digits (same as \\d)</item> + <tag>digit</tag> <item>decimal digits (same as \d)</item> <tag>graph</tag> <item>printing characters, excluding space</item> <tag>lower</tag> <item>lower case letters</item> <tag>print</tag> <item>printing characters, including space</item> <tag>punct</tag> <item>printing characters, excluding letters and digits</item> - <tag>space</tag> <item>whitespace (not quite the same as \\s)</item> + <tag>space</tag> <item>whitespace (not quite the same as \s)</item> <tag>upper</tag> <item>upper case letters</item> - <tag>word</tag> <item>"word" characters (same as \\w)</item> + <tag>word</tag> <item>"word" characters (same as \w)</item> <tag>xdigit</tag> <item>hexadecimal digits</item> </taglist> <p>The "space" characters are HT (9), LF (10), VT (11), FF (12), CR (13), and space (32). Notice that this list includes the VT character (code 11). This -makes "space" different to \\s, which does not include VT (for Perl +makes "space" different to \s, which does not include VT (for Perl compatibility).</p> <p>The name "word" is a Perl extension, and "blank" is a GNU extension @@ -1936,7 +1936,7 @@ match. Suppose you want to match the name of a weekday, either as a 3-letter abbreviation or as the full name, and in both cases you want to extract the abbreviation. This pattern (ignoring the line breaks) does the job:</p> -<code type="none"> +<code type="none"> (?<DN>Mon|Fri|Sun)(?:day)?| (?<DN>Tue)(?:sday)?| (?<DN>Wed)(?:nesday)?| @@ -1972,12 +1972,12 @@ following items:</p> <list> <item>a literal data character</item> <item>the dot metacharacter</item> - <item>the \\C escape sequence</item> - <item>the \\X escape sequence + <item>the \C escape sequence</item> + <item>the \X escape sequence (in UTF-8 mode with Unicode properties) </item> - <item>the \\R escape sequence</item> - <item>an escape such as \\d that matches a single character</item> + <item>the \R escape sequence</item> + <item>an escape such as \d that matches a single character</item> <item>a character class</item> <item>a back reference (see next section)</item> <item>a parenthesized subpattern (unless it is an assertion)</item> @@ -1999,7 +1999,7 @@ quantifier specifies an exact number of required matches. Thus</p> <p>matches at least 3 successive vowels, but may match many more, while</p> -<quote><p> \\d{8}</p></quote> +<quote><p> \d{8}</p></quote> <p>matches exactly 8 digits. An opening curly bracket that appears in a position where a quantifier is not allowed, or one that does not match the syntax of a @@ -2007,9 +2007,9 @@ quantifier, is taken as a literal character. For example, {,6} is not a quantifier, but a literal string of four characters.</p> <p>In UTF-8 mode, quantifiers apply to UTF-8 characters rather than to individual -bytes. Thus, for example, \\x{100}{2} matches two UTF-8 characters, each of +bytes. Thus, for example, \x{100}{2} matches two UTF-8 characters, each of which is represented by a two-byte sequence. Similarly, when Unicode property -support is available, \\X{3} matches three Unicode extended sequences, each of +support is available, \X{3} matches three Unicode extended sequences, each of which may be several bytes long (and they may be of different lengths).</p> <p>The quantifier {0} is permitted, causing the expression to behave as if the @@ -2042,7 +2042,7 @@ is in trying to match comments in C programs. These appear between /* and */ and within the comment, individual * and / characters may appear. An attempt to match C comments by applying the pattern</p> -<quote><p> /\\*.*\\*/</p></quote> +<quote><p> /\*.*\*/</p></quote> <p>to the string</p> @@ -2055,14 +2055,14 @@ item.</p> greedy, and instead matches the minimum number of times possible, so the pattern</p> -<quote><p> /\\*.*?\\*/</p></quote> +<quote><p> /\*.*?\*/</p></quote> <p>does the right thing with the C comments. The meaning of the various quantifiers is not otherwise changed, just the preferred number of matches. Do not confuse this use of question mark with its use as a quantifier in its own right. Because it has two uses, it can sometimes appear doubled, as in</p> -<quote><p> \\d??\\d</p></quote> +<quote><p> \d??\d</p></quote> <p>which matches one digit by preference, but can match two if that is the only way the rest of the pattern matches.</p> @@ -2081,7 +2081,7 @@ to Perl's /s) is set, thus allowing the dot to match newlines, the pattern is implicitly anchored, because whatever follows will be tried against every character position in the subject string, so there is no point in retrying the overall match at any position after the first. PCRE normally treats such a -pattern as though it were preceded by \\A.</p> +pattern as though it were preceded by \A.</p> <p>In cases where it is known that the subject string contains no newlines, it is worth setting <c>dotall</c> in order to obtain this optimization, or @@ -2092,7 +2092,7 @@ is inside capturing parentheses that are the subject of a backreference elsewhere in the pattern, a match at the start may fail where a later one succeeds. Consider, for example:</p> -<quote><p> (.*)abc\\1</p></quote> +<quote><p> (.*)abc\1</p></quote> <p>If the subject is "xyz123abc123" the match point is the fourth character. For this reason, such a pattern is not implicitly anchored.</p> @@ -2100,7 +2100,7 @@ this reason, such a pattern is not implicitly anchored.</p> <p>When a capturing subpattern is repeated, the value captured is the substring that matched the final iteration. For example, after</p> -<quote><p> (tweedle[dume]{3}\\s*)+</p></quote> +<quote><p> (tweedle[dume]{3}\s*)+</p></quote> <p>has matched "tweedledum tweedledee" the value of the captured substring is "tweedledee". However, if there are nested capturing subpatterns, the @@ -2123,12 +2123,12 @@ pattern to match. Sometimes it is useful to prevent this, either to change the nature of the match, or to cause it fail earlier than it otherwise might, when the author of the pattern knows there is no point in carrying on.</p> -<p>Consider, for example, the pattern \\d+foo when applied to the subject line</p> +<p>Consider, for example, the pattern \d+foo when applied to the subject line</p> <quote><p> 123456bar</p></quote> <p>After matching all 6 digits and then failing to match "foo", the normal -action of the matcher is to try again with only 5 digits matching the \\d+ +action of the matcher is to try again with only 5 digits matching the \d+ item, and then with 4, and so on, before ultimately failing. "Atomic grouping" (a term taken from Jeffrey Friedl's book) provides the means for specifying that once a subpattern has matched, it is not to be re-evaluated in this way.</p> @@ -2137,7 +2137,7 @@ that once a subpattern has matched, it is not to be re-evaluated in this way.</p immediately on failing to match "foo" the first time. The notation is a kind of special parenthesis, starting with (?> as in this example:</p> -<quote><p> (?>\\d+)foo</p></quote> +<quote><p> (?>\d+)foo</p></quote> <p>This kind of parenthesis "locks up" the part of the pattern it contains once it has matched, and a failure further into the pattern is prevented from @@ -2150,9 +2150,9 @@ the current point in the subject string.</p> <p>Atomic grouping subpatterns are not capturing subpatterns. Simple cases such as the above example can be thought of as a maximizing repeat that must swallow -everything it can. So, while both \\d+ and \\d+? are prepared to adjust the +everything it can. So, while both \d+ and \d+? are prepared to adjust the number of digits they match in order to make the rest of the pattern match, -(?>\\d+) can only match an entire sequence of digits.</p> +(?>\d+) can only match an entire sequence of digits.</p> <p>Atomic groups in general can of course contain arbitrarily complicated subpatterns, and can be nested. However, when the subpattern for an atomic @@ -2161,7 +2161,7 @@ notation, called a "possessive quantifier" can be used. This consists of an additional + character following a quantifier. Using this notation, the previous example can be rewritten as</p> -<quote><p> \\d++foo</p></quote> +<quote><p> \d++foo</p></quote> <p>Note that a possessive quantifier can be used with an entire group, for example:</p> @@ -2189,7 +2189,7 @@ be repeated an unlimited number of times, the use of an atomic group is the only way to avoid some failing matches taking a very long time indeed. The pattern</p> -<quote><p> (\\D+|<\\d+>)*[!?]</p></quote> +<quote><p> (\D+|<\d+>)*[!?]</p></quote> <p>matches an unlimited number of substrings that either consist of non-digits, or digits enclosed in <>, followed by either ! or ?. When it matches, it runs @@ -2198,7 +2198,7 @@ quickly. However, if it is applied to</p> <quote><p> aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa</p></quote> <p>it takes a long time before reporting failure. This is because the string can -be divided between the internal \\D+ repeat and the external * repeat in a +be divided between the internal \D+ repeat and the external * repeat in a large number of ways, and all have to be tried. (The example uses [!?] rather than a single character at the end, because both PCRE and Perl have an optimization that allows for fast failure when a single character is used. They @@ -2206,7 +2206,7 @@ remember the last single character that is required for a match, and fail early if it is not present in the string.) If the pattern is changed so that it uses an atomic group, like this:</p> -<quote><p> ((?>\\D+)|<\\d+>)*[!?]</p></quote> +<quote><p> ((?>\D+)|<\d+>)*[!?]</p></quote> <p>sequences of non-digits cannot be broken, and failure happens quickly.</p> @@ -2229,22 +2229,22 @@ in an earlier iteration.</p> <p>It is not possible to have a numerical "forward back reference" to a subpattern whose number is 10 or more using this syntax because a -sequence such as \\50 is interpreted as a character defined in +sequence such as \50 is interpreted as a character defined in octal. See the subsection entitled "Non-printing characters" above for further details of the handling of digits following a backslash. There is no such problem when named parentheses are used. A back reference to any subpattern is possible using named parentheses (see below).</p> <p>Another way of avoiding the ambiguity inherent in the use of digits -following a backslash is to use the \\g escape sequence, which is a +following a backslash is to use the \g escape sequence, which is a feature introduced in Perl 5.10. This escape must be followed by an unsigned number or a negative number, optionally enclosed in braces. These examples are all identical:</p> <list> - <item>(ring), \\1</item> - <item>(ring), \\g1</item> - <item>(ring), \\g{1}</item> + <item>(ring), \1</item> + <item>(ring), \g1</item> + <item>(ring), \g{1}</item> </list> <p>An unsigned number specifies an absolute reference without the @@ -2252,11 +2252,11 @@ ambiguity that is present in the older syntax. It is also useful when literal digits follow the reference. A negative number is a relative reference. Consider this example:</p> -<quote><p> (abc(def)ghi)\\g{-1}</p></quote> +<quote><p> (abc(def)ghi)\g{-1}</p></quote> -<p>The sequence \\g{-1} is a reference to the most recently started capturing -subpattern before \\g, that is, is it equivalent to \\2. Similarly, \\g{-2} -would be equivalent to \\1. The use of relative references can be helpful in +<p>The sequence \g{-1} is a reference to the most recently started capturing +subpattern before \g, that is, is it equivalent to \2. Similarly, \g{-2} +would be equivalent to \1. The use of relative references can be helpful in long patterns, and also in patterns that are created by joining together fragments that contain references within themselves.</p> @@ -2265,29 +2265,29 @@ subpattern in the current subject string, rather than anything matching the subpattern itself (see "Subpatterns as subroutines" below for a way of doing that). So the pattern</p> -<quote><p> (sens|respons)e and \\1ibility</p></quote> +<quote><p> (sens|respons)e and \1ibility</p></quote> <p>matches "sense and sensibility" and "response and responsibility", but not "sense and responsibility". If caseful matching is in force at the time of the back reference, the case of letters is relevant. For example,</p> -<quote><p> ((?i)rah)\\s+\\1</p></quote> +<quote><p> ((?i)rah)\s+\1</p></quote> <p>matches "rah rah" and "RAH RAH", but not "RAH rah", even though the original capturing subpattern is matched caselessly.</p> <p>There are several different ways of writing back references to named -subpatterns. The .NET syntax \\k{name} and the Perl syntax \\k<name> or -\\k'name' are supported, as is the Python syntax (?P=name). Perl 5.10's unified -back reference syntax, in which \\g can be used for both numeric and named +subpatterns. The .NET syntax \k{name} and the Perl syntax \k<name> or +\k'name' are supported, as is the Python syntax (?P=name). Perl 5.10's unified +back reference syntax, in which \g can be used for both numeric and named references, is also supported. We could rewrite the above example in any of the following ways:</p> <list> - <item>(?<p1>(?i)rah)\\s+\\k<p1></item> - <item>(?'p1'(?i)rah)\\s+\\k{p1}</item> - <item>(?P<p1>(?i)rah)\\s+(?P=p1)</item> - <item>(?<p1>(?i)rah)\\s+\\g{p1}</item> + <item>(?<p1>(?i)rah)\s+\k<p1></item> + <item>(?'p1'(?i)rah)\s+\k{p1}</item> + <item>(?P<p1>(?i)rah)\s+(?P=p1)</item> + <item>(?<p1>(?i)rah)\s+\g{p1}</item> </list> <p>A subpattern that is referenced by name may appear in the pattern before or @@ -2297,7 +2297,7 @@ after the reference.</p> subpattern has not actually been used in a particular match, any back references to it always fail. For example, the pattern</p> -<quote><p> (a|(bc))\\2</p></quote> +<quote><p> (a|(bc))\2</p></quote> <p>always fails if it starts to match "a" rather than "bc". Because there may be many capturing parentheses in a pattern, all digits @@ -2308,11 +2308,11 @@ some delimiter must be used to terminate the back reference. If the empty comment (see "Comments" below) can be used.</p> <p>A back reference that occurs inside the parentheses to which it refers fails -when the subpattern is first used, so, for example, (a\\1) never matches. +when the subpattern is first used, so, for example, (a\1) never matches. However, such references can be useful inside repeated subpatterns. For example, the pattern</p> -<quote><p> (a|b\\1)+</p></quote> +<quote><p> (a|b\1)+</p></quote> <p>matches any number of "a"s and also "aba", "ababbaa" etc. At each iteration of the subpattern, the back reference matches the character string corresponding @@ -2327,7 +2327,7 @@ minimum of zero.</p> <p>An assertion is a test on the characters following or preceding the current matching point that does not actually consume any characters. The simple -assertions coded as \\b, \\B, \\A, \\G, \\Z, \\z, ^ and $ are described +assertions coded as \b, \B, \A, \G, \Z, \z, ^ and $ are described above.</p> @@ -2348,7 +2348,7 @@ because it does not make sense for negative assertions.</p> <p>Lookahead assertions start with (?= for positive assertions and (?! for negative assertions. For example,</p> -<quote><p> \\w+(?=;)</p></quote> +<quote><p> \w+(?=;)</p></quote> <p>matches a word followed by a semicolon, but does not include the semicolon in the match, and</p> @@ -2400,7 +2400,7 @@ lengths, but it is acceptable if rewritten to use two top-level branches:</p> <quote><p> (?<=abc|abde)</p></quote> -<p>In some cases, the Perl 5.10 escape sequence \\K (see above) can be +<p>In some cases, the Perl 5.10 escape sequence \K (see above) can be used instead of a lookbehind assertion; this is not restricted to a fixed-length.</p> @@ -2409,9 +2409,9 @@ temporarily move the current position back by the fixed length and then try to match. If there are insufficient characters before the current position, the assertion fails.</p> -<p>PCRE does not allow the \\C escape (which matches a single byte in UTF-8 mode) +<p>PCRE does not allow the \C escape (which matches a single byte in UTF-8 mode) to appear in lookbehind assertions, because it makes it impossible to calculate -the length of the lookbehind. The \\X and \\R escapes, which can match +the length of the lookbehind. The \X and \R escapes, which can match different numbers of bytes, are also not permitted.</p> <p>Possessive quantifiers can be used in conjunction with lookbehind assertions to @@ -2443,7 +2443,7 @@ approach makes a significant difference to the processing time.</p> <p>Several assertions (of any sort) may occur in succession. For example,</p> -<quote><p> (?<=\\d{3})(?<!999)foo</p></quote> +<quote><p> (?<=\d{3})(?<!999)foo</p></quote> <p>matches "foo" preceded by three digits that are not "999". Notice that each of the assertions is applied independently at the same point @@ -2454,7 +2454,7 @@ three characters are not "999". This pattern does <em>not</em> match the last three of which are not "999". For example, it doesn't match "123abcfoo". A pattern to do that is</p> -<quote><p> (?<=\\d{3}...)(?<!999)foo</p></quote> +<quote><p> (?<=\d{3}...)(?<!999)foo</p></quote> <p>This time the first assertion looks at the preceding six characters, checking that the first three are digits, and then the @@ -2468,7 +2468,7 @@ second assertion checks that the preceding three characters are not <p>matches an occurrence of "baz" that is preceded by "bar" which in turn is not preceded by "foo", while</p> -<quote><p> (?<=\\d{3}(?!999)...)foo</p></quote> +<quote><p> (?<=\d{3}(?!999)...)foo</p></quote> <p>is another pattern that matches "foo" preceded by three digits and any three characters that are not "999".</p> @@ -2510,7 +2510,7 @@ refer to subsequent groups with constructs such as (?(+2).</p> whitespace to make it more readable (assume the <c>extended</c> option) and to divide it into three parts for ease of discussion:</p> -<quote><p> ( \\( )? [^()]+ (?(1) \\) )</p></quote> +<quote><p> ( \( )? [^()]+ (?(1) \) )</p></quote> <p>The first part matches an optional opening parenthesis, and if that character is present, sets it as the first captured substring. The second part @@ -2525,7 +2525,7 @@ non-parentheses, optionally enclosed in parentheses.</p> <p>If you were embedding this pattern in a larger one, you could use a relative reference:</p> -<quote><p> ...other stuff... ( \\( )? [^()]+ (?(-1) \\) ) ...</p></quote> +<quote><p> ...other stuff... ( \( )? [^()]+ (?(-1) \) ) ...</p></quote> <p>This makes the fragment independent of the parentheses in the larger pattern.</p> @@ -2543,7 +2543,7 @@ consist entirely of digits is not recommended.</p> <p>Rewriting the above example to use a named subpattern gives this:</p> -<quote><p> (?<OPEN> \\( )? [^()]+ (?(<OPEN>) \\) )</p></quote> +<quote><p> (?<OPEN> \( )? [^()]+ (?(<OPEN>) \) )</p></quote> <p><em>Checking for pattern recursion</em></p> @@ -2571,8 +2571,8 @@ point in the pattern; the idea of DEFINE is that it can be used to define is described below.) For example, a pattern to match an IPv4 address could be written like this (ignore whitespace and line breaks):</p> -<quote><p> (?(DEFINE) (?<byte> 2[0-4]\\d | 25[0-5] | 1\\d\\d | [1-9]?\\d) ) - \\b (?&byte) (\\.(?&byte)){3} \\b</p></quote> +<quote><p> (?(DEFINE) (?<byte> 2[0-4]\d | 25[0-5] | 1\d\d | [1-9]?\d) ) + \b (?&byte) (\.(?&byte)){3} \b</p></quote> <p>The first part of the pattern is a DEFINE group inside which a another group named "byte" is defined. This matches an individual component of an IPv4 @@ -2590,9 +2590,9 @@ assertion. This may be a positive or negative lookahead or lookbehind assertion. Consider this pattern, again containing non-significant whitespace, and with the two alternatives on the second line:</p> -<code type="none"> +<code type="none"> (?(?=[^a-z]*[a-z]) - \\d{2}-[a-z]{3}-\\d{2} | \\d{2}-\\d{2}-\\d{2} )</code> + \d{2}-[a-z]{3}-\d{2} | \d{2}-\d{2}-\d{2} )</code> <p>The condition is a positive lookahead assertion that matches an optional sequence of non-letters followed by a letter. In other words, it tests for the @@ -2631,7 +2631,7 @@ can refer to the expression itself. A Perl pattern using code interpolation to solve the parentheses problem can be created like this:</p> -<quote><p> $re = qr{\\( (?: (?>[^()]+) | (?p{$re}) )* \\)}x;</p></quote> +<quote><p> $re = qr{\( (?: (?>[^()]+) | (?p{$re}) )* \)}x;</p></quote> <p>The (?p{...}) item interpolates Perl code at run time, and in this case refers recursively to the pattern in which it appears.</p> @@ -2657,7 +2657,7 @@ failure.</p> <p>This PCRE pattern solves the nested parentheses problem (assume the <c>extended</c> option is set so that whitespace is ignored):</p> -<quote><p> \\( ( (?>[^()]+) | (?R) )* \\)</p></quote> +<quote><p> \( ( (?>[^()]+) | (?R) )* \)</p></quote> <p>First it matches an opening parenthesis. Then it matches any number of substrings which can either be a sequence of non-parentheses, or a @@ -2667,7 +2667,7 @@ parenthesized substring). Finally there is a closing parenthesis.</p> <p>If this were part of a larger pattern, you would not want to recurse the entire pattern, so instead you could use this:</p> -<quote><p> ( \\( ( (?>[^()]+) | (?1) )* \\) )</p></quote> +<quote><p> ( \( ( (?>[^()]+) | (?1) )* \) )</p></quote> <p>We have put the pattern into parentheses, and caused the recursion to refer to them instead of the whole pattern.</p> @@ -2691,7 +2691,7 @@ Perl syntax for this is (?&name); PCRE's earlier syntax (?P>name) is also supported. We could rewrite the above example as follows:</p> -<quote><p> (?<pn> \\( ( (?>[^()]+) | (?&pn) )* \\) )</p></quote> +<quote><p> (?<pn> \( ( (?>[^()]+) | (?&pn) )* \) )</p></quote> <p>If there is more than one subpattern with the same name, the earliest one is used.</p> @@ -2727,7 +2727,7 @@ If the pattern above is matched against</p> on at the top level. If additional parentheses are added, giving</p> <code type="none"> - \\( ( ( (?>[^()]+) | (?R) )* ) \\) + \( ( ( (?>[^()]+) | (?R) )* ) \) ^ ^ ^ ^</code> @@ -2747,7 +2747,7 @@ brackets, allowing for arbitrary nesting. Only digits are allowed in nested brackets (that is, when recursing), whereas any characters are permitted at the outer level.</p> -<quote><p> < (?: (?(R) \\d++ | [^<>]*+) | (?R)) * ></p></quote> +<quote><p> < (?: (?(R) \d++ | [^<>]*+) | (?R)) * ></p></quote> <p>In this pattern, (?(R) is the start of a conditional subpattern, with two different alternatives for the recursive and non-recursive @@ -2771,7 +2771,7 @@ relative, as in these examples:</p> <p>An earlier example pointed out that the pattern</p> -<quote><p> (sens|respons)e and \\1ibility</p></quote> +<quote><p> (sens|respons)e and \1ibility</p></quote> <p>matches "sense and sensibility" and "response and responsibility", but not "sense and responsibility". If instead the pattern</p> diff --git a/lib/stdlib/doc/src/regexp.xml b/lib/stdlib/doc/src/regexp.xml index 8da636e4ad..8c4191c88f 100644 --- a/lib/stdlib/doc/src/regexp.xml +++ b/lib/stdlib/doc/src/regexp.xml @@ -132,7 +132,7 @@ <v>RepCount = integer()</v> </type> <desc> - <p>Substitutes the first occurrence of a substring matching <c>RegExp</c> in <c>String</c> with the string <c>New</c>. A <c><![CDATA[&]]></c> in the string <c>New</c> is replaced by the matched substring of <c>String</c>. <c><![CDATA[\\&]]></c> puts a literal <c><![CDATA[&]]></c> into the replacement string. It returns as follows:</p> + <p>Substitutes the first occurrence of a substring matching <c>RegExp</c> in <c>String</c> with the string <c>New</c>. A <c><![CDATA[&]]></c> in the string <c>New</c> is replaced by the matched substring of <c>String</c>. <c><![CDATA[\&]]></c> puts a literal <c><![CDATA[&]]></c> into the replacement string. It returns as follows:</p> <taglist> <tag><c>{ok,NewString,RepCount}</c></tag> <item> @@ -286,7 +286,7 @@ <item> <p>matches the non-metacharacter <c>c</c>.</p> </item> - <tag>\\c</tag> + <tag>\c</tag> <item> <p>matches the escape sequence or literal character <c>c</c>.</p> </item> @@ -341,74 +341,74 @@ <p>The escape sequences allowed are the same as for Erlang strings:</p> <taglist> - <tag><c>\\b</c></tag> + <tag><c>\b</c></tag> <item> <p>backspace</p> </item> - <tag><c>\\f</c></tag> + <tag><c>\f</c></tag> <item> <p>form feed </p> </item> - <tag><c>\</c></tag> + <tag><c>\n</c></tag> <item> <p>newline (line feed) </p> </item> - <tag><c>\\r</c></tag> + <tag><c>\r</c></tag> <item> <p>carriage return </p> </item> - <tag><c>\\t</c></tag> + <tag><c>\t</c></tag> <item> <p>tab </p> </item> - <tag><c>\\e</c></tag> + <tag><c>\e</c></tag> <item> <p>escape </p> </item> - <tag><c>\\v</c></tag> + <tag><c>\v</c></tag> <item> <p>vertical tab </p> </item> - <tag><c>\\s</c></tag> + <tag><c>\s</c></tag> <item> <p>space </p> </item> - <tag><c>\\d</c></tag> + <tag><c>\d</c></tag> <item> <p>delete </p> </item> - <tag><c>\\ddd</c></tag> + <tag><c>\ddd</c></tag> <item> <p>the octal value ddd </p> </item> - <tag><c>\\xhh</c></tag> + <tag><c>\xhh</c></tag> <item> <p>The hexadecimal value <c>hh</c>.</p> </item> - <tag><c>\\x{h...}</c></tag> + <tag><c>\x{h...}</c></tag> <item> <p>The hexadecimal value <c>h...</c>.</p> </item> - <tag><c>\\c</c></tag> + <tag><c>\c</c></tag> <item> - <p>any other character literally, for example <c>\\\\</c> for backslash, - <c>\\"</c> for ")</p> + <p>any other character literally, for example <c>\\</c> for backslash, + <c>\"</c> for ")</p> </item> </taglist> <p>To make these functions easier to use, in combination with the function <c>io:get_line</c> which terminates the input line with a new line, the <c>$</c> characters also matches a string ending - with <c>"...\ "</c>. The following examples + with <c>"...\n"</c>. The following examples define Erlang data types:</p> <pre> Atoms [a-z][0-9a-zA-Z_]* Variables [A-Z_][0-9a-zA-Z_]* -Floats (\\+|-)?[0-9]+\\.[0-9]+((E|e)(\\+|-)?[0-9]+)?</pre> - <p>Regular expressions are written as Erlang strings when used with the functions in this module. This means that any <c>\\</c> or <c>"</c> characters in a regular expression - string must be written with <c>\\</c> as they are also escape characters for the string. For example, the regular expression string for Erlang floats is: - <c>"(\\\\+|-)?[0-9]+\\\\.[0-9]+((E|e)(\\\\+|-)?[0-9]+)?"</c>.</p> +Floats (\+|-)?[0-9]+\.[0-9]+((E|e)(\+|-)?[0-9]+)?</pre> + <p>Regular expressions are written as Erlang strings when used with the functions in this module. This means that any <c>\</c> or <c>"</c> characters in a regular expression + string must be written with <c>\</c> as they are also escape characters for the string. For example, the regular expression string for Erlang floats is: + <c>"(\\+|-)?[0-9]+\\.[0-9]+((E|e)(\\+|-)?[0-9]+)?"</c>.</p> <p>It is not really necessary to have the escape sequences as part of the regular expression syntax as they can always be generated directly in the string. They are included for completeness and can they can also be useful when generating regular expressions, or when they are entered other than with Erlang strings.</p> </section> </erlref> diff --git a/lib/stdlib/doc/src/shell.xml b/lib/stdlib/doc/src/shell.xml index 24b845fee9..b8fc64f45e 100644 --- a/lib/stdlib/doc/src/shell.xml +++ b/lib/stdlib/doc/src/shell.xml @@ -333,10 +333,12 @@ undefined <0.57.0> 27> <input>get(aa).</input> hello -28> <input>io:format("hello hello\ ").</input> -hello hello ok +28> <input>io:format("hello hello\n").</input> +hello hello +ok 29> <input>e(28).</input> -hello hello ok +hello hello +ok 30> <input>v(28).</input> ok 31> <input>c(ex).</input> diff --git a/lib/stdlib/doc/src/string.xml b/lib/stdlib/doc/src/string.xml index 7ee38e496d..de1b99a2d5 100644 --- a/lib/stdlib/doc/src/string.xml +++ b/lib/stdlib/doc/src/string.xml @@ -117,9 +117,9 @@ from) Chars.</p> <p>For example:</p> <code type="none"> -> string:span("\\t abcdef", " \\t"). +> string:span("\t abcdef", " \t"). 5 -> string:cspan("\\t abcdef", " \\t"). +> string:cspan("\t abcdef", " \t"). 0 </code> </desc> </func> diff --git a/lib/stdlib/doc/src/sys.xml b/lib/stdlib/doc/src/sys.xml index a395a8a415..10ead62073 100644 --- a/lib/stdlib/doc/src/sys.xml +++ b/lib/stdlib/doc/src/sys.xml @@ -4,23 +4,21 @@ <erlref> <header> <copyright> - <year>1996</year> - <year>2007</year> - <holder>Ericsson AB, All Rights Reserved</holder> + <year>1996</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> - The contents of this file are subject to the Erlang Public License, - Version 1.1, (the "License"); you may not use this file except in - compliance with the License. You should have received a copy of the - Erlang Public License along with this software. If not, it can be - retrieved online at http://www.erlang.org/. - - Software distributed under the License is distributed on an "AS IS" - basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - the License for the specific language governing rights and limitations - under the License. - - The Initial Developer of the Original Code is Ericsson AB. + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + </legalnotice> <title>sys</title> @@ -237,6 +235,17 @@ </type> <desc> <p>Gets the status of the process.</p> + <p>The value of <c>Misc</c> varies for different types of + processes. For example, a <c>gen_server</c> process returns + the callback module's state, and a <c>gen_fsm</c> process + returns information such as its current state name. Callback + modules for <c>gen_server</c> and <c>gen_fsm</c> can also + customise the value of <c>Misc</c> by exporting + a <c>format_status/2</c> function that contributes + module-specific information; + see <seealso marker="gen_server#format_status/2">gen_server:format_status/2</seealso> + and <seealso marker="gen_fsm#format_status/2">gen_fsm:format_status/2</seealso> + for more details.</p> </desc> </func> <func> diff --git a/lib/stdlib/doc/src/win32reg.xml b/lib/stdlib/doc/src/win32reg.xml index d8055047b0..28960cd098 100644 --- a/lib/stdlib/doc/src/win32reg.xml +++ b/lib/stdlib/doc/src/win32reg.xml @@ -48,7 +48,7 @@ <p>Paths to keys are left to right, with sub-keys to the right and backslash between keys. (Remember that backslashes must be doubled in Erlang strings.) Case is preserved but not significant. - Example: <c>"\\\\hkey_local_machine\\\\software\\\\Ericsson\\\\Erlang\\\\5.0"</c> is the key + Example: <c>"\\hkey_local_machine\\software\\Ericsson\\Erlang\\5.0"</c> is the key for the installation data for the latest Erlang release.</p> <p>There are six entry points in the Windows registry, top level keys. They can be abbreviated in the <c>win32reg</c> module as:</p> @@ -66,7 +66,7 @@ current_config HKEY_CURRENT_CONFIG hkcc HKEY_CURRENT_CONFIG dyn_data HKEY_DYN_DATA hkdd HKEY_DYN_DATA</pre> - <p>The key above could be written as <c>"\\\\hklm\\\\software\\\\ericsson\\\\erlang\\\\5.0"</c>.</p> + <p>The key above could be written as <c>"\\hklm\\software\\ericsson\\erlang\\5.0"</c>.</p> <p>The <c>win32reg</c> module uses a current key. It works much like the current directory. From the current key, values can be fetched, sub-keys can be listed, and so on.</p> @@ -96,7 +96,7 @@ hkdd HKEY_DYN_DATA</pre> <desc> <p>Changes the current key to another key. Works like cd. The key can be specified as a relative path or as an - absolute path, starting with \\.</p> + absolute path, starting with \.</p> </desc> </func> <func> diff --git a/lib/stdlib/src/c.erl b/lib/stdlib/src/c.erl index 9e4cec5db2..433833e233 100644 --- a/lib/stdlib/src/c.erl +++ b/lib/stdlib/src/c.erl @@ -197,7 +197,9 @@ nc(File, Opts0) when is_list(Opts0) -> Opts = Opts0 ++ [report_errors, report_warnings], case compile:file(File, Opts) of {ok,Mod} -> - Fname = concat([File, code:objfile_extension()]), + Dir = outdir(Opts), + Obj = filename:basename(File, ".erl") ++ code:objfile_extension(), + Fname = filename:join(Dir, Obj), case file:read_file(Fname) of {ok,Bin} -> rpc:eval_everywhere(code,load_binary,[Mod,Fname,Bin]), diff --git a/lib/stdlib/src/gen_fsm.erl b/lib/stdlib/src/gen_fsm.erl index f3775f967a..ba0275ae2b 100644 --- a/lib/stdlib/src/gen_fsm.erl +++ b/lib/stdlib/src/gen_fsm.erl @@ -603,7 +603,12 @@ get_msg(Msg) -> Msg. format_status(Opt, StatusData) -> [PDict, SysState, Parent, Debug, [Name, StateName, StateData, Mod, _Time]] = StatusData, - Header = lists:concat(["Status for state machine ", Name]), + NameTag = if is_pid(Name) -> + pid_to_list(Name); + is_atom(Name) -> + Name + end, + Header = lists:concat(["Status for state machine ", NameTag]), Log = sys:get_debug(log, Debug, []), Specfic = case erlang:function_exported(Mod, format_status, 2) of diff --git a/lib/stdlib/src/otp_internal.erl b/lib/stdlib/src/otp_internal.erl index 3df6f4bb90..7ea7de8d58 100644 --- a/lib/stdlib/src/otp_internal.erl +++ b/lib/stdlib/src/otp_internal.erl @@ -334,6 +334,10 @@ obsolete_1(ssl_pkix, decode_cert_file, A) when A =:= 1; A =:= 2 -> {deprecated,"deprecated (will be removed in R14B); use public_key:pem_to_der/1 and public_key:pkix_decode_cert/2 instead"}; obsolete_1(ssl_pkix, decode_cert, A) when A =:= 1; A =:= 2 -> {deprecated,{public_key,pkix_decode_cert,2},"R14B"}; + +%% Added in R13B04. +obsolete_1(erlang, concat_binary, 1) -> + {deprecated,{erlang,list_to_binary,1},"R14B"}; obsolete_1(_, _, _) -> no. diff --git a/lib/stdlib/src/sys.erl b/lib/stdlib/src/sys.erl index e0f2dbcd3c..12209c16d7 100644 --- a/lib/stdlib/src/sys.erl +++ b/lib/stdlib/src/sys.erl @@ -245,8 +245,17 @@ do_cmd(SysState, Other, _Parent, _Mod, Debug, Misc) -> {SysState, {error, {unknown_system_msg, Other}}, Debug, Misc}. get_status(SysState, Parent, Mod, Debug, Misc) -> + PDict = get(), + FmtMisc = + case erlang:function_exported(Mod, format_status, 2) of + true -> + FmtArgs = [PDict, SysState, Parent, Debug, Misc], + Mod:format_status(normal, FmtArgs); + _ -> + Misc + end, {status, self(), {module, Mod}, - [get(), SysState, Parent, Debug, Misc]}. + [PDict, SysState, Parent, Debug, FmtMisc]}. %%----------------------------------------------------------------- %% These are the system debug commands. diff --git a/lib/stdlib/test/c_SUITE.erl b/lib/stdlib/test/c_SUITE.erl index 5608d73d19..2edbc7ab4c 100644 --- a/lib/stdlib/test/c_SUITE.erl +++ b/lib/stdlib/test/c_SUITE.erl @@ -18,15 +18,16 @@ %% -module(c_SUITE). -export([all/1]). --export([c_1/1, c_2/1, c_3/1, c_4/1, memory/1]). +-export([c_1/1, c_2/1, c_3/1, c_4/1, nc_1/1, nc_2/1, nc_3/1, nc_4/1, + memory/1]). -include("test_server.hrl"). --import(c, [c/2]). +-import(c, [c/2, nc/2]). all(doc) -> ["Test cases for the 'c' module."]; all(suite) -> - [c_1, c_2, c_3, c_4, memory]. + [c_1, c_2, c_3, c_4, nc_1, nc_2, nc_3, nc_4, memory]. %%% Write output to a directory other than current directory: @@ -34,7 +35,7 @@ c_1(doc) -> ["Checks that c:c works also with option 'outdir' [ticket OTP-1209]."]; c_1(suite) -> []; -c_1(Config) when list(Config) -> +c_1(Config) when is_list(Config) -> ?line R = filename:join(?config(data_dir, Config), "m.erl"), ?line W = ?config(priv_dir, Config), ?line Result = c(R,[{outdir,W}]), @@ -44,7 +45,7 @@ c_2(doc) -> ["Checks that c:c works also with option 'outdir' [ticket OTP-1209]."]; c_2(suite) -> []; -c_2(Config) when list(Config) -> +c_2(Config) when is_list(Config) -> ?line R = filename:join(?config(data_dir, Config), "m"), ?line W = ?config(priv_dir, Config), ?line Result = c(R,[{outdir,W}]), @@ -59,7 +60,7 @@ c_3(doc) -> "directory). [ticket OTP-1209]."]; c_3(suite) -> []; -c_3(Config) when list(Config) -> +c_3(Config) when is_list(Config) -> ?line R = filename:join(?config(data_dir, Config), "m.erl"), ?line W = ?config(priv_dir, Config), ?line file:set_cwd(W), @@ -71,18 +72,68 @@ c_4(doc) -> "directory). [ticket OTP-1209]."]; c_4(suite) -> []; -c_4(Config) when list(Config) -> +c_4(Config) when is_list(Config) -> ?line R = filename:join(?config(data_dir, Config), "m"), ?line W = ?config(priv_dir, Config), ?line file:set_cwd(W), ?line Result = c(R,[{outdir,W}]), ?line {ok, m} = Result. +%%% Write output to a directory other than current directory: + +nc_1(doc) -> + ["Checks that c:nc works also with option 'outdir'."]; +nc_1(suite) -> + []; +nc_1(Config) when is_list(Config) -> + ?line R = filename:join(?config(data_dir, Config), "m.erl"), + ?line W = ?config(priv_dir, Config), + ?line Result = nc(R,[{outdir,W}]), + ?line {ok, m} = Result. + +nc_2(doc) -> + ["Checks that c:nc works also with option 'outdir'."]; +nc_2(suite) -> + []; +nc_2(Config) when is_list(Config) -> + ?line R = filename:join(?config(data_dir, Config), "m"), + ?line W = ?config(priv_dir, Config), + ?line Result = nc(R,[{outdir,W}]), + ?line {ok, m} = Result. + + +%%% Put results in current directory (or rather, change current dir +%%% to the output dir): + +nc_3(doc) -> + ["Checks that c:nc works also with option 'outdir' (same as current" + "directory)."]; +nc_3(suite) -> + []; +nc_3(Config) when is_list(Config) -> + ?line R = filename:join(?config(data_dir, Config), "m.erl"), + ?line W = ?config(priv_dir, Config), + ?line file:set_cwd(W), + ?line Result = nc(R,[{outdir,W}]), + ?line {ok, m} = Result. + +nc_4(doc) -> + ["Checks that c:nc works also with option 'outdir' (same as current" + "directory)."]; +nc_4(suite) -> + []; +nc_4(Config) when is_list(Config) -> + ?line R = filename:join(?config(data_dir, Config), "m"), + ?line W = ?config(priv_dir, Config), + ?line file:set_cwd(W), + ?line Result = nc(R,[{outdir,W}]), + ?line {ok, m} = Result. + memory(doc) -> ["Checks that c:memory/[0,1] returns consistent results."]; memory(suite) -> []; -memory(Config) when list(Config) -> +memory(Config) when is_list(Config) -> try ?line ML = c:memory(), ?line T = mget(total, ML), @@ -112,5 +163,5 @@ mget(K, L) -> ?line test_v(V). % Help function for c_SUITE:memory/1 -test_v(V) when integer(V) -> +test_v(V) when is_integer(V) -> ?line V. diff --git a/lib/stdlib/test/gen_fsm_SUITE.erl b/lib/stdlib/test/gen_fsm_SUITE.erl index 62f8b2f9dd..23c1d9a193 100644 --- a/lib/stdlib/test/gen_fsm_SUITE.erl +++ b/lib/stdlib/test/gen_fsm_SUITE.erl @@ -30,7 +30,7 @@ -export([shutdown/1]). --export([sys/1, sys1/1]). +-export([sys/1, sys1/1, call_format_status/1]). -export([hibernate/1,hiber_idle/3,hiber_wakeup/3,hiber_idle/2,hiber_wakeup/2]). @@ -42,7 +42,7 @@ % The gen_fsm behaviour -export([init/1, handle_event/3, handle_sync_event/4, terminate/3, - handle_info/3]). + handle_info/3, format_status/2]). -export([idle/2, idle/3, timeout/2, wfor_conf/2, wfor_conf/3, @@ -305,7 +305,7 @@ shutdown(Config) when is_list(Config) -> ok. -sys(suite) -> [sys1]. +sys(suite) -> [sys1, call_format_status]. sys1(Config) when is_list(Config) -> ?line {ok, Pid} = @@ -317,6 +317,13 @@ sys1(Config) when is_list(Config) -> ?line sys:resume(Pid), ?line stop_it(Pid). +call_format_status(Config) when is_list(Config) -> + ?line {ok, Pid} = gen_fsm:start(gen_fsm_SUITE, [], []), + ?line Status = sys:get_status(Pid), + ?line {status, Pid, _Mod, [_PDict, running, _Parent, _, Data]} = Status, + ?line [format_status_called | _] = lists:reverse(Data), + ?line stop_it(Pid). + %% Hibernation hibernate(suite) -> []; @@ -836,3 +843,6 @@ handle_sync_event(stop_shutdown_reason, _From, _State, Data) -> {stop, {shutdown,reason}, {shutdown,reason}, Data}; handle_sync_event({get, _Pid}, _From, State, Data) -> {reply, {state, State, Data}, State, Data}. + +format_status(_Opt, [_Pdict, _StateData]) -> + [format_status_called]. diff --git a/lib/stdlib/test/gen_server_SUITE.erl b/lib/stdlib/test/gen_server_SUITE.erl index 86a5a65ba3..6efdce78a1 100644 --- a/lib/stdlib/test/gen_server_SUITE.erl +++ b/lib/stdlib/test/gen_server_SUITE.erl @@ -30,7 +30,7 @@ call_remote_n1/1, call_remote_n2/1, call_remote_n3/1, spec_init/1, spec_init_local_registered_parent/1, spec_init_global_registered_parent/1, - otp_5854/1, hibernate/1, otp_7669/1 + otp_5854/1, hibernate/1, otp_7669/1, call_format_status/1 ]). % spawn export @@ -42,7 +42,7 @@ % The gen_server behaviour -export([init/1, handle_call/3, handle_cast/2, - handle_info/2, terminate/2]). + handle_info/2, terminate/2, format_status/2]). all(suite) -> [start, crash, call, cast, cast_fast, info, @@ -51,7 +51,7 @@ all(suite) -> call_remote_n2, call_remote_n3, spec_init, spec_init_local_registered_parent, spec_init_global_registered_parent, - otp_5854,hibernate,otp_7669]. + otp_5854, hibernate, otp_7669, call_format_status]. -define(default_timeout, ?t:minutes(1)). @@ -851,7 +851,7 @@ otp_5854(Config) when is_list(Config) -> ok. %% If initialization fails (with ignore or {stop,Reason}), -%% make sure that the process is not registered when gen_sever:start() +%% make sure that the process is not registered when gen_server:start() %% returns. otp_7669(Config) when is_list(Config) -> @@ -887,6 +887,24 @@ do_otp_7669_stop() -> ?MODULE, stop, []), ?line undefined = global:whereis_name(?MODULE). +%% Verify that sys:get_status correctly calls our format_status/2 fun +%% +call_format_status(suite) -> + []; +call_format_status(doc) -> + ["Test that sys:get_status/1,2 calls format_status/2"]; +call_format_status(Config) when is_list(Config) -> + ?line {ok, Pid} = gen_server:start_link({local, call_format_status}, + gen_server_SUITE, [], []), + ?line Status1 = sys:get_status(call_format_status), + ?line {status, Pid, _Mod, [_PDict, running, _Parent, _, Data1]} = Status1, + ?line [format_status_called | _] = lists:reverse(Data1), + ?line Status2 = sys:get_status(call_format_status, 5000), + ?line {status, Pid, _Mod, [_PDict, running, _Parent, _, Data2]} = Status2, + ?line [format_status_called | _] = lists:reverse(Data2), + ok. + + %%-------------------------------------------------------------- %% Help functions to spec_init_* start_link(Init, Options) -> @@ -1046,4 +1064,5 @@ terminate({From, stopped_info}, _State) -> terminate(_Reason, _State) -> ok. - +format_status(_Opt, [_PDict, _State]) -> + [format_status_called]. diff --git a/lib/test_server/doc/src/test_server_ctrl.xml b/lib/test_server/doc/src/test_server_ctrl.xml index 3d95813c14..42c965b496 100644 --- a/lib/test_server/doc/src/test_server_ctrl.xml +++ b/lib/test_server/doc/src/test_server_ctrl.xml @@ -582,7 +582,7 @@ Optional, if not given the test server controller node <br></br> <c>erl -noshell -s test_server_ctrl run_test KEY1 Value1 KEY2 Value2 ... -s erlang halt</c></p> <p>Or make an alias (this is for unix/tcsh) <br></br> -<c>alias erl_test 'erl -noshell -s test_server_ctrl run_test \\!* -s erlang halt'</c></p> +<c>alias erl_test 'erl -noshell -s test_server_ctrl run_test \!* -s erlang halt'</c></p> <p>And then use it like this <br></br> <c>erl_test KEY1 Value1 KEY2 Value2 ...</c> <br></br> </p> diff --git a/lib/test_server/doc/src/write_framework_chapter.xml b/lib/test_server/doc/src/write_framework_chapter.xml index 2fde67132e..8a20e9afec 100644 --- a/lib/test_server/doc/src/write_framework_chapter.xml +++ b/lib/test_server/doc/src/write_framework_chapter.xml @@ -103,7 +103,7 @@ <p>A typical command line may look like this <br></br> <c>erl -noshell -s test_server_ctrl run_test KEY1 Value1 KEY2 Value2 ... -s erlang halt</c></p> <p>Or make an alias (this is for unix/tcsh) <br></br> -<c>alias erl_test 'erl -noshell -s test_server_ctrl run_test \\!* -s erlang halt'</c></p> +<c>alias erl_test 'erl -noshell -s test_server_ctrl run_test \!* -s erlang halt'</c></p> <p>And then use it like this <br></br> <c>erl_test KEY1 Value1 KEY2 Value2 ...</c> <br></br> </p> diff --git a/lib/tools/doc/src/erlang_mode.xml b/lib/tools/doc/src/erlang_mode.xml index 72770898c2..912c442153 100644 --- a/lib/tools/doc/src/erlang_mode.xml +++ b/lib/tools/doc/src/erlang_mode.xml @@ -51,7 +51,7 @@ <list type="bulleted"> <item><em><c>TAB</c></em> (<c>erlang-indent-command</c>) - Indents the current line of code. </item> - <item><em><c>M-C-\\</c></em> (<c>indent-region</c>) - Indents all + <item><em><c>M-C-\</c></em> (<c>indent-region</c>) - Indents all lines in the region. </item> <item><em><c>M-l</c></em> (<c>indent-for-comment</c>) - Insert a comment character to the right of the code on the line (if diff --git a/lib/tools/doc/src/erlang_mode_chapter.xml b/lib/tools/doc/src/erlang_mode_chapter.xml index cf043e3302..b22c6b1809 100644 --- a/lib/tools/doc/src/erlang_mode_chapter.xml +++ b/lib/tools/doc/src/erlang_mode_chapter.xml @@ -74,10 +74,10 @@ environment variable is set, Emacs will look for the <c>.emacs</c> file in the directory indicated by the <em>HOME</em> variable. If <em>HOME</em> is not set, Emacs - will look for the <c>.emacs</c> file in <c>C:\\ </c>.</p> + will look for the <c>.emacs</c> file in <c>C:\ </c>.</p> <p>Below is a complete example of what should be added to a user's <c>.emacs</c> provided that OTP is installed in the directory - <c><![CDATA[C:\\Program Files\\erl<Ver>]]></c>: </p> + <c><![CDATA[C:\Program Files\erl<Ver>]]></c>: </p> <code type="none"><![CDATA[ (setq load-path (cons "C:/Program Files/erl<Ver>/lib/tools-<ToolsVer>/emacs" load-path)) @@ -87,7 +87,7 @@ ]]></code> <note> <p>In .emacs, the slash character "/" can be used as path - separator. But if you decide to use the backslash character "\\", + separator. But if you decide to use the backslash character "\", please not that you must use double backslashes, since they are treated as escape characters by Emacs.</p> </note> diff --git a/lib/tools/doc/src/notes.xml b/lib/tools/doc/src/notes.xml index 59f600145e..e6c074cc7d 100644 --- a/lib/tools/doc/src/notes.xml +++ b/lib/tools/doc/src/notes.xml @@ -30,6 +30,21 @@ </header> <p>This document describes the changes made to the Tools application.</p> +<section><title>Tools 2.6.5.1</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p>A bug concerning bit comprehensions has been fixed + in Cover. The bug was introduced in R13B03. + (Thanks to Matthew Sackman.)</p> + <p>Own Id: OTP-8340</p> + </item> + </list> + </section> + +</section> + <section><title>Tools 2.6.5</title> <section><title>Fixed Bugs and Malfunctions</title> diff --git a/lib/tools/doc/src/notes_history.xml b/lib/tools/doc/src/notes_history.xml index ef5ce1c03d..3791d5270a 100644 --- a/lib/tools/doc/src/notes_history.xml +++ b/lib/tools/doc/src/notes_history.xml @@ -4,23 +4,21 @@ <chapter> <header> <copyright> - <year>2006</year> - <year>2007</year> - <holder>Ericsson AB, All Rights Reserved</holder> + <year>2006</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> - The contents of this file are subject to the Erlang Public License, - Version 1.1, (the "License"); you may not use this file except in - compliance with the License. You should have received a copy of the - Erlang Public License along with this software. If not, it can be - retrieved online at http://www.erlang.org/. - - Software distributed under the License is distributed on an "AS IS" - basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - the License for the specific language governing rights and limitations - under the License. - - The Initial Developer of the Original Code is Ericsson AB. + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + </legalnotice> <title>Tools Release Notes</title> @@ -63,7 +61,7 @@ <p>Own Id: OTP-5073</p> </item> <item> - <p>Previous patch from open source messed up \\M-q so part of + <p>Previous patch from open source messed up \M-q so part of that patch was backed out.</p> <p>Own Id: OTP-5074</p> </item> diff --git a/lib/tools/doc/src/xref.xml b/lib/tools/doc/src/xref.xml index 6fff68fe9f..407a7392ad 100644 --- a/lib/tools/doc/src/xref.xml +++ b/lib/tools/doc/src/xref.xml @@ -1176,7 +1176,7 @@ Evaluates a predefined analysis. <item> <p><c>no_functions</c>. Functions in library modules and the functions <c>module_info/0,1</c> are not counted by - <c>info</c>. Assuming that <c>"Extra := _:module_info/\\"(0|1)\\" + LM"</c> has been evaluated, the + <c>info</c>. Assuming that <c>"Extra := _:module_info/\"(0|1)\" + LM"</c> has been evaluated, the sum of the number of local and exported functions are:</p> <list type="bulleted"> <item><c>"# (F - Extra)"</c> (info/1)</item> diff --git a/lib/tools/src/cover.erl b/lib/tools/src/cover.erl index aff3927db3..1a7ebdc69a 100644 --- a/lib/tools/src/cover.erl +++ b/lib/tools/src/cover.erl @@ -1685,8 +1685,8 @@ munge_expr({lc,Line,Expr,Qs}, Vars) -> {MungedQs, Vars3} = munge_qualifiers(Qs, Vars2), {{lc,Line,MungedExpr,MungedQs}, Vars3}; munge_expr({bc,Line,Expr,Qs}, Vars) -> - {bin,BLine,[{bin_element,EL,Val,Sz,TSL}]} = Expr, - Expr2 = {bin,BLine,[{bin_element,EL,?BLOCK1(Val),Sz,TSL}]}, + {bin,BLine,[{bin_element,EL,Val,Sz,TSL}|Es]} = Expr, + Expr2 = {bin,BLine,[{bin_element,EL,?BLOCK1(Val),Sz,TSL}|Es]}, {MungedExpr,Vars2} = munge_expr(Expr2, Vars), {MungedQs, Vars3} = munge_qualifiers(Qs, Vars2), {{bc,Line,MungedExpr,MungedQs}, Vars3}; diff --git a/lib/tools/vsn.mk b/lib/tools/vsn.mk index 644e8b719b..13cf5af9f5 100644 --- a/lib/tools/vsn.mk +++ b/lib/tools/vsn.mk @@ -16,4 +16,4 @@ # # %CopyrightEnd% -TOOLS_VSN = 2.6.5 +TOOLS_VSN = 2.6.5.1 diff --git a/lib/webtool/doc/src/webtool_chapter.xml b/lib/webtool/doc/src/webtool_chapter.xml index ceadce382d..f72a255b0a 100644 --- a/lib/webtool/doc/src/webtool_chapter.xml +++ b/lib/webtool/doc/src/webtool_chapter.xml @@ -212,16 +212,13 @@ http://Servername:Port/ErlScriptAlias/Mod/Func<?QueryString> ]]></code> header("text/html"). header(MimeType) -> - "Content-type: " ++ MimeType ++ "\\r\ -\\r\ -". + "Content-type: " ++ MimeType ++ "\r\n\r\n". html_header() -> "<HTML> <HEAD> <TITLE>Hello world Example </TITLE> - </HEAD>\ -". + </HEAD>\n". helloworld_body()-> "<BODY>Hello World</BODY>". diff --git a/lib/wx/api_gen/wxapi.conf b/lib/wx/api_gen/wxapi.conf index df154f0125..4a646650ea 100644 --- a/lib/wx/api_gen/wxapi.conf +++ b/lib/wx/api_gen/wxapi.conf @@ -985,7 +985,9 @@ {class, wxFileDialog, wxDialog, [{skip, [{wxFileDialog,0}]}], ['wxFileDialog','~wxFileDialog','GetDirectory','GetFilename', {'GetFilenames',[{"files", out}]}, - 'GetFilterIndex','GetMessage','GetPath','GetPaths','GetWildcard', + 'GetFilterIndex','GetMessage','GetPath', + {'GetPaths', [{"paths", out}]}, + 'GetWildcard', 'SetDirectory','SetFilename','SetFilterIndex','SetMessage','SetPath', 'SetWildcard']}. diff --git a/lib/wx/c_src/gen/wxe_funcs.cpp b/lib/wx/c_src/gen/wxe_funcs.cpp index cb662fc91b..ccbacce9b9 100644 --- a/lib/wx/c_src/gen/wxe_funcs.cpp +++ b/lib/wx/c_src/gen/wxe_funcs.cpp @@ -20582,19 +20582,11 @@ case wxFileDialog_GetPath: { // wxFileDialog::GetPath break; } case wxFileDialog_GetPaths: { // wxFileDialog::GetPaths - wxFileDialog *This = (wxFileDialog *) getPtr(bp,memenv); bp += 4; - int * pathsLen = (int *) bp; bp += 4; wxArrayString paths; - int pathsASz = 0, * pathsTemp; - for(int i=0; i < *pathsLen; i++) { - pathsTemp = (int *) bp; bp += 4; - paths.Add(wxString(bp, wxConvUTF8)); - bp += *pathsTemp; - pathsASz += *pathsTemp+4; - } - bp += (8-((0+ pathsASz) & 7 )) & 7; + wxFileDialog *This = (wxFileDialog *) getPtr(bp,memenv); bp += 4; if(!This) throw wxe_badarg(0); This->GetPaths(paths); + rt.add(paths); break; } case wxFileDialog_GetWildcard: { // wxFileDialog::GetWildcard diff --git a/lib/wx/configure.in b/lib/wx/configure.in index 7dc8d6e831..2b47f86baa 100755 --- a/lib/wx/configure.in +++ b/lib/wx/configure.in @@ -1,3 +1,21 @@ +dnl Process this file with autoconf to produce a configure script. -*-m4-*- + +dnl %CopyrightBegin% +dnl +dnl Copyright Ericsson AB 2008-2009. All Rights Reserved. +dnl +dnl The contents of this file are subject to the Erlang Public License, +dnl Version 1.1, (the "License"); you may not use this file except in +dnl compliance with the License. You should have received a copy of the +dnl Erlang Public License along with this software. If not, it can be +dnl retrieved online at http://www.erlang.org/. +dnl +dnl Software distributed under the License is distributed on an "AS IS" +dnl basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +dnl the License for the specific language governing rights and limitations +dnl under the License. +dnl +dnl %CopyrightEnd% AC_INIT() @@ -101,7 +119,7 @@ AC_SUBST(MIXED_CYGWIN) ## Check that we are in 32 bits mode on darwin ## (wxWidgets require that it currently uses 32-bits Carbon) ## Otherwise skip building wxErlang -AC_CHECK_SIZEOF(void *, 4) +AC_CHECK_SIZEOF(void *) case $ac_cv_sizeof_void_p-$host_os in 8-darwin*) diff --git a/lib/wx/doc/src/Makefile b/lib/wx/doc/src/Makefile index d18daa753a..fd9f7441a3 100644 --- a/lib/wx/doc/src/Makefile +++ b/lib/wx/doc/src/Makefile @@ -31,12 +31,6 @@ GenMods = $(shell ls ../../src/gen | grep 'wx[A-Z].*\.erl') \ glu.erl \ gl.erl -# GenMods = \ -# wx_misc.erl \ -# glu.erl \ -# gl.erl - - ModsNoExt = $(ErlMods:%.erl=%) $(GenMods:%.erl=%) ifneq ($(INSIDE_ERLSRC),true) @@ -126,9 +120,9 @@ gifs: $(GIF_FILES:%=$(HTMLDIR)/%) xml: $(XML_REF3_FILES) $(XML_CHAPTER_FILES) -ref_man.xml: ref_man.src.xml +ref_man.xml: ref_man.xml.src @echo Preparing ref_man.xml - @cat ref_man.src.xml > ref_man.xml + @cat ref_man.xml.src > ref_man.xml @for d in $(ModsNoExt); do \ echo " <xi:include href=\"$$d.xml\"/>" >> ref_man.xml ; \ done diff --git a/lib/wx/doc/src/ref_man.src.xml b/lib/wx/doc/src/ref_man.xml.src index 77fd16b050..77fd16b050 100644 --- a/lib/wx/doc/src/ref_man.src.xml +++ b/lib/wx/doc/src/ref_man.xml.src diff --git a/lib/wx/src/gen/wxFileDialog.erl b/lib/wx/src/gen/wxFileDialog.erl index 22b39aa150..efe1ff57f3 100644 --- a/lib/wx/src/gen/wxFileDialog.erl +++ b/lib/wx/src/gen/wxFileDialog.erl @@ -31,7 +31,7 @@ -module(wxFileDialog). -include("wxe.hrl"). -export([destroy/1,getDirectory/1,getFilename/1,getFilenames/1,getFilterIndex/1, - getMessage/1,getPath/1,getPaths/2,getWildcard/1,new/1,new/2,setDirectory/2, + getMessage/1,getPath/1,getPaths/1,getWildcard/1,new/1,new/2,setDirectory/2, setFilename/2,setFilterIndex/2,setMessage/2,setPath/2,setWildcard/2]). %% inherited exports @@ -152,15 +152,12 @@ getPath(#wx_ref{type=ThisT,ref=ThisRef}) -> wxe_util:call(?wxFileDialog_GetPath, <<ThisRef:32/?UI>>). -%% @spec (This::wxFileDialog(), Paths::[[string()]]) -> ok +%% @spec (This::wxFileDialog()) -> [[string()]] %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxfiledialog.html#wxfiledialoggetpaths">external documentation</a>. -getPaths(#wx_ref{type=ThisT,ref=ThisRef},Paths) - when is_list(Paths) -> +getPaths(#wx_ref{type=ThisT,ref=ThisRef}) -> ?CLASS(ThisT,wxFileDialog), - Paths_UCA = [unicode:characters_to_binary([PathsTemp,0]) || - PathsTemp <- Paths], - wxe_util:cast(?wxFileDialog_GetPaths, - <<ThisRef:32/?UI,(length(Paths_UCA)):32/?UI, (<< <<(byte_size(UC_Str)):32/?UI, UC_Str/binary>>|| UC_Str <- Paths_UCA>>)/binary, 0:(((8- ((0 + lists:sum([byte_size(S)+4||S<-Paths_UCA])) band 16#7)) band 16#7))/unit:8>>). + wxe_util:call(?wxFileDialog_GetPaths, + <<ThisRef:32/?UI>>). %% @spec (This::wxFileDialog()) -> string() %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxfiledialog.html#wxfiledialoggetwildcard">external documentation</a>. |