+/* SlapReply debugging, prodo-slap.h overrides it in OpenLDAP releases */
+#if defined(LDAP_TEST) || (defined(USE_RS_ASSERT) && (USE_RS_ASSERT))
+
+int rs_suppress_assert = 0;
+
+/* RS_ASSERT() helper function */
+void rs_assert_(const char*file, unsigned line, const char*fn, const char*cond)
+{
+ int no_assert = rs_suppress_assert, save_errno = errno;
+ const char *s;
+
+ if ( no_assert >= 0 ) {
+ if ( no_assert == 0 && (s = getenv( "NO_RS_ASSERT" )) && *s ) {
+ no_assert = rs_suppress_assert = atoi( s );
+ }
+ if ( no_assert > 0 ) {
+ errno = save_errno;
+ return;
+ }
+ }
+
+#ifdef rs_assert_ /* proto-slap.h #defined away the fn parameter */
+ fprintf( stderr,"%s:%u: " "RS_ASSERT(%s) failed.\n", file,line,cond );
+#else
+ fprintf( stderr,"%s:%u: %s: RS_ASSERT(%s) failed.\n", file,line,fn,cond );
+#endif
+ fflush( stderr );
+
+ errno = save_errno;
+ /* $NO_RS_ASSERT > 0: ignore rs_asserts, 0: abort, < 0: just warn */
+ if ( !no_assert /* from $NO_RS_ASSERT */ ) abort();
+}
+
+/* SlapReply is consistent */
+void
+(rs_assert_ok)( const SlapReply *rs )
+{
+ const slap_mask_t flags = rs->sr_flags;
+
+ if ( flags & REP_ENTRY_MASK ) {
+ RS_ASSERT( !(flags & REP_ENTRY_MUSTRELEASE)
+ || !(flags & (REP_ENTRY_MASK ^ REP_ENTRY_MUSTRELEASE)) );
+ RS_ASSERT( rs->sr_entry != NULL );
+ RS_ASSERT( (1 << rs->sr_type) &
+ ((1 << REP_SEARCH) | (1 << REP_SEARCHREF) |
+ (1 << REP_RESULT) | (1 << REP_GLUE_RESULT)) );
+ }
+#if defined(USE_RS_ASSERT) && (USE_RS_ASSERT) > 1 /* TODO: Enable when safe */
+ if ( (flags & (REP_MATCHED_MASK | REP_REF_MASK | REP_CTRLS_MASK)) ) {
+ RS_ASSERT( !(flags & REP_MATCHED_MASK) || rs->sr_matched );
+ RS_ASSERT( !(flags & REP_CTRLS_MASK ) || rs->sr_ctrls );
+ /* Note: LDAP_REFERRAL + !sr_ref is OK, becomes LDAP_NO_SUCH_OBJECT */
+ }
+#if (USE_RS_ASSERT) > 2
+ if ( rs->sr_err == LDAP_SUCCESS ) {
+ RS_ASSERT( rs->sr_text == NULL );
+ RS_ASSERT( rs->sr_matched == NULL );
+ }
+#endif
+#endif
+}
+
+/* Ready for calling a new backend operation */
+void
+(rs_assert_ready)( const SlapReply *rs )
+{
+ RS_ASSERT( !rs->sr_entry );
+#if defined(USE_RS_ASSERT) && (USE_RS_ASSERT) > 1 /* TODO: Enable when safe */
+ RS_ASSERT( !rs->sr_text );
+ RS_ASSERT( !rs->sr_ref );
+ RS_ASSERT( !rs->sr_matched );
+ RS_ASSERT( !rs->sr_ctrls );
+ RS_ASSERT( !rs->sr_flags );
+#if (USE_RS_ASSERT) > 2
+ RS_ASSERT( rs->sr_err == LDAP_SUCCESS );
+#endif
+#else
+ RS_ASSERT( !(rs->sr_flags & REP_ENTRY_MASK) );
+#endif
+}
+
+/* Backend operation done */
+void
+(rs_assert_done)( const SlapReply *rs )
+{
+#if defined(USE_RS_ASSERT) && (USE_RS_ASSERT) > 1 /* TODO: Enable when safe */
+ RS_ASSERT( !(rs->sr_flags & ~(REP_ENTRY_MODIFIABLE|REP_NO_OPERATIONALS)) );
+ rs_assert_ok( rs );
+#else
+ RS_ASSERT( !(rs->sr_flags & REP_ENTRY_MUSTFLUSH) );
+#endif
+}
+
+#endif /* LDAP_TEST || USE_RS_ASSERT */
+
+/* Reset a used SlapReply whose contents has been flushed (freed/released) */
+void
+(rs_reinit)( SlapReply *rs, slap_reply_t type )
+{
+ rs_reinit( rs, type ); /* proto-slap.h macro */
+}
+
+/* Obey and clear rs->sr_flags & REP_ENTRY_MASK. Clear sr_entry if freed. */
+void
+rs_flush_entry( Operation *op, SlapReply *rs, slap_overinst *on )
+{
+ rs_assert_ok( rs );
+
+ if ( (rs->sr_flags & REP_ENTRY_MUSTFLUSH) && rs->sr_entry != NULL ) {
+ if ( !(rs->sr_flags & REP_ENTRY_MUSTRELEASE) ) {
+ entry_free( rs->sr_entry );
+ } else if ( on != NULL ) {
+ overlay_entry_release_ov( op, rs->sr_entry, 0, on );
+ } else {
+ be_entry_release_rw( op, rs->sr_entry, 0 );
+ }
+ rs->sr_entry = NULL;
+ }
+
+ rs->sr_flags &= ~REP_ENTRY_MASK;
+}
+
+/* Set rs->sr_entry after obeying and clearing sr_flags & REP_ENTRY_MASK. */
+void
+rs_replace_entry( Operation *op, SlapReply *rs, slap_overinst *on, Entry *e )
+{
+ rs_flush_entry( op, rs, on );
+ rs->sr_entry = e;
+}
+
+/*
+ * Ensure rs->sr_entry is modifiable, by duplicating it if necessary.
+ * Obey sr_flags. Set REP_ENTRY_<MODIFIABLE, and MUSTBEFREED if duplicated>.
+ * Return nonzero if rs->sr_entry was replaced.
+ */
+int
+rs_entry2modifiable( Operation *op, SlapReply *rs, slap_overinst *on )
+{
+ if ( rs->sr_flags & REP_ENTRY_MODIFIABLE ) {
+ rs_assert_ok( rs );
+ return 0;
+ }
+ rs_replace_entry( op, rs, on, entry_dup( rs->sr_entry ));
+ rs->sr_flags |= REP_ENTRY_MODIFIABLE | REP_ENTRY_MUSTBEFREED;
+ return 1;
+}
+